diff --git a/.github/workflows/python_func_tests.yaml b/.github/workflows/python_func_tests.yaml new file mode 100644 index 0000000000..50e2f82986 --- /dev/null +++ b/.github/workflows/python_func_tests.yaml @@ -0,0 +1,33 @@ +name: Python unittests +on: + push: + paths: + - ush/*retrieve_data.py + - ush/templates/data_locations.yml + pull_request: + +env: + CI: true + +jobs: + python_functests: + name: Python Functional Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Install dependencies + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install python3 python3-pip netcdf-bin + sudo pip3 install pyyaml jinja2 f90nml + sudo pip3 install numpy matplotlib basemap + + # Run python functional tests + - name: Run python functional tests + run: | + cd ush + python3 -m unittest -b test_retrieve_data.FunctionalTesting diff --git a/.github/workflows/python_unittests.yaml b/.github/workflows/python_unittests.yaml new file mode 100644 index 0000000000..65688fd387 --- /dev/null +++ b/.github/workflows/python_unittests.yaml @@ -0,0 +1,27 @@ +name: Python unittests +on: [push, pull_request] +jobs: + + python_unittests: + name: Python unittests + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Install dependencies + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install python3 python3-pip netcdf-bin + sudo pip3 install pyyaml jinja2 f90nml + sudo pip3 install numpy matplotlib basemap + + # Run python unittests + - name: Run python unittests + run: | + cd ush + python3 -m unittest -b python_utils/test_python_utils.py + python3 -m unittest -b *.py + diff --git a/Externals.cfg b/Externals.cfg index c595c96b98..db4bfff00a 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -1,12 +1,3 @@ -[regional_workflow] -protocol = git -repo_url = https://github.com/ufs-community/regional_workflow -# Specify either a branch name or a hash but not both. -#branch = develop -hash = 3a2cb82 -local_path = regional_workflow -required = True - [ufs_utils] protocol = git repo_url = https://github.com/ufs-community/UFS_UTILS diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000000..2e75288d85 --- /dev/null +++ b/environment.yml @@ -0,0 +1,8 @@ +name: regional_workflow +channels: + - conda-forge +dependencies: + python: 3.7 + f90nml: 1.1.2 + jinja2: 2.11* + pyyaml: 5.1.2 diff --git a/jobs/JREGIONAL_GET_EXTRN_MDL_FILES b/jobs/JREGIONAL_GET_EXTRN_MDL_FILES new file mode 100755 index 0000000000..31c2963866 --- /dev/null +++ b/jobs/JREGIONAL_GET_EXTRN_MDL_FILES @@ -0,0 +1,249 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script gets either from the system directory or from mass store +# (HPSS) the files generated by the external model (specified by the +# variable EXTRN_MDL_NAME) for either the initial conditions (ICs) or the +# lateral boundary conditions (LBCs). Which of these we are considering +# depends on the value of the variable ICS_OR_LBCS, which should be defined +# in the environment (when calling this script from a rocoto workflow, +# the workflow should define this variable, e.g. using rocoto's +# tag). +# +# Note that when we refer to ICs, we are referring to not only the atmospheric +# fields at the initial time but also various surface fields (which are +# for now time-independent) as well as the 0-th forecast hour LBCs. Also, +# when we refer to LBCs, we are referring to the LBCs excluding the one +# at the 0-th hour. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that copies or fetches external +model files from disk, HPSS, or URL, and stages them for downstream use +to generate initial or lateral boundary conditions for the FV3 model. +========================================================================" + + +# +#----------------------------------------------------------------------- +# +# Check whether the environment variable ICS_OR_LBCS is set to a valid +# value. This variable specifies whether we are getting the external +# model files for the purpose of generating initial conditions (ICs) or +# lateral boundary condtions (LBCs) for the forecast model. +# +#----------------------------------------------------------------------- +# +valid_vals_ICS_OR_LBCS=( "ICS" "LBCS" ) +check_var_valid_value "ICS_OR_LBCS" "valid_vals_ICS_OR_LBCS" +# +#----------------------------------------------------------------------- +# +# Set parameters for grabbing either the initial conditions from analysis or +# forecast files of external models, or the lateral boundary conditions +# from external models. This script has been called to do the work for +# one or the other. +# +#----------------------------------------------------------------------- +# +if [ "${ICS_OR_LBCS}" = "ICS" ]; then + time_offset_hrs=${EXTRN_MDL_ICS_OFFSET_HRS:-0} + extrn_mdl_name=${EXTRN_MDL_NAME_ICS} + +elif [ "${ICS_OR_LBCS}" = "LBCS" ]; then + time_offset_hrs=${EXTRN_MDL_LBCS_OFFSET_HRS:-0} + extrn_mdl_name=${EXTRN_MDL_NAME_LBCS} +fi + +# +#----------------------------------------------------------------------- +# +# Set the external model start time +# +#----------------------------------------------------------------------- +# + +hh=${CDATE:8:2} +yyyymmdd=${CDATE:0:8} +extrn_mdl_cdate=$( $DATE_UTIL --utc --date "${yyyymmdd} ${hh} UTC - ${time_offset_hrs} hours" "+%Y%m%d%H" ) + +# +#----------------------------------------------------------------------- +# +# Check whether output files from the specified external model +# (extrn_mdl_name) are available on the specified cycle date and time +# (extrn_mdl_cdate). +# +#----------------------------------------------------------------------- +# + +function data_unavailable() { + + local name cdate end_date min_max + + name=$1 + cdate=$2 + end_date=$3 + min_max=$4 + + if [ ${min_max} = max ]; then + msg="\ +Output from the specified external model (extrn_mdl_name) is not availa- +ble for the specified cycle date and time (extrn_mdl_cdate) because the latter is +later than the last forecast date and time (cdate_max) with this model: + extrn_mdl_name = \"${name}\" + CDATE_max = \"${end_date}\" + extrn_mdl_cdate = \"${cdate}\"" + + elif [ ${min_max} = min ]; then + msg="\ +Output from the specified external model (extrn_mdl_name) is not availa- +ble for the specified cycle date and time (extrn_mdl_cdate) because the latter is +earlier than the implementation date of this model: + extrn_mdl_name = \"${name}\" + CDATE_min = \"${end_date}\" + extrn_mdl_cdate = \"${cdate}\"" + fi + + echo ${msg} +} + + +case ${extrn_mdl_name} in + +"GSMGFS") +# The transition date from the GSMGFS to the FV3GFS was 2019061212, i.e. +# this was the first official forecast with the FV3GFS. So we set the +# last CDATE for the GSMGFS to the one 6 hours before this. + cdate_max="2019061206" + if [ "$extrn_mdl_cdate" -gt "$cdate_max" ]; then + print_err_msg_exit "\ + $(data_unavailable $extrn_mdl_name $extrn_mdl_cdate $cdate_max max)" + fi + ;; + +"FV3GFS") +# The transition date from the GSMGFS to the FV3GFS was 2019061212, i.e. +# this was the first official forecast with the FV3GFS. However, paral- +# lel runs with the FV3GFS go back to 2018121500. So we set the first +# extrn_mdl_cdate for the FV3GFS to this date and time. +# CDATE_min="2019061212" + CDATE_min="2018121500" + if [ "$extrn_mdl_cdate" -lt "$CDATE_min" ]; then + print_err_msg_exit "\ + $(data_unavailable $extrn_mdl_name $extrn_mdl_cdate $cdate_min min)" + fi + ;; + +"RAP") +# Examination of the HPSS archives shows that the RAPX data goes back to +# July 01, 2015. + CDATE_min="2015070100" + if [ "$extrn_mdl_cdate" -lt "$CDATE_min" ]; then + print_err_msg_exit "\ + $(data_unavailable $extrn_mdl_name $extrn_mdl_cdate $cdate_min min)" + fi + ;; + +"HRRR") +# From the HRRR home page (https://rapidrefresh.noaa.gov/hrrr), the +# implementation of the first version of the operational HRRR was +# September 30, 2014. + CDATE_min="2014103000" + if [ "$extrn_mdl_cdate" -lt "$CDATE_min" ]; then + print_err_msg_exit "\ + $(data_unavailable $extrn_mdl_name $extrn_mdl_cdate $cdate_min min)" + fi + ;; + +esac +# +#----------------------------------------------------------------------- +# +# Create the directory where the exetrnal model files should be stored +# +#----------------------------------------------------------------------- +# +extrn_mdl_staging_dir="${CYCLE_DIR}/${extrn_mdl_name}/for_${ICS_OR_LBCS}" +mkdir_vrfy -p "${extrn_mdl_staging_dir}" +cd_vrfy "${extrn_mdl_staging_dir}" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary variables. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_get_extrn_mdl_files.sh \ + extrn_mdl_cdate="${extrn_mdl_cdate}" \ + extrn_mdl_name="${extrn_mdl_name}" \ + extrn_mdl_staging_dir="${extrn_mdl_staging_dir}" \ + time_offset_hrs=${time_offset_hrs} || +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/function. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_GET_OBS_CCPA b/jobs/JREGIONAL_GET_OBS_CCPA new file mode 100755 index 0000000000..bd1760ee0d --- /dev/null +++ b/jobs/JREGIONAL_GET_OBS_CCPA @@ -0,0 +1,94 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script pulls CCPA observation data for comparison to the model for +# the requested accumulations. Supported accumulations: 01h, 03h, and 06h. +# NOTE: Accumulation is currently hardcoded to 01h. +# The verification uses MET/pcp-combine to sum 01h files into +# desired accumulations. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that pulls CCPA observation data +for verification purposes. +========================================================================" + +# +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_get_ccpa_files.sh || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_GET_OBS_MRMS b/jobs/JREGIONAL_GET_OBS_MRMS new file mode 100755 index 0000000000..f5d6349745 --- /dev/null +++ b/jobs/JREGIONAL_GET_OBS_MRMS @@ -0,0 +1,95 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script pulls MRMS observation data for comparison to the model. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that pulls MRMS observation data +for verification purposes. +========================================================================" + +# +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +echo "VAR=${VAR}" +for field in ${VAR[@]}; do + export field + echo "Field=${field}" + $SCRIPTSDIR/exregional_get_mrms_files.sh || \ + print_err_msg_exit "\ + Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +done +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_GET_OBS_NDAS b/jobs/JREGIONAL_GET_OBS_NDAS new file mode 100755 index 0000000000..ab44e21b8f --- /dev/null +++ b/jobs/JREGIONAL_GET_OBS_NDAS @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script pulls NDAS observation data for comparison to the model. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that pulls NDAS observation data +for verification purposes. +========================================================================" + +# +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_get_ndas_files.sh || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_MAKE_GRID b/jobs/JREGIONAL_MAKE_GRID new file mode 100755 index 0000000000..bbf22e0241 --- /dev/null +++ b/jobs/JREGIONAL_MAKE_GRID @@ -0,0 +1,201 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script generates grid and orography files in NetCDF format that +# are required as inputs for running the FV3-LAM model (i.e. the FV3 mo- +# del on a regional domain). It in turn calls three other scripts whose +# file names are specified in the variables grid_gen_scr, orog_gen_scr, +# and orog_fltr_scr and then calls the executable defined in the varia- +# ble shave_exec. These scripts/executable perform the following tasks: +# +# 1) grid_gen_scr: +# +# This script generates grid files that will be used by subsequent +# preprocessing steps. It places its output in the directory defined +# by GRID_DIR. Note that: +# +# a) This script creates grid files for each of the 7 tiles of the +# cubed sphere grid (where tiles 1 through 6 cover the globe, and +# tile 7 is the regional grid located somewhere within tile 6) +# even though the forecast will be performed only on tile 7. +# +# b) The tile 7 grid file that this script creates includes a halo, +# i.e. a layer of cells beyond the boundary of tile 7). The width +# of this halo (i.e. the number of cells in the halo in the direc- +# tion perpendicular to the boundary of the tile) must be made +# large enough such that the "shave" steps later below (which take +# this file as input and generate grid files with thinner halos) +# have a wide enough starting halo to work with. More specifical- +# ly, the FV3-LAM model needs as inputs two grid files: one with a +# halo that is 3 cells and another with a halo that is 4 cells +# wide. Thus, the halo in the grid file that the grid_gen_scr +# script generates must be greater than 4 since otherwise, the +# shave steps would shave off cells from within the interior of +# tile 7. We will let NHW denote the width of the halo in the +# grid file generated by grid_gen_scr. The "n" in this variable +# name denotes number of cells, the "h" is used to indicate that +# it refers to a halo region, the "w" is used to indicate that it +# refers to a wide halo (i.e. wider than the 3-cell and 4-cell ha- +# los that the FV3-LAM model requires as inputs, and the "T7" is +# used to indicate that the cell count is on tile 7. +# +# 2) orog_gen_scr: +# +# This script generates the orography file. It places its output in +# the directory defined by OROG_DIR. Note that: +# +# a) This script generates an orography file only on tile 7. +# +# b) This orography file contains a halo of the same width (NHW) +# as the grid file for tile 7 generated by the grid_gen_scr script +# in the previous step. +# +# 3) orog_fltr_scr: +# +# This script generates a filtered version of the orography file ge- +# nerated by the script orog_gen_scr. This script places its output +# in the temporary directory defined in WORKDIR_FLTR. Note that: +# +# a) The filtered orography file generated by this script contains a +# halo of the same width (NHW) as the (unfiltered) orography file +# generated by script orog_gen_scr (and the grid file generated by +# grid_gen_scr). +# +# b) In analogy with the input grid files, the FV3-LAM model needs as +# input two (filtered) orography files -- one with no halo cells +# and another with 3. These are obtained later below by "shaving" +# off layers of halo cells from the (filtered) orography file ge- +# nerated in this step. +# +# 4) shave_exec: +# +# This "shave" executable is called 4 times to generate 4 files from +# the tile 7 grid file generated by grid_gen_scr and the tile 7 fil- +# tered orography file generated by orog_fltr_scr (both of which have +# a halo of width NHW cells). The 4 output files are placed in the +# temporary directory defined in WORKDIR_SHVE. More specifically: +# +# a) shave_exec is called to shave the halo in the tile 7 grid file +# generated by grid_gen_scr down to a width of 3 cells and store +# the result in a new grid file in WORKDIR_SHVE. +# +# b) shave_exec is called to shave the halo in the tile 7 grid file +# generated by grid_gen_scr down to a width of 4 cells and store +# the result in a new grid file in WORKDIR_SHVE. +# +# c) shave_exec is called to shave the halo in the tile 7 filtered +# orography file generated by orog_fltr_scr down to a width of 0 +# cells (i.e. no halo) and store the result in a new filtered oro- +# graphy file in WORKDIR_SHVE. +# +# d) shave_exec is called to shave the halo in the tile 7 filtered +# orography file generated by orog_fltr_scr down to a width of 4 +# cells and store the result in a new filtered orography file in +# WORKDIR_SHVE. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that generates grid files. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +${SCRIPTSDIR}/exregional_make_grid.sh || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Create a flag file to make rocoto aware that the make_grid task has +# successfully completed (so that other tasks that depend on it can be +# launched). +# +# Although we can use the tag to make other tasks depend on +# the successful completion of make_grid, it turns out that the tag assumes that the task it specifies (in this case make_grid) +# runs for the same set of cycles as the one in which it appears as a +# dependency. Thus, if we use in a cycle-dependent task in +# the workflow to make it depend on the make_grid, then the workflow +# will wait for make_grid to run for each cycle for which that cycle-de- +# pendent task is defined before running the task. But since make_grid +# will not run for each cycle (except possibly for the very first one), +# the cycle-dependent task will not be able to run for any of the cycles +# except the first one. For this reason, we cannot use the +# tag to make other cycle-dependent tasks depend on make_grid and must +# instead use a flag file. +# +#----------------------------------------------------------------------- +# +touch "$LOGDIR/make_grid_task_complete.txt" +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_MAKE_ICS b/jobs/JREGIONAL_MAKE_ICS new file mode 100755 index 0000000000..a5e5894f10 --- /dev/null +++ b/jobs/JREGIONAL_MAKE_ICS @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that generates initial condition +(IC), surface, and zeroth-hour lateral boundary condition (LBC0) files +for the FV3 (in NetCDF format). +========================================================================" +# +#----------------------------------------------------------------------- +# +# Set the name of and create the directory in which the output from this +# script will be placed (if that directory doesn't already exist). +# +#----------------------------------------------------------------------- +# +ics_dir="${CYCLE_DIR}${SLASH_ENSMEM_SUBDIR}/INPUT" +mkdir_vrfy -p "${ics_dir}" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary variables. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_make_ics.sh \ + ics_dir="${ics_dir}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/function. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_MAKE_LBCS b/jobs/JREGIONAL_MAKE_LBCS new file mode 100755 index 0000000000..bc7afbaf71 --- /dev/null +++ b/jobs/JREGIONAL_MAKE_LBCS @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that generates lateral boundary +condition (LBC) files (in NetCDF format) for all LBC update hours (except +hour zero). +========================================================================" +# +#----------------------------------------------------------------------- +# +# Set the name of and create the directory in which the output from this +# script will be placed (if it doesn't already exist). +# +#----------------------------------------------------------------------- +# +lbcs_dir="${CYCLE_DIR}${SLASH_ENSMEM_SUBDIR}/INPUT" +mkdir_vrfy -p "${lbcs_dir}" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary variables. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_make_lbcs.sh \ + lbcs_dir="${lbcs_dir}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/function. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_MAKE_OROG b/jobs/JREGIONAL_MAKE_OROG new file mode 100755 index 0000000000..50b6c03697 --- /dev/null +++ b/jobs/JREGIONAL_MAKE_OROG @@ -0,0 +1,103 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that generates orography files. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +${SCRIPTSDIR}/exregional_make_orog.sh || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Create a flag file to make rocoto aware that the make_orog task has +# successfully completed (so that other tasks that depend on it can be +# launched). +# +# Although we can use the tag to make other tasks depend on +# the successful completion of make_orog, it turns out that the tag assumes that the task it specifies (in this case make_orog) +# runs for the same set of cycles as the one in which it appears as a +# dependency. Thus, if we use in a cycle-dependent task in +# the workflow to make it depend on the make_orog, then the workflow +# will wait for make_orog to run for each cycle for which that cycle-de- +# pendent task is defined before running the task. But since make_orog +# will not run for each cycle (except possibly for the very first one), +# the cycle-dependent task will not be able to run for any of the cycles +# except the first one. For this reason, we cannot use the +# tag to make other cycle-dependent tasks depend on make_orog and must +# instead use a flag file. +# +#----------------------------------------------------------------------- +# +touch "$LOGDIR/make_orog_task_complete.txt" +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_MAKE_SFC_CLIMO b/jobs/JREGIONAL_MAKE_SFC_CLIMO new file mode 100755 index 0000000000..24af27bfa3 --- /dev/null +++ b/jobs/JREGIONAL_MAKE_SFC_CLIMO @@ -0,0 +1,125 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that generates surface fields from +climatology. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Create the output directory for the surface climatology files. If it +# already exists, deal with it as specified by PREEXISTING_DIR_METHOD. +# +#----------------------------------------------------------------------- +# +check_for_preexist_dir_file "${SFC_CLIMO_DIR}" "${PREEXISTING_DIR_METHOD}" +mkdir_vrfy -p "${SFC_CLIMO_DIR}" +# +#----------------------------------------------------------------------- +# +# Create a work directory. If it already exists, delete it. +# +#----------------------------------------------------------------------- +# +workdir="${SFC_CLIMO_DIR}/tmp" +check_for_preexist_dir_file "$workdir" "delete" +mkdir_vrfy $workdir +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +${SCRIPTSDIR}/exregional_make_sfc_climo.sh \ + workdir="$workdir" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Create a flag file to make rocoto aware that the make_sfc_climo task +# has successfully completed (so that other tasks that depend on it can +# be launched). +# +# Although we can use the tag to make other tasks depend on +# the successful completion of make_sfc_climo, it turns out that the +# tag assumes that the task it specifies (in this case make_- +# sfc_climo) runs for the same set of cycles as the one in which it ap- +# pears as a dependency. Thus, if we use in a cycle-dependent +# task in the workflow to make it depend on the make_sfc_climo, then the +# workflow will wait for make_sfc_climo to run for each cycle for which +# that cycle-dependent task is defined before running the task. But +# since make_sfc_climo will not run for each cycle (except possibly for +# the very first one), the cycle-dependent task will not be able to run +# for any of the cycles except the first one. For this reason, we can- +# not use the tag to make other cycle-dependent tasks depend +# on make_sfc_climo and must instead use a flag file. +# +#----------------------------------------------------------------------- +# +touch "$LOGDIR/make_sfc_climo_task_complete.txt" +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_FCST b/jobs/JREGIONAL_RUN_FCST new file mode 100755 index 0000000000..dbd4c80c4b --- /dev/null +++ b/jobs/JREGIONAL_RUN_FCST @@ -0,0 +1,104 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script copies files from various directories into the experiment +# directory, creates links to some of them, and modifies others (e.g. +# templates) to customize them for the current experiment setup. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs a forecast with FV3 for +the specified cycle. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Create the INPUT and RESTART directories under the run directory. +# +#----------------------------------------------------------------------- +# +run_dir="${CYCLE_DIR}${SLASH_ENSMEM_SUBDIR}" +mkdir_vrfy -p ${run_dir}/INPUT +mkdir_vrfy -p ${run_dir}/RESTART +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_fcst.sh \ + cdate="${CDATE}" \ + cycle_dir="${CYCLE_DIR}" \ + ensmem_indx="${ENSMEM_INDX}" \ + slash_ensmem_subdir="${SLASH_ENSMEM_SUBDIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_POST b/jobs/JREGIONAL_RUN_POST new file mode 100755 index 0000000000..86a30470bb --- /dev/null +++ b/jobs/JREGIONAL_RUN_POST @@ -0,0 +1,162 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script runs the post-processor (UPP) on the NetCDF output files +# of the write component of the FV3-LAM model. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs the post-processor (UPP) +on the output files corresponding to a specified forecast hour. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Set the run directory. +# +#----------------------------------------------------------------------- +# +run_dir="${CYCLE_DIR}${SLASH_ENSMEM_SUBDIR}" +# +# If SUB_HOURLY_POST is not set to "TRUE", ensure that the forecast +# minutes (fmn) are set to "00". This is necessary in order to pass +# "fmn" into the post ex-script for the calculation of post_time. +# +if [ "${SUB_HOURLY_POST}" != "TRUE" ]; then + fmn="00" +fi +# +#----------------------------------------------------------------------- +# +# If it doesn't already exist, create the directory (postprd_dir) in which +# to store post-processing output. (Note that postprd_dir may have already +# been created by this post-processing script for a different output time +# from the same forecast start time and/or ensemble member.) Also, create +# a temporary work directory (tmp_dir) for the current output time. This +# will be deleted later after the processing for the current output time +# is complete. Then change location to tmp_dir. +# +# Note that there may be a preexisting version of tmp_dir from previous +# runs of this script for the current forecast hour (and current forecast +# start time), e.g. from the workflow task that runs this script failing +# and then being called again. Thus, we first make sure preexisting +# versions are deleted. +# +#----------------------------------------------------------------------- +# +if [ "${RUN_ENVIR}" = "nco" ]; then + COMOUT="${COMOUT_BASEDIR}/$RUN.$PDY/$cyc${SLASH_ENSMEM_SUBDIR}" + postprd_dir="$COMOUT" +else + postprd_dir="${run_dir}/postprd" +fi +mkdir_vrfy -p "${postprd_dir}" + +if [ "${SUB_HOURLY_POST}" = "TRUE" ]; then + tmp_dir="${postprd_dir}/$fhr$fmn" +else + tmp_dir="${postprd_dir}/$fhr" +fi +check_for_preexist_dir_file "${tmp_dir}" "delete" +mkdir_vrfy -p "${tmp_dir}" + +cd_vrfy "${tmp_dir}" +# +#----------------------------------------------------------------------- +# +# Make sure that fhr is a non-empty string consisting of only digits. +# +#----------------------------------------------------------------------- +# +fhr=$( printf "%s" "${fhr}" | $SED -n -r -e "s/^([0-9]+)$/\1/p" ) +if [ -z "$fhr" ]; then + print_err_msg_exit "\ +The forecast hour (fhr) must be a non-empty string consisting of only +digits: + fhr = \"${fhr}\"" +fi +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_post.sh \ + cdate="${CDATE}" \ + run_dir="${run_dir}" \ + postprd_dir="${postprd_dir}" \ + tmp_dir="${tmp_dir}" \ + fhr="${fhr}" \ + fmn="${fmn}" \ + dt_atmos="${DT_ATMOS}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_ENSGRID b/jobs/JREGIONAL_RUN_VX_ENSGRID new file mode 100755 index 0000000000..867c75fc84 --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_ENSGRID @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script runs METplus for ensemble-stat on the UPP output files by +# initialization time for all forecast hours for gridded analysis. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for ensemble-stat +on gridded fields by initialization time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_ensgridvx.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_ENSGRID_MEAN b/jobs/JREGIONAL_RUN_VX_ENSGRID_MEAN new file mode 100755 index 0000000000..a75558d928 --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_ENSGRID_MEAN @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script runs METplus for grid-stat on the UPP output files by +# initialization time for all forecast hours for gridded analysis. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for grid-stat +on gridded fields by initialization time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_ensgridvx_mean.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_ENSGRID_PROB b/jobs/JREGIONAL_RUN_VX_ENSGRID_PROB new file mode 100755 index 0000000000..a8a2c43be5 --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_ENSGRID_PROB @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script runs METplus for grid-stat on the UPP output files by +# initialization time for all forecast hours for gridded analysis. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for grid-stat +on gridded fields by initialization time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_ensgridvx_prob.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_ENSPOINT b/jobs/JREGIONAL_RUN_VX_ENSPOINT new file mode 100755 index 0000000000..fc30f076fb --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_ENSPOINT @@ -0,0 +1,88 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for point-stat +by initialitation time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_enspointvx.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_ENSPOINT_MEAN b/jobs/JREGIONAL_RUN_VX_ENSPOINT_MEAN new file mode 100755 index 0000000000..a7d937c12e --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_ENSPOINT_MEAN @@ -0,0 +1,88 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for point-stat +by initialitation time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_enspointvx_mean.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_ENSPOINT_PROB b/jobs/JREGIONAL_RUN_VX_ENSPOINT_PROB new file mode 100755 index 0000000000..818e588e51 --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_ENSPOINT_PROB @@ -0,0 +1,88 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for point-stat +by initialitation time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_enspointvx_prob.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_GRIDSTAT b/jobs/JREGIONAL_RUN_VX_GRIDSTAT new file mode 100755 index 0000000000..8537cb3ec5 --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_GRIDSTAT @@ -0,0 +1,90 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script runs METplus for grid-stat on the UPP output files by +# initialization time for all forecast hours. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for grid-stat +by initialization time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_gridstatvx.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/jobs/JREGIONAL_RUN_VX_POINTSTAT b/jobs/JREGIONAL_RUN_VX_POINTSTAT new file mode 100755 index 0000000000..084543695f --- /dev/null +++ b/jobs/JREGIONAL_RUN_VX_POINTSTAT @@ -0,0 +1,88 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the J-job script for the task that runs METplus for point-stat +by initialitation time for all forecast hours. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Call the ex-script for this J-job and pass to it the necessary varia- +# bles. +# +#----------------------------------------------------------------------- +# +$SCRIPTSDIR/exregional_run_pointstatvx.sh \ + cycle_dir="${CYCLE_DIR}" || \ +print_err_msg_exit "\ +Call to ex-script corresponding to J-job \"${scrfunc_fn}\" failed." +# +#----------------------------------------------------------------------- +# +# Print exit message. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/modulefiles/module-setup.csh.inc b/modulefiles/module-setup.csh.inc new file mode 100644 index 0000000000..cb6cefb90f --- /dev/null +++ b/modulefiles/module-setup.csh.inc @@ -0,0 +1,61 @@ +set __ms_shell=csh + +eval "if ( -d / ) set __ms_shell=tcsh" + +if ( { test -d /lfs4 } ) then + if ( ! { module help >& /dev/null } ) then + source /apps/lmod/lmod/init/$__ms_shell + endif + module purge +else if ( { test -d /scratch3 } ) then + # We are on NOAA Theia + if ( ! { module help >& /dev/null } ) then + source /apps/lmod/lmod/init/$__ms_shell + endif + module purge +else if ( { test -d /glade } ) then + # We are on NCAR Yellowstone + if ( ! { module help >& /dev/null } ) then + source /usr/share/Modules/init/$__ms_shell + endif + module purge +else if ( { test -d /lustre -a -d /ncrc } ) then + # We are on GAEA. + if ( ! { module help >& /dev/null } ) then + # We cannot simply load the module command. The GAEA + # /etc/csh.login modifies a number of module-related variables + # before loading the module command. Without those variables, + # the module command fails. Hence we actually have to source + # /etc/csh.login here. + source /etc/csh.login + set __ms_source_etc_csh_login=yes + else + set __ms_source_etc_csh_login=no + endif + module purge + unsetenv _LMFILES_ + unsetenv _LMFILES_000 + unsetenv _LMFILES_001 + unsetenv LOADEDMODULES + module load modules + if ( { test -d /opt/cray/ari/modulefiles } ) then + module use -a /opt/cray/ari/modulefiles + endif + if ( { test -d /opt/cray/pe/ari/modulefiles } ) then + module use -a /opt/cray/pe/ari/modulefiles + endif + if ( { test -d /opt/cray/pe/craype/default/modulefiles } ) then + module use -a /opt/cray/pe/craype/default/modulefiles + endif + setenv NCEPLIBS /lustre/f1/pdata/ncep_shared/NCEPLIBS/lib + if ( { test -d /lustre/f1/pdata/ncep_shared/NCEPLIBS/lib } ) then + module use $NCEPLIBS/modulefiles + endif + if ( "$__ms_source_etc_csh_login" == yes ) then + source /etc/csh.login + unset __ms_source_etc_csh_login + endif +else + # Workaround for csh limitation. Use sh to print to stderr. + sh -c 'echo WARNING: UNKNOWN PLATFORM 1>&2' +endif diff --git a/modulefiles/module-setup.sh.inc b/modulefiles/module-setup.sh.inc new file mode 100644 index 0000000000..bf07ad9b13 --- /dev/null +++ b/modulefiles/module-setup.sh.inc @@ -0,0 +1,79 @@ +# Create a test function for sh vs. bash detection. The name is +# randomly generated to reduce the chances of name collision. +__ms_function_name="setup__test_function__$$" +eval "$__ms_function_name() { /bin/true ; }" + +# Determine which shell we are using +__ms_ksh_test=$( eval '__text="text" ; if [[ $__text =~ ^(t).* ]] ; then printf "%s" ${.sh.match[1]} ; fi' 2> /dev/null | cat ) +__ms_bash_test=$( eval 'if ( set | grep '$__ms_function_name' | grep -v name > /dev/null 2>&1 ) ; then echo t ; fi ' 2> /dev/null | cat ) + +if [[ ! -z "$__ms_ksh_test" ]] ; then + __ms_shell=ksh +elif [[ ! -z "$__ms_bash_test" ]] ; then + __ms_shell=bash +else + # Not bash or ksh, so assume sh. + __ms_shell=sh +fi + +if [[ -d /lfs4 ]] ; then + # We are on NOAA Jet + if ( ! eval module help > /dev/null 2>&1 ) ; then + source /apps/lmod/lmod/init/$__ms_shell + fi + module purge +elif [[ -d /scratch3 ]] ; then + # We are on NOAA Theia + if ( ! eval module help > /dev/null 2>&1 ) ; then + source /apps/lmod/lmod/init/$__ms_shell + fi + module purge +elif [[ -d /lustre && -d /ncrc ]] ; then + # We are on GAEA. + if ( ! eval module help > /dev/null 2>&1 ) ; then + # We cannot simply load the module command. The GAEA + # /etc/profile modifies a number of module-related variables + # before loading the module command. Without those variables, + # the module command fails. Hence we actually have to source + # /etc/profile here. + source /etc/profile + __ms_source_etc_profile=yes + else + __ms_source_etc_profile=no + fi + module purge +# clean up after purge + unset _LMFILES_ + unset _LMFILES_000 + unset _LMFILES_001 + unset LOADEDMODULES + module load modules + if [[ -d /opt/cray/ari/modulefiles ]] ; then + module use -a /opt/cray/ari/modulefiles + fi + if [[ -d /opt/cray/pe/ari/modulefiles ]] ; then + module use -a /opt/cray/pe/ari/modulefiles + fi + if [[ -d /opt/cray/pe/craype/default/modulefiles ]] ; then + module use -a /opt/cray/pe/craype/default/modulefiles + fi + if [[ -s /etc/opt/cray/pe/admin-pe/site-config ]] ; then + source /etc/opt/cray/pe/admin-pe/site-config + fi + export NCEPLIBS=/lustre/f1/pdata/ncep_shared/NCEPLIBS/lib + if [[ -d "$NCEPLIBS" ]] ; then + module use $NCEPLIBS/modulefiles + fi + if [[ "$__ms_source_etc_profile" == yes ]] ; then + source /etc/profile + unset __ms_source_etc_profile + fi +else + echo WARNING: UNKNOWN PLATFORM 1>&2 +fi + +unset __ms_shell +unset __ms_ksh_test +unset __ms_bash_test +unset $__ms_function_name +unset __ms_function_name diff --git a/modulefiles/tasks/.gitignore b/modulefiles/tasks/.gitignore new file mode 100644 index 0000000000..ba3584b344 --- /dev/null +++ b/modulefiles/tasks/.gitignore @@ -0,0 +1,6 @@ +make_orog +make_ics +make_lbcs +make_sfc_climo +run_fcst +run_post diff --git a/modulefiles/tasks/cheyenne/conda_regional_workflow b/modulefiles/tasks/cheyenne/conda_regional_workflow new file mode 100644 index 0000000000..e490af9091 --- /dev/null +++ b/modulefiles/tasks/cheyenne/conda_regional_workflow @@ -0,0 +1,5 @@ +#%Module +module unload python +module load conda +setenv SRW_ENV /glade/p/ral/jntp/UFS_SRW_app/conda/regional_workflow + diff --git a/modulefiles/tasks/cheyenne/get_extrn_ics.local b/modulefiles/tasks/cheyenne/get_extrn_ics.local new file mode 100644 index 0000000000..7f0ed16e4f --- /dev/null +++ b/modulefiles/tasks/cheyenne/get_extrn_ics.local @@ -0,0 +1,4 @@ +#%Module + +module load conda_regional_workflow + diff --git a/modulefiles/tasks/cheyenne/get_extrn_lbcs.local b/modulefiles/tasks/cheyenne/get_extrn_lbcs.local new file mode 100644 index 0000000000..7f0ed16e4f --- /dev/null +++ b/modulefiles/tasks/cheyenne/get_extrn_lbcs.local @@ -0,0 +1,4 @@ +#%Module + +module load conda_regional_workflow + diff --git a/modulefiles/tasks/cheyenne/make_grid.local b/modulefiles/tasks/cheyenne/make_grid.local new file mode 100644 index 0000000000..e708b857cc --- /dev/null +++ b/modulefiles/tasks/cheyenne/make_grid.local @@ -0,0 +1,2 @@ +#%Module +module load conda_regional_workflow diff --git a/modulefiles/tasks/cheyenne/make_ics.local b/modulefiles/tasks/cheyenne/make_ics.local new file mode 100644 index 0000000000..e708b857cc --- /dev/null +++ b/modulefiles/tasks/cheyenne/make_ics.local @@ -0,0 +1,2 @@ +#%Module +module load conda_regional_workflow diff --git a/modulefiles/tasks/cheyenne/make_lbcs.local b/modulefiles/tasks/cheyenne/make_lbcs.local new file mode 100644 index 0000000000..e708b857cc --- /dev/null +++ b/modulefiles/tasks/cheyenne/make_lbcs.local @@ -0,0 +1,2 @@ +#%Module +module load conda_regional_workflow diff --git a/modulefiles/tasks/cheyenne/make_orog.hardcoded b/modulefiles/tasks/cheyenne/make_orog.hardcoded new file mode 100644 index 0000000000..51c59c5ee4 --- /dev/null +++ b/modulefiles/tasks/cheyenne/make_orog.hardcoded @@ -0,0 +1,9 @@ +#%Module##################################################### + +module purge + +module load ncarenv/1.3 +module load intel/19.0.2 +module load ncarcompilers/0.5.0 +module load netcdf/4.6.3 + diff --git a/modulefiles/tasks/cheyenne/run_fcst.local b/modulefiles/tasks/cheyenne/run_fcst.local new file mode 100644 index 0000000000..e708b857cc --- /dev/null +++ b/modulefiles/tasks/cheyenne/run_fcst.local @@ -0,0 +1,2 @@ +#%Module +module load conda_regional_workflow diff --git a/modulefiles/tasks/cheyenne/run_vx.local b/modulefiles/tasks/cheyenne/run_vx.local new file mode 100644 index 0000000000..e708b857cc --- /dev/null +++ b/modulefiles/tasks/cheyenne/run_vx.local @@ -0,0 +1,2 @@ +#%Module +module load conda_regional_workflow diff --git a/modulefiles/tasks/gaea/make_grid.local b/modulefiles/tasks/gaea/make_grid.local new file mode 100644 index 0000000000..fbd52ffa08 --- /dev/null +++ b/modulefiles/tasks/gaea/make_grid.local @@ -0,0 +1,6 @@ +#%Module +module use /lustre/f2/pdata/esrl/gsd/contrib/modulefiles +module load rocoto +module load miniconda3 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/gaea/make_ics.local b/modulefiles/tasks/gaea/make_ics.local new file mode 100644 index 0000000000..fbd52ffa08 --- /dev/null +++ b/modulefiles/tasks/gaea/make_ics.local @@ -0,0 +1,6 @@ +#%Module +module use /lustre/f2/pdata/esrl/gsd/contrib/modulefiles +module load rocoto +module load miniconda3 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/gaea/make_lbcs.local b/modulefiles/tasks/gaea/make_lbcs.local new file mode 100644 index 0000000000..fbd52ffa08 --- /dev/null +++ b/modulefiles/tasks/gaea/make_lbcs.local @@ -0,0 +1,6 @@ +#%Module +module use /lustre/f2/pdata/esrl/gsd/contrib/modulefiles +module load rocoto +module load miniconda3 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/gaea/run_fcst.local b/modulefiles/tasks/gaea/run_fcst.local new file mode 100644 index 0000000000..fbd52ffa08 --- /dev/null +++ b/modulefiles/tasks/gaea/run_fcst.local @@ -0,0 +1,6 @@ +#%Module +module use /lustre/f2/pdata/esrl/gsd/contrib/modulefiles +module load rocoto +module load miniconda3 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/gaea/run_vx.local b/modulefiles/tasks/gaea/run_vx.local new file mode 100644 index 0000000000..51416ff471 --- /dev/null +++ b/modulefiles/tasks/gaea/run_vx.local @@ -0,0 +1,5 @@ +#%Module + +module use -a /contrib/anaconda/modulefiles +module load intel/18.0.5.274 +module load anaconda/latest diff --git a/modulefiles/tasks/hera/get_extrn_ics.local b/modulefiles/tasks/hera/get_extrn_ics.local new file mode 100644 index 0000000000..4b0b48cc00 --- /dev/null +++ b/modulefiles/tasks/hera/get_extrn_ics.local @@ -0,0 +1,9 @@ +#%Module##################################################### +## Module file for get_extrn_ics task. +############################################################# + +module purge + +module load hpss + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/hera/get_extrn_lbcs.local b/modulefiles/tasks/hera/get_extrn_lbcs.local new file mode 100644 index 0000000000..477dfb2e40 --- /dev/null +++ b/modulefiles/tasks/hera/get_extrn_lbcs.local @@ -0,0 +1,9 @@ +#%Module##################################################### +## Module file for get_extrn_lbcs task. +############################################################# + +module purge + +module load hpss + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/hera/get_obs.local b/modulefiles/tasks/hera/get_obs.local new file mode 100644 index 0000000000..d30a2a9189 --- /dev/null +++ b/modulefiles/tasks/hera/get_obs.local @@ -0,0 +1,13 @@ +#%Module##################################################### +## Module file for get_obs_ccpa, get_obs_mrms, and +## get_obs_ndas task. +############################################################# + +module purge + +module load hpss + +module use /contrib/miniconda3/modulefiles +module load miniconda3/4.5.12 + +setenv SRW_ENV pygraf diff --git a/modulefiles/tasks/hera/make_grid.local b/modulefiles/tasks/hera/make_grid.local new file mode 100644 index 0000000000..92505cf09c --- /dev/null +++ b/modulefiles/tasks/hera/make_grid.local @@ -0,0 +1,3 @@ +#%Module + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/hera/make_ics.local b/modulefiles/tasks/hera/make_ics.local new file mode 100644 index 0000000000..92505cf09c --- /dev/null +++ b/modulefiles/tasks/hera/make_ics.local @@ -0,0 +1,3 @@ +#%Module + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/hera/make_lbcs.local b/modulefiles/tasks/hera/make_lbcs.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/hera/make_lbcs.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/hera/miniconda_regional_workflow b/modulefiles/tasks/hera/miniconda_regional_workflow new file mode 100644 index 0000000000..48de7a99bb --- /dev/null +++ b/modulefiles/tasks/hera/miniconda_regional_workflow @@ -0,0 +1,5 @@ +#%Module +module use /contrib/miniconda3/modulefiles +module load miniconda3/4.5.12 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/hera/run_fcst.local b/modulefiles/tasks/hera/run_fcst.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/hera/run_fcst.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/hera/run_vx.local b/modulefiles/tasks/hera/run_vx.local new file mode 100644 index 0000000000..51416ff471 --- /dev/null +++ b/modulefiles/tasks/hera/run_vx.local @@ -0,0 +1,5 @@ +#%Module + +module use -a /contrib/anaconda/modulefiles +module load intel/18.0.5.274 +module load anaconda/latest diff --git a/modulefiles/tasks/jet/get_extrn_ics.local b/modulefiles/tasks/jet/get_extrn_ics.local new file mode 100644 index 0000000000..4b0b48cc00 --- /dev/null +++ b/modulefiles/tasks/jet/get_extrn_ics.local @@ -0,0 +1,9 @@ +#%Module##################################################### +## Module file for get_extrn_ics task. +############################################################# + +module purge + +module load hpss + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/jet/get_extrn_lbcs.local b/modulefiles/tasks/jet/get_extrn_lbcs.local new file mode 100644 index 0000000000..477dfb2e40 --- /dev/null +++ b/modulefiles/tasks/jet/get_extrn_lbcs.local @@ -0,0 +1,9 @@ +#%Module##################################################### +## Module file for get_extrn_lbcs task. +############################################################# + +module purge + +module load hpss + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/jet/make_grid.local b/modulefiles/tasks/jet/make_grid.local new file mode 100644 index 0000000000..92505cf09c --- /dev/null +++ b/modulefiles/tasks/jet/make_grid.local @@ -0,0 +1,3 @@ +#%Module + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/jet/make_ics.local b/modulefiles/tasks/jet/make_ics.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/jet/make_ics.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/jet/make_lbcs.local b/modulefiles/tasks/jet/make_lbcs.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/jet/make_lbcs.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/jet/miniconda_regional_workflow b/modulefiles/tasks/jet/miniconda_regional_workflow new file mode 100644 index 0000000000..48de7a99bb --- /dev/null +++ b/modulefiles/tasks/jet/miniconda_regional_workflow @@ -0,0 +1,5 @@ +#%Module +module use /contrib/miniconda3/modulefiles +module load miniconda3/4.5.12 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/jet/run_fcst.local b/modulefiles/tasks/jet/run_fcst.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/jet/run_fcst.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/jet/run_vx.local b/modulefiles/tasks/jet/run_vx.local new file mode 100644 index 0000000000..9be1ed3c79 --- /dev/null +++ b/modulefiles/tasks/jet/run_vx.local @@ -0,0 +1,5 @@ +#%Module + +module use -a /contrib/anaconda/modulefiles +module load intel/18.0.5.274 +module load anaconda/5.3.1 diff --git a/modulefiles/tasks/noaacloud/get_extrn_ics.local b/modulefiles/tasks/noaacloud/get_extrn_ics.local new file mode 100644 index 0000000000..19f582feda --- /dev/null +++ b/modulefiles/tasks/noaacloud/get_extrn_ics.local @@ -0,0 +1,7 @@ +#%Module + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow + diff --git a/modulefiles/tasks/noaacloud/get_extrn_lbcs.local b/modulefiles/tasks/noaacloud/get_extrn_lbcs.local new file mode 100644 index 0000000000..6b0d974687 --- /dev/null +++ b/modulefiles/tasks/noaacloud/get_extrn_lbcs.local @@ -0,0 +1,6 @@ +#%Module + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/make_grid.local b/modulefiles/tasks/noaacloud/make_grid.local new file mode 100644 index 0000000000..a97b9e4e58 --- /dev/null +++ b/modulefiles/tasks/noaacloud/make_grid.local @@ -0,0 +1,12 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/make_ics.local b/modulefiles/tasks/noaacloud/make_ics.local new file mode 100644 index 0000000000..ea7d89b73a --- /dev/null +++ b/modulefiles/tasks/noaacloud/make_ics.local @@ -0,0 +1,14 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran +module load libpng +module load jasper + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/make_lbcs.local b/modulefiles/tasks/noaacloud/make_lbcs.local new file mode 100644 index 0000000000..ea7d89b73a --- /dev/null +++ b/modulefiles/tasks/noaacloud/make_lbcs.local @@ -0,0 +1,14 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran +module load libpng +module load jasper + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/make_orog.local b/modulefiles/tasks/noaacloud/make_orog.local new file mode 100644 index 0000000000..a97b9e4e58 --- /dev/null +++ b/modulefiles/tasks/noaacloud/make_orog.local @@ -0,0 +1,12 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/make_sfc_climo.local b/modulefiles/tasks/noaacloud/make_sfc_climo.local new file mode 100644 index 0000000000..a97b9e4e58 --- /dev/null +++ b/modulefiles/tasks/noaacloud/make_sfc_climo.local @@ -0,0 +1,12 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/miniconda_regional_workflow b/modulefiles/tasks/noaacloud/miniconda_regional_workflow new file mode 100644 index 0000000000..936a9d4c84 --- /dev/null +++ b/modulefiles/tasks/noaacloud/miniconda_regional_workflow @@ -0,0 +1,5 @@ +#%Module +module use -a /contrib/GST/miniconda3/modulefiles +module load miniconda3/4.10.3 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/run_fcst.local b/modulefiles/tasks/noaacloud/run_fcst.local new file mode 100644 index 0000000000..ea7d89b73a --- /dev/null +++ b/modulefiles/tasks/noaacloud/run_fcst.local @@ -0,0 +1,14 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran +module load libpng +module load jasper + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/noaacloud/run_post.local b/modulefiles/tasks/noaacloud/run_post.local new file mode 100644 index 0000000000..ea7d89b73a --- /dev/null +++ b/modulefiles/tasks/noaacloud/run_post.local @@ -0,0 +1,14 @@ +#%Module + +module use /contrib/spack-stack/apps/srw-app-test/modulefiles/Core +module load stack-intel +module load stack-intel-oneapi-mpi +module load netcdf-c +module load netcdf-fortran +module load libpng +module load jasper + +module load miniconda_regional_workflow +module load rocoto +prepend-path PATH /contrib/GST/miniconda/envs/regional_workflow/bin +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/odin/get_extrn_ics.local b/modulefiles/tasks/odin/get_extrn_ics.local new file mode 100644 index 0000000000..77e8616036 --- /dev/null +++ b/modulefiles/tasks/odin/get_extrn_ics.local @@ -0,0 +1,8 @@ +#%Module##################################################### +## Module file for get_extrn_ics task. +############################################################# + +#module purge + +#module load hpss + diff --git a/modulefiles/tasks/odin/get_extrn_lbcs.local b/modulefiles/tasks/odin/get_extrn_lbcs.local new file mode 100644 index 0000000000..e0b1eb8abd --- /dev/null +++ b/modulefiles/tasks/odin/get_extrn_lbcs.local @@ -0,0 +1,8 @@ +#%Module##################################################### +## Module file for get_extrn_lbcs task. +############################################################# + +#module purge + +#module load hpss + diff --git a/modulefiles/tasks/orion/get_extrn_ics.local b/modulefiles/tasks/orion/get_extrn_ics.local new file mode 100644 index 0000000000..655aa30a2c --- /dev/null +++ b/modulefiles/tasks/orion/get_extrn_ics.local @@ -0,0 +1,7 @@ +#%Module##################################################### +## Module file for get_extrn_ics task. +############################################################# + +module purge +module load miniconda_regional_workflow + diff --git a/modulefiles/tasks/orion/get_extrn_lbcs.local b/modulefiles/tasks/orion/get_extrn_lbcs.local new file mode 100644 index 0000000000..a05a15faa9 --- /dev/null +++ b/modulefiles/tasks/orion/get_extrn_lbcs.local @@ -0,0 +1,7 @@ +#%Module##################################################### +## Module file for get_extrn_lbcs task. +############################################################# + +module purge + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/orion/make_grid.local b/modulefiles/tasks/orion/make_grid.local new file mode 100644 index 0000000000..92505cf09c --- /dev/null +++ b/modulefiles/tasks/orion/make_grid.local @@ -0,0 +1,3 @@ +#%Module + +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/orion/make_ics.local b/modulefiles/tasks/orion/make_ics.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/orion/make_ics.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/orion/make_lbcs.local b/modulefiles/tasks/orion/make_lbcs.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/orion/make_lbcs.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/orion/miniconda_regional_workflow b/modulefiles/tasks/orion/miniconda_regional_workflow new file mode 100644 index 0000000000..3703a9ba17 --- /dev/null +++ b/modulefiles/tasks/orion/miniconda_regional_workflow @@ -0,0 +1,5 @@ +#%Module +module use -a /apps/contrib/miniconda3-noaa-gsl/modulefiles +module load miniconda3/3.8 + +setenv SRW_ENV regional_workflow diff --git a/modulefiles/tasks/orion/run_fcst.local b/modulefiles/tasks/orion/run_fcst.local new file mode 100644 index 0000000000..61a3a77250 --- /dev/null +++ b/modulefiles/tasks/orion/run_fcst.local @@ -0,0 +1,2 @@ +#%Module +module load miniconda_regional_workflow diff --git a/modulefiles/tasks/stampede/get_extrn_ics.local b/modulefiles/tasks/stampede/get_extrn_ics.local new file mode 100644 index 0000000000..77e8616036 --- /dev/null +++ b/modulefiles/tasks/stampede/get_extrn_ics.local @@ -0,0 +1,8 @@ +#%Module##################################################### +## Module file for get_extrn_ics task. +############################################################# + +#module purge + +#module load hpss + diff --git a/modulefiles/tasks/stampede/get_extrn_lbcs.local b/modulefiles/tasks/stampede/get_extrn_lbcs.local new file mode 100644 index 0000000000..e0b1eb8abd --- /dev/null +++ b/modulefiles/tasks/stampede/get_extrn_lbcs.local @@ -0,0 +1,8 @@ +#%Module##################################################### +## Module file for get_extrn_lbcs task. +############################################################# + +#module purge + +#module load hpss + diff --git a/scripts/exregional_get_ccpa_files.sh b/scripts/exregional_get_ccpa_files.sh new file mode 100755 index 0000000000..b0ab11f5bb --- /dev/null +++ b/scripts/exregional_get_ccpa_files.sh @@ -0,0 +1,227 @@ +#!/bin/bash + +# This script reorganizes the CCPA data into a more intuitive structure: +# A valid YYYYMMDD directory is created, and all files for the valid day are placed within the directory. +# Supported accumulations: 01h, 03h, and 06h. NOTE: Accumulation is currently hardcoded to 01h. +# The verification uses MET/pcp-combine to sum 01h files into desired accumulations. + +# Top-level CCPA directory +ccpa_dir=${OBS_DIR}/.. +if [[ ! -d "$ccpa_dir" ]]; then + mkdir -p $ccpa_dir +fi + +# CCPA data from HPSS +ccpa_raw=$ccpa_dir/raw +if [[ ! -d "$ccpa_raw" ]]; then + mkdir -p $ccpa_raw +fi + +# Reorganized CCPA location +ccpa_proc=$ccpa_dir/proc +if [[ ! -d "$ccpa_proc" ]]; then + mkdir -p $ccpa_proc +fi + +# Accumulation is for accumulation of CCPA data to pull (hardcoded to 01h, see note above.) +#accum=${ACCUM} +accum=01 + +# Initialization +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh + +init=${CDATE}${hh} + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` + +# Forecast length +fcst_length=${fhr_last} + +current_fcst=$accum +while [[ ${current_fcst} -le ${fcst_length} ]]; do + # Calculate valid date info + fcst_sec=`expr ${current_fcst} \* 3600` # convert forecast lead hour to seconds + yyyy=`echo ${init} | cut -c1-4` # year (YYYY) of initialization time + mm=`echo ${init} | cut -c5-6` # month (MM) of initialization time + dd=`echo ${init} | cut -c7-8` # day (DD) of initialization time + hh=`echo ${init} | cut -c9-10` # hour (HH) of initialization time + init_ut=`$DATE_UTIL -ud ''${yyyy}-${mm}-${dd}' UTC '${hh}':00:00' +%s` # convert initialization time to universal time + vdate_ut=`expr ${init_ut} + ${fcst_sec}` # calculate current forecast time in universal time + vdate=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd=`echo ${vdate} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy=`echo ${vdate} | cut -c1-4` # year (YYYY) of valid time + vmm=`echo ${vdate} | cut -c5-6` # month (MM) of valid time + vdd=`echo ${vdate} | cut -c7-8` # day (DD) of valid time + vhh=`echo ${vdate} | cut -c9-10` # forecast hour (HH) + + vhh_noZero=$(expr ${vhh} + 0) + + # Calculate valid date - 1 day + vdate_ut_m1=`expr ${vdate_ut} - 86400` + vdate_m1=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_m1}' seconds' +%Y%m%d%H` + vyyyymmdd_m1=`echo ${vdate_m1} | cut -c1-8` + vyyyy_m1=`echo ${vdate_m1} | cut -c1-4` + vmm_m1=`echo ${vdate_m1} | cut -c5-6` + vdd_m1=`echo ${vdate_m1} | cut -c7-8` + vhh_m1=`echo ${vdate_m1} | cut -c9-10` + + # Calculate valid date + 1 day + vdate_ut_p1=`expr ${vdate_ut} + 86400` + vdate_p1=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_p1}' seconds' +%Y%m%d%H` + vyyyymmdd_p1=`echo ${vdate_p1} | cut -c1-8` + vyyyy_p1=`echo ${vdate_p1} | cut -c1-4` + vmm_p1=`echo ${vdate_p1} | cut -c5-6` + vdd_p1=`echo ${vdate_p1} | cut -c7-8` + vhh_p1=`echo ${vdate_p1} | cut -c9-10` + + # Create necessary raw and prop directories + if [[ ! -d "$ccpa_raw/${vyyyymmdd}" ]]; then + mkdir -p $ccpa_raw/${vyyyymmdd} + fi + + if [[ ! -d "$ccpa_raw/${vyyyymmdd_m1}" ]]; then + mkdir -p $ccpa_raw/${vyyyymmdd_m1} + fi + + if [[ ! -d "$ccpa_raw/${vyyyymmdd_p1}" ]]; then + mkdir -p $ccpa_raw/${vyyyymmdd_p1} + fi + + if [[ ! -d "$ccpa_proc/${vyyyymmdd}" ]]; then + mkdir -p $ccpa_proc/${vyyyymmdd} + fi + + # Name of CCPA tar file on HPSS is dependent on date. Logic accounts for files from 2019 until Sept. 2020. + if [[ ${vyyyymmdd} -ge 20190101 && ${vyyyymmdd} -lt 20190812 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/com2_ccpa_prod_ccpa.${vyyyy}${vmm}${vdd}.tar" + fi + + if [[ ${vyyyymmdd_m1} -ge 20190101 && ${vyyyymmdd_m1} -lt 20190812 ]]; then + TarFile_m1="/NCEPPROD/hpssprod/runhistory/rh${vyyyy_m1}/${vyyyy_m1}${vmm_m1}/${vyyyy_m1}${vmm_m1}${vdd_m1}/com2_ccpa_prod_ccpa.${vyyyy_m1}${vmm_m1}${vdd_m1}.tar" + fi + + if [[ ${vyyyymmdd_p1} -ge 20190101 && ${vyyyymmdd_p1} -lt 20190812 ]]; then + TarFile_p1="/NCEPPROD/hpssprod/runhistory/rh${vyyyy_p1}/${vyyyy_p1}${vmm_p1}/${vyyyy_p1}${vmm_p1}${vdd_p1}/com2_ccpa_prod_ccpa.${vyyyy_p1}${vmm_p1}${vdd_p1}.tar" + fi + + if [[ ${vyyyymmdd} -ge 20190812 && ${vyyyymmdd} -le 20200217 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/gpfs_dell1_nco_ops_com_ccpa_prod_ccpa.${vyyyy}${vmm}${vdd}.tar" + fi + + if [[ ${vyyyymmdd_m1} -ge 20190812 && ${vyyyymmdd_m1} -le 20200217 ]]; then + TarFile_m1="/NCEPPROD/hpssprod/runhistory/rh${vyyyy_m1}/${vyyyy_m1}${vmm_m1}/${vyyyy_m1}${vmm_m1}${vdd_m1}/gpfs_dell1_nco_ops_com_ccpa_prod_ccpa.${vyyyy_m1}${vmm_m1}${vdd_m1}.tar" + fi + + if [[ ${vyyyymmdd_p1} -ge 20190812 && ${vyyyymmdd_p1} -le 20200217 ]]; then + TarFile_p1="/NCEPPROD/hpssprod/runhistory/rh${vyyyy_p1}/${vyyyy_p1}${vmm_p1}/${vyyyy_p1}${vmm_p1}${vdd_p1}/gpfs_dell1_nco_ops_com_ccpa_prod_ccpa.${vyyyy_p1}${vmm_p1}${vdd_p1}.tar" + fi + + if [[ ${vyyyymmdd} -gt 20200217 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/com_ccpa_prod_ccpa.${vyyyy}${vmm}${vdd}.tar" + fi + + if [[ ${vyyyymmdd_m1} -gt 20200217 ]]; then + TarFile_m1="/NCEPPROD/hpssprod/runhistory/rh${vyyyy_m1}/${vyyyy_m1}${vmm_m1}/${vyyyy_m1}${vmm_m1}${vdd_m1}/com_ccpa_prod_ccpa.${vyyyy_m1}${vmm_m1}${vdd_m1}.tar" + fi + + if [[ ${vyyyymmdd_p1} -gt 20200217 ]]; then + TarFile_p1="/NCEPPROD/hpssprod/runhistory/rh${vyyyy_p1}/${vyyyy_p1}${vmm_p1}/${vyyyy_p1}${vmm_p1}${vdd_p1}/com_ccpa_prod_ccpa.${vyyyy_p1}${vmm_p1}${vdd_p1}.tar" + fi + + # Check if file exists on disk; if not, pull it. + ccpa_file="$ccpa_proc/${vyyyymmdd}/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2" + echo "CCPA FILE:${ccpa_file}" + if [[ ! -f "${ccpa_file}" ]]; then + if [[ ${accum} == "01" ]]; then + # Check if valid hour is 00 + if [[ ${vhh_noZero} -ge 19 && ${vhh_noZero} -le 23 ]]; then + cd $ccpa_raw/${vyyyymmdd_p1} + # Pull CCPA data from HPSS + TarCommand="htar -xvf ${TarFile_p1} \`htar -tf ${TarFile_p1} | egrep \"ccpa.t${vhh}z.${accum}h.hrap.conus.gb2\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile_p1} `htar -tf ${TarFile_p1} | egrep "ccpa.t${vhh}z.${accum}h.hrap.conus.gb2" | awk '{print $7}'` + else + cd $ccpa_raw/${vyyyymmdd} + # Pull CCPA data from HPSS + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"ccpa.t${vhh}z.${accum}h.hrap.conus.gb2\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "ccpa.t${vhh}z.${accum}h.hrap.conus.gb2" | awk '{print $7}'` + fi + + # One hour CCPA files have incorrect metadeta in the files under the "00" directory from 20180718 to 20210504. + # After data is pulled, reorganize into correct valid yyyymmdd structure. + if [[ ${vhh_noZero} -ge 1 && ${vhh_noZero} -le 6 ]]; then + cp $ccpa_raw/${vyyyymmdd}/06/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -ge 7 && ${vhh_noZero} -le 12 ]]; then + cp $ccpa_raw/${vyyyymmdd}/12/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -ge 13 && ${vhh_noZero} -le 18 ]]; then + cp $ccpa_raw/${vyyyymmdd}/18/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -ge 19 && ${vhh_noZero} -le 23 ]]; then + if [[ ${vyyyymmdd} -ge 20180718 && ${vyyyymmdd} -le 20210504 ]]; then + wgrib2 $ccpa_raw/${vyyyymmdd_p1}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 -set_date -24hr -grib $ccpa_proc/${vyyyymmdd}/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 -s + else + cp $ccpa_raw/${vyyyymmdd_p1}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + fi + elif [[ ${vhh_noZero} -eq 0 ]]; then + if [[ ${vyyyymmdd} -ge 20180718 && ${vyyyymmdd} -le 20210504 ]]; then + wgrib2 $ccpa_raw/${vyyyymmdd}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 -set_date -24hr -grib $ccpa_proc/${vyyyymmdd}/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 -s + else + cp $ccpa_raw/${vyyyymmdd}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + fi + fi + + elif [[ ${accum} == "03" ]]; then + # Check if valid hour is 21 + if [[ ${vhh_noZero} -ne 21 ]]; then + cd $ccpa_raw/${vyyyymmdd} + # Pull CCPA data from HPSS + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"ccpa.t${vhh}z.${accum}h.hrap.conus.gb2\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "ccpa.t${vhh}z.${accum}h.hrap.conus.gb2" | awk '{print $7}'` + elif [[ ${vhh_noZero} -eq 21 ]]; then + cd $ccpa_raw/${vyyyymmdd_p1} + # Pull CCPA data from HPSS + TarCommand="htar -xvf ${TarFile_p1} \`htar -tf ${TarFile_p1} | egrep \"ccpa.t${vhh}z.${accum}h.hrap.conus.gb2\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile_p1} `htar -tf ${TarFile_p1} | egrep "ccpa.t${vhh}z.${accum}h.hrap.conus.gb2" | awk '{print $7}'` + fi + + if [[ ${vhh_noZero} -eq 0 ]]; then + cp $ccpa_raw/${vyyyymmdd}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 3 || ${vhh_noZero} -eq 6 ]]; then + cp $ccpa_raw/${vyyyymmdd}/06/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 9 || ${vhh_noZero} -eq 12 ]]; then + cp $ccpa_raw/${vyyyymmdd}/12/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 15 || ${vhh_noZero} -eq 18 ]]; then + cp $ccpa_raw/${vyyyymmdd}/18/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 21 ]]; then + cp $ccpa_raw/${vyyyymmdd_p1}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + fi + + elif [[ ${accum} == "06" ]]; then + cd $ccpa_raw/${vyyyymmdd} + # Pull CCPA data from HPSS + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"ccpa.t${vhh}z.${accum}h.hrap.conus.gb2\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "ccpa.t${vhh}z.${accum}h.hrap.conus.gb2" | awk '{print $7}'` + + if [[ ${vhh_noZero} -eq 0 ]]; then + cp $ccpa_raw/${vyyyymmdd}/00/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 6 ]]; then + cp $ccpa_raw/${vyyyymmdd}/06/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 12 ]]; then + cp $ccpa_raw/${vyyyymmdd}/12/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + elif [[ ${vhh_noZero} -eq 18 ]]; then + cp $ccpa_raw/${vyyyymmdd}/18/ccpa.t${vhh}z.${accum}h.hrap.conus.gb2 $ccpa_proc/${vyyyymmdd} + fi + fi + fi + + # Increment to next forecast hour + current_fcst=$((${current_fcst} + ${accum})) + echo "Current fcst hr=${current_fcst}" + +done + diff --git a/scripts/exregional_get_extrn_mdl_files.sh b/scripts/exregional_get_extrn_mdl_files.sh new file mode 100755 index 0000000000..5a3fe04cf3 --- /dev/null +++ b/scripts/exregional_get_extrn_mdl_files.sh @@ -0,0 +1,183 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that copies or fetches external model +input data from disk, HPSS, or a URL, and stages them to the +workflow-specified location so that they may be used to generate initial +or lateral boundary conditions for the FV3. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. Then +# process the arguments provided to this script/function (which should +# consist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ +"extrn_mdl_cdate" \ +"extrn_mdl_name" \ +"extrn_mdl_staging_dir" \ +"time_offset_hrs" \ +) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args + + +# +#----------------------------------------------------------------------- +# +# Set up variables for call to retrieve_data.py +# +#----------------------------------------------------------------------- +# +set -x +if [ "${ICS_OR_LBCS}" = "ICS" ]; then + if [ ${time_offset_hrs} -eq 0 ] ; then + anl_or_fcst="anl" + else + anl_or_fcst="fcst" + fi + fcst_hrs=${time_offset_hrs} + file_names=${EXTRN_MDL_FILES_ICS[@]} + if [ ${extrn_mdl_name} = FV3GFS ] ; then + file_type=$FV3GFS_FILE_FMT_ICS + fi + input_file_path=${EXTRN_MDL_SOURCE_BASEDIR_ICS:-$EXTRN_MDL_SYSBASEDIR_ICS} + +elif [ "${ICS_OR_LBCS}" = "LBCS" ]; then + anl_or_fcst="fcst" + first_time=$((time_offset_hrs + LBC_SPEC_INTVL_HRS)) + last_time=$((time_offset_hrs + FCST_LEN_HRS)) + fcst_hrs="${first_time} ${last_time} ${LBC_SPEC_INTVL_HRS}" + file_names=${EXTRN_MDL_FILES_LBCS[@]} + if [ ${extrn_mdl_name} = FV3GFS ] ; then + file_type=$FV3GFS_FILE_FMT_LBCS + fi + input_file_path=${EXTRN_MDL_SOURCE_BASEDIR_LBCS:-$EXTRN_MDL_SYSBASEDIR_LBCS} +fi + +data_stores="${EXTRN_MDL_DATA_STORES}" + +yyyymmddhh=${extrn_mdl_cdate:0:10} +yyyy=${yyyymmddhh:0:4} +yyyymm=${yyyymmddhh:0:6} +yyyymmdd=${yyyymmddhh:0:8} +mm=${yyyymmddhh:4:2} +dd=${yyyymmddhh:6:2} +hh=${yyyymmddhh:8:2} + + +input_file_path=$(eval echo ${input_file_path}) +# +#----------------------------------------------------------------------- +# +# Set up optional flags for calling retrieve_data.py +# +#----------------------------------------------------------------------- +# +additional_flags="" + + +if [ -n "${file_type:-}" ] ; then + additional_flags="$additional_flags \ + --file_type ${file_type}" +fi + +if [ -n "${file_names:-}" ] ; then + additional_flags="$additional_flags \ + --file_templates ${file_names[@]}" +fi + +if [ -n "${input_file_path:-}" ] ; then + data_stores="disk $data_stores" + additional_flags="$additional_flags \ + --input_file_path ${input_file_path}" +fi + +# +#----------------------------------------------------------------------- +# +# Call ush script to retrieve files +# +#----------------------------------------------------------------------- +# +cmd=" +python3 -u ${USHDIR}/retrieve_data.py \ + --debug \ + --anl_or_fcst ${anl_or_fcst} \ + --config ${USHDIR}/templates/data_locations.yml \ + --cycle_date ${extrn_mdl_cdate} \ + --data_stores ${data_stores} \ + --external_model ${extrn_mdl_name} \ + --fcst_hrs ${fcst_hrs[@]} \ + --output_path ${extrn_mdl_staging_dir} \ + --summary_file ${EXTRN_MDL_VAR_DEFNS_FN} \ + $additional_flags" + +$cmd || print_err_msg_exit "\ +Call to retrieve_data.py failed with a non-zero exit status. + +The command was: +${cmd} +" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/function. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/scripts/exregional_get_mrms_files.sh b/scripts/exregional_get_mrms_files.sh new file mode 100755 index 0000000000..d0abf8f9bb --- /dev/null +++ b/scripts/exregional_get_mrms_files.sh @@ -0,0 +1,141 @@ +#!/bin/bash + +. ${GLOBAL_VAR_DEFNS_FP} + +# This script pulls MRMS data from the NOAA HPSS +# Top-level MRMS directory +set -x +mrms_dir=${OBS_DIR}/.. +if [[ ! -d "$mrms_dir" ]]; then + mkdir -p $mrms_dir +fi + +# MRMS data from HPSS +mrms_raw=$mrms_dir/raw +if [[ ! -d "$mrms_raw" ]]; then + mkdir -p $mrms_raw +fi + +# Reorganized MRMS location +mrms_proc=$mrms_dir/proc +if [[ ! -d "$mrms_proc" ]]; then + mkdir -p $mrms_proc +fi + +# Initialization +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh + +start_valid=${CDATE}${hh} + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` + +# Forecast length +fcst_length=${fhr_last} + +s_yyyy=`echo ${start_valid} | cut -c1-4` # year (YYYY) of start time +s_mm=`echo ${start_valid} | cut -c5-6` # month (MM) of start time +s_dd=`echo ${start_valid} | cut -c7-8` # day (DD) of start time +s_hh=`echo ${start_valid} | cut -c9-10` # hour (HH) of start time +start_valid_ut=`$DATE_UTIL -ud ''${s_yyyy}-${s_mm}-${s_dd}' UTC '${s_hh}':00:00' +%s` # convert start time to universal time + +end_fcst_sec=`expr ${fcst_length} \* 3600` # convert last forecast lead hour to seconds +end_valid_ut=`expr ${start_valid_ut} + ${end_fcst_sec}` # calculate current forecast time in universal time + +cur_ut=${start_valid_ut} +current_fcst=0 +fcst_sec=`expr ${current_fcst} \* 3600` # convert forecast lead hour to seconds + +while [[ ${cur_ut} -le ${end_valid_ut} ]]; do + cur_time=`$DATE_UTIL -ud '1970-01-01 UTC '${cur_ut}' seconds' +%Y%m%d%H` # convert universal time to standard time + echo "cur_time=${cur_time}" + + # Calculate valid date info + vyyyy=`echo ${cur_time} | cut -c1-4` # year (YYYY) of time + vmm=`echo ${cur_time} | cut -c5-6` # month (MM) of time + vdd=`echo ${cur_time} | cut -c7-8` # day (DD) of time + vhh=`echo ${cur_time} | cut -c9-10` # hour (HH) of time + vyyyymmdd=`echo ${cur_time} | cut -c1-8` # YYYYMMDD of time + vinit_ut=`$DATE_UTIL -ud ''${vyyyy}-${vmm}-${vdd}' UTC '${vhh}':00:00' +%s` # convert time to universal time + + # Create necessary raw and proc directories + if [[ ! -d "$mrms_raw/${vyyyymmdd}" ]]; then + mkdir -p $mrms_raw/${vyyyymmdd} + fi + + # Set field of interest from the MRMS products, including name and level information. + if [ "${field}" = "REFC" ]; then + #field_base_name="MergedReflectivityQComposite" + #level="_00.00_" + field_base_name="MergedReflectivityQCComposite" + level="_00.50_" + elif [ "${field}" = "RETOP" ]; then + field_base_name="EchoTop" + level="_18_00.50_" + else + echo "Field is not set to REFC or RETOP" + fi + + # Check if file exists on disk; if not, pull it. + mrms_file="$mrms_proc/${vyyyymmdd}/${field_base_name}${level}${vyyyy}${vmm}${vdd}-${vhh}0000.grib2" + echo "MRMS FILE:${mrms_file}" + + if [[ ! -f "${mrms_file}" ]]; then + cd $mrms_raw/${vyyyymmdd} + + # Name of MRMS tar file on HPSS is dependent on date. Logic accounts for files from 2019 until Sept. 2020. + if [[ ${vyyyymmdd} -ge 20190101 && ${vyyyymmdd} -lt 20200303 ]]; then + CheckFile=`hsi "ls -1 /NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/ldmdata.gyre.${vyyyy}${vmm}${vdd}.tar" >& /dev/null` + Status=$? + if [[ ${Status} == 0 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/ldmdata.gyre.${vyyyy}${vmm}${vdd}.tar" + else + CheckFile=`hsi "ls -1 /NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/ldmdata.tide.${vyyyy}${vmm}${vdd}.tar" >& /dev/null` + Status=$? + if [[ ${Status} == 0 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/ldmdata.tide.${vyyyy}${vmm}${vdd}.tar" + else + echo "ERROR: MRMS data not available for ${vyyyy}${vmm}${vdd}!" + exit + fi + fi + fi + + if [[ ${vyyyymmdd} -ge 20200303 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/dcom_prod_ldmdata_obs.tar" + fi + + echo "TAR FILE:${TarFile}" + + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"${field_base_name}${level}${vyyyy}${vmm}${vdd}-[0-9][0-9][0-9][0-9][0-9][0-9].grib2.gz\" | awk '{print $7}'\`" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "${field_base_name}${level}${vyyyy}${vmm}${vdd}-[0-9][0-9][0-9][0-9][0-9][0-9].grib2.gz" | awk '{print $7}'` + Status=$? + + if [[ ${Status} != 0 ]]; then + echo "WARNING: Bad return status (${Status}) for date \"${CurDate}\". Did you forget to run \"module load hpss\"?" + echo "WARNING: ${TarCommand}" + exit ${Status} + else + if [[ ! -d "$mrms_proc/${vyyyymmdd}" ]]; then + mkdir -p $mrms_proc/${vyyyymmdd} + fi + + hour=0 + while [[ ${hour} -le 23 ]]; do + echo "hour=${hour}" + python ${USHDIR}/mrms_pull_topofhour.py ${vyyyy}${vmm}${vdd}${hour} ${mrms_proc} ${mrms_raw} ${field_base_name} ${level} + hour=$((${hour} + 1)) # hourly increment + done + fi + + else + echo "mrms_file exists: \"$mrms_proc/${vyyyymmdd}/${field_base_name}${level}${vyyyy}${vmm}${vdd}-${vhh}0000.grib2\" No work to be done." + fi + + # Increment + current_fcst=$((${current_fcst} + 1)) # hourly increment + fcst_sec=`expr ${current_fcst} \* 3600` # convert forecast lead hour to seconds + cur_ut=`expr ${start_valid_ut} + ${fcst_sec}` + +done diff --git a/scripts/exregional_get_ndas_files.sh b/scripts/exregional_get_ndas_files.sh new file mode 100755 index 0000000000..0105f2edb0 --- /dev/null +++ b/scripts/exregional_get_ndas_files.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +# This script reorganizes the NDAS data into a more intuitive structure: +# A valid YYYYMMDD directory is created, and all files for the valid day are placed within the directory. + +# Top-level NDAS directory +ndas_dir=${OBS_DIR}/.. +if [[ ! -d "$ndas_dir" ]]; then + mkdir -p $ndas_dir +fi + +# NDAS data from HPSS +ndas_raw=$ndas_dir/raw +if [[ ! -d "$ndas_raw" ]]; then + mkdir -p $ndas_raw +fi + +# Reorganized NDAS location +ndas_proc=$ndas_dir/proc +if [[ ! -d "$ndas_proc" ]]; then + mkdir -p $ndas_proc +fi + +# Initialization +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh + +init=${CDATE}${hh} + +# Forecast length +fhr_last=`echo ${FHR} | awk '{ print $NF }'` + +fcst_length=${fhr_last} + +current_fcst=00 +while [[ ${current_fcst} -le ${fcst_length} ]]; do + fcst_sec=`expr ${current_fcst} \* 3600` # convert forecast lead hour to seconds + yyyy=`echo ${init} | cut -c1-4` # year (YYYY) of initialization time + mm=`echo ${init} | cut -c5-6` # month (MM) of initialization time + dd=`echo ${init} | cut -c7-8` # day (DD) of initialization time + hh=`echo ${init} | cut -c9-10` # hour (HH) of initialization time + init_ut=`$DATE_UTIL -ud ''${yyyy}-${mm}-${dd}' UTC '${hh}':00:00' +%s` # convert initialization time to universal time + vdate_ut=`expr ${init_ut} + ${fcst_sec}` # calculate current forecast time in universal time + vdate=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd=`echo ${vdate} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy=`echo ${vdate} | cut -c1-4` # year (YYYY) of valid time + vmm=`echo ${vdate} | cut -c5-6` # month (MM) of valid time + vdd=`echo ${vdate} | cut -c7-8` # day (DD) of valid time + vhh=`echo ${vdate} | cut -c9-10` # forecast hour (HH) + +echo "yyyy mm dd hh= $yyyy $mm $dd $hh" +echo "vyyyy vmm vdd vhh= $vyyyy $vmm $vdd $vhh" + + vdate_ut_m1h=`expr ${vdate_ut} - 3600` # calculate current forecast time in universal time + vdate_m1h=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_m1h}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd_m1h=`echo ${vdate_m1h} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy_m1h=`echo ${vdate_m1h} | cut -c1-4` # year (YYYY) of valid time + vmm_m1h=`echo ${vdate_m1h} | cut -c5-6` # month (MM) of valid time + vdd_m1h=`echo ${vdate_m1h} | cut -c7-8` # day (DD) of valid time + vhh_m1h=`echo ${vdate_m1h} | cut -c9-10` # forecast hour (HH) + + vdate_ut_m2h=`expr ${vdate_ut} - 7200` # calculate current forecast time in universal time + vdate_m2h=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_m2h}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd_m2h=`echo ${vdate_m2h} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy_m2h=`echo ${vdate_m2h} | cut -c1-4` # year (YYYY) of valid time + vmm_m2h=`echo ${vdate_m2h} | cut -c5-6` # month (MM) of valid time + vdd_m2h=`echo ${vdate_m2h} | cut -c7-8` # day (DD) of valid time + vhh_m2h=`echo ${vdate_m2h} | cut -c9-10` # forecast hour (HH) + + vdate_ut_m3h=`expr ${vdate_ut} - 10800` # calculate current forecast time in universal time + vdate_m3h=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_m3h}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd_m3h=`echo ${vdate_m3h} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy_m3h=`echo ${vdate_m3h} | cut -c1-4` # year (YYYY) of valid time + vmm_m3h=`echo ${vdate_m3h} | cut -c5-6` # month (MM) of valid time + vdd_m3h=`echo ${vdate_m3h} | cut -c7-8` # day (DD) of valid time + vhh_m3h=`echo ${vdate_m3h} | cut -c9-10` # forecast hour (HH) + + vdate_ut_m4h=`expr ${vdate_ut} - 14400` # calculate current forecast time in universal time + vdate_m4h=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_m4h}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd_m4h=`echo ${vdate_m4h} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy_m4h=`echo ${vdate_m4h} | cut -c1-4` # year (YYYY) of valid time + vmm_m4h=`echo ${vdate_m4h} | cut -c5-6` # month (MM) of valid time + vdd_m4h=`echo ${vdate_m4h} | cut -c7-8` # day (DD) of valid time + vhh_m4h=`echo ${vdate_m4h} | cut -c9-10` # forecast hour (HH) + + vdate_ut_m5h=`expr ${vdate_ut} - 18000` # calculate current forecast time in universal time + vdate_m5h=`$DATE_UTIL -ud '1970-01-01 UTC '${vdate_ut_m5h}' seconds' +%Y%m%d%H` # convert universal time to standard time + vyyyymmdd_m5h=`echo ${vdate_m5h} | cut -c1-8` # forecast time (YYYYMMDD) + vyyyy_m5h=`echo ${vdate_m5h} | cut -c1-4` # year (YYYY) of valid time + vmm_m5h=`echo ${vdate_m5h} | cut -c5-6` # month (MM) of valid time + vdd_m5h=`echo ${vdate_m5h} | cut -c7-8` # day (DD) of valid time + vhh_m5h=`echo ${vdate_m5h} | cut -c9-10` # forecast hour (HH) + + vhh_noZero=$(expr ${vhh} + 0) + +echo "vyyyymmdd_m1h vhh_m1h=$vyyyymmdd_m1h $vhh_m1h" +echo "vhh_noZero=$vhh_noZero" + + # Check if file exists on disk + ndas_file="$ndas_proc/prepbufr.ndas.${vyyyymmdd}${vhh}" + echo "NDAS PB FILE:${ndas_file}" + + if [[ ! -f "${ndas_file}" ]]; then + if [[ ! -d "$ndas_raw/${vyyyymmdd}${vhh}" ]]; then + mkdir -p $ndas_raw/${vyyyymmdd}${vhh} + fi + cd $ndas_raw/${vyyyymmdd}${vhh} + + # Name of NDAS tar file on HPSS is dependent on date. Logic accounts for files from 2019 until July 2020. + if [[ ${vyyyymmdd} -ge 20190101 && ${vyyyymmdd} -le 20190820 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/com2_nam_prod_nam.${vyyyy}${vmm}${vdd}${vhh}.bufr.tar" + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"prepbufr.tm[0-9][0-9].nr\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "prepbufr.tm[0-9][0-9].nr" | awk '{print $7}'` + elif [[ ${vyyyymmdd} -ge 20190821 && ${vyyyymmdd} -le 20200226 ]]; then + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/gpfs_dell1_nco_ops_com_nam_prod_nam.${vyyyy}${vmm}${vdd}${vhh}.bufr.tar" + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"prepbufr.tm[0-9][0-9].nr\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "prepbufr.tm[0-9][0-9].nr" | awk '{print $7}'` + else + TarFile="/NCEPPROD/hpssprod/runhistory/rh${vyyyy}/${vyyyy}${vmm}/${vyyyy}${vmm}${vdd}/com_nam_prod_nam.${vyyyy}${vmm}${vdd}${vhh}.bufr.tar" + TarCommand="htar -xvf ${TarFile} \`htar -tf ${TarFile} | egrep \"prepbufr.tm[0-9][0-9].nr\" | awk '{print $7}'\`" + echo "CALLING: ${TarCommand}" + htar -xvf ${TarFile} `htar -tf ${TarFile} | egrep "prepbufr.tm[0-9][0-9].nr" | awk '{print $7}'` + fi + + if [[ ! -d "$ndas_proc" ]]; then + mkdir -p $ndas_proc + fi + + if [[ ${vhh_noZero} -eq 0 || ${vhh} -eq 6 || ${vhh} -eq 12 || ${vhh} -eq 18 ]]; then + #echo "$ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm00.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd}${vhh}" + cp $ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm00.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd}${vhh} + cp $ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm01.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd_m1h}${vhh_m1h} + cp $ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm02.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd_m2h}${vhh_m2h} + cp $ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm03.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd_m3h}${vhh_m3h} + cp $ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm04.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd_m4h}${vhh_m4h} + cp $ndas_raw/${vyyyymmdd}${vhh}/nam.t${vhh}z.prepbufr.tm05.nr $ndas_proc/prepbufr.ndas.${vyyyymmdd_m5h}${vhh_m5h} + fi + fi + current_fcst=$((${current_fcst} + 6)) + echo "new fcst=${current_fcst}" + +done diff --git a/scripts/exregional_make_grid.sh b/scripts/exregional_make_grid.sh new file mode 100755 index 0000000000..bc3bca1aba --- /dev/null +++ b/scripts/exregional_make_grid.sh @@ -0,0 +1,638 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Source other necessary files. +# +#----------------------------------------------------------------------- +# +. $USHDIR/make_grid_mosaic_file.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that generates grid files. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. Then +# process the arguments provided to this script/function (which should +# consist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# +valid_args=() +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set the machine-dependent run command. Also, set resource limits as +# necessary. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +if [ -z "${RUN_CMD_SERIAL:-}" ] ; then + print_err_msg_exit " \ + Run command was not set in machine file. \ + Please set RUN_CMD_SERIAL for your platform" +else + RUN_CMD_SERIAL=$(eval echo ${RUN_CMD_SERIAL}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_SERIAL}\'." +fi +# +#----------------------------------------------------------------------- +# +# Create the (cycle-independent) subdirectories under the experiment +# directory (EXPTDIR) that are needed by the various steps and substeps +# in this script. +# +#----------------------------------------------------------------------- +# +check_for_preexist_dir_file "${GRID_DIR}" "${PREEXISTING_DIR_METHOD}" +mkdir_vrfy -p "${GRID_DIR}" + +tmpdir="${GRID_DIR}/tmp" +mkdir_vrfy -p "$tmpdir" +# +#----------------------------------------------------------------------- +# +# Generate grid files. +# +# The following will create 7 grid files (one per tile, where the 7th +# "tile" is the grid that covers the regional domain) named +# +# ${CRES}_grid.tileN.nc for N=1,...,7. +# +# It will also create a mosaic file named ${CRES}_mosaic.nc that con- +# tains information only about tile 7 (i.e. it does not have any infor- +# mation on how tiles 1 through 6 are connected or that tile 7 is within +# tile 6). All these files will be placed in the directory specified by +# GRID_DIR. Note that the file for tile 7 will include a halo of width +# NHW cells. +# +# Since tiles 1 through 6 are not needed to run the FV3-LAM model and are +# not used later on in any other preprocessing steps, it is not clear +# why they are generated. It might be because it is not possible to di- +# rectly generate a standalone regional grid using the make_hgrid uti- +# lity/executable that grid_gen_scr calls, i.e. it might be because with +# make_hgrid, one has to either create just the 6 global tiles or create +# the 6 global tiles plus the regional (tile 7), and then for the case +# of a regional simulation (i.e. GTYPE="regional", which is always the +# case here) just not use the 6 global tiles. +# +# The grid_gen_scr script called below takes its next-to-last argument +# and passes it as an argument to the --halo flag of the make_hgrid uti- +# lity/executable. make_hgrid then checks that a regional (or nested) +# grid of size specified by the arguments to its --istart_nest, --iend_- +# nest, --jstart_nest, and --jend_nest flags with a halo around it of +# size specified by the argument to the --halo flag does not extend be- +# yond the boundaries of the parent grid (tile 6). In this case, since +# the values passed to the --istart_nest, ..., and --jend_nest flags al- +# ready include a halo (because these arguments are +# +# ${ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG}, +# ${IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG}, +# ${JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG}, and +# ${JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG}, +# +# i.e. they include "WITH_WIDE_HALO_" in their names), it is reasonable +# to pass as the argument to --halo a zero. However, make_hgrid re- +# quires that the argument to --halo be at least 1, so below, we pass a +# 1 as the next-to-last argument to grid_gen_scr. +# +# More information on make_hgrid: +# ------------------------------ +# +# The grid_gen_scr called below in turn calls the make_hgrid executable +# as follows: +# +# make_hgrid \ +# --grid_type gnomonic_ed \ +# --nlon 2*${RES} \ +# --grid_name C${RES}_grid \ +# --do_schmidt --stretch_factor ${STRETCH_FAC} \ +# --target_lon ${LON_CTR} +# --target_lat ${LAT_CTR} \ +# --nest_grid --parent_tile 6 --refine_ratio ${GFDLgrid_REFINE_RATIO} \ +# --istart_nest ${ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ +# --jstart_nest ${JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ +# --iend_nest ${IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ +# --jend_nest ${JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ +# --halo ${NH3} \ +# --great_circle_algorithm +# +# This creates the 7 grid files ${CRES}_grid.tileN.nc for N=1,...,7. +# The 7th file ${CRES}_grid.tile7.nc represents the regional grid, and +# the extents of the arrays in that file do not seem to include a halo, +# i.e. they are based only on the values passed via the four flags +# +# --istart_nest ${ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} +# --jstart_nest ${JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} +# --iend_nest ${IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} +# --jend_nest ${JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} +# +# According to Rusty Benson of GFDL, the flag +# +# --halo ${NH3} +# +# only checks to make sure that the nested or regional grid combined +# with the specified halo lies completely within the parent tile. If +# so, make_hgrid issues a warning and exits. Thus, the --halo flag is +# not meant to be used to add a halo region to the nested or regional +# grid whose limits are specified by the flags --istart_nest, --iend_- +# nest, --jstart_nest, and --jend_nest. +# +# Note also that make_hgrid has an --out_halo option that, according to +# the documentation, is meant to output extra halo cells around the +# nested or regional grid boundary in the file generated by make_hgrid. +# However, according to Rusty Benson of GFDL, this flag was originally +# created for a special purpose and is limited to only outputting at +# most 1 extra halo point. Thus, it should not be used. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Generate grid file. +# +#----------------------------------------------------------------------- +# +# Set the name and path to the executable that generates the grid file +# and make sure that it exists. +# +if [ "${GRID_GEN_METHOD}" = "GFDLgrid" ]; then + exec_fn="make_hgrid" +elif [ "${GRID_GEN_METHOD}" = "ESGgrid" ]; then + exec_fn="regional_esg_grid" +fi + +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for generating the grid file does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi +# +# Change location to the temporary (work) directory. +# +cd_vrfy "$tmpdir" + +print_info_msg "$VERBOSE" " +Starting grid file generation..." +# +# Generate a GFDLgrid-type of grid. +# +if [ "${GRID_GEN_METHOD}" = "GFDLgrid" ]; then +# +# Set local variables needed in the call to the executable that generates +# a GFDLgrid-type grid. +# + nx_t6sg=$(( 2*GFDLgrid_NUM_CELLS )) + grid_name="${GRID_GEN_METHOD}" +# +# Call the executable that generates the grid file. Note that this call +# will generate a file not only the regional grid (tile 7) but also files +# for the 6 global tiles. However, after this call we will only need the +# regional grid file. +# + $RUN_CMD_SERIAL ${exec_fp} \ + --grid_type gnomonic_ed \ + --nlon ${nx_t6sg} \ + --grid_name ${grid_name} \ + --do_schmidt \ + --stretch_factor ${STRETCH_FAC} \ + --target_lon ${LON_CTR} \ + --target_lat ${LAT_CTR} \ + --nest_grid \ + --parent_tile 6 \ + --refine_ratio ${GFDLgrid_REFINE_RATIO} \ + --istart_nest ${ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ + --jstart_nest ${JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ + --iend_nest ${IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ + --jend_nest ${JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG} \ + --halo 1 \ + --great_circle_algorithm || \ + print_err_msg_exit "\ +Call to executable (exec_fp) that generates grid files returned with +nonzero exit code. + exec_fp = \"${exec_fp}\"" +# +# Set the name of the regional grid file generated by the above call. +# + grid_fn="${grid_name}.tile${TILE_RGNL}.nc" +# +# Generate a ESGgrid-type of grid. +# +elif [ "${GRID_GEN_METHOD}" = "ESGgrid" ]; then +# +# Create the namelist file read in by the ESGgrid-type grid generation +# code in the temporary subdirectory. +# + rgnl_grid_nml_fp="$tmpdir/${RGNL_GRID_NML_FN}" + + print_info_msg "$VERBOSE" " +Creating namelist file (rgnl_grid_nml_fp) to be read in by the grid +generation executable (exec_fp): + rgnl_grid_nml_fp = \"${rgnl_grid_nml_fp}\" + exec_fp = \"${exec_fp}\"" +# +# Create a multiline variable that consists of a yaml-compliant string +# specifying the values that the namelist variables need to be set to +# (one namelist variable per line, plus a header and footer). Below, +# this variable will be passed to a python script that will create the +# namelist file. +# + settings=" +'regional_grid_nml': { + 'plon': ${LON_CTR}, + 'plat': ${LAT_CTR}, + 'delx': ${DEL_ANGLE_X_SG}, + 'dely': ${DEL_ANGLE_Y_SG}, + 'lx': ${NEG_NX_OF_DOM_WITH_WIDE_HALO}, + 'ly': ${NEG_NY_OF_DOM_WITH_WIDE_HALO}, + 'pazi': ${PAZI}, + } +" +# +# Call the python script to create the namelist file. +# + ${USHDIR}/set_namelist.py -q -u "$settings" -o ${rgnl_grid_nml_fp} || \ + print_err_msg_exit "\ +Call to python script set_namelist.py to set the variables in the +regional_esg_grid namelist file failed. Parameters passed to this script +are: + Full path to output namelist file: + rgnl_grid_nml_fp = \"${rgnl_grid_nml_fp}\" + Namelist settings specified on command line (these have highest precedence): + settings = +$settings" +# +# Call the executable that generates the grid file. +# + $RUN_CMD_SERIAL ${exec_fp} ${rgnl_grid_nml_fp} || \ + print_err_msg_exit "\ +Call to executable (exec_fp) that generates a ESGgrid-type regional grid +returned with nonzero exit code: + exec_fp = \"${exec_fp}\"" +# +# Set the name of the regional grid file generated by the above call. +# This must be the same name as in the regional_esg_grid code. +# + grid_fn="regional_grid.nc" + +fi +# +# Set the full path to the grid file generated above. Then change location +# to the original directory. +# +grid_fp="$tmpdir/${grid_fn}" +cd_vrfy - + +print_info_msg "$VERBOSE" " +Grid file generation completed successfully." +# +#----------------------------------------------------------------------- +# +# Calculate the regional grid's global uniform cubed-sphere grid equivalent +# resolution. +# +#----------------------------------------------------------------------- +# +exec_fn="global_equiv_resol" +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for calculating the regional grid's global uniform +cubed-sphere grid equivalent resolution does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi + +$RUN_CMD_SERIAL ${exec_fp} "${grid_fp}" || \ +print_err_msg_exit "\ +Call to executable (exec_fp) that calculates the regional grid's global +uniform cubed-sphere grid equivalent resolution returned with nonzero exit +code: + exec_fp = \"${exec_fp}\"" + +# Make sure 'ncdump' is available before we try to use it +if ! command -v ncdump &> /dev/null +then + print_err_msg_exit "\ +The utility 'ncdump' was not found in the environment. Be sure to add the +netCDF 'bin/' directory to your PATH." +fi + +# Make the following (reading of res_equiv) a function in another file +# so that it can be used both here and in the exregional_make_orog.sh +# script. +res_equiv=$( ncdump -h "${grid_fp}" | \ + grep -o ":RES_equiv = [0-9]\+" | grep -o "[0-9]" ) || \ +print_err_msg_exit "\ +Attempt to extract the equivalent global uniform cubed-sphere grid reso- +lution from the grid file (grid_fp) failed: + grid_fp = \"${grid_fp}\"" +res_equiv=${res_equiv//$'\n'/} +# +#----------------------------------------------------------------------- +# +# Set the string CRES that will be comprise the start of the grid file +# name (and other file names later in other tasks/scripts). Then set its +# value in the variable definitions file. +# +#----------------------------------------------------------------------- +# +if [ "${GRID_GEN_METHOD}" = "GFDLgrid" ]; then + if [ "${GFDLgrid_USE_NUM_CELLS_IN_FILENAMES}" = "TRUE" ]; then + CRES="C${GFDLgrid_NUM_CELLS}" + else + CRES="C${res_equiv}" + fi +elif [ "${GRID_GEN_METHOD}" = "ESGgrid" ]; then + CRES="C${res_equiv}" +fi +set_file_param "${GLOBAL_VAR_DEFNS_FP}" "CRES" "'$CRES'" +# +#----------------------------------------------------------------------- +# +# Move the grid file from the temporary directory to GRID_DIR. In the +# process, rename it such that its name includes CRES and the halo width. +# +#----------------------------------------------------------------------- +# +grid_fp_orig="${grid_fp}" +grid_fn="${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NHW}.nc" +grid_fp="${GRID_DIR}/${grid_fn}" +mv_vrfy "${grid_fp_orig}" "${grid_fp}" +# +#----------------------------------------------------------------------- +# +# If there are pre-existing orography or climatology files that we will +# be using (i.e. if RUN_TASK_MAKE_OROG or RUN_TASK_MAKE_SURF_CLIMO is set +# to "FALSE", in which case RES_IN_FIXLAM_FILENAMES will not be set to a +# null string), check that the grid resolution contained in the variable +# CRES set above matches the resolution appearing in the names of the +# preexisting orography and/or surface climatology files. +# +#----------------------------------------------------------------------- +# +if [ ! -z "${RES_IN_FIXLAM_FILENAMES}" ]; then + res="${CRES:1}" + if [ "$res" -ne "${RES_IN_FIXLAM_FILENAMES}" ]; then + print_err_msg_exit "\ +The resolution (res) calculated for the grid does not match the resolution +(RES_IN_FIXLAM_FILENAMES) appearing in the names of the orography and/or +surface climatology files: + res = \"$res\" + RES_IN_FIXLAM_FILENAMES = \"${RES_IN_FIXLAM_FILENAMES}\"" + fi +fi +# +#----------------------------------------------------------------------- +# +# Partially "shave" the halo from the grid file having a wide halo to +# generate two new grid files -- one with a 3-grid-wide halo and another +# with a 4-cell-wide halo. These are needed as inputs by the forecast +# model as well as by the code (chgres_cube) that generates the lateral +# boundary condition files. <== Are these also needed by make_sfc_climo??? +# +#----------------------------------------------------------------------- +# +# Set the name and path to the executable and make sure that it exists. +# +exec_fn="shave" +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit " \ +The executable (exec_fp) for \"shaving\" down the halo in the grid file +does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi +# +# Set the full path to the "unshaved" grid file, i.e. the one with a wide +# halo. This is the input grid file for generating both the grid file +# with a 3-cell-wide halo and the one with a 4-cell-wide halo. +# +unshaved_fp="${grid_fp}" +# +# We perform the work in tmpdir, so change location to that directory. +# Once it is complete, we will move the resultant file from tmpdir to +# GRID_DIR. +# +cd_vrfy "$tmpdir" +# +# Create an input namelist file for the shave executable to generate a +# grid file with a 3-cell-wide halo from the one with a wide halo. Then +# call the shave executable. Finally, move the resultant file to the +# GRID_DIR directory. +# +print_info_msg "$VERBOSE" " +\"Shaving\" grid file with wide halo to obtain grid file with ${NH3}-cell-wide +halo..." + +nml_fn="input.shave.grid.halo${NH3}" +shaved_fp="${tmpdir}/${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NH3}.nc" +printf "%s %s %s %s %s\n" \ + $NX $NY ${NH3} \"${unshaved_fp}\" \"${shaved_fp}\" \ + > ${nml_fn} + +$RUN_CMD_SERIAL ${exec_fp} < ${nml_fn} || \ +print_err_msg_exit "\ +Call to executable (exec_fp) to generate a grid file with a ${NH3}-cell-wide +halo from the grid file with a ${NHW}-cell-wide halo returned with nonzero +exit code: + exec_fp = \"${exec_fp}\" +The namelist file (nml_fn) used in this call is in directory tmpdir: + nml_fn = \"${nml_fn}\" + tmpdir = \"${tmpdir}\"" +mv_vrfy ${shaved_fp} ${GRID_DIR} +# +# Create an input namelist file for the shave executable to generate a +# grid file with a 4-cell-wide halo from the one with a wide halo. Then +# call the shave executable. Finally, move the resultant file to the +# GRID_DIR directory. +# +print_info_msg "$VERBOSE" " +\"Shaving\" grid file with wide halo to obtain grid file with ${NH4}-cell-wide +halo..." + +nml_fn="input.shave.grid.halo${NH4}" +shaved_fp="${tmpdir}/${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NH4}.nc" +printf "%s %s %s %s %s\n" \ + $NX $NY ${NH4} \"${unshaved_fp}\" \"${shaved_fp}\" \ + > ${nml_fn} + +$RUN_CMD_SERIAL ${exec_fp} < ${nml_fn} || \ +print_err_msg_exit "\ +Call to executable (exec_fp) to generate a grid file with a ${NH4}-cell-wide +halo from the grid file with a ${NHW}-cell-wide halo returned with nonzero +exit code: + exec_fp = \"${exec_fp}\" +The namelist file (nml_fn) used in this call is in directory tmpdir: + nml_fn = \"${nml_fn}\" + tmpdir = \"${tmpdir}\"" +mv_vrfy ${shaved_fp} ${GRID_DIR} +# +# Change location to the original directory. +# +cd_vrfy - +# +#----------------------------------------------------------------------- +# +# Create the grid mosaic file for the grid with a NHW-cell-wide halo. +# +#----------------------------------------------------------------------- +# +make_grid_mosaic_file \ + grid_dir="${GRID_DIR}" \ + grid_fn="${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NHW}.nc" \ + mosaic_fn="${CRES}${DOT_OR_USCORE}mosaic.halo${NHW}.nc" \ + run_cmd="${RUN_CMD_SERIAL}" || \ + print_err_msg_exit "\ +Call to function to generate the mosaic file for a grid with a ${NHW}-cell-wide +halo failed." +# +#----------------------------------------------------------------------- +# +# Create the grid mosaic file for the grid with a NH3-cell-wide halo. +# +#----------------------------------------------------------------------- +# +make_grid_mosaic_file \ + grid_dir="${GRID_DIR}" \ + grid_fn="${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NH3}.nc" \ + mosaic_fn="${CRES}${DOT_OR_USCORE}mosaic.halo${NH3}.nc" \ + run_cmd="${RUN_CMD_SERIAL}" || \ + print_err_msg_exit "\ +Call to function to generate the mosaic file for a grid with a ${NH3}-cell-wide +halo failed." +# +#----------------------------------------------------------------------- +# +# Create the grid mosaic file for the grid with a NH4-cell-wide halo. +# +#----------------------------------------------------------------------- +# +make_grid_mosaic_file \ + grid_dir="${GRID_DIR}" \ + grid_fn="${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NH4}.nc" \ + mosaic_fn="${CRES}${DOT_OR_USCORE}mosaic.halo${NH4}.nc" \ + run_cmd="${RUN_CMD_SERIAL}" || \ + print_err_msg_exit "\ +Call to function to generate the mosaic file for a grid with a ${NH4}-cell-wide +halo failed." +# +#----------------------------------------------------------------------- +# +# Create symlinks in the FIXLAM directory to the grid and mosaic files +# generated above in the GRID_DIR directory. +# +#----------------------------------------------------------------------- +# +python3 $USHDIR/link_fix.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + --file-group "grid" || \ +print_err_msg_exit "\ +Call to function to create symlinks to the various grid and mosaic files +failed." +# +#----------------------------------------------------------------------- +# +# Call a function (set_FV3nml_sfc_climo_filenames) to set the values of +# those variables in the forecast model's namelist file that specify the +# paths to the surface climatology files. These files will either already +# be avaialable in a user-specified directory (SFC_CLIMO_DIR) or will be +# generated by the MAKE_SFC_CLIMO_TN task. They (or symlinks to them) +# will be placed (or wll already exist) in the FIXLAM directory. +# +#----------------------------------------------------------------------- +# +python3 $USHDIR/set_FV3nml_sfc_climo_filenames.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + || print_err_msg_exit "\ +Call to function to set surface climatology file names in the FV3 namelist +file failed." +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Grid files with various halo widths generated successfully!!! + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + + + diff --git a/scripts/exregional_make_ics.sh b/scripts/exregional_make_ics.sh new file mode 100755 index 0000000000..b7a8dbe05a --- /dev/null +++ b/scripts/exregional_make_ics.sh @@ -0,0 +1,679 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that generates initial condition +(IC), surface, and zeroth hour lateral boundary condition (LBC0) files +(in NetCDF format) for the FV3-LAM. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. Then +# process the arguments provided to this script/function (which should +# consist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ +"ics_dir" \ +) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set OpenMP variables. +# +#----------------------------------------------------------------------- +# +export KMP_AFFINITY=${KMP_AFFINITY_MAKE_ICS} +export OMP_NUM_THREADS=${OMP_NUM_THREADS_MAKE_ICS} +export OMP_STACKSIZE=${OMP_STACKSIZE_MAKE_ICS} +# +#----------------------------------------------------------------------- +# +# Set machine-dependent parameters. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +nprocs=$(( NNODES_MAKE_ICS*PPN_MAKE_ICS )) + +if [ -z "${RUN_CMD_UTILS:-}" ] ; then + print_err_msg_exit "\ + Run command was not set in machine file. \ + Please set RUN_CMD_UTILS for your platform" +else + RUN_CMD_UTILS=$(eval echo ${RUN_CMD_UTILS}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_UTILS}\'." +fi + + +# +#----------------------------------------------------------------------- +# +# Source the file containing definitions of variables associated with the +# external model for ICs. +# +#----------------------------------------------------------------------- +# +extrn_mdl_staging_dir="${CYCLE_DIR}/${EXTRN_MDL_NAME_ICS}/for_ICS" +extrn_mdl_var_defns_fp="${extrn_mdl_staging_dir}/${EXTRN_MDL_VAR_DEFNS_FN}" +. ${extrn_mdl_var_defns_fp} +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# +workdir="${ics_dir}/tmp_ICS" +mkdir_vrfy -p "$workdir" +cd_vrfy $workdir +# +#----------------------------------------------------------------------- +# +# Set physics-suite-dependent variable mapping table needed in the FORTRAN +# namelist file that the chgres_cube executable will read in. +# +#----------------------------------------------------------------------- +# +varmap_file="" + +case "${CCPP_PHYS_SUITE}" in +# + "FV3_GFS_2017_gfdlmp" | \ + "FV3_GFS_2017_gfdlmp_regional" | \ + "FV3_GFS_v16" | \ + "FV3_GFS_v15p2" ) + varmap_file="GFSphys_var_map.txt" + ;; +# + "FV3_RRFS_v1beta" | \ + "FV3_GFS_v15_thompson_mynn_lam3km" | \ + "FV3_HRRR" ) + if [ "${EXTRN_MDL_NAME_ICS}" = "RAP" ] || \ + [ "${EXTRN_MDL_NAME_ICS}" = "HRRR" ]; then + varmap_file="GSDphys_var_map.txt" + elif [ "${EXTRN_MDL_NAME_ICS}" = "NAM" ] || \ + [ "${EXTRN_MDL_NAME_ICS}" = "FV3GFS" ] || \ + [ "${EXTRN_MDL_NAME_ICS}" = "GSMGFS" ]; then + varmap_file="GFSphys_var_map.txt" + fi + ;; +# + *) + print_err_msg_exit "\ +The variable \"varmap_file\" has not yet been specified for this physics +suite (CCPP_PHYS_SUITE): + CCPP_PHYS_SUITE = \"${CCPP_PHYS_SUITE}\"" + ;; +# +esac +# +#----------------------------------------------------------------------- +# +# Set external-model-dependent variables that are needed in the FORTRAN +# namelist file that the chgres_cube executable will read in. These are de- +# scribed below. Note that for a given external model, usually only a +# subset of these all variables are set (since some may be irrelevant). +# +# external_model: +# Name of the external model from which we are obtaining the fields +# needed to generate the ICs. +# +# fn_atm: +# Name (not including path) of the nemsio or netcdf file generated by the +# external model that contains the atmospheric fields. Currently used for +# GSMGFS and FV3GFS external model data. +# +# fn_sfc: +# Name (not including path) of the nemsio or netcdf file generated by the +# external model that contains the surface fields. Currently used for +# GSMGFS and FV3GFS external model data. +# +# fn_grib2: +# Name (not including path) of the grib2 file generated by the external +# model. Currently used for NAM, RAP, and HRRR external model data. +# +# input_type: +# The "type" of input being provided to chgres_cube. This contains a combi- +# nation of information on the external model, external model file for- +# mat, and maybe other parameters. For clarity, it would be best to +# eliminate this variable in chgres_cube and replace with with 2 or 3 others +# (e.g. extrn_mdl, extrn_mdl_file_format, etc). +# +# tracers_input: +# List of atmospheric tracers to read in from the external model file +# containing these tracers. +# +# tracers: +# Names to use in the output NetCDF file for the atmospheric tracers +# specified in tracers_input. With the possible exception of GSD phys- +# ics, the elements of this array should have a one-to-one correspond- +# ence with the elements in tracers_input, e.g. if the third element of +# tracers_input is the name of the O3 mixing ratio, then the third ele- +# ment of tracers should be the name to use for the O3 mixing ratio in +# the output file. For GSD physics, three additional tracers -- ice, +# rain, and water number concentrations -- may be specified at the end +# of tracers, and these will be calculated by chgres_cube. +# +# nsoill_out: +# The number of soil layers to include in the output NetCDF file. +# +# FIELD_from_climo, where FIELD = "vgtyp", "sotyp", "vgfrc", "lai", or +# "minmax_vgfrc": +# Logical variable indicating whether or not to obtain the field in +# question from climatology instead of the external model. The field in +# question is one of vegetation type (FIELD="vgtyp"), soil type (FIELD= +# "sotyp"), vegetation fraction (FIELD="vgfrc"), leaf area index +# (FIELD="lai"), or min/max areal fractional coverage of annual green +# vegetation (FIELD="minmax_vfrr"). If FIELD_from_climo is set to +# ".true.", then the field is obtained from climatology (regardless of +# whether or not it exists in an external model file). If it is set +# to ".false.", then the field is obtained from the external model. +# If "false" is chosen and the external model file does not provide +# this field, then chgres_cube prints out an error message and stops. +# +# tg3_from_soil: +# Logical variable indicating whether or not to set the tg3 soil tempe- # Needs to be verified. +# rature field to the temperature of the deepest soil layer. +# +#----------------------------------------------------------------------- +# + +# GSK comments about chgres: +# +# The following are the three atmsopheric tracers that are in the atmo- +# spheric analysis (atmanl) nemsio file for CDATE=2017100700: +# +# "spfh","o3mr","clwmr" +# +# Note also that these are hardcoded in the code (file input_data.F90, +# subroutine read_input_atm_gfs_spectral_file), so that subroutine will +# break if tracers_input(:) is not specified as above. +# +# Note that there are other fields too ["hgt" (surface height (togography?)), +# pres (surface pressure), ugrd, vgrd, and tmp (temperature)] in the atmanl file, but those +# are not considered tracers (they're categorized as dynamics variables, +# I guess). +# +# Another note: The way things are set up now, tracers_input(:) and +# tracers(:) are assumed to have the same number of elements (just the +# atmospheric tracer names in the input and output files may be differ- +# ent). There needs to be a check for this in the chgres_cube code!! +# If there was a varmap table that specifies how to handle missing +# fields, that would solve this problem. +# +# Also, it seems like the order of tracers in tracers_input(:) and +# tracers(:) must match, e.g. if ozone mixing ratio is 3rd in +# tracers_input(:), it must also be 3rd in tracers(:). How can this be checked? +# +# NOTE: Really should use a varmap table for GFS, just like we do for +# RAP/HRRR. +# +# A non-prognostic variable that appears in the field_table for GSD physics +# is cld_amt. Why is that in the field_table at all (since it is a non- +# prognostic field), and how should we handle it here?? +# I guess this works for FV3GFS but not for the spectral GFS since these +# variables won't exist in the spectral GFS atmanl files. +# tracers_input="\"sphum\",\"liq_wat\",\"ice_wat\",\"rainwat\",\"snowwat\",\"graupel\",\"o3mr\"" +# +# Not sure if tracers(:) should include "cld_amt" since that is also in +# the field_table for CDATE=2017100700 but is a non-prognostic variable. + +external_model="" +fn_atm="" +fn_sfc="" +fn_grib2="" +input_type="" +tracers_input="\"\"" +tracers="\"\"" +nsoill_out="" +geogrid_file_input_grid="\"\"" +vgtyp_from_climo="" +sotyp_from_climo="" +vgfrc_from_climo="" +minmax_vgfrc_from_climo="" +lai_from_climo="" +tg3_from_soil="" +convert_nst="" +# +#----------------------------------------------------------------------- +# +# If the external model is not one that uses the RUC land surface model +# (LSM) -- which currently includes all valid external models except the +# HRRR and the RAP -- then we set the number of soil levels to include +# in the output NetCDF file that chgres_cube generates (nsoill_out; this +# is a variable in the namelist that chgres_cube reads in) to 4. This +# is because FV3 can handle this regardless of the LSM that it is using +# (which is specified in the suite definition file, or SDF), as follows. +# If the SDF does not use the RUC LSM (i.e. it uses the Noah or Noah MP +# LSM), then it will expect to see 4 soil layers; and if the SDF uses +# the RUC LSM, then the RUC LSM itself has the capability to regrid from +# 4 soil layers to the 9 layers that it uses. +# +# On the other hand, if the external model is one that uses the RUC LSM +# (currently meaning that it is either the HRRR or the RAP), then what +# we set nsoill_out to depends on whether the RUC or the Noah/Noah MP +# LSM is used in the SDF. If the SDF uses RUC, then both the external +# model and FV3 use RUC (which expects 9 soil levels), so we simply set +# nsoill_out to 9. In this case, chgres_cube does not need to do any +# regridding of soil levels (because the number of levels in is the same +# as the number out). If the SDF uses the Noah or Noah MP LSM, then the +# output from chgres_cube must contain 4 soil levels because that is what +# these LSMs expect, and the code in FV3 does not have the capability to +# regrid from the 9 levels in the external model to the 4 levels expected +# by Noah/Noah MP. In this case, chgres_cube does the regridding from +# 9 to 4 levels. +# +# In summary, we can set nsoill_out to 4 unless the external model is +# the HRRR or RAP AND the forecast model is using the RUC LSM. +# +#----------------------------------------------------------------------- +# +nsoill_out="4" +if [ "${EXTRN_MDL_NAME_ICS}" = "HRRR" -o \ + "${EXTRN_MDL_NAME_ICS}" = "RAP" ] && \ + [ "${SDF_USES_RUC_LSM}" = "TRUE" ]; then + nsoill_out="9" +fi +# +#----------------------------------------------------------------------- +# +# If the external model for ICs is one that does not provide the aerosol +# fields needed by Thompson microphysics (currently only the HRRR and +# RAP provide aerosol data) and if the physics suite uses Thompson +# microphysics, set the variable thomp_mp_climo_file in the chgres_cube +# namelist to the full path of the file containing aerosol climatology +# data. In this case, this file will be used to generate approximate +# aerosol fields in the ICs that Thompson MP can use. Otherwise, set +# thomp_mp_climo_file to a null string. +# +#----------------------------------------------------------------------- +# +thomp_mp_climo_file="" +if [ "${EXTRN_MDL_NAME_ICS}" != "HRRR" -a \ + "${EXTRN_MDL_NAME_ICS}" != "RAP" ] && \ + [ "${SDF_USES_THOMPSON_MP}" = "TRUE" ]; then + thomp_mp_climo_file="${THOMPSON_MP_CLIMO_FP}" +fi +# +#----------------------------------------------------------------------- +# +# Set other chgres_cube namelist variables depending on the external +# model used. +# +#----------------------------------------------------------------------- +# +case "${EXTRN_MDL_NAME_ICS}" in + +"GSMGFS") + external_model="GSMGFS" + fn_atm="${EXTRN_MDL_FNS[0]}" + fn_sfc="${EXTRN_MDL_FNS[1]}" + input_type="gfs_gaussian_nemsio" # For spectral GFS Gaussian grid in nemsio format. + convert_nst=False + tracers_input="[\"spfh\",\"clwmr\",\"o3mr\"]" + tracers="[\"sphum\",\"liq_wat\",\"o3mr\"]" + vgtyp_from_climo=True + sotyp_from_climo=True + vgfrc_from_climo=True + minmax_vgfrc_from_climo=True + lai_from_climo=True + tg3_from_soil=False + ;; + +"FV3GFS") + if [ "${FV3GFS_FILE_FMT_ICS}" = "nemsio" ]; then + external_model="FV3GFS" + input_type="gaussian_nemsio" # For FV3GFS data on a Gaussian grid in nemsio format. + tracers_input="[\"spfh\",\"clwmr\",\"o3mr\",\"icmr\",\"rwmr\",\"snmr\",\"grle\"]" + tracers="[\"sphum\",\"liq_wat\",\"o3mr\",\"ice_wat\",\"rainwat\",\"snowwat\",\"graupel\"]" + fn_atm="${EXTRN_MDL_FNS[0]}" + fn_sfc="${EXTRN_MDL_FNS[1]}" + convert_nst=True + elif [ "${FV3GFS_FILE_FMT_ICS}" = "grib2" ]; then + external_model="GFS" + fn_grib2="${EXTRN_MDL_FNS[0]}" + input_type="grib2" + convert_nst=False + elif [ "${FV3GFS_FILE_FMT_ICS}" = "netcdf" ]; then + external_model="FV3GFS" + input_type="gaussian_netcdf" # For FV3GFS data on a Gaussian grid in netcdf format. + tracers_input="[\"spfh\",\"clwmr\",\"o3mr\",\"icmr\",\"rwmr\",\"snmr\",\"grle\"]" + tracers="[\"sphum\",\"liq_wat\",\"o3mr\",\"ice_wat\",\"rainwat\",\"snowwat\",\"graupel\"]" + fn_atm="${EXTRN_MDL_FNS[0]}" + fn_sfc="${EXTRN_MDL_FNS[1]}" + convert_nst=True + fi + vgtyp_from_climo=True + sotyp_from_climo=True + vgfrc_from_climo=True + minmax_vgfrc_from_climo=True + lai_from_climo=True + tg3_from_soil=False + ;; + +"HRRR") + external_model="HRRR" + fn_grib2="${EXTRN_MDL_FNS[0]}" + input_type="grib2" +# +# Path to the HRRRX geogrid file. +# + geogrid_file_input_grid="${FIXgsm}/geo_em.d01.nc_HRRRX" +# Note that vgfrc, shdmin/shdmax (minmax_vgfrc), and lai fields are only available in HRRRX +# files after mid-July 2019, and only so long as the record order didn't change afterward + vgtyp_from_climo=True + sotyp_from_climo=True + vgfrc_from_climo=True + minmax_vgfrc_from_climo=True + lai_from_climo=True + tg3_from_soil=True + convert_nst=False + ;; + +"RAP") + external_model="RAP" + fn_grib2="${EXTRN_MDL_FNS[0]}" + input_type="grib2" +# +# Path to the RAPX geogrid file. +# + geogrid_file_input_grid="${FIXgsm}/geo_em.d01.nc_RAPX" + vgtyp_from_climo=True + sotyp_from_climo=True + vgfrc_from_climo=True + minmax_vgfrc_from_climo=True + lai_from_climo=True + tg3_from_soil=True + convert_nst=False + ;; + +"NAM") + external_model="NAM" + fn_grib2="${EXTRN_MDL_FNS[0]}" + input_type="grib2" + vgtyp_from_climo=True + sotyp_from_climo=True + vgfrc_from_climo=True + minmax_vgfrc_from_climo=True + lai_from_climo=True + tg3_from_soil=False + convert_nst=False + ;; + +*) + print_err_msg_exit "\ +External-model-dependent namelist variables have not yet been specified +for this external IC model (EXTRN_MDL_NAME_ICS): + EXTRN_MDL_NAME_ICS = \"${EXTRN_MDL_NAME_ICS}\"" + ;; + +esac +# +#----------------------------------------------------------------------- +# +# Get the starting month, day, and hour of the the external model forecast. +# +#----------------------------------------------------------------------- +# +mm="${EXTRN_MDL_CDATE:4:2}" +dd="${EXTRN_MDL_CDATE:6:2}" +hh="${EXTRN_MDL_CDATE:8:2}" +# +#----------------------------------------------------------------------- +# +# Check that the executable that generates the ICs exists. +# +#----------------------------------------------------------------------- +# +exec_fn="chgres_cube" +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for generating initial conditions on the FV3-LAM +native grid does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi +# +#----------------------------------------------------------------------- +# +# Build the FORTRAN namelist file that chgres_cube will read in. +# +#----------------------------------------------------------------------- +# +# Create a multiline variable that consists of a yaml-compliant string +# specifying the values that the namelist variables need to be set to +# (one namelist variable per line, plus a header and footer). Below, +# this variable will be passed to a python script that will create the +# namelist file. +# +# IMPORTANT: +# If we want a namelist variable to be removed from the namelist file, +# in the "settings" variable below, we need to set its value to the +# string "null". This is equivalent to setting its value to +# !!python/none +# in the base namelist file specified by FV3_NML_BASE_SUITE_FP or the +# suite-specific yaml settings file specified by FV3_NML_YAML_CONFIG_FP. +# +# It turns out that setting the variable to an empty string also works +# to remove it from the namelist! Which is better to use?? +# +settings=" +'config': { + 'fix_dir_target_grid': ${FIXLAM}, + 'mosaic_file_target_grid': ${FIXLAM}/${CRES}${DOT_OR_USCORE}mosaic.halo$((10#${NH4})).nc, + 'orog_dir_target_grid': ${FIXLAM}, + 'orog_files_target_grid': ${CRES}${DOT_OR_USCORE}oro_data.tile${TILE_RGNL}.halo$((10#${NH4})).nc, + 'vcoord_file_target_grid': ${FIXam}/global_hyblev.l65.txt, + 'varmap_file': ${UFS_UTILS_DIR}/parm/varmap_tables/${varmap_file}, + 'data_dir_input_grid': ${extrn_mdl_staging_dir}, + 'atm_files_input_grid': ${fn_atm}, + 'sfc_files_input_grid': ${fn_sfc}, + 'grib2_file_input_grid': \"${fn_grib2}\", + 'cycle_mon': $((10#${mm})), + 'cycle_day': $((10#${dd})), + 'cycle_hour': $((10#${hh})), + 'convert_atm': True, + 'convert_sfc': True, + 'convert_nst': ${convert_nst}, + 'regional': 1, + 'halo_bndy': $((10#${NH4})), + 'halo_blend': $((10#${HALO_BLEND})), + 'input_type': ${input_type}, + 'external_model': ${external_model}, + 'tracers_input': ${tracers_input}, + 'tracers': ${tracers}, + 'nsoill_out': $((10#${nsoill_out})), + 'geogrid_file_input_grid': ${geogrid_file_input_grid}, + 'vgtyp_from_climo': ${vgtyp_from_climo}, + 'sotyp_from_climo': ${sotyp_from_climo}, + 'vgfrc_from_climo': ${vgfrc_from_climo}, + 'minmax_vgfrc_from_climo': ${minmax_vgfrc_from_climo}, + 'lai_from_climo': ${lai_from_climo}, + 'tg3_from_soil': ${tg3_from_soil}, + 'thomp_mp_climo_file': ${thomp_mp_climo_file}, +} +" +# +# Call the python script to create the namelist file. +# +nml_fn="fort.41" +${USHDIR}/set_namelist.py -q -u "$settings" -o ${nml_fn} || \ + print_err_msg_exit "\ +Call to python script set_namelist.py to set the variables in the namelist +file read in by the ${exec_fn} executable failed. Parameters passed to +this script are: + Name of output namelist file: + nml_fn = \"${nml_fn}\" + Namelist settings specified on command line (these have highest precedence): + settings = +$settings" +# +#----------------------------------------------------------------------- +# +# Run chgres_cube. +# +#----------------------------------------------------------------------- +# +# NOTE: +# Often when the chgres_cube.exe run fails, it still returns a zero +# return code, so the failure isn't picked up the the logical OR (||) +# below. That should be fixed. This might be due to the RUN_CMD_UTILS +# command - maybe that is returning a zero exit code even though the +# exit code of chgres_cube is nonzero. A similar thing happens in the +# forecast task. +# +${RUN_CMD_UTILS} ${exec_fp} || \ + print_err_msg_exit "\ +Call to executable (exec_fp) to generate surface and initial conditions +(ICs) files for the FV3-LAM failed: + exec_fp = \"${exec_fp}\" +The external model from which the ICs files are to be generated is: + EXTRN_MDL_NAME_ICS = \"${EXTRN_MDL_NAME_ICS}\" +The external model files that are inputs to the executable (exec_fp) are +located in the following directory: + extrn_mdl_staging_dir = \"${extrn_mdl_staging_dir}\"" +# +#----------------------------------------------------------------------- +# +# Move initial condition, surface, control, and 0-th hour lateral bound- +# ary files to ICs_BCs directory. +# +#----------------------------------------------------------------------- +# +mv_vrfy out.atm.tile${TILE_RGNL}.nc \ + ${ics_dir}/gfs_data.tile${TILE_RGNL}.halo${NH0}.nc + +mv_vrfy out.sfc.tile${TILE_RGNL}.nc \ + ${ics_dir}/sfc_data.tile${TILE_RGNL}.halo${NH0}.nc + +mv_vrfy gfs_ctrl.nc ${ics_dir} + +mv_vrfy gfs.bndy.nc ${ics_dir}/gfs_bndy.tile${TILE_RGNL}.000.nc +# +#----------------------------------------------------------------------- +# +# Process FVCOM Data +# +#----------------------------------------------------------------------- +# +if [ "${USE_FVCOM}" = "TRUE" ]; then + +#Format for fvcom_time: YYYY-MM-DDTHH:00:00.000000 + fvcom_exec_fn="fvcom_to_FV3" + fvcom_exec_fp="$EXECDIR/${fvcom_exec_fn}" + fvcom_time="${DATE_FIRST_CYCL:0:4}-${DATE_FIRST_CYCL:4:2}-${DATE_FIRST_CYCL:6:2}T${CYCL_HRS[0]}:00:00.000000" + if [ ! -f "${fvcom_exec_fp}" ]; then + print_err_msg_exit "\ +The executable (fvcom_exec_fp) for processing FVCOM data onto FV3-LAM +native grid does not exist: + fvcom_exec_fp = \"${fvcom_exec_fp}\" +Please ensure that you've built this executable." + fi + cp_vrfy ${fvcom_exec_fp} ${ics_dir}/. + fvcom_data_fp="${FVCOM_DIR}/${FVCOM_FILE}" + if [ ! -f "${fvcom_data_fp}" ]; then + print_err_msg_exit "\ +The file or path (fvcom_data_fp) does not exist: + fvcom_data_fp = \"${fvcom_data_fp}\" +Please check the following user defined variables: + FVCOM_DIR = \"${FVCOM_DIR}\" + FVCOM_FILE= \"${FVCOM_FILE}\" " + fi + + cp_vrfy ${fvcom_data_fp} ${ics_dir}/fvcom.nc + cd_vrfy ${ics_dir} + ${RUN_CMD_UTILS} ${fvcom_exec_fn} sfc_data.tile${TILE_RGNL}.halo${NH0}.nc fvcom.nc ${FVCOM_WCSTART} ${fvcom_time}|| \ + print_err_msg_exit "\ +Call to executable (fvcom_exe) to modify sfc fields for FV3-LAM failed: + fvcom_exe = \"${fvcom_exe}\" +The following variables were being used: + FVCOM_DIR = \"${FVCOM_DIR}\" + FVCOM_FILE = \"${FVCOM_FILE}\" + fvcom_time = \"${fvcom_time}\" + FVCOM_WCSTART = \"${FVCOM_WCSTART}\" + ics_dir = \"${ics_dir}\" + fvcom_exe_dir = \"${fvcom_exe_dir}\" + fvcom_exe = \"${fvcom_exe}\"" +fi +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Initial condition, surface, and zeroth hour lateral boundary condition +files (in NetCDF format) for FV3 generated successfully!!! + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_make_lbcs.sh b/scripts/exregional_make_lbcs.sh new file mode 100755 index 0000000000..6dc3ba369a --- /dev/null +++ b/scripts/exregional_make_lbcs.sh @@ -0,0 +1,540 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that generates lateral boundary con- +dition (LBC) files (in NetCDF format) for all LBC update hours (except +hour zero). +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. Then +# process the arguments provided to this script/function (which should +# consist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ +"lbcs_dir" \ +) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set OpenMP variables. +# +#----------------------------------------------------------------------- +# +export KMP_AFFINITY=${KMP_AFFINITY_MAKE_LBCS} +export OMP_NUM_THREADS=${OMP_NUM_THREADS_MAKE_LBCS} +export OMP_STACKSIZE=${OMP_STACKSIZE_MAKE_LBCS} +# +#----------------------------------------------------------------------- +# +# Set machine-dependent parameters. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +nprocs=$(( NNODES_MAKE_LBCS*PPN_MAKE_LBCS )) + +if [ -z "${RUN_CMD_UTILS:-}" ] ; then + print_err_msg_exit "\ + Run command was not set in machine file. \ + Please set RUN_CMD_UTILS for your platform" +else + RUN_CMD_UTILS=$(eval echo ${RUN_CMD_UTILS}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_UTILS}\'." +fi +# +#----------------------------------------------------------------------- +# +# Source the file containing definitions of variables associated with the +# external model for LBCs. +# +#----------------------------------------------------------------------- +# +extrn_mdl_staging_dir="${CYCLE_DIR}/${EXTRN_MDL_NAME_LBCS}/for_LBCS" +extrn_mdl_var_defns_fp="${extrn_mdl_staging_dir}/${EXTRN_MDL_VAR_DEFNS_FN}" +. ${extrn_mdl_var_defns_fp} +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# +workdir="${lbcs_dir}/tmp_LBCS" +mkdir_vrfy -p "$workdir" +cd_vrfy $workdir +# +#----------------------------------------------------------------------- +# +# Set physics-suite-dependent variable mapping table needed in the FORTRAN +# namelist file that the chgres_cube executable will read in. +# +#----------------------------------------------------------------------- +# +varmap_file="" + +case "${CCPP_PHYS_SUITE}" in +# + "FV3_GFS_2017_gfdlmp" | \ + "FV3_GFS_2017_gfdlmp_regional" | \ + "FV3_GFS_v16" | \ + "FV3_GFS_v15p2" ) + varmap_file="GFSphys_var_map.txt" + ;; +# + "FV3_RRFS_v1beta" | \ + "FV3_GFS_v15_thompson_mynn_lam3km" | \ + "FV3_HRRR" ) + if [ "${EXTRN_MDL_NAME_LBCS}" = "RAP" ] || \ + [ "${EXTRN_MDL_NAME_LBCS}" = "HRRR" ]; then + varmap_file="GSDphys_var_map.txt" + elif [ "${EXTRN_MDL_NAME_LBCS}" = "NAM" ] || \ + [ "${EXTRN_MDL_NAME_LBCS}" = "FV3GFS" ] || \ + [ "${EXTRN_MDL_NAME_LBCS}" = "GSMGFS" ]; then + varmap_file="GFSphys_var_map.txt" + fi + ;; +# + *) + print_err_msg_exit "\ +The variable \"varmap_file\" has not yet been specified for this physics +suite (CCPP_PHYS_SUITE): + CCPP_PHYS_SUITE = \"${CCPP_PHYS_SUITE}\"" + ;; +# +esac +# +#----------------------------------------------------------------------- +# +# Set external-model-dependent variables that are needed in the FORTRAN +# namelist file that the chgres_cube executable will read in. These are de- +# scribed below. Note that for a given external model, usually only a +# subset of these all variables are set (since some may be irrelevant). +# +# external_model: +# Name of the external model from which we are obtaining the fields +# needed to generate the LBCs. +# +# fn_atm: +# Name (not including path) of the nemsio or netcdf file generated by the +# external model that contains the atmospheric fields. Currently used for +# GSMGFS and FV3GFS external model data. +# +# fn_grib2: +# Name (not including path) of the grib2 file generated by the external +# model. Currently used for NAM, RAP, and HRRR external model data. +# +# input_type: +# The "type" of input being provided to chgres_cube. This contains a combi- +# nation of information on the external model, external model file for- +# mat, and maybe other parameters. For clarity, it would be best to +# eliminate this variable in chgres_cube and replace with with 2 or 3 others +# (e.g. extrn_mdl, extrn_mdl_file_format, etc). +# +# tracers_input: +# List of atmospheric tracers to read in from the external model file +# containing these tracers. +# +# tracers: +# Names to use in the output NetCDF file for the atmospheric tracers +# specified in tracers_input. With the possible exception of GSD phys- +# ics, the elements of this array should have a one-to-one correspond- +# ence with the elements in tracers_input, e.g. if the third element of +# tracers_input is the name of the O3 mixing ratio, then the third ele- +# ment of tracers should be the name to use for the O3 mixing ratio in +# the output file. For GSD physics, three additional tracers -- ice, +# rain, and water number concentrations -- may be specified at the end +# of tracers, and these will be calculated by chgres_cube. +# +#----------------------------------------------------------------------- +# + +# GSK comments about chgres_cube: +# +# The following are the three atmsopheric tracers that are in the atmo- +# spheric analysis (atmanl) nemsio file for CDATE=2017100700: +# +# "spfh","o3mr","clwmr" +# +# Note also that these are hardcoded in the code (file input_data.F90, +# subroutine read_input_atm_gfs_spectral_file), so that subroutine will +# break if tracers_input(:) is not specified as above. +# +# Note that there are other fields too ["hgt" (surface height (togography?)), +# pres (surface pressure), ugrd, vgrd, and tmp (temperature)] in the atmanl file, but those +# are not considered tracers (they're categorized as dynamics variables, +# I guess). +# +# Another note: The way things are set up now, tracers_input(:) and +# tracers(:) are assumed to have the same number of elements (just the +# atmospheric tracer names in the input and output files may be differ- +# ent). There needs to be a check for this in the chgres_cube code!! +# If there was a varmap table that specifies how to handle missing +# fields, that would solve this problem. +# +# Also, it seems like the order of tracers in tracers_input(:) and +# tracers(:) must match, e.g. if ozone mixing ratio is 3rd in +# tracers_input(:), it must also be 3rd in tracers(:). How can this be checked? +# +# NOTE: Really should use a varmap table for GFS, just like we do for +# RAP/HRRR. +# + +# A non-prognostic variable that appears in the field_table for GSD physics +# is cld_amt. Why is that in the field_table at all (since it is a non- +# prognostic field), and how should we handle it here?? + +# I guess this works for FV3GFS but not for the spectral GFS since these +# variables won't exist in the spectral GFS atmanl files. +# tracers_input="\"sphum\",\"liq_wat\",\"ice_wat\",\"rainwat\",\"snowwat\",\"graupel\",\"o3mr\"" +# +# Not sure if tracers(:) should include "cld_amt" since that is also in +# the field_table for CDATE=2017100700 but is a non-prognostic variable. + +external_model="" +fn_atm="" +fn_grib2="" +input_type="" +tracers_input="\"\"" +tracers="\"\"" +# +#----------------------------------------------------------------------- +# +# If the external model for LBCs is one that does not provide the aerosol +# fields needed by Thompson microphysics (currently only the HRRR and +# RAP provide aerosol data) and if the physics suite uses Thompson +# microphysics, set the variable thomp_mp_climo_file in the chgres_cube +# namelist to the full path of the file containing aerosol climatology +# data. In this case, this file will be used to generate approximate +# aerosol fields in the LBCs that Thompson MP can use. Otherwise, set +# thomp_mp_climo_file to a null string. +# +#----------------------------------------------------------------------- +# +thomp_mp_climo_file="" +if [ "${EXTRN_MDL_NAME_LBCS}" != "HRRR" -a \ + "${EXTRN_MDL_NAME_LBCS}" != "RAP" ] && \ + [ "${SDF_USES_THOMPSON_MP}" = "TRUE" ]; then + thomp_mp_climo_file="${THOMPSON_MP_CLIMO_FP}" +fi +# +#----------------------------------------------------------------------- +# +# Set other chgres_cube namelist variables depending on the external +# model used. +# +#----------------------------------------------------------------------- +# +case "${EXTRN_MDL_NAME_LBCS}" in + +"GSMGFS") + external_model="GSMGFS" + input_type="gfs_gaussian_nemsio" # For spectral GFS Gaussian grid in nemsio format. + tracers_input="[\"spfh\",\"clwmr\",\"o3mr\"]" + tracers="[\"sphum\",\"liq_wat\",\"o3mr\"]" + ;; + +"FV3GFS") + if [ "${FV3GFS_FILE_FMT_LBCS}" = "nemsio" ]; then + external_model="FV3GFS" + input_type="gaussian_nemsio" # For FV3GFS data on a Gaussian grid in nemsio format. + tracers_input="[\"spfh\",\"clwmr\",\"o3mr\",\"icmr\",\"rwmr\",\"snmr\",\"grle\"]" + tracers="[\"sphum\",\"liq_wat\",\"o3mr\",\"ice_wat\",\"rainwat\",\"snowwat\",\"graupel\"]" + elif [ "${FV3GFS_FILE_FMT_LBCS}" = "grib2" ]; then + external_model="GFS" + fn_grib2="${EXTRN_MDL_FNS[0]}" + input_type="grib2" + elif [ "${FV3GFS_FILE_FMT_LBCS}" = "netcdf" ]; then + external_model="FV3GFS" + input_type="gaussian_netcdf" # For FV3GFS data on a Gaussian grid in netcdf format. + tracers_input="[\"spfh\",\"clwmr\",\"o3mr\",\"icmr\",\"rwmr\",\"snmr\",\"grle\"]" + tracers="[\"sphum\",\"liq_wat\",\"o3mr\",\"ice_wat\",\"rainwat\",\"snowwat\",\"graupel\"]" + fi + ;; + +"RAP") + external_model="RAP" + input_type="grib2" + ;; + +"HRRR") + external_model="HRRR" + input_type="grib2" + ;; + +"NAM") + external_model="NAM" + input_type="grib2" + ;; + +*) + print_err_msg_exit "\ +External-model-dependent namelist variables have not yet been specified +for this external LBC model (EXTRN_MDL_NAME_LBCS): + EXTRN_MDL_NAME_LBCS = \"${EXTRN_MDL_NAME_LBCS}\"" + ;; + +esac +# +#----------------------------------------------------------------------- +# +# Check that the executable that generates the LBCs exists. +# +#----------------------------------------------------------------------- +# +exec_fn="chgres_cube" +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for generating initial conditions on the FV3-LAM +native grid does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi +# +#----------------------------------------------------------------------- +# +# Loop through the LBC update times and run chgres_cube for each such time to +# obtain an LBC file for each that can be used as input to the FV3-LAM. +# +#----------------------------------------------------------------------- +# +num_fhrs="${#EXTRN_MDL_FHRS[@]}" +for (( i=0; i<${num_fhrs}; i++ )); do +# +# Get the forecast hour of the external model. +# + fhr="${EXTRN_MDL_FHRS[$i]}" +# +# Set external model output file name and file type/format. Note that +# these are now inputs into chgres_cube. +# + fn_atm="" + fn_grib2="" + + case "${EXTRN_MDL_NAME_LBCS}" in + "GSMGFS") + fn_atm="${EXTRN_MDL_FNS[$i]}" + ;; + "FV3GFS") + if [ "${FV3GFS_FILE_FMT_LBCS}" = "nemsio" ]; then + fn_atm="${EXTRN_MDL_FNS[$i]}" + elif [ "${FV3GFS_FILE_FMT_LBCS}" = "grib2" ]; then + fn_grib2="${EXTRN_MDL_FNS[$i]}" + elif [ "${FV3GFS_FILE_FMT_LBCS}" = "netcdf" ]; then + fn_atm="${EXTRN_MDL_FNS[$i]}" + fi + ;; + "RAP") + fn_grib2="${EXTRN_MDL_FNS[$i]}" + ;; + "HRRR") + fn_grib2="${EXTRN_MDL_FNS[$i]}" + ;; + "NAM") + fn_grib2="${EXTRN_MDL_FNS[$i]}" + ;; + *) + print_err_msg_exit "\ +The external model output file name to use in the chgres_cube FORTRAN name- +list file has not specified for this external LBC model (EXTRN_MDL_NAME_LBCS): + EXTRN_MDL_NAME_LBCS = \"${EXTRN_MDL_NAME_LBCS}\"" + ;; + esac +# +# Get the starting date (year, month, and day together), month, day, and +# hour of the the external model forecast. Then add the forecast hour +# to it to get a date and time corresponding to the current forecast time. +# + yyyymmdd="${EXTRN_MDL_CDATE:0:8}" + mm="${EXTRN_MDL_CDATE:4:2}" + dd="${EXTRN_MDL_CDATE:6:2}" + hh="${EXTRN_MDL_CDATE:8:2}" + + cdate_crnt_fhr=$( $DATE_UTIL --utc --date "${yyyymmdd} ${hh} UTC + ${fhr} hours" "+%Y%m%d%H" ) +# +# Get the month, day, and hour corresponding to the current forecast time +# of the the external model. +# + mm="${cdate_crnt_fhr:4:2}" + dd="${cdate_crnt_fhr:6:2}" + hh="${cdate_crnt_fhr:8:2}" +# +# Build the FORTRAN namelist file that chgres_cube will read in. +# + +# +# Create a multiline variable that consists of a yaml-compliant string +# specifying the values that the namelist variables need to be set to +# (one namelist variable per line, plus a header and footer). Below, +# this variable will be passed to a python script that will create the +# namelist file. +# +# IMPORTANT: +# If we want a namelist variable to be removed from the namelist file, +# in the "settings" variable below, we need to set its value to the +# string "null". This is equivalent to setting its value to +# !!python/none +# in the base namelist file specified by FV3_NML_BASE_SUITE_FP or the +# suite-specific yaml settings file specified by FV3_NML_YAML_CONFIG_FP. +# +# It turns out that setting the variable to an empty string also works +# to remove it from the namelist! Which is better to use?? +# +settings=" +'config': { + 'fix_dir_target_grid': ${FIXLAM}, + 'mosaic_file_target_grid': ${FIXLAM}/${CRES}${DOT_OR_USCORE}mosaic.halo$((10#${NH4})).nc, + 'orog_dir_target_grid': ${FIXLAM}, + 'orog_files_target_grid': ${CRES}${DOT_OR_USCORE}oro_data.tile${TILE_RGNL}.halo$((10#${NH4})).nc, + 'vcoord_file_target_grid': ${FIXam}/global_hyblev.l65.txt, + 'varmap_file': ${UFS_UTILS_DIR}/parm/varmap_tables/${varmap_file}, + 'data_dir_input_grid': ${extrn_mdl_staging_dir}, + 'atm_files_input_grid': ${fn_atm}, + 'grib2_file_input_grid': \"${fn_grib2}\", + 'cycle_mon': $((10#${mm})), + 'cycle_day': $((10#${dd})), + 'cycle_hour': $((10#${hh})), + 'convert_atm': True, + 'regional': 2, + 'halo_bndy': $((10#${NH4})), + 'halo_blend': $((10#${HALO_BLEND})), + 'input_type': ${input_type}, + 'external_model': ${external_model}, + 'tracers_input': ${tracers_input}, + 'tracers': ${tracers}, + 'thomp_mp_climo_file': ${thomp_mp_climo_file}, +} +" +# +# Call the python script to create the namelist file. +# + nml_fn="fort.41" + ${USHDIR}/set_namelist.py -q -u "$settings" -o ${nml_fn} || \ + print_err_msg_exit "\ +Call to python script set_namelist.py to set the variables in the namelist +file read in by the ${exec_fn} executable failed. Parameters passed to +this script are: + Name of output namelist file: + nml_fn = \"${nml_fn}\" + Namelist settings specified on command line (these have highest precedence): + settings = +$settings" +# +#----------------------------------------------------------------------- +# +# Run chgres_cube. +# +#----------------------------------------------------------------------- +# +# NOTE: +# Often when the chgres_cube.exe run fails, it still returns a zero +# return code, so the failure isn't picked up the the logical OR (||) +# below. That should be fixed. This might be due to the RUN_CMD_UTILS +# command - maybe that is returning a zero exit code even though the +# exit code of chgres_cube is nonzero. A similar thing happens in the +# forecast task. +# + ${RUN_CMD_UTILS} ${exec_fp} || \ + print_err_msg_exit "\ +Call to executable (exec_fp) to generate lateral boundary conditions (LBCs) +file for the FV3-LAM for forecast hour fhr failed: + exec_fp = \"${exec_fp}\" + fhr = \"$fhr\" +The external model from which the LBCs files are to be generated is: + EXTRN_MDL_NAME_LBCS = \"${EXTRN_MDL_NAME_LBCS}\" +The external model files that are inputs to the executable (exec_fp) are +located in the following directory: + extrn_mdl_staging_dir = \"${extrn_mdl_staging_dir}\"" +# +# Move LBCs file for the current lateral boundary update time to the LBCs +# work directory. Note that we rename the file by including in its name +# the forecast hour of the FV3-LAM (which is not necessarily the same as +# that of the external model since their start times may be offset). +# + fcst_hhh_FV3LAM=$( printf "%03d" "${LBC_SPEC_FCST_HRS[$i]}" ) + mv_vrfy gfs.bndy.nc ${lbcs_dir}/gfs_bndy.tile7.${fcst_hhh_FV3LAM}.nc + +done +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Lateral boundary condition (LBC) files (in NetCDF format) generated suc- +cessfully for all LBC update hours (except hour zero)!!! + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_make_orog.sh b/scripts/exregional_make_orog.sh new file mode 100755 index 0000000000..e0a5b48935 --- /dev/null +++ b/scripts/exregional_make_orog.sh @@ -0,0 +1,604 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that generates orography files. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. Then +# process the arguments provided to this script/function (which should +# consist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# +valid_args=() +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set OpenMP variables. The orog executable runs with OMP. +# +#----------------------------------------------------------------------- +# +export KMP_AFFINITY=${KMP_AFFINITY_MAKE_OROG} +export OMP_NUM_THREADS=${OMP_NUM_THREADS_MAKE_OROG} +export OMP_STACKSIZE=${OMP_STACKSIZE_MAKE_OROG} +# +#----------------------------------------------------------------------- +# +# Load modules and set various computational parameters and directories. +# +# Note: +# These module loads should all be moved to modulefiles. This has been +# done for Hera but must still be done for other machines. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +if [ -z "${RUN_CMD_SERIAL:-}" ] ; then + print_err_msg_exit "\ + Run command was not set in machine file. \ + Please set RUN_CMD_SERIAL for your platform" +else + RUN_CMD_SERIAL=$(eval echo ${RUN_CMD_SERIAL}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_SERIAL}\'." +fi +# +#----------------------------------------------------------------------- +# +# Create the (cycle-independent) subdirectories under the experiment +# directory (EXPTDIR) that are needed by the various steps and substeps +# in this script. +# +#----------------------------------------------------------------------- +# +check_for_preexist_dir_file "${OROG_DIR}" "${PREEXISTING_DIR_METHOD}" +mkdir_vrfy -p "${OROG_DIR}" + +raw_dir="${OROG_DIR}/raw_topo" +mkdir_vrfy -p "${raw_dir}" + +filter_dir="${OROG_DIR}/filtered_topo" +mkdir_vrfy -p "${filter_dir}" + +shave_dir="${OROG_DIR}/shave_tmp" +mkdir_vrfy -p "${shave_dir}" +# +# +#----------------------------------------------------------------------- +# +# Preparatory steps before calling raw orography generation code. +# +#----------------------------------------------------------------------- +# +# Set the name and path to the executable that generates the raw orography +# file and make sure that it exists. +# +exec_fn="orog" +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for generating the orography file does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi +# +# Create a temporary (work) directory in which to generate the raw orography +# file and change location to it. +# +tmp_dir="${raw_dir}/tmp" +mkdir_vrfy -p "${tmp_dir}" +cd_vrfy "${tmp_dir}" +# +# Copy topography and related data files from the system directory (TOPO_DIR) +# to the temporary directory. +# +cp_vrfy ${TOPO_DIR}/thirty.second.antarctic.new.bin fort.15 +cp_vrfy ${TOPO_DIR}/landcover30.fixed . +cp_vrfy ${TOPO_DIR}/gmted2010.30sec.int fort.235 +# +#----------------------------------------------------------------------- +# +# The orography filtering code reads in from the grid mosaic file the +# the number of tiles, the name of the grid file for each tile, and the +# dimensions (nx and ny) of each tile. Next, set the name of the grid +# mosaic file and create a symlink to it in filter_dir. +# +# Note that in the namelist file for the orography filtering code (created +# later below), the mosaic file name is saved in a variable called +# "grid_file". It would have been better to call this "mosaic_file" +# instead so it doesn't get confused with the grid file for a given tile... +# +#----------------------------------------------------------------------- +# +mosaic_fn="${CRES}${DOT_OR_USCORE}mosaic.halo${NHW}.nc" +mosaic_fp="$FIXLAM/${mosaic_fn}" + +grid_fn=$( get_charvar_from_netcdf "${mosaic_fp}" "gridfiles" ) || print_err_msg_exit "\ + get_charvar_from_netcdf function failed." +grid_fp="${FIXLAM}/${grid_fn}" +# +#----------------------------------------------------------------------- +# +# Set input parameters for the orography generation executable and write +# them to a text file. +# +# Note that it doesn't matter what lonb and latb are set to below because +# if we specify an input grid file to the executable read in (which is +# what we do below), then if lonb and latb are not set to the dimensions +# of the grid specified in that file (divided by 2 since the grid file +# specifies a "supergrid"), then lonb and latb effectively get reset to +# the dimensions specified in the grid file. +# +#----------------------------------------------------------------------- +# +mtnres=1 +#lonb=$res +#latb=$res +lonb=0 +latb=0 +jcap=0 +NR=0 +NF1=0 +NF2=0 +efac=0 +blat=0 + +input_redirect_fn="INPS" +orogfile="none" + +echo $mtnres $lonb $latb $jcap $NR $NF1 $NF2 $efac $blat > "${input_redirect_fn}" +# +# The following two inputs are read in as strings, so they must be quoted +# in the input file. +# +echo "\"${grid_fp}\"" >> "${input_redirect_fn}" +echo "\"$orogfile\"" >> "${input_redirect_fn}" +cat "${input_redirect_fn}" +# +#----------------------------------------------------------------------- +# +# Call the executable to generate the raw orography file corresponding +# to tile 7 (the regional domain) only. +# +# The following will create an orography file named +# +# oro.${CRES}.tile7.nc +# +# and will place it in OROG_DIR. Note that this file will include +# orography for a halo of width NHW cells around tile 7. The follow- +# ing will also create a work directory called tile7 under OROG_DIR. +# This work directory can be removed after the orography file has been +# created (it is currently not deleted). +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "\ +Starting orography file generation..." + +${RUN_CMD_SERIAL} "${exec_fp}" < "${input_redirect_fn}" || \ + print_err_msg_exit "\ +Call to executable (exec_fp) that generates the raw orography file returned +with nonzero exit code: + exec_fp = \"${exec_fp}\"" + +# +# Change location to the original directory. +# +cd_vrfy - +# +#----------------------------------------------------------------------- +# +# Move the raw orography file from the temporary directory to raw_dir. +# In the process, rename it such that its name includes CRES and the halo +# width. +# +#----------------------------------------------------------------------- +# +raw_orog_fp_orig="${tmp_dir}/out.oro.nc" +raw_orog_fn_prefix="${CRES}${DOT_OR_USCORE}raw_orog" +fn_suffix_with_halo="tile${TILE_RGNL}.halo${NHW}.nc" +raw_orog_fn="${raw_orog_fn_prefix}.${fn_suffix_with_halo}" +raw_orog_fp="${raw_dir}/${raw_orog_fn}" +mv_vrfy "${raw_orog_fp_orig}" "${raw_orog_fp}" +# +#----------------------------------------------------------------------- +# +# Call the code to generate the two orography statistics files (large- +# and small-scale) needed for the drag suite in the FV3_HRRR physics +# suite. +# +#----------------------------------------------------------------------- +# +if [ "${CCPP_PHYS_SUITE}" = "FV3_HRRR" ]; then + tmp_dir="${OROG_DIR}/temp_orog_data" + mkdir_vrfy -p ${tmp_dir} + cd_vrfy ${tmp_dir} + mosaic_fn_gwd="${CRES}${DOT_OR_USCORE}mosaic.halo${NH4}.nc" + mosaic_fp_gwd="$FIXLAM/${mosaic_fn_gwd}" + grid_fn_gwd=$( get_charvar_from_netcdf "${mosaic_fp_gwd}" "gridfiles" ) || \ + print_err_msg_exit "get_charvar_from_netcdf function failed." + grid_fp_gwd="${FIXLAM}/${grid_fn_gwd}" + ls_fn="geo_em.d01.lat-lon.2.5m.HGT_M.nc" + ss_fn="HGT.Beljaars_filtered.lat-lon.30s_res.nc" + create_symlink_to_file target="${grid_fp_gwd}" symlink="${tmp_dir}/${grid_fn_gwd}" \ + relative="TRUE" + create_symlink_to_file target="${FIXam}/${ls_fn}" symlink="${tmp_dir}/${ls_fn}" \ + relative="TRUE" + create_symlink_to_file target="${FIXam}/${ss_fn}" symlink="${tmp_dir}/${ss_fn}" \ + relative="TRUE" + + input_redirect_fn="grid_info.dat" + cat > "${input_redirect_fn}" < "${filter_dir}/input.nml" < ${nml_fn} + +${RUN_CMD_SERIAL} ${exec_fp} < ${nml_fn} || \ +print_err_msg_exit "\ +Call to executable (exec_fp) to generate a (filtered) orography file with +a ${NH0}-cell-wide halo from the orography file with a {NHW}-cell-wide halo +returned with nonzero exit code: + exec_fp = \"${exec_fp}\" +The namelist file (nml_fn) used in this call is in directory shave_dir: + nml_fn = \"${nml_fn}\" + shave_dir = \"${shave_dir}\"" +mv_vrfy ${shaved_fp} ${OROG_DIR} +# +# Create an input namelist file for the shave executable to generate an +# orography file with a 4-cell-wide halo from the one with a wide halo. +# Then call the shave executable. Finally, move the resultant file to +# the OROG_DIR directory. +# +print_info_msg "$VERBOSE" " +\"Shaving\" filtered orography file with a ${NHW}-cell-wide halo to obtain +a filtered orography file with a ${NH4}-cell-wide halo..." + +nml_fn="input.shave.orog.halo${NH4}" +shaved_fp="${shave_dir}/${CRES}${DOT_OR_USCORE}oro_data.tile${TILE_RGNL}.halo${NH4}.nc" +printf "%s %s %s %s %s\n" \ + $NX $NY ${NH4} \"${unshaved_fp}\" \"${shaved_fp}\" \ + > ${nml_fn} + +${RUN_CMD_SERIAL} ${exec_fp} < ${nml_fn} || \ +print_err_msg_exit "\ +Call to executable (exec_fp) to generate a (filtered) orography file with +a ${NH4}-cell-wide halo from the orography file with a {NHW}-cell-wide halo +returned with nonzero exit code: + exec_fp = \"${exec_fp}\" +The namelist file (nml_fn) used in this call is in directory shave_dir: + nml_fn = \"${nml_fn}\" + shave_dir = \"${shave_dir}\"" +mv_vrfy "${shaved_fp}" "${OROG_DIR}" +# +# Change location to the original directory. +# +cd_vrfy - +# +#----------------------------------------------------------------------- +# +# Add link in ORIG_DIR directory to the orography file with a 4-cell-wide +# halo such that the link name do not contain the halo width. These links +# are needed by the make_sfc_climo task. +# +# NOTE: It would be nice to modify the sfc_climo_gen_code to read in +# files that have the halo size in their names. +# +#----------------------------------------------------------------------- +# +python3 $USHDIR/link_fix.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + --file-group "orog" || \ +print_err_msg_exit "\ +Call to function to create links to orography files failed." +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Orography files with various halo widths generated successfully!!! + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + + diff --git a/scripts/exregional_make_sfc_climo.sh b/scripts/exregional_make_sfc_climo.sh new file mode 100755 index 0000000000..995b17f305 --- /dev/null +++ b/scripts/exregional_make_sfc_climo.sh @@ -0,0 +1,263 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that generates surface fields from +climatology. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "workdir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set OpenMP variables. +# +#----------------------------------------------------------------------- +# +export KMP_AFFINITY=${KMP_AFFINITY_MAKE_SFC_CLIMO} +export OMP_NUM_THREADS=${OMP_NUM_THREADS_MAKE_SFC_CLIMO} +export OMP_STACKSIZE=${OMP_STACKSIZE_MAKE_SFC_CLIMO} +# +#----------------------------------------------------------------------- +# +# Are these machine dependent?? +# +#----------------------------------------------------------------------- +# +ulimit -s unlimited +# +#----------------------------------------------------------------------- +# +# Change location to the temporary directory. +# +#----------------------------------------------------------------------- +# +cd_vrfy $workdir +# +#----------------------------------------------------------------------- +# +# Create the namelist that the sfc_climo_gen code will read in. +# +# Question: Should this instead be created from a template file? +# +#----------------------------------------------------------------------- +# +cat << EOF > ./fort.41 +&config +input_facsf_file="${SFC_CLIMO_INPUT_DIR}/facsf.1.0.nc" +input_substrate_temperature_file="${SFC_CLIMO_INPUT_DIR}/substrate_temperature.2.6x1.5.nc" +input_maximum_snow_albedo_file="${SFC_CLIMO_INPUT_DIR}/maximum_snow_albedo.0.05.nc" +input_snowfree_albedo_file="${SFC_CLIMO_INPUT_DIR}/snowfree_albedo.4comp.0.05.nc" +input_slope_type_file="${SFC_CLIMO_INPUT_DIR}/slope_type.1.0.nc" +input_soil_type_file="${SFC_CLIMO_INPUT_DIR}/soil_type.statsgo.0.05.nc" +input_vegetation_type_file="${SFC_CLIMO_INPUT_DIR}/vegetation_type.igbp.0.05.nc" +input_vegetation_greenness_file="${SFC_CLIMO_INPUT_DIR}/vegetation_greenness.0.144.nc" +mosaic_file_mdl="${FIXLAM}/${CRES}${DOT_OR_USCORE}mosaic.halo${NH4}.nc" +orog_dir_mdl="${FIXLAM}" +orog_files_mdl="${CRES}${DOT_OR_USCORE}oro_data.tile${TILE_RGNL}.halo${NH4}.nc" +halo=${NH4} +maximum_snow_albedo_method="bilinear" +snowfree_albedo_method="bilinear" +vegetation_greenness_method="bilinear" +/ +EOF +# +#----------------------------------------------------------------------- +# +# Set the machine-dependent run command. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +nprocs=$(( NNODES_MAKE_SFC_CLIMO*PPN_MAKE_SFC_CLIMO )) + +if [ -z "${RUN_CMD_UTILS:-}" ] ; then + print_err_msg_exit "\ + Run command was not set in machine file. \ + Please set RUN_CMD_UTILS for your platform" +else + RUN_CMD_UTILS=$(eval echo ${RUN_CMD_UTILS}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_UTILS}\'." +fi +# +#----------------------------------------------------------------------- +# +# Generate the surface climatology files. +# +#----------------------------------------------------------------------- +# +# Set the name and path to the executable and make sure that it exists. +# +exec_fn="sfc_climo_gen" +exec_fp="$EXECDIR/${exec_fn}" +if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for generating the surface climatology files +does not exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." +fi + +${RUN_CMD_UTILS} ${exec_fp} || \ +print_err_msg_exit "\ +Call to executable (exec_fp) to generate surface climatology files returned +with nonzero exit code: + exec_fp = \"${exec_fp}\"" +# +#----------------------------------------------------------------------- +# +# Move output files out of the temporary directory. +# +#----------------------------------------------------------------------- +# +case "$GTYPE" in + +# +# Consider, global, stetched, and nested grids. +# +"global" | "stretch" | "nested") +# +# Move all files ending with ".nc" to the SFC_CLIMO_DIR directory. +# In the process, rename them so that the file names start with the C- +# resolution (followed by an underscore). +# + for fn in *.nc; do + if [[ -f $fn ]]; then + mv_vrfy $fn ${SFC_CLIMO_DIR}/${CRES}_${fn} + fi + done + ;; + +# +# Consider regional grids. +# +"regional") +# +# Move all files ending with ".halo.nc" (which are the files for a grid +# that includes the specified non-zero-width halo) to the WORKDIR_SFC_- +# CLIMO directory. In the process, rename them so that the file names +# start with the C-resolution (followed by a dot) and contain the (non- +# zero) halo width (in units of number of grid cells). +# + for fn in *.halo.nc; do + if [ -f $fn ]; then + bn="${fn%.halo.nc}" + mv_vrfy $fn ${SFC_CLIMO_DIR}/${CRES}.${bn}.halo${NH4}.nc + fi + done +# +# Move all remaining files ending with ".nc" (which are the files for a +# grid that doesn't include a halo) to the SFC_CLIMO_DIR directory. +# In the process, rename them so that the file names start with the C- +# resolution (followed by a dot) and contain the string "halo0" to indi- +# cate that the grids in these files do not contain a halo. +# + for fn in *.nc; do + if [ -f $fn ]; then + bn="${fn%.nc}" + mv_vrfy $fn ${SFC_CLIMO_DIR}/${CRES}.${bn}.halo${NH0}.nc + fi + done + ;; + +esac +# +#----------------------------------------------------------------------- +# +# Can these be moved to stage_static if this script is called before +# stage_static.sh???? +# These have been moved. Can delete the following after testing. +# +#----------------------------------------------------------------------- +# +python3 $USHDIR/link_fix.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + --file-group "sfc_climo" || \ +print_err_msg_exit "\ +Call to function to create links to surface climatology files failed." +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +All surface climatology files generated successfully!!! + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_ensgridvx.sh b/scripts/exregional_run_ensgridvx.sh new file mode 100755 index 0000000000..8b8736ec42 --- /dev/null +++ b/scripts/exregional_run_ensgridvx.sh @@ -0,0 +1,201 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for ensemble-stat on +the UPP output files by initialization time for all forecast hours for +gridded data. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args + +#----------------------------------------------------------------------- +# +# Begin grid-to-grid ensemble vx. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "Starting ensemble-stat verification" + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Read in FHR and create a comma-separated list +# for METplus to run over. Determine the number padding needed based +# on number of ensemble members. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +NUM_PAD=${NDIGITS_ENSMEM_NAMES} + +# +#----------------------------------------------------------------------- +# +# Create LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# + +if [ ${VAR} == "APCP" ]; then + LOG_SUFFIX=ensgrid_${CDATE}_${VAR}_${ACCUM}h +else + LOG_SUFFIX=ensgrid_${CDATE}_${VAR} +fi + +# +#----------------------------------------------------------------------- +# +# Make sure directories in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/ensemble_stat" # Output directory for ensemble_stat tool. + +# +# If the variable is accumulated precipitation for a time interval +# (bucket) other than 1 hour, the MET/METplus tools called below will +# include pcp_combine. In that case, create (if necessary) directories +# needed by pcp_combine. +# +if [ "${VAR}" = "APCP" ] && [ "${ACCUM: -1}" != "1" ]; then + mkdir_vrfy -p "${EXPTDIR}/metprd/pcp_combine" # For observations + mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/pcp_combine" # For forecast +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML +# +#----------------------------------------------------------------------- +# +export SCRIPTSDIR +export EXPTDIR +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME +export NUM_ENS_MEMBERS +export NUM_PAD +export LOG_SUFFIX + +# +#----------------------------------------------------------------------- +# +# Run METplus +# +#----------------------------------------------------------------------- +# +if [ ${VAR} == "APCP" ]; then + acc="${ACCUM}h" # for stats output prefix in EnsembleStatConfig + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/EnsembleStat_${VAR}${acc}.conf +else + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/EnsembleStat_${VAR}.conf +fi + +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus ensemble-stat grid completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_ensgridvx_mean.sh b/scripts/exregional_run_ensgridvx_mean.sh new file mode 100755 index 0000000000..faa56d5caa --- /dev/null +++ b/scripts/exregional_run_ensgridvx_mean.sh @@ -0,0 +1,199 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for grid-stat on +the UPP output files by initialization time for all forecast hours for +gridded data. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args + +#----------------------------------------------------------------------- +# +# Begin grid-to-grid vx on ensemble output. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "Starting grid-stat verification" + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create INPUT_BASE and LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +INPUT_BASE=${EXPTDIR}/${CDATE}/metprd/ensemble_stat + +if [ ${VAR} == "APCP" ]; then + LOG_SUFFIX=ensgrid_mean_${CDATE}_${VAR}_${ACCUM}h +else + LOG_SUFFIX=ensgrid_mean_${CDATE}_${VAR} +fi + +# +#----------------------------------------------------------------------- +# +# Make sure directory in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/ensemble_stat_mean" # Output directory for grid_stat tool. + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML +# +#----------------------------------------------------------------------- +# +export SCRIPTSDIR +export EXPTDIR +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME +export INPUT_BASE +export LOG_SUFFIX + +# +#----------------------------------------------------------------------- +# +# Run METplus +# +#----------------------------------------------------------------------- +# +if [ ${VAR} == "APCP" ]; then + export acc="${ACCUM}h" + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/GridStat_${VAR}${acc}_mean.conf +else + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/GridStat_${VAR}_mean.conf +fi + +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus grid-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_ensgridvx_prob.sh b/scripts/exregional_run_ensgridvx_prob.sh new file mode 100755 index 0000000000..dc32f599a4 --- /dev/null +++ b/scripts/exregional_run_ensgridvx_prob.sh @@ -0,0 +1,199 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for grid-stat on +the UPP output files by initialization time for all forecast hours for +gridded data. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args + +#----------------------------------------------------------------------- +# +# Begin grid-to-grid vx on ensemble output. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "Starting grid-stat verification" + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create INPUT_BASE and LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +INPUT_BASE=${EXPTDIR}/${CDATE}/metprd/ensemble_stat + +if [ ${VAR} == "APCP" ]; then + LOG_SUFFIX=ensgrid_prob_${CDATE}_${VAR}_${ACCUM}h +else + LOG_SUFFIX=ensgrid_prob_${CDATE}_${VAR} +fi + +# +#----------------------------------------------------------------------- +# +# Make sure directory in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/ensemble_stat_prob" # Output directory for grid_stat tool. + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML +# +#----------------------------------------------------------------------- +# +export SCRIPTSDIR +export INPUT_BASE +export EXPTDIR +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME +export LOG_SUFFIX + +# +#----------------------------------------------------------------------- +# +# Run METplus +# +#----------------------------------------------------------------------- +# +if [ ${VAR} == "APCP" ]; then + export acc="${ACCUM}h" + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/GridStat_${VAR}${acc}_prob.conf +else + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/GridStat_${VAR}_prob.conf +fi + +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus grid-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_enspointvx.sh b/scripts/exregional_run_enspointvx.sh new file mode 100755 index 0000000000..3ac4401c27 --- /dev/null +++ b/scripts/exregional_run_enspointvx.sh @@ -0,0 +1,181 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for point-stat on +the UPP output files by initialization time for all forecast hours. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +#----------------------------------------------------------------------- +# +# Begin grid-to-point ensemble vx. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "Starting point-based ensemble-stat verification" + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +LOG_SUFFIX=enspoint_${CDATE} + +# +#----------------------------------------------------------------------- +# +# Make sure directories in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/metprd/pb2nc" # Output directory for pb2nc tool. +mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/ensemble_stat" # Output directory for ensemble_stat tool. + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML and run METplus +# +#----------------------------------------------------------------------- +# +export EXPTDIR +export LOG_SUFFIX +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME +export NUM_ENS_MEMBERS + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/EnsembleStat_conus_sfc.conf + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/EnsembleStat_upper_air.conf + +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus ensemble-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_enspointvx_mean.sh b/scripts/exregional_run_enspointvx_mean.sh new file mode 100755 index 0000000000..cd9ee7004c --- /dev/null +++ b/scripts/exregional_run_enspointvx_mean.sh @@ -0,0 +1,181 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for point-stat on +the UPP output files by initialization time for all forecast hours. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +#----------------------------------------------------------------------- +# +# Begin grid-to-point vx on ensemble output. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "Starting point-stat verification" + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create INPUT_BASE and LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +INPUT_BASE=${EXPTDIR}/${CDATE}/metprd/ensemble_stat +LOG_SUFFIX=enspoint_mean_${CDATE} + +# +#----------------------------------------------------------------------- +# +# Make sure directories in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/metprd/pb2nc" # Output directory for pb2nc tool. +mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/ensemble_stat_mean" # Output directory for point_stat tool. + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML and run METplus +# +#----------------------------------------------------------------------- +# +export EXPTDIR +export INPUT_BASE +export LOG_SUFFIX +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/PointStat_conus_sfc_mean.conf + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/PointStat_upper_air_mean.conf +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus ensemble-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_enspointvx_prob.sh b/scripts/exregional_run_enspointvx_prob.sh new file mode 100755 index 0000000000..4e025125cb --- /dev/null +++ b/scripts/exregional_run_enspointvx_prob.sh @@ -0,0 +1,181 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for point-stat on +the UPP output files by initialization time for all forecast hours. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +#----------------------------------------------------------------------- +# +# Begin grid-to-point vx on ensemble output. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" "Starting point-stat verification" + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create INPUT_BASE and LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +INPUT_BASE=${EXPTDIR}/${CDATE}/metprd/ensemble_stat +LOG_SUFFIX=enspoint_prob_${CDATE} + +# +#----------------------------------------------------------------------- +# +# Make sure directories in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/metprd/pb2nc" # Output directory for pb2nc tool. +mkdir_vrfy -p "${EXPTDIR}/${CDATE}/metprd/ensemble_stat_prob" # Output directory for point_stat tool. + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML and run METplus +# +#----------------------------------------------------------------------- +# +export EXPTDIR +export INPUT_BASE +export LOG_SUFFIX +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/PointStat_conus_sfc_prob.conf + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/PointStat_upper_air_prob.conf +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus ensemble-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_fcst.sh b/scripts/exregional_run_fcst.sh new file mode 100755 index 0000000000..f3dcabeb9a --- /dev/null +++ b/scripts/exregional_run_fcst.sh @@ -0,0 +1,573 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs a forecast with FV3 for the +specified cycle. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ +"cdate" \ +"cycle_dir" \ +"ensmem_indx" \ +"slash_ensmem_subdir" \ +) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set OpenMP variables. +# +#----------------------------------------------------------------------- +# +export KMP_AFFINITY=${KMP_AFFINITY_RUN_FCST} +export OMP_NUM_THREADS=${OMP_NUM_THREADS_RUN_FCST} +export OMP_STACKSIZE=${OMP_STACKSIZE_RUN_FCST} +# +#----------------------------------------------------------------------- +# +# Load modules. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +nprocs=$(( NNODES_RUN_FCST*PPN_RUN_FCST )) + +if [ -z "${RUN_CMD_FCST:-}" ] ; then + print_err_msg_exit "\ + Run command was not set in machine file. \ + Please set RUN_CMD_FCST for your platform" +else + RUN_CMD_FCST=$(eval echo ${RUN_CMD_FCST}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_FCST}\'." +fi +# +#----------------------------------------------------------------------- +# +# Set the forecast run directory. +# +#----------------------------------------------------------------------- +# +run_dir="${cycle_dir}${slash_ensmem_subdir}" +# +#----------------------------------------------------------------------- +# +# Create links in the INPUT subdirectory of the current run directory to +# the grid and (filtered) orography files. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" " +Creating links in the INPUT subdirectory of the current run directory to +the grid and (filtered) orography files ..." + + +# Create links to fix files in the FIXLAM directory. + + +cd_vrfy ${run_dir}/INPUT + +# +# For experiments in which the MAKE_GRID_TN task is run, we make the +# symlinks to the grid files relative because those files wlll be located +# within the experiment directory. This keeps the experiment directory +# more portable and the symlinks more readable. However, for experiments +# in which the MAKE_GRID_TN task is not run, pregenerated grid files will +# be used, and those will be located in an arbitrary directory (specified +# by the user) that is somwehere outside the experiment directory. Thus, +# in this case, there isn't really an advantage to using relative symlinks, +# so we use symlinks with absolute paths. +# +if [ "${RUN_TASK_MAKE_GRID}" = "TRUE" ]; then + relative_link_flag="TRUE" +else + relative_link_flag="FALSE" +fi + +# Symlink to mosaic file with a completely different name. +#target="${FIXLAM}/${CRES}${DOT_OR_USCORE}mosaic.halo${NH4}.nc" # Should this point to this halo4 file or a halo3 file??? +target="${FIXLAM}/${CRES}${DOT_OR_USCORE}mosaic.halo${NH3}.nc" # Should this point to this halo4 file or a halo3 file??? +symlink="grid_spec.nc" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + +## Symlink to halo-3 grid file with "halo3" stripped from name. +#target="${FIXLAM}/${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NH3}.nc" +#if [ "${RUN_TASK_MAKE_SFC_CLIMO}" = "TRUE" ] && \ +# [ "${GRID_GEN_METHOD}" = "GFDLgrid" ] && \ +# [ "${GFDLgrid_USE_NUM_CELLS_IN_FILENAMES}" = "FALSE" ]; then +# symlink="C${GFDLgrid_NUM_CELLS}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.nc" +#else +# symlink="${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.nc" +#fi + +# Symlink to halo-3 grid file with "halo3" stripped from name. +mosaic_fn="grid_spec.nc" +grid_fn=$( get_charvar_from_netcdf "${mosaic_fn}" "gridfiles" ) + +target="${FIXLAM}/${grid_fn}" +symlink="${grid_fn}" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + +# Symlink to halo-4 grid file with "${CRES}_" stripped from name. +# +# If this link is not created, then the code hangs with an error message +# like this: +# +# check netcdf status= 2 +# NetCDF error No such file or directory +# Stopped +# +# Note that even though the message says "Stopped", the task still con- +# sumes core-hours. +# +target="${FIXLAM}/${CRES}${DOT_OR_USCORE}grid.tile${TILE_RGNL}.halo${NH4}.nc" +symlink="grid.tile${TILE_RGNL}.halo${NH4}.nc" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + + +# +# As with the symlinks grid files above, when creating the symlinks to +# the orography files, use relative paths if running the MAKE_OROG_TN +# task and absolute paths otherwise. +# +if [ "${RUN_TASK_MAKE_OROG}" = "TRUE" ]; then + relative_link_flag="TRUE" +else + relative_link_flag="FALSE" +fi + +# Symlink to halo-0 orography file with "${CRES}_" and "halo0" stripped from name. +target="${FIXLAM}/${CRES}${DOT_OR_USCORE}oro_data.tile${TILE_RGNL}.halo${NH0}.nc" +symlink="oro_data.nc" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" +# +# Symlink to halo-4 orography file with "${CRES}_" stripped from name. +# +# If this link is not created, then the code hangs with an error message +# like this: +# +# check netcdf status= 2 +# NetCDF error No such file or directory +# Stopped +# +# Note that even though the message says "Stopped", the task still con- +# sumes core-hours. +# +target="${FIXLAM}/${CRES}${DOT_OR_USCORE}oro_data.tile${TILE_RGNL}.halo${NH4}.nc" +symlink="oro_data.tile${TILE_RGNL}.halo${NH4}.nc" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" +# +# If using the FV3_HRRR physics suite, there are two files (that contain +# statistics of the orography) that are needed by the gravity wave drag +# parameterization in that suite. Below, create symlinks to these files +# in the run directory. Note that the symlinks must have specific names +# that the FV3 model is hardcoded to recognize, and those are the names +# we use below. +# +if [ "${CCPP_PHYS_SUITE}" = "FV3_HRRR" ]; then + + fileids=( "ss" "ls" ) + for fileid in "${fileids[@]}"; do + target="${FIXLAM}/${CRES}${DOT_OR_USCORE}oro_data_${fileid}.tile${TILE_RGNL}.halo${NH0}.nc" + symlink="oro_data_${fileid}.nc" + create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + done + +fi + +# +#----------------------------------------------------------------------- +# +# The FV3 model looks for the following files in the INPUT subdirectory +# of the run directory: +# +# gfs_data.nc +# sfc_data.nc +# gfs_bndy*.nc +# gfs_ctrl.nc +# +# Some of these files (gfs_ctrl.nc, gfs_bndy*.nc) already exist, but +# others do not. Thus, create links with these names to the appropriate +# files (in this case the initial condition and surface files only). +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" " +Creating links with names that FV3 looks for in the INPUT subdirectory +of the current run directory (run_dir), where + run_dir = \"${run_dir}\" +..." + +cd_vrfy ${run_dir}/INPUT +# +# The symlinks to be created point to files in the same directory (INPUT), +# so it's most straightforward to use relative paths. +# +relative_link_flag="TRUE" + +target="gfs_data.tile${TILE_RGNL}.halo${NH0}.nc" +symlink="gfs_data.nc" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + +target="sfc_data.tile${TILE_RGNL}.halo${NH0}.nc" +symlink="sfc_data.nc" +create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" +# +#----------------------------------------------------------------------- +# +# Create links in the current run directory to fixed (i.e. static) files +# in the FIXam directory. These links have names that are set to the +# names of files that the forecast model expects to exist in the current +# working directory when the forecast model executable is called (and +# that is just the run directory). +# +#----------------------------------------------------------------------- +# +cd_vrfy ${run_dir} + +print_info_msg "$VERBOSE" " +Creating links in the current run directory (run_dir) to fixed (i.e. +static) files in the FIXam directory: + FIXam = \"${FIXam}\" + run_dir = \"${run_dir}\"" +# +# For experiments that are run in "community" mode, the FIXam directory +# is an actual directory (i.e. not a symlink) located under the experiment +# directory containing actual files (i.e. not symlinks). In this case, +# we use relative paths for the symlinks in order to keep the experiment +# directory more portable and the symlinks more readable. However, for +# experiments that are run in "nco" mode, the FIXam directory is a symlink +# under the experiment directory that points to an arbitrary (user specified) +# location outside the experiment directory. Thus, in this case, there +# isn't really an advantage to using relative symlinks, so we use symlinks +# with absolute paths. +# +if [ "${RUN_ENVIR}" != "nco" ]; then + relative_link_flag="TRUE" +else + relative_link_flag="FALSE" +fi + +regex_search="^[ ]*([^| ]+)[ ]*[|][ ]*([^| ]+)[ ]*$" +num_symlinks=${#CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING[@]} +for (( i=0; i<${num_symlinks}; i++ )); do + + mapping="${CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING[$i]}" + symlink=$( printf "%s\n" "$mapping" | \ + $SED -n -r -e "s/${regex_search}/\1/p" ) + target=$( printf "%s\n" "$mapping" | \ + $SED -n -r -e "s/${regex_search}/\2/p" ) + + symlink="${run_dir}/$symlink" + target="$FIXam/$target" + create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + +done +# +#----------------------------------------------------------------------- +# +# Create links in the current run directory to the MERRA2 aerosol +# climatology data files and lookup table for optics properties. +# +#----------------------------------------------------------------------- +# +if [ "${USE_MERRA_CLIMO}" = "TRUE" ]; then + for f_nm_path in ${FIXclim}/*; do + f_nm=$( basename "${f_nm_path}" ) + pre_f="${f_nm%%.*}" + + if [ "${pre_f}" = "merra2" ]; then + mnth=$( printf "%s\n" "${f_nm}" | grep -o -P '(?<=2014.m).*(?=.nc)' ) + symlink="${run_dir}/aeroclim.m${mnth}.nc" + else + symlink="${run_dir}/${pre_f}.dat" + fi + target="${f_nm_path}" + create_symlink_to_file target="$target" symlink="$symlink" \ + relative="${relative_link_flag}" + done +fi +# +#----------------------------------------------------------------------- +# +# If running this cycle/ensemble member combination more than once (e.g. +# using rocotoboot), remove any time stamp file that may exist from the +# previous attempt. +# +#----------------------------------------------------------------------- +# +cd_vrfy ${run_dir} +rm_vrfy -f time_stamp.out +# +#----------------------------------------------------------------------- +# +# Create links in the current run directory to cycle-independent (and +# ensemble-member-independent) model input files in the main experiment +# directory. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" " +Creating links in the current run directory to cycle-independent model +input files in the main experiment directory..." +# +# For experiments that are run in "community" mode, the model input files +# to which the symlinks will point are under the experiment directory. +# Thus, in this case, we use relative paths for the symlinks in order to +# keep the experiment directory more portable and the symlinks more readable. +# However, for experiments that are run in "nco" mode, the experiment +# directory in which the model input files are located is in general +# completely different than the run directory in which the symlinks will +# be created. Thus, in this case, there isn't really an advantage to +# using relative symlinks, so we use symlinks with absolute paths. +# +if [ "${RUN_ENVIR}" != "nco" ]; then + relative_link_flag="TRUE" +else + relative_link_flag="FALSE" +fi + +create_symlink_to_file target="${DATA_TABLE_FP}" \ + symlink="${run_dir}/${DATA_TABLE_FN}" \ + relative="${relative_link_flag}" + +create_symlink_to_file target="${FIELD_TABLE_FP}" \ + symlink="${run_dir}/${FIELD_TABLE_FN}" \ + relative="${relative_link_flag}" + +create_symlink_to_file target="${NEMS_CONFIG_FP}" \ + symlink="${run_dir}/${NEMS_CONFIG_FN}" \ + relative="${relative_link_flag}" + +create_symlink_to_file target="${FIELD_DICT_FP}" \ + symlink="${run_dir}/${FIELD_DICT_FN}" \ + relative="${relative_link_flag}" + +if [ ${WRITE_DOPOST} = "TRUE" ]; then + cp_vrfy ${UPP_DIR}/parm/nam_micro_lookup.dat ./eta_micro_lookup.dat + if [ ${USE_CUSTOM_POST_CONFIG_FILE} = "TRUE" ]; then + post_config_fp="${CUSTOM_POST_CONFIG_FP}" + print_info_msg " +==================================================================== + CUSTOM_POST_CONFIG_FP = \"${CUSTOM_POST_CONFIG_FP}\" +====================================================================" + else + post_config_fp="${UPP_DIR}/parm/postxconfig-NT-fv3lam.txt" + print_info_msg " +==================================================================== + post_config_fp = \"${post_config_fp}\" +====================================================================" + fi + cp_vrfy ${post_config_fp} ./postxconfig-NT_FH00.txt + cp_vrfy ${post_config_fp} ./postxconfig-NT.txt + cp_vrfy ${UPP_DIR}/parm/params_grib2_tbl_new . +fi + +if [ "${DO_ENSEMBLE}" = TRUE ] && ([ "${DO_SPP}" = TRUE ] || [ "${DO_SPPT}" = TRUE ] || [ "${DO_SHUM}" = TRUE ] || \ + [ "${DO_SKEB}" = TRUE ] || [ "${DO_LSM_SPP}" = TRUE ]); then + python3 $USHDIR/set_FV3nml_ens_stoch_seeds.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + --cdate "$cdate" || print_err_msg_exit "\ +Call to function to create the ensemble-based namelist for the current +cycle's (cdate) run directory (run_dir) failed: + cdate = \"${cdate}\" + run_dir = \"${run_dir}\"" +else + create_symlink_to_file target="${FV3_NML_FP}" \ + symlink="${run_dir}/${FV3_NML_FN}" \ + relative="${relative_link_flag}" +fi +# +#----------------------------------------------------------------------- +# +# Call the function that creates the model configuration file within each +# cycle directory. +# +#----------------------------------------------------------------------- +# +python3 $USHDIR/create_model_configure_file.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + --cdate "$cdate" \ + --run-dir "${run_dir}" \ + --sub-hourly-post "${SUB_HOURLY_POST}" \ + --dt-subhourly-post-mnts "${DT_SUBHOURLY_POST_MNTS}" \ + --dt-atmos "${DT_ATMOS}" || print_err_msg_exit "\ +Call to function to create a model configuration file for the current +cycle's (cdate) run directory (run_dir) failed: + cdate = \"${cdate}\" + run_dir = \"${run_dir}\"" +# +#----------------------------------------------------------------------- +# +# Call the function that creates the diag_table file within each cycle +# directory. +# +#----------------------------------------------------------------------- +# +python3 $USHDIR/create_diag_table_file.py \ + --path-to-defns ${GLOBAL_VAR_DEFNS_FP} \ + --run-dir "${run_dir}" || print_err_msg_exit "\ +Call to function to create a diag table file for the current cycle's +(cdate) run directory (run_dir) failed: + run_dir = \"${run_dir}\"" +# +#----------------------------------------------------------------------- +# +# Run the FV3-LAM model. Note that we have to launch the forecast from +# the current cycle's directory because the FV3 executable will look for +# input files in the current directory. Since those files have been +# staged in the cycle directory, the current directory must be the cycle +# directory (which it already is). +# +#----------------------------------------------------------------------- +# +${RUN_CMD_FCST} ${FV3_EXEC_FP} || print_err_msg_exit "\ +Call to executable to run FV3-LAM forecast returned with nonzero exit +code." +# +#----------------------------------------------------------------------- +# +# If doing inline post, create the directory in which the post-processing +# output will be stored (postprd_dir). +# +#----------------------------------------------------------------------- +# +if [ ${WRITE_DOPOST} = "TRUE" ]; then + + yyyymmdd=${cdate:0:8} + hh=${cdate:8:2} + cyc=$hh + fmn="00" + + if [ "${RUN_ENVIR}" = "nco" ]; then + COMOUT="${COMOUT_BASEDIR}/$RUN.$PDY/$cyc${SLASH_ENSMEM_SUBDIR}" + postprd_dir="$COMOUT" + else + postprd_dir="${run_dir}/postprd" + fi + mkdir_vrfy -p "${postprd_dir}" + + cd_vrfy ${postprd_dir} + + for fhr in $(seq -f "%03g" 0 ${FCST_LEN_HRS}); do + + if [ ${fhr:0:1} = "0" ]; then + fhr_d=${fhr:1:2} + else + fhr_d=${fhr} + fi + + post_time=$( $DATE_UTIL --utc --date "${yyyymmdd} ${hh} UTC + ${fhr_d} hours + ${fmn} minutes" "+%Y%m%d%H%M" ) + post_mn=${post_time:10:2} + post_mn_or_null="" + post_fn_suffix="GrbF${fhr_d}" + post_renamed_fn_suffix="f${fhr}${post_mn_or_null}.${POST_OUTPUT_DOMAIN_NAME}.grib2" + + basetime=$( $DATE_UTIL --date "$yyyymmdd $hh" +%y%j%H%M ) + symlink_suffix="_${basetime}f${fhr}${post_mn}" + fids=( "prslev" "natlev" ) + for fid in "${fids[@]}"; do + FID=$(echo_uppercase $fid) + post_orig_fn="${FID}.${post_fn_suffix}" + post_renamed_fn="${NET}.t${cyc}z.${fid}.${post_renamed_fn_suffix}" + mv_vrfy ${run_dir}/${post_orig_fn} ${post_renamed_fn} + ln_vrfy -fs ${post_renamed_fn} ${FID}${symlink_suffix} + done + done + +fi +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +FV3 forecast completed successfully!!! + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/scripts/exregional_run_gridstatvx.sh b/scripts/exregional_run_gridstatvx.sh new file mode 100755 index 0000000000..b6b5671814 --- /dev/null +++ b/scripts/exregional_run_gridstatvx.sh @@ -0,0 +1,214 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for grid-stat on +the UPP output files by initialization time for all forecast hours. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create INPUT_BASE and LOG_SUFFIX to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +if [[ ${DO_ENSEMBLE} == "FALSE" ]]; then + INPUT_BASE=${EXPTDIR}/${CDATE}/postprd + OUTPUT_BASE=${EXPTDIR}/${CDATE} + if [ ${VAR} == "APCP" ]; then + LOG_SUFFIX=gridstat_${CDATE}_${VAR}_${ACCUM}h + else + LOG_SUFFIX=gridstat_${CDATE}_${VAR} + fi +elif [[ ${DO_ENSEMBLE} == "TRUE" ]]; then + INPUT_BASE=${EXPTDIR}/${CDATE}/${SLASH_ENSMEM_SUBDIR}/postprd + OUTPUT_BASE=${EXPTDIR}/${CDATE}/${SLASH_ENSMEM_SUBDIR} + ENSMEM=`echo ${SLASH_ENSMEM_SUBDIR} | cut -d"/" -f2` + MODEL=${MODEL}_${ENSMEM} + if [ ${VAR} == "APCP" ]; then + LOG_SUFFIX=gridstat_${CDATE}_${ENSMEM}_${VAR}_${ACCUM}h + else + LOG_SUFFIX=gridstat_${CDATE}_${ENSMEM}_${VAR} + fi +fi + +# +#----------------------------------------------------------------------- +# +# Make sure directories in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${OUTPUT_BASE}/metprd/grid_stat" +# +# If the variable is accumulated precipitation for a time interval +# (bucket) other than 1 hour, the MET/METplus tools called below will +# include pcp_combine. In that case, create (if necessary) directories +# needed by pcp_combine. +# +if [ "${VAR}" = "APCP" ] && [ "${ACCUM: -1}" != "1" ]; then + mkdir_vrfy -p "${EXPTDIR}/metprd/pcp_combine" # For observations + mkdir_vrfy -p "${OUTPUT_BASE}/metprd/pcp_combine" # For forecast +fi + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." + exit +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML +# +#----------------------------------------------------------------------- +# +export SCRIPTSDIR +export EXPTDIR +export INPUT_BASE +export OUTPUT_BASE +export LOG_SUFFIX +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME + +# +#----------------------------------------------------------------------- +# +# Run METplus +# +#----------------------------------------------------------------------- +# +if [ ${VAR} == "APCP" ]; then + export acc="${ACCUM}h" # for stats output prefix in GridStatConfig + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/GridStat_${VAR}${acc}.conf +else + ${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/GridStat_${VAR}.conf +fi + +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus grid-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_pointstatvx.sh b/scripts/exregional_run_pointstatvx.sh new file mode 100755 index 0000000000..8afed1dd4a --- /dev/null +++ b/scripts/exregional_run_pointstatvx.sh @@ -0,0 +1,185 @@ +#!/bin/bash +set -x + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs METplus for point-stat on +the UPP output files by initialization time for all forecast hours. +========================================================================" + +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( "cycle_dir" ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args + +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respect- +# ively) from CDATE. Also read in FHR and create a comma-separated list +# for METplus to run over. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${CDATE:0:8} +hh=${CDATE:8:2} +cyc=$hh +export CDATE +export hh + +fhr_last=`echo ${FHR} | awk '{ print $NF }'` +export fhr_last + +fhr_list=`echo ${FHR} | $SED "s/ /,/g"` +export fhr_list + +# +#----------------------------------------------------------------------- +# +# Create INPUT_BASE to read into METplus conf files. +# +#----------------------------------------------------------------------- +# +if [[ ${DO_ENSEMBLE} == "FALSE" ]]; then + INPUT_BASE=${EXPTDIR}/${CDATE}/postprd + OUTPUT_BASE=${EXPTDIR}/${CDATE} + LOG_SUFFIX=pointstat_${CDATE} +elif [[ ${DO_ENSEMBLE} == "TRUE" ]]; then + INPUT_BASE=${EXPTDIR}/${CDATE}/${SLASH_ENSMEM_SUBDIR}/postprd + OUTPUT_BASE=${EXPTDIR}/${CDATE}/${SLASH_ENSMEM_SUBDIR} + ENSMEM=`echo ${SLASH_ENSMEM_SUBDIR} | cut -d"/" -f2` + MODEL=${MODEL}_${ENSMEM} + LOG_SUFFIX=pointstat_${CDATE}_${ENSMEM} +fi + +# +#----------------------------------------------------------------------- +# +# Make sure directories in which output files will be placed exist. +# +#----------------------------------------------------------------------- +# +mkdir_vrfy -p "${EXPTDIR}/metprd/pb2nc" # Output directory for pb2nc tool. +mkdir_vrfy -p "${OUTPUT_BASE}/metprd/point_stat" # Output directory for point_stat tool. + +# +#----------------------------------------------------------------------- +# +# Check for existence of top-level OBS_DIR +# +#----------------------------------------------------------------------- +# +if [[ ! -d "$OBS_DIR" ]]; then + print_err_msg_exit "\ + Exiting: OBS_DIR does not exist." +fi + +# +#----------------------------------------------------------------------- +# +# Export some environment variables passed in by the XML and run METplus +# +#----------------------------------------------------------------------- +# +export EXPTDIR +export INPUT_BASE +export OUTPUT_BASE +export LOG_SUFFIX +export MET_INSTALL_DIR +export MET_BIN_EXEC +export METPLUS_PATH +export METPLUS_CONF +export MET_CONFIG +export MODEL +export NET +export POST_OUTPUT_DOMAIN_NAME + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/PointStat_conus_sfc.conf + +${METPLUS_PATH}/ush/run_metplus.py \ + -c ${METPLUS_CONF}/common.conf \ + -c ${METPLUS_CONF}/PointStat_upper_air.conf + +# +#----------------------------------------------------------------------- +# +# Print message indicating successful completion of script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +METplus point-stat completed successfully. + +Exiting script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" +========================================================================" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/scripts/exregional_run_post.sh b/scripts/exregional_run_post.sh new file mode 100755 index 0000000000..cb8c3d5d5e --- /dev/null +++ b/scripts/exregional_run_post.sh @@ -0,0 +1,337 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Print message indicating entry into script. +# +#----------------------------------------------------------------------- +# +print_info_msg " +======================================================================== +Entering script: \"${scrfunc_fn}\" +In directory: \"${scrfunc_dir}\" + +This is the ex-script for the task that runs the post-processor (UPP) on +the output files corresponding to a specified forecast hour. +========================================================================" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. +# Then process the arguments provided to this script/function (which +# should consist of a set of name-value pairs of the form arg1="value1", +# etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ +"cdate" \ +"run_dir" \ +"postprd_dir" \ +"tmp_dir" \ +"fhr" \ +"fmn" \ +"dt_atmos" \ +) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# +print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Set OpenMP variables. +# +#----------------------------------------------------------------------- +# +export KMP_AFFINITY=${KMP_AFFINITY_RUN_POST} +export OMP_NUM_THREADS=${OMP_NUM_THREADS_RUN_POST} +export OMP_STACKSIZE=${OMP_STACKSIZE_RUN_POST} +# +#----------------------------------------------------------------------- +# +# Load modules. +# +#----------------------------------------------------------------------- +# +source $USHDIR/source_machine_file.sh +eval ${PRE_TASK_CMDS} + +nprocs=$(( NNODES_RUN_POST*PPN_RUN_POST )) +if [ -z "${RUN_CMD_POST:-}" ] ; then + print_err_msg_exit "\ + Run command was not set in machine file. \ + Please set RUN_CMD_POST for your platform" +else + RUN_CMD_POST=$(eval echo ${RUN_CMD_POST}) + print_info_msg "$VERBOSE" " + All executables will be submitted with command \'${RUN_CMD_POST}\'." +fi +# +#----------------------------------------------------------------------- +# +# Remove any files from previous runs and stage necessary files in the +# temporary work directory specified by tmp_dir. +# +#----------------------------------------------------------------------- +# +rm_vrfy -f fort.* +cp_vrfy ${UPP_DIR}/parm/nam_micro_lookup.dat ./eta_micro_lookup.dat +if [ ${USE_CUSTOM_POST_CONFIG_FILE} = "TRUE" ]; then + post_config_fp="${CUSTOM_POST_CONFIG_FP}" + print_info_msg " +==================================================================== +Copying the user-defined post flat file specified by CUSTOM_POST_CONFIG_FP +to the temporary work directory (tmp_dir): + CUSTOM_POST_CONFIG_FP = \"${CUSTOM_POST_CONFIG_FP}\" + tmp_dir = \"${tmp_dir}\" +====================================================================" +else + if [ ${FCST_MODEL} = "fv3gfs_aqm" ]; then + post_config_fp="${UPP_DIR}/parm/postxconfig-NT-fv3lam_cmaq.txt" + else + post_config_fp="${UPP_DIR}/parm/postxconfig-NT-fv3lam.txt" + fi + print_info_msg " +==================================================================== +Copying the default post flat file specified by post_config_fp to the +temporary work directory (tmp_dir): + post_config_fp = \"${post_config_fp}\" + tmp_dir = \"${tmp_dir}\" +====================================================================" +fi +cp_vrfy ${post_config_fp} ./postxconfig-NT.txt +cp_vrfy ${UPP_DIR}/parm/params_grib2_tbl_new . +if [ ${USE_CRTM} = "TRUE" ]; then + cp_vrfy ${CRTM_DIR}/fix/EmisCoeff/IR_Water/Big_Endian/Nalli.IRwater.EmisCoeff.bin ./ + cp_vrfy ${CRTM_DIR}/fix/EmisCoeff/MW_Water/Big_Endian/FAST*.bin ./ + cp_vrfy ${CRTM_DIR}/fix/EmisCoeff/IR_Land/SEcategory/Big_Endian/NPOESS.IRland.EmisCoeff.bin ./ + cp_vrfy ${CRTM_DIR}/fix/EmisCoeff/IR_Snow/SEcategory/Big_Endian/NPOESS.IRsnow.EmisCoeff.bin ./ + cp_vrfy ${CRTM_DIR}/fix/EmisCoeff/IR_Ice/SEcategory/Big_Endian/NPOESS.IRice.EmisCoeff.bin ./ + cp_vrfy ${CRTM_DIR}/fix/AerosolCoeff/Big_Endian/AerosolCoeff.bin ./ + cp_vrfy ${CRTM_DIR}/fix/CloudCoeff/Big_Endian/CloudCoeff.bin ./ + cp_vrfy ${CRTM_DIR}/fix/SpcCoeff/Big_Endian/*.bin ./ + cp_vrfy ${CRTM_DIR}/fix/TauCoeff/ODPS/Big_Endian/*.bin ./ + print_info_msg " +==================================================================== +Copying the external CRTM fix files from CRTM_DIR to the temporary +work directory (tmp_dir): + CRTM_DIR = \"${CRTM_DIR}\" + tmp_dir = \"${tmp_dir}\" +====================================================================" +fi +# +#----------------------------------------------------------------------- +# +# Get the cycle date and hour (in formats of yyyymmdd and hh, respectively) +# from cdate. +# +#----------------------------------------------------------------------- +# +yyyymmdd=${cdate:0:8} +hh=${cdate:8:2} +cyc=$hh +# +#----------------------------------------------------------------------- +# +# Create the namelist file (itag) containing arguments to pass to the post- +# processor's executable. +# +#----------------------------------------------------------------------- +# +# Set the variable (mnts_secs_str) that determines the suffix in the names +# of the forecast model's write-component output files that specifies the +# minutes and seconds of the corresponding output forecast time. +# +# Note that if the forecast model is instructed to output at some hourly +# interval (via the output_fh parameter in the MODEL_CONFIG_FN file, +# with nsout set to a non-positive value), then the write-component +# output file names will not contain any suffix for the minutes and seconds. +# For this reason, when SUB_HOURLY_POST is not set to "TRUE", mnts_sec_str +# must be set to a null string. +# +mnts_secs_str="" +if [ "${SUB_HOURLY_POST}" = "TRUE" ]; then + if [ ${fhr}${fmn} = "00000" ]; then + mnts_secs_str=":"$( $DATE_UTIL --utc --date "${yyyymmdd} ${hh} UTC + ${dt_atmos} seconds" "+%M:%S" ) + else + mnts_secs_str=":${fmn}:00" + fi +fi +# +# Set the names of the forecast model's write-component output files. +# +dyn_file="${run_dir}/dynf${fhr}${mnts_secs_str}.nc" +phy_file="${run_dir}/phyf${fhr}${mnts_secs_str}.nc" +# +# Set parameters that specify the actual time (not forecast time) of the +# output. +# +post_time=$( $DATE_UTIL --utc --date "${yyyymmdd} ${hh} UTC + ${fhr} hours + ${fmn} minutes" "+%Y%m%d%H%M" ) +post_yyyy=${post_time:0:4} +post_mm=${post_time:4:2} +post_dd=${post_time:6:2} +post_hh=${post_time:8:2} +post_mn=${post_time:10:2} +# +# Create the input namelist file to the post-processor executable. +# +if [ ${FCST_MODEL} = "fv3gfs_aqm" ]; then + post_itag_add="aqfcmaq_on=.true.," +else + post_itag_add="" +fi +cat > itag < /dev/null 2>&1 + diff --git a/tests/WE2E/create_WE2E_resource_summary.py b/tests/WE2E/create_WE2E_resource_summary.py new file mode 100644 index 0000000000..5095a9fe69 --- /dev/null +++ b/tests/WE2E/create_WE2E_resource_summary.py @@ -0,0 +1,187 @@ +''' +Generate a summary of resources used for the WE2E test suite. + +Examples: + + To print usage + + python create_WE2E_resource_summary.py + python create_WE2E_resource_summary.py -h + + To print a report for all the experiments in an experiment directory + + python create_WE2E_resource_summary.py -e /path/to/expt_dir + + To print a report for all the grid_* and nco_* experiments. + + python create_WE2E_resource_summary.py -e /path/to/expt_dir \ + -n 'grid*' 'nco*' + + To compute a total estimated cost for all experiments on instances that are + $0.15 per core hour. + + python create_WE2E_resource_summary.py -e /path/to/expt_dir -c $0.15 + +Information about the output summary. + + - The core hours are an underestimate in many cases. + - Multiple tries are not captured. + - The use of a portion of a node or instance is not known. If the whole node + is used, but isn't reflected in the core count, the cores are not counted. + Partition information is not stored in the database, so mapping to a given + node type becomes ambiguous. + + For example, jobs that request 4 nodes with 2 processors per node with an + --exclusive flag will underestimate the total core hour usage by a factor + of 20 when using a 40 processor node. + + - When computing cost per job, it will also provide an underestimate for the + reasons listed above. + - Only one cost will be applied across all jobs. Rocoto jobs do not store + partition information in the job table, so was not included as an option here. + +''' + +import argparse +import glob +import os +import sys +import sqlite3 + +REPORT_WIDTH = 110 + +def parse_args(argv): + + + ''' + Function maintains the arguments accepted by this script. Please see + Python's argparse documenation for more information about settings of each + argument. + ''' + + parser = argparse.ArgumentParser( + description="Generate a usage report for a set of SRW experiments." + ) + + parser.add_argument( + '-e', '--expt_path', + help='The path to the directory containing the experiment \ + directories', + ) + parser.add_argument( + '-n', '--expt_names', + default=['*'], + help='A list of experiments to generate the report for. Wildcards \ + accepted by glob.glob may be used. If not provided, a report will be \ + generated for all experiments in the expt_path that have a Rocoto \ + database', + nargs='*', + ) + + # Optional + parser.add_argument( + '-c', '--cost_per_core_hour', + help='Provide the cost per core hour for the instance type used. \ + Only supports homogenous clusters.', + type=float, + ) + + return parser.parse_args(argv) + +def get_workflow_info(db_path): + + ''' Given the path to a Rocoto database, return the total number of tasks, + core hours and wall time for the workflow. ''' + + con = sqlite3.connect(db_path) + cur = con.cursor() + + # jobs schema is: + # (id INTEGER PRIMARY KEY, jobid VARCHAR(64), taskname VARCHAR(64), cycle + # DATETIME, cores INTEGER, state VARCHAR(64), native_state VARCHAR[64], + # exit_status INTEGER, tries INTEGER, nunknowns INTEGER, duration REAL) + # + # an example: + # 5|66993580|make_sfc_climo|1597017600|48|SUCCEEDED|COMPLETED|0|1|0|83.0 + try: + cur.execute('SELECT cores, duration from jobs') + except sqlite3.OperationalError: + return 0, 0, 0 + + workflow_info = cur.fetchall() + + core_hours = 0 + wall_time = 0 + ntasks = 0 + for cores, duration in workflow_info: + core_hours += cores * duration / 3600 + wall_time += duration / 60 + ntasks += 1 + + return ntasks, core_hours, wall_time + + +def fetch_expt_summaries(expts): + + ''' Get the important information from the database of each experiment, and + return a list, sorted by experiment name. ''' + + summaries = [] + for expt in expts: + test_name = expt.split('/')[-1] + db_path = os.path.join(expt, 'FV3LAM_wflow.db') + if not os.path.exists(db_path): + print(f'No FV3LAM_wflow.db exists for expt: {test_name}') + continue + ntasks, core_hours, wall_time = get_workflow_info(db_path) + summaries.append((test_name, ntasks, core_hours, wall_time)) + + return sorted(summaries) + +def generate_report(argv): + + ''' Given user arguments, print a summary of the requested experiments' + usage information, including cost (if requested). ''' + + cla = parse_args(argv) + + experiments = [] + for expt in cla.expt_names: + experiments.extend(glob.glob( + os.path.join(cla.expt_path, expt) + )) + + header = f'{" "*60} Core Hours | Run Time (mins)' + if cla.cost_per_core_hour: + header = f'{header} | Est. Cost ($) ' + + print('-'*REPORT_WIDTH) + print('-'*REPORT_WIDTH) + print(header) + print('-'*REPORT_WIDTH) + + total_ch = 0 + total_cost = 0 + for name, ntasks, ch, wt in fetch_expt_summaries(experiments): + line = f'{name[:60]:<60s} {ch:^12.2f} {wt:^20.1f}' + if cla.cost_per_core_hour: + cost = ch * cla.cost_per_core_hour + line = f'{line} ${cost:<.2f}' + total_cost += cost + total_ch += ch + print(line) + + print('-'*REPORT_WIDTH) + print(f'TOTAL CORE HOURS: {total_ch:6.2f}') + if cla.cost_per_core_hour: + print(f'TOTAL COST: ${cla.cost_per_core_hour * total_ch:6.2f}') + + print('*'*REPORT_WIDTH) + print('WARNING: This data reflects only the job information from the last', + 'logged try. It does not account for the use \n of an entire node, only', + 'the actual cores requested. It may provide an underestimate of true compute usage.') + print('*'*REPORT_WIDTH) + + +if __name__ == "__main__": + generate_report(sys.argv[1:]) diff --git a/tests/WE2E/get_WE2Etest_names_subdirs_descs.sh b/tests/WE2E/get_WE2Etest_names_subdirs_descs.sh new file mode 100755 index 0000000000..23ef0500c2 --- /dev/null +++ b/tests/WE2E/get_WE2Etest_names_subdirs_descs.sh @@ -0,0 +1,1747 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This file defines a function that gathers and returns information about +# the WE2E tests available in the WE2E testing system. This information +# consists of the test names, the category subdirectories in which the +# test configuration files are located (relative to a base directory), +# the test IDs, and the test descriptions. This function optionally +# also creates a CSV (Comma-Separated Value) file containing various +# pieces of information about each of the workflow end-to-end (WE2E) +# tests. These are described in more detail below. +# +# The function takes as inputs the following arguments: +# +# WE2Edir: +# Directory in which the WE2E testing system is located. This system +# consists of the main script for running WE2E tests, various auxiliary +# scripts, and the test configuration files. +# +# generate_csv_file: +# Flag that specifies whether or not a CSV (Comma-Separated Value) file +# containing information about the WE2E tests should be generated. +# +# verbose: +# Optional verbosity flag. Should be set to "TRUE" or "FALSE". Default +# is "FALSE". +# +# outvarname_test_configs_basedir: +# Name of output variable in which to return the base directory of the +# WE2E test configuration files. +# +# outvarname_test_names: +# Name of output array variable in which to return the names of the WE2E +# tests. +# +# outvarname_test_subdirs: +# Name of output array variable in which to return the category subdirectories +# in which the WE2E tests are located. +# +# outvarname_test_ids: +# Name of output array variable in which to return the IDs of the WE2E +# tests. +# +# outvarname_test_descs: +# Name of output array variable in which to return the descriptions of +# the WE2E tests. +# +# Note that any input argument that is not specified in the call to this +# function gets set to a null string in the body of the function. In +# particular, if any of the arguments that start with "outvarname_" +# (indicating that they specify the name of an output variable) are not +# set in the call, the values corresponding to those variables are not +# returned to the calling script or function. +# +# In order to gather information about the available WE2E tests, this +# function sets the local variable test_configs_basedir to the full path +# of the base directory in which the test configuration files (which may +# be ordinary files or symlinks) are located. It sets this as follows: +# +# test_configs_basedir="${WE2Edir}/test_configs" +# +# If the argument outvarname_test_configs_basedir is specified in the +# call to this function, then the value of test_configs_basedir will be +# returned to the calling script or function (in the variable specified +# by outvarname_test_configs_basedir). +# +# The WE2E test configuration files are located in subdirectories under +# the base directory. This function sets the names of these subdirectories +# in the local array category_subdirs. We refer to these as "category" +# subdirectories because they are used for clarity to group the tests +# into categories (instead of putting them all directly under the base +# directory). For example, one category of tests might be those that +# test workflow capabilities such as running multiple cycles and ensemble +# forecasts, another might be those that run various combinations of +# grids, physics suites, and external models for ICs/LBCs, etc. Note +# that if a new category subdirectory is added under test_configs_basedir, +# its name must be added below as a new element in category_subdirs; +# otherwise, this new subdirectory will not be searched for test +# configuration files. Note also that if one of the elements of +# category_subdirs is ".", then this function will also search directly +# under the base directory itself for test configuration files. +# +# Once test_configs_basedir and category_subdirs are set, this function +# searches the category subdirectories for WE2E test configuration files. +# In doing so, it assumes that any ordinary file or symlink in the category +# subdirectories having a name of the form +# +# config.${test_name}.sh +# +# is a test configuration file, and it takes the name of the corresponding +# test to be given by whatever test_name in the above file name happens +# to be. Here, by "ordinary" file we mean an item in the file system +# that is not a symlink (or a directory or other more exotic entity). +# Also, for simplicity, we require that any configuration file that is a +# symlink have a target that is an ordinary configuration file, i.e. not +# a symlink. +# +# We allow test configuration files to be symlinks in order to avoid the +# presence of identical configuration files with different names in the +# WE2E testing system. For example, assume there is a test named +# "test_grid1" that is used to test whether the forecast model can run +# on a grid named "grid1", and assume that the configuration file for +# this test is an ordinary file located in a category subdirectory named +# "grids" that contains tests for various grids. Then the full path to +# this configuration file will be +# +# ${test_configs_basedir}/grids/config.test_grid1.sh +# +# Now assume that there is another category subdirectory named "suites" +# that contains configuration files for tests that check whether the +# forecast model can run with various physics suites. Thus, in order to +# have a test that checks whether the forecast model can run successfully +# with a physics suite named "suite1", we might create an ordinary +# configuration file named "config.test_suite1.sh" in "suites" (so that +# the corresponding test name is "test_suite1"). Thus, the full path to +# this configuration file would be +# +# ${test_configs_basedir}/suites/config.test_suite1.sh +# +# Now if test "test_grid1" happens to use physics suite "suite1", then +# we may be able to use that test for testing both "grid1" and "suite1". +# However, we'd still want to have a configuration file in the "suites" +# subdirectory with a test name that makes it clear that the purpose of +# the test is to run using "suite1". Then, since the WE2E testing system +# allows configuration files to by symlinks, instead of copying +# "config.test_grid1.sh" from the "grids" to the "suites" subdirectory +# and renaming it to "config.test_suite1.sh" (which would create two +# identical ordinary configuration files), we could simply make +# "config.test_suite1.sh" in "suites" a symlink to "config.test_grid1.sh" +# in "grids", i.e. +# +# ${test_configs_basedir}/suites/config.test_suite1.sh +# --> ${test_configs_basedir}/grids/config.test_grid1.sh +# +# With this approach, there will be only one ordinary configuration file +# to maintain. Note that there may be more than one symlink pointing to +# the same ordinary configuration file. For example, there may be another +# category subdirectory named "wflow_features" containing tests for +# various workflow features. Then if the test "test_grid1" runs a test +# that, in addition to running the forecast model on "grid1" using the +# "suite1" physics suite also performs subhourly output, then a symlink +# named "config.test_subhourly.sh" can be created under "wflow_features" +# that points to the configuration file "config.test_grid1.sh", i.e. +# +# ${test_configs_basedir}/wflow_features/config.test_subhourly.sh +# --> ${test_configs_basedir}/grids/config.test_grid1.sh +# +# Since the WE2E testing system allows configuration files to be symlinks, +# the same WE2E test may be referred to via multiple test names -- the +# test name corresponding to the ordinary configuration file ("test_grid1" +# in the example above) and any one of the test names corresponding to +# any symlinks that have this ordinary file as their target ("test_suite1" +# and "test_subhourly" in the example above). Here, for clarity we will +# refer to the test name derived from the name of the ordinary configuration +# file as the "primary" test name, and we will refer to the test names +# dervied from the symlinks as the alternate test names. Since these +# test names all represent the same actual test, we also assign to each +# group of primary and alternate test names a single test ID. This is +# simply an integer that uniquely identifies each group of primary and +# alternate test names. +# +# For each configuration file (which may be an ordinary file or a symlink) +# found in the category subdirectories, this function saves in local +# arrays the following information about the WE2E files: +# +# 1) The list of all available WE2E test names, both primary and alternate. +# 2) The category subdirectories under the base directory test_configs_basedir +# in which the test configuration files corresponding to each test +# name are located. +# 3) The IDs corresponding to each of the test names. +# 4) The test descriptions (if outvarname_test_descs is specified in the +# call to this function or if generate_csv_file is or gets set to +# "TRUE"; see below). +# +# These local arrays are sorted in order of increasing test ID. Within +# each group of tests that have the same ID, the primary test name is +# listed first followed by zero or more alternate test names. Note also +# that to reduce confusion, we do not allow two or more configuration +# files of the same name anywere under test_configs_basedir (either +# representing the same actual test or different ones). In other words, +# the list of all test names that this function generates cannot contain +# any duplicate names (either primary or alternate). After assembling +# the full list of test names, this function checks for such duplicates +# and exits with an error message if any are found. +# +# The following input arguments to this function specify the names of +# the arrays in which each of the quantities listed above should be +# returned (to the calling script or function): +# +# outvarname_test_names +# outvarname_test_subdirs +# outvarname_test_ids +# outvarname_test_descs +# +# If any of these is not specified in the call to this function, then +# the corresponding quantity will not be returned to the calling script +# or function. +# +# The test descriptions are headers consisting of one or more bash-style +# comment lines at the top of each ordinary test configuraiton file. +# They are extracted from each such file and placed in a local array only +# if one or both of the following conditions are met: +# +# 1) The user explicitly asks for the descriptions to be returned by +# specifying in the call to this function the name of the array in +# which to return them (by setting a value for the argument +# outvarname_test_descs). +# 2) A CSV file summarizing the WE2E tests will be generated (see below) +# +# For convenience, this function can generate a CSV (comma-separated +# value) file containing information about the WE2E tests. If it does, +# the file will be placed in the main WE2E testing system directory +# specified by the input argument WE2Edir. The CSV file can be read +# into a spreadsheet in Google Sheets (or another similar tool) to get +# an overview of all the available WE2E tests. The rows of the CSV file +# correspond to the primary WE2E tests, and the columns correspond to +# the (primary) test name, alternate test names (if any), test description, +# number of times the test calls the forecast model, and values of various +# SRW App experiment variables for that test. +# +# A CSV file will be generated in the directory specified by WE2Edir if +# one or more of the following conditions hold: +# +# 1) The input argument generate_csv_file is set to "TRUE" in the call +# to this function. +# 2) The input argument generate_csv_file is not set in the call to this +# function, and a CSV file does not already exist. +# 3) The input argument generate_csv_file is not set in the call to this +# function, a CSV file already exists, and the modification time of +# at least one category subdirectory in category_subdirs is later +# than that of the CSV file, i.e. the existing CSV file needs to be +# updated because the test configuration files may have changed in +# some way. +# +# A CSV file is not generated if generate_csv_file is explicitly set to +# "FALSE" in the call to this function (regardless of whether or not a +# CSV file already exists). If a CSV file is generated, it is placed in +# the directory specified by the input argment WE2Edir, and it overwrites +# any existing copies of the file in that directory. The contents of +# each column of the CSV file are described below. +# +#----------------------------------------------------------------------- +# +function get_WE2Etest_names_subdirs_descs() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script or function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script or function. +# Then process the arguments provided to it on the command line (which +# should consist of a set of name-value pairs of the form arg1="value1", +# arg2="value2", etc). +# +#----------------------------------------------------------------------- +# + local valid_args=( \ + "WE2Edir" \ + "generate_csv_file" \ + "verbose" \ + "outvarname_test_configs_basedir" \ + "outvarname_test_names" \ + "outvarname_test_subdirs" \ + "outvarname_test_ids" \ + "outvarname_test_descs" \ + ) + process_args "valid_args" "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# + print_input_args "valid_args" +# +#----------------------------------------------------------------------- +# +# Make the default value of "verbose" "FALSE". Then make sure "verbose" +# is set to a valid value. +# +#----------------------------------------------------------------------- +# + verbose=${verbose:-"FALSE"} + check_var_valid_value "verbose" "valid_vals_BOOLEAN" + verbose=$(boolify "$verbose") +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local abs_cost_ref \ + ac \ + all_items \ + alt_test_name \ + alt_test_names \ + alt_test_names_subdirs \ + alt_test_prim_test_names \ + alt_test_subdir \ + alt_test_subdirs \ + array_names_vars_to_extract \ + array_names_vars_to_extract_orig \ + category_subdirs \ + cmd \ + column_titles \ + config_fn \ + crnt_item \ + crnt_title \ + csv_delimiter \ + csv_fn \ + csv_fp \ + cwd \ + default_val \ + dt_atmos \ + fcst_len_hrs \ + get_test_descs \ + hash_or_null \ + i \ + ii \ + j \ + jp1 \ + k \ + line \ + mod_time_csv \ + mod_time_subdir \ + msg \ + nf \ + num_alt_tests \ + num_category_subdirs \ + num_cdates \ + num_cycles_per_day \ + num_days \ + num_fcsts \ + num_fcsts_orig \ + num_grid_pts \ + num_items \ + num_occurrences \ + num_prim_tests \ + num_tests \ + num_time_steps \ + num_vars_to_extract \ + prim_array_names_vars_to_extract \ + prim_test_descs \ + prim_test_dt_atmos \ + prim_test_ids \ + prim_test_name_subdir \ + prim_test_names \ + prim_test_num_fcsts \ + prim_test_rel_cost \ + prim_test_subdirs \ + rc \ + regex_search \ + rel_cost \ + row_content \ + sort_inds \ + stripped_line \ + subdir \ + subdir_fp \ + subdirs \ + target_dir \ + target_fn \ + target_fp \ + target_prim_test_name \ + target_rp \ + target_test_name_or_null \ + test_configs_basedir \ + test_desc \ + test_descs \ + test_descs_esc_sq \ + test_descs_orig \ + test_descs_str \ + test_id \ + test_id_next \ + test_ids \ + test_ids_and_inds \ + test_ids_and_inds_sorted \ + test_ids_orig \ + test_ids_str \ + test_name \ + test_name_or_null \ + test_names \ + test_names_orig \ + test_names_str \ + test_subdirs \ + test_subdirs_orig \ + test_subdirs_str \ + test_type \ + units \ + ushdir \ + val \ + var_name \ + var_name_at \ + vars_to_extract + + local grid_gen_method \ + \ + gfdlgrid_lon_t6_ctr \ + gfdlgrid_lat_t6_ctr \ + gfdlgrid_num_cells \ + gfdlgrid_stretch_fac \ + gfdlgrid_refine_ratio \ + gfdlgrid_istart_of_rgnl_dom_on_t6g \ + gfdlgrid_iend_of_rgnl_dom_on_t6g \ + gfdlgrid_jstart_of_rgnl_dom_on_t6g \ + gfdlgrid_jend_of_rgnl_dom_on_t6g \ + \ + esggrid_lon_ctr \ + esggrid_lat_ctr \ + esggrid_nx \ + esggrid_ny \ + esggrid_pazi \ + esggrid_wide_halo_width \ + esggrid_delx \ + esggrid_dely \ + \ + nx \ + ny \ + dta +# +#----------------------------------------------------------------------- +# +# Source files. +# +#----------------------------------------------------------------------- +# + ushdir=$( readlink -f "$WE2Edir/../../ush" ) + . $ushdir/constants.sh +# +#----------------------------------------------------------------------- +# +# Set variables associated with the CSV (comma-separated value) file that +# this function may generate. The conditions under which such a file is +# generated are described above in the description of this function. +# +#----------------------------------------------------------------------- +# +# Set the name and full path to the CSV file. +# + csv_fn="WE2E_test_info.csv" + csv_fp="${WE2Edir}/${csv_fn}" +# +# If generate_csv_file is specified as an input argument in the call to +# this function, make sure that it is set to a valid value. +# + if [ ! -z "${generate_csv_file}" ]; then + + check_var_valid_value "generate_csv_file" "valid_vals_BOOLEAN" + generate_csv_file=$(boolify "${generate_csv_file}") +# +# If generate_csv_file was not specified as an input argument in the +# call to this function, then it will have been set above to a null +# string. In this case, if a CSV file doesn't already exsit, reset +# generate_csv_file to "TRUE" so that one will be generated. If a CSV +# file does exist, get its modification time so that later below, we can +# compare it to the modification times of the category subdirectories +# and determine whether a new CSV file needs to be generated. +# +# Note that the modification "times" obtained here and later below using +# the "stat" utility are the seconds elapsed between Epoch (which is a +# fixed point in time) and the last modification time of the specified +# file, not the dates/times at which the file was last modified. This +# is due to the use of the "--format=%Y" flag in the call to "stat". We +# choose these "seconds since Epoch" units because they make it easier +# to determine which of two files is younger/older (the one with the +# larger seconds-since-Epoch will be the more recently modified file.) +# + else + + if [ ! -f "${csv_fp}" ]; then + mod_time_csv="0" + generate_csv_file="TRUE" + else + mod_time_csv=$( stat --format=%Y "${csv_fp}" ) + fi + + fi + + if [ "${generate_csv_file}" = "TRUE" ]; then + print_info_msg " +Will generate a CSV (Comma Separated Value) file (csv_fp) containing +information on all WE2E tests: + csv_fp = \"${csv_fp}\"" + fi +# +#----------------------------------------------------------------------- +# +# Set the base directory containing the WE2E test configuration files +# (or, more precisely, containing the category subdirectories in which +# the configuration files are located). +# +#----------------------------------------------------------------------- +# + test_configs_basedir="${WE2Edir}/test_configs" +# +#----------------------------------------------------------------------- +# +# Set the array category_subdirs that specifies the subdirectories under +# test_configs_basedir in which to search for WE2E test configuration +# files. Note that if "." is included as one of the elements of this +# array, then the base directory itself will also be searched. +# +#----------------------------------------------------------------------- +# + category_subdirs=( \ + "." \ + "grids_extrn_mdls_suites_community" \ + "grids_extrn_mdls_suites_nco" \ + "release_SRW_v1" \ + "wflow_features" \ + ) + num_category_subdirs="${#category_subdirs[@]}" +# +#----------------------------------------------------------------------- +# +# Loop over the category subdirectories under test_configs_basedir +# (possibly including the base directory itself). In each subdirectory, +# consider all items that have names of the form +# +# config.${test_name}.sh +# +# and that are either ordinary files (i.e. not symlinks) or are symlinks +# whose targets are ordinary files having names of the form above. For +# each item that is an ordinary file, save the corresponding primary test +# name, the category subdirectory in which the item is located, and the +# test ID in the arrays +# +# prim_test_names +# prim_test_subdirs +# prim_test_ids +# +# respectively. For each item that is a symlink to an ordinary file, +# save the alternate test name corresponding to the symlink name, the +# category subdirectory in which the symlink is located, and the test +# name derived from the name of the symlink's target (i.e. the primary +# test name that this alternate test name corresponds to) in the arrays +# +# alt_test_names +# alt_test_subdirs +# alt_test_prim_test_names +# +# respectively. +# +#----------------------------------------------------------------------- +# + prim_test_names=() + prim_test_ids=() + prim_test_subdirs=() + prim_test_num_fcsts=() + prim_test_dt_atmos=() + prim_test_rel_cost=() + + alt_test_names=() + alt_test_subdirs=() + alt_test_prim_test_names=() +# +# Initialize the counter that will be used to assign test IDs to the +# primary test names. This will be incremented below every time a new +# primary test name is found. Note that we do not yet assign IDs to the +# alternate test names. These will be assigned IDs later below that +# will be identical to the IDs of the primary thest names they correspond +# to. +# + test_id="0" + + for (( i=0; i<=$((num_category_subdirs-1)); i++ )); do + + subdir="${category_subdirs[$i]}" + subdir_fp="${test_configs_basedir}/$subdir" +# +# If at this point in the code generate_csv_file is still set to a null +# string, it means that a CSV file containing information about the WE2E +# tests already exists. In this case, a new version of this file needs +# to be generated only if one or more of the category subdirectories +# have modification times that are later than that of the existing CSV +# file. Check for this condition and set generate_csv_file accordingly. +# Note that this if-statement will be executed at most once since it sets +# generate_csv_file to "TRUE", after which the test for entering the if- +# statement will be false. +# + if [ -z "${generate_csv_file}" ]; then + mod_time_subdir=$( stat --format=%Y "${subdir_fp}" ) + if [ "${mod_time_subdir}" -gt "${mod_time_csv}" ]; then + generate_csv_file="TRUE" + print_info_msg " +The current category subdirectory (subdir) has a modification time +(mod_time_subdir) that is later than the modification time (mod_time_csv) +of the existing CSV file (csv_fp) containing WE2E test information: + subdir = \"${subdir}\" + mod_time_subdir = \"${mod_time_subdir}\" (in units of seconds since Epoch) + mod_time_csv = \"${mod_time_csv}\" (in units of seconds since Epoch) + csv_fp = \"${csv_fp}\" +Thus, the CSV file must be updated. Setting generate_csv_file to \"TRUE\" +to generate a new CSV file: + generate_csv_file = \"${generate_csv_file}\"" + fi + fi +# +# Change location to the current category subdirectory. +# + cd_vrfy "${subdir_fp}" +# +# Get the contents of the current subdirectory. We consider each item +# that has a name of the form +# +# config.${test_name}.sh +# +# to be a WE2E test configuration file, and we take the name of the test +# to be whatever ${test_name} in the above expression corresponds to. +# We ignore all other items in the subdirectory. +# + all_items=( $(ls -1) ) + num_items="${#all_items[@]}" + for (( j=0; j<=$((num_items-1)); j++ )); do + + crnt_item="${all_items[$j]}" +# +# Try to extract the name of the test from the name of the current item +# and place the result in test_name_or_null. test_name_or_null will +# contain the name of the test only if the item has a name of the form +# "config.${test_name}.sh", in which case it will be equal to ${test_name}. +# Otherwise, it will be a null string. +# + regex_search="^config\.(.*)\.sh$" + test_name_or_null=$( printf "%s\n" "${crnt_item}" | \ + sed -n -r -e "s/${regex_search}/\1/p" ) +# +#----------------------------------------------------------------------- +# +# Take further action for this item only if it has a name of the form +# above expected for a WE2E test configuration file, which will be the +# case only if test_name_or_null is not a null string. +# +#----------------------------------------------------------------------- +# + if [ ! -z "${test_name_or_null}" ]; then +# +#----------------------------------------------------------------------- +# +# Use bash's -h conditional operator to check whether the current item +# (which at this point is taken to be a test configuration file) is a +# symlink. If it is a symlink, the only type of entity we allow the +# target to be is an existing ordinary file. In particular, to keep the +# WE2E testing system simple, we do not allow the target to be a symlink. +# Of course, it also cannot be a directory or other exotic entity. Below, +# we check for these various possibilities and only allow the case of the +# target being an existing ordinary file. +# +#----------------------------------------------------------------------- +# + if [ -h "${crnt_item}" ]; then +# +# Extract the name of the test from the name of the symlink and append +# it to the array alt_test_names. Also, append the category subdirectory +# under test_configs_basedir in which the symlink is located to the array +# alt_test_subdirs. +# + alt_test_names+=("${test_name_or_null}") + alt_test_subdirs+=("$subdir") +# +# Get the full path to the target of the symlink without following targets +# that are themselves symlinks. The "readlink" utility without any flags +# (such as -f) can do this, but when -f is omitted, it returns a relative +# path. To convert that relative path to an absolute path without resolving +# symlinks, use the "realpath" utility with the -s flag. +# + target_rp=$( readlink "${crnt_item}" ) + target_fp=$( realpath -s "${target_rp}" ) +# +# Use bash's -h conditional operator to check whether the target itself +# is a symlink. For simplicity, this is not allowed. Thus, in this +# case, print out an error message and exit. +# + if [ -h "${target_fp}" ]; then + cwd="$(pwd)" + print_err_msg_exit "\ +The symlink (crnt_item) in the current directory (cwd) has a target +(target_fp) that is itself a symlink: + cwd = \"${cwd}\" + crnt_item = \"${crnt_item}\" + target_fp = \"${target_fp}\" +This is not allowed. Please ensure that the current item points to an +ordinary file (i.e. not a symlink) and rerun." + fi +# +# Now use bash's -f conditional operator to check whether the target is +# a "regular" file (as defined by bash). Note that this test will return +# false if the target is a directory or does not exist and true otherwise. +# Thus, the negation of this test applied to the target (i.e. ! -f) that +# we use below will be true if the target is not an existing file. In +# this case, we print out an error message and exit. +# +# Note also that the -f operator recursively follows a symlink passed to +# it as an argument. For this reason, we need to first perform the -h +# test above to check that the target (without resolving symlinks) is +# itself not a symlink. The -f test below does not help in this regard. +# + if [ ! -f "${target_fp}" ]; then + cwd="$(pwd)" + print_err_msg_exit "\ +The symlink (crnt_item) in the current directory (cwd) has a target +(target_fp) that is not an existing ordinary file: + cwd = \"${cwd}\" + crnt_item = \"${crnt_item}\" + target_fp = \"${target_fp}\" +This is probably because either the target doesn't exist or is a directory, +neither of which is allowed because the symlink must point to an ordinary +(i.e. non-symlink) WE2E test configuration file. Please either point the +symlink to such a file or remove it, then rerun." + fi +# +# Get the name of the directory in which the target is located. +# + target_dir=$( dirname "${target_fp}" ) +# +# Next, check whether the directory in which the target is located is +# under the base directory of the WE2E test configuration files (i.e. +# test_configs_basedir). We require that the target be located in one +# of the subdirectories under test_configs_basedir (or directly under +# test_configs_basedir itself) because we don't want to deal with tests +# that have configuration files that may be located anywhere in the file +# system; for simplicity, we want all configuration files to be placed +# somewhere under test_configs_basedir. +# +# Note that the bash parameter expansion ${var/search/replace} returns +# $var but with the first instance of "search" replaced by "replace" if +# the former is found in $var. Otherwise, it returns the original $var. +# If "replace" is omitted, then "search" is simply deleted. Thus, in +# the if-statement below, if ${target_dir/${test_configs_basedir}/} +# returns ${target_dir} without changes (in which case the test in the +# if-statment will evaluate to true), it means ${test_configs_basedir} +# was not found within ${target_dir}. That in turn means ${target_dir} +# is not a location under ${test_configs_basedir}. In this case, print +# out a warning and exit. +# + if [ "${target_dir}" = "${target_dir/${test_configs_basedir}/}" ]; then + cwd="$(pwd)" + print_err_msg_exit "\ +The symlink (crnt_item) in the current directory (cwd) has a target +(target_fp) located in a directory (target_dir) that is not somewhere +under the WE2E tests base directory (test_configs_basedir): + cwd = \"${cwd}\" + crnt_item = \"${crnt_item}\" + target_fp = \"${target_fp}\" + target_dir = \"${target_dir}\" + test_configs_basedir = \"${test_configs_basedir}\" +For clarity, we require all WE2E test configuration files to be located +somewhere under test_configs_basedir (either directly in this base +directory on in a subdirectory). Please correct and rerun." + fi +# +# Finally, check whether the name of the target file is in the expected +# format "config.${test_name}.sh" for a WE2E test configuration file. +# If not, print out a warning and exit. +# + target_fn=$( basename "${target_fp}" ) + target_test_name_or_null=$( printf "%s\n" "${target_fn}" | \ + sed -n -r -e "s/${regex_search}/\1/p" ) + if [ -z "${target_test_name_or_null}" ]; then + cwd="$(pwd)" + print_err_msg_exit "\ +The symlink (crnt_item) in the current directory (cwd) has a target +(target_fn; located in the directory target_dir) with a name that is +not in the form \"config.[test_name].sh\" expected for a WE2E test +configuration file: + cwd = \"${cwd}\" + crnt_item = \"${crnt_item}\" + target_dir = \"${target_dir}\" + target_fn = \"${target_fn}\" +Please either rename the target to have the form specified above or +remove the symlink, then rerun." + fi +# +# Now that all the checks above have succeeded, for later use save the +# name of the WE2E test that the target represents in the array +# alt_test_prim_test_names. +# + alt_test_prim_test_names+=("${target_test_name_or_null}") +# +#----------------------------------------------------------------------- +# +# If the current item is not a symlink... +# +#----------------------------------------------------------------------- +# + else +# +# Check if the current item is a "regular" file (as defined by bash) and +# thus not a directory or some other exotic entity. If it is a regular +# file, save the corresponding WE2E test name and category subdirectory +# in the arrays prim_test_names and prim_test_subdirs, respectively. +# Also, set its test ID and save it in the array prim_test_ids. If the +# current item is not a regular file, print out a warning and exit. +# + if [ -f "${crnt_item}" ]; then + prim_test_names+=("${test_name_or_null}") + prim_test_subdirs+=("${subdir}") + test_id=$((test_id+1)) + prim_test_ids+=("${test_id}") + else + cwd="$(pwd)" + print_err_msg_exit "\ +The item (crnt_item) in the current directory (cwd) is not a symlink, +but it is also not a \"regular\" file (i.e. it fails bash's -f conditional +operator): + cwd = \"${cwd}\" + crnt_item = \"${crnt_item}\" + [ -f "${crnt_item}" ] = $([ -f "${crnt_item}" ]) +This is probably because it is a directory. Please correct and rerun." + fi + + fi + + fi + + done + + done +# +# For later use, save the number of primary and alternate test names in +# variables. +# + num_prim_tests="${#prim_test_names[@]}" + num_alt_tests="${#alt_test_names[@]}" +# +#----------------------------------------------------------------------- +# +# Create the array test_names that contains both the primary and alternate +# test names found above (with the list of primary names first followed +# by the list of alternate names). Also, create the array test_subdirs +# that contains the category subdirectories corresponding to these test +# names. +# +#----------------------------------------------------------------------- +# + test_names=("${prim_test_names[@]}") + test_subdirs=("${prim_test_subdirs[@]}") + if [ "${num_alt_tests}" -gt "0" ]; then + test_names+=("${alt_test_names[@]:-}") + test_subdirs+=("${alt_test_subdirs[@]:-}") + fi +# +#----------------------------------------------------------------------- +# +# For simplicity, make sure that each test name (either primary or +# alternate) appears exactly once in the array test_names. This is +# equivalent to requiring that a test configuration file (ordinary file +# or symlink) corresponding to each name appear exactly once anywhere +# under the base directory test_configs_basedir. +# +#----------------------------------------------------------------------- +# + num_tests="${#test_names[@]}" + for (( i=0; i<=$((num_tests-1)); i++ )); do + + test_name="${test_names[$i]}" + + subdirs=() + num_occurrences=0 + for (( j=0; j<=$((num_tests-1)); j++ )); do + if [ "${test_names[$j]}" = "${test_name}" ]; then + num_occurrences=$((num_occurrences+1)) + subdirs+=("${test_subdirs[$j]}") + fi + done + + if [ "${num_occurrences}" -ne "1" ]; then + print_err_msg_exit "\ +There must be exactly one WE2E test configuration file (which may be a +ordinary file or a symlink) corresponding to each test name anywhere +under the base directory test_configs_basedir. However, the number of +configuration files (num_occurences) corresponding to the current test +name (test_name) is not 1: + test_configs_basedir = \"${test_configs_basedir}\" + test_name = \"${test_name}\" + num_occurrences = ${num_occurrences} +These configuration files all have the name + \"config.${test_name}.sh\" +and are located in the following category subdirectories under +test_configs_basedir: + subdirs = ( $( printf "\"%s\" " "${subdirs[@]}" )) +Please rename or remove all but one of these configuration files so that +they correspond to unique test names and rerun." + fi + + done +# +#----------------------------------------------------------------------- +# +# If the input argument outvarname_test_descs is not set to a null string +# (meaning that the name of the array in which to return the WE2E test +# descriptions is specified in the call to this function), or if the flag +# generate_csv_file is set to "TRUE", we need to obtain the WE2E test +# descriptions from the test configuration files. In these cases, set +# the local variable get_test_descs to "TRUE". Otherwise, set it to +# "FALSE". +# +#----------------------------------------------------------------------- +# + get_test_descs="FALSE" + if [ ! -z "${outvarname_test_descs}" ] || \ + [ "${generate_csv_file}" = "TRUE" ]; then + get_test_descs="TRUE" + fi +# +#----------------------------------------------------------------------- +# +# If get_test_descs is set to "TRUE", loop through all the primary test +# names and extract from the configuration file of each the description +# of the test. This is assumed to be a section of (bash) comment lines +# at the top of the configuration file. Then append the test description +# to the array prim_test_descs. Note that we assume the first non-comment +# line at the top of the configuration file indicates the end of the test +# description header. +# +#----------------------------------------------------------------------- +# + if [ "${get_test_descs}" = "TRUE" ]; then +# +# Specify in "vars_to_extract" the list of experiment variables to extract +# from each test configuration file (and later to place in the CSV file). +# Recall that the rows of the CSV file correspond to the various WE2E +# tests, and the columns correspond to the test name, description, and +# experiment variable values. The elements of "vars_to_extract" should +# be the names of SRW App experiment variables that are (or can be) +# specified in the App's configuration file. Note that if a variable is +# not specified in the test configuration file, in most cases its value +# is set to an empty string (and recorded as such in the CSV file). In +# some cases, it is set to some other value (e.g. for the number of +# ensemble members NUM_ENS_MEMBERS, it is set to 1). +# + vars_to_extract=( "PREDEF_GRID_NAME" \ + "CCPP_PHYS_SUITE" \ + "EXTRN_MDL_NAME_ICS" \ + "EXTRN_MDL_NAME_LBCS" \ + "DATE_FIRST_CYCL" \ + "DATE_LAST_CYCL" \ + "CYCL_HRS" \ + "INCR_CYCL_FREQ" \ + "FCST_LEN_HRS" \ + "LBC_SPEC_INTVL_HRS" \ + "NUM_ENS_MEMBERS" \ + ) + num_vars_to_extract="${#vars_to_extract[@]}" +# +# Create names of local arrays that will hold the value of the corresponding +# variable for each test. Then use these names to define them as empty +# arrays. [The arrays named "prim_..." are to hold values for only the +# primary tests, while other arrays are to hold values for all (primary +# plus alternate) tests.] +# + prim_array_names_vars_to_extract=( $( printf "prim_test_%s_vals " "${vars_to_extract[@]}" ) ) + array_names_vars_to_extract=( $( printf "%s_vals " "${vars_to_extract[@]}" ) ) + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + cmd="local ${prim_array_names_vars_to_extract[$k]}=()" + eval $cmd + cmd="local ${array_names_vars_to_extract[$k]}=()" + eval $cmd + done + + print_info_msg " +Gathering test descriptions and experiment variable values from the +configuration files of the primary WE2E tests... +" + + prim_test_descs=() + for (( i=0; i<=$((num_prim_tests-1)); i++ )); do + + test_name="${prim_test_names[$i]}" + print_info_msg "\ + Reading in the test description for primary WE2E test: \"${test_name}\" + In category (subdirectory): \"${subdir}\" +" + subdir=("${prim_test_subdirs[$i]}") + cd_vrfy "${test_configs_basedir}/$subdir" +# +# Keep reading lines from the current test's configuration line until +# a line is encountered that does not start with zero or more spaces, +# followed by the hash symbol (which is the bash comment character) +# possibly followed by a single space character. +# +# In the while-loop below, we read in every such line, strip it of any +# leading spaces, the hash symbol, and possibly another space and append +# what remains to the local variable test_desc. +# + config_fn="config.${test_name}.sh" + test_desc="" + while read -r line; do + + regex_search="^[ ]*(#)([ ]{0,1})(.*)" + hash_or_null=$( printf "%s" "${line}" | \ + sed -n -r -e "s/${regex_search}/\1/p" ) +# +# If the current line is part of the file header containing the test +# description, then... +# + if [ "${hash_or_null}" = "#" ]; then +# +# Strip from the current line any leading whitespace followed by the +# hash symbol possibly followed by a single space. If what remains is +# empty, it means there are no comments on that line and it is just a +# separator line. In that case, simply add a newline to test_desc. +# Otherwise, append what remains after stripping to what test_desc +# already contains, followed by a single space in preparation for +# appending the next (stripped) line. +# + stripped_line=$( printf "%s" "${line}" | \ + sed -n -r -e "s/${regex_search}/\3/p" ) + if [ -z "${stripped_line}" ]; then + test_desc="\ +${test_desc} + +" + else + test_desc="\ +${test_desc}${stripped_line} " + fi +# +# If the current line is not part of the file header containing the test +# description, break out of the while-loop (and thus stop reading the +# file). +# + else + break + fi + + done < "${config_fn}" +# +# At this point, test_desc contains a description of the current test. +# Note that: +# +# 1) It will be empty if the configuration file for the current test +# does not contain a header describing the test. +# 2) It will contain newlines if the description header contained lines +# that start with the hash symbol and contain no other characters. +# These are used to delimit paragraphs within the description. +# 3) It may contain leading and trailing whitespace. +# +# Next, for clarity, we remove any leading and trailing whitespace using +# bash's pattern matching syntax. +# +# Note that the right-hand sides of the following two lines are NOT +# regular expressions. They are expressions that use bash's pattern +# matching syntax (gnu.org/software/bash/manual/html_node/Pattern-Matching.html, +# wiki.bash-hackers.org/syntax/pattern) used in substring removal +# (tldp.org/LDP/abs/html/string-manipulation.html). For example, +# +# ${var%%[![:space:]]*} +# +# says "remove from var its longest substring that starts with a non- +# space character". +# +# First remove leading whitespace. +# + test_desc="${test_desc#"${test_desc%%[![:space:]]*}"}" +# +# Now remove trailing whitespace. +# + test_desc="${test_desc%"${test_desc##*[![:space:]]}"}" +# +# Finally, save the description of the current test as the next element +# of the array prim_test_descs. +# + prim_test_descs+=("${test_desc}") +# +# Get from the current test's configuration file the values of the +# variables specified in "vars_to_extract". Then save the value in the +# arrays specified by "prim_array_names_vars_to_extract". +# + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + + var_name="${vars_to_extract[$k]}" + cmd=$( grep "^[ ]*${var_name}=" "${config_fn}" ) + eval $cmd + + if [ -z "${!var_name+x}" ]; then + + msg=" + The variable \"${var_name}\" is not defined in the current test's + configuration file (config_fn): + config_fn = \"${config_fn}\" + Setting the element in the array \"${prim_array_names_vars_to_extract[$k]}\" + corresponding to this test to" + + case "${var_name}" in + + "NUM_ENS_MEMBERS") + default_val="1" + msg=$msg": + ${var_name} = \"${default_val}\"" + ;; + + "INCR_CYCL_FREQ") + default_val="24" + msg=$msg": + ${var_name} = \"${default_val}\"" + ;; + + *) + default_val="" + msg=$msg" an empty string." + ;; + + esac + cmd="${var_name}=\"${default_val}\"" + eval $cmd + + print_info_msg "$verbose" "$msg" + cmd="${prim_array_names_vars_to_extract[$k]}+=(\"'${default_val}\")" + + else +# +# The following are important notes regarding how the variable "cmd" +# containing the command that will append an element to the array +# specified by ${prim_array_names_vars_to_extract[$k]} is formulated: +# +# 1) If all the experiment variables were scalars, then the more complex +# command below could be replaced with the following: +# +# cmd="${prim_array_names_vars_to_extract[$k]}+=(\"${!var_name}\")" +# +# But some variables are arrays, so we need the more complex approach +# to cover those cases. +# +# 2) The double quotes (which need to be escaped here, i.e. \") are needed +# so that for any experiment variables that are arrays, all the elements +# of the array are combined together and treated as a single element. +# If the experiment variable is CYCL_HRS (cycle hours) and is set to +# the array ("00" "12"), we want the value saved in the local array +# here to be a single element consisting of "00 12". Otherwise, "00" +# and "12" will be treated as separate elements, and more than one +# element would be added to the array (which would be incorrect here). +# +# 3) The single quote (which needs to be escaped here, i.e. \') is needed +# so that any numbers (e.g. a set of cycle hours such as "00 12") are +# treated as strings when the CSV file is opened in Google Sheets. +# If this is not done, Google Sheets will remove leading zeros. +# + var_name_at="${var_name}[@]" + cmd="${prim_array_names_vars_to_extract[$k]}+=(\'\"${!var_name_at}\")" + fi + eval $cmd + + done +# +# Calculate the number of forecasts that will be launched by the current +# test. The "10#" forces bash to treat the following number as a decimal +# (not hexadecimal, etc). Note that INCR_CYCL_FREQ is in units of hours, +# so the factor of 24 is needed to convert the number of days to hours. +# + num_cycles_per_day=${#CYCL_HRS[@]} + num_days=$(( (${DATE_LAST_CYCL} - ${DATE_FIRST_CYCL} + 1)*24/10#${INCR_CYCL_FREQ} )) + num_cdates=$(( ${num_cycles_per_day}*${num_days} )) + nf=$(( ${num_cdates}*10#${NUM_ENS_MEMBERS} )) +# +# Save the number of forecasts launched by the current test in an +# appropriately named array. In the following, the single quote at the +# beginning forces Google Sheets to interpret this quantity as a string. +# This prevents any automatic number fomatting from being applied when +# the CSV file is imported into Google Sheets. +# + prim_test_num_fcsts+=( "'$nf" ) +# +#----------------------------------------------------------------------- +# +# Calculate the relative dynamics cost of the test, i.e. the relative +# cost of running only the dynamics portion of the forecast model. Here, +# we define the absolute cost of running the dynamics as +# +# abs_cost = nx*ny*num_time_steps*num_fcsts +# +# where nx and ny are the horizontal dimensions of the grid, num_time_steps +# is the number of time steps that need to be taken to complete one +# forecast within the test, and num_fcsts are the number of forecasts +# the test makes (e.g. if the test performs an ensemble forecast, the +# value of this parameter will be greater than 1). +# +# The relative cost is obtained by dividing the absolute cost of a test +# by the absolute cost of a reference 6-hour forecast on the RRFS_CONUS_25km +# predefined grid using the default time step for that grid. This is +# calculated later below and saved in the variable abs_cost_ref. Thus, +# the relative cost is given by +# +# rel_cost = abs_cost/abs_cost_ref +# +# defined as abs_cost_ref. +# +# Note that the (absolute or relative) cost defined here does not take +# into account the costs of running different physics suites, nor does +# it take into account the costs of workflow tasks other than the forecast +# task (e.g. generation of initial and boundary conditions, post processing, +# verification, etc; that is why it is referred to as the relative DYNAMICS +# cost). Note also that if in the future the number of levels in the +# vertical becomes a user-specified parameter, that will also have to be +# added to the definition of the cost. +# +#----------------------------------------------------------------------- +# + +# +# To calculate the absolute cost as defined above, we need the number of +# points in the two horizontal directions, nx and ny. Also, to calculate +# the number of time steps, we need the size of the time step (dt_atmos). +# These depend on the grid being used and must be extracted from the grid +# parameters. The way the latter are obtained depends on whether or not +# a predefined grid is being used. +# +params=$(\ + PREDEF_GRID_NAME="${PREDEF_GRID_NAME}" \ + QUILTING="FALSE" \ + RADIUS_EARTH=${RADIUS_EARTH} \ + DEGS_PER_RADIAN=${DEGS_PER_RADIAN} \ + NH4=${NH4} \ + $ushdir/calculate_cost.py -c "${test_configs_basedir}/$subdir/${config_fn}") + +read dta nxny dta_r nxny_r <<< "${params}" + +# +# Save the value of dta (which is just dt_atmos) in an array. The single +# quote at the beginning forces Google Sheets to interpret this quantity +# as a string. This prevents any automatic number fomatting from being +# applied when the CSV file is imported into Google Sheets. +# + prim_test_dt_atmos+=( "'${dta}" ) +# +# Calculate the total number of horizontal grid points. +# + num_grid_pts=$nxny +# +# Calculate the number of time steps for the test. Note that FCST_LEN_HRS +# is in units of hours while dta is in units of seconds. Also, the factor +# dta - 1 in the numerator is to cause the division to round up to the +# nearest integer (adding the denominator minus one to the numerator will +# make this happen). +# + num_time_steps=$(( (FCST_LEN_HRS*3600 + dta - 1)/dta )) +# +# Calculate the absolute cost of the test. +# + ac=$(( num_grid_pts*num_time_steps*nf )) +# +# Save the absolute cost for this test in the array that will eventually +# contain the relative cost. The values in this array will be divided +# by abs_cost_ref later below to obtain relative costs. +# + prim_test_rel_cost+=( "$ac" ) +# +# Unset the experiment variables defined for the current test so that +# they are not accidentally used for the next one. +# + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + var_name="${vars_to_extract[$k]}" + cmd="unset ${var_name}" + eval $cmd + done + + done # End loop over primary tests +# +#----------------------------------------------------------------------- +# +# Normalize the absolute costs calculated above for each test by the +# absolute cost of a reference 6-hour forecast on the RRFS_CONUS_25km +# predefined grid (using the default time step for that grid). +# +#----------------------------------------------------------------------- +# + num_grid_pts=$nxny_r + fcst_len_hrs="6" + num_time_steps=$(( (fcst_len_hrs*3600 + dta_r - 1)/dta_r )) + abs_cost_ref=$(( num_grid_pts*num_time_steps )) + + for (( i=0; i<=$((num_prim_tests-1)); i++ )); do +# +# In the following, the single quote at the beginning forces Google Sheets +# to interpret this quantity as a string. This prevents any automatic +# number fomatting from being applied when the CSV file is imported into +# Google Sheets. +# + prim_test_rel_cost[$i]="'"$( printf "%g" \ + $( bc -l <<< " ${prim_test_rel_cost[$i]}/${abs_cost_ref}" ) ) + done + + fi +# +#----------------------------------------------------------------------- +# +# Create the arrays test_ids and test_descs that initially contain the +# test IDs and descriptions corresponding to the primary test names +# (those of the alternate test names will be appended below). Then, in +# the for-loop, do same for the arrays containing the experiment variable +# values for each test. +# +#----------------------------------------------------------------------- +# + test_ids=("${prim_test_ids[@]}") + if [ "${get_test_descs}" = "TRUE" ]; then + test_descs=("${prim_test_descs[@]}") + num_fcsts=("${prim_test_num_fcsts[@]}") + dt_atmos=("${prim_test_dt_atmos[@]}") + rel_cost=("${prim_test_rel_cost[@]}") + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + cmd="${array_names_vars_to_extract[$k]}=(\"\${${prim_array_names_vars_to_extract[$k]}[@]}\")" + eval $cmd + done + fi +# +#----------------------------------------------------------------------- +# +# Append to the arrays test_ids and test_descs the test IDs and descriptions +# of the alternate test names. We set the test ID and description of +# each alternate test name to those of the corresponding primary test +# name. Then, in the inner for-loop, do the same for the arrays containing +# the experiment variable values. +# +#----------------------------------------------------------------------- +# + for (( i=0; i<=$((num_alt_tests-1)); i++ )); do + + alt_test_name="${alt_test_names[$i]}" + alt_test_subdir=("${alt_test_subdirs[$i]}") + target_prim_test_name="${alt_test_prim_test_names[$i]}" + + num_occurrences=0 + for (( j=0; j<=$((num_prim_tests-1)); j++ )); do + if [ "${prim_test_names[$j]}" = "${target_prim_test_name}" ]; then + test_ids+=("${prim_test_ids[$j]}") + if [ "${get_test_descs}" = "TRUE" ]; then + test_descs+=("${prim_test_descs[$j]}") + num_fcsts+=("${prim_test_num_fcsts[$j]}") + dt_atmos+=("${prim_test_dt_atmos[$j]}") + rel_cost+=("${prim_test_rel_cost[$j]}") + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + cmd="${array_names_vars_to_extract[$k]}+=(\"\${${prim_array_names_vars_to_extract[$k]}[$j]}\")" + eval $cmd + done + fi + num_occurrences=$((num_occurrences+1)) + fi + done + + if [ "${num_occurrences}" -ne 1 ]; then + print_err_msg_exit "\ +Each alternate test name must have a corresponding primary test name that +occurs exactly once in the full list of primary test names. For the +current alternate test name (alt_test_name), the number of occurrences +(num_occurrences) of the corresponding primary test name (target_prim_test_name) +is not 1: + alt_test_name = \"${alt_test_name}\" + target_prim_test_name = \"${target_prim_test_name}\" + num_occurrences = \"${num_occurrences}\" +Please correct and rerun." + fi + + done +# +#----------------------------------------------------------------------- +# +# Sort in order of increasing test ID the arrays containing the names, +# IDs, category subdirectories, and descriptions of the WE2E tests as +# well as the arrays containing the experiment variable values for each +# test. +# +# For this purpose, we first create an array (test_ids_and_inds) each +# of whose elements consist of the test ID, the test type, and the index +# of the array element (with a space used as delimiter). The test type +# is simply an identifier to distinguish between primary test names and +# alternate (symlink-derived) ones. For the former, we set the test +# type to "A", and for the latter, we set it to "B". We do this in order +# to obtain a sorted result in which the elements are not only sorted by +# test ID but also sorted by test type such that within each group of +# elements/tests that has the same test ID, the primary test name is +# listed first followed by zero or more alternte test names. +# +# Next, we sort the array test_ids_and_inds using the "sort" utility +# and save the result in the new array test_ids_and_inds_sorted. The +# latter will be sorted according to test ID because that is the first +# quantity on each line (element) of the original array test_ids_and_inds. +# Also, as described above, for each group of test names that have the +# same ID, the names will be sorted such that the primary test name is +# listed first. +# +# Finally, we extract from test_ids_and_inds_sorted the second number +# in each element (the one after the first number, which is the test ID, +# and the test type, which we no longer need), which is the original +# array index before sorting, and save the results in the array sort_inds. +# This array will contain the original indices in sorted order that we +# then use to sort the arrays containing the WE2E test names, IDs, +# subdirectories, descriptions, and experiment variable values. +# +#----------------------------------------------------------------------- +# + test_ids_and_inds=() + for (( i=0; i<=$((num_tests-1)); i++ )); do + test_type="A" + if [ "$i" -ge "${num_prim_tests}" ]; then + test_type="B" + fi + test_ids_and_inds[$i]="${test_ids[$i]} ${test_type} $i" + done + + readarray -t "test_ids_and_inds_sorted" < \ + <( printf "%s\n" "${test_ids_and_inds[@]}" | sort --numeric-sort ) + + sort_inds=() + regex_search="^[ ]*([0-9]*)[ ]*[AB][ ]*([0-9]*)$" + for (( i=0; i<=$((num_tests-1)); i++ )); do + sort_inds[$i]=$( printf "%s" "${test_ids_and_inds_sorted[$i]}" | \ + sed -n -r -e "s/${regex_search}/\2/p" ) + done + + local test_names_orig=( "${test_names[@]}" ) + local test_subdirs_orig=( "${test_subdirs[@]}" ) + local test_ids_orig=( "${test_ids[@]}" ) + for (( i=0; i<=$((num_tests-1)); i++ )); do + ii="${sort_inds[$i]}" + test_names[$i]="${test_names_orig[$ii]}" + test_subdirs[$i]="${test_subdirs_orig[$ii]}" + test_ids[$i]="${test_ids_orig[$ii]}" + done + + if [ "${get_test_descs}" = "TRUE" ]; then + + local test_descs_orig=( "${test_descs[@]}" ) + local num_fcsts_orig=( "${num_fcsts[@]}" ) + local dt_atmos_orig=( "${dt_atmos[@]}" ) + local rel_cost_orig=( "${rel_cost[@]}" ) + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + cmd="local ${array_names_vars_to_extract[$k]}_orig=(\"\${${array_names_vars_to_extract[$k]}[@]}\")" + eval $cmd + done + + for (( i=0; i<=$((num_tests-1)); i++ )); do + ii="${sort_inds[$i]}" + test_descs[$i]="${test_descs_orig[$ii]}" + num_fcsts[$i]="${num_fcsts_orig[$ii]}" + dt_atmos[$i]="${dt_atmos_orig[$ii]}" + rel_cost[$i]="${rel_cost_orig[$ii]}" + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + cmd="${array_names_vars_to_extract[$k]}[$i]=\"\${${array_names_vars_to_extract[$k]}_orig[$ii]}\"" + eval $cmd + done + done + + fi +# +#----------------------------------------------------------------------- +# +# If generate_csv_file is set to "TRUE", generate a CSV (comma-separated +# value) file containing information about the WE2E tests. This file +# can be opened in a spreadsheet in Google Sheets (and possibly Microsoft +# Excel as well) to view information about all the WE2E tests. Note that +# in doing so, the user must specify the field delimiter to be the same +# character that csv_delimiter is set to below. +# +#----------------------------------------------------------------------- +# + if [ "${generate_csv_file}" = "TRUE" ]; then +# +# If a CSV file already exists, delete it. +# + rm_vrfy -f "${csv_fp}" +# +# Set the character used to delimit columns in the CSV file. This has +# to be something that would normally not appear in the fields being +# written to the CSV file. +# + csv_delimiter="|" +# +# Set the titles of the columns that will be in the file. Then write +# them to the file. The contents of the columns are described in more +# detail further below. +# + column_titles="\ +\"Test Name +(Subdirectory)\" ${csv_delimiter} \ +\"Alternate Test Names +(Subdirectories)\" ${csv_delimiter} \ +\"Test Purpose/Description\" ${csv_delimiter} \ +\"Relative Cost of Running Dynamics +(1 corresponds to running a 6-hour forecast on the RRFS_CONUS_25km predefined grid using the default time step)\" ${csv_delimiter} \ +\"Number of Forecast Model Runs\"" + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + + crnt_title="${vars_to_extract[$k]}" + # + # Add units for select fields. + # + units="" + case "${vars_to_extract[$k]}" in + "INCR_CYCL_FREQ") + units="[hr]" + ;; + "FCST_LEN_HRS") + units="[hr]" + ;; + "LBC_SPEC_INTVL_HRS") + units="[hr]" + ;; + esac + crnt_title="${crnt_title}${units:+ $units}" + + column_titles="${column_titles} ${csv_delimiter} \"${crnt_title}\"" + # + # Insert a column for DT_ATMOS right after the one for FCST_LEN_HRS. + # + if [ "${vars_to_extract[$k]}" = "FCST_LEN_HRS" ]; then + units="[sec]" + crnt_title="DT_ATMOS${units:+ $units}" + column_titles="${column_titles} ${csv_delimiter} \"${crnt_title}\"" + fi + + done + printf "%s\n" "${column_titles}" >> "${csv_fp}" +# +# Loop through the arrays containing the WE2E test information. Extract +# the necessary information and record it to the CSV file row-by-row. +# Note that each row corresponds to a primary test. When an alternate +# test is encountered, its information is stored in the row of the +# corresponding primary test (i.e. a new row is not created). +# + j=0 + jp1=$((j+1)) + while [ "$j" -lt "${num_tests}" ]; do +# +# Get the primary name of the test and the category subdirectory in which +# it is located. +# + prim_test_name_subdir="${test_names[$j]}"$'\n'"(${test_subdirs[$j]})" +# +# Get the test ID. +# + test_id="${test_ids[$j]}" +# +# Get the test description. +# + test_desc="${test_descs[$j]}" +# +# Replace any double-quotes in the test description with two double-quotes +# since this is the way a double-quote is escaped in a CSV file, at least +# a CSV file that is read in by Google Sheets. +# + test_desc=$( printf "%s" "${test_desc}" | sed -r -e "s/\"/\"\"/g" ) +# +# Get the time step. +# + dta="${dt_atmos[$j]}" +# +# Get the relative cost. +# + rc="${rel_cost[$j]}" +# +# Get the number of forecasts (number of times the forcast model is run). +# + nf="${num_fcsts[$j]}" +# +# In the following inner while-loop, we step through all alternate test +# names (if any) that follow the current primary name and construct a +# string (alt_test_names_subdirs) consisting of all the alternate test +# names for this primary name, with each followed by the subdirectory +# the corresponding symlink is in. Note that when the CSV file is opened +# as a spreadsheet (e.g. in Google Sheets), this alternate test name +# information all appears in one cell of the spreadsheet. +# + alt_test_names_subdirs="" + while [ "$jp1" -lt "${num_tests}" ]; do + test_id_next="${test_ids[$jp1]}" + if [ "${test_id_next}" -eq "${test_id}" ]; then + alt_test_names_subdirs="${alt_test_names_subdirs}${test_names[$jp1]}"$'\n'"(${test_subdirs[$jp1]})"$'\n' + j="$jp1" + jp1=$((j+1)) + else + break + fi + done +# Remove trailing newline. + alt_test_names_subdirs="${alt_test_names_subdirs%$'\n'}" +# +# Write a line to the CSV file representing a single row of the spreadsheet. +# This row contains the following columns: +# +# Column 1: +# The primary test name followed by the category subdirectory it is +# located in (the latter in parentheses). +# +# Column 2: +# Any alternate test names followed by their category subdirectories (in +# parentheses). Each alternate test name and subdirectory pair is followed +# by a newline, but all lines will appear in a single cell of the spreadsheet. +# +# Column 3: +# The test description. +# +# Column 4: +# The relative cost of running the dynamics in the test. See above for +# details. +# +# Column 5: +# The number of times the forecast model will be run by the test. This +# is calculated using quantities such as the number of cycle dates (i.e. +# forecast model start dates) and the number of of ensemble members (which +# is greater than 1 if running ensemble forecasts and 1 otherwise). The +# latter are in turn obtained directly or indirectly from the quantities +# in Columns 6, 7, .... +# +# Columns 6, 7, ...: +# The values of the experiment variables specified in vars_to_extract, +# plus DT_ATMOS (included right after FCST_LEN_HRS). Note that DT_ATMOS +# cannot be included in vars_to_extract because it is usually not in the +# WE2E test configuration file where this script looks for these variables +# (because most of the tests use predefined grids, and for those cases, +# DT_ATMOS is defined in the same file/script where the other grid +# parameters are defined). +# + row_content="\ +\"${prim_test_name_subdir}\" ${csv_delimiter} \ +\"${alt_test_names_subdirs}\" ${csv_delimiter} \ +\"${test_desc}\" ${csv_delimiter} \ +\"${rc}\" ${csv_delimiter} \ +\"${nf}\"" + + for (( k=0; k<=$((num_vars_to_extract-1)); k++ )); do + + unset "val" + cmd="val=\"\${${array_names_vars_to_extract[$k]}[$j]}\"" + eval $cmd + row_content="${row_content} ${csv_delimiter} \"${val}\"" +# +# Insert value of DT_ATMOS right after value of FCST_LEN_HRS. +# + if [ "${vars_to_extract[$k]}" = "FCST_LEN_HRS" ]; then + row_content="${row_content} ${csv_delimiter} \"${dta}\"" + fi + + done + + printf "%s\n" "${row_content}" >> "${csv_fp}" +# +# Update loop indices. +# + j="$jp1" + jp1=$((j+1)) + + done + + print_info_msg "\ +Successfully generated a CSV (Comma Separated Value) file (csv_fp) +containing information on all WE2E tests: + csv_fp = \"${csv_fp}\"" + + fi +# +#----------------------------------------------------------------------- +# +# Use the eval function to set this function's output variables. Note +# that each of these is set only if the corresponding input variable +# specifying the name to use for the output variable is not empty. +# +#----------------------------------------------------------------------- +# + if [ ! -z "${outvarname_test_configs_basedir}" ]; then + eval ${outvarname_test_configs_basedir}="${test_configs_basedir}" + fi + + if [ ! -z "${outvarname_test_names}" ]; then + test_names_str="( "$( printf "\"%s\" " "${test_names[@]}" )")" + eval ${outvarname_test_names}="${test_names_str}" + fi + + if [ ! -z "${outvarname_test_subdirs}" ]; then + test_subdirs_str="( "$( printf "\"%s\" " "${test_subdirs[@]}" )")" + eval ${outvarname_test_subdirs}="${test_subdirs_str}" + fi + + if [ ! -z "${outvarname_test_ids}" ]; then + test_ids_str="( "$( printf "\"%s\" " "${test_ids[@]}" )")" + eval ${outvarname_test_ids}="${test_ids_str}" + fi + + if [ ! -z "${outvarname_test_descs}" ]; then +# +# We want to treat all characters in the test descriptions literally +# when evaluating the array specified by outvarname_test_descs below +# using the eval function because otherwise, characters such as "$", +# "(", ")", etc will be interpreted as indicating the value of a variable, +# the start of an array, the end of an array, etc, and lead to errors. +# Thus, below, when forming the array that will be passed to eval, we +# will surround each element of the local array test_descs in single +# quotes. However, the test descriptions themselves may include single +# quotes (e.g. when a description contains a phrase such as "Please see +# the User's Guide for..."). In order to treat these single quotes +# literally (as opposed to as delimiters indicating the start or end of +# array elements), we have to pass them as separate strings by replacing +# each single quote with the following series of characters: +# +# '"'"' +# +# In this, the first single quote indicates the end of the previous +# single-quoted string, the "'" indicates a string containing a literal +# single quote, and the last single quote inidicates the start of the +# next single-quoted string. +# +# For example, let's assume there are only two WE2E tests to consider. +# Assume the description of the first is +# +# Please see the User's Guide. +# +# and that of the second is: +# +# See description of ${DOT_OR_USCORE} in the configuration file. +# +# Then, if outvarname_test_descs is set to "some_array", the exact string +# we want to pass to eval is: +# +# some_array=('Please see the User'"'"'s Guide.' 'See description of ${DOT_OR_USCORE} in the configuration file.') +# + test_descs_esc_sq=() + for (( i=0; i<=$((num_tests-1)); i++ )); do + test_descs_esc_sq[$i]=$( printf "%s" "${test_descs[$i]}" | \ + sed -r -e "s/'/'\"'\"'/g" ) + done + test_descs_str="( "$( printf "'%s' " "${test_descs_esc_sq[@]}" )")" + eval ${outvarname_test_descs}="${test_descs_str}" + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script or +# function. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/tests/WE2E/get_expts_status.sh b/tests/WE2E/get_expts_status.sh new file mode 100755 index 0000000000..108ec68e35 --- /dev/null +++ b/tests/WE2E/get_expts_status.sh @@ -0,0 +1,445 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script updates and reports back the workflow status of all active +# forecast experiments under a specified base directory (expts_basedir). +# It must be supplied exactly one argument, which is the full path to the +# experiments base directory. +# +# The script first determines which of the subdirectories under the base +# directory represent active experiments (see below for how this is done). +# For all such experiments, it calls the workflow (re)launch script to +# update the status of the workflow and prints the status out to screen. +# It also generates a status report file in the base directory that +# contains the last num_log_lines lines (defined below) of each experiment's +# workflow log file [which is generated by the (re)launch script] and thus +# has information on which tasks may have succeeded/failed]. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Do not allow uninitialized variables. +# +#----------------------------------------------------------------------- +# +set -u +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( readlink -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# The current script should be located in the "tests" subdirectory of the +# workflow's top-level directory, which we denote by SR_WX_APP_TOP_DIR. +# SR_WX_APP_TOP_DIR is the directory two levels above the directory in +# which the current script is located; set SR_WX_APP_TOP_DIR accordingly. +# +#----------------------------------------------------------------------- +# +SR_WX_APP_TOP_DIR=${scrfunc_dir%/*/*} +# +#----------------------------------------------------------------------- +# +# Set directories. +# +#----------------------------------------------------------------------- +# +ushdir="$SR_WX_APP_TOP_DIR/ush" +# +#----------------------------------------------------------------------- +# +# Source bash utility functions. +# +#----------------------------------------------------------------------- +# +. $ushdir/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Set the usage message. +# +#----------------------------------------------------------------------- +# +usage_str="\ +Usage: + + ${scrfunc_fn} \\ + expts_basedir=\"...\" \\ + [num_log_lines=\"...\"] \\ + [verbose=\"...\"] + +The arguments in brackets are optional. The arguments are defined as +follows: + +expts_basedir: +Full path to the experiments base directory, i.e. the directory containing +the experiment subdirectories. + +num_log_lines: +Optional integer specifying the number of lines from the end of the +workflow launch log file (log.launch_FV3LAM_wflow) of each test to +include in the status report file that this script generates. + +verbose: +Optional verbosity flag. Should be set to \"TRUE\" or \"FALSE\". Default +is \"FALSE\". +" +# +#----------------------------------------------------------------------- +# +# Check to see if usage help for this script is being requested. If so, +# print it out and exit with a 0 exit code (success). +# +#----------------------------------------------------------------------- +# +help_flag="--help" +if [ "$#" -eq 1 ] && [ "$1" = "${help_flag}" ]; then + print_info_msg "${usage_str}" + exit 0 +fi +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script or function. +# Then process the arguments provided to it on the command line (which +# should consist of a set of name-value pairs of the form arg1="value1", +# arg2="value2", etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ + "expts_basedir" \ + "num_log_lines" \ + "verbose" \ + ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# Set the default value of "num_log_lines". +# +#----------------------------------------------------------------------- +# +num_log_lines=${num_log_lines:-"40"} +# +#----------------------------------------------------------------------- +# +# Make the default value of "verbose" "FALSE". Then make sure "verbose" +# is set to a valid value. +# +#----------------------------------------------------------------------- +# +verbose=${verbose:-"FALSE"} +check_var_valid_value "verbose" "valid_vals_BOOLEAN" +verbose=$(boolify "$verbose") +# +#----------------------------------------------------------------------- +# +# Verify that the required arguments to this script have been specified. +# If not, print out an error message and exit. +# +#----------------------------------------------------------------------- +# +help_msg="\ +Use + ${scrfunc_fn} ${help_flag} +to get help on how to use this script." + +if [ -z "${expts_basedir}" ]; then + print_err_msg_exit "\ +The argument \"expts_basedir\" specifying the base directory containing +the experiment directories was not specified in the call to this script. \ +${help_msg}" +fi +# +#----------------------------------------------------------------------- +# +# Check that the specified experiments base directory exists and is +# actually a directory. If not, print out an error message and exit. +# +#----------------------------------------------------------------------- +# +if [ ! -d "${expts_basedir}" ]; then + print_err_msg_exit " +The specified experiments base directory (expts_basedir) does not exit +or is not actually a directory: + expts_basedir = \"${expts_basedir}\"" +fi +# +#----------------------------------------------------------------------- +# +# Create an array containing the names of the subdirectories in the +# experiment base directory. +# +#----------------------------------------------------------------------- +# +cd_vrfy "${expts_basedir}" +# +# Get a list of all subdirectories (but not files) in the experiment base +# directory. Note that the ls command below will return a string containing +# the subdirectory names, with each name followed by a backslash and a +# newline. +# +subdirs_list=$( \ls -1 -d */ ) +# +# Remove all backslashes from the ends of the subdirectory names. +# +subdirs_list=$( printf "${subdirs_list}" "%s" | sed -r 's|/||g' ) +# +# Create an array out of the string containing the newline-separated list +# of subdirectories. +# +subdirs_list=( ${subdirs_list} ) +# +#----------------------------------------------------------------------- +# +# Loop through the elements of the array subdirs_list and create an array +# containing a list of all active experiment subdirectories under the +# experiment base directory. These active subdirectories will be further +# processed later below. Here, by "active" experiment subdirectory, we +# mean a subdirectory that (1) contains a forecast experiment (i.e. was +# was created by the experiment generation scripts) and (2) does not +# represent an old experiment whose workflow status is no longer relevant. +# For this purpose, for each element in subdirs_list, we: +# +# 1) Change location to the subdirectory. +# +# 2) Check whether an experiment variable definitions file (var_defns.sh) +# exists. If so, we assume the subdirectory is an experiment directory. +# If not, we assume it is not, in which case the subdirectory will +# not be added to the list of active experiment subdirectories. +# +# 3) If the subdirectory is an experiment directory, ensure that it is +# an active experiment, i.e. that it is not an old experiment that +# has been renamed and whose experiment status is thus irrelevant. +# For this purpose, we source the variable definitions file in order +# to have available the workflow variable EXPT_SUBDIR that contains +# the name of the experiment when it was first created. If this +# matches the name of the current subdirectory, then add the latter +# to the list of active experiment subdirectories; otherwise, do not. +# In the latter case, we are assuming that the original experiment +# subdirectory was renamed (e.g. to something like the orginal name +# with the string "_old001" appended) and thus does not contain an +# active experiment whose workflow status is of interest. +# +# 4) Change location back to the experiments base directory. +# +#----------------------------------------------------------------------- +# +separator="======================================" + +var_defns_fn="var_defns.sh" +j="0" +expt_subdirs=() + +print_info_msg "\ +Checking for active experiment directories in the specified experiments +base directory (expts_basedir): + expts_basedir = \"${expts_basedir}\" +..." + +num_subdirs="${#subdirs_list[@]}" +for (( i=0; i<=$((num_subdirs-1)); i++ )); do + + subdir="${subdirs_list[$i]}" + msg=" +$separator +Checking whether the subdirectory + \"${subdir}\" +contains an active experiment..." + print_info_msg "$verbose" "$msg" + + cd_vrfy "${subdir}" +# +# If a variable definitions file does not exist, print out a message +# and move on to the next subdirectory. +# + if [ ! -f "${var_defns_fn}" ]; then + + print_info_msg "$verbose" " +The current subdirectory (subdir) under the experiments base directory +(expts_basedir) does not contain an experiment variable defintions file +(var_defns_fn): + expts_basedir = \"${expts_basedir}\" + subdir = \"${subdir}\" + var_defns_fn = \"${var_defns_fn}\" +Thus, we will assume it is not an experiment directory and will not add +it to the list of active experiments subdirectories whose workflow status +must be checked." +# +# If a variable definitions file does exist, then... +# + else +# +# Source the variable definitions file. +# + . "./${var_defns_fn}" +# +# If the workflow variable EXPT_SUBDIR is the same as the name of the +# current subdirectory, then assume this subdirectory contains an active +# experiment. In this case, print out a message and add its name to the +# list of such experiments. +# + if [ "${EXPT_SUBDIR}" = "$subdir" ]; then + + print_info_msg "$verbose" " +The current subdirectory (subdir) under the experiments base directory +(expts_basedir) contains an active experiment: + expts_basedir = \"${expts_basedir}\" + subdir = \"${subdir}\" +Adding the current subdirectory to the list of active experiment +subdirectories whose workflow status must be checked." + + expt_subdirs[$j]="$subdir" + j=$((j+1)) +# +# If the workflow variable EXPT_SUBDIR is not the same as the name of +# the current subdirectory, then assume this subdirectory contains an +# "inactive" that has been renamed. In this case, print out a message +# and move on to the next subdirectory (whithout adding the the name of +# the currend subdirectory to the list of active experiments). +# + else + + print_info_msg "$verbose" " +The current subdirectory (subdir) under the experiments base directory +(expts_basedir) contains an experiment whose original name (EXPT_SUBDIR) +does not match the name of the current subdirectory: + expts_basedir = \"${expts_basedir}\" + subdir = \"${subdir}\" + EXPT_SUBDIR = \"${EXPT_SUBDIR}\" +Thus, we will assume that the current subdirectory contains an inactive +(i.e. old) experiment whose workflow status is not relevant and will not +add it to the list of active experiment subdirectories whose workflow +status must be checked." + + fi + + fi + + print_info_msg "$verbose" "\ +$separator +" +# +# Change location back to the experiments base directory. +# + cd_vrfy "${expts_basedir}" + +done +# +#----------------------------------------------------------------------- +# +# Get the number of active experiments for which to check the workflow +# status and print out an informational message. +# +#----------------------------------------------------------------------- +# +num_expts="${#expt_subdirs[@]}" +expt_subdirs_str=$( printf " \'%s\'\n" "${expt_subdirs[@]}" ) +print_info_msg " +The number of active experiments found is: + num_expts = ${num_expts} +The list of experiments whose workflow status will be checked is: +${expt_subdirs_str} +" +# +#----------------------------------------------------------------------- +# +# Set the name and full path of the file in which the status report will +# be saved. If such a file already exists, rename it. +# +#----------------------------------------------------------------------- +# +yyyymmddhhmn=$( date +%Y%m%d%H%M ) +expts_status_fn="expts_status_${yyyymmddhhmn}.txt" +expts_status_fp="${expts_basedir}/${expts_status_fn}" + +# Note that the check_for_preexist_dir_file function assumes that there +# is a variable named "VERBOSE" in the environment. Set that before +# calling the function. +VERBOSE="TRUE" +check_for_preexist_dir_file "${expts_status_fp}" "rename" +# +#----------------------------------------------------------------------- +# +# Loop through the elements of the array expt_subdirs. For each element +# (i.e. for each active experiment), change location to the experiment +# directory and call the script launch_FV3LAM_wflow.sh to update the log +# file log.launch_FV3LAM_wflow. Then take the last num_log_lines of +# this log file (along with an appropriate message) and add it to the +# status report file. +# +#----------------------------------------------------------------------- +# +launch_wflow_fn="launch_FV3LAM_wflow.sh" +launch_wflow_log_fn="log.launch_FV3LAM_wflow" + +for (( i=0; i<=$((num_expts-1)); i++ )); do + + expt_subdir="${expt_subdirs[$i]}" + msg="\ +$separator +Checking workflow status of experiment \"${expt_subdir}\" ..." + print_info_msg "$msg" +# +# Change location to the experiment subdirectory, call the workflow launch +# script to update the workflow launch log file, and capture the output +# from that call. +# + cd_vrfy "${expt_subdir}" + launch_msg=$( "${launch_wflow_fn}" 2>&1 ) + log_tail=$( tail -n ${num_log_lines} "${launch_wflow_log_fn}" ) +# +# Print the workflow status to the screen. +# + # The "tail -1" is to get only the last occurrence of "Workflow status" + wflow_status=$( printf "${log_tail}" | grep "Workflow status:" | tail -1 ) + # Not sure why this doesn't work to strip leading spaces. +# wflow_status="${wflow_status## }" + # Remove leading spaces. + wflow_status=$( printf "${wflow_status}" "%s" | sed -r 's|^[ ]*||g' ) + print_info_msg "${wflow_status}" + print_info_msg "\ +$separator +" +# +# Combine message above with the last num_log_lines lines from the workflow +# launch log file and place the result in the status report file. +# + msg=$msg" +${wflow_status} + +The last ${num_log_lines} lines of this experiment's workflow launch log file +(\"${launch_wflow_log_fn}\") are: + +${log_tail} + + +" + print_info_msg "$msg" >> "${expts_status_fp}" +# +# Change location back to the experiments base directory. +# + cd_vrfy "${expts_basedir}" + +done + +print_info_msg "\ +A status report has been created in: + expts_status_fp = \"${expts_status_fp}\" + +DONE." diff --git a/tests/WE2E/machine_suites/hera.txt b/tests/WE2E/machine_suites/hera.txt new file mode 100644 index 0000000000..0887e6c58e --- /dev/null +++ b/tests/WE2E/machine_suites/hera.txt @@ -0,0 +1,9 @@ +grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2 +grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16 +grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_RAP_suite_HRRR +grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v15p2 +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_HRRR +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_RRFS_v1beta +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta +nco_grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR diff --git a/tests/WE2E/machine_suites/jet.txt b/tests/WE2E/machine_suites/jet.txt new file mode 100644 index 0000000000..0887e6c58e --- /dev/null +++ b/tests/WE2E/machine_suites/jet.txt @@ -0,0 +1,9 @@ +grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2 +grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16 +grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_RAP_suite_HRRR +grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v15p2 +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_HRRR +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_RRFS_v1beta +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR +grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta +nco_grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR diff --git a/tests/WE2E/run_WE2E_tests.sh b/tests/WE2E/run_WE2E_tests.sh new file mode 100755 index 0000000000..7333c25d36 --- /dev/null +++ b/tests/WE2E/run_WE2E_tests.sh @@ -0,0 +1,1299 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This script runs the specified WE2E tests. Type +# +# run_WE2E_tests.sh --help +# +# for a full description of how to use this script. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script or function is +# located (scrfunc_fp), the name of that file (scrfunc_fn), and the +# directory in which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( readlink -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Set the full path to the top-level directory of the UFS SRW App +# repository. We denote this path by SR_WX_APP_TOP_DIR. The current script +# should be located in the "tests/WE2E" subdirectory under this directory. +# Thus, SR_WX_APP_TOP_DIR is the directory two levels above the directory in which +# the current script is located. +# +#----------------------------------------------------------------------- +# +SR_WX_APP_TOP_DIR=${scrfunc_dir%/*/*} +# +#----------------------------------------------------------------------- +# +# Set other directories that depend on SR_WX_APP_TOP_DIR. +# +#----------------------------------------------------------------------- +# +ushdir="$SR_WX_APP_TOP_DIR/ush" +testsdir="$SR_WX_APP_TOP_DIR/tests" +WE2Edir="$testsdir/WE2E" +# +#----------------------------------------------------------------------- +# +# Source bash utility functions. +# +#----------------------------------------------------------------------- +# +. $ushdir/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Source other needed files. +# +#----------------------------------------------------------------------- +# +. ${WE2Edir}/get_WE2Etest_names_subdirs_descs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script or function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Set the usage message. +# +#----------------------------------------------------------------------- +# +usage_str="\ +Usage: + + ${scrfunc_fn} \\ + tests_file=\"...\" \\ + machine=\"...\" \\ + account=\"...\" \\ + [expt_basedir=\"...\"] \\ + [exec_subdir=\"...\"] \\ + [use_cron_to_relaunch=\"...\"] \\ + [cron_relaunch_intvl_mnts=\"...\"] \\ + [verbose=\"...\"] \\ + [generate_csv_file=\"...\"] \\ + [machine_file=\"...\"] \\ + [stmp=\"...\"] \\ + [ptmp=\"...\"] \\ + [compiler=\"...\"] \\ + [build_mod_fn=\"...\"] + +The arguments in brackets are optional. The arguments are defined as +follows: + +tests_file: +Name of file or relative or absolute path to file containing the list of +WE2E tests to run. This file must contain one test name per line, with +no repeated names. This is a required argument. + +machine: +Argument used to explicitly set the experiment variable MACHINE in the +experiment configuration files of all the WE2E tests the user wants to +run. (A description of MACHINE can be found in the default experiment +configuration file.) This is a required argument. + +account: +Argument used to explicitly set the experiment variable ACCOUNT in the +experiment configuration files of all the WE2E tests the user wants to +run. (A description of ACCOUNT can be found in the default experiment +configuration file.) This is a required argument. + +expt_basedir: +Optional argument used to explicitly set the experiment variable +EXPT_BASEDIR in the experiment configuration files of all the WE2E tests +the user wants to run. (A description of EXPT_BASEDIR can be found in +the default experiment configuration file.) If expt_basedir is specified +in the call to this script, its value is used to set EXPT_BASEDIR in the +configuration files. If it is not specified, EXPT_BASEDIR is not set in +the configuration files, in which case the workflow generation script +sets it to a default value. Note that if expt_basedir is set to a +relative path (e.g. expt_basedir=\"testset1\" in the call to this script), +then the experiment generation script will set EXPT_BASEDIR for the +experiment to a default absolute path followed by \${expt_basedir}. +This feature can be used to group the WE2E tests into subdirectories for +convenience, e.g. a set of tests under subdirectory testset1, another +set of tests under testset2, etc. + +exec_subdir: +Optional argument used to explicitly set the experiment variable +EXEC_SUBDIR in the experiment configuration files of all the WE2E tests +the user wants to run. See the default experiment configuration file +\"config_defaults.sh\" for a full description of EXEC_SUBDIR. + +use_cron_to_relaunch: +Optional argument used to explicitly set the experiment variable +USE_CRON_TO_RELAUNCH in the experiment configuration files of all the +WE2E tests the user wants to run. (A description of USE_CRON_TO_RELAUNCH +can be found in the default experiment configuration file.) If +use_cron_to_relaunch is specified in the call to this script, its value +is used to set USE_CRON_TO_RELAUNCH in the configuration files. If it +is not specified, USE_CRON_TO_RELAUNCH is set to \"TRUE\" in the +configuration files, in which case cron jobs are used to (re)launch the +workflows for all tests (one cron job per test). Thus, use_cron_to_relaunch +needs to be specified only if the user wants to turn off use of cron jobs +for all tests (by specifying use_cron_to_relaunch=\"FALSE\" on the command +line). Note that it is not possible to specify a different value for +USE_CRON_TO_RELAUNCH for each test via this argument; either all tests +use cron jobs or none do. + +cron_relaunch_intvl_mnts: +Optional argument used to explicitly set the experiment variable +CRON_RELAUNCH_INTVL_MNTS in the experiment configuration files of +all the WE2E tests the user wants to run. (A description of +CRON_RELAUNCH_INTVL_MNTS can be found in the default experiment +configuration file.) If cron_relaunch_intvl_mnts is specified in the +call to this script, its value is used to set CRON_RELAUNCH_INTVL_MNTS +in the configuration files. If it is not specified, CRON_RELAUNCH_INTVL_MNTS +is set to \"02\" (i.e. two minutes) in the configuration files. Note +that it is not possible to specify a different value for +CRON_RELAUNCH_INTVL_MNTS for each test via this argument; all tests will +use the same value for USE_CRON_TO_RELAUNCH (either the value specified +in the call to this script or the default value of \"02\"). Note also +that the value of this argument matters only if the argument +use_cron_to_relaunch is not explicitly set to \"FALSE\" in the call to +this script. + +verbose: +Optional argument used to explicitly set the experiment variable VERBOSE +in the experiment configuration files of all the WE2E tests the user +wants to run. (A description of VERBOSE can be found in the default +experiment configuration file.) If verbose is specified in the call to +this script, its value is used to set VERBOSE in the configuration files. +If it is not specified, VERBOSE is set to \"TRUE\" in the configuration +files. Note that it is not possible to specify a different value for +VERBOSE for each test via this argument; either all tests will have +VERBOSE set to \"TRUE\" or all will have it set to \"FALSE\". + +generate_csv_file: +Optional argument that specifies whether or not to generate a CSV file +containing summary information about all the tests available in the WE2E +testing system. Default value is \"TRUE\". + +machine_file: +Optional argument specifying the full path to a machine configuration +file. If not set, a supported platform machine file may be used. + +stmp: +Optional argument used to explicitly set the experiment variable STMP in +the experiment configuration files of all the WE2E tests the user wants +to run that are in NCO mode, i.e. they have test configuration files that +set the experiment variable RUN_ENVIR to \"nco\". (A description of +STMP can be found in the default experiment configuration file.) If +stmp is specified in the call to this script, its value is used to set +STMP in the configuration files of all tests that will run in NCO mode. +If it is not specified, STMP is (effectively) set as follows in the +configuration files (of all NCO mode tests to be run): + + STMP=\$( readlink -f \"\$SR_WX_APP_TOP_DIR/../nco_dirs/stmp\" \) + +Here, SR_WX_APP_TOP_DIR is the base directory in which the UFS SRW App +repository is cloned. Note that it is not possible to specify a different +value for STMP for each test via this argument; all tests will use the +same value for STMP (either the value specified in the call to this +script or the default value above). Note also that the value of this +argument is not used for any tests that are not in NCO mode. + +ptmp: +Same as the argument \"stmp\" described above but for setting the +experiment variable PTMP for all tests that will run in NCO mode. + +compiler: +Optional argument used to explicitly set the experiment variable COMPILER +in the experiment configuration files of all the WE2E tests the user +wants to run. (A description of COMPILER can be found in the default +experiment configuration file.) If compiler is specified in the call to +this script, its value is used to set COMPILER in the configuration files. +If it is not specified, COMPILER is set to \"intel\" in the configuration +files. Note that it is not possible to specify a different value for +COMPILER for each test via this argument; all tests will use the same +value for COMPILER (either the value specified in the call to this script +or the default value of \"intel\"). + +build_mod_fn: +Optional argument used to explicitly set the experiment variable +BUILD_MOD_FN in the experiment configuration files of all the WE2E tests +the user wants to run (e.g. \"build_cheyenne_gnu\"). If the string +\"gnu\" appears in this file name, the \"compiler\" option to this +function must also be specified with the value \"gnu\". + + +Usage Examples: +-------------- +Here, we give several common usage examples. In the following, assume +my_tests.txt is a text file in the same directory as this script containing +a list of test names that we want to run, e.g. + +> more my_tests.txt +new_ESGgrid +specify_DT_ATMOS_LAYOUT_XY_BLOCKSIZE + +Then: + +1) To run the tests listed in my_tests.txt on Hera and charge the core- + hours used to the \"rtrr\" account, use: + + > run_WE2E_tests.sh tests_file=\"my_tests.txt\" machine=\"hera\" account=\"rtrr\" + + This will create the experiment subdirectories for the two tests in + the directory + + \${SR_WX_APP_TOP_DIR}/../expt_dirs + + where SR_WX_APP_TOP_DIR is the directory in which the ufs-srweather-app + repository is cloned. Thus, the following two experiment directories + will be created: + + \${SR_WX_APP_TOP_DIR}/../expt_dirs/new_ESGgrid + \${SR_WX_APP_TOP_DIR}/../expt_dirs/specify_DT_ATMOS_LAYOUT_XY_BLOCKSIZE + + In addition, by default, cron jobs will be created in the user's cron + table to relaunch the workflows of these experiments every 2 minutes. + +2) To change the frequency with which the cron relaunch jobs are submitted + from the default of 2 minutes to 1 minute, use: + + > run_WE2E_tests.sh tests_file=\"my_tests.txt\" machine=\"hera\" account=\"rtrr\" cron_relaunch_intvl_mnts=\"01\" + +3) To disable use of cron (which means the worfkow for each test will + have to be relaunched manually from within each experiment directory), + use: + + > run_WE2E_tests.sh tests_file=\"my_tests.txt\" machine=\"hera\" account=\"rtrr\" use_cron_to_relaunch=\"FALSE\" + +4) To place the experiment subdirectories in a subdirectory named \"test_set_01\" + under + + \${SR_WX_APP_TOP_DIR}/../expt_dirs + + (instead of immediately under the latter), use: + + > run_WE2E_tests.sh tests_file=\"my_tests.txt\" machine=\"hera\" account=\"rtrr\" expt_basedir=\"test_set_01\" + + In this case, the full paths to the experiment directories will be: + + \${SR_WX_APP_TOP_DIR}/../expt_dirs/test_set_01/new_ESGgrid + \${SR_WX_APP_TOP_DIR}/../expt_dirs/test_set_01/specify_DT_ATMOS_LAYOUT_XY_BLOCKSIZE + +5) To use a list of tests that is located in + + /path/to/custom/my_tests.txt + + instead of in the same directory as this script, and to have the + experiment directories be placed in an arbitrary location, say + + /path/to/custom/expt_dirs + + use: + + > run_WE2E_tests.sh tests_file=\"/path/to/custom/my_tests.txt\" machine=\"hera\" account=\"rtrr\" expt_basedir=\"/path/to/custom/expt_dirs\" +" +# +#----------------------------------------------------------------------- +# +# Check to see if usage help for this script is being requested. If so, +# print it out and exit with a 0 exit code (success). +# +#----------------------------------------------------------------------- +# +help_flag="--help" +if [ "$#" -eq 1 ] && [ "$1" = "${help_flag}" ]; then + print_info_msg "${usage_str}" + exit 0 +fi +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script or function. +# Then process the arguments provided to it on the command line (which +# should consist of a set of name-value pairs of the form arg1="value1", +# arg2="value2", etc). +# +#----------------------------------------------------------------------- +# +valid_args=( \ + "tests_file" \ + "machine" \ + "account" \ + "expt_basedir" \ + "exec_subdir" \ + "use_cron_to_relaunch" \ + "cron_relaunch_intvl_mnts" \ + "verbose" \ + "generate_csv_file" \ + "machine_file" \ + "stmp" \ + "ptmp" \ + "compiler" \ + "build_mod_fn" \ + ) +process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# "TRUE". +# +#----------------------------------------------------------------------- +# +print_input_args "valid_args" +# +#----------------------------------------------------------------------- +# +# Verify that the required arguments to this script have been specified. +# If not, print out an error message and exit. +# +#----------------------------------------------------------------------- +# +help_msg="\ +Use + ${scrfunc_fn} ${help_flag} +to get help on how to use this script." + +if [ -z "${tests_file}" ]; then + print_err_msg_exit "\ +The argument \"tests_file\" specifying the file containing a list of the +WE2E tests to run was not specified in the call to this script. \ +${help_msg}" +fi + +if [ -z "${machine}" ]; then + print_err_msg_exit "\ +The argument \"machine\" specifying the machine or platform on which to +run the WE2E tests was not specified in the call to this script. \ +${help_msg}" +fi + +if [ -z "${account}" ]; then + print_err_msg_exit "\ +The argument \"account\" specifying the account under which to submit +jobs to the queue when running the WE2E tests was not specified in the +call to this script. \ +${help_msg}" +fi +# +#----------------------------------------------------------------------- +# +# Get the full path to the file containing the list of user-specified +# WE2E tests to run. Then verify that the file exists. +# +#----------------------------------------------------------------------- +# +user_spec_tests_fp=$( readlink -f "${tests_file}" ) + +if [ ! -f "${user_spec_tests_fp}" ]; then + print_err_msg_exit "\ +The file containing the user-specified list of WE2E tests to run +(tests_file) that is passed in as an argument to this script does not +exit: + tests_file = \"${tests_file}\" +The full path to this script is: + user_spec_tests_fp = \"${user_spec_tests_fp}\" +Please ensure that this file exists and rerun." +fi +# +#----------------------------------------------------------------------- +# +# Read in each line of the file specified by user_spec_tests_fp and add +# each non-empty line to the array user_spec_tests. Note that the read +# command will remove any leading and trailing whitespace from each line +# in user_spec_tests_fp [because it treats whatever character(s) the bash +# variable IFS (Internal Field Separator) is set to as word separators +# on each line, and IFS is by default set to a space, a tab, and a +# newline]. +# +#----------------------------------------------------------------------- +# +user_spec_tests=() +while read -r line; do + if [ ! -z "$line" ]; then + user_spec_tests+=("$line") + fi +done < "${user_spec_tests_fp}" +# +#----------------------------------------------------------------------- +# +# Call a function to obtain the names of all available WE2E tests (i.e. +# not just the ones the user wants to run but all that are part of the +# WE2E testing system), the test IDs, and the category subdirectory in +# which each corresponding test configuration file is located. +# +# The array of test names (avail_WE2E_test_names) that the function +# called below returns contains both primary and alternate test names. +# A primary test name is a test name obtained from the name of a WE2E +# test configuration file that is an ordinary file, i.e. not a symlink, +# whereas an alternate name is one that is derived from the name of a +# symlink whose target is an ordinary test configuration file (but not +# another symlink). To be able to determine the set of test names that +# correspond to the same primary test, the function called also returns +# an array of test IDs (avail_WE2E_test_IDs) such that the IDs for a +# primary test name and all the alternate names that map to it (if any) +# are the same. These IDs will be used later below to ensure that the +# user does not list in the set of test names to run a given test more +# than once, e.g. by accidentally including in the list its primary name +# as well as one of its alternate names. +# +# The category subdirectories in the array avail_WE2E_test_subdirs +# returned by the function called below are relative to the base +# directory under which the WE2E test configuration files are located. +# This base directory is set by the function call below and is returned +# in the output variable avail_WE2E_test_configs_basedir. The i-th +# element of avail_WE2E_test_subdirs specifies the subdirectory under +# this base directory that contains the ordinary test configuration file +# (for a primary test name) or the symlink (for an alternate test name) +# corresponding to the i-th element (which may be a primary or alternate +# test name) in avail_WE2E_test_names. We refer to these subdirectories +# as "category" subdirectories because they are used for clarity to group +# the WE2E tests into types or categories. +# +# Finally, note that the returned arrays +# +# avail_WE2E_test_names +# avail_WE2E_test_ids +# avail_WE2E_test_subdirs +# +# are sorted in order of increasing test ID and such that for a given +# set of test names that share the same ID, the primary test name is +# listed first followed by zero or more alternate names. As an example, +# assume that there are three category subdirectories under the base +# directory specified by avail_WE2E_test_configs_basedir: dir1, dir2, +# and dir3. Also, assume that dir1 contains a test configuration file +# named config.primary_name.sh that is an ordinary file, and dir2 and dir3 +# contain the following symlinks that point config.primary_name.sh: +# +# ${avail_WE2E_test_configs_basedir}/dir2/config.alt_name_1.sh +# --> ${avail_WE2E_test_configs_basedir}/dir1/config.primary_name.sh +# +# ${avail_WE2E_test_configs_basedir}/dir3/config.alt_name_2.sh +# --> ${avail_WE2E_test_configs_basedir}/dir1/config.primary_name.sh +# +# Finally, assume that the ID of the test primary_name is 21 and that +# this ID is at indices 7, 8, and 9 in avail_WE2E_test_ids. Then indices +# 7, 8, and 9 of the three arrays returned by the function call below +# may be as follows: +# +# avail_WE2E_test_names[7]="primary_name" +# avail_WE2E_test_names[8]="alt_name_1" +# avail_WE2E_test_names[9]="alt_name_2" +# +# avail_WE2E_test_ids[7]="21" +# avail_WE2E_test_ids[8]="21" +# avail_WE2E_test_ids[9]="21" +# +# avail_WE2E_test_subdirs[7]="dir1" +# avail_WE2E_test_subdirs[8]="dir2" +# avail_WE2E_test_subdirs[9]="dir3" +# +#----------------------------------------------------------------------- +# +print_info_msg " +Getting information about all available WE2E tests..." + +get_WE2Etest_names_subdirs_descs \ + WE2Edir="${WE2Edir}" \ + generate_csv_file="${generate_csv_file}" \ + outvarname_test_configs_basedir="avail_WE2E_test_configs_basedir" \ + outvarname_test_names="avail_WE2E_test_names" \ + outvarname_test_subdirs="avail_WE2E_test_subdirs" \ + outvarname_test_ids="avail_WE2E_test_ids" +# +# Get the total number of available WE2E test names (including alternate +# names). +# +num_avail_WE2E_tests="${#avail_WE2E_test_names[@]}" +# +#----------------------------------------------------------------------- +# +# Loop through the elements of the array user_spec_tests and perform +# sanity checks. For each such element (i.e. for each WE2E test to run +# specified by the user), make sure that: +# +# 1) The name of the test exists in the complete list of available WE2E +# tests in avail_WE2E_test_names. +# 2) The test does not have an ID that is identical to a previously +# considered test in the user-specified list of tests to run (because +# if so, it would be identical to that previously considered test, +# and it would be a waste of computational resources to run). +# +# If these requirements are met, add the test name to the list of tests +# to run in the array names_tests_to_run, and add the test's category +# subdirectory to subdirs_tests_to_run. +# +#----------------------------------------------------------------------- +# +print_info_msg " +Performing sanity checks on user-specified list of WE2E tests to run..." + +names_tests_to_run=() +ids_tests_to_run=() +subdirs_tests_to_run=() +# +# Initialize the array that will contain the remaining available WE2E +# test names (including alternate names, if any) after finding a match +# for the i-th user-specified test name to run in user_spec_tests. +# +remaining_avail_WE2E_test_names=( "${avail_WE2E_test_names[@]}" ) + +num_user_spec_tests="${#user_spec_tests[@]}" +for (( i=0; i<=$((num_user_spec_tests-1)); i++ )); do + + user_spec_test="${user_spec_tests[$i]}" + + print_info_msg "\ + Checking user-specified WE2E test: \"${user_spec_test}\"" +# +# For the current user-specified WE2E test (user_spec_test), loop through +# the list of all remaining available WE2E test names (i.e. the ones that +# haven't yet been matched to any of the user-specified test names to +# run) and make sure that: +# +# 1) The name of the test exists (either as a primary test name or an +# alternate test name) in the list of all available WE2E test names. +# 2) The test is not repeated in the user-specified list of tests to run, +# either under the same name or an alternate name (i.e. make sure that +# it does not have the same test ID as a previously considered test). +# +# Note that in the loop below, the index j gets set to only those elements +# of remaining_avail_WE2E_test_names that are defined [the syntax +# "${!some_array[@]}" expands to the indices of some_array that have +# defined elements]. We do this for efficiency; we unset elements of +# remaining_avail_WE2E_test_names that have already been matched with +# one of the user-specified test names to run because we know that any +# remaining user-specified test names will not match those elements. +# + match_found="FALSE" + for j in "${!remaining_avail_WE2E_test_names[@]}"; do + + test_name="${avail_WE2E_test_names[$j]}" + test_id="${avail_WE2E_test_ids[$j]}" +# +# Check whether the name of the current user-specified test (user_spec_test) +# matches any of the names in the full list of WE2E tests. If so: +# +# 1) Set match_found to "TRUE". +# 2) Make sure that the test to run doesn't have a test ID that is +# identical to a previously considered test in the user-specified +# list of tests to run (which would mean the two tests are identical). +# If so, print out an error message and exit. +# + if [ "${test_name}" = "${user_spec_test}" ]; then + + match_found="TRUE" + + is_element_of "ids_tests_to_run" "${test_id}" && { + + user_spec_tests_str=$(printf " \"%s\"\n" "${user_spec_tests[@]}") + user_spec_tests_str=$(printf "(\n%s\n )" "${user_spec_tests_str}") + + all_names_for_test=() + for (( k=0; k<=$((num_avail_WE2E_tests-1)); k++ )); do + if [ "${avail_WE2E_test_ids[$k]}" = "${test_id}" ]; then + all_names_for_test+=("${avail_WE2E_test_names[$k]}") + fi + done + all_names_for_test_str=$(printf " \"%s\"\n" "${all_names_for_test[@]}") + + print_err_msg_exit "\ +The current user-specified test to run (user_spec_test) is already included +in the list of tests to run (user_spec_tests), either under the same name +or an alternate name: + user_spec_test = \"${user_spec_test}\" + user_spec_tests = ${user_spec_tests_str} +This test has the following primary and possible alternate names: +${all_names_for_test_str} +In order to avoid repeating the same WE2E test (and thus waste computational +resources), only one of these test names can be specified in the list of +tests to run. Please modify this list in the file + user_spec_tests_fp = \"${user_spec_tests_fp}\" +accordingly and rerun." + + } +# +# Append the name of the current user-specified test, its ID, and its +# category subdirectory to the arrays that contain the sanity-checked +# versions of of these quantities. +# + names_tests_to_run+=("${user_spec_test}") + ids_tests_to_run+=("${test_id}") + subdirs_tests_to_run+=("${avail_WE2E_test_subdirs[$j]}") +# +# Remove the j-th element of remaining_avail_WE2E_test_names so that for +# the next user-specified test to run, we do not need to check whether +# the j-th test is a match. Then break out of the loop over all remaining +# available WE2E tests. +# + unset remaining_avail_WE2E_test_names[$j] + break + + fi + + done +# +# If match_found is still "FALSE" after exiting the loop above, then a +# match for the current user-specifed test to run was not found in the +# list of all WE2E tests -- neither as a primary test name nor as an +# alternate name. In this case, print out an error message and exit. +# + if [ "${match_found}" = "FALSE" ]; then + avail_WE2E_test_names_str=$( printf " \"%s\"\n" "${avail_WE2E_test_names[@]}" ) + print_err_msg_exit "\ +The name of the current user-specified test to run (user_spec_test) does +not match any of the names (either primary or alternate) of the available +WE2E tests: + user_spec_test = \"${user_spec_test}\" +Valid values for user_spec_test consist of the names (primary or alternate) +of the available WE2E tests, which are: +${avail_WE2E_test_names_str} +Each name in the user-specified list of tests to run: + 1) Must match one of the (primary or alternate) test names of the + availabe WE2E tests. + 2) Must not be the primary or alternate name of a test that has its + primary or one of its alternate names already included in the user- + specified list of test to run, i.e. tests must not be repeated (in + order not to waste computational resources). +Please modify the user-specified list of tests to run such that it adheres +to the rules above and rerun. This list is in the file specified by the +input variable tests_file: + tests_file = \"${tests_file}\" +The full path to this file is: + user_spec_tests_fp = \"${user_spec_tests_fp}\"" + fi + +done +# +#----------------------------------------------------------------------- +# +# Get the number of WE2E tests to run and print out an informational +# message. +# +#----------------------------------------------------------------------- +# +num_tests_to_run="${#names_tests_to_run[@]}" +tests_to_run_str=$( printf " \'%s\'\n" "${names_tests_to_run[@]}" ) +print_info_msg " +After processing the user-specified list of WE2E tests to run, the number +of tests to run (num_tests_to_run) is + num_tests_to_run = ${num_tests_to_run} +and the list of WE2E tests to run (one test per line) is +${tests_to_run_str}" +# +#----------------------------------------------------------------------- +# +# Loop through the WE2E tests to run. For each test, use the corresponding +# test configuration file to generate a temporary experiment file and +# launch the experiment generation script using that file. +# +#----------------------------------------------------------------------- +# +for (( i=0; i<=$((num_tests_to_run-1)); i++ )); do + + test_name="${names_tests_to_run[$i]}" + test_subdir="${subdirs_tests_to_run[$i]}" +# +# Generate the full path to the current WE2E test's configuration file. +# Then ensure that this file exists. +# + test_config_fp="${avail_WE2E_test_configs_basedir}/${test_subdir}/config.${test_name}.sh" + + if [ ! -f "${test_config_fp}" ]; then + print_err_msg_exit "\ +The experiment configuration file (test_config_fp) for the current WE2E +test (test_name) does not exist: + test_name = \"${test_name}\" + test_config_fp = \"${test_config_fp}\" +Please correct and rerun." + fi +# +#----------------------------------------------------------------------- +# +# Source the default experiment configuration file to set values of +# various experiment variables to their defaults. Then source the +# current WE2E test's configuration file to overwrite certain variables' +# default values with test-specific ones. +# +#----------------------------------------------------------------------- +# + . ${ushdir}/config_defaults.sh + . ${test_config_fp} +# +#----------------------------------------------------------------------- +# +# We will now construct a multiline variable consisting of the contents +# that we want the experiment configuration file for this WE2E test to +# have. Once this variable is constructed, we will write its contents +# to the generic configuration file that the experiment generation script +# reads in (specified by the variable EXPT_CONFIG_FN in the default +# configuration file config_defaults.sh sourced above) and then run that +# script to generate an experiment for the current WE2E test. +# +# We name the multiline variable that will contain the contents of the +# experiment configuration file "expt_config_str" (short for "experiment +# configuration string"). Here, we initialize this to a null string, +# and we append to it later below. +# +#----------------------------------------------------------------------- +# + expt_config_str="" +# +#----------------------------------------------------------------------- +# +# Set (and then write to expt_config_str) various experiment variables +# that depend on the input arguments to this script (as opposed to +# variable settings in the test configuration file specified by +# test_config_fp). Note that any values of these parameters specified +# in the default experiment configuration file (config_defaults.sh) +# or in the test configuraiton file (test_config_fp) that were sourced +# above will be overwritten by the settings below. +# +# Note also that if EXPT_BASEDIR ends up getting set to a null string, +# the experiment generation script that gets called further below will +# set it to a default path; if it gets set to a relative path, then the +# experiment generation script will set it to a path consisting of a +# default path with the relative path appended to it; and if it gets set +# to an absolute path, then the workflow will leave it set to that path. +# +#----------------------------------------------------------------------- +# + MACHINE="${machine^^}" + ACCOUNT="${account}" + COMPILER=${compiler:-"intel"} + BUILD_MOD_FN=${build_mod_fn:-"build_${machine}_${COMPILER}"} + EXPT_BASEDIR="${expt_basedir}" + EXPT_SUBDIR="${test_name}" + EXEC_SUBDIR="${exec_subdir}" + USE_CRON_TO_RELAUNCH=${use_cron_to_relaunch:-"TRUE"} + CRON_RELAUNCH_INTVL_MNTS=${cron_relaunch_intvl_mnts:-"02"} + VERBOSE=${verbose:-"TRUE"} + + MACHINE_FILE=${machine_file:-"${ushdir}/machine/${machine,,}.sh"} + + # Set the machine-specific configuration settings by sourcing the + # machine file in the ush directory + + source $ushdir/source_machine_file.sh + + expt_config_str=${expt_config_str}"\ +# +# The machine on which to run, the account to which to charge computational +# resources, the base directory in which to create the experiment directory +# (if different from the default location), and the name of the experiment +# subdirectory. +# +MACHINE=\"${MACHINE}\" +ACCOUNT=\"${ACCOUNT}\" + +COMPILER=\"${COMPILER}\" +BUILD_MOD_FN=\"${BUILD_MOD_FN}\"" + + if [ -n "${EXEC_SUBDIR}" ]; then + expt_config_str=${expt_config_str}" +EXEC_SUBDIR=\"${EXEC_SUBDIR}\"" + fi + + if [ -n "${EXPT_BASEDIR}" ]; then + expt_config_str=${expt_config_str}" +EXPT_BASEDIR=\"${EXPT_BASEDIR}\"" + fi + + expt_config_str=${expt_config_str}" +EXPT_SUBDIR=\"${EXPT_SUBDIR}\" +# +# Flag specifying whether or not to automatically resubmit the worfklow +# to the batch system via cron and, if so, the frequency (in minutes) of +# resubmission. +# +USE_CRON_TO_RELAUNCH=\"${USE_CRON_TO_RELAUNCH}\" +CRON_RELAUNCH_INTVL_MNTS=\"${CRON_RELAUNCH_INTVL_MNTS}\" +# +# Path to machine configuration file. +# +MACHINE_FILE=\"${MACHINE_FILE}\" +# +# Flag specifying whether to run in verbose mode. +# +VERBOSE=\"${VERBOSE}\"" +# +#----------------------------------------------------------------------- +# +# Append the contents of the current WE2E test's configuration file to +# the experiment configuration string. +# +#----------------------------------------------------------------------- +# + expt_config_str=${expt_config_str}" +# +#----------------------------------------------------------------------- +#----------------------------------------------------------------------- +# The following section is a copy of this WE2E test's configuration file. +# +" + expt_config_str=${expt_config_str}$( cat "${test_config_fp}" ) + expt_config_str=${expt_config_str}" +# +# End of section from this test's configuration file. +#----------------------------------------------------------------------- +#-----------------------------------------------------------------------" +# +#----------------------------------------------------------------------- +# +# Modifications to the experiment configuration file if the WE2E test +# uses pre-generated grid, orography, or surface climatology files. +# +# If not running one or more of the grid, orography, and surface +# climatology file generation tasks, specify directories in which +# pregenerated versions of these files can be found. +# +#----------------------------------------------------------------------- +# + if [ "${RUN_TASK_MAKE_GRID}" = "FALSE" ] || \ + [ "${RUN_TASK_MAKE_OROG}" = "FALSE" ] || \ + [ "${RUN_TASK_MAKE_SFC_CLIMO}" = "FALSE" ]; then + + pregen_basedir=${TEST_PREGEN_BASEDIR:-} + + if [ ! -d "${pregen_basedir:-}" ] ; then + print_err_msg_exit "\ +The base directory (pregen_basedir) in which the pregenerated grid, +orography, and/or surface climatology files are located has not been +specified for this machine (MACHINE): + MACHINE= \"${MACHINE}\"" + fi + + pregen_dir="${pregen_basedir}/${PREDEF_GRID_NAME}" + + fi +# +# Directory for pregenerated grid files. +# + if [ "${RUN_TASK_MAKE_GRID}" = "FALSE" ]; then + GRID_DIR="${pregen_dir}" + expt_config_str=${expt_config_str}" +# +# Directory containing the pregenerated grid files. +# +GRID_DIR=\"${GRID_DIR}\"" + fi +# +# Directory for pregenerated orography files. +# + if [ "${RUN_TASK_MAKE_OROG}" = "FALSE" ]; then + OROG_DIR="${pregen_dir}" + expt_config_str=${expt_config_str}" +# +# Directory containing the pregenerated orography files. +# +OROG_DIR=\"${OROG_DIR}\"" + fi +# +# Directory for pregenerated surface climatology files. +# + if [ "${RUN_TASK_MAKE_SFC_CLIMO}" = "FALSE" ]; then + SFC_CLIMO_DIR="${pregen_dir}" + expt_config_str=${expt_config_str}" +# +# Directory containing the pregenerated surface climatology files. +# +SFC_CLIMO_DIR=\"${SFC_CLIMO_DIR}\"" + fi +# +#----------------------------------------------------------------------- +# +# Modifications to the experiment configuration file if running the WE2E +# test in NCO mode. +# +#----------------------------------------------------------------------- +# + if [ "${RUN_ENVIR}" = "nco" ]; then +# +# Set RUN and envir. +# + expt_config_str=${expt_config_str}" +# +# In order to prevent simultaneous WE2E (Workflow End-to-End) tests that +# are running in NCO mode and which run the same cycles from interfering +# with each other, for each cycle, each such test must have a distinct +# path to the following two directories: +# +# 1) The directory in which the cycle-dependent model input files, symlinks +# to cycle-independent input files, and raw (i.e. before post-processing) +# forecast output files for a given cycle are stored. The path to this +# directory is +# +# \$STMP/tmpnwprd/\$RUN/\$cdate +# +# where cdate is the starting year (yyyy), month (mm), day (dd) and +# hour of the cycle in the form yyyymmddhh. +# +# 2) The directory in which the output files from the post-processor (UPP) +# for a given cycle are stored. The path to this directory is +# +# \$PTMP/com/\$NET/\$model_ver/\$RUN.\$yyyymmdd/\$hh +# +# Here, we make the first directory listed above unique to a WE2E test +# by setting RUN to the name of the current test. This will also make +# the second directory unique because it also conains the variable RUN +# in its full path, but if this directory -- or set of directories since +# it involves a set of cycles and forecast hours -- already exists from +# a previous run of the same test, then it is much less confusing to the +# user to first move or delete this set of directories during the workflow +# generation step and then start the experiment (whether we move or delete +# depends on the setting of PREEXISTING_DIR_METHOD). For this purpose, +# it is most convenient to put this set of directories under an umbrella +# directory that has the same name as the experiment. This can be done +# by setting the variable envir to the name of the current test. Since +# as mentiond above we will store this name in RUN, below we simply set +# envir to the same value as RUN (which is just EXPT_SUBDIR). Then, for +# this test, the UPP output will be located in the directory +# +# \$PTMP/com/\$NET/\we2e/\$RUN.\$yyyymmdd/\$hh +# +RUN=\"\${EXPT_SUBDIR}\" +model_ver="we2e"" + +# +# Set COMIN. + + COMIN=${TEST_COMIN:-} + + if [ ! -d "${COMIN:-}" ] ; then + print_err_msg_exit "\ +The directory (COMIN) that needs to be specified when running the +workflow in NCO mode (RUN_ENVIR set to \"nco\") AND using the FV3GFS or +the GSMGFS as the external model for ICs and/or LBCs has not been specified +for this machine (MACHINE): + MACHINE= \"${MACHINE}\"" + fi + + expt_config_str=${expt_config_str}" +# +# Directory that needs to be specified when running the workflow in NCO +# mode (RUN_ENVIR set to \"nco\"). +# +COMIN=\"${COMIN}\"" + +# +# Set STMP and PTMP. +# + nco_basedir=$( readlink -f "$SR_WX_APP_TOP_DIR/../nco_dirs" ) + STMP=${stmp:-"${nco_basedir}/stmp"} + PTMP=${ptmp:-"${nco_basedir}/ptmp"} + + expt_config_str=${expt_config_str}" +# +# Directories STMP and PTMP that need to be specified when running the +# workflow in NCO-mode (i.e. RUN_ENVIR set to "nco"). +# +STMP=\"${STMP}\" +PTMP=\"${PTMP}\"" + + fi +# +#----------------------------------------------------------------------- +# +# Modifications to the experiment configuration file if the WE2E test +# uses user-staged external model files. +# +#----------------------------------------------------------------------- +# + if [ "${USE_USER_STAGED_EXTRN_FILES}" = "TRUE" ]; then + + # Ensure we only check on disk for these files + data_stores="disk" + + extrn_mdl_source_basedir=${TEST_EXTRN_MDL_SOURCE_BASEDIR:-} + if [ ! -d "${extrn_mdl_source_basedir:-}" ] ; then + print_err_msg_exit "\ +The base directory (extrn_mdl_source_basedir) in which the user-staged +external model files should be located has not been specified for this +machine (MACHINE): + MACHINE= \"${MACHINE}\"" + fi + EXTRN_MDL_SOURCE_BASEDIR_ICS="${extrn_mdl_source_basedir}/${EXTRN_MDL_NAME_ICS}" + if [ "${EXTRN_MDL_NAME_ICS}" = "FV3GFS" ] ; then + EXTRN_MDL_SOURCE_BASEDIR_ICS="${EXTRN_MDL_SOURCE_BASEDIR_ICS}/${FV3GFS_FILE_FMT_ICS}/\${yyyymmddhh}" + else + EXTRN_MDL_SOURCE_BASEDIR_ICS="${EXTRN_MDL_SOURCE_BASEDIR_ICS}/\${yyyymmddhh}" + fi + + EXTRN_MDL_SOURCE_BASEDIR_LBCS="${extrn_mdl_source_basedir}/${EXTRN_MDL_NAME_LBCS}" + if [ "${EXTRN_MDL_NAME_LBCS}" = "FV3GFS" ] ; then + EXTRN_MDL_SOURCE_BASEDIR_LBCS="${EXTRN_MDL_SOURCE_BASEDIR_LBCS}/${FV3GFS_FILE_FMT_LBCS}/\${yyyymmddhh}" + else + EXTRN_MDL_SOURCE_BASEDIR_LBCS="${EXTRN_MDL_SOURCE_BASEDIR_LBCS}/\${yyyymmddhh}" + fi +# +# Make sure that the forecast length is evenly divisible by the interval +# between the times at which the lateral boundary conditions will be +# specified. +# + rem=$(( 10#${FCST_LEN_HRS} % 10#${LBC_SPEC_INTVL_HRS} )) + if [ "$rem" -ne "0" ]; then + print_err_msg_exit "\ +The forecast length (FCST_LEN_HRS) must be evenly divisible by the lateral +boundary conditions specification interval (LBC_SPEC_INTVL_HRS): + FCST_LEN_HRS = ${FCST_LEN_HRS} + LBC_SPEC_INTVL_HRS = ${LBC_SPEC_INTVL_HRS} + rem = FCST_LEN_HRS%%LBC_SPEC_INTVL_HRS = $rem" + fi + expt_config_str="${expt_config_str} +# +# Locations and names of user-staged external model files for generating +# ICs and LBCs. +# +EXTRN_MDL_SOURCE_BASEDIR_ICS='${EXTRN_MDL_SOURCE_BASEDIR_ICS}' +EXTRN_MDL_FILES_ICS=( ${EXTRN_MDL_FILES_ICS[@]} ) +EXTRN_MDL_SOURCE_BASEDIR_LBCS='${EXTRN_MDL_SOURCE_BASEDIR_LBCS}' +EXTRN_MDL_FILES_LBCS=( ${EXTRN_MDL_FILES_LBCS[@]} ) +EXTRN_MDL_DATA_STORES=\"$data_stores\"" + + fi +# +#----------------------------------------------------------------------- +# +# Check that MET directories have been set appropriately, if needed. +# +#----------------------------------------------------------------------- +# + if [ "${RUN_TASK_VX_GRIDSTAT}" = "TRUE" ] || \ + [ "${RUN_TASK_VX_POINTSTAT}" = "TRUE" ] || \ + [ "${RUN_TASK_VX_ENSGRID}" = "TRUE" ] || \ + [ "${RUN_TASK_VX_ENSPOINT}" = "TRUE" ]; then + + check=0 + if [ ! -d ${MET_INSTALL_DIR} ] ; then + print_info_msg "\ + The MET installation location must be set for this machine! + MET_INSTALL_DIR = \"${MET_INSTALL_DIR}\"" + check=1 + fi + + if [ ! -d ${METPLUS_PATH} ] ; then + print_info_msg "\ + The MET+ installation location must be set for this machine! + METPLUS_PATH = \"${METPLUS_PATH}\"" + check=1 + fi + + if [ -z ${MET_BIN_EXEC} ] ; then + print_info_msg "\ + The MET execution command must be set for this machine! + MET_BIN_EXEC = \"${MET_BIN_EXEC}\"" + check=1 + fi + + if [ ! -d ${CCPA_OBS_DIR} ] ; then + print_info_msg "\ + The CCPA observation location must be set for this machine! + CCPA_OBS_DIR = \"${CCPA_OBS_DIR}\"" + check=1 + fi + + if [ ! -d ${MRMS_OBS_DIR} ] ; then + print_info_msg "\ + The MRMS observation location must be set for this machine! + MRMS_OBS_DIR = \"${MRMS_OBS_DIR}\"" + check=1 + fi + + if [ ! -d ${NDAS_OBS_DIR} ] ; then + print_info_msg "\ + The NDAS observation location must be set for this machine! + NDAS_OBS_DIR = \"${NDAS_OBS_DIR}\"" + check=1 + fi + + if [ ${check} = 1 ] ; then + print_err_msg_exit "\ + Please set MET variables in the machine file for \ + MACHINE = \"${MACHINE}\"" + fi + + fi +# +#----------------------------------------------------------------------- +# +# On some machines (e.g. cheyenne), some tasks often require multiple +# tries before they succeed. To make it more convenient to run the WE2E +# tests on these machines without manual intervention, change the number +# of attempts for such tasks on those machines to be more than one. +# +#----------------------------------------------------------------------- +# + add_maxtries="FALSE" + + if [ "$MACHINE" = "HERA" ]; then + add_maxtries="TRUE" + MAXTRIES_MAKE_ICS="2" + MAXTRIES_MAKE_LBCS="2" + MAXTRIES_RUN_POST="2" + elif [ "$MACHINE" = "CHEYENNE" ]; then + add_maxtries="TRUE" + MAXTRIES_MAKE_SFC_CLIMO="3" + MAXTRIES_MAKE_ICS="5" + MAXTRIES_MAKE_LBCS="10" + MAXTRIES_RUN_POST="10" + fi + + if [ "${add_maxtries}" = "TRUE" ]; then + + expt_config_str=${expt_config_str}" +# +# Maximum number of attempts at running each task. +# +MAXTRIES_MAKE_GRID=\"${MAXTRIES_MAKE_GRID}\" +MAXTRIES_MAKE_OROG=\"${MAXTRIES_MAKE_OROG}\" +MAXTRIES_MAKE_SFC_CLIMO=\"${MAXTRIES_MAKE_SFC_CLIMO}\" +MAXTRIES_GET_EXTRN_ICS=\"${MAXTRIES_GET_EXTRN_ICS}\" +MAXTRIES_GET_EXTRN_LBCS=\"${MAXTRIES_GET_EXTRN_LBCS}\" +MAXTRIES_MAKE_ICS=\"${MAXTRIES_MAKE_ICS}\" +MAXTRIES_MAKE_LBCS=\"${MAXTRIES_MAKE_LBCS}\" +MAXTRIES_RUN_FCST=\"${MAXTRIES_RUN_FCST}\" +MAXTRIES_RUN_POST=\"${MAXTRIES_RUN_POST}\"" + + fi +# +#----------------------------------------------------------------------- +# +# Set the full path to the configuration file that the experiment +# generation script reads in. Then write the contents of expt_config_str +# to that file. +# +#----------------------------------------------------------------------- +# + expt_config_fp="$ushdir/${EXPT_CONFIG_FN}" + printf "%s" "${expt_config_str}" > "${expt_config_fp}" +# +#----------------------------------------------------------------------- +# +# The following are changes that need to be made directly to the +# experiment configuration file created above (as opposed to the +# experiment configuration string expt_config_str) because they involve +# resetting of values that have already been set in the experiment +# configuration file. +# +# If EXTRN_MDL_SYSBASEDIR_ICS has been specified in the current WE2E +# test's base configuration file, it must be set to one of the following: +# +# 1) The string "set_to_non_default_location_in_testing_script" in order +# to allow this script to set it to a valid location depending on the +# machine and external model (for ICs). +# +# 2) To an existing directory. If it is set to a directory, then this +# script ensures that the directory exists (via the check below). +# +#----------------------------------------------------------------------- +# + if [ -n "${EXTRN_MDL_SYSBASEDIR_ICS}" ]; then + + if [ "${EXTRN_MDL_SYSBASEDIR_ICS}" = "set_to_non_default_location_in_testing_script" ]; then + + EXTRN_MDL_SYSBASEDIR_ICS="${TEST_ALT_EXTRN_MDL_SYSBASEDIR_ICS:-}" + + if [ -z "${EXTRN_MDL_SYSBASEDIR_ICS}" ]; then + print_err_msg_exit "\ +A non-default location for EXTRN_MDL_SYSBASEDIR_ICS for testing purposes +has not been specified for this machine (MACHINE) and external model for +initial conditions (EXTRN_MDL_NAME_ICS) combination: + MACHINE= \"${MACHINE}\" + EXTRN_MDL_NAME_ICS = \"${EXTRN_MDL_NAME_ICS}\"" + fi + + # Maintain any templates in EXTRN_MDL_SYSBASEDIR_ICS -- don't use + # quotes. + set_bash_param "${expt_config_fp}" \ + "EXTRN_MDL_SYSBASEDIR_ICS" ${EXTRN_MDL_SYSBASEDIR_ICS} + + fi + + # Check the base directory for the specified location. + if [ ! -d "$(dirname ${EXTRN_MDL_SYSBASEDIR_ICS%%\$*})" ]; then + print_err_msg_exit "\ +The non-default location specified by EXTRN_MDL_SYSBASEDIR_ICS does not +exist or is not a directory: + EXTRN_MDL_NAME_ICS = \"${EXTRN_MDL_NAME_ICS}\"" + fi + + + fi +# +#----------------------------------------------------------------------- +# +# Same as above but for EXTRN_MDL_SYSBASEDIR_LBCS. +# +#----------------------------------------------------------------------- +# + if [ -n "${EXTRN_MDL_SYSBASEDIR_LBCS}" ]; then + + if [ "${EXTRN_MDL_SYSBASEDIR_LBCS}" = "set_to_non_default_location_in_testing_script" ]; then + + EXTRN_MDL_SYSBASEDIR_LBCS="${TEST_ALT_EXTRN_MDL_SYSBASEDIR_LBCS:-}" + + if [ -z "${EXTRN_MDL_SYSBASEDIR_LBCS}" ]; then + print_err_msg_exit "\ +A non-default location for EXTRN_MDL_SYSBASEDIR_LBCS for testing purposes +has not been specified for this machine (MACHINE) and external model for +initial conditions (EXTRN_MDL_NAME_LBCS) combination: + MACHINE= \"${MACHINE}\" + EXTRN_MDL_NAME_LBCS = \"${EXTRN_MDL_NAME_LBCS}\"" + fi + + # Maintain any templates in EXTRN_MDL_SYSBASEDIR_ICS -- don't use + # quotes. + set_bash_param "${expt_config_fp}" \ + "EXTRN_MDL_SYSBASEDIR_LBCS" ${EXTRN_MDL_SYSBASEDIR_LBCS} + + fi + + # Check the base directory for the specified location. + if [ ! -d "$(dirname ${EXTRN_MDL_SYSBASEDIR_LBCS%%\$*})" ]; then + print_err_msg_exit "\ +The non-default location specified by EXTRN_MDL_SYSBASEDIR_LBCS does not +exist or is not a directory: + EXTRN_MDL_NAME_LBCS = \"${EXTRN_MDL_NAME_LBCS}\"" + fi + + + fi +# +#----------------------------------------------------------------------- +# +# Call the experiment generation script to generate an experiment +# directory and a rocoto workflow XML for the current WE2E test to run. +# +#----------------------------------------------------------------------- +# + $ushdir/generate_FV3LAM_wflow.py || \ + print_err_msg_exit "\ +Could not generate an experiment for the test specified by test_name: + test_name = \"${test_name}\"" + +done +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script or +# function. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + diff --git a/tests/WE2E/setup_WE2E_tests.sh b/tests/WE2E/setup_WE2E_tests.sh new file mode 100755 index 0000000000..5b084c2fc6 --- /dev/null +++ b/tests/WE2E/setup_WE2E_tests.sh @@ -0,0 +1,95 @@ +#!/bin/bash -l + +#---------------------------------------------------------------------- +# Wrapper for the automation of UFS Short Range Weather App Workflow +# End to End Tests. +# +# The wrapper loads the appropriate workflow environment for the +# machine, and sets the machine test suite file before invoking the +# run_WE2E_tests.sh. +# +# The script is dependent on a successful build of this repo using the +# test/build.sh script in the ufs-srweather-app repository. The UFS +# build must be completed in a particular manner for this script to +# function properly, notably the location of the build and bin +# directories: +# BUILD_DIR=${APP_DIR}/build_${compiler} +# BIN_DIR=${APP_DIR}/bin_${compiler} +# +# Example: ./end_to_end_tests.sh hera zrtrr +#---------------------------------------------------------------------- + +#----------------------------------------------------------------------- +# Set variables +#----------------------------------------------------------------------- + +function usage { + echo + echo "Usage: $0 machine slurm_account | -h" + echo + echo " machine [required] is one of: ${machines[@]}" + echo " slurm_account [required] case sensitive name of the user-specific slurm account" + echo " -h display this help" + echo + exit 1 + +} + +machines=( hera jet ) + +if [ "$1" = "-h" ] ; then usage ; fi +[[ $# -le 1 ]] && usage + +machine=$1 +machine=$(echo "${machine}" | tr '[A-Z]' '[a-z]') # scripts in sorc need lower case machine name + +account=$2 + +#----------------------------------------------------------------------- +# Set directories +#----------------------------------------------------------------------- +scrfunc_fp=$( readlink -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) + +TESTS_DIR=$( dirname "${scrfunc_dir}" ) +REGIONAL_WORKFLOW_DIR=$( dirname "${TESTS_DIR}" ) +SRW_APP_DIR=$( dirname "${REGIONAL_WORKFLOW_DIR}" ) +TOP_DIR=$( dirname "${SRW_APP_DIR}" ) + +EXPTS_DIR=${TOP_DIR}/expt_dirs + +#----------------------------------------------------------------------- +# Set the path to the machine-specific test suite file. +#----------------------------------------------------------------------- + +auto_file=${scrfunc_dir}/machine_suites/${machine}.txt + +#---------------------------------------------------------------------- +# Use exec_subdir consistent with the automated build. +#---------------------------------------------------------------------- + +exec_subdir='bin_intel/bin' + +#----------------------------------------------------------------------- +# Run E2E Tests +#----------------------------------------------------------------------- + +# Load Python Modules +env_path="${SRW_APP_DIR}/modulefiles" +env_file="wflow_${machine}" +echo "-- Load environment =>" $env_file +source ${SRW_APP_DIR}/etc/lmod-setup.sh ${machine} +module use ${env_path} +module load ${env_file} +conda activate regional_workflow + +module list + +# Run the E2E Workflow tests +./run_WE2E_tests.sh \ + tests_file=${auto_file} \ + machine=${machine} \ + account=${account} \ + exec_subdir=${exec_subdir} + diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_CONUS_25km_GFDLgrid_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_CONUS_25km_GFDLgrid_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..34a61a6adf --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_CONUS_25km_GFDLgrid_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,26 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the CONUS_25km_GFDLgrid grid (which is a +# GFDLgrid type of grid) using the GFS_v16 suite with ICs and LBCs +# derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="CONUS_25km_GFDLgrid" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_CONUS_3km_GFDLgrid_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_CONUS_3km_GFDLgrid_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..a081731e50 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_CONUS_3km_GFDLgrid_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,26 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the CONUS_3km_GFDLgrid grid (which is a +# GFDLgrid type of grid) using the GFS_v16 suite with ICs and LBCs +# derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="CONUS_3km_GFDLgrid" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_AK_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_AK_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..7a059e4ffd --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_AK_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_AK_13km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_AK_13km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_AK_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_AK_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..d9d1151b0b --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_AK_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_AK_3km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_AK_3km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh new file mode 100644 index 0000000000..7c6564a30f --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_13km grid using the GFS_v15p2 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_13km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..de780b806c --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_13km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_13km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh new file mode 100644 index 0000000000..f85ed71e1f --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_13km grid using the HRRR +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_13km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..b759b00528 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_13km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_13km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_2017_gfdlmp.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_2017_gfdlmp.sh new file mode 100644 index 0000000000..2f7d6ecccf --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_2017_gfdlmp.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_2017_gfdlmp +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_2017_gfdlmp_regional.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_2017_gfdlmp_regional.sh new file mode 100644 index 0000000000..b21cfbe2cd --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_2017_gfdlmp_regional.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_2017_gfdlmp_regional +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp_regional" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh new file mode 100644 index 0000000000..5a36d59886 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_v15p2 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..3c6841ddf0 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh new file mode 100644 index 0000000000..d8da153c16 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the HRRR +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..2b342d9eef --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_RAP_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_RAP_suite_HRRR.sh new file mode 100644 index 0000000000..1465641a59 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_RAP_suite_HRRR.sh @@ -0,0 +1,32 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the HRRR +# physics suite with ICs derived from the FV3GFS and LBCs derived from +# the RAP. +# +# Note that this test specifies the file format of the FV3GFS external +# model data (from which to generate ICs) to be "grib2" as opposed to +# the default value of "nemsio". +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="1" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_2017_gfdlmp.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_2017_gfdlmp.sh new file mode 100644 index 0000000000..7e5b304acc --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_2017_gfdlmp.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_2017_gfdlmp +# physics suite with ICs and LBCs derived from the GSMGFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="GSMGFS" +EXTRN_MDL_NAME_LBCS="GSMGFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190520" +DATE_LAST_CYCL="20190520" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v15p2.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v15p2.sh new file mode 100644 index 0000000000..af3a13440f --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v15p2.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_v15p2 +# physics suite with ICs and LBCs derived from the GSMGFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="GSMGFS" +EXTRN_MDL_NAME_LBCS="GSMGFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190520" +DATE_LAST_CYCL="20190520" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..616b0e7447 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_GSMGFS_lbcs_GSMGFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the GSMGFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="GSMGFS" +EXTRN_MDL_NAME_LBCS="GSMGFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190520" +DATE_LAST_CYCL="20190520" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_NAM_lbcs_NAM_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_NAM_lbcs_NAM_suite_HRRR.sh new file mode 100644 index 0000000000..10be9fed96 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_NAM_lbcs_NAM_suite_HRRR.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the HRRR +# physics suite with ICs and LBCs derived from the NAM. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="NAM" +EXTRN_MDL_NAME_LBCS="NAM" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20210615" +DATE_LAST_CYCL="20210615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_NAM_lbcs_NAM_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_NAM_lbcs_NAM_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..540e5a0589 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_25km_ics_NAM_lbcs_NAM_suite_RRFS_v1beta.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_25km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the NAM. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="NAM" +EXTRN_MDL_NAME_LBCS="NAM" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20210615" +DATE_LAST_CYCL="20210615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15_thompson_mynn_lam3km.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15_thompson_mynn_lam3km.sh new file mode 100644 index 0000000000..03dbd2c381 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15_thompson_mynn_lam3km.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_3km grid using the GFS_v15_ +# thompson_mynn_lam3km physics suite with ICs and LBCs derived from FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_3km" +CCPP_PHYS_SUITE="FV3_GFS_v15_thompson_mynn_lam3km" + +USE_MERRA_CLIMO="TRUE" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh new file mode 100644 index 0000000000..528de40de1 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_3km grid using the GFS_v15p2 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_3km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..cd2deecb8b --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_3km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_3km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh new file mode 100644 index 0000000000..0435df0a2f --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_HRRR.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_3km grid using the HRRR +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_3km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..41f4d86a34 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUS_3km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_3km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..d7c402004c --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_13km grid using the +# GFS_v16 physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_13km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_HRRR_lbcs_RAP_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_HRRR_lbcs_RAP_suite_HRRR.sh new file mode 100644 index 0000000000..40f5e4997e --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_HRRR_lbcs_RAP_suite_HRRR.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_13km grid using the HRRR +# physics suite with ICs derived from the HRRR and LBCs derived from the +# RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_13km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="1" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..afcfa32e16 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_13km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_13km grid using the RRFS_v1beta +# physics suite with ICs derived from the HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_13km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..f5fc6384bf --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_25km grid using the +# GFS_v16 physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_HRRR.sh new file mode 100644 index 0000000000..f1302d1634 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_HRRR.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_25km grid using the HRRR +# physics suite with ICs and LBCs derived from the HRRR. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="HRRR" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="24" +LBC_SPEC_INTVL_HRS="3" + diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..0060e44663 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_HRRR_suite_RRFS_v1beta.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_25km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the HRRR. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="HRRR" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="24" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh new file mode 100644 index 0000000000..3dfedb5686 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_25km grid using the HRRR +# physics suite with ICs derived from the HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="2" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..8fc60571db --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_25km grid using the RRFS_v1beta +# physics suite with ICs derived from the HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="3" +LBC_SPEC_INTVL_HRS="1" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..5cd9b09042 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_3km grid using the +# GFS_v16 physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_3km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_GFS_v15p2.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_GFS_v15p2.sh new file mode 100644 index 0000000000..11227ea005 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_GFS_v15p2.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_3km grid using the GFS_v15p2 +# physics suite with ICs derived from the HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_3km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_HRRR.sh new file mode 100644 index 0000000000..396ce3e150 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_HRRR.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_3km grid using the HRRR +# physics suite with ICs derived from the HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_3km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="1" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..a75f8d79e6 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_CONUScompact_3km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_CONUScompact_3km grid using the +# RRFS_v1beta physics suite with ICs derived from the HRRR and LBCs +# derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_3km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_NA_13km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_NA_13km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..9e4cb594b1 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_NA_13km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh @@ -0,0 +1,54 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_NA_13km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the FV3GFS. +# +# Note that this test also sets various resource parameters for several +# of the rocoto tasks in order to more efficiently run the code on this +# (very large) grid. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_NA_13km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" + +######################################################################### +# The following code/namelist/workflow setting changes are necessary to # +# run/optimize end-to-end experiments using the 3-km NA grid # +######################################################################### + +# The model should be built in 32-bit mode (64-bit will result in much +# longer run times. + +# Use k_split=2 and n_split=5, the previous namelist values (k_split=4 +# and n_split=5) will result in significantly longer run times. + +NNODES_MAKE_ICS="12" +NNODES_MAKE_LBCS="12" +PPN_MAKE_ICS="4" +PPN_MAKE_LBCS="4" +WTIME_MAKE_LBCS="01:00:00" + +NNODES_RUN_POST="6" +PPN_RUN_POST="12" + +OMP_STACKSIZE_MAKE_ICS="2048m" +OMP_STACKSIZE_RUN_FCST="2048m" + +############################################################################### diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_NA_3km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_NA_3km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..cd0a933e6c --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_NA_3km_ics_FV3GFS_lbcs_FV3GFS_suite_RRFS_v1beta.sh @@ -0,0 +1,54 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_NA_3km grid using the RRFS_v1beta +# physics suite with ICs and LBCs derived from the FV3GFS. +# +# Note that this test also sets various resource parameters for several +# of the rocoto tasks in order to more efficiently run the code on this +# (very large) grid. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_NA_3km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" + +######################################################################### +# The following code/namelist/workflow setting changes are necessary to # +# run/optimize end-to-end experiments using the 3-km NA grid # +######################################################################### + +# The model should be built in 32-bit mode (64-bit will result in much +# longer run times. + +# Use k_split=2 and n_split=5, the previous namelist values (k_split=4 +# and n_split=5) will result in significantly longer run times. + +NNODES_MAKE_ICS="12" +NNODES_MAKE_LBCS="12" +PPN_MAKE_ICS="4" +PPN_MAKE_LBCS="4" +WTIME_MAKE_LBCS="01:00:00" + +NNODES_RUN_POST="8" +PPN_RUN_POST="12" + +OMP_STACKSIZE_MAKE_ICS="2048m" +OMP_STACKSIZE_RUN_FCST="2048m" + +############################################################################### diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_SUBCONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_SUBCONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..eac0a993a5 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_SUBCONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,25 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_SUBCONUS_3km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_SUBCONUS_3km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_SUBCONUS_3km_ics_HRRR_lbcs_RAP_suite_GFS_v15p2.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_SUBCONUS_3km_ics_HRRR_lbcs_RAP_suite_GFS_v15p2.sh new file mode 100644 index 0000000000..c5512d0ead --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_RRFS_SUBCONUS_3km_ics_HRRR_lbcs_RAP_suite_GFS_v15p2.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the RRFS_SUBCONUS_3km grid using the GFS_v15p2 +# physics suite with ICs derived from the HRRR and LBCs derived from the +# RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_SUBCONUS_3km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..e11ab393a3 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the SUBCONUS_Ind_3km grid using the GFS_v16 +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="SUBCONUS_Ind_3km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "18" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_HRRR_lbcs_RAP_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_HRRR_lbcs_RAP_suite_HRRR.sh new file mode 100644 index 0000000000..aa2cf6edcf --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_HRRR_lbcs_RAP_suite_HRRR.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the SUBCONUS_Ind_3km grid using the HRRR +# physics suite with ICs derived from HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="SUBCONUS_Ind_3km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh new file mode 100644 index 0000000000..82c5ef43ab --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_community/config.grid_SUBCONUS_Ind_3km_ics_HRRR_lbcs_RAP_suite_RRFS_v1beta.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully on the SUBCONUS_Ind_3km grid using the RRFS_v1beta +# physics suite with ICs derived from HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="SUBCONUS_Ind_3km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh new file mode 100644 index 0000000000..f6d6454bde --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v16.sh @@ -0,0 +1,26 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in nco mode completes +# successfully on the RRFS_CONUS_13km grid using the GFS_v16 physics +# suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="nco" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_13km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15_thompson_mynn_lam3km.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15_thompson_mynn_lam3km.sh new file mode 100644 index 0000000000..19b36f87f5 --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15_thompson_mynn_lam3km.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in nco mode completes +# successfully on the RRFS_CONUS_3km grid using the GFS_v15_thompson_mynn_lam3km +# physics suite with ICs and LBCs derived from the FV3GFS. +# + +RUN_ENVIR="nco" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_3km" +CCPP_PHYS_SUITE="FV3_GFS_v15_thompson_mynn_lam3km" + +USE_MERRA_CLIMO="TRUE" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh b/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh new file mode 100644 index 0000000000..e5c4e7732d --- /dev/null +++ b/tests/WE2E/test_configs/grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh @@ -0,0 +1,29 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in nco mode completes +# successfully on the RRFS_CONUScompact_25km grid using the HRRR physics +# suite with ICs derived from the HRRR and LBCs derived from the RAP. +# + +RUN_ENVIR="nco" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +WRITE_DOPOST="TRUE" diff --git a/tests/WE2E/test_configs/release_SRW_v1/config.GST_release_public_v1.sh b/tests/WE2E/test_configs/release_SRW_v1/config.GST_release_public_v1.sh new file mode 100644 index 0000000000..0a5cec5252 --- /dev/null +++ b/tests/WE2E/test_configs/release_SRW_v1/config.GST_release_public_v1.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow successfully completes the +# Graduate Student Test (GST) included in Release 1 of the UFS SRW App. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="48" +LBC_SPEC_INTVL_HRS="6" + +WTIME_RUN_FCST="01:00:00" diff --git a/tests/WE2E/test_configs/wflow_features/config.MET_ensemble_verification.sh b/tests/WE2E/test_configs/wflow_features/config.MET_ensemble_verification.sh new file mode 100644 index 0000000000..078ce144f9 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.MET_ensemble_verification.sh @@ -0,0 +1,38 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully with MET verification. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +DO_ENSEMBLE="TRUE" +NUM_ENS_MEMBERS="2" + +USE_USER_STAGED_EXTRN_FILES="TRUE" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" + +MODEL="FV3_GFS_v15p2_CONUS_25km" +RUN_TASK_VX_GRIDSTAT="TRUE" +RUN_TASK_VX_POINTSTAT="TRUE" +RUN_TASK_VX_ENSGRID="TRUE" +RUN_TASK_VX_ENSPOINT="TRUE" + +WTIME_RUN_FCST="01:00:00" diff --git a/tests/WE2E/test_configs/wflow_features/config.MET_verification.sh b/tests/WE2E/test_configs/wflow_features/config.MET_verification.sh new file mode 100644 index 0000000000..8d7cc8d4c5 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.MET_verification.sh @@ -0,0 +1,33 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test is to ensure that the workflow running in community mode +# completes successfully with MET verification. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +USE_USER_STAGED_EXTRN_FILES="TRUE" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" + +MODEL="FV3_GFS_v15p2_CONUS_25km" +RUN_TASK_VX_GRIDSTAT="TRUE" +RUN_TASK_VX_POINTSTAT="TRUE" + +WTIME_RUN_FCST="01:00:00" diff --git a/tests/WE2E/test_configs/wflow_features/config.community_ensemble_008mems.sh b/tests/WE2E/test_configs/wflow_features/config.community_ensemble_008mems.sh new file mode 100644 index 0000000000..922367c726 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.community_ensemble_008mems.sh @@ -0,0 +1,31 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to run ensemble forecasts +# (i.e. DO_ENSEMBLE set to "TRUE") in community mode (i.e. RUN_ENVIR set +# to "community") with the number of ensemble members (NUM_ENS_MEMBERS) +# set to "008". The leading zeros in "008" should cause the ensemble +# members to be numbered "mem001", "mem002", ..., "mem008" (instead of, +# for instance, "mem1", "mem2", ..., "mem8"). +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190702" +CYCL_HRS=( "00" "12" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +DO_ENSEMBLE="TRUE" +NUM_ENS_MEMBERS="008" diff --git a/tests/WE2E/test_configs/wflow_features/config.community_ensemble_2mems.sh b/tests/WE2E/test_configs/wflow_features/config.community_ensemble_2mems.sh new file mode 100644 index 0000000000..c9b68006a7 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.community_ensemble_2mems.sh @@ -0,0 +1,35 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to run ensemble forecasts +# (i.e. DO_ENSEMBLE set to "TRUE") in community mode (i.e. RUN_ENVIR set +# to "community") with the number of ensemble members (NUM_ENS_MEMBERS) +# set to "2". The lack of leading zeros in this "2" should cause the +# ensemble members to be named "mem1" and "mem2" (instead of, for instance, +# "mem01" and "mem02"). +# +# Note also that this test uses two cycle hours ("00" and "12") to test +# the capability of the workflow to run ensemble forecasts for more than +# one cycle hour in community mode. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190702" +CYCL_HRS=( "00" "12" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +DO_ENSEMBLE="TRUE" +NUM_ENS_MEMBERS="2" diff --git a/tests/WE2E/test_configs/wflow_features/config.community_ensemble_2mems_stoch.sh b/tests/WE2E/test_configs/wflow_features/config.community_ensemble_2mems_stoch.sh new file mode 100644 index 0000000000..934de78bb7 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.community_ensemble_2mems_stoch.sh @@ -0,0 +1,38 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to run ensemble forecasts +# (i.e. DO_ENSEMBLE set to "TRUE") in community mode (i.e. RUN_ENVIR set +# to "community") with the number of ensemble members (NUM_ENS_MEMBERS) +# set to "2" and all stochastic physics options turned on. +# The lack of leading zeros in this "2" should cause the +# ensemble members to be named "mem1" and "mem2" (instead of, for instance, +# "mem01" and "mem02"). +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="SUBCONUS_Ind_3km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="HRRR" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="3" +LBC_SPEC_INTVL_HRS="3" + +DO_ENSEMBLE="TRUE" +NUM_ENS_MEMBERS="2" +DO_SHUM="TRUE" +DO_SPPT="TRUE" +DO_SKEB="TRUE" +DO_SPP="TRUE" diff --git a/tests/WE2E/test_configs/wflow_features/config.custom_ESGgrid.sh b/tests/WE2E/test_configs/wflow_features/config.custom_ESGgrid.sh new file mode 100644 index 0000000000..86b3ff0b74 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.custom_ESGgrid.sh @@ -0,0 +1,65 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the user +# specify a new grid (as opposed to one of the predefined ones in the +# workflow) of ESGgrid type. + + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp_regional" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" +# +# Define custom grid. +# +POST_OUTPUT_DOMAIN_NAME="custom_ESGgrid" +GRID_GEN_METHOD="ESGgrid" + +ESGgrid_LON_CTR="-97.5" +ESGgrid_LAT_CTR="41.25" + +ESGgrid_DELX="25000.0" +ESGgrid_DELY="25000.0" + +ESGgrid_NX="216" +ESGgrid_NY="156" + +ESGgrid_PAZI="0.0" + +ESGgrid_WIDE_HALO_WIDTH="6" + +DT_ATMOS="40" + +LAYOUT_X="8" +LAYOUT_Y="12" +BLOCKSIZE="13" + +QUILTING="TRUE" +if [ "$QUILTING" = "TRUE" ]; then + WRTCMP_write_groups="1" + WRTCMP_write_tasks_per_group=$(( 1*LAYOUT_Y )) + WRTCMP_output_grid="lambert_conformal" + WRTCMP_cen_lon="${ESGgrid_LON_CTR}" + WRTCMP_cen_lat="${ESGgrid_LAT_CTR}" + WRTCMP_stdlat1="${ESGgrid_LAT_CTR}" + WRTCMP_stdlat2="${ESGgrid_LAT_CTR}" + WRTCMP_nx="200" + WRTCMP_ny="150" + WRTCMP_lon_lwr_left="-122.21414225" + WRTCMP_lat_lwr_left="22.41403305" + WRTCMP_dx="${ESGgrid_DELX}" + WRTCMP_dy="${ESGgrid_DELY}" +fi diff --git a/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid.sh b/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid.sh new file mode 100644 index 0000000000..db148e3ab2 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid.sh @@ -0,0 +1,94 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the user +# specify a new grid (as opposed to one of the predefined ones in the +# workflow) of GFDLgrid type. Note that this test sets the workflow +# variable +# +# GFDLgrid_USE_NUM_CELLS_IN_FILENAMES +# +# to "TRUE" (which is its default value); see the UFS SRW App's User's +# Guide for a description of this variable. +# +# The difference between this test and the one named +# +# new_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_TRUE +# +# is that this one uses almost no stretching by setting the workflow +# variable GFDLgrid_STRETCH_FAC very close to 1. Setting it exactly to +# 1 used to cause the workflow to fail because it caused the GFDL grid +# generator to assume a global grid. This bug should be rechecked, e.g. +# by setting GFDLgrid_STRETCH_FAC to exactly 1 below. If the grid +# generation succeeds, then this test can be removed. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" +# +# Define custom grid. +# +POST_OUTPUT_DOMAIN_NAME="custom_GFDLgrid" +GRID_GEN_METHOD="GFDLgrid" + +GFDLgrid_LON_T6_CTR="-97.5" +GFDLgrid_LAT_T6_CTR="38.5" +GFDLgrid_STRETCH_FAC="1.0001" # Cannot be exactly 1.0 because then FV3 thinnks it's a global grid. This needs to be fixed in the ufs_weather_model repo. +GFDLgrid_NUM_CELLS="96" +GFDLgrid_REFINE_RATIO="2" + +#num_margin_cells_T6_left="9" +#GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G=$(( num_margin_cells_T6_left + 1 )) +GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G="10" + +#num_margin_cells_T6_right="9" +#GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G=$(( GFDLgrid_NUM_CELLS - num_margin_cells_T6_right )) +GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G="87" + +#num_margin_cells_T6_bottom="9" +#GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G=$(( num_margin_cells_T6_bottom + 1 )) +#GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G="10" +GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G="19" + +#num_margin_cells_T6_top="9" +#GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G=$(( GFDLgrid_NUM_CELLS - num_margin_cells_T6_top )) +#GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G="87" +GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G="78" + +GFDLgrid_USE_NUM_CELLS_IN_FILENAMES="TRUE" + +DT_ATMOS="100" + +LAYOUT_X="6" +LAYOUT_Y="6" +BLOCKSIZE="26" + +QUILTING="TRUE" +if [ "$QUILTING" = "TRUE" ]; then + WRTCMP_write_groups="1" + WRTCMP_write_tasks_per_group=$(( 1*LAYOUT_Y )) + WRTCMP_output_grid="rotated_latlon" + WRTCMP_cen_lon="${GFDLgrid_LON_T6_CTR}" + WRTCMP_cen_lat="${GFDLgrid_LAT_T6_CTR}" +# The following have not been tested... + WRTCMP_lon_lwr_left="-25.0" + WRTCMP_lat_lwr_left="-15.0" + WRTCMP_lon_upr_rght="25.0" + WRTCMP_lat_upr_rght="15.0" + WRTCMP_dlon="0.24" + WRTCMP_dlat="0.24" +fi diff --git a/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_FALSE.sh b/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_FALSE.sh new file mode 100644 index 0000000000..ff4d928094 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_FALSE.sh @@ -0,0 +1,81 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the user +# specify a new grid (as opposed to one of the predefined ones in the +# workflow) of GFDLgrid type. Note that this test sets the workflow +# variable +# +# GFDLgrid_USE_NUM_CELLS_IN_FILENAMES +# +# to "FALSE"; see the UFS SRW App's User's Guide for a description of +# this variable. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" +# +# Define custom grid. +# +POST_OUTPUT_DOMAIN_NAME="custom_GFDLgrid" +GRID_GEN_METHOD="GFDLgrid" + +GFDLgrid_LON_T6_CTR="-97.5" +GFDLgrid_LAT_T6_CTR="38.5" +GFDLgrid_STRETCH_FAC="1.5" +GFDLgrid_NUM_CELLS="96" +GFDLgrid_REFINE_RATIO="2" + +#num_margin_cells_T6_left="9" +#GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G=$(( num_margin_cells_T6_left + 1 )) +GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G="10" + +#num_margin_cells_T6_right="9" +#GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G=$(( GFDLgrid_NUM_CELLS - num_margin_cells_T6_right )) +GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G="87" + +#num_margin_cells_T6_bottom="9" +#GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G=$(( num_margin_cells_T6_bottom + 1 )) +GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G="10" + +#num_margin_cells_T6_top="9" +#GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G=$(( GFDLgrid_NUM_CELLS - num_margin_cells_T6_top )) +GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G="87" + +GFDLgrid_USE_NUM_CELLS_IN_FILENAMES="FALSE" + +DT_ATMOS="100" + +LAYOUT_X="6" +LAYOUT_Y="6" +BLOCKSIZE="26" + +QUILTING="TRUE" +if [ "$QUILTING" = "TRUE" ]; then + WRTCMP_write_groups="1" + WRTCMP_write_tasks_per_group=$(( 1*LAYOUT_Y )) + WRTCMP_output_grid="rotated_latlon" + WRTCMP_cen_lon="${GFDLgrid_LON_T6_CTR}" + WRTCMP_cen_lat="${GFDLgrid_LAT_T6_CTR}" +# The following have not been tested... + WRTCMP_lon_lwr_left="-25.0" + WRTCMP_lat_lwr_left="-15.0" + WRTCMP_lon_upr_rght="25.0" + WRTCMP_lat_upr_rght="15.0" + WRTCMP_dlon="0.24" + WRTCMP_dlat="0.24" +fi diff --git a/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_TRUE.sh b/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_TRUE.sh new file mode 100644 index 0000000000..dc5d79c2ef --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.custom_GFDLgrid__GFDLgrid_USE_NUM_CELLS_IN_FILENAMES_eq_TRUE.sh @@ -0,0 +1,81 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the user +# specify a new grid (as opposed to one of the predefined ones in the +# workflow) of GFDLgrid type. Note that this test sets the workflow +# variable +# +# GFDLgrid_USE_NUM_CELLS_IN_FILENAMES +# +# to "TRUE" (which is its default value); see the UFS SRW App's User's +# Guide for a description of this variable. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" +# +# Define custom grid. +# +POST_OUTPUT_DOMAIN_NAME="custom_GFDLgrid" +GRID_GEN_METHOD="GFDLgrid" + +GFDLgrid_LON_T6_CTR="-97.5" +GFDLgrid_LAT_T6_CTR="38.5" +GFDLgrid_STRETCH_FAC="1.5" +GFDLgrid_NUM_CELLS="96" +GFDLgrid_REFINE_RATIO="2" + +#num_margin_cells_T6_left="9" +#GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G=$(( num_margin_cells_T6_left + 1 )) +GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G="10" + +#num_margin_cells_T6_right="9" +#GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G=$(( GFDLgrid_NUM_CELLS - num_margin_cells_T6_right )) +GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G="87" + +#num_margin_cells_T6_bottom="9" +#GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G=$(( num_margin_cells_T6_bottom + 1 )) +GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G="10" + +#num_margin_cells_T6_top="9" +#GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G=$(( GFDLgrid_NUM_CELLS - num_margin_cells_T6_top )) +GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G="87" + +GFDLgrid_USE_NUM_CELLS_IN_FILENAMES="TRUE" + +DT_ATMOS="100" + +LAYOUT_X="6" +LAYOUT_Y="6" +BLOCKSIZE="26" + +QUILTING="TRUE" +if [ "$QUILTING" = "TRUE" ]; then + WRTCMP_write_groups="1" + WRTCMP_write_tasks_per_group=$(( 1*LAYOUT_Y )) + WRTCMP_output_grid="rotated_latlon" + WRTCMP_cen_lon="${GFDLgrid_LON_T6_CTR}" + WRTCMP_cen_lat="${GFDLgrid_LAT_T6_CTR}" +# The following have not been tested... + WRTCMP_lon_lwr_left="-25.0" + WRTCMP_lat_lwr_left="-15.0" + WRTCMP_lon_upr_rght="25.0" + WRTCMP_lat_upr_rght="15.0" + WRTCMP_dlon="0.24" + WRTCMP_dlat="0.24" +fi diff --git a/tests/WE2E/test_configs/wflow_features/config.deactivate_tasks.sh b/tests/WE2E/test_configs/wflow_features/config.deactivate_tasks.sh new file mode 100644 index 0000000000..2375a648f5 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.deactivate_tasks.sh @@ -0,0 +1,60 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test has two purposes: +# +# 1) It checks that the various workflow tasks can be deactivated, i.e. +# removed from the Rocoto XML. +# 2) It checks the capability of the workflow to use "template" experiment +# variables, i.e. variables whose definitions include references to +# other variables, e.g. +# +# MY_VAR='\${ANOTHER_VAR}' +# +# Note that we do not deactivate all tasks in the workflow; we leave the +# MAKE_GRID_TN, MAKE_OROG_TN, and MAKE_SFC_CLIMO_TN activated because: +# +# 1) There is already a WE2E test that runs with these three tasks +# deactivated (that test is to ensure that pre-generated grid, +# orography, and surface climatology files can be used). +# 2) In checking the template variable capability, we want to make sure +# that the variable defintions file (GLOBAL_VAR_DEFNS_FN) generated +# does not have syntax or other errors in it by sourcing it in these +# three tasks. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +RUN_TASK_GET_EXTRN_ICS="FALSE" +RUN_TASK_GET_EXTRN_LBCS="FALSE" +RUN_TASK_MAKE_ICS="FALSE" +RUN_TASK_MAKE_LBCS="FALSE" +RUN_TASK_RUN_FCST="FALSE" +RUN_TASK_RUN_POST="FALSE" +# +# The following shows examples of how to define template variables. Here, +# we define RUN_CMD_UTILS, RUN_CMD_FCST, and RUN_CMD_POST as template +# variables. Note that during this test, these templates aren't actually +# expanded/used (something that would be done using bash's "eval" built-in +# command) anywhere in the scripts. They are included here only to verify +# that the test completes with some variables defined as templates. +# +RUN_CMD_UTILS='cd $yyyymmdd' +RUN_CMD_FCST='mpirun -np ${PE_MEMBER01}' +RUN_CMD_POST='echo hello $yyyymmdd' diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2019061200.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2019061200.sh new file mode 100644 index 0000000000..a835466b53 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2019061200.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS grib2-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on the first cycle +# date (2019061200) on which the FV3GFS officially became operational. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" + +DATE_FIRST_CYCL="20190612" +DATE_LAST_CYCL="20190612" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2019101818.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2019101818.sh new file mode 100644 index 0000000000..d7891e6686 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2019101818.sh @@ -0,0 +1,29 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS grib2-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on a cycle date +# (2019101818) that is about halfway between the date (2019061200) on +# which the FV3GFS officially became operational and the date (2020022600) +# on which changes to the FV3GFS output files took effect. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" + +DATE_FIRST_CYCL="20191018" +DATE_LAST_CYCL="20191018" +CYCL_HRS=( "18" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2020022518.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2020022518.sh new file mode 100644 index 0000000000..a4bea4ac17 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2020022518.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS grib2-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on the last cycle date +# (2020022518) before changes to the FV3GFS output files took effect on +# 2020022600. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" + +DATE_FIRST_CYCL="20200225" +DATE_LAST_CYCL="20200225" +CYCL_HRS=( "18" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2020022600.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2020022600.sh new file mode 100644 index 0000000000..0f4863a0c4 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2020022600.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS grib2-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on the first cycle +# date (2020022600) on which changes to the FV3GFS output files took +# effect. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" + +DATE_FIRST_CYCL="20200226" +DATE_LAST_CYCL="20200226" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2021010100.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2021010100.sh new file mode 100644 index 0000000000..70e0130eb6 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_grib2_2021010100.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS grib2-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on a cycle date +# (2021010100) that is several months in the future from the date +# (2020022600) on which changes to the FV3GFS output files took effect. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" + +DATE_FIRST_CYCL="20210101" +DATE_LAST_CYCL="20210101" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio.sh new file mode 100644 index 0000000000..17a9990c68 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio.sh @@ -0,0 +1,24 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS nemsio-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived). +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2019061200.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2019061200.sh new file mode 100644 index 0000000000..63cea83776 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2019061200.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS nemsio-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on the first cycle +# date (2019061200) on which the FV3GFS officially became operational. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="nemsio" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="nemsio" + +DATE_FIRST_CYCL="20190612" +DATE_LAST_CYCL="20190612" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2019101818.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2019101818.sh new file mode 100644 index 0000000000..cfac4ab62e --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2019101818.sh @@ -0,0 +1,29 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS nemsio-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on a cycle date +# (2019101818) that is about halfway between the date (2019061200) on +# which the FV3GFS officially became operational and the date (2020022600) +# on which changes to the FV3GFS output files took effect. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="nemsio" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="nemsio" + +DATE_FIRST_CYCL="20191018" +DATE_LAST_CYCL="20191018" +CYCL_HRS=( "18" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2020022518.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2020022518.sh new file mode 100644 index 0000000000..e80507600d --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2020022518.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS nemsio-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on the last cycle date +# (2020022518) before changes to the FV3GFS output files took effect on +# 2020022600. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="nemsio" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="nemsio" + +DATE_FIRST_CYCL="20200225" +DATE_LAST_CYCL="20200225" +CYCL_HRS=( "18" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2020022600.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2020022600.sh new file mode 100644 index 0000000000..873a13bef9 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2020022600.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS nemsio-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on the first cycle +# date (2020022600) on which changes to the FV3GFS output files took +# effect. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="nemsio" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="nemsio" + +DATE_FIRST_CYCL="20200226" +DATE_LAST_CYCL="20200226" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2021010100.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2021010100.sh new file mode 100644 index 0000000000..53421da0f5 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio_2021010100.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS nemsio-formatted output files generated by the FV3GFS external +# model (from which ICs and LBCs will be derived) on a cycle date +# (2021010100) that is several months in the future from the date +# (2020022600) on which changes to the FV3GFS output files took effect. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="nemsio" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="nemsio" + +DATE_FIRST_CYCL="20210101" +DATE_LAST_CYCL="20210101" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_netcdf_2021062000.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_netcdf_2021062000.sh new file mode 100644 index 0000000000..441690e810 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_netcdf_2021062000.sh @@ -0,0 +1,26 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS netcdf-formatted output files generated by the FV3GFS external +# model. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="netcdf" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="netcdf" + +DATE_FIRST_CYCL="20210620" +DATE_LAST_CYCL="20210620" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_netcdf_2022060112_48h.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_netcdf_2022060112_48h.sh new file mode 100644 index 0000000000..c119306516 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_FV3GFS_lbcs_FV3GFS_fmt_netcdf_2022060112_48h.sh @@ -0,0 +1,26 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS netcdf-formatted output files generated by the FV3GFS external +# model (FCST_LEN_HRS>=40). +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v16" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="netcdf" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_ICS="netcdf" + +DATE_FIRST_CYCL="20220601" +DATE_LAST_CYCL="20220601" +CYCL_HRS=( "12" ) + +FCST_LEN_HRS="48" +LBC_SPEC_INTVL_HRS="12" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_GSMGFS_lbcs_GSMGFS.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_GSMGFS_lbcs_GSMGFS.sh new file mode 100644 index 0000000000..8c5c54193a --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_GSMGFS_lbcs_GSMGFS.sh @@ -0,0 +1,24 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS files generated by the GSMGFS external model from which ICs and +# LBCs will be derived. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="GSMGFS" +EXTRN_MDL_NAME_LBCS="GSMGFS" + +DATE_FIRST_CYCL="20190520" +DATE_LAST_CYCL="20190520" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_HRRR_lbcs_RAP.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_HRRR_lbcs_RAP.sh new file mode 100644 index 0000000000..61d4e5c9eb --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_HRRR_lbcs_RAP.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS files generated by the HRRR external model from which ICs (and +# the LBCs at the 0th forecast hour) will be derived and files from the +# RAP external model from which the LBCs (except for the ones at the 0th +# forecast hour) will be derived. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_RAP_lbcs_RAP.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_RAP_lbcs_RAP.sh new file mode 100644 index 0000000000..bed8ceb8c8 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_HPSS_ics_RAP_lbcs_RAP.sh @@ -0,0 +1,24 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOAA +# HPSS files generated by the RAP external model from which ICs and LBCs +# will be derived. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="RAP" +EXTRN_MDL_NAME_LBCS="RAP" + +DATE_FIRST_CYCL="20190520" +DATE_LAST_CYCL="20190520" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" diff --git a/tests/WE2E/test_configs/wflow_features/config.get_from_NOMADS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio.sh b/tests/WE2E/test_configs/wflow_features/config.get_from_NOMADS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio.sh new file mode 100644 index 0000000000..04efe1fa2c --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.get_from_NOMADS_ics_FV3GFS_lbcs_FV3GFS_fmt_nemsio.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to retrieve from NOMADS +# nemsio-formatted output files generated by the FV3GFS external model +# (from which ICs and LBCs will be derived). +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" + +DATE_FIRST_CYCL="20200826" +DATE_LAST_CYCL="20200826" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +NOMADS="TRUE" +NOMADS_file_type="NEMSIO" diff --git a/tests/WE2E/test_configs/wflow_features/config.inline_post.sh b/tests/WE2E/test_configs/wflow_features/config.inline_post.sh new file mode 100644 index 0000000000..e491f9b179 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.inline_post.sh @@ -0,0 +1,26 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to use the inline +# post option (WRITE_DOPOST) in model_configure. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +WRITE_DOPOST="TRUE" diff --git a/tests/WE2E/test_configs/wflow_features/config.nco_ensemble.sh b/tests/WE2E/test_configs/wflow_features/config.nco_ensemble.sh new file mode 100644 index 0000000000..0f43e9e1dd --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.nco_ensemble.sh @@ -0,0 +1,35 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to run ensemble forecasts +# (i.e. DO_ENSEMBLE set to "TRUE") in nco mode (i.e. RUN_ENVIR set to +# "nco") with the number of ensemble members (NUM_ENS_MEMBERS) set to +# "2". The lack of leading zeros in this "2" should cause the ensemble +# members to be named "mem1" and "mem2" (instead of, for instance, "mem01" +# and "mem02"). +# +# Note also that this test uses two cycle hours ("12" and "18") to test +# the capability of the workflow to run ensemble forecasts for more than +# one cycle hour in nco mode. +# + +RUN_ENVIR="nco" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190702" +CYCL_HRS=( "00" "12" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +DO_ENSEMBLE="TRUE" +NUM_ENS_MEMBERS="2" diff --git a/tests/WE2E/test_configs/wflow_features/config.nco_inline_post.sh b/tests/WE2E/test_configs/wflow_features/config.nco_inline_post.sh new file mode 120000 index 0000000000..392d3311ac --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.nco_inline_post.sh @@ -0,0 +1 @@ +../grids_extrn_mdls_suites_nco/config.nco_grid_RRFS_CONUScompact_25km_ics_HRRR_lbcs_RAP_suite_HRRR.sh \ No newline at end of file diff --git a/tests/WE2E/test_configs/wflow_features/config.pregen_grid_orog_sfc_climo.sh b/tests/WE2E/test_configs/wflow_features/config.pregen_grid_orog_sfc_climo.sh new file mode 100644 index 0000000000..fa1d0f06a4 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.pregen_grid_orog_sfc_climo.sh @@ -0,0 +1,28 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to use pregenerated +# grid, orography, and surface climatology files. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +RUN_TASK_MAKE_GRID="FALSE" +RUN_TASK_MAKE_OROG="FALSE" +RUN_TASK_MAKE_SFC_CLIMO="FALSE" diff --git a/tests/WE2E/test_configs/wflow_features/config.specify_DOT_OR_USCORE.sh b/tests/WE2E/test_configs/wflow_features/config.specify_DOT_OR_USCORE.sh new file mode 100644 index 0000000000..979d8e96e9 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.specify_DOT_OR_USCORE.sh @@ -0,0 +1,39 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the character +# (DOT_OR_USCORE) in the names of the input grid and orography files +# that comes after the C-resolution be set to a user-specified value. +# For example, a grid file may be named +# +# C403${DOT_OR_USCORE}grid.tile7.halo4.nc +# +# where "C403" is the C-resolution for this specific grid and +# ${DOT_OR_USCORE} represents the contents of the workflow variable +# DOT_OR_USCORE (bash syntax). DOT_OR_USCORE is by default set to an +# underscore, but for consistency with the rest of the separators in the +# file name (as well as with the character after the C-resolution in the +# names of the surface climatology files), it should be a "." (a dot). +# The MAKE_GRID_TN and MAKE_OROG_TN tasks will name the grid and orography +# files that they create using this character. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_2017_gfdlmp" + +EXTRN_MDL_NAME_ICS="GSMGFS" +EXTRN_MDL_NAME_LBCS="GSMGFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190520" +DATE_LAST_CYCL="20190520" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="6" + +DOT_OR_USCORE="." diff --git a/tests/WE2E/test_configs/wflow_features/config.specify_DT_ATMOS_LAYOUT_XY_BLOCKSIZE.sh b/tests/WE2E/test_configs/wflow_features/config.specify_DT_ATMOS_LAYOUT_XY_BLOCKSIZE.sh new file mode 100644 index 0000000000..7a10a0ec34 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.specify_DT_ATMOS_LAYOUT_XY_BLOCKSIZE.sh @@ -0,0 +1,32 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the forecast +# model's time step (DT_ATMOS), its MPI layout (LAYOUT_X and LAYOUT_Y), +# and its cache block size be set to user-specified values. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_HRRR" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200801" +DATE_LAST_CYCL="20200801" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +DT_ATMOS="100" +LAYOUT_X="10" +LAYOUT_Y="4" +BLOCKSIZE="35" diff --git a/tests/WE2E/test_configs/wflow_features/config.specify_EXTRN_MDL_SYSBASEDIR_ICS_LBCS.sh b/tests/WE2E/test_configs/wflow_features/config.specify_EXTRN_MDL_SYSBASEDIR_ICS_LBCS.sh new file mode 100644 index 0000000000..eca762a946 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.specify_EXTRN_MDL_SYSBASEDIR_ICS_LBCS.sh @@ -0,0 +1,29 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the base +# directories on the system disk in which the external model files are +# located be set to user-specified values. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +FV3GFS_FILE_FMT_ICS="grib2" +EXTRN_MDL_NAME_LBCS="FV3GFS" +FV3GFS_FILE_FMT_LBCS="grib2" + +DATE_FIRST_CYCL="20210615" +DATE_LAST_CYCL="20210615" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +EXTRN_MDL_SYSBASEDIR_ICS="set_to_non_default_location_in_testing_script" +EXTRN_MDL_SYSBASEDIR_LBCS="set_to_non_default_location_in_testing_script" diff --git a/tests/WE2E/test_configs/wflow_features/config.specify_RESTART_INTERVAL.sh b/tests/WE2E/test_configs/wflow_features/config.specify_RESTART_INTERVAL.sh new file mode 100644 index 0000000000..3051cb5a89 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.specify_RESTART_INTERVAL.sh @@ -0,0 +1,27 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the time +# interval (RESTART_INTERVAL) at which restart files are written by the +# forecast model be set to a user-specified value. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +RESTART_INTERVAL="1" diff --git a/tests/WE2E/test_configs/wflow_features/config.specify_template_filenames.sh b/tests/WE2E/test_configs/wflow_features/config.specify_template_filenames.sh new file mode 100644 index 0000000000..81185425c6 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.specify_template_filenames.sh @@ -0,0 +1,30 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to use user-defined +# template files. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +CCPP_PHYS_SUITE="FV3_GFS_v15p2" + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +USE_USER_STAGED_EXTRN_FILES="TRUE" + +DATE_FIRST_CYCL="20190701" +DATE_LAST_CYCL="20190701" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +DATA_TABLE_TMPL_FN="data_table" +DIAG_TABLE_TMPL_FN="diag_table" +FIELD_TABLE_TMPL_FN="field_table" +MODEL_CONFIG_TMPL_FN="model_configure" +NEMS_CONFIG_TMPL_FN="nems.configure" diff --git a/tests/WE2E/test_configs/wflow_features/config.subhourly_post.sh b/tests/WE2E/test_configs/wflow_features/config.subhourly_post.sh new file mode 100644 index 0000000000..a1676e4d58 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.subhourly_post.sh @@ -0,0 +1,31 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to have the model write +# output files and perform post-processing on a sub-hourly time interval. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="3" +LBC_SPEC_INTVL_HRS="1" + +DT_ATMOS="120" + +SUB_HOURLY_POST="TRUE" +DT_SUBHOURLY_POST_MNTS="2" diff --git a/tests/WE2E/test_configs/wflow_features/config.subhourly_post_ensemble_2mems.sh b/tests/WE2E/test_configs/wflow_features/config.subhourly_post_ensemble_2mems.sh new file mode 100644 index 0000000000..adcc37a332 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.subhourly_post_ensemble_2mems.sh @@ -0,0 +1,40 @@ +# +# TEST PURPOSE/DESCRIPTION: +# ------------------------ +# +# This test checks the capability of the workflow to run ensemble forecasts +# that require the forecast model to write output files and perform post- +# processing on a sub-hourly time interval. +# +# This test is needed in addition to the one named "subhourly_post" +# because in the jinja template file from which the rocoto workflow XML +# is generated, the code changes that were made to add the subhourly +# capability also involved changes to the ensemble capability. +# + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUScompact_25km" +CCPP_PHYS_SUITE="FV3_RRFS_v1beta" + +EXTRN_MDL_NAME_ICS="HRRR" +EXTRN_MDL_NAME_LBCS="RAP" +USE_USER_STAGED_EXTRN_FILES="TRUE" +EXTRN_MDL_FILES_ICS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) +EXTRN_MDL_FILES_LBCS=( '{yy}{jjj}{hh}00{fcst_hr:02d}00' ) + +DATE_FIRST_CYCL="20200810" +DATE_LAST_CYCL="20200810" +CYCL_HRS=( "00" ) + +FCST_LEN_HRS="3" +LBC_SPEC_INTVL_HRS="1" + +DT_ATMOS="120" + +SUB_HOURLY_POST="TRUE" +DT_SUBHOURLY_POST_MNTS="12" + +DO_ENSEMBLE="TRUE" +NUM_ENS_MEMBERS="2" diff --git a/tests/WE2E/test_configs/wflow_features/config.template_vars.sh b/tests/WE2E/test_configs/wflow_features/config.template_vars.sh new file mode 120000 index 0000000000..80ede54374 --- /dev/null +++ b/tests/WE2E/test_configs/wflow_features/config.template_vars.sh @@ -0,0 +1 @@ +config.deactivate_tasks.sh \ No newline at end of file diff --git a/update_fork.pl b/update_fork.pl new file mode 100755 index 0000000000..17cb67dc16 --- /dev/null +++ b/update_fork.pl @@ -0,0 +1,77 @@ +#!/usr/bin/perl -w + +# Script for easily updating your fork of the main regional_workflow repository +# +# Author: Michael Kavulich, September 2016 +# Updated for regional_workflow repository, July 2019 +# No rights reserved, this script may be used, copied, or modified for any purpose +# +# Instructions: +# 1. Clone your fork of the repository (if you already have a local clone of your fork this is optional) +# git clone https://your_username@github.com/your_username/regional_workflow.git +# 2. Enter the directory of the local clone of your fork +# cd regional_workflow +# 3. Run this script from within the directory structure of your local clone of your fork +# ./update_fork.pl +# You will be asked to enter your Github username: enter it and hit "return". +# 4. If all went well, you should see one of two different messages at the end: +# - If your fork is already up-to-date, you should see "Already up-to-date." +# - If your fork is not up-to-date, this script initiates a fast-forward merge to bring your fork +# up to date with the develop of the main repository (https://github.com/ufs-community/regional_workflow). +# Near the end git will print a line of statistics describing what changed, which will look +# something like this: +# +# 19 files changed, 27 insertions(+), 27 deletions(-) +# +# followed by a few more lines and this final message: +# +# Branch develop set up to track remote branch develop from origin. + +# Notes: +# - This is a preliminary version of what will hopefully be a more detailed script in the future. +# This one only performs fast-forward merges. + +use strict; + +my $username; +my $go_on = ""; + +# First off: check if we are on develop, and quit if we are not. We want the branch switch to be transparent to users +my $curr_branch = `git rev-parse --abbrev-ref HEAD`; +chomp $curr_branch; +die "\nERROR ERROR ERROR:\nYou are currently on the branch $curr_branch\n\nThis script must be run from the develop branch.\n\nCheck out the develop branch, then run this script, then check out your working branch $curr_branch when the update is finished\n\n" unless $curr_branch eq "develop"; + + +# Prompt user for their username +print "Please enter your Github username:\n"; + while ($go_on eq "") { + $go_on = ; + chop($go_on); + if ($go_on eq "") { + print "Please enter your Github username:\n"; + } else { + $username = $go_on; + } + } + +print "Username = $username\n"; +my $main_repo = "https://$username\@github.com/ufs-community/regional_workflow.git"; +my $fork = "https://$username\@github.com/$username/regional_workflow.git"; + +# Set main repository as a remote repository named "upstream", per standard git conventions +print "\nStep 1: Setting main repository as a remote repository named 'upstream'\n\n"; +! system("git", "remote", "rm", "upstream") or warn "If you see \"error: Could not remove config section 'remote.upstream'\" this is normal! Don't panic!\n"; +! system("git", "remote", "add", "upstream", $main_repo) or die "Can not add main repository '$main_repo' for merging: $!\n"; + +# Set the "push" url for "upstream" to be the user's fork, to avoid accidentally pushing to the main repository +print "\nStep 2: Setting the 'push' url for 'upstream' to the user's fork, to avoid accidentally pushing to the main repository\n\n"; +! system("git", "remote", "set-url", "--push", "upstream", $fork) or die "Can not add set push repository '$fork': $!\n"; + +# Checkout develop, fetch "upstream" commits, and perform a fastforward merge +print "\nStep 3: Fetching 'upstream' commits, and performing fastforward merge\n\n"; +! system("git", "fetch", "upstream", "develop") or die "Can not fetch upstream changes from : $!\nSomething has gone seriously wrong! Perhaps you don't have internet access?\n"; +! system("git", "merge", "--ff-only", "upstream/develop") or die "\nCan not perform fastforward merge from upstream/develop: $!\n\nTroubleshooting info:\n\n 1. If you receive a message 'fatal: 'upstream/develop' does not point to a commit', your git version may be too old. On yellowstone, try `module load git`\n 2. If you receive a message' fatal: Not possible to fast-forward, aborting.', you have likely made local changes to the develop branch of your fork. All work should be done on branches of your fork, not the develop!\n"; + +# Finally, push updated develop to the Github copy of your fork: +print "\nStep 4: Pushing updated develop to fork\n\n"; +! system("git", "push", "-u", "origin", "develop") or die "\nCan not push updates to origin/develop : $!\n"; diff --git a/ush/.gitignore b/ush/.gitignore new file mode 100644 index 0000000000..ea085be4e8 --- /dev/null +++ b/ush/.gitignore @@ -0,0 +1,4 @@ +err.* +out.* +log.* + diff --git a/ush/NCL/.gitignore b/ush/NCL/.gitignore new file mode 100644 index 0000000000..4410d352e8 --- /dev/null +++ b/ush/NCL/.gitignore @@ -0,0 +1,5 @@ +*.png +*.ncgm +*.sw* +*.orig +*.before*.ncl diff --git a/ush/NCL/NCL_ICs_BCs/.gitignore b/ush/NCL/NCL_ICs_BCs/.gitignore new file mode 100644 index 0000000000..e947fbe246 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/.gitignore @@ -0,0 +1,5 @@ +old_files* +png_old* +*.txt +*.nc +*.png diff --git a/ush/NCL/NCL_ICs_BCs/adjust_longitude_range.ncl b/ush/NCL/NCL_ICs_BCs/adjust_longitude_range.ncl new file mode 100644 index 0000000000..3f07b8c75e --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/adjust_longitude_range.ncl @@ -0,0 +1,96 @@ +; ********************************************************************** +; +; File name: adjust_longitude_range.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function adjust the given array of longitude values such that all +; values in the returned array lon_out are in the range +; +; -lon_min <= lon_out < lon_max, +; +; Here, lon_min is the given minimum longitude value and lon_max is ei- +; ther lon_min plus 360 deg (if the units of lon and lon_min are in de- +; grees) or lon_min plus 2*pi (if the units are in radians). lon and +; lon_min must have the same units (degrees or radians). These units +; are specified by the input string degs_or_rads. This string should be +; set either to "degs" for degrees or to "rads" for radians. +; * +; ********************************************************************** + +load "strcmp.ncl" + +undef("adjust_longitude_range") + +function adjust_longitude_range( \ + lon:snumeric, lon_min:snumeric, degs_or_rads:string) + +local char_dq, pi, lon_domain_size, lon_max, lon_out + +begin +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; + char_dq = integertochar(34) +; +; ********************************************************************** +; * +; Set the size of the longitude domain. This is either 360 deg (if the +; given longitudes are in degrees) or 2*pi (if the given longitudes are +; in radians). +; * +; ********************************************************************** +; + if (strcmp(degs_or_rads, "degs")) then + lon_domain_size = 360.0 + else if (strcmp(degs_or_rads, "rads")) then + pi = 4.0d*atan(1.0d) + lon_domain_size = 2.0d*pi + else + print("") + print("Disallowed value specified for input argument degs_or_rads:") + print(" degs_or_rads = " + char_dq + degs_or_rads + char_dq) + print("Allowed values are " + char_dq + "degs" + char_dq + \ + " and " + char_dq + "rads" + char_dq + ".") + print("Stopping.") + exit + end if + end if +; +; ********************************************************************** +; * +; Add the longitude domain size calculated above to the given minimum +; longitude to obtain the maximum longitude. +; * +; ********************************************************************** +; + lon_max = lon_min + lon_domain_size +; +; ********************************************************************** +; * +; Create a new longitude array (lon_out) that will serve as the output +; of this function. Then adjust longitudes to ensure that all elements +; of lon_out are in the range lon_min <= lon_out < lon_max. +; * +; ********************************************************************** +; + lon_out := lon + lon_out := where(lon_out .lt. lon_min, lon_out + lon_domain_size, lon_out) + lon_out := where(lon_out .ge. lon_max, lon_out - lon_domain_size, lon_out) +; +; ********************************************************************** +; * +; Return the adjusted longitude array lon_out. +; * +; ********************************************************************** +; + return(lon_out) + +end + + diff --git a/ush/NCL/NCL_ICs_BCs/calc_field_stats.ncl b/ush/NCL/NCL_ICs_BCs/calc_field_stats.ncl new file mode 100644 index 0000000000..12e84c71cf --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/calc_field_stats.ncl @@ -0,0 +1,120 @@ +; ********************************************************************** +; +; File name: calc_field_stats.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates and returns various statistics of the speci- +; fied field. If the argument print_field_stats is set to True, it will +; also print these statistics to the screen. +; * +; ********************************************************************** + +load "special_chars.ncl" + +undef("calc_field_stats") + +function calc_field_stats( \ + field:snumeric, field_desc:string, field_units:string, \ + print_field_stats:logical) + +local field_dims, field_rank, dim_nums, \ + field_min, field_max, field_median, field_mean, \ + field_dims_str, units, msg, field_stat_info + +begin +; +; ********************************************************************** +; +; Get the field's dimensions and rank. +; +; ********************************************************************** +; + field_dims := dimsizes(field) + field_rank := dimsizes(field_dims) + dim_nums := ispan(0, field_rank-1, 1) +; +; ********************************************************************** +; +; Calculate the field's minimum and maximum values and its median and +; mean. Note that the median is calculated over all elements of the +; field (i.e. over all dimensions of the array containing the field). +; +; ********************************************************************** +; + field_min := min(field) + field_max := max(field) + field_median := dim_median_n(field, dim_nums) + field_mean := avg(field) + + field_dims_str := tostring(field_dims) + field_dims_str := str_join(field_dims_str, ", ") + units := " [" + field_units + "]" + + msg := char_nl + \ +"The specified field's description, units, rank, and dimensions are:" + char_nl + \ +char_nl + \ +" field_desc = " + char_dq + field_desc + char_dq + char_nl + \ +" field_units = " + char_dq + field_units + char_dq + char_nl + \ +" field_rank = " + field_rank + char_nl + \ +" field_dims = (" + field_dims_str + ")" + char_nl + \ +char_nl + \ +"Statistics of this field are:" + char_nl + \ +char_nl + \ +" field_min = " + field_min + units + char_nl + \ +" field_max = " + field_max + units + char_nl + \ +" field_median = " + field_median + units + char_nl + \ +" field_mean = " + field_mean + units + + msg := str_split(msg, char_nl) + + + if (print_field_stats) then + +if (False) then + print("") + print("The specified field's description, units, rank, and dimensions are:") + print("") + print(" field_desc = " + char_dq + field_desc + char_dq) + print(" field_units = " + char_dq + field_units + char_dq) + print(" field_rank = " + field_rank) + field_dims_str := tostring(field_dims) + field_dims_str := str_join(field_dims_str, ", ") + print(" field_dims = (" + field_dims_str + ")") + print("") + print("Statistics of this field are:") + print("") + units := " [" + field_units + "]" + print(" field_min = " + field_min + units) + print(" field_max = " + field_max + units) + print(" field_median = " + field_median + units) + print(" field_mean = " + field_mean + units) +end if + + print("" + msg) + + end if +; +; ********************************************************************** +; * +; Return various output variables as attributes of the field_stat_info +; variable. +; * +; ********************************************************************** +; + field_stat_info := True + + field_stat_info@field_rank = field_rank + field_stat_info@field_dims = field_dims + field_stat_info@field_min = field_min + field_stat_info@field_max = field_max + field_stat_info@field_median = field_median + field_stat_info@field_mean = field_mean + field_stat_info@msg = msg + + return(field_stat_info) + +end + + diff --git a/ush/NCL/NCL_ICs_BCs/generate_ICs_BCs.sh b/ush/NCL/NCL_ICs_BCs/generate_ICs_BCs.sh new file mode 100755 index 0000000000..fd6a08fd79 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/generate_ICs_BCs.sh @@ -0,0 +1,343 @@ +#!/bin/bash + +set -eux + +module load intel +module load ncl/6.4.0 + +#RES="96" +RES="384" + +CRES="C${RES}" + +#CDATE=2018-08-09_03_00_00.RAP +CDATE="2018080903" + +fcst_len_hrs="0" + +BC_interval_hrs="3" + +plot_RAP_fields="True" +#plot_RAP_fields="False" + +plot_FV3LAM_fields="True" +#plot_FV3LAM_fields="False" + +#grid_dir="/scratch3/BMC/det/beck/FV3-CAM/work.C384r0p7n3_regional_RAP/INPUT" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_FV3_regional_C96_2018032900/INPUT" +#grid_dir="/scratch3/BMC/fim/Julie.Schramm/regional_FV3_EMC_visit_20180509/work_FV3_regional_C96_2018032900/INPUT" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_FV3_regional_C96_2018032900/INPUT" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_1p5_rfn_3_HRRR/grid" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_2p0_rfn_3_HRRR/grid" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_1p8_rfn_3_HRRR/grid" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_1p8_rfn_5_HRRR/grid" +#grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_0p7_rfn_3_test_all/grid" +grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_1p5_rfn_3_descriptive_str/filter_topo" +grid_dir="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/C384_S0p63_RR3_RAP_new_chgres_fv3sar07/shave" + +RAP_grid_fn="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/geo_em.d01.RAP.nc" +#RAP_grid_fn="/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/geo_em.d01.HRRR.nc" + +if [ 1 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a cylindrical projection. +# +ncl -n generate_RAP_based_ICs_BCs.ncl \ + CDATE=${CDATE} \ + fcst_len_hrs=${fcst_len_hrs} \ + BC_interval_hrs=${BC_interval_hrs} \ + plot_RAP_fields=${plot_RAP_fields} \ + plot_FV3LAM_fields=${plot_FV3LAM_fields} \ + 'regions=[/ [/ "GLOBE", (/-180, 180, -90, 90/), False, False /], \ + [/ "FV3LAM", (/-140, -60, 20, 55/), False, False /], \ + [/ "FV3LAMNW", (/-145, -135, 50, 60/), True, True /], \ + [/ "FV3LAMSE", (/ -75, -70, 20, 25/), True, False /], \ + [/ "dummy_list_element_dont_remove" /] \ + /]' \ + map_proj=\"cyln\" + +# 'regions=[/ [/ "GLOBE", (/-180, 180, -90, 90/), False, False /], \ +# [/ "FV3LAM", (/-140, -60, 20, 55/), False, False /], \ +# [/ "FV3LAMNW", (/-135, -130, 45, 50/), True, True /], \ +# [/ "FV3LAMSE", (/ -75, -70, 20, 25/), True, False /], \ +# [/ "dummy_list_element_dont_remove" /] \ +# /]' \ + +# 'regions=[/ [/ "FV3LAMNW", (/-135, -130, 45, 50/), True, True /], \ +# [/ "dummy_list_element_dont_remove" /] \ +# /]' \ + +# 'regions=[/ [/ "FV3LAM", (/-140, -60, 20, 55/), False, False /], \ +# [/ "dummy_list_element_dont_remove" /] \ +# /]' \ + +# draw_RAP_grid=False \ +# draw_FV3LAM_grid=True \ +# plot_subregs=True \ +# subreg_names=\(/\"haloAll\",\"haloNW\",\"haloSE\"/\) \ +# subreg_coords=\(/\(/-140,-60,20,55/\),\(/-135,-130,45,50/\),\(/-75,-70,20,25/\)/\) \ +# subreg_draw_RAP_grid=\(/False,True,False/\) \ +# subreg_draw_FV3LAM_grid=\(/False,True,True/\) \ + +# bbb=\[/\[/\"globe\",\(/-140,-60,20,55/\),True,True/\],\[/\"RAP\",\(/-140,-60,20,55/\),True,True/\],\[/\"RAPNW\",\(/-140,-60,20,55/\),False,False/\],\[/\"dummy\"/\]/\] \ +# bbb=\[/\[/\"globe\",\(/-140,-60,20,55/\),True,True/\],\ +#\[/\"RAP\",\(/-140,-60,20,55/\),True,True/\],\ +#\[/\"RAPNW\",\(/-140,-60,20,55/\),False,False/\],\ +#\[/\"dummy_list_element_dont_remove\"/\]/\] \ +# subregions=\[/\[/\"haloNW\",-140,-60,20,55/\],\[/\"haloSE\",-75,-70,20,25/\]/\] \ +# subregions=\(/\(/-140,-60,20,55/\),\(/-65,-60,45,50/\)/\) \ +# +# map_proj=\"ortho\" \ +# map_proj_ctr=\(/-105,50/\) \ +# map_proj=\"cyln\" \ +# subreg=\(/-180,-35,-10,80/\) \ +# subreg=\(/-140,-60,45,55/\) \ # Northern portion of halo. +# subreg=\(/-125,-70,22,23/\) \ # Southern portion of halo. +# subreg=\(/-133,-122,20,50/\) \ # Western portion of halo. +# subreg=\(/-73,-62,20,50/\) \ # Eastern portion of halo. +# subreg=\(/-134,-132,46.5,47.5/\) \ +# subreg=\(/-135,-130,45,50/\) \ # North-west corner of halo. +# subreg=\(/-65,-60,45,50/\) \ # North-east corner of halo. +# subreg=\(/-125,-120,20,25/\) \ # South-west corner of halo. +# subreg=\(/-75,-70,20,25/\) \ # South-east corner of halo. +# +# subreg=\(/-140,-60,20,55/\) \ # Whole halo. +# +#mv RAP_T.png RAP_T_all.png +#mv FV3_halo.png FV3_halo_all.png + + +fi +exit + + + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a sphere (orthogonal spherical projection). +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"ortho\" \ + map_proj_ctr=\(/-105,50/\) \ + graphics_type=\"png\" +# +mv ${CRES}_grid.png ${CRES}rgnl_grid_size_and_RAP_domain_sphr.png +fi + + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a sphere (orthogonal spherical projection). +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/5,6,7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=True \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=True \ + map_proj=\"cyln\" \ + subreg=\(/-47,-40,15,22/\) \ + graphics_type=\"png\" +# +mv ${CRES}_grid.png ${CRES}rgnl_and_RAP_gridlines_cyln_closeup.png +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a cylindrical projection. +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=False \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + graphics_type=\"png\" +# +mv ${CRES}_grid.png ${CRES}rgnl_RAP_grids_cyln.png + +fi + + +if [ 0 = 1 ]; then +# +# +ncl -n plot_grid.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=False \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=True \ + map_proj=\"cyln\" \ + subreg=\(/-130,-60,25,55/\) \ + graphics_type=\"png\" +# +mv ${CRES}_grid.png ${CRES}rgnl_RAP_grids_cyln_subreg_CONUS.png + +fi + +if [ 0 = 1 ]; then +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=True \ + draw_RAP_domain=False \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + graphics_type=\"png\" +# subreg=\(/-47,-40,15,22/\) \ +# tile_inds=\(/1,2,3,4,5,6/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# subreg=\(/-150,-40,0,70/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# +#mv ${CRES}_grid.png ${CRES}rgnl_RAP_grids_cyln_subreg.png +mv ${CRES}_grid.png ${CRES}rgnl_RAP_grids_cyln.png + +fi + + + +if [ 0 = 1 ]; then +# +#ncl -n plot_fields.ncl \ +ncl -n plot_grid.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + subreg=\(/-135,-60,10,60/\) \ + graphics_type=\"png\" +# subreg=\(/-47,-40,15,22/\) \ +# tile_inds=\(/1,2,3,4,5,6/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# subreg=\(/-150,-40,0,70/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# +#mv ${CRES}_grid.png ${CRES}rgnl_RAP_fields_cyln_subreg.png +mv ${CRES}_grid.png ${CRES}rgnl_RAP_fields_cyln.png + +fi + + +if [ 0 = 1 ]; then +# +#ncl -n plot_fields.ncl \ +ncl -n plot_grid.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"lamb\" \ + subreg=\(/-128,-70,20,53/\) \ + graphics_type=\"png\" +# subreg=\(/-47,-40,15,22/\) \ +# tile_inds=\(/1,2,3,4,5,6/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# subreg=\(/-150,-40,0,70/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# map_proj=\"cyln\" \ +# subreg=\(/-135,-60,10,60/\) \ +# subreg=\(/-128,-70,20,53/\) \ +# map_proj=\"lamb\" \ +# +#mv ${CRES}_grid.png ${CRES}rgnl_RAP_fields_cyln_subreg.png +#mv ${CRES}_grid.png ${CRES}rgnl_RAP_fields_cyln.png +fi + + +if [ 0 = 1 ]; then +# +#ncl -n plot_fields.ncl \ +ncl -n plot_grid.ncl \ + grid_dir=\"$grid_dir\" \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=False \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"ortho\" \ + map_proj_ctr=\(/-105,50/\) \ + subreg=\(/-180,-35,-10,80/\) \ + graphics_type=\"png\" +# subreg=\(/-47,-40,15,22/\) \ +# tile_inds=\(/1,2,3,4,5,6/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# subreg=\(/-150,-40,0,70/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# map_proj=\"cyln\" \ +# subreg=\(/-135,-60,10,60/\) \ +# subreg=\(/-128,-70,20,53/\) \ +# map_proj=\"lamb\" \ +# +#mv ${CRES}_grid.png ${CRES}rgnl_RAP_fields_cyln_subreg.png +#mv ${CRES}_grid.png ${CRES}rgnl_RAP_fields_cyln.png +fi + + + +if [ 0 = 1 ]; then +ncl -n plot_grid.ncl \ + 'grid_dir="./some_dir/grid"' \ + 'res=96' \ + 'tile_inds=(/1,2,3/)' \ + 'draw_tile_bdy=True' \ + 'draw_tile_grid=True' \ + 'draw_RAP_domain=True' \ + 'RAP_grid_fn="./some_dir/RAP_grid.nc"' \ + 'draw_RAP_bdy=True' \ + 'draw_RAP_grid=True' \ + 'map_proj="cyln"' \ + 'map_proj_ctr=(/0,90/)' \ + 'subreg=(/-30,30,-25,25/)' \ + 'graphics_type="ncgm"' +fi + + + + diff --git a/ush/NCL/NCL_ICs_BCs/generate_RAP_based_ICs_BCs.ncl b/ush/NCL/NCL_ICs_BCs/generate_RAP_based_ICs_BCs.ncl new file mode 100644 index 0000000000..4e57166850 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/generate_RAP_based_ICs_BCs.ncl @@ -0,0 +1,938 @@ +; +; ********************************************************************** +; * +; This script horizontally interpolates the specified 2-D or 3-D field +; * +; ********************************************************************** +; +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/esmf/ESMF_regridding.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/wrf/WRFUserARW.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/contrib/cd_string.ncl" + +load "pause.ncl" +load "strcmp.ncl" +load "interpolate_RAP_to_FV3LAM.ncl" +load "read_RAP_grid.ncl" +load "read_FV3LAM_grid_halo.ncl" +load "calc_field_stats.ncl" +load "read_RAP_horiz_field.ncl" +load "adjust_longitude_range.ncl" +load "set_cnLevels_lbLabels.ncl" +load "plot_model_field_generic.ncl" + +begin + + + + +if (False) then + +;print(aaa) +;pause + +;bbb := [/ [/ "globe", (/-140,-60,20,55/), True, True /], \ +; [/ "RAP", (/-140,-60,20,55/), True, True /], \ +; [/ "RAPNW", (/-140,-60,20,55/), False, False /], \ +; [/ "dummy_list_index_dont_remove" /] \ +; /] + +bbb := [/ [/ "globe", (/-140,-60,20,55/), True, True /], \ + [/ "RAP", (/-140,-60,20,55/), True, True /], \ + [/ "RAPNW", (/-140,-60,20,55/), False, False /] \ + /] + +;dummy_var = [/ "dummy" /] + +;aaa := ListAppend(bbb, dummy_var) + +; [/ "dummy_list_index_dont_remove" /] \ + +print("") +num_elems_bbb = ListCount(bbb) +print("num_elems_bbb = " + num_elems_bbb) +print("ListGetType(bbb) = " + ListGetType(bbb)) +pause +print(bbb) +pause + +k = 2 +ccc := bbb[k] +;ccc := ListPop(bbb) +num_elems_ccc = ListCount(ccc) +;num_elems_ccc = dimsizes(ccc) +print("") +print("typeof(ccc) = " + typeof(ccc)) +pause +print("ccc = bbb[" + k + "]") +print("num_elems_ccc = " + num_elems_ccc) +print(ccc) +pause + +do i=0,num_elems_ccc-1 + ddd := ccc[i] + print("") + print("i = " + i) + print(" ddd = ccc[" + i + "]") + print(" dimsizes(ddd) = " + dimsizes(ddd)) + print(" ddd = " + ddd) + pause +end do +exit + +end if + + + +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; + char_dq = integertochar(34) + char_nl = str_get_nl() +; +; ********************************************************************** +; * +; Check whether draw_RAP_grid has been specified on the command line. +; If not, set it to False. Do same for draw_FV3LAM_grid. +; * +; ********************************************************************** +; + if (.not. isvar("draw_RAP_grid")) then + draw_RAP_grid = False + end if + + if (.not. isvar("draw_FV3LAM_grid")) then + draw_FV3LAM_grid = False + end if +; +; ********************************************************************** +; * +; Check whether map_proj is specified, and if so, whether the specified +; value is valid. Default is to use a cylindrical-equidistant project- +; ion. +; * +; ********************************************************************** +; +if (False) then + + if (.not. isvar("map_proj")) then + map_proj := "cyln" + end if + + idx_cyln := str_match_ind_regex(map_proj, "^" + "cyln" + "$") + idx_ortho := str_match_ind_regex(map_proj, "^" + "ortho" + "$") + idx_lamb := str_match_ind_regex(map_proj, "^" + "lamb" + "$") + + if (ismissing(idx_cyln) .and. \ + ismissing(idx_ortho) .and. \ + ismissing(idx_lamb)) then + print("") + print("Disallowed value specified for " + char_dq + "map_proj" + \ + char_dq + ":") + print(" map_proj = " + char_dq + map_proj + char_dq) + print("Allowed values are:") + print(" " + char_dq + "cyln" + char_dq + \ + " (for cylindrical-equidistant projection)") + print(" " + char_dq + "ortho" + char_dq + \ + " (for orthographic (i.e. on a sphere) projection)") + print(" " + char_dq + "lamb" + char_dq + \ + " (for Lambert conformal projection)") + print("Please specify one of these allowed values for " + \ + char_dq + "map_proj" + char_dq + ".") + print("Stopping.") + exit + end if +end if +; +; ********************************************************************** +; * +; Check whether map_proj_ctr is specified. If not, set it according to +; the specified map projection. Note that this variable is not used for +; the cylindrical-equidistant map projection. +; * +; ********************************************************************** +; +if (False) then + if (.not. isvar("map_proj_ctr")) then + + map_proj_ctr = new((/2/), "float") + + if (.not. ismissing(idx_cyln)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (.not. ismissing(idx_ortho)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (.not. ismissing(idx_lamb)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 90. + end if + end if + end if + + end if +end if +; +; ********************************************************************** +; * +; Check that the initial date and time of the forecast (CDATE), the +; forecast length in hours (fcst_len_hrs), and the time interval (in +; hours) between boundary condition updates (BC_interval_hrs) have all +; been specified. If not, print out a warning and exit. +; * +; ********************************************************************** +; + if (.not. isvar("CDATE")) then + print("") + print("The initial forecast date and time (CDATE) has not been specified:") + print(" isvar(" + char_dq + "CDATE" + char_dq + ") = " + isvar("CDATE")) + print("Stopping.") + exit + end if + + if (.not. isvar("fcst_len_hrs")) then + print("") + print("The forecast length (fcst_len_hrs) has not been specified:") + print(" isvar(" + char_dq + "fcst_len_hrs" + char_dq + ") = " + isvar("fcst_len_hrs")) + print("Stopping.") + exit + end if + + if (.not. isvar("BC_interval_hrs")) then + print("") + print("The boundary condition time interval (BC_interval_hrs) has not been specified:") + print(" isvar(" + char_dq + "BC_interval_hrs" + char_dq + ") = " + isvar("BC_interval_hrs")) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Check that the forecast length (fcst_len_hrs) and the time interval +; between boundary condition updates (BC_interval_hrs) are both inte- +; gers. If not, print out a warning and exit. Note that fcst_len_hrs +; and BC_interval_hrs are assumed to have units of hours. +; * +; ********************************************************************** +; + if (.not. isinteger(fcst_len_hrs)) then + print("") + print("The forecast length (fcst_len_hrs) must be an integer (in units of hours):") + print(" fcst_len_hrs = " + fcst_len_hrs) + print(" isinteger(fcst_len_hrs) = " + isinteger(fcst_len_hrs)) + print("Stopping.") + exit + end if + + if (.not. isinteger(BC_interval_hrs)) then + print("") + print("The boundary condition time interval (BC_interval_hrs) must be an integer (in units of hours):") + print(" BC_interval_hrs = " + BC_interval_hrs) + print(" isinteger(BC_interval_hrs) = " + isinteger(BC_interval_hrs)) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; +if (False) then + if (.not. isvar("plot_subregs")) then + plot_subregs = False + end if + + if (plot_subregs) then + + if ((.not. isvar("subreg_names")) .or. \ + (.not. isvar("subreg_coords"))) then + print("") + print("When plot_subregs is set to True, the arrays subreg_names " + \ + "and subreg_coords " + char_nl + \ + "must both be specified:") + print(" plot_subregs = " + plot_subregs) + print(" isvar(subreg_names) = " + isvar("subreg_names")) + print(" isvar(subreg_coords) = " + isvar("subreg_coords")) + print("Stopping.") + exit + end if + + dims_subreg_names = dimsizes(subreg_names) + numel_subreg_names = dims_subreg_names(0) + dims_subreg_coords = dimsizes(subreg_coords) + left_dim_subreg_coords = dims_subreg_coords(0) + if (numel_subreg_names .ne. left_dim_subreg_coords) then + print("") + print("When plot_subregs is set to True, the number of elements " + \ + "in subreg_names must " + char_nl + \ + "be equal to the size of the leftmost dimension of subreg_coords:") + print(" plot_subregs = " + plot_subregs) + print(" numel_subreg_names = " + numel_subreg_names) + print(" left_dim_subreg_coords = " + left_dim_subreg_coords) + print("Stopping.") + exit + end if + + num_subregions = numel_subreg_names + + else + + num_subregions = 1 + + end if +end if + + + + + if (.not. isvar("regions")) then + regions=[/ [/ "globe", (/-180, 180, -90, 90/), True, True /] /] + end if + + + + num_regions = ListCount(regions) - 1 + region_names = new((/ num_regions /), "string") + region_bounds = new((/ num_regions, 4 /), "float") +; region_draw_RAP_grid = new((/ num_regions /), "logical") +; region_draw_FV3LAM_grid = new((/ num_regions /), "logical") + draw_grid_by_region = True + draw_grid_by_region@RAP = new((/ num_regions /), "logical") + draw_grid_by_region@FV3LAM = new((/ num_regions /), "logical") + + do i=0, num_regions-1 +;print("") +;print("i = " + i) + curnt_region := regions[i] +;print(curnt_region) + region_names(i) = curnt_region[0] + region_bounds(i,:) = curnt_region[1] +; region_draw_RAP_grid(i) = curnt_region[2] +; region_draw_FV3LAM_grid(i) = curnt_region[3] + draw_grid_by_region@RAP(i) = curnt_region[2] + draw_grid_by_region@FV3LAM(i) = curnt_region[3] +;pause + end do + +;print("") +;print(region_names) +;print("") +;print(region_bounds) +;print("") +;;print(region_draw_RAP_grid) +;print(draw_grid_by_region@RAP) +;print("") +;;print(region_draw_FV3LAM_grid) +;print(draw_grid_by_region@FV3LAM) +;pause + + + + + + +print("") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("Reading in RAP grid...") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("") + +; +; ********************************************************************** +; * +; Read in the RAP grid. +; * +; ********************************************************************** +; + file_dir = "./" +;file_dir = "/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509" + + RAP_geo_file = "geo_em.d01.RAP.nc" + RAP_geo_file = file_dir + "/" + RAP_geo_file + + out := read_RAP_grid(RAP_geo_file) + + nx_RAP = out@nx + ny_RAP = out@ny +; num_cells_RAP = out@num_cells +; lon_cntrs_by_cell_RAP = out@lon_cntrs_by_cell +; lat_cntrs_by_cell_RAP = out@lat_cntrs_by_cell +; lon_verts_by_cell_RAP = out@lon_verts_by_cell +; lat_verts_by_cell_RAP = out@lat_verts_by_cell + +; lon_min = -180.0 +; lon_cntrs_by_cell_RAP := adjust_longitude_range( \ +; lon_cntrs_by_cell_RAP, lon_min, "degs") +; exit + + lon_cntrs_by_cell = True + lat_cntrs_by_cell = True + lon_verts_by_cell = True + lat_verts_by_cell = True + field_by_cell = True + + + lon_cntrs_by_cell@RAP = out@lon_cntrs_by_cell + lat_cntrs_by_cell@RAP = out@lat_cntrs_by_cell + lon_verts_by_cell@RAP = out@lon_verts_by_cell + lat_verts_by_cell@RAP = out@lat_verts_by_cell + + +print("") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("Reading in FV3LAM grid...") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("") + +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; +; nh = 4 + nh = 50 + +; FV3LAM_grid_dir = "/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/fv3gfs/fix/fix_fv3/rgnl_C384_strch_1p8_rfn_5_HRRR" + FV3LAM_grid_dir = "/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/work_dirs/rgnl_C384_strch_1p5_rfn_3_descriptive_str/filter_topo" + CRES = "C384" + FV3LAM_halo4_grid_file = CRES + "_grid.tile7.halo4.nc" + FV3LAM_halo4_grid_file_full = FV3LAM_grid_dir + "/" + FV3LAM_halo4_grid_file + + out := read_FV3LAM_grid_halo(FV3LAM_halo4_grid_file_full, nh) + +;; num_cells_FV3LAM = out@num_cells_total +; lon_cntrs_by_cell_FV3LAM = out@lon_cntrs_by_cell +; lat_cntrs_by_cell_FV3LAM = out@lat_cntrs_by_cell +; lon_verts_by_cell_FV3LAM = out@lon_verts_by_cell +; lat_verts_by_cell_FV3LAM = out@lat_verts_by_cell + + lon_cntrs_by_cell@FV3LAM = out@lon_cntrs_by_cell + lat_cntrs_by_cell@FV3LAM = out@lat_cntrs_by_cell + lon_verts_by_cell@FV3LAM = out@lon_verts_by_cell + lat_verts_by_cell@FV3LAM = out@lat_verts_by_cell + + + + + + + + + + + +print("") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("Looping over all RAP output times and RAP fields...") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("") + +; +; ********************************************************************** +; * +; Read in the RAP wrfout file for a specified output time. +; * +; ********************************************************************** +; + RAP_output_dir := "." + + YYYY = str_get_cols((/CDATE/), 0, 3) + MM = str_get_cols((/CDATE/), 4, 5) + DD = str_get_cols((/CDATE/), 6, 7) + HH = str_get_cols((/CDATE/), 8, 9) + + RAP_init_date := YYYY + "-" + MM + "-" + DD + RAP_init_hr := HH +print("") +print("RAP_init_date = " + RAP_init_date) +print("RAP_init_hr = " + RAP_init_hr) + + remainder = fcst_len_hrs % BC_interval_hrs + if (remainder .ne. 0) then + print("") + print("Error. The forecast length is not evenly divisible by the BC time interval:") + print(" fcst_len_hrs = " + fcst_len_hrs + " hrs") + print(" BC_interval_hrs = " + BC_interval_hrs + " hrs") + print(" remander = fcst_len_hrs % BC_interval_hrs = " + remainder) + print("Exiting script.") + exit + else + RAP_fcst_hrs := ispan(0, fcst_len_hrs, BC_interval_hrs) + end if +print("") +print("RAP_fcst_hrs = " + RAP_fcst_hrs) + + RAP_fcst_hrs@units = "hours since " + RAP_init_date + " " + RAP_init_hr + ":00:00" +print("") +print("RAP_fcst_hrs@units = " + RAP_fcst_hrs@units) + RAP_fcst_dates_times = cd_string(RAP_fcst_hrs, "%Y-%N-%D_%H_%M_%S") +print("") +print("RAP_fcst_dates_times = " + RAP_fcst_dates_times) + num_RAP_output_times := dimsizes(RAP_fcst_dates_times) + +; RAP_field_names := (/ "T", "VAR_SSO" /) +; RAP_field_names := (/ "T", "PSFC" /) +; RAP_field_names := (/ "PSFC" /) +; RAP_field_names := (/ "T" /) + RAP_field_names := (/ "VAR_SSO" /) + + num_RAP_fields := dimsizes(RAP_field_names) + +; RAP_vert_levels = (/ 5, 10 /) + RAP_vert_levels = (/ 5 /) + num_RAP_levels := dimsizes(RAP_vert_levels) + + do n=0, num_RAP_output_times-1 + + fcst_hr := RAP_fcst_hrs(n) + + RAP_fcst_date_time = RAP_fcst_dates_times(n) + wrfout_file = RAP_output_dir + "/wrfout_d01_" + RAP_fcst_date_time + ".nc" + f_wrfout = addfile(wrfout_file, "r") +; +; ********************************************************************** +; * +; Loop over fields. +; * +; ********************************************************************** +; + do f=0, num_RAP_fields-1 + + field_name := RAP_field_names(f) +; +; ********************************************************************** +; * +; Check whether the specified field exists in the specified file. If +; not, print out a message and exit script. +; * +; ********************************************************************** +; + if (.not. isfilevar(f_wrfout, field_name)) then + print("") + print("Specified field does not exist in specified file:") + print(" field_name = " + field_name) + print(" wrfout_file = " + wrfout_file) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Get the current field's dimension names and dimension sizes. Then +; calculate its rank (i.e. the number of dimensions). +; * +; ********************************************************************** +; + field_dim_names := getfilevardims(f_wrfout, field_name) +; field_dim_sizes := getfilevardimsizes(f_wrfout, field_name) + field_rank := dimsizes(field_dim_names) +; +; ********************************************************************** +; * +; Determine whether field is a function of time, altitude, latitude, +; and/or longitude. +; * +; ********************************************************************** +; + func_t = False + func_z = False + func_y = False + func_x = False + + do d=0, field_rank-1 + + dim_name = field_dim_names(d) + + idx := str_match_ind(dim_name, "Time") + if (.not. ismissing(idx)) then + func_t = True + end if + + idx1 := str_match_ind(dim_name, "bottom_top") + idx2 := str_match_ind(dim_name, "bottom_top_stag") + if ((.not. ismissing(idx1)) .or. (.not. ismissing(idx2))) then + func_z = True + end if + + idx1 := str_match_ind(dim_name, "south_north") + idx2 := str_match_ind(dim_name, "south_north_stag") + if ((.not. ismissing(idx1)) .or. (.not. ismissing(idx2))) then + func_y = True + end if + + idx1 := str_match_ind(dim_name, "west_east") + idx2 := str_match_ind(dim_name, "west_east_stag") + if ((.not. ismissing(idx1)) .or. (.not. ismissing(idx2))) then + func_x = True + end if + + end do + +;print("") +;print("func_t = " + func_t) +;print("func_z = " + func_z) +;print("func_y = " + func_y) +;print("func_x = " + func_x) +;pause + +; +; ********************************************************************** +; * +; For a field that is not a function of altitude (e.g. a 2-D field), we +; set the the number of RAP vertical levels to consider to 1 (as opposed +; to the number of levels specified in the array RAP_vert_levels above). +; * +; ********************************************************************** +; + kk_max = num_RAP_levels + if (.not. func_z) then + kk_max = 1 + end if +; +; ********************************************************************** +; * +; Loop over all relevant vertical levels. +; * +; ********************************************************************** +; + do kk=0, kk_max-1 + + k = RAP_vert_levels(kk) + if (.not. func_z) then + k = -1 + end if +print("") +print("field_name = " + field_name + "; k = " + k) +pause + print_field_stats = True + out := read_RAP_horiz_field( \ + f_wrfout, field_name, func_z, k, print_field_stats) + + field_desc = out@field_desc + field_units = out@field_units + field_by_cell@RAP = out@field_by_cell +; field_min_RAP = out@field_min +; field_max_RAP = out@field_max + + + + + + + + + + + + + + + + + + + + + +print("") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("Interpolating RAP field onto halo of FV3LAM regional domain...") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("") + +; +; ********************************************************************** +; * +; The flag gen_weights determines whether NetCDF file containing the in- +; terpolation weights will be generated along with NetCDF files describ- +; ing the source (i.e. RAP) and destination (i.e. latlon) grids. The +; names of these files are specified by opt@WgtFileName, opt@SrcFile- +; Name, and opt@DstFileName, respectively. If gen_weights is set to +; False on the command line, these three files must already exist in or- +; der for the ESMF interpolation to work; otherwise, the interpolation +; will fail. If gen_weights is set to True on the command line, these +; files will be regenerated whether or not they already exist. Finally, +; if gen_weights is not yet specified (e.g. somewhere above or on the +; command line), the "if" statement below will set it to False if all +; three NetCDF files already exist and to True otherwise. +; * +; ********************************************************************** +; +; gen_weights = True + gen_weights = False + + src_grid_filename = "src_grid_RAP.nc" + dst_grid_filename = "dst_grid_FV3LAMhalo" + nh + ".nc" + weights_filename = "weights_RAP_to_FV3LAMhalo" + nh + ".nc" + + print("") + print("Source grid, destination grid, and weights files are:") + print(" src_grid_filename = " + src_grid_filename) + print(" dst_grid_filename = " + dst_grid_filename) + print(" weights_filename = " + weights_filename) + + if (.not. isvar("gen_weights")) then + + if (fileexists(src_grid_filename) .and. \ + fileexists(dst_grid_filename) .and. \ + fileexists(weights_filename)) then + print("") + print("Source grid (RAP), destination grid (FV3LAM), and " + \ + "weights files " + char_nl + \ + "already exist. Not regenerating these files.") + gen_weights = False + else + print("") + print("Source grid (RAP), destination grid (FV3LAM), and/or " + \ + "weights file do " + char_nl + \ + "not exist and must be generated.") + gen_weights = True + end if + + end if + + if (.not. gen_weights .and. \ + (.not. fileexists(src_grid_filename) .or. \ + .not. fileexists(dst_grid_filename) .or. \ + .not. fileexists(weights_filename))) then + print("") + print("gen_weights has been set to True, but the source grid (RAP) " + \ + "file, the destination " + char_nl + \ + "grid (FV3LAM) file, and/or the weights file does/do not exist:") + print(" fileexists(src_grid_filename) = " + fileexists(src_grid_filename)) + print(" fileexists(dst_grid_filename) = " + fileexists(dst_grid_filename)) + print(" fileexists(weights_filename) = " + fileexists(weights_filename)) + print("Set gen_weights to True and rerun.") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Perform interpolation (regridding) of the field on the RAP grid to the +; halo of the FV3LAM grid. +; * +; ********************************************************************** +; +; out := interpolate_RAP_to_FV3LAM( \ +; lon_cntrs_by_cell_RAP, lat_cntrs_by_cell_RAP, \ +; lon_verts_by_cell_RAP, lat_verts_by_cell_RAP, \ +; lon_cntrs_by_cell_FV3LAM, lat_cntrs_by_cell_FV3LAM, \ +; lon_verts_by_cell_FV3LAM, lat_verts_by_cell_FV3LAM, \ +; field_by_cell_RAP, \ +; gen_weights, \ +; src_grid_filename, dst_grid_filename, weights_filename) + + out := interpolate_RAP_to_FV3LAM( \ + lon_cntrs_by_cell@RAP, lat_cntrs_by_cell@RAP, \ + lon_verts_by_cell@RAP, lat_verts_by_cell@RAP, \ + lon_cntrs_by_cell@FV3LAM, lat_cntrs_by_cell@FV3LAM, \ + lon_verts_by_cell@FV3LAM, lat_verts_by_cell@FV3LAM, \ + field_by_cell@RAP, \ + gen_weights, \ + src_grid_filename, dst_grid_filename, weights_filename) + + field_by_cell@FV3LAM = out@field_by_cell_FV3LAM +; +; ********************************************************************** +; * +; Calculate and print out basic statistics of the regridded field on the +; FV3LAM grid. +; * +; ********************************************************************** +; + print_field_stats = True + out := calc_field_stats( \ + field_by_cell@FV3LAM, field_desc, field_units, print_field_stats) +; field_min_FV3LAM = out@field_min +; field_max_FV3LAM = out@field_max + + + + + + + + + + + + + + + + + + +; +; ********************************************************************** +; * +; If plot_RAP_fields or plot_FV3LAM_fields is set to True, plot the +; * +; ********************************************************************** +; + if (plot_RAP_fields .or. plot_FV3LAM_fields) then + +print("") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("Plotting RAP and/or (interpolated) FV3LAM fields...") +print("") +print("==============================================================") +print("==============================================================") +print("") +print("") + + fn_graphics_base := field_name + if (func_z) then + fn_graphics_base = fn_graphics_base + "_k" + k + end if + if (func_t) then + fn_graphics_base = fn_graphics_base + "_t" + fcst_hr + "hr" + end if + + num_cnLevels = 10 + + plot_options_common := True + plot_options_common@fn_graphics_base = fn_graphics_base + plot_options_common@num_cnLevels = num_cnLevels +; +; Set the flag that determines whether plots will be resized (e.g. to a +; larger area than the default). This would generally be done using the +; gsnMaximize resource, but it's not clear how to use or reset this re- +; source after adding annotations to the plot (annotations in our case +; are the plot titles). Thus, we perform the resizing/maximization man- +; ually. +; + plot_options_common@resize_plot = True +; +; Set the size (either width or height) of the bounding box which the +; resized plot will have. Note that this is in NDC (non-dimensional co- +; ordinate, aka page) coordinates. This value must be between 0 and 1. +; + plot_options_common@bounding_box_size_NDC = 0.98 + + if (isvar("map_proj")) then + plot_options_common@map_proj := map_proj + end if + + if (isvar("map_proj_ctr")) then + plot_options_common@map_proj_ctr := map_proj_ctr + end if +; +; ********************************************************************** +; * +; Loop over the regions to plot. +; * +; ********************************************************************** +; + do s=0,num_regions-1 + + plot_options := plot_options_common + + plot_options@region_name = region_names(s) + plot_options@lon_min = region_bounds(s,0) + plot_options@lon_max = region_bounds(s,1) + plot_options@lat_min = region_bounds(s,2) + plot_options@lat_max = region_bounds(s,3) +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + if (plot_RAP_fields) then + + model_name = "RAP" + + out := plot_model_field_generic( \ + model_name, \ + lon_cntrs_by_cell@RAP, lat_cntrs_by_cell@RAP, \ + lon_verts_by_cell@RAP, lat_verts_by_cell@RAP, \ + field_by_cell@RAP, \ + field_name, field_desc, field_units, \ + func_t, func_z, \ + fcst_hr, k, \ + draw_grid_by_region@RAP(s), \ + plot_options) + + copy_VarAtts(out, plot_options) + + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + if (plot_FV3LAM_fields) then + + model_name = "FV3LAM" + + out := plot_model_field_generic( \ + model_name, \ + lon_cntrs_by_cell@FV3LAM, lat_cntrs_by_cell@FV3LAM, \ + lon_verts_by_cell@FV3LAM, lat_verts_by_cell@FV3LAM, \ + field_by_cell@FV3LAM, \ + field_name, field_desc, field_units, \ + func_t, func_z, \ + fcst_hr, k, \ + draw_grid_by_region@FV3LAM(s), \ + plot_options) + + end if + + end do + + end if + + + + end do + + end do + + end do + + +end + + diff --git a/ush/NCL/NCL_ICs_BCs/get_rect_grid_bdy.ncl b/ush/NCL/NCL_ICs_BCs/get_rect_grid_bdy.ncl new file mode 100644 index 0000000000..f36f0c94c5 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/get_rect_grid_bdy.ncl @@ -0,0 +1,190 @@ +; ********************************************************************** +; +; File name: get_rect_grid_bdy.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns 1-D arrays containing the 2-D coordinates (say x +; and y) of the points (cells) along the boundary of the rectangular +; grid specified by the given arrays. +; * +; ********************************************************************** + +load "special_chars.ncl" +load "strcmp.ncl" + +undef("get_rect_grid_bdy") + +function get_rect_grid_bdy( \ + x_coords:snumeric, y_coords:snumeric, \ + repeat_last_point:logical, array_order:string) + +local x, y, dims, nx, ny, x_bdy, y_bdy, i, j, out + +begin +; +; ********************************************************************** +; +; Check that array_order has a valid value. +; +; ********************************************************************** +; + if (.not. strcmp(array_order, "ij") .and. \ + .not. strcmp(array_order, "ji")) then + print("") + print("The input argument array_order must be set to either " + \ + char_dq + "ji" + char_dq + " or " + \ + char_dq + "ij" + char_dq + ":") + print(" array_order = " + char_dq + array_order + char_dq) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; The code below assumes that the coordinate arrays use the index order +; (j,i) [as opposed to (i,j)]. Thus, if the given arrays use the order +; (i,j), transpose them to get back to (j,i) order. +; +; ********************************************************************** +; + x = x_coords + y = y_coords + if (strcmp(array_order, "ij")) then + x = transpose(x) + y = transpose(y) + end if +; +; ********************************************************************** +; +; Get the dimensions of the coordinate arrays and check that they are +; identical. +; +; ********************************************************************** +; + dims_x = dimsizes(x) + dims_y = dimsizes(y) + + dims_are_equal = (dims_x .eq. dims_y) + if (.not. all(dims_are_equal)) then + dims_x_str = str_join(tostring(dims_x), ", ") + dims_y_str = str_join(tostring(dims_y), ", ") + print("") + print("The dimensions of the x-coordinate array do not match those of the y-coordinate array:") + print(" dims_x = (" + dims_x_str + ")") + print(" dims_y = (" + dims_y_str + ")") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; For convenience, set nx and ny to the number of grid points in the x +; and y directions, respectively. +; +; ********************************************************************** +; + nx = dims_x(1) + ny = dims_x(0) +; +; ********************************************************************** +; +; Create 1-D arrays to hold the x and y coordinates of the boundary +; points of the grid. Note that initially, these arrays will contain +; only one element; more elements will be appended later below. +; +; ********************************************************************** +; + x_bdy := new((/1/), typeof(x)) + y_bdy := new((/1/), typeof(y)) +; +; ********************************************************************** +; +; Copy in the coordinates of the point at (i,j) = (0,0). +; +; ********************************************************************** +; + i = 0 + j = 0 + x_bdy(0) = x(j,i) + y_bdy(0) = y(j,i) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "southern" boundary +; (j = 0). +; +; ********************************************************************** +; + j = 0 + x_bdy := array_append_record(x_bdy, x(j,1:), 0) + y_bdy := array_append_record(y_bdy, y(j,1:), 0) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "eastern" boundary +; (i = nx). +; +; ********************************************************************** +; + i = nx - 1 + x_bdy := array_append_record(x_bdy, x(1:,i), 0) + y_bdy := array_append_record(y_bdy, y(1:,i), 0) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "northern" boundary +; (j = ny). Note that in specifying the i-index range [i.e. (nx-1:0)], +; we do not specify a negative stride, i.e. we do not use (nx-1:0:-1), +; because in NCL, the order of the elements is automatically reversed if +; the starting index is larger than the ending index. +; +; ********************************************************************** +; + j = ny - 1 + x_bdy := array_append_record(x_bdy, x(j,nx-2:0), 0) + y_bdy := array_append_record(y_bdy, y(j,nx-2:0), 0) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "western" boundary +; (i = 0). Note that in specifying the j-index range [i.e. (ny-1:1)], +; we do not specify a negative stride, i.e. we do not use (ny-1:1:-1), +; because in NCL, the order of the elements is automatically reversed if +; the starting index is larger than the ending index. +; +; ********************************************************************** +; + i = 0 + x_bdy := array_append_record(x_bdy, x(ny-2:1,i), 0) + y_bdy := array_append_record(y_bdy, y(ny-2:1,i), 0) +; +; ********************************************************************** +; +; If repeat_last_point is set to True, repeat the first point on the +; boundary again as the last point. This is done so that if a polyline +; object is used to plot the tile boundary, the boundary closes on it- +; self. +; +; ********************************************************************** +; + if (repeat_last_point) then + x_bdy := array_append_record(x_bdy, (/ x_bdy(0) /), 0) + y_bdy := array_append_record(y_bdy, (/ y_bdy(0) /), 0) + end if +; +; ********************************************************************** +; * +; Return the arrays containing the coordinates of the boundary points as +; as attributes of the "out" variable. +; * +; ********************************************************************** +; + out := True + out@x_bdy = x_bdy + out@y_bdy = y_bdy + return(out) + +end + diff --git a/ush/NCL/NCL_ICs_BCs/get_resized_viewport_dims.ncl b/ush/NCL/NCL_ICs_BCs/get_resized_viewport_dims.ncl new file mode 100644 index 0000000000..32db919c03 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/get_resized_viewport_dims.ncl @@ -0,0 +1,230 @@ +; ********************************************************************** +; +; File name: get_resized_viewport_dims.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function +; * +; ********************************************************************** + +undef("get_resized_viewport_dims") + +function get_resized_viewport_dims( \ + plot:graphic, + bb_size_new:snumeric, \ + opts:logical) + +local char_dq, char_nl, verbose, \ + bb_old, bb_top_old, bb_bot_old, bb_lft_old, bb_rgt_old, \ + bb_width_old, bb_height_old, \ + bb_new, bb_top_new, bb_bot_new, bb_lft_new, bb_rgt_new, \ + bb_width_new, bb_height_new, \ + vpXF_old, vpYF_old, vpWidthF_old, vpHeightF_old, \ + vpXF_new, vpYF_new, vpWidthF_new, vpHeightF_new, \ + dx_old, dy_old, dx_new, dy_new, \ + x_ratio_new_to_old, y_ratio_new_to_old, \ + out + +begin +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; + char_dq = integertochar(34) + char_nl = str_get_nl() +; +; ********************************************************************** +; * +; The local variable "verbose" determines whether informational messag- +; es are printed out to the screen. If the options argument opts has an +; attribute named verbose, then set the local variable verbose to this +; attribute. Otherwise, set verbose to False. +; * +; ********************************************************************** +; + if (isatt(opts, "verbose")) then + verbose = opts@verbose + else + verbose = False + end if + + if (verbose) then + print("") + print("Start of output from function get_resized_viewport_dims(...):") + print("=======================================================") + end if +; +; ********************************************************************** +; * +; Check that bb_size_new has a valid value. +; * +; ********************************************************************** +; + if ((bb_size_new .lt. 0) .or. (bb_size_new .gt. 1)) then + print("") + print("Error: The bounding box size of the resized plot " + \ + "(bb_size_new) must be " + char_nl + \ + "between 0 and 1:") + print(" bb_size_new = " + bb_size_new) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Get the NDC coordinates of the bounding box of the original plot. +; * +; ********************************************************************** +; + bb_old = NhlGetBB(plot) + bb_top_old = bb_old(0) + bb_bot_old = bb_old(1) + bb_lft_old = bb_old(2) + bb_rgt_old = bb_old(3) + + if (verbose) then + print("") + print("bb_top_old = " + bb_top_old) + print("bb_bot_old = " + bb_bot_old) + print("bb_lft_old = " + bb_lft_old) + print("bb_rgt_old = " + bb_rgt_old) + end if +; +; ********************************************************************** +; * +; Calculate the NDC width and height of the bounding box of the original +; (old) plot. +; +; Note that a bounding box is the smallest rectangle in NDC space that +; contains all of a particular object's attributes. For a 2-D XY or +; contour plot (which is what we're considering here), this would in- +; clude the area containing the tickmarks, tickmark labels, the main +; title, axis titles, legend, and anything else associated with the +; plot. This is in contrast to the viewport (which we will also consi- +; der below), which contains only the area within the axes. See +; +; https://www.ncl.ucar.edu/Applications/viewport.shtml +; +; for examples. +; * +; ********************************************************************** +; + bb_width_old = bb_rgt_old - bb_lft_old + bb_height_old = bb_top_old - bb_bot_old +; +; ********************************************************************** +; * +; Set or calculate the NDC width, height, and coordinates of the bound- +; ing box of the new resized plot. +; * +; ********************************************************************** +; + if (bb_width_old .le. bb_height_old) then + bb_height_new = bb_size_new + bb_width_new = (bb_width_old/bb_height_old)*bb_height_new + else + bb_width_new = bb_size_new + bb_height_new = (bb_height_old/bb_width_old)*bb_width_new + end if + bb_lft_new = (1 - bb_width_new)/2.0 + bb_rgt_new = bb_lft_new + bb_width_new + bb_top_new = (1 + bb_height_new)/2.0 + bb_bot_new = bb_top_new - bb_height_new + + if (verbose) then + print("") + print("bb_width_old = " + bb_width_old) + print("bb_height_old = " + bb_height_old) + print("bb_width_new = " + bb_width_new) + print("bb_height_new = " + bb_height_new) + print("bb_lft_new = " + bb_lft_new) + print("bb_top_new = " + bb_top_new) + end if +; +; ********************************************************************** +; * +; Get the NDC coordinates of the top left point of the viewport of the +; original plot and the NDC width and height of the original plot. +; * +; ********************************************************************** +; + getvalues plot + "vpXF" : vpXF_old + "vpYF" : vpYF_old + "vpWidthF" : vpWidthF_old + "vpHeightF" : vpHeightF_old + end getvalues + + if (verbose) then + print("") + print("vpXF_old = " + vpXF_old) + print("vpYF_old = " + vpYF_old) + print("vpWidthF_old = " + vpWidthF_old) + print("vpHeightF_old = " + vpHeightF_old) + end if +; +; ********************************************************************** +; * +; Calculate the NDC coordinates of the top left point of the viewport of +; the new (resized) plot and the NDC width and height of the new plot. +; +; Recall that the bounding box is larger than the viewport; in particu- +; lar, it includes the viewport as well as the axis titles, plot title, +; etc. Thus, the variables dx_old and dy_old calculated below are the +; horizontal and vertical offsets in the original plot from the bounda- +; ries of the bounding box to those of the viewport, and dx_new and dy_- +; new are the analogous quantities for the new (resized) plot. +; * +; ********************************************************************** +; + dx_old = vpXF_old - bb_lft_old + dy_old = bb_top_old - vpYF_old + + x_ratio_new_to_old = bb_width_new/bb_width_old + y_ratio_new_to_old = bb_height_new/bb_height_old + + dx_new = dx_old*x_ratio_new_to_old + dy_new = dy_old*y_ratio_new_to_old + + vpXF_new = bb_lft_new + dx_new + vpYF_new = bb_top_new - dy_new + + vpWidthF_new = vpWidthF_old*x_ratio_new_to_old + vpHeightF_new = vpHeightF_old*y_ratio_new_to_old +; +; ********************************************************************** +; * +; Resize the plot to its new size by changing its viewport coordinates. +; +; Apparently, can't maximize from within function. Not sure why. +; * +; ********************************************************************** +; +; setvalues plot +; "vpXF" : vpXF_new +; "vpYF" : vpYF_new +; "vpWidthF" : vpWidthF_new +; "vpHeightF" : vpHeightF_new +; end setvalues +; +; ********************************************************************** +; * +; Return viewport of new plot. +; * +; ********************************************************************** +; + out := True + out@vpXF = vpXF_new + out@vpYF = vpYF_new + out@vpWidthF = vpWidthF_new + out@vpHeightF = vpHeightF_new + return(out) + +end + + diff --git a/ush/NCL/NCL_ICs_BCs/interpolate_RAP_to_FV3LAM.ncl b/ush/NCL/NCL_ICs_BCs/interpolate_RAP_to_FV3LAM.ncl new file mode 100644 index 0000000000..c3c4a3d004 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/interpolate_RAP_to_FV3LAM.ncl @@ -0,0 +1,155 @@ +; ********************************************************************** +; +; File name: interpolate_RAP_to_FV3LAM.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function interpolates (regrids) a field on the RAP grid to the +; halo of the FV3-LAM grid. +; * +; ********************************************************************** + +undef("interpolate_RAP_to_FV3LAM") + +function interpolate_RAP_to_FV3LAM( \ + lon_cntrs_by_cell_RAP:snumeric, \ + lat_cntrs_by_cell_RAP:snumeric, \ + lon_verts_by_cell_RAP:snumeric, \ + lat_verts_by_cell_RAP:snumeric, \ + lon_cntrs_by_cell_FV3LAM:snumeric, \ + lat_cntrs_by_cell_FV3LAM:snumeric, \ + lon_verts_by_cell_FV3LAM:snumeric, \ + lat_verts_by_cell_FV3LAM:snumeric, \ + field_by_cell_RAP:snumeric, \ + gen_weights:logical, \ + src_grid_filename:string, dst_grid_filename:string, weights_filename:string) + +local opt, field_by_cell_FV3LAM, out + +begin +; +; ********************************************************************** +; * +; If gen_weights is set to True, call the function ESMF_regrid(...) to +; generate a set of weights and interpolate the specified field from the +; RAP to the FV3-LAM grid. The ESMF_regrid(...) function will also save +; the weights it generates in the specified file (opt@WgtFileName), and +; it will save descriptions of the source (RAP) and destination (FV3-LAM) +; grids in two additional NetCDF files (opt@SrcFileName and opt@ Dst- +; FileName, respectively). +; * +; ********************************************************************** +; + if (gen_weights) then +; +; ********************************************************************** +; * +; Create the variable whose attributes will contain the options to be +; passed to NCL's ESMF (Earth System Modeling Framework) regridding +; functions below. Then set some of its attributes. +; * +; ********************************************************************** +; + opt = True + +; If output files already exist, allow them to be overwritten. + opt@ForceOverwrite = True + +; Turn debugging messages on in the calls to ESMF regridding functions. + opt@Debug = True + +; Print the CPU time spent in the individual ESMF routines. + opt@PrintTimings = True +; +; ********************************************************************** +; * +; Set the source grid type and specify the coordinates of the source +; grid's cell centers and corners. +; * +; ********************************************************************** +; + opt@SrcGridType = "unstructured" +; + opt@SrcGridLon = lon_cntrs_by_cell_RAP + opt@SrcGridLat = lat_cntrs_by_cell_RAP +; + opt@SrcGridCornerLon = lon_verts_by_cell_RAP + opt@SrcGridCornerLat = lat_verts_by_cell_RAP +; +; ********************************************************************** +; * +; Set the destination grid type and specify the coordinates of the des- +; tination grid's cell centers and corners. +; * +; ********************************************************************** +; + opt@DstGridType = "unstructured" +; + opt@DstGridLon = lon_cntrs_by_cell_FV3LAM + opt@DstGridLat = lat_cntrs_by_cell_FV3LAM +; + opt@DstGridCornerLon = lon_verts_by_cell_FV3LAM + opt@DstGridCornerLat = lat_verts_by_cell_FV3LAM +; +; ********************************************************************** +; * +; Set the names of the source and destination grid description files +; and the name of the interpolation weights file. +; * +; ********************************************************************** +; + opt@SrcFileName = src_grid_filename + opt@DstFileName = dst_grid_filename + opt@WgtFileName = weights_filename + +print("") +print("opt@SrcFileName = " + opt@SrcFileName) +print("opt@DstFileName = " + opt@DstFileName) +print("opt@WgtFileName = " + opt@WgtFileName) + + print("") + print("Generating source grid (RAP), destination grid " + \ + "(FV3-LAM), and weights file and regridding field " + \ + "to destination (FV3-LAM) grid...") + field_by_cell_FV3LAM = ESMF_regrid(field_by_cell_RAP, opt) +; +; ********************************************************************** +; * +; If gen_weights is set to False, call the function ESMF_regrid_with_- +; weights(...) to interpolate the specified field from the RAP to the +; FV3-LAM grid using the precomputed weights specified in the file opt@ +; WgtFileName. +; * +; ********************************************************************** +; + else + + print("") + print("Regridding field to destination (FV3-LAM) grid...") + field_by_cell_FV3LAM \ + = ESMF_regrid_with_weights(field_by_cell_RAP, weights_filename, False) + + end if + +print("") +printVarSummary(field_by_cell_FV3LAM) +; +; ********************************************************************** +; * +; Return the interpolated field. This is done as an attribute to the +; "out" variable to allow this function to return additional variables +; in the future (as other attributes of "out"). +; * +; ********************************************************************** +; + out = True + out@field_by_cell_FV3LAM = field_by_cell_FV3LAM + return(out) + +end + + + + + diff --git a/ush/NCL/NCL_ICs_BCs/pause.ncl b/ush/NCL/NCL_ICs_BCs/pause.ncl new file mode 100644 index 0000000000..40550f2b78 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/pause.ncl @@ -0,0 +1,11 @@ +undef("pause") +procedure pause() +local temp +begin + print("Program paused. Press to continue.") +; temp := systemfunc("read ANS; echo $ANS") + temp := systemfunc("read ANS") + print("Continuing ...") +end + + diff --git a/ush/NCL/NCL_ICs_BCs/plot_horiz_field.ncl b/ush/NCL/NCL_ICs_BCs/plot_horiz_field.ncl new file mode 100644 index 0000000000..a37103b3e7 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/plot_horiz_field.ncl @@ -0,0 +1,780 @@ +; ********************************************************************** +; +; File name: plot_horiz_field.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function reads in (a horizontal slice of) the specified RAP field +; from the specified file pointer (which should be pointing at a wrfout +; file). +; * +; ********************************************************************** + +load "strcmp.ncl" +load "special_chars.ncl" +load "get_resized_viewport_dims.ncl" + +undef("plot_horiz_field") + +function plot_horiz_field( \ + lon_cntrs_by_cell:snumeric, \ + lat_cntrs_by_cell:snumeric, \ + lon_verts_by_cell:snumeric, \ + lat_verts_by_cell:snumeric, \ + field_by_cell:snumeric, \ + fn_graphics:string, \ + plot_options:logical) + +local fn_graphics, wks_type, wks, \ + rsrc, \ + out + +begin +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; +; char_dq = integertochar(34) +; char_nl = str_get_nl() +; +; ********************************************************************** +; * +; Line to print out in order to more clearly separate different sections +; of the printout. +; * +; ********************************************************************** +; + separator_line \ + = "##################################################################" +; +; ********************************************************************** +; * +; Set local variables to corresponding attributes of plot_options (if +; those attributes are specified) or to default values. +; * +; ********************************************************************** +; + if (isatt(plot_options, "map_proj")) then + map_proj = plot_options@map_proj + else + map_proj = "cyln" + end if + + if (isatt(plot_options, "map_proj_ctr")) then + map_proj_ctr = plot_options@map_proj_ctr + else + map_proj_ctr = new((/2/), "float") + end if + + if (isatt(plot_options, "draw_grid")) then + draw_grid = plot_options@draw_grid + else + draw_grid = False + end if + +; if (isatt(plot_options, "subreg_name")) then +; plot_subreg = True +; subreg_name = plot_options@subreg_name +; lon_min = plot_options@lon_min +; lon_max = plot_options@lon_max +; lat_min = plot_options@lat_min +; lat_max = plot_options@lat_max +; else +; plot_subreg = False +; end if + +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + idx_cyln := str_match_ind_regex(map_proj, "^" + "cyln" + "$") + idx_ortho := str_match_ind_regex(map_proj, "^" + "ortho" + "$") + idx_lamb := str_match_ind_regex(map_proj, "^" + "lamb" + "$") + + if (ismissing(idx_cyln) .and. \ + ismissing(idx_ortho) .and. \ + ismissing(idx_lamb)) then + + print("") + print("Disallowed value specified for " + char_dq + "map_proj" + \ + char_dq + ":") + print(" map_proj = " + char_dq + map_proj + char_dq) + print("Allowed values are:") + print(" " + char_dq + "cyln" + char_dq + \ + " (for cylindrical-equidistant projection)") + print(" " + char_dq + "ortho" + char_dq + \ + " (for orthographic (i.e. on a sphere) projection)") + print(" " + char_dq + "lamb" + char_dq + \ + " (for Lambert conformal projection)") + print("Please specify one of these allowed values for " + \ + char_dq + "map_proj" + char_dq + ".") + print("Stopping.") + exit + + end if + +; +; ********************************************************************** +; * +; Check whether map_proj_ctr is specified. If not, set it according to +; the specified map projection. Note that this variable is not used for +; the cylindrical-equidistant map projection. +; * +; ********************************************************************** +; + if (.not. ismissing(idx_cyln)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (.not. ismissing(idx_ortho)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (.not. ismissing(idx_lamb)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 90. + end if + end if + end if +; +; ********************************************************************** +; * +; Set workstation file type and dimensions and open the workstation. +; * +; ********************************************************************** +; + wks_type := "png" + wks_type@wkWidth = 1000 + wks_type@wkHeight = 750 + wks := gsn_open_wks(wks_type, fn_graphics) + +; +; Set the colormap. To see the various colormaps, go to: +; +; http://www.ncl.ucar.edu/Document/Graphics/color_table_gallery.shtml +; + gsn_define_colormap(wks, "BlAqGrYeOrReVi200") + + print("") + print("" + separator_line) + print("") + print("Generating plot in graphics file:") + print(" fn_graphics = " + fn_graphics + "." + wks_type) +; +; ********************************************************************** +; * +; Set contour plot resources and generate color contour plot. +; * +; ********************************************************************** +; + +; Specify plot resources. + rsrc = True + +; Maximize size of plot in frame. +; if (.not. isatt(plot_options, "vpXF")) then +; rsrc@gsnMaximize = True +; end if + +; Use full colormap, but start at color index 24. + rsrc@gsnSpreadColors = True + rsrc@gsnSpreadColorStart = 24 + +; Turn on contour fill. + rsrc@cnFillOn = True +; rsrc@cnFillOn = False + +; +; Set the fill mode to "CellFill". This means each cell has a single +; color that represents the field value for that cell, and no interpola- +; tion is performed. Other values for this resource can be "AreaFill" +; and "RasterFill", but those require interoplation. +; + rsrc@cnFillMode = "CellFill" +; rsrc@cnFillMode = "AreaFill" + +; Set sfXArray and sfYArray to the cell center coordinates. + rsrc@sfXArray = lon_cntrs_by_cell + rsrc@sfYArray = lat_cntrs_by_cell + +; Set sfXCellBounds and sfYCellBounds to the cell vertex coordinates. + if (rsrc@cnFillOn .and. strcmp(rsrc@cnFillMode, "CellFill")) then + + rsrc@sfXCellBounds = lon_verts_by_cell + rsrc@sfYCellBounds = lat_verts_by_cell + +; If draw_grid is True, then draw the cell edges. + if (draw_grid) then + rsrc@cnCellFillEdgeColor = "black" + end if + + end if + +; Set sfDataArray to the field (which has one value per cell). + rsrc@sfDataArray = field_by_cell + +; Set the color for cells containing missing values. This is by default +; "transparent", but we repeat it here for clarity. + rsrc@cnMissingValFillColor = "transparent" + +; Specify opacity of cell colors. +; rsrc@cnFillOpacityF = 0.0 ; Transparent. +; rsrc@cnFillOpacityF = 0.1 +; rsrc@cnFillOpacityF = 0.35 + rsrc@cnFillOpacityF = 1.0 ; Opaque. + +; Draw a labelbar (colorbar). + rsrc@lbLabelBarOn = True +; rsrc@lbLabelBarOn = False + +; Do not draw vertical box separator lines in the labelbar (but this +; doesn't turn off the box around the whole label bar). + rsrc@lbBoxSeparatorLinesOn = False + +; Turn off text box that says "CONTOUR FROM AAA TO BBB BY CCC". + rsrc@cnInfoLabelOn = False + +; Make sure the labelbar is fully opaque regardless of what the opacity +; of the contour plot is set to (via the cnFillOcacityF resource). + rsrc@lbOverrideFillOpacity = True +; +; ********************************************************************** +; * +; Set the latitude and longitude of the center of the map projection co- +; ordinate system. +; * +; ********************************************************************** +; + rsrc@mpCenterLonF = map_proj_ctr(0) + rsrc@mpCenterLatF = map_proj_ctr(1) + +; Set the map projection to use. For the Lambert equal-area projection, +; we rotate the projection such that it is centered at the North Pole. + if (.not. ismissing(idx_cyln)) then + rsrc@mpProjection = "CylindricalEquidistant" + else if (.not. ismissing(idx_ortho)) then + rsrc@mpProjection = "Orthographic" + else if (.not. ismissing(idx_lamb)) then +; rsrc@mpProjection = "LambertEqualArea" + rsrc@mpProjection = "LambertConformal" + end if + end if + end if + +; Improve the resolution of the map outlines. Default is "LowRes". + rsrc@mpDataBaseVersion = "MediumRes" +; rsrc@mpDataBaseVersion = "HighRes" + +; Turn on map tickmarks. + rsrc@pmTickMarkDisplayMode = "Always" + +; If "plot_subreg" is specified, plot only a subregion. Note that this has +; an effect only for the cylindrical-equidistant map projection. + + rsrc@mpMinLonF = plot_options@lon_min + rsrc@mpMaxLonF = plot_options@lon_max + rsrc@mpMinLatF = plot_options@lat_min + rsrc@mpMaxLatF = plot_options@lat_max + + if (strcmp(map_proj, "lamb")) then + + rsrc@mpLimitMode = "LatLon" +; rsrc@mpMinLonF = -128 +; rsrc@mpMaxLonF = -70 +; rsrc@mpMinLatF = 20 +; rsrc@mpMaxLatF = 53 + + rsrc@mpLambertParallel1F = 38.5 + rsrc@mpLambertParallel2F = 38.5 + rsrc@mpLambertMeridianF = -97.5 + +; rsrc@mpLimitMode = "Corners" +; rsrc@mpLeftCornerLonF = plot_options@lon_min +; rsrc@mpLeftCornerLatF = plot_options@lat_min +; rsrc@mpRightCornerLonF = plot_options@lon_max +; rsrc@mpRightCornerLatF = plot_options@lat_max + rsrc@mpLeftCornerLonF = -122 + rsrc@mpLeftCornerLatF = 15 + rsrc@mpRightCornerLonF = -65 + rsrc@mpRightCornerLatF = 55 + + end if +; +; ********************************************************************** +; * +; Turn on or off drawing of contour lines. +; +; Note that when cnFillOn is set to True and nFillMode is set to "Cell- +; Fill", setting cnLinesOn to True draws dashed contour lines everywhere +; instead of drawing solid lines for positive contour values and dashed +; lines for negative values (which is the expected behavior). It is not +; clear why this happens. +; * +; ********************************************************************** +; + rsrc@cnLinesOn = True +; rsrc@cnLinesOn = False +; +; ********************************************************************** +; * +; Turn on or off placement of contour line labels. +; +; Note that when cnFillOn is set to True and nFillMode is set to "Cell- +; Fill", setting cnLineLabelsOn to True seems to make no difference, +; i.e. contour line labels are not placed on the contour lines. This +; seems to do with the fact that in this case, the arrays sfXCellBounds +; and sfYCellBounds are defined. +; * +; ********************************************************************** +; + rsrc@cnLineLabelsOn = True +; rsrc@cnLineLabelsOn = False +; +; ********************************************************************** +; * +; Set the background color around contour the line labels. If this co- +; lor is not specified, it seems to default to transparent (which cor- +; responds to color index -1), although the online manual says it's sup- +; posed to default to the background color (color index 0). +; * +; ********************************************************************** +; +; rsrc@cnLineLabelBackgroundColor = "white" + rsrc@cnLineLabelBackgroundColor = "transparent" +; rsrc@cnLineLabelBackgroundColor = 0 +; +; ********************************************************************** +; * +; Explicitly set the labels to use for the contour line labels. These +; will be used only if we are placing labels on the contour lines. We +; set these to the set of labels retruned by the function set_cnLevels_- +; lbLabels(..) (which are the same labels that will be used for the la- +; belbar/colorbar labels). +; * +; ********************************************************************** +; + rsrc@cnExplicitLineLabelsOn = True + rsrc@cnLineLabelStrings = plot_options@lbLabel_strs + +; rsrc@cnMaxDataValueFormat = "*+.6^sg" + + + rsrc@cnLineLabelDensityF = 2.0 +; Want every contour line to be labeled. If we want to label only every +; other contour line, set this to 2, etc. Default is 2. + rsrc@cnLineLabelInterval = 1 + +; +; ********************************************************************** +; * +; Set the method to use for selecting the contour levels. Then set +; other resources accordingly. +; * +; ********************************************************************** +; +; rsrc@cnLevelSelectionMode = "AutomaticLevels" +; rsrc@cnLevelSelectionMode = "ManualLevels" + rsrc@cnLevelSelectionMode = "ExplicitLevels" +; rsrc@cnLevelSelectionMode = "EqualSpacedLevels" ; This should not be used! Investigate further. + + if (strcmp(rsrc@cnLevelSelectionMode, "ManualLevels")) then + rsrc@cnMinLevelValF = plot_options@cnLevel_min + rsrc@cnMaxLevelValF = plot_options@cnLevel_max + rsrc@cnLevelSpacingF = plot_options@cnStep + else if (strcmp(rsrc@cnLevelSelectionMode, "ExplicitLevels")) then + rsrc@cnLevels = plot_options@lbLabel_nums +; else if (strcmp(rsrc@cnLevelSelectionMode, "EqualSpacedLevels")) then +; rsrc@cnMaxLevelCount = plot_options@nLevs +; rsrc@cnMaxLevelCount = 10 + else + print("") + print("Disallowed value specified for the cnLevelSelectionMode attribute of rsrc:") + print("") + print(" rsrc@cnLevelSelectionMode = " + rsrc@cnLevelSelectionMode) + print("") + print("Allowed values are:") + print("") + print(" " + char_dq + "ManualLevels" + char_dq) + print(" " + char_dq + "ExplicitLevels" + char_dq) +; print(" " + char_dq + "EqualSpacedLevels" + char_dq) + print("") + print("Stopping.") + exit + end if + end if +; end if +; +; ********************************************************************** +; * +; Allow the user to explicitly set lbLabelStrings, which specifies the +; set of strings to use as labels for the lablebar (colorbar). Note +; that the flag cnExplicitLabelBarLabelsOn must be set to True in order +; for the plotting routine to use the user-specified value of lbLabel- +; Strings (instead of overwriting it with its own values). Note also +; that the elements of lbLabelStrings may not all appear as labels in +; the plot. This is because by default, the plotting routine ensures +; that these labels do not overlap by skipping every other label, every +; 2 out of 3 labels, etc, as necessary. +; * +; ********************************************************************** +; + rsrc@cnExplicitLabelBarLabelsOn = True + rsrc@lbLabelStrings = plot_options@lbLabel_strs +; +; ********************************************************************** +; * +; Allow for spatially constant fields to be plotted. +; * +; ********************************************************************** +; + rsrc@cnConstFEnableFill = True + rsrc@cnConstFLabelOn = False +; +; ********************************************************************** +; * +; If available (e.g. from a previous call to this function) as attri- +; butes of the plot_options input argument, retrieve the viewport para- +; meters to use for this plot and set them to corresponding attributes +; in rsrc. These viewport values consist of the NDC coordinates of the +; lower-left corner of the viewport and the width and height of the +; viewport (also in NDC units). Note that the viewport for a contour +; plot conists of the rectagle delineated by the x and y axes. If the +; viewport parameters are not specified as attributes of plot_options, +; they will be set by the plotting routine (gsn_csm_contour_map(...)). +; * +; ********************************************************************** +; + if (isatt(plot_options, "vpXF") .and. \ + isatt(plot_options, "vpYF") .and. \ + isatt(plot_options, "vpWidthF") .and. \ + isatt(plot_options, "vpHeightF")) then + rsrc@vpXF = plot_options@vpXF + rsrc@vpYF = plot_options@vpYF + rsrc@vpWidthF = plot_options@vpWidthF + rsrc@vpHeightF = plot_options@vpHeightF + end if +; +; ********************************************************************** +; * +; Do not immediately draw the contour plot nor advance the frame because +; other objects might still need to be added to the plot. +; * +; ********************************************************************** +; + rsrc@gsnDraw = False + rsrc@gsnFrame = False +; +; ********************************************************************** +; * +; Generate (but not yet draw) the color contour plot (along with a map). +; * +; ********************************************************************** +; + map = gsn_csm_contour_map(wks, field_by_cell, rsrc) +; +; ********************************************************************** +; * +; Get the viewport upper-left point coordinates and width and height of +; the plot. Note that the viewport consists only of the region inside +; the contour plot, i.e. it doesn't include the axis labels, labelbar, +; any plot titles, etc. These coordinates and sizes will be used in +; calculating the coordinates of the locations where the plot title +; strings (three of them: a left, a right, and a center string) will be +; placed. +; * +; ********************************************************************** +; + getvalues map + "vpXF" : vpXF + "vpYF" : vpYF + "vpWidthF" : vpWidthF + "vpHeightF" : vpHeightF + end getvalues +; +; ********************************************************************** +; * +; Set the font height and color of the left, right, and center title +; strings. +; * +; ********************************************************************** +; + FontHeightF_LR = 0.01 + FontColor_LR = "black" + + FontHeightF_C = 1.25*FontHeightF_LR + FontColor_C = "black" +; +; ********************************************************************** +; * +; Set the vertical distance (in NDC units) of the offset to use between +; the top of the plot viewport and the bottoms of the left and right +; title strings. We will also use this distance as the offset between +; the top of the left or right title string (whichever is taller) and +; the bottom of the center title string. +; * +; ********************************************************************** +; + dx_vert_offset_ndc = 0.01 +; +; ********************************************************************** +; * +; Set the coordinate of the left and right title strings in coordinates +; normalized with respect to the viewport size. This will be used in +; specifying the location at which the left and right title string will +; be annotated to the plot. +; * +; ********************************************************************** +; + amOrthogonalPosF_LR = -0.5 - dx_vert_offset_ndc*(1.0/vpHeightF) +; +; ********************************************************************** +; * +; Create (using gsn_create_text(...)) and then annotate to the plot +; (using gsn_add_annotation(...)) the left title string. +; * +; ********************************************************************** +; + txres := True + txres@txFontHeightF = FontHeightF_LR + txres@txFontColor = FontColor_LR + txid_left_str = gsn_create_text(wks, plot_options@left_str, txres) + + amres := True + amres@amParallelPosF = -0.5 + amres@amOrthogonalPosF = amOrthogonalPosF_LR + amres@amJust = "BottomLeft" + annotid_left_str = gsn_add_annotation(map, txid_left_str, amres) +; +; Get the viewpoint coordinates and width and height of the text box of +; the left title string. +; + getvalues txid_left_str + "vpXF" : vpXF_left_str + "vpYF" : vpYF_left_str + "vpWidthF" : vpWF_left_str + "vpHeightF" : vpHF_left_str + end getvalues +;print("") +;print("vpXF_left_str = " + vpXF_left_str) +;print("vpYF_left_str = " + vpYF_left_str) +;print("vpWF_left_str = " + vpWF_left_str) +;print("vpHF_left_str = " + vpHF_left_str) +;pause + +; +; ********************************************************************** +; * +; Create (using gsn_create_text(...)) and then annotate to the plot +; (using gsn_add_annotation(...)) the left title string. +; * +; ********************************************************************** +; + txres := True + txres@txFontHeightF = FontHeightF_LR + txres@txFontColor = FontColor_LR + txres@txJust = "BottomLeft" + txid_right_str = gsn_create_text(wks, plot_options@right_str, txres) + + amres := True + amres@amParallelPosF = 0.5 + amres@amOrthogonalPosF = amOrthogonalPosF_LR + amres@amJust = "BottomRight" + annotid_right_str = gsn_add_annotation(map, txid_right_str, amres) +; +; Get the viewpoint coordinates and width and height of the text box of +; the right title string. +; + getvalues txid_right_str + "vpXF" : vpXF_right_str + "vpYF" : vpYF_right_str + "vpWidthF" : vpWF_right_str + "vpHeightF" : vpHF_right_str + end getvalues +;print("") +;print("vpXF_right_str = " + vpXF_right_str) +;print("vpYF_right_str = " + vpYF_right_str) +;print("vpWF_right_str = " + vpWF_right_str) +;print("vpHF_right_str = " + vpHF_right_str) +;pause + +; +; ********************************************************************** +; * +; Get the height of the taller of the left and right title strings. +; * +; ********************************************************************** +; + height_max = max((/ vpHF_left_str, vpHF_right_str /)) +; +; ********************************************************************** +; * +; Set the coordinate of the center title string in coordinates normal- +; ized with respect to the viewport size. This will be used in specify- +; ing the location at which the center title string will be annotated to +; the plot. +; * +; ********************************************************************** +; + amOrthogonalPosF_cntr \ + = amOrthogonalPosF_LR - height_max*(1.0/vpHeightF) \ + - dx_vert_offset_ndc*(1.0/vpHeightF) +; +; ********************************************************************** +; * +; Create (using gsn_create_text(...)) and then annotate to the plot +; (using gsn_add_annotation(...)) the center title string. +; * +; ********************************************************************** +; + txres := True + txres@txFontHeightF = FontHeightF_C + txres@txFontColor = FontColor_C + txid_cntr_str = gsn_create_text(wks, plot_options@main_str, txres) + + amres := True + amres@amParallelPosF = 0.0 ; Horizontally centered above plot. + amres@amOrthogonalPosF = amOrthogonalPosF_cntr + amres@amJust = "BottomCenter" + annotid_cntr_str = gsn_add_annotation(map, txid_cntr_str, amres) +; +; ********************************************************************** +; * +; Set labelbar resources to those specified as attributes of plot_op- +; tions, if any. +; * +; ********************************************************************** +; + getvalues map@contour + "pmAnnoViews" : pmAnnoViews + end getvalues + lb_object = pmAnnoViews(0) + + if (isatt(plot_options, "lbar_x") .and. \ + isatt(plot_options, "lbar_y") .and. \ + isatt(plot_options, "lbar_w") .and. \ + isatt(plot_options, "lbar_h") .and. \ + isatt(plot_options, "lbar_fh")) then + + rsrc@lbAutoManage = False + + setvalues lb_object + "vpXF" : plot_options@lbar_x + "vpYF" : plot_options@lbar_y + "vpHeightF" : plot_options@lbar_h + "vpWidthF" : plot_options@lbar_w + "lbLabelFontHeightF" : plot_options@lbar_fh + end setvalues + + end if +; +; ********************************************************************** +; * +; Draw NDC (non-dimensional coordinate, aka page coordinates) grid on +; the plot. These range from 0 to 1. This grid helps visualize loca- +; tions of various graphics objects. +; * +; ********************************************************************** +; +; drawNDCGrid(wks) +; +; ********************************************************************** +; * +; Retrieve the viewport values of the drawable object. These will be +; returned to the calling function/script. +; * +; ********************************************************************** +; + getvalues map + "vpXF" : vpXF + "vpYF" : vpYF + "vpWidthF" : vpWidthF + "vpHeightF" : vpHeightF + end getvalues +; print("") +; print("vpXF = " + vpXF) +; print("vpYF = " + vpYF) +; print("vpWidthF = " + vpWidthF) +; print("vpHeightF = " + vpHeightF) +; pause + + getvalues lb_object + "vpXF" : lbar_x + "vpYF" : lbar_y + "vpHeightF" : lbar_h + "vpWidthF" : lbar_w + "lbLabelFontHeightF" : lbar_fh + end getvalues +; +; ********************************************************************** +; * +; Resize the plot (if appropriate flag is set to True). +; * +; ********************************************************************** +; + if (isatt(plot_options, "resize_plot") .and. \ + isatt(plot_options, "bounding_box_size_NDC") .and. \ + plot_options@resize_plot) then + + opts := True +; opts@verbose = True + opts@verbose = False + out := get_resized_viewport_dims( \ + map, plot_options@bounding_box_size_NDC, opts) + + vpXF_new = out@vpXF + vpYF_new = out@vpYF + vpWidthF_new = out@vpWidthF + vpHeightF_new = out@vpHeightF + + setvalues map + "vpXF" : vpXF_new + "vpYF" : vpYF_new + "vpWidthF" : vpWidthF_new + "vpHeightF" : vpHeightF_new + end setvalues + + end if +; +; ********************************************************************** +; * +; Draw the plot and advance the frame. +; * +; ********************************************************************** +; + draw(map) + frame(wks) + + print("") + print("Done generating graphics file.") + print("") + print("" + separator_line) + print("") +; +; ********************************************************************** +; * +; Return various output variables as attributes of the "out" variable. +; Include here all variables that we want to pass to the next call to +; this function. +; * +; ********************************************************************** +; + out := True + out@vpXF := vpXF + out@vpYF := vpYF + out@vpWidthF := vpWidthF + out@vpHeightF := vpHeightF + out@lbar_x = lbar_x + out@lbar_y = lbar_y + out@lbar_h = lbar_h + out@lbar_w = lbar_w + out@lbar_fh = lbar_fh + + return(out) + +end + diff --git a/ush/NCL/NCL_ICs_BCs/plot_model_field_generic.ncl b/ush/NCL/NCL_ICs_BCs/plot_model_field_generic.ncl new file mode 100644 index 0000000000..1fe34c0e97 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/plot_model_field_generic.ncl @@ -0,0 +1,179 @@ +; ********************************************************************** +; +; File name: plot_model_field_generic.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function +; * +; ********************************************************************** + +load "pause.ncl" +load "special_chars.ncl" +load "set_plot_header.ncl" +load "plot_horiz_field.ncl" + +undef("plot_model_field_generic") + +function plot_model_field_generic( \ + model_name:string, + lon_cntrs_by_cell:snumeric, lat_cntrs_by_cell:snumeric, \ + lon_verts_by_cell:snumeric, lat_verts_by_cell:snumeric, \ + field_by_cell:snumeric, \ + field_name:string, field_desc:string, field_units:string, \ + func_t:logical, func_z:logical, \ + fcst_hr:integer, k:integer, \ + draw_grid:logical, \ + plot_options:logical) + +;local char_dq ; Need to add all local variables. + +begin +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; +; char_dq = integertochar(34) +; char_nl = str_get_nl() +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + plot_options@draw_grid = draw_grid +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + fn_graphics = plot_options@fn_graphics_base + \ + "_dmn" + plot_options@region_name + \ + "_grd" + model_name +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + inds_region_by_cell \ + := ind((lon_cntrs_by_cell .ge. plot_options@lon_min) .and. \ + (lon_cntrs_by_cell .le. plot_options@lon_max) .and. \ + (lat_cntrs_by_cell .ge. plot_options@lat_min) .and. \ + (lat_cntrs_by_cell .le. plot_options@lat_max)) + + lon_cntrs_region_by_cell := lon_cntrs_by_cell(inds_region_by_cell) + lat_cntrs_region_by_cell := lat_cntrs_by_cell(inds_region_by_cell) + lon_verts_region_by_cell := lon_verts_by_cell(inds_region_by_cell,:) + lat_verts_region_by_cell := lat_verts_by_cell(inds_region_by_cell,:) + + field_region_by_cell := field_by_cell(inds_region_by_cell) +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + field_min = min(field_region_by_cell) + field_max = max(field_region_by_cell) + print("") + print(" field_min = " + field_min + " " + field_units + \ + " in region " + char_dq + plot_options@region_name + char_dq) + print(" field_max = " + field_max + " " + field_units + \ + " in region " + char_dq + plot_options@region_name + char_dq) + + opts := True +; opts@header_style = "main_only" + opts@header_style = "main_left_right" + opts@fcst_hr = fcst_hr + opts@vert_idx = k + out := set_plot_header( \ + field_desc, field_units, field_min, field_max, \ + model_name, func_t, func_z, opts) + + if (isatt(out, "main_str")) then + plot_options@main_str = out@main_str + end if + if (isatt(out, "left_str")) then + plot_options@left_str = out@left_str + end if + if (isatt(out, "right_str")) then + plot_options@right_str = out@right_str + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + if (.not. isatt(plot_options, "calc_cnLevels")) then + plot_options@calc_cnLevels = True + else + plot_options@calc_cnLevels = False + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + if (plot_options@calc_cnLevels) then + + print("") + print("Calculating " + char_dq + "nice" + char_dq + " contour " + \ + "values from the field's minimum and " + char_nl + \ + "maximum values...") + + opts := True + opts@verbose = True +; opts@verbose = False + out := set_cnLevels_lbLabels( \ + field_min, field_max, plot_options@num_cnLevels, opts) + copy_VarAtts(out, plot_options) + + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + out := plot_horiz_field( \ + lon_cntrs_region_by_cell, \ + lat_cntrs_region_by_cell, \ + lon_verts_region_by_cell, \ + lat_verts_region_by_cell, \ + field_region_by_cell, \ + fn_graphics, \ + plot_options) +; +; ********************************************************************** +; * +; All attributes of the output variable "out" are plotting attributes +; that should be reused for the plot generated by the next call to +; plot_horiz_field(...) (which will plot a regridded version of the +; field above on the FV3-LAM grid). For this purpose, here we copy all +; attributes of "out" into the variable plot_options. We will then use +; plot_options as an input arguemnt to plot_horiz_field(...). +; * +; ********************************************************************** +; + copy_VarAtts(out, plot_options) + + return(out) + +end + + diff --git a/ush/NCL/NCL_ICs_BCs/read_FV3LAM_grid_halo.ncl b/ush/NCL/NCL_ICs_BCs/read_FV3LAM_grid_halo.ncl new file mode 100644 index 0000000000..e8dd9e92a5 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/read_FV3LAM_grid_halo.ncl @@ -0,0 +1,439 @@ +; +; ********************************************************************** +; +; File name: read_FV3LAM_grid_halo.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function reads in the coordinates of the FV3-LAM regional grid +; from the specified grid file and extracts from it the coordinates of +; the halo. +; +; ********************************************************************** +; +load "strcmp.ncl" +load "adjust_longitude_range.ncl" + +undef("read_FV3LAM_grid_halo") + +function read_FV3LAM_grid_halo(grid_file:string, nh:integer) + +local f_grid, \ + two_nx, two_ny, nx, ny, nxp, nyp, \ +; + i_bottom, j_bottom, i_top, j_top, i_left, j_left, i_right, j_right, \ + i_s_bottom, j_s_bottom, i_s_top, j_s_top, i_s_left, j_s_left, i_s_right, j_s_right, \ + i_w_bottom, j_w_bottom, i_w_top, j_w_top, i_w_left, j_w_left, i_w_right, j_w_right, \ +; + lon_verts_supergrid, lat_verts_supergrid, \ +; + lon_cntrs, lat_cntrs, lon_verts, lat_verts, \ + lon_cntrs_bottom, lat_cntrs_bottom, lon_verts_bottom, lat_verts_bottom, \ + lon_cntrs_top, lat_cntrs_top, lon_verts_top, lat_verts_top, \ + lon_cntrs_left, lat_cntrs_left, lon_verts_left, lat_verts_left, \ + lon_cntrs_right, lat_cntrs_right, lon_verts_right, lat_verts_right, \ +; + dims_bottom, nx_bottom, ny_bottom, num_cells_bottom, \ + dims_top, nx_top, ny_top, num_cells_top, \ + dims_left, nx_left, ny_left, num_cells_left, \ + dims_right, nx_right, ny_right, num_cells_right, \ +; + num_cells_total, num_verts_per_cell, \ +; + lon_cntrs_by_cell, lat_cntrs_by_cell, \ + lon_verts_by_cell, lat_verts_by_cell, \ +; + num_halo_portions, dims_halo_portions, \ + v, p, \ +; + lon_verts_halo_portions, lat_verts_halo_portions, \ +; + nx, ny, i_start, i_end, j_start, j_end, \ + inds_x, inds_y, lon_crnt_portion, lat_crnt_portion, \ + lon, lat, num_verts_per_cell, v, v_ref, \ +; + abs_del_lon, is_greater, \ + out + +begin +; +; ********************************************************************** +; +; Open the FV3-LAM grid file containing grid information. +; +; ********************************************************************** +; + f_grid = addfile(grid_file, "r") +; +; Get the dimensions of the tile 7 supergrid. +; + dim_sizes = getfiledimsizes(f_grid) + two_nx = dim_sizes(1) + two_ny = dim_sizes(2) +; +; ********************************************************************** +; +; Calculate the dimensions of the tile 7 computational grid. +; +; ********************************************************************** +; + nx = two_nx/2 + ny = two_ny/2 + nxp = nx + 1 + nyp = ny + 1 + +;print("") +;print("nx = " + nx) +;print("ny = " + ny) + +; +; Set variable containing one plus the number of cells in the halo. +; + nhp = nh + 1 +; +; Generate Fortran i and j indices of mass points in the bottom, top, +; left, and right portions of the halo. +; + i_bottom = ispan(1, nx, 1) + j_bottom = ispan(1, nh, 1) + + i_top = i_bottom + j_top = ispan(ny - nh + 1, ny, 1) + + i_left = ispan(1, nh, 1) + j_left = ispan(nh + 1, ny - nh, 1) + + i_right = ispan(nx - nh + 1, nx, 1) + j_right = j_left +; +; Generate Fortran i and j indices of west cell faces in the bottom, +; top, left, and right portions of the halo. +; + i_w_bottom = ispan(1, nxp, 1) + j_w_bottom = ispan(1, nh, 1) + + i_w_top = i_w_bottom + j_w_top = ispan(ny - nh + 1, ny, 1) + + i_w_left = ispan(1, nhp, 1) + j_w_left = ispan(nh + 1, ny - nh, 1) + + i_w_right = ispan(nxp - nhp + 1, nxp, 1) + j_w_right = j_w_left +; +; Generate Fortran i and j indices of south cell faces in the bottom, +; top, left, and right portions of the halo. +; + i_s_bottom = ispan(1, nx, 1) + j_s_bottom = ispan(1, nhp, 1) + + i_s_top = i_s_bottom + j_s_top = ispan(nyp - nhp + 1, nyp, 1) + + i_s_left = ispan(1, nh, 1) + j_s_left = ispan(nhp + 1, nyp - nhp, 1) + + i_s_right = ispan(nxp - nhp + 1, nxp, 1) + j_s_right = j_s_left +; +; The following are indices to generate coordinates that include an ex- +; tra row below and an extra row above the south-face coordinates of the +; left and right portions of the halo. +; + j_s_left_plot = ispan(nhp, nyp - nhp + 1, 1) + j_s_right_plot = j_s_left_plot +; +; Read in the supergrid coordinates. The supergrid of a given tile is a +; grid having twice the resolution of the actual (i.e. computational) +; grid of that tile. It is used to store the coordintes of both the +; centers and the vertices of the cells on the computational grid. +; + lon_verts_supergrid := f_grid->x(:,:) + lat_verts_supergrid := f_grid->y(:,:) +; +; Make sure that longitudes are in the range -180 deg <= lon < 180 deg. +; + lon_min = -180.0 + lon_verts_supergrid := adjust_longitude_range( \ + lon_verts_supergrid, lon_min, "degs") +; +; Get the coordinates of the cell vertices on the current tile. +; + lon_verts := lon_verts_supergrid(0::2,0::2) + lat_verts := lat_verts_supergrid(0::2,0::2) +; +; Get the coordinates of the cell centers on the current tile. +; + lon_cntrs := lon_verts_supergrid(1::2,1::2) + lat_cntrs := lat_verts_supergrid(1::2,1::2) +; +; Delete supergrid coordinates to save memory. +; + delete([/ lon_verts_supergrid, lat_verts_supergrid /]) +; +; Set cell center and cell vertex coordinates of cells in the bottom +; portion of the halo. +; + lon_cntrs_bottom = (/ lon_cntrs(j_bottom-1, i_bottom-1) /) + lat_cntrs_bottom = (/ lat_cntrs(j_bottom-1, i_bottom-1) /) + + lon_verts_bottom = (/ lon_verts(j_s_bottom-1, i_w_bottom-1) /) + lat_verts_bottom = (/ lat_verts(j_s_bottom-1, i_w_bottom-1) /) +; +; Set cell center and cell vertex coordinates of cells in the top por- +; tion of the halo. +; + lon_cntrs_top = (/ lon_cntrs(j_top-1, i_top-1) /) + lat_cntrs_top = (/ lat_cntrs(j_top-1, i_top-1) /) + + lon_verts_top = (/ lon_verts(j_s_top-1, i_w_top-1) /) + lat_verts_top = (/ lat_verts(j_s_top-1, i_w_top-1) /) +; +; Set cell center and cell vertex coordinates of cells in the left por- +; tion of the halo. +; + lon_cntrs_left = (/ lon_cntrs(j_left-1, i_left-1) /) + lat_cntrs_left = (/ lat_cntrs(j_left-1, i_left-1) /) + + lon_verts_left = (/ lon_verts(j_s_left-1, i_w_left-1) /) + lat_verts_left = (/ lat_verts(j_s_left-1, i_w_left-1) /) + + lon_verts_left_plot = (/ lon_verts(j_s_left_plot-1, i_w_left-1) /) + lat_verts_left_plot = (/ lat_verts(j_s_left_plot-1, i_w_left-1) /) +; +; Set cell center and cell vertex coordinates of cells in the right por- +; tion of the halo. +; + lon_cntrs_right = (/ lon_cntrs(j_right-1, i_right-1) /) + lat_cntrs_right = (/ lat_cntrs(j_right-1, i_right-1) /) + + lon_verts_right = (/ lon_verts(j_s_right-1, i_w_right-1) /) + lat_verts_right = (/ lat_verts(j_s_right-1, i_w_right-1) /) + + lon_verts_right_plot = (/ lon_verts(j_s_right_plot-1, i_w_right-1) /) + lat_verts_right_plot = (/ lat_verts(j_s_right_plot-1, i_w_right-1) /) +; +; Get the dimensions of the grids for the bottom, top, left, and right +; portions of the halo around regional domain. Then calculate the num- +; ber of cells in each of these four portions. +; + dims_bottom = dimsizes(lon_cntrs_bottom) + nx_bottom = dims_bottom(1) + ny_bottom = dims_bottom(0) + num_cells_bottom = nx_bottom*ny_bottom + + dims_top = dimsizes(lon_cntrs_top) + nx_top = dims_top(1) + ny_top = dims_top(0) + num_cells_top = nx_top*ny_top + + dims_left = dimsizes(lon_cntrs_left) + nx_left = dims_left(1) + ny_left = dims_left(0) + num_cells_left = nx_left*ny_left + + dims_right = dimsizes(lon_cntrs_right) + nx_right = dims_right(1) + ny_right = dims_right(0) + num_cells_right = nx_right*ny_right +; +; Calculate the total number of cells in the halo. +; + num_cells_total = num_cells_bottom + num_cells_top \ + + num_cells_left + num_cells_right + +print("") +print("num_cells_bottom = " + num_cells_bottom) +print("num_cells_top = " + num_cells_top) +print("num_cells_left = " + num_cells_left) +print("num_cells_right = " + num_cells_right) +print("") +print("num_cells_total = " + num_cells_total) + +; +; For plotting purposes, allocate arrays to hold the coordinates of the +; four corners of each cell to be plotted (i.e. of each cell in the ha- +; lo). The first dimension of these arrays is the number of cells in +; the halo. This is simply the sum of the number of cells in the bot- +; tom, top, left, and right portions of the halo. The second dimension +; of these arrays is the number of vertices per cell, which in the case +; of the cubed-sphere grid is always 4. +; + num_verts_per_cell = 4 + lon_cntrs_by_cell := new((/ num_cells_total /), "double") + lat_cntrs_by_cell := new((/ num_cells_total /), "double") + lon_verts_by_cell := new((/ num_cells_total, num_verts_per_cell /), "double") + lat_verts_by_cell := new((/ num_cells_total, num_verts_per_cell /), "double") +; +; Create string array containing a descriptive name for each of the four +; portions of the halo. Then set the number of halo portions (which is +; just 4). Finally, for convenience, set a 2-D array containing the di- +; mensions of these four portions. +; +; halo_portion_names = (/"bottom", "top", "left", "right"/) +; num_halo_portions = dimsizes(halo_portion_names) + num_halo_portions = 4 + dims_halo_portions = (/ (/ ny_bottom, nx_bottom /), \ + (/ ny_top, nx_top /), \ + (/ ny_left, nx_left /), \ + (/ ny_right, nx_right /) /) +; +; Create lists containing the longitudes and latitudes of the centers of +; cells in each portion of the halo. Then loop through these lists and +; generate arrays +; + lon_cntrs_halo_portions := [/ lon_cntrs_bottom, lon_cntrs_top, \ + lon_cntrs_left, lon_cntrs_right /] + lat_cntrs_halo_portions := [/ lat_cntrs_bottom, lat_cntrs_top, \ + lat_cntrs_left, lat_cntrs_right /] + + do p=0,num_halo_portions-1 + lon_crnt_portion := ndtooned(lon_cntrs_halo_portions[p]) + lat_crnt_portion := ndtooned(lat_cntrs_halo_portions[p]) + if (p .eq. 0) then + lon_cntrs_by_cell := lon_crnt_portion + lat_cntrs_by_cell := lat_crnt_portion + else + lon_cntrs_by_cell := array_append_record(lon_cntrs_by_cell, lon_crnt_portion, 0) + lat_cntrs_by_cell := array_append_record(lat_cntrs_by_cell, lat_crnt_portion, 0) + end if + end do + + delete([/ lon_cntrs_halo_portions, lat_cntrs_halo_portions /]) +; +; Create lists containing the longitudes and latitudes of the vertices +; of cells in each portion of the halo. +; + lon_verts_halo_portions \ + := [/ lon_verts_bottom, lon_verts_top, \ + lon_verts_left_plot, lon_verts_right_plot /] ; Notice the _plot. Rename? + lat_verts_halo_portions \ + := [/ lat_verts_bottom, lat_verts_top, \ + lat_verts_left_plot, lat_verts_right_plot /] ; Notice the _plot. Rename? +; +; Loop over the four vertices of each cell and over the four regions of +; the halo and assign the coordinates of vertices of each cell. +; + do v=0, num_verts_per_cell-1 + + do p=0,num_halo_portions-1 +; +; Get the dimensions of the current halo portion. +; + nx = dims_halo_portions(p,1) + ny = dims_halo_portions(p,0) +; +; Set the range of indices in each direction of the subarrays to extract +; from the full coordinate arrays. +; + if (v .eq. 0) then + i_start = 0 + i_end = nx - 1 + j_start = 0 + j_end = ny - 1 + else if (v .eq. 1) then + i_start = 1 + i_end = nx + j_start = 0 + j_end = ny - 1 + else if (v .eq. 2) then + i_start = 1 + i_end = nx + j_start = 1 + j_end = ny + else if (v .eq. 3) then + i_start = 0 + i_end = nx - 1 + j_start = 1 + j_end = ny + end if + end if + end if + end if + + inds_x := ispan(i_start, i_end, 1) + inds_y := ispan(j_start, j_end, 1) +; +; Get longitudes of the current vertex of all cells in the current halo +; portion. +; + lon_crnt_portion := lon_verts_halo_portions[p] + lon_crnt_portion := ndtooned(lon_crnt_portion(inds_y, inds_x)) +; +; Get latitudes of the current vertex of all cells in the current halo +; portion. +; + lat_crnt_portion := lat_verts_halo_portions[p] + lat_crnt_portion := ndtooned(lat_crnt_portion(inds_y, inds_x)) +; +; Construct the arrays containing the coordinates of the current vertex +; of all cells in the halo. +; + if (p .eq. 0) then + lon := lon_crnt_portion + lat := lat_crnt_portion + else + lon := array_append_record(lon, lon_crnt_portion, 0) + lat := array_append_record(lat, lat_crnt_portion, 0) + end if + + end do + +;print("") +;print("v = " + v) +;print("max(lon) = " + max(lon)) +;print("max(lat) = " + max(lat)) +;pause + + lon_verts_by_cell(:,v) = lon + lat_verts_by_cell(:,v) = lat + + end do +; +; Delete unneeded work arrays. +; + delete([/ lon_verts_halo_portions, lat_verts_halo_portions, lon, lat /]) +; +; For cells that cross over the international date line, modify longi- +; tudes of the vertices so that there is no discontinuity in their val- +; ues. +; +if (False) then + v_ref = 0 + do v=1, num_verts_per_cell-1 + abs_del_lon := abs(lon_verts_by_cell(:,v) - lon_verts_by_cell(:,v_ref)) + is_greater := (lon_verts_by_cell(:,v) .gt. lon_verts_by_cell(:,v_ref)) + lon_verts_by_cell(:,v) \ + = where((abs_del_lon .gt. 180.0) .and. is_greater, \ + lon_verts_by_cell(:,v) - 360.0, \ + lon_verts_by_cell(:,v)) + lon_verts_by_cell(:,v) \ + = where((abs_del_lon .gt. 180.0) .and. (.not. is_greater), \ + lon_verts_by_cell(:,v) + 360.0, \ + lon_verts_by_cell(:,v)) + end do + delete([/ abs_del_lon, is_greater /]) +end if +; +; ********************************************************************** +; +; Return various output variables as attributes of the "out" variable. +; +; ********************************************************************** +; + out = True + out@num_cells_total = num_cells_total + out@lon_cntrs_by_cell = lon_cntrs_by_cell + out@lat_cntrs_by_cell = lat_cntrs_by_cell + out@lon_verts_by_cell = lon_verts_by_cell + out@lat_verts_by_cell = lat_verts_by_cell + return(out) + +end + + + + + + diff --git a/ush/NCL/NCL_ICs_BCs/read_RAP_grid.ncl b/ush/NCL/NCL_ICs_BCs/read_RAP_grid.ncl new file mode 100644 index 0000000000..f24563ac26 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/read_RAP_grid.ncl @@ -0,0 +1,198 @@ +; ********************************************************************** +; +; File name: read_RAP_grid.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function reads in the RAP grid from the specified file. +; * +; ********************************************************************** + +load "adjust_longitude_range.ncl" + +undef("read_RAP_grid") + +function read_RAP_grid(RAP_geo_file:string) + +local f_geo, \ + lon_cntrs, lat_cntrs, lon_verts, lat_verts, \ + RAP_dims, nx, ny, num_cells, \ + lon_cntrs_by_cell, lat_cntrs_by_cell, \ + lon_verts_by_cell, lat_verts_by_cell, \ + lon, lat, num_verts_per_cell, v, v_ref, \ + abs_del_lon, is_greater, \ + out + +begin +; +; ********************************************************************** +; * +; Open the RAP geo-file containing RAP grid information. +; * +; ********************************************************************** +; + f_geo = addfile(RAP_geo_file, "r") +; +; Read in the center coordinates of all cells in the RAP domain. +; + lon_cntrs := f_geo->XLONG_M(:,:,:) + lat_cntrs := f_geo->XLAT_M(:,:,:) +; +; Read in the corner coordinates of all cells in the RAP domain. +; + lon_verts := f_geo->XLONG_C(:,:,:) + lat_verts := f_geo->XLAT_C(:,:,:) +; +; Remove singleton dimensions (e.g. time). +; + lon_cntrs := rm_single_dims(lon_cntrs) + lat_cntrs := rm_single_dims(lat_cntrs) + + lon_verts := rm_single_dims(lon_verts) + lat_verts := rm_single_dims(lat_verts) +; +; Make sure that longitudes are in the range -180 deg <= lon < 180 deg. +; + lon_min = -180.0 + lon_cntrs := adjust_longitude_range(lon_cntrs, lon_min, "degs") + lon_verts := adjust_longitude_range(lon_verts, lon_min, "degs") +; +; Get the dimensions of the RAP domain. +; + RAP_dims := dimsizes(lon_cntrs) + nx = RAP_dims(1) + ny = RAP_dims(0) + num_cells = nx*ny + +print("") +print("nx = " + nx) +print("ny = " + ny) +print("num_cells = " + num_cells) +; +; ********************************************************************** +; * +; Form arrays containing the coordinates of cell centers on a "by-cell" +; basis. +; * +; ********************************************************************** +; + lon_cntrs_by_cell := ndtooned(lon_cntrs) + lat_cntrs_by_cell := ndtooned(lat_cntrs) +; +; ********************************************************************** +; * +; Form arrays containing the coordinates of cell corners on a "by-cell" +; basis. +; * +; ********************************************************************** +; + num_verts_per_cell = 4 + lon_verts_by_cell := new((/ num_cells, num_verts_per_cell /), "double") + lat_verts_by_cell := new((/ num_cells, num_verts_per_cell /), "double") + + v = 0 + lon := ndtooned(lon_verts(0:ny-1,0:nx-1)) + lat := ndtooned(lat_verts(0:ny-1,0:nx-1)) + lon_verts_by_cell(:,v) = lon + lat_verts_by_cell(:,v) = lat + + v = 1 + lon := ndtooned(lon_verts(0:ny-1,1:nx)) + lat := ndtooned(lat_verts(0:ny-1,1:nx)) + lon_verts_by_cell(:,v) = lon + lat_verts_by_cell(:,v) = lat + + v = 2 + lon := ndtooned(lon_verts(1:ny,1:nx)) + lat := ndtooned(lat_verts(1:ny,1:nx)) + lon_verts_by_cell(:,v) = lon + lat_verts_by_cell(:,v) = lat + + v = 3 + lon := ndtooned(lon_verts(1:ny,0:nx-1)) + lat := ndtooned(lat_verts(1:ny,0:nx-1)) + lon_verts_by_cell(:,v) = lon + lat_verts_by_cell(:,v) = lat +; +; Delete unneeded arrays. +; + delete([/ lon, lat /]) +; +; For cells that cross over the international date line, modify longi- +; tudes of the vertices so that there is no discontinuity in their val- +; ues. +; + v_ref = 0 + do v=1, num_verts_per_cell-1 + abs_del_lon := abs(lon_verts_by_cell(:,v) - lon_verts_by_cell(:,v_ref)) + is_greater := (lon_verts_by_cell(:,v) .gt. lon_verts_by_cell(:,v_ref)) + lon_verts_by_cell(:,v) \ + = where((abs_del_lon .gt. 180.0) .and. is_greater, \ + lon_verts_by_cell(:,v) - 360.0, \ + lon_verts_by_cell(:,v)) + lon_verts_by_cell(:,v) \ + = where((abs_del_lon .gt. 180.0) .and. (.not. is_greater), \ + lon_verts_by_cell(:,v) + 360.0, \ + lon_verts_by_cell(:,v)) + end do + + + +if (False) then + clon_cntrs := f_geo->CLONG + clat_cntrs := f_geo->CLAT + + lon_min = 180.0 + clon_cntrs = adjust_longitude_range(clon_cntrs, lon_min, "degs") + + temp := dimsizes(clon_cntrs) + west_east = temp(2) + south_north = temp(1) + + clon_min = min(clon_cntrs) + clon_max = max(clon_cntrs) + + clat_min = min(clat_cntrs) + clat_max = max(clat_cntrs) + + del_clon = (clon_max - clon_min)/(west_east-1) + del_clat = (clat_max - clat_min)/(south_north-1) + + + print("") + print("clon_min = " + clon_min) + print("clon_max = " + clon_max) + print("del_clon = " + del_clon) + print("") + print("clat_min = " + clat_min) + print("clat_max = " + clat_max) + print("del_clat = " + del_clat) +;pause +end if + + + +; +; ********************************************************************** +; * +; Return various output variables as attributes of the "out" variable. +; * +; ********************************************************************** +; + out = True + out@nx = nx + out@ny = ny + out@num_cells = num_cells + out@lon_cntrs_by_cell = lon_cntrs_by_cell + out@lat_cntrs_by_cell = lat_cntrs_by_cell + out@lon_verts_by_cell = lon_verts_by_cell + out@lat_verts_by_cell = lat_verts_by_cell + return(out) + +end + + + + + diff --git a/ush/NCL/NCL_ICs_BCs/read_RAP_horiz_field.ncl b/ush/NCL/NCL_ICs_BCs/read_RAP_horiz_field.ncl new file mode 100644 index 0000000000..442541ae2b --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/read_RAP_horiz_field.ncl @@ -0,0 +1,76 @@ +; ********************************************************************** +; +; File name: read_RAP_horiz_field.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function reads in (a horizontal slice of) the specified RAP field +; from the specified file pointer (which should be pointing at a wrfout +; file). +; * +; ********************************************************************** + +load "calc_field_stats.ncl" + +undef("read_RAP_horiz_field") + +function read_RAP_horiz_field( \ + f_wrfout:file, field_name:string, func_z:logical, k:integer, \ + print_field_stats:logical) + +local field, field_by_cell, \ + field_desc, field_units, \ + field_min, field_max, \ + out + +begin +; +; ********************************************************************** +; * +; Read in the field from the specified RAP wrfout file. +; * +; ********************************************************************** +; + if (func_z) then + field = f_wrfout->$field_name$(0,k,:,:) + else + field = f_wrfout->$field_name$(0,:,:) + end if +; +; Convert the field to a cell-based one for plotting on an unstructured +; grid. +; + field_by_cell := ndtooned(field) +; +; Get the description and units of the field. +; + field_desc = f_wrfout->$field_name$@description + field_units = f_wrfout->$field_name$@units +; +; ********************************************************************** +; * +; Calculate and print out basic statistics of the field on the RAP grid. +; * +; ********************************************************************** +; + out := calc_field_stats( \ + field_by_cell, field_desc, field_units, print_field_stats) + field_min = out@field_min + field_max = out@field_max +; +; ********************************************************************** +; * +; Return various output variables as attributes of the "out" variable. +; * +; ********************************************************************** +; + out := True + out@field_desc = field_desc + out@field_units = field_units + out@field_by_cell = field_by_cell + out@field_min = field_min + out@field_max = field_max + return(out) + +end diff --git a/ush/NCL/NCL_ICs_BCs/set_cnLevels_lbLabels.ncl b/ush/NCL/NCL_ICs_BCs/set_cnLevels_lbLabels.ncl new file mode 100644 index 0000000000..9f9c89c154 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/set_cnLevels_lbLabels.ncl @@ -0,0 +1,623 @@ +; ********************************************************************** +; +; File name: set_cnLevels_lbLabels.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function generates and returns a numeric array containing the le- +; vels at which to draw contours for a field having the specified mini- +; mum and maximum values (field_min and field_max). The number of such +; levels (i.e. the size of the array) is specified by the input argument +; num_cnLevels. +; +; This function also generates (and returns) a string array containing +; the labels corresponding to the calculated levels. These labels can +; be used to annotate the contour lines (using the cnLineLabelStrings +; resource) and/or to annotate the labelbar (using the lbLabelStrings +; resource) in case a labelbar is to be generated for the contour plot. +; * +; ********************************************************************** + +load "pause.ncl" +load "strcmp.ncl" + +undef("set_cnLevels_lbLabels") + +function set_cnLevels_lbLabels( \ + field_min:snumeric, field_max:snumeric, num_cnLevels:integer, \ + opts:logical) + +local char_dq, char_nl, \ + verbose, \ + field_type, \ + field_range, nLevs, cnIntvl, \ + precision, fmt, cnIntvl_E_fmt_str, \ + idx_E, mntsa_cnIntvl_str, expnt_cnIntvl_str, \ + mntsa_cnIntvl, expnt_cnIntvl, expnt_cnIntvl_factor, \ + mntsa_cnLevel_min, cnLevel_min, cnLevel_max, \ + lbLabel_nums, lbLabel_strs, \ + out + +begin +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; + char_dq = integertochar(34) + char_nl = str_get_nl() +; +; ********************************************************************** +; * +; The local variable "verbose" determines whether informational messag- +; es are printed out to the screen. If the options argument opts has an +; attribute named verbose, then set the local variable verbose to this +; attribute. Otherwise, set the local verbose variable to False. +; * +; ********************************************************************** +; + if (isatt(opts, "verbose")) then + verbose = opts@verbose + else + verbose = False + end if + + if (verbose) then + print("") + print("Start of output from function set_cnLevels_lbLabels(...):") + print("========================================================") + end if +; +; ********************************************************************** +; * +; Check that field_min is less than or equal to field_max. If not, +; print out a warning and stop. +; * +; ********************************************************************** +; + if (field_min .gt. field_max) then + print("") + print("Error: field_min must be less than or equal to field_max:") + print(" field_min = " + field_min) + print(" field_max = " + field_max) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Get the data type of the field and store it in the variable field_- +; type. In doing so, we first check whether field_min and field_max are +; of the same type. If so, we set field_type to this type. If not, we +; print out an error message and stop. +; * +; ********************************************************************** +; + if (strcmp(typeof(field_min), typeof(field_max))) then + field_type = typeof(field_min) + else + print("") + print("Error: field_min and field_max must have the same data type:") + print(" typeof(field_min) = " + typeof(field_min)) + print(" typeof(field_max) = " + typeof(field_max)) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Calculate the range of values for the field, i.e. the difference be- +; tween the maximum and minimum values. Then use this range to calcu- +; late an initial estimate for the contour interval (i.e. the difference +; between any two contour level values), which we denote by cnIntvl. +; * +; ********************************************************************** +; + field_range = field_max - field_min + nLevs = num_cnLevels + cnIntvl = field_range/(nLevs - 1) + + if (verbose) then + print("") + print("Input parameters and initial estimate of contour interval:") + print(" field_min = " + field_min) + print(" field_max = " + field_max) + print(" field_range = " + field_range) + print(" field_type = " + field_type) + print(" nLevs = " + nLevs) + print(" cnIntvl = " + cnIntvl) + end if +; +; ********************************************************************** +; * +; No variation in the field (i.e. constant field). +; * +; ********************************************************************** +; + if (field_range .eq. 0) then + + print("") + print("Encountered constant field.") + print("Setting all nLevs = " + tostring(nLevs) + \ + " contour levels to same value.") + + lbLabel_nums := new((/nLevs/), field_type) + lbLabel_nums = field_min + + fmt = "%0.2f" + lbLabel_strs = sprintf(fmt, lbLabel_nums) + + out := True + out@lbLabel_nums = lbLabel_nums + out@lbLabel_strs = lbLabel_strs + + if (verbose) then + print("") + print("End of output from function set_cnLevels_lbLabels(...).") + print("=======================================================") + end if + + return(out) + + end if +; +; ********************************************************************** +; * +; Generate a string containing the contour interval (cnIntvl) expressed +; in scientific notation, i.e. in the form +; +; [-]m.ddE±xx, +; +; where the number of "d"s (i.e. the precision) is 2. +; * +; ********************************************************************** +; + precision = 2 + fmt = "%0." + precision + "E" + cnIntvl_E_fmt_str := sprintf(fmt, cnIntvl) +; +; ********************************************************************** +; * +; Get the portions of the string before the "E" (the mantissa) and after +; (the exponent). +; * +; ********************************************************************** +; + idx_E = str_index_of_substr(cnIntvl_E_fmt_str, "E", 1) + mntsa_cnIntvl_str := str_get_cols(cnIntvl_E_fmt_str, 0, idx_E-1) + expnt_cnIntvl_str := str_get_cols(cnIntvl_E_fmt_str, idx_E+1, -1) + + if (verbose) then + print("") + print("After conversion of cnIntvl to a string using formatted " + \ + "sprintf(...):") + print(" fmt = " + char_dq + fmt + char_dq) + print(" cnIntvl_E_fmt_str = " + cnIntvl_E_fmt_str) + print(" mntsa_cnIntvl_str = " + mntsa_cnIntvl_str) + print(" expnt_cnIntvl_str = " + expnt_cnIntvl_str) + end if +; +; ********************************************************************** +; * +; Calculate the mantissa and the exponent of cnIntvl by converting their +; string representations back to numerical representations. Note that: +; +; *) The mantissa will be rounded to 3 significant digits. This is be- +; cause in expressing the mantissa in scientific notation above using +; the sprintf(...) function, we set the precision to 2. This is a +; minor adjustment to the mantissa. +; +; *) Due to the output format used in the call to sprintf(...) above, +; the mantissa of cnIntvl is guaranteed to be greater than or equal +; to 1 and less than 10. +; +; Then use the mantissa and exponent of cnIntvl to calculate cnIntvl to +; 3 significant digits. +; * +; ********************************************************************** +; + mntsa_cnIntvl = totype(mntsa_cnIntvl_str, field_type) + expnt_cnIntvl = tointeger(expnt_cnIntvl_str) + cnIntvl = mntsa_cnIntvl*10^expnt_cnIntvl + + if (verbose) then + print("") + print("After rounding cnIntvl to " + tostring(precision+1) + \ + " significant digits:") + print(" mntsa_cnIntvl = " + mntsa_cnIntvl) + print(" expnt_cnIntvl = " + expnt_cnIntvl) + print(" cnIntvl = " + cnIntvl) + end if +; +; ********************************************************************** +; * +; We now adjust the mantissa of the contour interval (mntsa_cnIntvl) to +; obtain a value that will (later below) generate "nice" values for the +; contour levels, i.e. values that are easily comprehensible in a con- +; tour plot. In this adjustment, we require that mntsa_cnIntvl be one +; of the integers 1, 2, 4, 5, and 10. To determine which of these inte- +; gers mntsa_cnIntvl be set to, we first find the one it is is closest +; to and then reset it to that integer. Thus, the adjustment procedure +; for mntsa_cnIntvl is as follows: +; +; *) If 1.0 <= mntsa_cnIntvl < 1.5, reset mntsa_cnIntvl to 1. +; *) If 1.5 <= mntsa_cnIntvl < 3.0, reset mntsa_cnIntvl to 2. +; *) If 3.0 <= mntsa_cnIntvl < 4.5, reset mntsa_cnIntvl to 4. +; *) If 4.5 <= mntsa_cnIntvl < 7.5, reset mntsa_cnIntvl to 5. +; *) If 7.5 <= mntsa_cnIntvl < 10, reset mntsa_cnIntvl to 10. +; * +; ********************************************************************** +; + if ((1.0 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 1.5)) then + mntsa_cnIntvl = 1 + else if ((1.5 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 3.0)) then + mntsa_cnIntvl = 2 + else if ((3.0 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 4.5)) then + mntsa_cnIntvl = 4 + else if ((4.5 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 7.5)) then + mntsa_cnIntvl = 5 + else if ((7.5 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 10.0)) then +; Resetting the mntsa_cnIntvl to 10 is the same as resetting it to 1 and +; incrementing the exponent of cnIntvl (expnt_cnIntvl) by 1. + mntsa_cnIntvl = 1 + expnt_cnIntvl = expnt_cnIntvl + 1 + end if + end if + end if + end if + end if +; +; ********************************************************************** +; * +; Since mntsa_cnIntvl is now an integer and will be treated as such in +; the following code, we now change its type to an integer. +; * +; ********************************************************************** +; + mntsa_cnIntvl := tointeger(mntsa_cnIntvl) +; +; ********************************************************************** +; * +; Use the new integer value of mntsa_cnIntvl to calculate a new cnIntvl. +; * +; ********************************************************************** +; + expnt_cnIntvl_factor := 10^expnt_cnIntvl + cnIntvl := mntsa_cnIntvl*expnt_cnIntvl_factor + + if (verbose) then + print("") + print("After adjusting cnIntvl to a " + char_dq + "nice" + char_dq + \ + " integer value:") + print(" mntsa_cnIntvl = " + mntsa_cnIntvl) + print(" expnt_cnIntvl = " + expnt_cnIntvl + \ + " (expnt_cnIntvl_factor = " + expnt_cnIntvl_factor + ")") + print(" cnIntvl = " + cnIntvl) + end if +; +; ********************************************************************** +; * +; In order to obtain "nice" values for the contour levels, not only must +; the contour interval have a nice value but so must the minimum contour +; line value cnLevel_min (because we will add multiples of cnIntvl to +; cnLevel_min to obtain all the contour line values). To derive a nice +; value for cnLevel_min, we start by deriving such a value for its man- +; tissa, as described below. +; +; Calculate an initial estimate for the mantissa of the minimum contour +; line value cnLevel_min if cnLevel_min were expressed with an exponent +; that is equal to that of cnIntvl. We denote this mantissa by mntsa_- +; cnLevel_min. Thus, mntsa_cnLevel_min is defined by the expression +; +; cnLevel_min = mntsa_cnLevel_min*10^(expnt_cnIntvl) +; +; Solving this for mntsa_cnLevel_min gives +; +; mntsa_cnLevel_min = cnLevel_min/10^(expnt_cnIntvl) +; +; To obtain an initial estimate for mntsa_cnLevel_min, we set cnLevel_- +; min on the right-hand side to field_min. This gives +; +; mntsa_cnLevel_min = field_min/10^(expnt_cnIntvl) +; +; We use this expression below. +; * +; ********************************************************************** +; + mntsa_cnLevel_min = field_min/expnt_cnIntvl_factor +; +; ********************************************************************** +; * +; To obtain a "nice" value for cnLevel_min (i.e. a value that is easily +; comprehensible when displayed in a contour plot), we will require that +; its mantissa be an integer. Also, we would like cnLevel_min to be +; less than or equal to field_min (so that all values of the field are +; included in the range [cnLevel_min, cnLevel_max] that we will calcu- +; late). Thus, we now truncate the mntsa_cnLevel_min calculated above +; using NCL's floor(...) function. +; * +; ********************************************************************** +; + mntsa_cnLevel_min := tointeger(floor(mntsa_cnLevel_min)) +; +; ********************************************************************** +; * +; We do not necessary yet have a "nice" value for mntsa_cnLevel_min, +; i.e. a value that will correspond to a "nice" value for cnLevel_min in +; the contour plot to be generated. Thus, we now decrement our previous +; estimate for mntsa_cnLevel_min (which is now an integer) by 1 as many +; times as necessary until we obtain one that corresponds to a "nice" +; value. (Note that we decrement, not increment, by 1 in order to be +; sure that the value of cnLevel_min we end up with is less than or +; equal to field_min.) What constitutes a "nice" value for mntsa_cnLe- +; vel_min depends on the mantissa of cnIntvl (i.e. mntsa_cnIntvl; recall +; that this is now one of the following integers: 1, 2, 4, and 5) as +; follows: +; +; *) If mntsa_cnIntvl is 1, we define a "nice" value for mntsa_cnLevel_- +; min to be any integer. Since mntsa_cnLevel_min is already an inte- +; ger, we do not need to make any adjustments to it. +; +; *) If mntsa_cnIntvl is 2 or 4, we define a "nice" value for mntsa_cn- +; Level_min to be an even integer. Thus, if mntsa_cnLevel_min is al- +; ready even, we do not make any adjustments to it. If mntsa_cnLe- +; vel_min is odd, we decrement it by 1 to obtain an even integer. +; +; *) If mntsa_cnIntvl is 5, we define a "nice" value for mntsa_cnLevel_- +; min_to be an integer that ends in a 0 or a 5 (i.e. an integer that +; is evenly divisible by 5). Thus, if mntsa_cnLevel_min is already +; divisible by 5, we do not make any adjustments to it. If mntsa_- +; cnLevel_min is not divisible by 5, we repeatedly decrement it by 1 +; until we obtain a value that is divisible by 5. +; * +; ********************************************************************** +; + if (mntsa_cnIntvl .eq. 1) then + +; Do nothing. + + else if ((mntsa_cnIntvl .eq. 2) .or. (mntsa_cnIntvl .eq. 4)) then + + if ((mntsa_cnLevel_min%2) .ne. 0) then + mntsa_cnLevel_min = mntsa_cnLevel_min - 1 + end if + + else if (mntsa_cnIntvl .eq. 5) then + + do while ((mntsa_cnLevel_min%5) .ne. 0) + mntsa_cnLevel_min = mntsa_cnLevel_min - 1 + end do + + else + + print("") + print("Error: Disallowed value for mntsa_cnIntvl:") + print(" mntsa_cnIntvl = " + mntsa_cnIntvl) + print("mntsa_cnIntvl must be 1, 2, 4, or 5.") + print("Stopping.") + exit + + end if + end if + end if +; +; ********************************************************************** +; * +; Now that we've determined the mantissa and exponent of the first +; (i.e. smallest or minimum) contour level cnLevel_min (the mantissa +; being mntsa_cnLevel_min and the exponent being the same as that of +; cnIntvl, i.e. expnt_cnIntvl), we proceed to calculate cnLevel_min it- +; self. Note that since mntsa_cnLevel_min and expnt_cnIntvl_factor are +; both integers, cnLevel_min will also be an integer. Note also that +; cnLevel_min will be less than field_min by some amount that is less +; than or equal to cnIntvl. +; * +; ********************************************************************** +; + cnLevel_min := mntsa_cnLevel_min*expnt_cnIntvl_factor +; +; ********************************************************************** +; * +; Now calculate the value of the last (i.e. largest or maximum) contour +; level (cnLevel_max). We do this by first setting cnLevel_max to cnLe- +; vel_min and then repeatedly incrementing it by cnIntvl until it be- +; comes greater than or equal to field_max. Then calculate the number +; of contour levels between cnLevel_min and cnLevel_max, inclusive. +; * +; ********************************************************************** +; + cnLevel_max := cnLevel_min + do while (cnLevel_max .lt. field_max) + cnLevel_max = cnLevel_max + cnIntvl + end do + nLevs = tointeger(round((cnLevel_max - cnLevel_min)/cnIntvl + 1, 0)) + + if (verbose) then + print("") + print("Contour level min/max values that include field_min and field_max:") + print(" cnLevel_min = " + cnLevel_min + " (field_min = " + field_min + ")") + print(" cnLevel_max = " + cnLevel_max + " (field_max = " + field_max + ")") + print(" cnIntvl = " + cnIntvl) + print(" nLevs = " + nLevs) + end if +; +; ********************************************************************** +; * +; Check that cnLevel_min is indeed less than or equal to field_min and +; that cnLevel_max is indeed greater than or equal to field_max. This +; should be the case by design, but we test to be sure. +; * +; ********************************************************************** +; + if (cnLevel_min .gt. field_min) then + print("") + print("cnLevel_min must be less than or equal to field_min in " + \ + "order for the " + char_nl + \ + "contour plot to include all values of the field:") + print(" cnLevel_min = " + cnLevel_min) + print(" field_min = " + field_min) + print("Stopping.") + exit + end if + + if (cnLevel_max .lt. field_max) then + print("") + print("cnLevel_max must be greater than or equal to field_max in " + \ + "order for the " + char_nl + \ + "contour plot to include all values of the field:") + print(" cnLevel_max = " + cnLevel_max) + print(" field_max = " + field_max) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; Check that the difference between field_min and cnLevel_min is indeed +; less than or equal to cnIntv. Similary, check that the difference be- +; tween field_max and cnLevel_max is indeed less than or equal to cn- +; Intv. These constraints should be satisfied, but test to be sure. +; * +; ********************************************************************** +; + abs_diff = abs(field_min - cnLevel_min) + if (abs_diff .gt. cnIntvl) then + print("") + print("cnLevel_min must be within cnIntvl of field_min:") + print(" field_min = " + field_min) + print(" cnLevel_min = " + cnLevel_min) + print(" cnIntvl = " + cnIntvl) + print(" abs(field_min - cnLevel_min))= " + abs_diff) + print("Stopping.") + exit + end if + + abs_diff = abs(field_max - cnLevel_max) + if (abs_diff .gt. cnIntvl) then + print("") + print("cnLevel_max must be within cnIntvl of field_max:") + print(" field_max = " + field_max) + print(" cnLevel_max = " + cnLevel_max) + print(" cnIntvl = " + cnIntvl) + print(" abs(field_max - cnLevel_max))= " + abs_diff) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; * +; We now have a cnLevel_min and a cnLevel_max that satisfy the inequali- +; ties +; +; cnLevel_min <= field_min <= field_max <= cnLevel_max +; +; and +; +; 0 <= field_min - cnLevel_min <= cnIntvl +; +; and +; +; 0 <= cnLevel_max - field_max <= cnIntvl +; +; Note that during the generation a contour plot in NCL, if the contour +; levels are specified, the contour plot routines add a bin (or color if +; color-filling between contour levels) before the minimum specified +; contour value (to hold field values that are less than the minimum +; contour value) and a bin (or color) after the maximum specified con- +; tour value (to hold field values that are greater than the maximum +; contour value). Thus, if the range [cnLevel_min, cnLevel_max] already +; includes field_min and field_max, no values of the field will fall in +; these two new bins, making them irrelevant. To make these bins rele- +; vant, we now increase cnLevel_min by cnIntvl and decrease cnLevel_max +; by cnIntvl such that we have +; +; field_min <= cnLevel_min <= cnLevel_max <= field_max +; +; and +; +; 0 <= cnLevel_min - field_min <= cnIntvl +; +; and +; +; 0 <= field_max - cnLevel_max <= cnIntvl +; +; With this modification, at least some values of the field will fall +; within the two bins that the NCL contour plotting routines add. +; * +; ********************************************************************** +; + cnLevel_min := cnLevel_min + cnIntvl + cnLevel_max := cnLevel_max - cnIntvl + nLevs = tointeger(round((cnLevel_max - cnLevel_min)/cnIntvl + 1, 0)) + + if (verbose) then + print("") + print("Contour level min/max values that exclude field_min and " + \ + "field_max " + char_nl + \ + "(by less than a contour interval):") + print(" cnLevel_min = " + cnLevel_min + " (field_min = " + field_min + ")") + print(" cnLevel_max = " + cnLevel_max + " (field_max = " + field_max + ")") + print(" cnIntvl = " + cnIntvl) + print(" nLevs = " + nLevs) + end if +; +; ********************************************************************** +; * +; Construct the numeric array containing the contour levels. +; * +; ********************************************************************** +; + lbLabel_nums := fspan(cnLevel_min, cnLevel_max, nLevs) +; lbLabel_nums := ispan(cnLevel_min, cnLevel_max, cnIntvl) ; cnIntvl is not necessarily an integer, so can't use this. + + if (verbose) then + print("") + print("Contour level values:") + print(" lbLabel_nums = " + lbLabel_nums) + end if +; +; ********************************************************************** +; * +; Construct the string array containing the contour labels. +; * +; ********************************************************************** +; + precision = 0 + if (expnt_cnIntvl .lt. 0) then + precision = abs(expnt_cnIntvl) + end if + fmt = "%0." + tostring(precision) + "f" + lbLabel_strs = sprintf(fmt, lbLabel_nums) + + if (verbose) then + print("") + print("Contour level labels (strings) generated using fmt = " + \ + char_dq + fmt + char_dq + ":") + print(" lbLabel_strs = " + lbLabel_strs) + end if +; +; ********************************************************************** +; * +; Return various output variables as attributes of the "out" variable. +; Note that we convert types back to that of the specified field. +; * +; ********************************************************************** +; + out := True + out@lbLabel_nums = totype(lbLabel_nums, field_type) + out@lbLabel_strs = lbLabel_strs + + if (verbose) then + print("") + print("End of output from function set_cnLevels_lbLabels(...).") + print("=======================================================") + end if + + return(out) + +end + + diff --git a/ush/NCL/NCL_ICs_BCs/set_plot_header.ncl b/ush/NCL/NCL_ICs_BCs/set_plot_header.ncl new file mode 100644 index 0000000000..bbc638471b --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/set_plot_header.ncl @@ -0,0 +1,334 @@ +; ********************************************************************** +; +; File name: set_plot_header.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function generates a string containing the plot title. This +; string contains various NCL function codes to specify the font, new- +; lines, etc. +; * +; ********************************************************************** + +undef("set_plot_header") + +function set_plot_header( \ + field_desc:string, \ + field_units:string, \ + field_min:snumeric, \ + field_max:snumeric, \ + model_name:string, \ + func_t:logical, func_z:logical, \ + opts:logical) + +local char_dq, \ + title_line1, num_chars_line1, title_line2, num_chars_line2, \ + num_chars_shortest_line, num_chars_longest_line, diff_num_chars, \ + num_spaces_begin, num_spaces_end, \ + pad_begin, pad_end, \ + fc_font, fc_newline, \ + plot_title + +begin +; +; ********************************************************************** +; * +; Special characters that can't be directly input into an NCL string. +; * +; ********************************************************************** +; + char_dq = integertochar(34) +; +; ********************************************************************** +; * +; Get the forecast hour and vertical index from the attributes of the +; opts variable. If these are not specified as attributes, set them to +; default values. +; * +; ********************************************************************** +; + if (isatt(opts, "header_style")) then + header_style = opts@header_style + else + header_style = "main_only" + header_style = "main_left_right" + end if + + if (isatt(opts, "fcst_hr")) then + fcst_hr = opts@fcst_hr + else + fcst_hr = "unspecified" + end if + + if (isatt(opts, "fcst_hr")) then + fcst_hr = opts@fcst_hr + else + fcst_hr = "unspecified" + end if + + if (isatt(opts, "vert_idx")) then + vert_idx = opts@vert_idx + else + vert_idx = "unspecified" + end if +; +; ********************************************************************** +; * +; Function codes used in strings. +; * +; ********************************************************************** +; + +; fc_font = "~F7~" ; complex_roman + fc_font = "~F29~" ; courier +; fc_font = "~F30~" ; courier-bold +; fc_font = "" ; default font + + fc_newline = "~C~" + +; fc_zoom = "~Z50~" + fc_zoom = "" + + fc_vert_raise = "" + fc_vert_raise = "~V-15~" +; fc_vert_raise = "~V-1Q~" +; +; ********************************************************************** +; * +; Delete pre-defined output variables. +; * +; ********************************************************************** +; + if (isvar("main_str")) then + delete(main_str) + end if + + if (isvar("left_str")) then + delete(left_str) + end if + + if (isvar("right_str")) then + delete(right_str) + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + if (func_t) then + fcst_hr_or_NA = tostring(fcst_hr) + else + fcst_hr_or_NA = "N/A" + end if + + if (func_z) then + vert_idx_or_NA = tostring(vert_idx) + else + vert_idx_or_NA = "N/A" + end if + + fmt = "%-4.4G" +; fmt = "%-4.8G" + + min_str = sprintf(fmt, field_min) + first_char_min = str_get_cols(min_str, 0, 0) + + max_str = sprintf(fmt, field_max) + first_char_max = str_get_cols(max_str, 0, 0) + + if (strcmp(first_char_min, "-")) then + if (.not. strcmp(first_char_max, "-")) then + max_str = "+" + max_str + end if + end if + +; if (.not. strcmp(first_char, "-")) then +; max_str = " " + max_str +; end if +; +; ********************************************************************** +; * +; Generate a plot header that has a main title only, i.e. no left-justi- +; fied and right-justified strings. This main title consists of two +; lines, with the lines horizontally centered with respect to the plot +; (and each other). +; * +; ********************************************************************** +; + if (strcmp(header_style, "main_only")) then +; +; ********************************************************************** +; * +; Form the first line of the title and get the number of characters in +; that line. +; * +; ********************************************************************** +; + title_line1 := field_desc + " [" + field_units + "]" + num_chars_line1 = strlen(title_line1) +; +; ********************************************************************** +; * +; Form the second line of the title and get the number of characters in +; that line. +; * +; ********************************************************************** +; + title_line2 \ + = "fcst_hr = " + fcst_hr_or_NA + " hr" + \ + "; k = " + vert_idx_or_NA + + fmt = "%-4.4G" + minmax_str = "min/max = " + \ + min_str + " [" + field_units + "]" + \ + " / " + \ + max_str + " [" + field_units + "]" + title_line2 = title_line2 + "; " + minmax_str + title_line2 = title_line2 + "; " + model_name + " grid" + + num_chars_line2 = strlen(title_line2) +; +; ********************************************************************** +; * +; Get the number of characters in the shorter and longer of the two +; lines. Then calculate the difference between the two as well as the +; number of spaces to add at the beginning and end of the shorter line +; so that it is horizontally centered with respect to the longer line +; (assuming we're using monospaced fonts). +; * +; ********************************************************************** +; + num_chars_shortest_line = min((/ num_chars_line1, num_chars_line2 /)) + num_chars_longest_line = max((/ num_chars_line1, num_chars_line2 /)) + + diff_num_chars = num_chars_longest_line - num_chars_shortest_line + if ((diff_num_chars % 2) .eq. 0) then + num_spaces_begin = diff_num_chars/2 + else + num_spaces_begin = (diff_num_chars - 1)/2 + end if + num_spaces_end = diff_num_chars - num_spaces_begin +; +; ********************************************************************** +; * +; Add the appropriate number of spaces at the beginning and end of the +; shorter line so that it is horizontally centered with respect to the +; longer line. +; * +; ********************************************************************** +; + pad_begin = "" + do i=1, num_spaces_begin + pad_begin = pad_begin + " " + end do + + pad_end = "" + do i=1, num_spaces_end + pad_end = pad_end + " " + end do + + if (num_chars_line1 .eq. num_chars_shortest_line) then + title_line1 := pad_begin + title_line1 + pad_end + else + title_line2 := pad_begin + title_line2 + pad_end + end if + +;print("") +;print("title_line1 = " + char_dq + title_line1 + char_dq) +;print("title_line2 = " + char_dq + title_line2 + char_dq) +;pause + +; +; ********************************************************************** +; * +; Use the function codes to generate a complete string for the plot ti- +; tle. +; * +; ********************************************************************** +; + main_str = fc_font + fc_zoom + \ + title_line1 + \ + fc_newline + fc_vert_raise + title_line2 +; +; ********************************************************************** +; * +; Generate a plot header that has a main title as well as a left-justi- +; fied and a right-justified string. +; * +; ********************************************************************** +; + else if (strcmp(header_style, "main_left_right")) then +; +; Create the main title string. +; + main_str = fc_font + fc_zoom + \ + field_desc + " [" + field_units + "]" +; +; Create string that will appear left-justified above the plot (and be- +; low the main title). +; + left_str = fc_font + fc_zoom + \ + "Grid: " + model_name + + left_str = left_str + fc_newline + fc_vert_raise + \ + "fcst_hr = " + fcst_hr_or_NA + " hr" + + left_str = left_str + fc_newline + fc_vert_raise + fc_vert_raise + \ + "k = " + vert_idx_or_NA +; +; Create string that will appear right-justified above the plot (and be- +; low the main title). +; + min_str = "min = " + min_str + " [" + field_units + "]" + max_str = "max = " + max_str + " [" + field_units + "]" + + right_str = fc_font + fc_zoom + min_str + \ + fc_newline + fc_vert_raise + max_str + + right_str = right_str + fc_newline + fc_vert_raise + fc_vert_raise + \ + " " +; +; ********************************************************************** +; * +; Disallowed value for header_style. +; * +; ********************************************************************** +; + else + + print("") + print("Disallowed value for header_style:") + print(" header_style = " + char_dq + header_style + char_dq) + print("Allowed values are:") + print(" " + char_dq + "main_only" + char_dq) + print(" " + char_dq + "main_left_right" + char_dq) + print("Stopping.") + exit + + end if + end if +; +; ********************************************************************** +; * +; Return the plot title. +; * +; ********************************************************************** +; + out := True + if (isvar("main_str")) then + out@main_str = main_str + end if + if (isvar("left_str")) then + out@left_str = left_str + end if + if (isvar("right_str")) then + out@right_str = right_str + end if + + return(out) + +end + diff --git a/ush/NCL/NCL_ICs_BCs/special_chars.ncl b/ush/NCL/NCL_ICs_BCs/special_chars.ncl new file mode 100644 index 0000000000..f3ec1310d9 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/special_chars.ncl @@ -0,0 +1,12 @@ +; +; ********************************************************************** +; +; Define special characters that can't be directly input into an NCL +; string. +; +; ********************************************************************** +; +char_nl = str_get_nl() +char_dq = str_get_dq() + + diff --git a/ush/NCL/NCL_ICs_BCs/strcmp.ncl b/ush/NCL/NCL_ICs_BCs/strcmp.ncl new file mode 100644 index 0000000000..3c23dd0cb1 --- /dev/null +++ b/ush/NCL/NCL_ICs_BCs/strcmp.ncl @@ -0,0 +1,33 @@ +; ********************************************************************** +; +; File name: strcmp.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function compares two strings. It returns True if they are iden- +; tical and False otherwise. It is called as follows: +; +; are_equal = strcmp(str1, str2) +; * +; ********************************************************************** + +undef("strcmp") + +function strcmp(str1:string, str2:string) +local len1, len2, match_result, are_equal + +begin + + len1 = strlen(str1) + len2 = strlen(str2) + match_result = str_match(str1, str2) + are_equal = False + if ((.not. ismissing(match_result)) .and. (len1 .eq. len2)) then + are_equal = True + end if + return(are_equal) + +end + + diff --git a/ush/NCL/README b/ush/NCL/README new file mode 100644 index 0000000000..63429e6c95 --- /dev/null +++ b/ush/NCL/README @@ -0,0 +1,163 @@ + +This script generates a 2-D color plot of one or more of the tiles on +a cubed-sphere grid on top of a map of the continents. Each tile is +depicted in the output graphics file as a uniformly colored region. + +An example of a call to this script from the command line is as fol- +lows: + + ncl -n plot_fields.ncl \ + 'help=False' \ + 'grid_dir="./some_dir/grid"' \ + 'input_file="nggps2d.nc"' \ + 'fields="u1000"' \ + 'res=96' \ + 'tile_inds=(/1,2,3/)' \ + 'draw_tile_bdy=True' \ + 'draw_tile_grid=True' \ + 'draw_RAP_domain=True' \ + 'RAP_grid_fn="./some_dir/RAP_grid.nc"' \ + 'draw_RAP_bdy=True' \ + 'draw_RAP_grid=True' \ + 'map_proj="cyln"' \ + 'map_proj_ctr=(/0,90/)' \ + 'subreg=(/-30,30,-25,25/)' \ + 'graphics_type="ncgm"' + +The output is a graphics file named + + C[res]_grid.[ext] + +where res is the specified resolution and ext is the graphics file ex- +tension (determined by the specified output graphics type graphics_- +type). The input arguments to this script are: + +help: +This argument specifies whether or not to print out the documentation +for this script and exit. It is either True or False. Default is +False. If this is set to True, this script prints out the documenta- +tion and exits, ignoring all other arguments. To see the documenta- +tion, type "ncl plot_fields.ncl 'help=True'" on the command line in the +directory of this script. + +grid_dir: +This argument specifies the directory in which the grid files are lo- +cated. It is assumed that these are NetCDF files with names of the +form + + C[res]_grid.tile[N].nc + +where res is the resolution specified on the command line and N is the +tile number. The tile numbers to consider are specified by the input +argument tile_inds (see below). Default value is the current directo- +ry, i.e. "./". + +input_file: +This argument specifies the file that contains the fields to be plotted. +It can be any of the FV3 output files that are typically named nggps2d.nc, +nggps3d_4xdaily.nc, atmos_4xdaily.nc, atmos_static.nc, etc. + +fields: +This argument specifies the fields from the input_file that will be plotted. + +nlev: +Index of vertical (presssure) level to plot. + +fcst_index: +Forecast index to plot. + +res: +This argument specifies the cubed-sphere resolution, i.e. the number +of cells in each of the two horizontal directions on each of the 6 +tiles of the global cubed-sphere grid. Valid values are: 48, 96, 192, +384, 768, 1152, and 3072. + +tile_inds: +This argument specifies the indices of those tiles on the cubed-sphere +grid that are to be plotted. For example, to plot tiles 1, 3, and 5, +specify + + tile_inds = (/ 1, 3, 5 /) + +If this is not specified, all available tiles are plotted (where by +"available", we mean all tiles for which there exists a grid file in +grid_dir). + +draw_tile_bdy: +This argument specifies whether or not to draw the boundary of each +specified tile. It is either True or False. Default is True. + +draw_tile_grid: +This argument specifies whether or not to draw the boundaries of all +grid cells on each tile that is being plotted. It is either True or +False. Default is False. For a high-resolution grid, this can make +it difficult to see the underlying color of the tile in the output +graphics file (because there would be many grid lines drawn very close +together). + +draw_RAP_domain: +This argument specifies whether or not to draw the original [i.e. pre- +FV3 RAP (RAPid Refresh) domain]. It is either True or False. Default +is False. If this is set to True, the RAP domain is added to the plot +as a uniformly colored region (with a color that is different from any +of the cubed-sphere tiles). + +RAP_grid_fn: +This argument specifies the full (i.e. including directory) file name +of the NetCDF file that describes the RAP grid. This is used only if +draw_RAP_domain is set to True. + +draw_RAP_bdy: +This argument specifies whether or not to draw the boundary of the RAP +domain. It is either True or False. Default is True. This has no +effect if draw_RAP_domain is set to False. + +draw_RAP_grid: +This argument specifies whether or not to draw the boundaries of all +grid cells on the RAP domain. It is either True or False. Default is +False. For a high-resolution RAP grid, setting this to True can make +it difficult to see the underlying color of the RAP domain in the out- +put graphics file (because there would be many grid lines drawn very +close together. This has no effect if draw_RAP_domain is set to +False. + +map_proj: +This argument specifies the map projection to use for the plot. Valid +values are: + + "cyln" - for cylindrical-equidistant projection + "ortho" - for orthographic (i.e. on a sphere) projection + "lamb" - for Lambert equal-area projection + +If this argument is omitted, a cylindrical-equidistant projection is +used. + +map_proj_ctr: +This argument specifies the point on the sphere at which to center the +map projection used for the plot. It consists of the point's longi- +tude and latitude (in degrees), as follows: + + map_proj_ctr = (/ 30, 40 /) + +If this is not specified, it is set to (/0,0/) for the cylindrical- +equidistant and orthographic (i.e. on a sphere) projections and to +(/0,90/) (i.e. the North Pole) for the Lambert equal-area projection. + +subreg: +If using a cylindrical-equidistant map projection, this argument spe- +cifies the minimum and maximum longitudes and latitudes (in degrees) +of the subregion to plot. It has the format + + subreg = (/ lon_min, lon_max, lat_min, lat_max /) + +where lon_min and lon_max are the minimum and maximum values of the +longitude and lat_min and lat_max are the minimum and maximum values +of the latitude. If this arbument is omitted, the field is plotted on +the whole globe. It is ignored for projections other than cylindri- +cal-equidistant. + +graphics_type: +This argument specifies the type of graphics file to generate as out- +put. It can be either "ncgm" (NCAR Graphics) or "png". Default is +"ncgm". + diff --git a/ush/NCL/calc_wrtcmp_grid_params.ncl b/ush/NCL/calc_wrtcmp_grid_params.ncl new file mode 100644 index 0000000000..d24627e0c2 --- /dev/null +++ b/ush/NCL/calc_wrtcmp_grid_params.ncl @@ -0,0 +1,487 @@ +; +; ********************************************************************** +; +; Load files. +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "strpad.ncl") +loadscript(lib_location + "repeat_str.ncl") +loadscript(lib_location + "convert_from_to_sphr_coords_to_from_rotated_sphr.ncl") +loadscript(lib_location + "convert_sphr_coords_to_lambert_cnfrml.ncl") +loadscript(lib_location + "convert_lambert_cnfrml_coords_to_sphr.ncl") + +undef("calc_wrtcmp_grid_params") + +function calc_wrtcmp_grid_params( \ + wrtcmp_config_fn:string, \ + lon_ctr_native:snumeric, lat_ctr_native:snumeric, \ + lon_tile_corners_face_midpts_native[8]:snumeric, \ + lat_tile_corners_face_midpts_native[8]:snumeric, \ + dx_native:snumeric, dy_native:snumeric, \ + angle_units:string) + +local lon_ctr, lat_ctr, lat1, lat2, \ + x_SW_native, y_SW_native, \ + num_gap_cells, \ + dx, x_SW, x_NE, Lx, Lx_ovr_dx, nx, frac_x, x_increment, \ + dy, y_SW, y_NE, Ly, Ly_ovr_dy, ny, frac_y, y_increment, \ + sphr_coords, lon_SW, lat_SW, \ + param_names, num_params, param_names_and_vals, trailing_comments, \ + np, param_name, param_value, param_value_str, \ + regex_search, regex_print, sed_cmd, \ + fmt_str, msg, \ + str_lens, str_len_max, num_delimit_spaces, delimit_spaces, \ + lines_final, regex_replace, sed_output, \ + out + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Set the coordinates of the center of the write-component output grid +; to be equal to those of the native grid. Also, set the latitudes de- +; fining the two standard parallels of the Lambert conformal projection +; used by the output grid to the latitude of the output grid center. +; +; ********************************************************************** +; +; lon_ctr = lon_ctr_native +; lat_ctr = lat_ctr_native +; lat1 = lat_ctr +; lat2 = lat_ctr +; +; ********************************************************************** +; +; Calculate the Lambert coordinates of the southwest corner of the na- +; tive grid from its spherical coordinates. +; +; ********************************************************************** +; + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + + lon_ctr = lon_ctr_native + lat_ctr = lat_ctr_native + + rotated_sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon_ctr, lat_ctr, angle_units, 1, \ + lon_tile_corners_face_midpts_native, \ + lat_tile_corners_face_midpts_native) + lon_verts = sphr_coords@lon_out + lat_verts = sphr_coords@lat_out + x_tile_corners_face_midpts_native = rotated_sphr_coords@lon_out + y_tile_corners_face_midpts_native = rotated_sphr_coords@lat_out + + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + + lon_ctr = lon_ctr_native + lat_ctr = lat_ctr_native + lat1 = lat_ctr + lat2 = lat_ctr + + lambert_coords \ + := convert_sphr_coords_to_lambert_cnfrml( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + lon_tile_corners_face_midpts_native, \ + lat_tile_corners_face_midpts_native) + x_tile_corners_face_midpts_native = lambert_coords@x + y_tile_corners_face_midpts_native = lambert_coords@y + + end if + end if + + i = 0 + x_SW_native = x_tile_corners_face_midpts_native(i) + y_SW_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_S_native = x_tile_corners_face_midpts_native(i) + y_S_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_SE_native = x_tile_corners_face_midpts_native(i) + y_SE_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_E_native = x_tile_corners_face_midpts_native(i) + y_E_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_NE_native = x_tile_corners_face_midpts_native(i) + y_NE_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_N_native = x_tile_corners_face_midpts_native(i) + y_N_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_NW_native = x_tile_corners_face_midpts_native(i) + y_NW_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_W_native = x_tile_corners_face_midpts_native(i) + y_W_native = y_tile_corners_face_midpts_native(i) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + dx = dx_native + dy = dy_native +; num_margin_cells = 1 + num_margin_cells = 5 +; num_margin_cells = 100 +; +; ********************************************************************** +; +; Reduce the extent of the write-component grid in both the positive and +; negative x directions until the latitude of the center of the west +; face of the write-component grid is greater than that of the native +; grid, and the latitude of the center of the east face of the write- +; component grid is less than that of the native grid (i.e. the write- +; component grid lies within the native grid in the x direction). Then, +; as an extra safety measure, reduce each of these extents by a further +; nc_reduce_extra_max cells of size dx. +; +; ********************************************************************** +; + x_W_native_max = max((/x_SW_native, x_W_native, x_NW_native/)) + x_E_native_min = min((/x_SE_native, x_E_native, x_NE_native/)) + + x_W = x_W_native_max + num_margin_cells*dx + x_E = x_E_native_min - num_margin_cells*dx + + Lx = x_E - x_W + Lx_ovr_dx = Lx/dx + nx = tointeger(Lx_ovr_dx) + frac_x = Lx_ovr_dx - nx + x_adj = (0.5d+0*frac_x)*dx + x_W = x_W + x_adj + x_E = x_E - x_adj +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + y_S_native_max = max((/y_SW_native, y_S_native, y_SE_native/)) + y_N_native_min = min((/y_NW_native, y_N_native, y_NE_native/)) + + y_S = y_S_native_max + num_margin_cells*dy + y_N = y_N_native_min - num_margin_cells*dy + + y_S_tmp = y_S + y_N_tmp = y_N + y_S = -min(abs((/y_S_tmp, y_N_tmp/))) + y_N = -y_S + + Ly = y_N - y_S + Ly_ovr_dy = Ly/dy + ny = tointeger(Ly_ovr_dy) + frac_y = Ly_ovr_dy - ny + y_adj = (0.5d+0*frac_y)*dy + y_S = y_S + y_adj + y_N = y_N - y_adj +; +; ********************************************************************** +; +; Calculate the spherical coordinates of the southwest corner of the na- +; tive grid from its Lambert coordinates. +; +; ********************************************************************** +; + x_W = x_W + 0.5*dx + x_E = x_E - 0.5*dx + + y_S = y_S + 0.5*dy + y_N = y_N - 0.5*dy + + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon_ctr, lat_ctr, angle_units, -1, \ + x_W, y_S) + lon_SW = sphr_coords@lon_out + lat_SW = sphr_coords@lat_out + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + sphr_coords \ + := convert_lambert_cnfrml_coords_to_sphr( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + x_W, y_S) + lon_SW = sphr_coords@lon + lat_SW = sphr_coords@lat + end if + end if +; +; ********************************************************************** +; +; Create a string array containing the names of the Lambert conformal +; output grid parameters that appear in the NEMS model_configure file. +; +; ********************************************************************** +; + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + + param_names = (/ \ + "output_grid", \ + "cen_lon", \ + "cen_lat", \ + "lon1", \ + "lat1", \ + "lon2", \ + "lat2", \ + "dlon", \ + "dlat" /) + + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + + param_names = (/ \ + "output_grid", \ + "cen_lon", \ + "cen_lat", \ + "stdlat1", \ + "stdlat2", \ + "nx", \ + "ny", \ + "lon1", \ + "lat1", \ + "dx", \ + "dy" /) + + end if + end if +; +; ********************************************************************** +; +; Get the number of Lambert conformal output grid parameters that need +; to be se tin the NEMS model_configure file. Then initialize string +; arrays needed in setting these parameters. +; +; ********************************************************************** +; + num_params = dimsizes(param_names) + param_names_and_vals := new(num_params, "string") + trailing_comments := new(num_params, "string") +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + np = 0 + param_name = param_names(np) +; param_value := char_sq + "lambert_conformal" + char_sq + param_value := char_sq + wrtcmp_coord_sys + char_sq + param_value_str := tostring(param_value) + + regex_search = "^(\s*" + param_name + ":\s+)(<" + param_name + ">)(\s*)(.*)" + + regex_print = "\1" + param_value_str + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + wrtcmp_config_fn + param_names_and_vals(np) = systemfunc(sed_cmd) + + regex_print = "\4" + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + wrtcmp_config_fn + trailing_comments(np) = systemfunc(sed_cmd) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + do np=1, num_params-1 + + param_name := param_names(np) + unrecognized_param = False + + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + + if (strcmp_exact(param_name, "cen_lon")) then + param_value := lon_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "cen_lat")) then + param_value := lat_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lon1")) then + param_value := rot_lon_SW + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lat1")) then + param_value := rot_lat_SW + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lon2")) then + param_value := rot_lon_NE + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lat2")) then + param_value := rot_lat_NE + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dlon")) then + param_value := dlon + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dlat")) then + param_value := dlat + fmt_str = "%16.8f" + else + unrecognized_param = True + end if + end if + end if + end if + end if + end if + end if + end if + + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + + if (strcmp_exact(param_name, "cen_lon")) then + param_value := lon_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "cen_lat")) then + param_value := lat_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "stdlat1")) then + param_value := lat1 + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "stdlat2")) then + param_value := lat2 + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "nx")) then + param_value := nx + fmt_str = "%10.0f" + else if (strcmp_exact(param_name, "ny")) then + param_value := ny + fmt_str = "%10.0f" + else if (strcmp_exact(param_name, "lon1")) then + param_value := lon_SW + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lat1")) then + param_value := lat_SW + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dx")) then + param_value := dx + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dy")) then + param_value := dy + fmt_str = "%16.8f" + else + unrecognized_param = True + end if + end if + end if + end if + end if + end if + end if + end if + end if + end if + + end if + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + if (unrecognized_param) then + msg := char_nl + \ +"Unknown parameter name specified for given output_coord_sys:" + char_nl + \ +" output_coord_sys = " + char_dq + output_coord_sys + char_dq + char_nl + \ +" param_name = " + char_dq + param_name + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; Generate a string containing the parameter value and formatted as spe- +; cified by fmt_str. Then strip any leading and trailing whitespace +; from it. +; + param_value_str := sprintf(fmt_str, param_value) + param_value_str := str_strip(param_value_str) +; +; Set the regular expression to search for. +; + regex_search = "^(\s*" + param_name + ":\s+)(<" + param_name + ">)(\s*)(.*)" +; +; Get the parameter name and value without the trailing comment (if any). +; + regex_print = "\1" + param_value_str + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + wrtcmp_config_fn + param_names_and_vals(np) = systemfunc(sed_cmd) +; +; Get the trailing name and comment. +; + regex_print = "\4" + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + wrtcmp_config_fn + trailing_comments(np) = systemfunc(sed_cmd) + + end do +; +; ********************************************************************** +; +; Generate a string array containing each line in the model_configure +; file that specifies a parameter describing the write-component output +; grid. Each such line will contain the parameter name, value, and any +; trailing comments, with the trailing comments aligned for readability. +; +; ********************************************************************** +; + lines_final := strpad(param_names_and_vals, " ", "right") + lines_final := lines_final + " " + trailing_comments +; +; ********************************************************************** +; +; Loop through the set of parameters and find the line in the template +; file where each is set. Then replace that line with the corresponding +; line generated above containing the parameter name, its value, and the +; optional aligned comment. +; +; ********************************************************************** +; + do np=0, num_params-1 + param_name = param_names(np) + regex_search = "^(\s*" + param_name + ":\s+)(<" + param_name + ">)(\s*)(.*)" + regex_replace = lines_final(np) + sed_cmd = "sed -i -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_replace + "|" + char_dq + " " + wrtcmp_config_fn + sed_output = systemfunc(sed_cmd) + end do +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + out = True + return(out) + +end + diff --git a/ush/NCL/calc_wrtcmp_grid_params_lambert_cnfrml.ncl b/ush/NCL/calc_wrtcmp_grid_params_lambert_cnfrml.ncl new file mode 100644 index 0000000000..07b45c261b --- /dev/null +++ b/ush/NCL/calc_wrtcmp_grid_params_lambert_cnfrml.ncl @@ -0,0 +1,400 @@ +; +; ********************************************************************** +; +; Load files. +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "strpad.ncl") +loadscript(lib_location + "repeat_str.ncl") +loadscript(lib_location + "convert_sphr_coords_to_lambert_cnfrml.ncl") +loadscript(lib_location + "convert_lambert_cnfrml_coords_to_sphr.ncl") + +undef("calc_wrtcmp_grid_params_lambert_cnfrml") + +function calc_wrtcmp_grid_params_lambert_cnfrml( \ + model_config_tmpl_fp:string, \ + lon_ctr_native:snumeric, lat_ctr_native:snumeric, \ + lon_tile_corners_face_midpts_native[8]:snumeric, \ + lat_tile_corners_face_midpts_native[8]:snumeric, \ + dx_native:snumeric, dy_native:snumeric, \ + angle_units:string) + +local lon_ctr, lat_ctr, lat1, lat2, \ + x_SW_native, y_SW_native, \ + num_gap_cells, \ + dx, x_SW, x_NE, Lx, Lx_ovr_dx, nx, frac_x, x_increment, \ + dy, y_SW, y_NE, Ly, Ly_ovr_dy, ny, frac_y, y_increment, \ + sphr_coords, lonctr_ll_cell, latctr_ll_cell, \ + param_names, num_params, param_names_and_vals, trailing_comments, \ + np, param_name, param_value, param_value_str, \ + regex_search, regex_print, sed_cmd, \ + fmt_str, msg, \ + str_lens, str_len_max, num_delimit_spaces, delimit_spaces, \ + lines_final, regex_replace, sed_output, \ + out + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Set the coordinates of the center of the write-component output grid +; to be equal to those of the native grid. Also, set the latitudes de- +; fining the two standard parallels of the Lambert conformal projection +; used by the output grid to the latitude of the output grid center. +; +; ********************************************************************** +; + lon_ctr = lon_ctr_native + lat_ctr = lat_ctr_native + lat1 = lat_ctr + lat2 = lat_ctr +; +; ********************************************************************** +; +; Calculate the Lambert coordinates of the southwest corner of the na- +; tive grid from its spherical coordinates. +; +; ********************************************************************** +; + lambert_coords \ + := convert_sphr_coords_to_lambert_cnfrml( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + lon_tile_corners_face_midpts_native, \ + lat_tile_corners_face_midpts_native) + x_tile_corners_face_midpts_native = lambert_coords@x + y_tile_corners_face_midpts_native = lambert_coords@y + + i = 0 + x_SW_native = x_tile_corners_face_midpts_native(i) + y_SW_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_S_native = x_tile_corners_face_midpts_native(i) + y_S_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_SE_native = x_tile_corners_face_midpts_native(i) + y_SE_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_E_native = x_tile_corners_face_midpts_native(i) + y_E_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_NE_native = x_tile_corners_face_midpts_native(i) + y_NE_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_N_native = x_tile_corners_face_midpts_native(i) + y_N_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_NW_native = x_tile_corners_face_midpts_native(i) + y_NW_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_W_native = x_tile_corners_face_midpts_native(i) + y_W_native = y_tile_corners_face_midpts_native(i) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + dx = dx_native + dy = dy_native + num_margin_cells = 1 +; num_margin_cells = 5 +; num_margin_cells = 100 +; +; ********************************************************************** +; +; Reduce the extent of the write-component grid in both the positive and +; negative x directions until the latitude of the center of the west +; face of the write-component grid is greater than that of the native +; grid, and the latitude of the center of the east face of the write- +; component grid is less than that of the native grid (i.e. the write- +; component grid lies within the native grid in the x direction). Then, +; as an extra safety measure, reduce each of these extents by a further +; nc_reduce_extra_max cells of size dx. +; +; ********************************************************************** +; + x_W_native_max = max((/x_SW_native, x_W_native, x_NW_native/)) + x_E_native_min = min((/x_SE_native, x_E_native, x_NE_native/)) + + x_W = x_W_native_max + num_margin_cells*dx + x_E = x_E_native_min - num_margin_cells*dx + + Lx = x_E - x_W + Lx_ovr_dx = Lx/dx + nx = tointeger(Lx_ovr_dx) + frac_x = Lx_ovr_dx - nx + x_adj = (0.5d+0*frac_x)*dx + x_W = x_W + x_adj + x_E = x_E - x_adj +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + y_S_native_max = max((/y_SW_native, y_S_native, y_SE_native/)) + y_N_native_min = min((/y_NW_native, y_N_native, y_NE_native/)) + + y_S = y_S_native_max + num_margin_cells*dy + y_N = y_N_native_min - num_margin_cells*dy + +; The following forces the write-component domain in Lambert conformal +; space (i.e. the xy-plane) to be symmetric (about (x,y)=(0,0)) in the y +; direction. Can't remember why I wanted to enforece this... + y_S = -min(abs((/y_S, y_N/))) + y_N = -y_S + + Ly = y_N - y_S + Ly_ovr_dy = Ly/dy + ny = tointeger(Ly_ovr_dy) + frac_y = Ly_ovr_dy - ny + y_adj = (0.5d+0*frac_y)*dy + y_S = y_S + y_adj + y_N = y_N - y_adj +; +; ********************************************************************** +; +; Calculate the spherical coordinates of the southwest corner of the +; native grid from its Lambert coordinates. +; +; Note that the coordinates that the write-component takes as input are +; those of the center of the grid cell at the lower-left corner of the +; grid. However, the Lambert coordinates (x_W, y_S) caluclated above +; are those of the lower-left vertex (not center) of that cell. Thus, +; we first add half a grid distance in the x and y directions to the +; Lambert coordinates of the vertex to obtain the Lambert coordinates of +; the cell center. We then convert the result to spherical coordinates. +; +; ********************************************************************** +; + xctr_ll_cell = x_W + 0.5*dx + yctr_ll_cell = y_S + 0.5*dy + + sphr_coords \ + := convert_lambert_cnfrml_coords_to_sphr( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + xctr_ll_cell, yctr_ll_cell) + lonctr_ll_cell = sphr_coords@lon + latctr_ll_cell = sphr_coords@lat +; +; ********************************************************************** +; +; Create a string array containing the names of the Lambert conformal +; output grid parameters that appear in the NEMS model_configure file. +; +; ********************************************************************** +; + param_names = (/ \ + "output_grid", \ + "cen_lon", \ + "cen_lat", \ + "stdlat1", \ + "stdlat2", \ + "nx", \ + "ny", \ + "lon1", \ + "lat1", \ + "dx", \ + "dy" /) +; +; ********************************************************************** +; +; Get the number of Lambert conformal output grid parameters that need +; to be se tin the NEMS model_configure file. Then initialize string +; arrays needed in setting these parameters. +; +; ********************************************************************** +; + num_params = dimsizes(param_names) + param_names_and_vals := new(num_params, "string") + trailing_comments := new(num_params, "string") +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + np = 0 + param_name = param_names(np) + param_value := char_sq + "lambert_conformal" + char_sq + param_value_str := tostring(param_value) + + regex_search = "^(\s*" + param_name + ":\s+)('\{\{\s*" + param_name + "\s*\}\}')(\s*)(.*)" + + regex_print = "\1" + param_value_str + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + param_names_and_vals(np) = systemfunc(sed_cmd) + + regex_print = "\4" + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + trailing_comments(np) = systemfunc(sed_cmd) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + do np=1, num_params-1 + + param_name := param_names(np) + + if (strcmp_exact(param_name, "cen_lon")) then + param_value := lon_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "cen_lat")) then + param_value := lat_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "stdlat1")) then + param_value := lat1 + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "stdlat2")) then + param_value := lat2 + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "nx")) then + param_value := nx + fmt_str = "%10.0f" + else if (strcmp_exact(param_name, "ny")) then + param_value := ny + fmt_str = "%10.0f" + else if (strcmp_exact(param_name, "lon1")) then + param_value := lonctr_ll_cell + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lat1")) then + param_value := latctr_ll_cell + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dx")) then + param_value := dx + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dy")) then + param_value := dy + fmt_str = "%16.8f" + else + + msg := char_nl + \ +"Unknown parameter name specified for given output_coord_sys:" + char_nl + \ +" output_coord_sys = " + char_dq + output_coord_sys + char_dq + char_nl + \ +" param_name = " + char_dq + param_name + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if + end if + end if + end if + end if + end if + end if + end if + end if +; +; Generate a string containing the parameter value and formatted as spe- +; cified by fmt_str. Then strip any leading and trailing whitespace +; from it. +; + param_value_str := sprintf(fmt_str, param_value) + param_value_str := str_strip(param_value_str) +; +; Set the regular expression to search for. +; + regex_search = "^(\s*" + param_name + ":\s+)(\{\{\s*" + param_name + "\s*\}\})(\s*)(.*)" +; +; Get the parameter name and value without the trailing comment (if any). +; + regex_print = "\1" + param_value_str + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + tmp := systemfunc(sed_cmd) + param_names_and_vals(np) = tmp(0) +; +; Get the trailing name and comment. +; + regex_print = "\4" + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + tmp := systemfunc(sed_cmd) + trailing_comments(np) = tmp(0) + + end do +; +; ********************************************************************** +; +; Generate a string array containing each line in the model_configure +; file that specifies a parameter describing the write-component output +; grid. Each such line will contain the parameter name, value, and an +; trailing comment, with the trailing comments aligned for readability. +; +; ********************************************************************** +; + lines_final := strpad(param_names_and_vals, " ", "right") + lines_final := lines_final + " " + trailing_comments +; +; ********************************************************************** +; +; Print out the write-component parameter values calculated above. +; +; ********************************************************************** +; + msg := char_nl + \ +"Write-component parameters corresponding to this native grid are:" + char_nl + print("" + msg) + print("" + lines_final) +; +; ********************************************************************** +; +; Loop through the set of parameters and find the line in the template +; file where each is set. Then replace that line with the corresponding +; line generated above containing the parameter name, its value, and the +; optional aligned comment. +; +; ********************************************************************** +; + do np=0, num_params-1 + param_name = param_names(np) + regex_search = "^(\s*" + param_name + ":\s+)(<" + param_name + ">)(\s*)(.*)" + regex_replace = lines_final(np) + sed_cmd = "sed -i -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_replace + "|" + char_dq + " " + wrtcmp_config_fn + sed_output = systemfunc(sed_cmd) + end do +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + out = True + return(out) + +end + diff --git a/ush/NCL/calc_wrtcmp_grid_params_rotated_latlon.ncl b/ush/NCL/calc_wrtcmp_grid_params_rotated_latlon.ncl new file mode 100644 index 0000000000..b74925d124 --- /dev/null +++ b/ush/NCL/calc_wrtcmp_grid_params_rotated_latlon.ncl @@ -0,0 +1,560 @@ +; +; ********************************************************************** +; +; Load files. +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "strpad.ncl") +loadscript(lib_location + "repeat_str.ncl") +loadscript(lib_location + "interpol_extrapol_linear.ncl") +loadscript(lib_location + "calc_rotated_sphr_coords_from_sphr.ncl") +loadscript(lib_location + "calc_sphr_coords_from_rotated_sphr.ncl") +loadscript(lib_location + "convert_from_to_sphr_coords_to_from_rotated_sphr.ncl") + +undef("calc_wrtcmp_grid_params_rotated_latlon") + +function calc_wrtcmp_grid_params_rotated_latlon( \ + model_config_tmpl_fp:string, \ + lon_ctr_native:snumeric, lat_ctr_native:snumeric, \ + lon_tile_corners_face_midpts_native[8]:snumeric, \ + lat_tile_corners_face_midpts_native[8]:snumeric, \ + lon_bdy_native[*]:snumeric, \ + lat_bdy_native[*]:snumeric, \ + nx_native:snumeric, ny_native:snumeric, \ + dx_native:snumeric, dy_native:snumeric, \ + angle_units:string) + +local lon_ctr, lat_ctr, lat1, lat2, \ + x_SW_native, y_SW_native, \ + num_gap_cells, \ + dx, x_SW, x_NE, Lx, Lx_ovr_dx, nx, frac_x, x_increment, \ + dy, y_SW, y_NE, Ly, Ly_ovr_dy, ny, frac_y, y_increment, \ + sphr_coords, lon_SW, lat_SW, \ + param_names, num_params, param_names_and_vals, trailing_comments, \ + np, param_name, param_value, param_value_str, \ + regex_search, regex_print, sed_cmd, \ + fmt_str, msg, \ + str_lens, str_len_max, num_delimit_spaces, delimit_spaces, \ + lines_final, regex_replace, sed_output, \ + out + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Set the coordinates of the center of the write-component output grid +; to be equal to those of the native grid. Also, set the latitudes de- +; fining the two standard parallels of the Lambert conformal projection +; used by the output grid to the latitude of the output grid center. +; +; ********************************************************************** +; + lon_ctr = lon_ctr_native + lat_ctr = lat_ctr_native +; +; ********************************************************************** +; +; The following is a manual intervention to ensure that the first elements +; of lon_tile_corners_face_midpts_native and lat_tile_corners_face_midpts_native +; represent the southwest corner of the grid. If that is already the case, +; i_start should be set to 0. +; +; Note that this will not be the case for a GFDLgrid type of grid because +; for that case, tile 6 on which the regional grid (tile 7) is based starts +; its numbering such that the northeast corner of the tile is (i,j) = (0,0), +; and i increases going west while j increases going south. For that case, +; i_start must be set to 4 (since the northwest corner is the first element +; and thus has an index of 0, so we have to march four points forward - +; to the midpoint of the north face, then to the northwest corner, then +; to the midpoint of the west face, and finally to the southwest corner). +; +; The following may also be needed for grids (of either GFDLgrid or ESGgrid +; type) that straddle the international date line (which is the case if +; they include one or the other pole). The RAP domain is such an example. +; In such cases, the order of the coordinates must be manually verified +; and possbily fixed using the code below. +; +; ********************************************************************** +; +if (False) +;if (True) + +print("") +print("(lon_tile_corners_face_midpts_native, lat_tile_corners_face_midpts_native) = " + \ + lon_tile_corners_face_midpts_native + ", " + \ + lat_tile_corners_face_midpts_native) +pause + + i_start = 4 + + nn = dimsizes(lon_tile_corners_face_midpts_native) + i_end = i_start + nn - 1 + + i_vec = ispan(i_start, i_end, 1) + i_vec = where(i_vec .gt. nn-1, i_vec - nn, i_vec) + + lon_tile_corners_face_midpts_native := lon_tile_corners_face_midpts_native(i_vec) + lat_tile_corners_face_midpts_native := lat_tile_corners_face_midpts_native(i_vec) +print("") +print("(lon_tile_corners_face_midpts_native, lat_tile_corners_face_midpts_native) = " + \ + lon_tile_corners_face_midpts_native + ", " + \ + lat_tile_corners_face_midpts_native) +pause + +end if +; +; ********************************************************************** +; +; Calculate the rotated spherical coordinates of the southwest corner of +; the native grid from its spherical coordinates. +; +; ********************************************************************** +; +;print("") +;print("(lon_tile_corners_face_midpts_native, lat_tile_corners_face_midpts_native) = " + \ +; lon_tile_corners_face_midpts_native + ", " + \ +; lat_tile_corners_face_midpts_native) +;pause + + rotated_sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon_ctr, lat_ctr, angle_units, 1, \ + lon_tile_corners_face_midpts_native, \ + lat_tile_corners_face_midpts_native) + x_tile_corners_face_midpts_native = rotated_sphr_coords@lon_out + y_tile_corners_face_midpts_native = rotated_sphr_coords@lat_out + + rotated_sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon_ctr, lat_ctr, angle_units, 1, \ + lon_bdy_native, \ + lat_bdy_native) + x_bdy_native = rotated_sphr_coords@lon_out + y_bdy_native = rotated_sphr_coords@lat_out + +;print("") +;print("(x_tile_corners_face_midpts_native, y_tile_corners_face_midpts_native) = " + \ +; x_tile_corners_face_midpts_native + ", " + \ +; y_tile_corners_face_midpts_native) +;pause + + i = 0 + x_SW_native = x_tile_corners_face_midpts_native(i) + y_SW_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_S_native = x_tile_corners_face_midpts_native(i) + y_S_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_SE_native = x_tile_corners_face_midpts_native(i) + y_SE_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_E_native = x_tile_corners_face_midpts_native(i) + y_E_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_NE_native = x_tile_corners_face_midpts_native(i) + y_NE_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_N_native = x_tile_corners_face_midpts_native(i) + y_N_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_NW_native = x_tile_corners_face_midpts_native(i) + y_NW_native = y_tile_corners_face_midpts_native(i) + + i = i + 1 + x_W_native = x_tile_corners_face_midpts_native(i) + y_W_native = y_tile_corners_face_midpts_native(i) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + +; Calculate grid size in degrees along the rotated spherical coordinates. + dx = (dx_native/rad_Earth)*degs_per_rad + dy = (dy_native/rad_Earth)*degs_per_rad + + num_margin_cells = 1 +; num_margin_cells = 5 +; num_margin_cells = 100 +; +; ********************************************************************** +; +; Reduce the extent of the write-component grid in both the positive and +; negative x directions until the latitude of the center of the west +; face of the write-component grid is greater than that of the native +; grid, and the latitude of the center of the east face of the write- +; component grid is less than that of the native grid (i.e. the write- +; component grid lies within the native grid in the x direction). Then, +; as an extra safety measure, reduce each of these extents by a further +; nc_reduce_extra_max cells of size dx. +; +; ********************************************************************** +; + x_W_native_max = max((/x_SW_native, x_W_native, x_NW_native/)) + x_E_native_min = min((/x_SE_native, x_E_native, x_NE_native/)) + + x_W = x_W_native_max + num_margin_cells*dx + x_E = x_E_native_min - num_margin_cells*dx + + Lx = x_E - x_W + Lx_ovr_dx = Lx/dx + nx = tointeger(Lx_ovr_dx) + frac_x = Lx_ovr_dx - nx + x_adj = (0.5d+0*frac_x)*dx + x_W = x_W + x_adj + x_E = x_E - x_adj +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + y_S_native_max = max((/y_SW_native, y_S_native, y_SE_native/)) + y_N_native_min = min((/y_NW_native, y_N_native, y_NE_native/)) + +; +; The following code is for the case in which in the xy-plane [i.e. in the +; lonp-latp plane, where lonp and latp are the rotated latlon coordinates +; (with the "p" indicating "prime")] the left and right boundaries are +; concave (bow into the domain) and the bottom and top boundaries are +; convex (bow out of the domain). It allows the write-component domain +; in the y (i.e. latp) direction to be slightly larger by calculating +; the lower and upper bounds of the domain in a less conservative way. +; This needs to be generalized to cases in which the left and right +; boundaries are convex and the bottom and top boundaries are convex. +; +; This code (after generalization) needs to be included in the file +; calc_wrtcmp_grid_params_lambert_cnfrml.ncl. +; +if (True) then +;if (False) then + + if ((y_S_native .lt. y_SW_native) .and. (y_S_native .lt. y_SE_native)) then + + indx_start = 0 + indx_end = indx_start + nx_native + x_bdy_native_bot := x_bdy_native(indx_start:indx_end) + y_bdy_native_bot := y_bdy_native(indx_start:indx_end) + + inds_sort := dim_pqsort(x_bdy_native_bot, 2) + y_bdy_native_bot := y_bdy_native_bot(inds_sort) + + indx_nearest = ind_nearest_coord(x_W_native_max, x_bdy_native_bot, 0) + if (x_W_native_max .lt. x_bdy_native_bot(indx_nearest)) then + indx_1 = indx_nearest - 1 + indx_2 = indx_nearest + else if (x_W_native_max .ge. x_bdy_native_bot(indx_nearest)) then + indx_1 = indx_nearest + indx_2 = indx_nearest + 1 + end if + end if + +; y_S_native_max_linear := interpol_extrapol_linear( \ +; x_SW_native, y_SW_native, \ +; x_S_native, y_S_native, \ +; x_W_native_max) + y_S_native_max = interpol_extrapol_linear( \ + x_bdy_native_bot(indx_1), y_bdy_native_bot(indx_1), \ + x_bdy_native_bot(indx_2), y_bdy_native_bot(indx_2), \ + x_W_native_max) +;print("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN") +;print("y_S_native_max_linear = " + y_S_native_max_linear) +;print("y_S_native_max = " + y_S_native_max) +;pause + + end if + + + if ((y_N_native .gt. y_NW_native) .and. (y_N_native .gt. y_NE_native)) then + + indx_start = nx_native + ny_native + indx_end = indx_start + nx_native + x_bdy_native_top := x_bdy_native(indx_start:indx_end) + y_bdy_native_top := y_bdy_native(indx_start:indx_end) + + inds_sort := dim_pqsort(x_bdy_native_top, 2) + y_bdy_native_top := y_bdy_native_top(inds_sort) + + indx_nearest = ind_nearest_coord(x_W_native_max, x_bdy_native_top, 0) + if (x_W_native_max .lt. x_bdy_native_top(indx_nearest)) then + indx_1 = indx_nearest - 1 + indx_2 = indx_nearest + else if (x_W_native_max .ge. x_bdy_native_top(indx_nearest)) then + indx_1 = indx_nearest + indx_2 = indx_nearest + 1 + end if + end if + +; y_N_native_min_linear := interpol_extrapol_linear( \ +; x_NW_native, y_NW_native, \ +; x_N_native, y_N_native, \ +; x_W_native_max) + y_N_native_min = interpol_extrapol_linear( \ + x_bdy_native_top(indx_1), y_bdy_native_top(indx_1), \ + x_bdy_native_top(indx_2), y_bdy_native_top(indx_2), \ + x_W_native_max) +;print("NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN") +;print("y_N_native_min_linear = " + y_N_native_min_linear) +;print("y_N_native_min = " + y_N_native_min) +;pause + + end if + +end if + + + + y_S = y_S_native_max + num_margin_cells*dy + y_N = y_N_native_min - num_margin_cells*dy +print("") +print("y_S = " + y_S) +print("y_N = " + y_N) + + y_S = -min(abs((/y_S, y_N/))) + y_N = -y_S + + Ly = y_N - y_S + Ly_ovr_dy = Ly/dy + ny = tointeger(Ly_ovr_dy) + frac_y = Ly_ovr_dy - ny + y_adj = (0.5d+0*frac_y)*dy + y_S = y_S + y_adj + y_N = y_N - y_adj +; +; ********************************************************************** +; +; Calculate the spherical coordinates of the southwest corner of the +; native grid from its rotated latlon coordinates. +; +; ********************************************************************** +; + lon_ctr_ll_cell = x_W + 0.5*dx + lat_ctr_ll_cell = y_S + 0.5*dy + + lon_ctr_ur_cell = x_E - 0.5*dx + lat_ctr_ur_cell = y_N - 0.5*dy + +; dlon = dx*degs_per_rad +; dlat = dy*degs_per_rad + + dlon = dx + dlat = dy + +; sphr_coords \ +; := calc_sphr_coords_from_rotated_sphr( \ +; lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ +; x_W, y_S) +; lon_SW = sphr_coords@lon +; lat_SW = sphr_coords@lat +; +; ********************************************************************** +; +; Create a string array containing the names of the Lambert conformal +; output grid parameters that appear in the NEMS model_configure file. +; +; ********************************************************************** +; + param_names = (/ \ + "output_grid", \ + "cen_lon", \ + "cen_lat", \ + "lon1", \ + "lat1", \ + "lon2", \ + "lat2", \ + "dlon", \ + "dlat" /) +; +; ********************************************************************** +; +; Get the number of Lambert conformal output grid parameters that need +; to be se tin the NEMS model_configure file. Then initialize string +; arrays needed in setting these parameters. +; +; ********************************************************************** +; + num_params = dimsizes(param_names) + param_names_and_vals := new(num_params, "string") + trailing_comments := new(num_params, "string") +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + np = 0 + param_name = param_names(np) + param_value := char_sq + "rotated_latlon" + char_sq + param_value_str := tostring(param_value) + + regex_search = "^(\s*" + param_name + ":\s+)('\{\{\s*" + param_name + "\s*\}\}')(\s*)(.*)" + + regex_print = "\1" + param_value_str + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + param_names_and_vals(np) = systemfunc(sed_cmd) + + regex_print = "\4" + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + trailing_comments(np) = systemfunc(sed_cmd) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + do np=1, num_params-1 + + param_name := param_names(np) + + if (strcmp_exact(param_name, "cen_lon")) then + param_value := lon_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "cen_lat")) then + param_value := lat_ctr + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lon1")) then + param_value := lon_ctr_ll_cell + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lat1")) then + param_value := lat_ctr_ll_cell + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lon2")) then + param_value := lon_ctr_ur_cell + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "lat2")) then + param_value := lat_ctr_ur_cell + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dlon")) then + param_value := dlon + fmt_str = "%16.8f" + else if (strcmp_exact(param_name, "dlat")) then + param_value := dlat + fmt_str = "%16.8f" + else + + msg := char_nl + \ +"Unknown parameter name specified for given output_coord_sys:" + char_nl + \ +" output_coord_sys = " + char_dq + output_coord_sys + char_dq + char_nl + \ +" param_name = " + char_dq + param_name + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if + end if + end if + end if + end if + end if + end if +; +; Generate a string containing the parameter value and formatted as spe- +; cified by fmt_str. Then strip any leading and trailing whitespace +; from it. +; + param_value_str := sprintf(fmt_str, param_value) + param_value_str := str_strip(param_value_str) +; +; Set the regular expression to search for. +; + regex_search = "^(\s*" + param_name + ":\s+)(\{\{\s*" + param_name + "\s*\}\})(\s*)(.*)" +; +; Get the parameter name and value without the trailing comment (if any). +; + regex_print = "\1" + param_value_str + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + tmp := systemfunc(sed_cmd) + param_names_and_vals(np) = tmp(0) +; +; Get the trailing name and comment. +; + regex_print = "\4" + sed_cmd = "sed -n -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + model_config_tmpl_fp + tmp := systemfunc(sed_cmd) + trailing_comments(np) = tmp(0) + + end do +; +; ********************************************************************** +; +; Generate a string array containing each line in the model_configure +; file that specifies a parameter describing the write-component output +; grid. Each such line will contain the parameter name, value, and an +; trailing comment, with the trailing comments aligned for readability. +; +; ********************************************************************** +; + lines_final := strpad(param_names_and_vals, " ", "right") + lines_final := lines_final + " " + trailing_comments +; +; ********************************************************************** +; +; Print out the write-component parameter values calculated above. +; +; ********************************************************************** +; + msg := char_nl + \ +"Write-component parameters corresponding to this native grid are:" + char_nl + print("" + msg) + print("" + lines_final) +; +; ********************************************************************** +; +; Loop through the set of parameters and find the line in the template +; file where each is set. Then replace that line with the corresponding +; line generated above containing the parameter name, its value, and the +; optional aligned comment. +; +; ********************************************************************** +; + do np=0, num_params-1 + param_name = param_names(np) + regex_search = "^(\s*" + param_name + ":\s+)(<" + param_name + ">)(\s*)(.*)" + regex_replace = lines_final(np) + sed_cmd = "sed -i -r -e " + char_dq + "s|" + regex_search + "|" \ + + regex_replace + "|" + char_dq + " " + model_config_tmpl_fp + sed_output = systemfunc(sed_cmd) + end do +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + out = True + return(out) + +end + diff --git a/ush/NCL/check_filevar_existence_dims.ncl b/ush/NCL/check_filevar_existence_dims.ncl new file mode 100644 index 0000000000..b301a2d49c --- /dev/null +++ b/ush/NCL/check_filevar_existence_dims.ncl @@ -0,0 +1,595 @@ +; +; ********************************************************************** +; +; File name: check_filevar_existence_dims.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("check_filevar_existence_dims") + +function check_filevar_existence_dims( \ + file_name:string, \ + var_name:string, \ + nx:integer, ny:integer, \ + vert_inds[*]:integer, \ + time_inds[*]:integer) + +local fp, \ + all_var_names, \ + var_dim_names, var_dim_sizes, var_rankj, \ + x_filedim_names, y_filedim_names, \ + z_filedim_names, t_filedim_names, \ + x_filedim_names_str, y_filedim_names_str, \ + z_filedim_names_str, t_filedim_names_str, \ + var_dim_names_str, var_dim_sizes_str, \ + func_xy_only, func_xyz_only, func_xyt_only, func_xyzt_only, \ + msg, func_x, func_y, func_z, func_t, \ + nz, vert_inds_min, vert_inds_max, \ + nt, time_inds_min, time_inds_max, \ + x_dim_size, y_dim_size, average_in_x, average_in_y, \ + var_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Open the specified file for reading. +; +; ********************************************************************** +; + print("") + print("" + separator_line) + print("Opening file for reading:") + print("") + print(" file_name = " + char_dq + file_name + char_dq) + + fp = addfile(file_name, "r") +; +; ********************************************************************** +; +; Get the names of all variables in the file. Then check if the speci- +; filed variable is one of the ones in the file. If not, print out an +; error message and exit. +; +; ********************************************************************** +; + all_var_names = getfilevarnames(fp) + + if (.not. strcmp_exact(all_var_names, var_name)) then + msg := char_nl + \ +"Variable not found in file:" + char_nl + \ +" file_name = " + char_dq + file_name + char_dq + char_nl + \ +" var_name = " + char_dq + var_name + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; Get the variable's dimension names and sizes, and calculate the rank +; of the variable. +; +; ********************************************************************** +; + var_dim_names = getfilevardimnames(fp, var_name) + var_dim_sizes = getfilevardimsizes(fp, var_name) + var_rank = dimsizes(var_dim_sizes) +; +; ********************************************************************** +; +; Set the dimension names we expect to see in the file(s) from which we +; will read in the FV3-LAM field. This depends on the file base name. +; These dimension names will be used to check the consistency of the di- +; mensions of the specified field. +; +; ********************************************************************** +; +; x_filedim_names = (/ "grid_x", "grid_xt", "nx", "nxp" /) +; y_filedim_names = (/ "grid_y", "grid_yt", "ny", "nyp" /) +; z_filedim_names = (/ "phalf", "pfull" /) +; t_filedim_names = (/ "time" /) +; The following are temporary to be able to process ICs and surface files. +; Either make these permanent or change the gfs_data.tile7.nc and +; sfc_data.tile7.nc files to have dimension names that are consistent +; with other files (e.g. instead of xaxis_1 and lon, should have nx). + x_filedim_names = (/ "grid_x", "grid_xt", "nx", "nxp", "xaxis_1", "lon" /) + y_filedim_names = (/ "grid_y", "grid_yt", "ny", "nyp", "yaxis_1", "lat" /) + z_filedim_names = (/ "phalf", "pfull", "zaxis_1", "lev" /) + t_filedim_names = (/ "time", "Time" /) +; +; ********************************************************************** +; +; Create strings to use in output messages. +; +; ********************************************************************** +; + x_filedim_names_str := char_dq + x_filedim_names + char_dq + x_filedim_names_str := "(" + str_join(x_filedim_names_str, ", ") + ")" + + y_filedim_names_str := char_dq + y_filedim_names + char_dq + y_filedim_names_str := "(" + str_join(y_filedim_names_str, ", ") + ")" + + z_filedim_names_str := char_dq + z_filedim_names + char_dq + z_filedim_names_str := "(" + str_join(z_filedim_names_str, ", ") + ")" + + t_filedim_names_str := char_dq + t_filedim_names + char_dq + t_filedim_names_str := "(" + str_join(t_filedim_names_str, ", ") + ")" + + var_dim_names_str := char_dq + var_dim_names + char_dq + var_dim_names_str := "(" + str_join(var_dim_names_str, ", ") + ")" + + var_dim_sizes_str := tostring(var_dim_sizes) + var_dim_sizes_str := "(" + str_join(var_dim_sizes_str, ", ") + ")" +; +; ********************************************************************** +; +; Initialize the logical variables that will indicate the functional de- +; pendence of the specified variable to False. These variables are: +; +; func_xy_only: +; This will be set to True if the variable is a function of the horizon- +; tal coordinates x and y but not of the verical coordinate (referred to +; generically here as "z") or of time (referred to here as "t"). +; +; func_xyz_only: +; This will be set to True if the variable is a function of x, y, and z +; but not of t. +; +; func_xyt_only: +; This will be set to True if the variable is a function of x, y, and t +; but not of z. +; +; func_xyzt_only: +; This will be set to True if the variable is a function of x, y, z, and +; t. +; +; Note that only one of these variables will eventually get reset to +; True. +; +; ********************************************************************** +; + func_xy_only = False + func_xyz_only = False + func_xyt_only = False + func_xyzt_only = False +; +; ********************************************************************** +; +; We do not consider any variable that is not a function of at least x +; and y (which would mean that its rank is less than 2). Check for +; this. +; +; ********************************************************************** +; + if (var_rank .lt. 2) then + + msg := char_nl + \ +"The specified variable must have at least two dimensions to be plotted:" + char_nl + \ +" var_name = " + char_dq + var_name + char_dq + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +" var_dim_sizes = " + var_dim_sizes_str + char_nl + \ +"Stopping." + print("" + msg) + exit +; +; ********************************************************************** +; +; Now consider only variables that have a rank of at least 2. +; +; ********************************************************************** +; + else +; +; ********************************************************************** +; +; We require that the last dimension of the variable represent x and the +; next to last dimension represent y. Check for this. +; +; ********************************************************************** +; +; Check whether the last dimension represents the x horizontal direction +; (as defined by the string array x_filedim_names; this direction may +; be, for example, longitude). +; + func_x = False + do i=0, dimsizes(x_filedim_names)-1 + if (strcmp_exact(var_dim_names(var_rank-1), x_filedim_names(i))) then + func_x = True + break + end if + end do +; +; Check whether the next-to-last dimension represents the y horizontal +; direction (as defined by the string array y_filedim_names; this direc- +; tion may be, for example, latitude). +; + func_y = False + do i=0, dimsizes(y_filedim_names)-1 + if (strcmp_exact(var_dim_names(var_rank-2), y_filedim_names(i))) then + func_y = True + break + end if + end do +; +; If the last and next-to-last dimensions do not represent the x and y +; horizontal directions, print out an error message and exit. +; + if (.not. (func_x .and. func_y)) then + msg := char_nl + \ +"For a variable of rank greater than or equal to 2, the last dimension " + char_nl + \ +"must represent the x horizontal direction [i.e. var_dim_names(var_rank-1) " + char_nl + \ +"must be equal to one of the elements of x_filedim_names], and the next-" + char_nl + \ +"to-last dimension must represent the y horizontal direction [i.e. var_-" + char_nl + \ +"dim_names(var_rank-2) must be equal to one of the elements of y_filedim_-" + char_nl + \ +"names]:" + char_nl + \ +" var_name = " + char_dq + var_name + char_dq + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +" var_dim_names(var_rank-1) = var_dim_names(" + (var_rank-1) + ") = " + \ +char_dq + var_dim_names(var_rank-1) + char_dq + char_nl + \ +" x_filedim_names = " + x_filedim_names_str + char_nl + \ +" var_dim_names(var_rank-2) = var_dim_names(" + (var_rank-2) + ") = " + \ +char_dq + var_dim_names(var_rank-2) + char_dq + char_nl + \ +" y_filedim_names = " + y_filedim_names_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; At this point, we know that the specified variable has a rank of at +; least 2 and that its last dimension represents x and its next-to-last +; dimension represents y. Thus, if the variable has a rank of exactly +; 2, it must be a function of x and y only. In this case, set func_xy_- +; only to True. +; +; ********************************************************************** +; + if (var_rank .eq. 2) then + + func_xy_only = True +; +; ********************************************************************** +; +; Next, consider a variable of rank 3. In this case, we want the zeroth +; dimension to represent either z or t. Check for this. +; +; ********************************************************************** +; + else if (var_rank .eq. 3) then +; +; Check whether the zeroth dimension represents z. If so, set func_- +; xyz_only to True. +; + do i=0, dimsizes(z_filedim_names)-1 + if (strcmp_exact(var_dim_names(0), z_filedim_names(i))) then + func_xyz_only = True + break + end if + end do +; +; If the zeroth dimension does not represent z, check whether it repre- +; sents z. If so, set func_xyt_only to True. +; + if (.not. func_xyz_only) then + do i=0, dimsizes(t_filedim_names)-1 + if (strcmp_exact(var_dim_names(0), t_filedim_names(i))) then + func_xyt_only = True + break + end if + end do + end if +; +; If the zeroth dimension represents neither z nor t, print out an error +; message and exit. +; + if (.not. (func_xyt_only .or. func_xyz_only)) then + msg := char_nl + \ +"For a variable of rank 3, the first dimension [i.e. var_dim_names(0)] " + char_nl + \ +"must represent either time or the vertical direction [i.e. var_dim_names(0) " + char_nl + \ +"must be equal to either one of the elements of t_filedim_names or to one " + char_nl + \ +"of the elements of z_filedim_names]:" + char_nl + \ +" var_name = " + var_name + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +" var_dim_names(0) = " + char_dq + var_dim_names(0) + char_dq + char_nl + \ +" z_filedim_names = " + z_filedim_names_str + char_nl + \ +" t_filedim_names = " + t_filedim_names_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; Consider a variable of rank 4. In this case, we require the zeroth +; dimension to represent t and the first dimension to represent z. +; Check for this. +; +; ********************************************************************** +; + else if (var_rank .eq. 4) then +; +; Check whether the zeroth dimension represents t. If so, set the tem- +; porary variable func_t to True. +; + func_t = False + do i=0, dimsizes(t_filedim_names)-1 + if (strcmp_exact(var_dim_names(0), t_filedim_names(i))) then + func_t = True + break + end if + end do +; +; Check whether the first dimension represents z. If so, set the tempo- +; rary variable func_z to True. +; + func_z = False + do i=0, dimsizes(z_filedim_names)-1 + if (strcmp_exact(var_dim_names(1), z_filedim_names(i))) then + func_z = True + break + end if + end do +; +; If the zeroth dimension represents t and the first dimension repre- +; sents z, then we know that the variable is a function of x, y, z, and +; t (since we already know that the last and next-to-last dimensions +; represent x and y, respectively). In this case, we set func_xyzt_only +; to True. Otherwise, we print out an error message and exit. +; + if (func_t .and. func_z) then + func_xyzt_only = True + else + msg := char_nl + \ +"For a variable of rank 4, the first dimension [i.e. var_dim_names(0)] " + char_nl + \ +"must represent time [i.e. var_dim_names(0) must be equal to t_filedim_-" + char_nl + \ +"names], the second dimension [i.e. var_dim_names(1)] must represent the " + char_nl + \ +"vertical direction [i.e. var_dim_names(1) must be equal to one of the " + char_nl + \ +"elements of z_filedim_names], the third dimension [i.e. var_dim_names(2)] " + char_nl + \ +"must represent the y horizontal direction [i.e. var_dim_names(2) must " + char_nl + \ +"be equal to one of the elements of y_filedim_names], and the fourth di-" + char_nl + \ +"mension [i.e. var_dim_names(3)] must represent the x horizontal direc-" + char_nl + \ +"tion [i.e. var_dim_names(3) must be equal to one of the elements of x_-" + char_nl + \ +"filedim_names]:" + char_nl + \ +" var_name = " + var_name + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +" var_dim_names(0) = " + char_dq + var_dim_names(0) + char_dq + char_nl + \ +" var_dim_names(1) = " + char_dq + var_dim_names(1) + char_dq + char_nl + \ +" var_dim_names(2) = " + char_dq + var_dim_names(2) + char_dq + char_nl + \ +" var_dim_names(3) = " + char_dq + var_dim_names(3) + char_dq + char_nl + \ +" t_filedim_names = " + t_filedim_names_str + char_nl + \ +" z_filedim_names = " + z_filedim_names_str + char_nl + \ +" y_filedim_names = " + y_filedim_names_str + char_nl + \ +" x_filedim_names = " + x_filedim_names_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; We do not allow variables with rank greater than 4. +; +; ********************************************************************** +; + else + + msg := char_nl + \ +"Variables with rank greater than 4 cannot (yet) be handled by this function:" + char_nl + \ +" var_name = " + var_name + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if + end if + + end if +; +; ********************************************************************** +; +; For a variable that is a function of the vertical, ensure that the +; vertical indices at which we will attempt to make a 2-D contour plot +; of the variable are not out of the bounds of its vertical dimension. +; +; ********************************************************************** +; + if (func_xyz_only .or. func_xyzt_only) then + + if (func_xyz_only) then + nz = var_dim_sizes(0) + else + nz = var_dim_sizes(1) + end if + + vert_inds_min = min(vert_inds) + vert_inds_max = max(vert_inds) + + if (vert_inds_min .lt. 0) then + msg := char_nl + \ +"The minimum specified vertical index must be greater than or equal to 0:" + char_nl + \ +" vert_inds_min = " + vert_inds_min + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + if (vert_inds_max .ge. nz) then + msg := char_nl + \ +"The maximum specified vertical index must be less than the variable's " + char_nl + \ +"vertical dimension size (nz):" + char_nl + \ +" var_name = " + char_dq + var_name + char_dq + char_nl + \ +" nz = " + nz + char_nl + \ +" vert_inds_max = " + vert_inds_max + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + end if +; +; ********************************************************************** +; +; For a variable that is a function of time, ensure that the time indi- +; ces at which we will attempt to make a 2-D contour plot of the varia- +; ble are not out of the bounds of its time dimension. +; +; ********************************************************************** +; + if (func_xyt_only .or. func_xyzt_only) then + + nt = var_dim_sizes(0) + + time_inds_min = min(time_inds) + time_inds_max = max(time_inds) + + if (time_inds_min .lt. 0) then + msg := char_nl + \ +"The minimum specified time index must be greater than or equal to 0:" + char_nl + \ +" time_inds_min = " + time_inds_min + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + if (time_inds_max .ge. nt) then + msg := char_nl + \ +"The maximum specified time index must be less than the variable's time " + char_nl + \ +"dimension size (nt):" + char_nl + \ +" var_name = " + char_dq + var_name + char_dq + char_nl + \ +" nt = " + nt + char_nl + \ +" time_inds_max = " + time_inds_max + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + end if +; +; ********************************************************************** +; +; A variable may be given at cell centers, on the faces of cells, or at +; cell vertices. If nx and ny are the number of cells in the x and y +; directions, respectively (obtained from the grid files), then: +; +; 1) If the variable is given at cell centers, then the variable's x +; dimension size should be nx, and its y dimension size should be ny. +; +; 2) If the variable is given on cell faces that lie along curves of +; constant x (if x happens to be the west-to-east direction, these +; would be the western and eastern cell faces), then the variable's +; x dimension size should be nx+1, and its y dimension size should be +; ny. +; +; 3) If the variable is given on cell faces that lie along curves of +; constant y (if y happens to be the south-to-north direction, these +; would be the southern and northern cell faces), then the variable's +; x dimension size should be nx, and its y dimension size should be +; ny+1. +; +; 4) If the variable is given at cell veritces, then the variable's x +; dimension size should be nx+1, and its y dimension size should be +; ny+1. +; +; The plotting approach we use assumes that varaible values are given at +; cell centers. Thus, if the variable is given on cell faces that lie +; along curves of constant x, we must average the variable in the x di- +; rection to obtain a field at cell centers. Similarly, if the variable +; is given on cell faces that lie along curves of constant y, we must +; average the variable in the y direction to obtain a field at cell cen- +; ters. Finally, if the variable is given at cell vertices, we must +; average the variable in both the x and y directions to obtain a field +; at cell centers. In all cases, the field after averaging will have +; dimension sizes nx by ny. Below, we set flags that indicate the di- +; rections in which the averaging needs to be performed. +; +; ********************************************************************** +; + x_dim_size = var_dim_sizes(var_rank-1) + y_dim_size = var_dim_sizes(var_rank-2) + + if ((x_dim_size .eq. nx) .and. (y_dim_size .eq. ny)) then + average_in_x = False + average_in_y = False + else if ((x_dim_size .eq. (nx+1)) .and. (y_dim_size .eq. ny)) then + average_in_x = True + average_in_y = False + else if ((x_dim_size .eq. nx) .and. (y_dim_size .eq. (ny+1))) then + average_in_x = False + average_in_y = True + else if ((x_dim_size .eq. (nx+1)) .and. (y_dim_size .eq. (ny+1))) then + average_in_x = True + average_in_y = True + else + msg := char_nl + \ +"The horizontal dimensions of the variable read in from file [given by " + char_nl + \ +"var_dim_sizes(var_rank-1) in the x direction and var_dim_sizes(var_rank-2) " + char_nl + \ +"in the y direction] are not consistent with the dimensions (nx,ny) read " + char_nl + \ +"in from the grid file. The variable dimension sizes must be (nx,ny), " + char_nl + \ +"(nx+1,ny), (nx,ny+1), or (nx+1,ny+1):" + char_nl + \ +" (nx, ny) = (" + nx + ", " + ny + ") [These are the dimensions read from the grid file.]" + char_nl + \ +" file_name = " + char_dq + file_name + char_dq + char_nl + \ +" var_name = " + char_dq + var_name + char_dq + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +" var_dim_sizes = " + var_dim_sizes_str + char_nl + \ +" var_dim_sizes(var_rank-1) = var_dim_sizes(" + tostring(var_rank-1) + ") = " + x_dim_size + char_nl + \ +" var_dim_sizes(var_rank-2) = var_dim_sizes(" + tostring(var_rank-2) + ") = " + y_dim_size + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + end if + end if + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable var_info. +; +; ********************************************************************** +; + var_info := True + + var_info@fp = fp + var_info@var_rank = var_rank + var_info@var_dim_names = var_dim_names + var_info@var_dim_sizes = var_dim_sizes + var_info@func_xy_only = func_xy_only + var_info@func_xyz_only = func_xyz_only + var_info@func_xyt_only = func_xyt_only + var_info@func_xyzt_only = func_xyzt_only + var_info@average_in_x = average_in_x + var_info@average_in_y = average_in_y + + return(var_info) + +end + diff --git a/ush/NCL/find_wrtcmp_grid_params.ncl b/ush/NCL/find_wrtcmp_grid_params.ncl new file mode 100644 index 0000000000..01ab25f709 --- /dev/null +++ b/ush/NCL/find_wrtcmp_grid_params.ncl @@ -0,0 +1,350 @@ +; +; ********************************************************************** +; +; Declare global variables before loading files. This has the same ef- +; fect as declaring these variables on the command line. +; +; ********************************************************************** +; +;help = True + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/test_latest_20191002/expt_dirs/test_sheleg_GSD_HRRR3km_01" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_GSD_HRRR13km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/suite_FV3_GSD_SAR" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/suite_FV3_GSD_SAR_3km_works03" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/suite_FV3_GSD_SAR_3km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_SUBCONUS_3km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_CONUS_25km_GFDLgrid" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_CONUS_3km_GFDLgrid" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_AK_3km" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_AK_13km" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_AK_13km_old001" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_13km_HRRRX_RAPX" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_3km_FV3GFS_FV3GFS" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try03/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try03/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_maximize_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_maximize_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_maximize_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_Jeff_Duda_subhourly_post/expt_dirs/big_grid01/grid_GSD_RAP13km_pregen" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_Jeff_Duda_subhourly_post/expt_dirs/big_grid01/grid_GSD_RAP13km_pregen_old003" + +; +; ********************************************************************** +; +; Load external files. +; +; ********************************************************************** +; +lib_location = "lib/" + +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +load "calc_wrtcmp_grid_params_rotated_latlon.ncl" +load "calc_wrtcmp_grid_params_lambert_cnfrml.ncl" +load "read_FV3LAM_grid_native.ncl" + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name := "find_wrtcmp_grid_params(...)" +; +; ********************************************************************** +; +; Set usage message. +; +; ********************************************************************** +; + usage_msg = \ +" ncl -n find_wrtcmp_grid_params.ncl \" + char_nl + \ +" need to fill in the rest of this message" +; +; ********************************************************************** +; +; Set help message. The help message contains the documentation for +; this script and thus should reflect any changes to the code. +; +; ********************************************************************** +; + help_msg = char_nl + \ +"Need to fill in this help message." +; +; ********************************************************************** +; +; If the variable "help" is specified on the command line and is set to +; True, print out the help message and exit. +; +; ********************************************************************** +; + if (isvar("help")) then + if (help .eq. True) then + print("" + help_msg) + exit + end if + else + help = False + end if +; +; ********************************************************************** +; +; Set the full path to the varible defintions file for this experiment. +; Then read various parameters from it. +; +; ********************************************************************** +; + var_defns_fp = expt_dir + "/var_defns.sh" + + param_names = (/ \ +"MODEL_CONFIG_TMPL_FP", \ +"WRTCMP_output_grid", \ +"GTYPE", \ +"CRES", \ +"ESGgrid_DELX", \ +"ESGgrid_DELY", \ +"NH4" /) + + num_params = dimsizes(param_names) + do np=0, num_params-1 +print("np = " + np) + + param_name = param_names(np) + regex_search = "^\s*" + param_name + "=(" + char_dq + "([^" \ + + char_dq + "]+)" + char_dq + "|([^ " + char_dq + "]+))(.*)$" + regex_print = "\2\3" + sed_cmd = "sed --regexp-extended --silent --expression " + char_sq \ + + "s/" + regex_search + "/" + regex_print + "/p" + char_sq \ + + " " + var_defns_fp + sed_output = systemfunc(sed_cmd) +print("sed_output = " + sed_output) +; +; Convert the output from the sed command (which will be a string) to +; the appropriate NCL data type. +; + if (strcmp_exact(param_name, "MODEL_CONFIG_TMPL_FP")) then + MODEL_CONFIG_TMPL_FP = tostring(sed_output) + else if (strcmp_exact(param_name, "WRTCMP_output_grid")) then + WRTCMP_output_grid = tostring(sed_output) + else if (strcmp_exact(param_name, "GTYPE")) then + GTYPE = tostring(sed_output) + else if (strcmp_exact(param_name, "CRES")) then + CRES = tostring(sed_output) + else if (strcmp_exact(param_name, "ESGgrid_DELX")) then + dx_native = todouble(sed_output) +;dx_native = 25122.693954919 ; Need if using the CONUS_25km_GFDLgrid grid +;dx_native = 2964.19334212185 ; Need if using the CONUS_3km_GFDLgrid grid + else if (strcmp_exact(param_name, "ESGgrid_DELY")) then + dy_native = todouble(sed_output) +;dy_native = 25122.693954919 ; Need if using the CONUS_25km_GFDLgrid grid +;dy_native = 2964.19334212185 ; Need if using the CONUS_3km_GFDLgrid grid + else if (strcmp_exact(param_name, "NH4")) then + nhalo_T7 = tointeger(sed_output) + else + + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"The data type to convert the current variable defintions file parameter" + char_nl + \ +"to has not been spedified:" + char_nl + \ +" param_name = " + char_dq + param_name + char_dq + char_nl + \ +"Stopping." + char_nl + print("" + msg) + exit + + end if + end if + end if + end if + end if + end if + end if + + end do +; +; ********************************************************************** +; +; Check that GTYPE has the proper value. +; +; ********************************************************************** +; +print("AAAAAAAAAAAAAAAAAAAAAAAAAAA") + if (strcmp_exact(GTYPE, "regional")) then + + inds_tiles_to_plot = (/ 7 /) + + else + + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"This script is designed to handle only regional grids. Thus, GTYPE" + char_nl + \ +"may only be set to " + char_dq + "regional" + char_dq + ":" + char_nl + \ +" GTYPE = " + char_dq + GTYPE + char_dq + char_nl + \ +"Stopping." + char_nl + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; Read in the native FV3-LAM grid. +; +; ********************************************************************** +; +print("BBBBBBBBBBBBBBBBBBBBBBBBBBB") + remove_rgnl_halo = True +; get_tile_bdies = False + get_tile_bdies = True + + grid_info := read_FV3LAM_grid_native( \ + expt_dir, \ + GTYPE, \ + CRES, \ + inds_tiles_to_plot, \ + get_tile_bdies, \ + nhalo_T7, \ + remove_rgnl_halo) + + lon_tile_cntr_tiles_to_plot = grid_info@lon_tile_cntr_all_tiles + lat_tile_cntr_tiles_to_plot = grid_info@lat_tile_cntr_all_tiles + + lon_tile_corners_face_midpts_tiles_to_plot \ + = grid_info@lon_tile_corners_face_midpts_all_tiles + lat_tile_corners_face_midpts_tiles_to_plot \ + = grid_info@lat_tile_corners_face_midpts_all_tiles + + lon_bdy_tiles_to_plot = grid_info@lon_bdy_all_tiles + lat_bdy_tiles_to_plot = grid_info@lat_bdy_all_tiles + + nx_all_tiles := grid_info@nx_all_tiles + ny_all_tiles := grid_info@ny_all_tiles + +;print("LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL") +;print("dimsizes(lon_tile_corners_face_midpts_tiles_to_plot) = " + dimsizes(lon_tile_corners_face_midpts_tiles_to_plot)) +;print("dimsizes(lon_bdy_tiles_to_plot) = " + dimsizes(lon_bdy_tiles_to_plot)) +;print("dimsizes(nx_all_tiles) = " + dimsizes(nx_all_tiles)) +;pause + +;lon_tile_corners_face_midpts_tiles_to_plot \ +;= where(lon_tile_corners_face_midpts_tiles_to_plot .gt. 0.0d+0, \ +; lon_tile_corners_face_midpts_tiles_to_plot - 360.0d+0, \ +; lon_tile_corners_face_midpts_tiles_to_plot) +;print("lon_tile_corners_face_midpts_tiles_to_plot, lat_tile_corners_face_midpts_tiles_to_plot = " + \ +; lon_tile_corners_face_midpts_tiles_to_plot + ", " + lat_tile_corners_face_midpts_tiles_to_plot) +;pause +; +; ********************************************************************** +; +; Extract and save into new, appropriately dimensioned variables the +; output from the grid-read operation above. Then call the function +; that calculates the write-component grid parameters for a lambert- +; conformal grid that is guaranteed to lie completely inside the native +; FV3-LAM grid. +; +; ********************************************************************** +; + nn = 0 + + lon_grid_cntr_native = lon_tile_cntr_tiles_to_plot(nn) + lat_grid_cntr_native = lat_tile_cntr_tiles_to_plot(nn) + + lon_tile_corners_face_midpts_native \ + := lon_tile_corners_face_midpts_tiles_to_plot(nn,:) + lat_tile_corners_face_midpts_native \ + := lat_tile_corners_face_midpts_tiles_to_plot(nn,:) + + nx_native := nx_all_tiles(nn) + ny_native := ny_all_tiles(nn) +;print("nx_native = " + nx_native) +;print("ny_native = " + ny_native) +;pause + + indx_start := 0 + indx_end := 2*(nx_native + ny_native) + lon_bdy_native := lon_bdy_tiles_to_plot(indx_start:indx_end) + lat_bdy_native := lat_bdy_tiles_to_plot(indx_start:indx_end) +;print("dimsizes(lon_bdy_native) = " + dimsizes(lon_bdy_native)) +;pause + + angle_units = "deg" + + valid_vals_WRTCMP_output_grid \ + := (/ "rotated_latlon", "lambert_conformal" /) +;WRTCMP_output_grid = "rotated_latlon" + + if (strcmp_exact(valid_vals_WRTCMP_output_grid, WRTCMP_output_grid)) then + + if (strcmp_exact(WRTCMP_output_grid, "rotated_latlon")) then + + out := calc_wrtcmp_grid_params_rotated_latlon( \ + MODEL_CONFIG_TMPL_FP, \ + lon_grid_cntr_native, lat_grid_cntr_native, \ + lon_tile_corners_face_midpts_native, \ + lat_tile_corners_face_midpts_native, \ + lon_bdy_native, \ + lat_bdy_native, \ + nx_native, ny_native, \ + dx_native, dy_native, \ + angle_units) + + else if (strcmp_exact(WRTCMP_output_grid, "lambert_conformal")) then + + out := calc_wrtcmp_grid_params_lambert_cnfrml( \ + MODEL_CONFIG_TMPL_FP, \ + lon_grid_cntr_native, lat_grid_cntr_native, \ + lon_tile_corners_face_midpts_native, \ + lat_tile_corners_face_midpts_native, \ + dx_native, dy_native, \ + angle_units) + +; else if (strcmp_exact(WRTCMP_output_grid, "rotated_latlon")) then +; +; msg := char_nl + \ +;"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +;"Function to calculate write-component output grid parameters for an " + char_nl + \ +;"output grid of type " + char_dq + "rotated_latlon" + char_dq + " has " + \ +;"not yet been written:" + char_nl + \ +;" WRTCMP_output_grid = " + char_dq + WRTCMP_output_grid + char_dq + char_nl + \ +;"Stopping." + char_nl +; print("" + msg) +; exit + + end if + end if + + else + + valid_vals_str := tostring(valid_vals_WRTCMP_output_grid) + valid_vals_str := str_join(valid_vals_str, char_dq + ", " + char_dq) + valid_vals_str := "(/ " + char_dq + valid_vals_str + char_dq + " /)" + + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"Specified type of write-component output grid is not currently support-" + char_nl + \ +"ed:" + char_nl + \ +" WRTCMP_output_grid = " + char_dq + WRTCMP_output_grid + char_dq + char_nl + \ +"Currently, this script can generate write-component parameters only for" + char_nl + \ +"output grids of the following types:" + char_nl + \ +" valid_vals_WRTCMP_output_grid = " + valid_vals_str + char_nl + \ +"Stopping." + char_nl + print("" + msg) + exit + + end if + + print("") + print("Done calculating write-component grid parameters.") + +end diff --git a/ush/NCL/get_gridfield_info.ncl b/ush/NCL/get_gridfield_info.ncl new file mode 100644 index 0000000000..380b2d135a --- /dev/null +++ b/ush/NCL/get_gridfield_info.ncl @@ -0,0 +1,149 @@ +; +; ********************************************************************** +; +; File name: get_gridfield_info.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns +; +; ********************************************************************** +; + +undef("get_gridfield_info") + +function get_gridfield_info( \ + field_name:string, \ + horiz_dist_units:string, \ + horiz_area_units:string) + +local calc_dA_cell_cntrs, \ + calc_dx_cell_cntrs, \ + calc_dy_cell_cntrs, \ + calc_dx_cell_faces, \ + calc_dy_cell_faces, \ + calc_angle_dx_cell_cntrs, \ + calc_angle_dy_cell_cntrs, \ + filevar_names, \ + gridfield_desc, \ + gridfield_units + +begin +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + calc_dA_cell_cntrs = False + calc_dx_cell_cntrs = False + calc_dy_cell_cntrs = False + calc_dx_cell_faces = False + calc_dy_cell_faces = False + calc_angle_dx_cell_cntrs = False + calc_angle_dy_cell_cntrs = False + + filevar_names := default_fillvalue("string") + + if (strcmp_exact(field_name, "cell_area")) then + + gridfield_desc = "Cell Area" + gridfield_units = horiz_area_units + calc_dA_cell_cntrs = True + filevar_names := (/ "area" /) + + else if (strcmp_exact(field_name, "sqrt_cell_area")) then + + gridfield_desc = "Square Root of Cell Area" + gridfield_units = horiz_dist_units + calc_dA_cell_cntrs = True + filevar_names := (/ "area" /) + + else if (strcmp_exact(field_name, "cell_dx")) then + + gridfield_desc = "Cell Size in x-Direction Along Cell Centerline" + gridfield_units = horiz_dist_units + calc_dx_cell_cntrs = True + filevar_names := (/ "dx" /) + + else if (strcmp_exact(field_name, "cell_dy")) then + + gridfield_desc = "Cell Size in y-Direction Along Cell Centerline" + gridfield_units = horiz_dist_units + calc_dy_cell_cntrs = True + filevar_names := (/ "dy" /) + + else if (strcmp_exact(field_name, "cell_dx_ovr_cell_dy")) then + + gridfield_desc = "Ratio of dx to dy (dx/dy)" + gridfield_units = "-" + calc_dx_cell_cntrs = True + calc_dy_cell_cntrs = True + filevar_names := (/ "dx", "dy" /) + + else if (strcmp_exact(field_name, "min_cell_dx_cell_dy")) then + + gridfield_desc = "MIN(dx, dy)" + gridfield_units = horiz_dist_units + calc_dx_cell_faces = True + calc_dy_cell_faces = True + filevar_names := (/ "dx", "dy" /) + + else if (strcmp_exact(field_name, "angle_cell_dx")) then + + gridfield_desc = "Grid Vertex x-Angle with Respect to Geographic East" + gridfield_units = "deg east" + calc_angle_dx_cell_cntrs = True + filevar_names := (/ "angle_dx" /) + + else if (strcmp_exact(field_name, "angle_cell_dy")) then + + gridfield_desc = "Grid Vertex y-Angle with Respect to Geographic North" + gridfield_units = "deg north" + calc_angle_dy_cell_cntrs = True + filevar_names := (/ "angle_dy" /) + + else if (strcmp_exact(field_name, "none")) then + + gridfield_desc = "Empty Field" + gridfield_units = "-" + + else + + gridfield_desc = "Unknown Field" + gridfield_units = "?" + + end if + end if + end if + end if + end if + end if + end if + end if + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable gridfield_info. +; +; ********************************************************************** +; + gridfield_info := True + + gridfield_info@gridfield_desc := gridfield_desc + gridfield_info@gridfield_units := gridfield_units + gridfield_info@filevar_names := filevar_names + gridfield_info@calc_dA_cell_cntrs := calc_dA_cell_cntrs + gridfield_info@calc_dx_cell_cntrs := calc_dx_cell_cntrs + gridfield_info@calc_dy_cell_cntrs := calc_dy_cell_cntrs + gridfield_info@calc_dx_cell_faces := calc_dx_cell_faces + gridfield_info@calc_dy_cell_faces := calc_dy_cell_faces + gridfield_info@calc_angle_dx_cell_cntrs := calc_angle_dx_cell_cntrs + gridfield_info@calc_angle_dy_cell_cntrs := calc_angle_dy_cell_cntrs + + return(gridfield_info) + +end diff --git a/ush/NCL/get_wrtcmp_grid.ncl b/ush/NCL/get_wrtcmp_grid.ncl new file mode 100644 index 0000000000..e24e333b56 --- /dev/null +++ b/ush/NCL/get_wrtcmp_grid.ncl @@ -0,0 +1,620 @@ +; +; ********************************************************************** +; +; Load files. +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "convert_from_to_sphr_coords_to_from_rotated_sphr.ncl") +loadscript(lib_location + "convert_sphr_coords_to_lambert_cnfrml.ncl") +loadscript(lib_location + "convert_lambert_cnfrml_coords_to_sphr.ncl") + +undef("get_wrtcmp_grid") + +function get_wrtcmp_grid( \ + wrtcmp_config_fn:string, \ + get_domain_bdy:logical) + +local proj_params, \ + var_name, regex_search, regex_print, sed_cmd, \ + wrtcmp_coord_sys, valid_vals_wrtcmp_coord_sys, valid_vals, msg, \ + param_names, coord_data_type, num_params, param_name, \ + lon_ctr_rad, lat_ctr_rad, lat1_rad, lat2_rad, \ + nxm, nyp, lon_cell_cntr_SW, lat_cell_cntr_SW, dx, dy, \ + angle_units, \ + nx, ny, lambert_coords, x_cell_cntr_SW, y_cell_cntr_SW, \ + i_vec, j_vec, x_verts_vec, y_verts_vec, x_verts, y_verts, \ + sphr_coords, lon_verts, lat_verts, \ + x_cntrs, y_cntrs, lon_cntrs, lat_cntrs, \ + lon_cntrs_unstruc, lat_cntrs_unstruc, \ + lon_verts_unstruc, lat_verts_unstruc, \ + x_is_longitude, opts, corner_info, corner_lons, corner_lats, \ + fmt_str, lon_str, lat_str, \ + rem_nx, rem_ny, i_cntr, j_cntr, lon_grid_cntr, lat_grid_cntr + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Get the coordinate system in which the write-component output grid is +; specified. +; +; ********************************************************************** +; + var_name = "output_grid" + regex_search = "^\s*" + var_name + ":\s*'([^ #]*)'.*$" + regex_print = "\1" + sed_cmd = "sed -r -n -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + wrtcmp_config_fn + wrtcmp_coord_sys = systemfunc(sed_cmd) +; +; ********************************************************************** +; +; Check that the output coordinate system read in above is valid. +; +; ********************************************************************** +; + valid_vals_wrtcmp_coord_sys = (/ "rotated_latlon", "lambert_conformal" /) + + if (.not. strcmp_exact(valid_vals_wrtcmp_coord_sys, wrtcmp_coord_sys)) then + + valid_vals \ + := char_dq \ + + str_join(valid_vals_wrtcmp_coord_sys, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"The coordinate system in which the write-component output grid is spe-" + char_nl + \ +"cified (wrtcmp_coord_sys) has not been set to a valid value:" + char_nl + \ +" wrtcmp_coord_sys = " + char_dq + wrtcmp_coord_sys + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with a valid grid type. Stopping." + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; Print out the coordinate system used by the output grid. +; +; ********************************************************************** +; + msg := char_nl + \ +"The coordinate system in which the write-component output grid is spe-" + char_nl + \ +"cified (wrtcmp_coord_sys) is:" + char_nl + \ +" wrtcmp_coord_sys = " + char_dq + wrtcmp_coord_sys + char_dq + char_nl + print("" + msg) +; +; ********************************************************************** +; +; Set the names of the parameters in the write component configuration +; file that determine the transformation from spherical coordinates to +; the output coordinate system specified above (and vice versa). +; +; ********************************************************************** +; + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + + param_names = (/ \ + "cen_lon", \ + "cen_lat", \ + "lon1", \ + "lat1", \ + "lon2", \ + "lat2", \ + "dlon", \ + "dlat" /) + + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + + param_names = (/ \ + "cen_lon", \ + "cen_lat", \ + "stdlat1", \ + "stdlat2", \ + "nx", \ + "ny", \ + "lon1", \ + "lat1", \ + "dx", \ + "dy" /) + + else + + msg := char_nl + \ +"param_names has not been set for this value of the write-component out-" + char_nl + \ +"put grid coordinate system (wrtcmp_coord_sys):" + char_nl + \ +" wrtcmp_coord_sys = " + char_dq + wrtcmp_coord_sys + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if +; +; ********************************************************************** +; +; Set the data type (i.e. float or double) of the coordinate arrays for +; the write-component output grid to be "double". Note that here, we +; are constructing this grid from the "grid" parameters, so we can choose +; this data type to be whatever we like (i.e. "float" or "double"). +; +; ********************************************************************** +; + coord_data_type = "double" +; +; ********************************************************************** +; +; Loop through the list of coordinate system parameters specified above +; and get the value of each from the write-component configuration file. +; +; ********************************************************************** +; + num_params = dimsizes(param_names) + + msg = char_nl + \ +"Reading in write-component output grid coordinate system parameters " + char_nl + \ +"from file wrtcmp_config_fn:" + char_nl + \ +" wrtcmp_config_fn = " + char_dq + wrtcmp_config_fn + char_dq + + do np=0, num_params-1 + + param_name = param_names(np) + regex_search = "^\s*" + param_name + ":\s*([^ #]*).*$" + regex_print = "\1" + sed_cmd = "sed -r -n -e " + char_dq + "s|" + regex_search + "|" \ + + regex_print + "|p" + char_dq + " " + wrtcmp_config_fn + sed_output = systemfunc(sed_cmd) + + unrecognized_param = False + + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + + if (strcmp_exact(param_name, "cen_lon")) then + lon_ctr := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "cen_lat")) then + lat_ctr := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "lon1")) then + rot_lon_cell_cntr_SW := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "lat1")) then + rot_lat_cell_cntr_SW := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "lon2")) then + rot_lon_cell_cntr_NE := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "lat2")) then + rot_lat_cell_cntr_NE := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "dlon")) then + dlon := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "dlat")) then + dlat := totype(sed_output, coord_data_type) + else + unrecognized_param = True + end if + end if + end if + end if + end if + end if + end if + end if + + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + + if (strcmp_exact(param_name, "cen_lon")) then + lon_ctr := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "cen_lat")) then + lat_ctr := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "stdlat1")) then + lat1 := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "stdlat2")) then + lat2 := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "nx")) then + nx := totype(sed_output, "integer") + else if (strcmp_exact(param_name, "ny")) then + ny := totype(sed_output, "integer") + else if (strcmp_exact(param_name, "lon1")) then + lon_cell_cntr_SW := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "lat1")) then + lat_cell_cntr_SW := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "dx")) then + dx := totype(sed_output, coord_data_type) + else if (strcmp_exact(param_name, "dy")) then + dy := totype(sed_output, coord_data_type) + else + unrecognized_param = True + end if + end if + end if + end if + end if + end if + end if + end if + end if + end if + + else + + msg := char_nl + \ +"Grid parameters have not yet been specified for this value of the " + char_nl + \ +"write-component output grid coordinate system (wrtcmp_coord_sys):" + char_nl + \ +" wrtcmp_coord_sys = " + char_dq + wrtcmp_coord_sys + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + if (unrecognized_param) then + + msg := char_nl + \ +"Unknown parameter name specified for the given write-component output" + char_nl + \ +"grid coordinate system (wrtcmp_coord_sys):" + char_nl + \ +" wrtcmp_coord_sys = " + char_dq + wrtcmp_coord_sys + char_dq + char_nl + \ +" param_name = " + char_dq + param_name + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + + end do + + + + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + dx = dlon + dy = dlat + nx = (rot_lon_cell_cntr_NE - rot_lon_cell_cntr_SW)/dlon + 1 + nx := round(nx, 3) + ny = (rot_lat_cell_cntr_NE - rot_lat_cell_cntr_SW)/dlat + 1 + ny := round(ny, 3) +print("") +print("nx = " + nx) +print("ny = " + ny) +pause + end if + +; +; ********************************************************************** +; +; Print out values of parameters read in from the write-component con- +; figuration file. +; +; ********************************************************************** +; +; msg = char_nl + \ +;"Values of write-component output grid coordinate system parameters read" + char_nl + \ +;"in from the model_configure file are:" +; +; do np=0, num_params-1 +; param_name = param_names(np) +; param_value = $param_name$ +; msg = char_nl + \ +;" " + param_name + " = " + param_value +; end do + +; if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then +; +; else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then +; +; print("") +; print("" + separator_line) +; +; msg = char_nl + \ +;"Values of write-component output grid coordinate system parameters read" + char_nl + \ +;"in from the model_configure file are:" + char_nl + \ +;" lon_ctr = " + lon_ctr + char_nl + \ +;" lat_ctr = " + lat_ctr + char_nl + \ +;" lat1 = " + lat1 + char_nl + \ +;" lat2 = " + lat2 + char_nl + \ +;" nx = " + nx + char_nl + \ +;" ny = " + ny + char_nl + \ +;" lon_cell_cntr_SW = " + lon_cell_cntr_SW + char_nl + \ +;" lat_cell_cntr_SW = " + lat_cell_cntr_SW + char_nl + \ +;" dx = " + dx + char_nl + \ +;" dy = " + dy + char_nl +; print("" + msg) +; +; else +; +; msg := char_nl + \ +;"Grid parameters have not yet been specified for this value of the " + char_nl + \ +;"write-component output grid coordinate system (wrtcmp_coord_sys):" + char_nl + \ +;" wrtcmp_coord_sys = " + char_dq + wrtcmp_coord_sys + char_dq + char_nl + \ +;"Stopping." +; print("" + msg) +; exit +; +; end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + angle_units = "deg" +; +; ********************************************************************** +; +; Use the given spherical coordinates (lon_cell_cntr_SW, lat_cell_cntr_- +; SW) of the southwest corner of the grid to calculate the Lambert con- +; formal coordinates (x_cell_cntr_SW, y_cell_cntr_SW) of that corner. +; +; ********************************************************************** +; + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + x_cell_cntr_SW = rot_lon_cell_cntr_SW + y_cell_cntr_SW = rot_lat_cell_cntr_SW + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + lambert_cnfrml_coords \ + := convert_sphr_coords_to_lambert_cnfrml( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + lon_cell_cntr_SW, lat_cell_cntr_SW) + x_cell_cntr_SW = lambert_cnfrml_coords@x + y_cell_cntr_SW = lambert_cnfrml_coords@y + end if + end if + + x_min = x_cell_cntr_SW - 0.5d+0*dx + y_min = y_cell_cntr_SW - 0.5d+0*dy +; +; ********************************************************************** +; +; Construct the vectors defining the locations of the grid cell vertices +; in the plane of the Lambert conformal coordinates (x,y). Note that +; the write-component output grid is uniform in that plane. +; +; ********************************************************************** +; + i_vec := ispan(0, nx, 1) + j_vec := ispan(0, ny, 1) + + x_verts_vec := dx*i_vec + x_min + y_verts_vec := dy*j_vec + y_min +; +; ********************************************************************** +; +; Create arrays containing the Lambert conformal coordinates of the cell +; vertices of a uniform grid in the (x,y)-plane. +; +; ********************************************************************** +; + x_verts_vec := transpose(transpose(x_verts_vec)) + x_verts = x_verts_vec + do j=1, ny + x_verts := array_append_record(x_verts, x_verts_vec, 0) + end do + + y_verts_vec := transpose(transpose(y_verts_vec)) + y_verts = y_verts_vec + do i=1, nx + y_verts := array_append_record(y_verts, y_verts_vec, 0) + end do + y_verts := transpose(y_verts) +; +; ********************************************************************** +; +; Calculate the spherical coordinates corresponding to the Lambert con- +; formal coordinates of the grid cell vertices. +; +; ********************************************************************** +; + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon_ctr, lat_ctr, angle_units, -1, \ + x_verts, y_verts) + lon_verts = sphr_coords@lon_out + lat_verts = sphr_coords@lat_out + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + sphr_coords \ + := convert_lambert_cnfrml_coords_to_sphr( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + x_verts, y_verts) + lon_verts = sphr_coords@lon + lat_verts = sphr_coords@lat + end if + end if +; +; ********************************************************************** +; +; Average the x and y coordinates of the cell vertices in the (x,y) +; plane to obtain the (x,y) coordinates of the cell centers. +; +; ********************************************************************** +; + x_cntrs := 0.25d+0*( \ + x_verts(0:ny-1,0:nx-1) \ + + x_verts(0:ny-1,1:nx) \ + + x_verts(1:ny,1:nx) \ + + x_verts(1:ny,0:nx-1) \ + ) + + y_cntrs := 0.25d+0*( \ + y_verts(0:ny-1,0:nx-1) \ + + y_verts(0:ny-1,1:nx) \ + + y_verts(1:ny,1:nx) \ + + y_verts(1:ny,0:nx-1) \ + ) +; +; ********************************************************************** +; +; Calculate the spherical coordinates corresponding to the Lambert con- +; formal coordinates of the grid cell centers. +; +; ********************************************************************** +; + if (strcmp_exact(wrtcmp_coord_sys, "rotated_latlon")) then + sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon_ctr, lat_ctr, angle_units, -1, \ + x_cntrs, y_cntrs) + lon_cntrs = sphr_coords@lon_out + lat_cntrs = sphr_coords@lat_out + else if (strcmp_exact(wrtcmp_coord_sys, "lambert_conformal")) then + sphr_coords \ + := convert_lambert_cnfrml_coords_to_sphr( \ + lon_ctr, lat_ctr, lat1, lat2, rad_Earth, angle_units, \ + x_cntrs, y_cntrs) + lon_cntrs = sphr_coords@lon + lat_cntrs = sphr_coords@lat + end if + end if +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the spherical coord- +; inates of the vertices of each cell on the grid. Note that these are +; 2-D arrays whose first dimension size is the number of cells on the +; grid (i.e. nx*ny) and whose second dimension size is 4 (since each +; cell has 4 vertices). This unstructured format is useful in generat- +; ing color-contour plots of fields on the grid that have one value per +; cell represented by a flat color in that cell. +; +; ********************************************************************** +; + lon_cntrs_unstruc := ndtooned(lon_cntrs) + lat_cntrs_unstruc := ndtooned(lat_cntrs) + + lon_verts_unstruc \ + := (/ ndtooned(lon_verts(0:ny-1,0:nx-1)), \ + ndtooned(lon_verts(0:ny-1,1:nx)), \ + ndtooned(lon_verts(1:ny,1:nx)), \ + ndtooned(lon_verts(1:ny,0:nx-1)) /) + lon_verts_unstruc := transpose(lon_verts_unstruc) + + lat_verts_unstruc \ + := (/ ndtooned(lat_verts(0:ny-1,0:nx-1)), \ + ndtooned(lat_verts(0:ny-1,1:nx)), \ + ndtooned(lat_verts(1:ny,1:nx)), \ + ndtooned(lat_verts(1:ny,0:nx-1)) /) + lat_verts_unstruc := transpose(lat_verts_unstruc) +; +; ********************************************************************** +; +; If get_domain_bdy is specified to be True, save in a pair of 1-D ar- +; rays the spherical coordinates of those cell vertices that lie on the +; boundary of the grid. +; +; ********************************************************************** +; + if (get_domain_bdy) then + repeat_last_point = True + array_order = "ji" + bdy_info := get_rect_grid_bdy( \ + lon_verts, lat_verts, \ + repeat_last_point, array_order) + lon_bdy := bdy_info@x_bdy + lat_bdy := bdy_info@y_bdy + else + lon_bdy := default_fillvalue(coord_data_type) + lat_bdy := default_fillvalue(coord_data_type) + end if +; +; ********************************************************************** +; +; Find and print out the spherical coordinates of the corners of the +; grid. +; +; ********************************************************************** +; + x_is_longitude = True + opts := True + opts@verbose = False + corner_info := get_rect_grid_corners( \ + lon_verts, lat_verts, \ + "deg", "deg", x_is_longitude, opts) + corner_lons := corner_info@x_corners + corner_lats := corner_info@y_corners + + print("") + print(" The write-component output grid's corner lon/lat coordinates are:") + fmt_str = "%7.2f" + do c=0, dimsizes(corner_lons)-1 + lon_str = sprintf(fmt_str, corner_lons(c)) + lat_str = sprintf(fmt_str, corner_lats(c)) + print(" Corner " + (c+1) + ": lon = " + lon_str + " deg; " + \ + "lat = " + lat_str + " deg") + end do +; +; ********************************************************************** +; +; Calculate the coordinates of the center of the write-component grid. +; +; ********************************************************************** +; + rem_nx = mod(nx, 2) + rem_ny = mod(ny, 2) + + if ((rem_nx .eq. 0) .and. (rem_ny .eq. 0)) then + i_cntr = nx/2 + j_cntr = ny/2 + lon_grid_cntr := lon_verts(j_cntr,i_cntr) + lat_grid_cntr := lat_verts(j_cntr,i_cntr) + else if ((rem_nx .eq. 1) .and. (rem_ny .eq. 0)) then + i_cntr = (nx - 1)/2 + j_cntr = ny/2 + lon_grid_cntr := lon_cntrs(j_cntr,i_cntr) + lat_grid_cntr := lat_verts(j_cntr,i_cntr) + else if ((rem_nx .eq. 0) .and. (rem_ny .eq. 1)) then + i_cntr = nx/2 + j_cntr = (ny - 1)/2 + lon_grid_cntr := lon_verts(j_cntr,i_cntr) + lat_grid_cntr := lat_cntrs(j_cntr,i_cntr) + else if ((rem_nx .eq. 1) .and. (rem_ny .eq. 1)) then + i_cntr = (nx - 1)/2 + j_cntr = (ny - 1)/2 + lon_grid_cntr := lon_cntrs(j_cntr,i_cntr) + lat_grid_cntr := lat_cntrs(j_cntr,i_cntr) + end if + end if + end if + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable grid_info. +; +; ********************************************************************** +; + grid_info := True + + grid_info@nx = nx + grid_info@ny = ny + grid_info@lon_cntrs_unstruc = lon_cntrs_unstruc + grid_info@lat_cntrs_unstruc = lat_cntrs_unstruc + grid_info@lon_verts_unstruc = lon_verts_unstruc + grid_info@lat_verts_unstruc = lat_verts_unstruc + grid_info@lon_bdy = lon_bdy + grid_info@lat_bdy = lat_bdy + grid_info@lon_grid_cntr = lon_grid_cntr + grid_info@lat_grid_cntr = lat_grid_cntr + grid_info@coord_data_type = coord_data_type + + return(grid_info) + +end + diff --git a/ush/NCL/lib/adjust_longitude_range.ncl b/ush/NCL/lib/adjust_longitude_range.ncl new file mode 100644 index 0000000000..76d6f90843 --- /dev/null +++ b/ush/NCL/lib/adjust_longitude_range.ncl @@ -0,0 +1,90 @@ +; ********************************************************************** +; +; File name: adjust_longitude_range.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function adjust the given array of longitude values such that all +; values in the returned array lon_out are in the range +; +; -lon_min <= lon_out < lon_max, +; +; Here, lon_min is the given minimum longitude value and lon_max is ei- +; ther lon_min plus 360 deg (if the units of lon and lon_min are in de- +; grees) or lon_min plus 2*pi (if the units are in radians). lon and +; lon_min must have the same units (degrees or radians). These units +; are specified by the input string degs_or_rads. This string should be +; set either to "degs" for degrees or to "rads" for radians. +; * +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("adjust_longitude_range") + +function adjust_longitude_range( \ + lon:snumeric, lon_min:snumeric, degs_or_rads:string) + +local char_dq, pi, lon_domain_size, lon_max, lon_out + +begin +; +; ********************************************************************** +; * +; Set the size of the longitude domain. This is either 360 deg (if the +; given longitudes are in degrees) or 2*pi (if the given longitudes are +; in radians). +; * +; ********************************************************************** +; + if (strcmp_exact(degs_or_rads, "degs")) then + lon_domain_size = 360.0 + else if (strcmp_exact(degs_or_rads, "rads")) then + pi = 4.0d*atan(1.0d) + lon_domain_size = 2.0d*pi + else + msg := \ +"Disallowed value specified for input argument degs_or_rads:" + char_nl + \ +" degs_or_rads = " + char_dq + degs_or_rads + char_dq + \ +"Allowed values are " + char_dq + "degs" + char_dq + \ +" and " + char_dq + "rads" + char_dq + "." + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + end if +; +; ********************************************************************** +; * +; Add the longitude domain size calculated above to the given minimum +; longitude to obtain the maximum longitude. +; * +; ********************************************************************** +; + lon_max = lon_min + lon_domain_size +; +; ********************************************************************** +; * +; Create a new longitude array (lon_out) that will serve as the output +; of this function. Then adjust longitudes to ensure that all elements +; of lon_out are in the range lon_min <= lon_out < lon_max. +; * +; ********************************************************************** +; + lon_out := lon + lon_out := where(lon_out .lt. lon_min, lon_out + lon_domain_size, lon_out) + lon_out := where(lon_out .ge. lon_max, lon_out - lon_domain_size, lon_out) +; +; ********************************************************************** +; * +; Return the adjusted longitude array lon_out. +; * +; ********************************************************************** +; + return(lon_out) + +end + + diff --git a/ush/NCL/lib/append_to_snumeric_array.ncl b/ush/NCL/lib/append_to_snumeric_array.ncl new file mode 100644 index 0000000000..5734024b00 --- /dev/null +++ b/ush/NCL/lib/append_to_snumeric_array.ncl @@ -0,0 +1,130 @@ +; +; ********************************************************************** +; +; File name: append_to_snumeric_array.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function appends to the snumeric array orig_array the snumeric +; array array_to_append. The result is saved in new_array and returned. +; Note that if the two arrays are not of the same snumeric type, then +; array_to_append is converted to the type of orig_array before appending +; it to orig_array. +; +; ********************************************************************** +; +loadscript(lib_location + "strcmp_exact.ncl") + +undef("append_to_snumeric_array") + +function append_to_snumeric_array( \ + orig_array:snumeric, array_to_append:snumeric) + +local dims_orig_array, \ + num_dims_orig_array, \ + dims_orig_array_str, \ +\ + dims_array_to_append, \ + num_dims_array_to_append, \ + dims_array_to_append_str, \ +\ + msg, \ +\ + num_dims, \ + dims_compare, \ + right_dims_equal, \ +\ + tmp, \ + new_array + +begin +; +; ********************************************************************** +; +; Get the dimensions and the number of dimensions of the two input arrays. +; +; ********************************************************************** +; + dims_orig_array := dimsizes(orig_array) + num_dims_orig_array := dimsizes(dims_orig_array) + dims_orig_array_str \ + := "(/ " + str_join(tostring(dims_orig_array), ", ") + " /)" + + dims_array_to_append := dimsizes(array_to_append) + num_dims_array_to_append := dimsizes(dims_array_to_append) + dims_array_to_append_str \ + := "(/ " + str_join(tostring(dims_array_to_append), ", ") + " /)" +; +; ********************************************************************** +; +; Check that the two input arrays have the same number of dimensions. +; +; ********************************************************************** +; + if (num_dims_array_to_append .ne. num_dims_orig_array) then + msg = "" + char_nl + \ +"Error:" + char_nl + \ +"The number of dimensions of orig_array (num_dims_orig_array) and of " + char_nl + \ +"array_to_append (num_dims_array_to_append) must be the same:" + char_nl + \ +" dims_orig_array = " + dims_orig_array_str + char_nl + \ +" dims_array_to_append = " + dims_array_to_append_str + char_nl + \ +" num_dims_orig_array = " + num_dims_orig_array + char_nl + \ +" num_dims_array_to_append = " + num_dims_array_to_append + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; Check that all dimensions in the two input arrays after (i.e. to the +; right of) the first dimension are identical. +; +; ********************************************************************** +; + num_dims = num_dims_orig_array + if (num_dims .gt. 1) then + dims_compare := (dims_orig_array .eq. dims_array_to_append) + right_dims_equal := all(dims_compare(1:)) + else + right_dims_equal := True + end if + + if (.not. right_dims_equal) then + msg = "" + char_nl + \ +"Error:" + char_nl + \ +"All dimensions of orig_array and array_to_append after the first dimension" + char_nl + \ +"must be equal:" + char_nl + \ +" dims_orig_array = " + dims_orig_array_str + char_nl + \ +" dims_array_to_append = " + dims_array_to_append_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; If necessary, convert the type of array_to_append to that of orig_array. +; +; ********************************************************************** +; + tmp := array_to_append + if (.not. strcmp_exact(typeof(tmp), typeof(orig_array))) then + tmp := totype(tmp, typeof(orig_array)) + end if +; +; ********************************************************************** +; +; Append array_to_append to orig_array and save the result in new_array. +; Then return new_array. +; +; ********************************************************************** +; + new_array := array_append_record(orig_array, tmp, 0) + + return(new_array) + +end + + diff --git a/ush/NCL/lib/calc_field_stats.ncl b/ush/NCL/lib/calc_field_stats.ncl new file mode 100644 index 0000000000..d1d6e2c2cd --- /dev/null +++ b/ush/NCL/lib/calc_field_stats.ncl @@ -0,0 +1,121 @@ +; +; ********************************************************************** +; +; File name: calc_field_stats.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates and returns various statistics of the speci- +; fied field. These statistics consist of the minimum, maximum, median, +; and mean. This function also returns the field's rank and dimension +; sizes as well as a multiline string containing information about the +; field and its statistics. If the argument print_field_stats is set to +; True, this function will also print this string to the screen. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") + +undef("calc_field_stats") + +function calc_field_stats( \ + field:snumeric, field_desc:string, field_units:string, \ + print_field_stats:logical) + +local field_dims, field_rank, dim_inds, \ + field_min, field_max, field_median, field_mean, \ + field_dims_str, units, msg, field_stat_info + +begin +; +; ********************************************************************** +; +; Get the field's dimensions and rank. +; +; ********************************************************************** +; + field_dims := dimsizes(field) + field_rank := dimsizes(field_dims) + dim_inds := ispan(0, field_rank-1, 1) +; +; ********************************************************************** +; +; If the given field consists solely of missing values, set the minimum, +; maximum, median, and mean for the field to this missing value. Other- +; wise, call functions to calculate the minimum, maximum, median, and +; mean. Note that the median is calculated over all elements of the +; field (i.e. over all dimensions of the array containing the field). +; +; ********************************************************************** +; + if (all(ismissing(field))) then + field_missing_value = default_fillvalue(typeof(field)) + field_min := field_missing_value + field_max := field_missing_value + field_median := field_missing_value + field_mean := field_missing_value + else + field_min := min(field) + field_max := max(field) + field_median := dim_median_n(field, dim_inds) + field_mean := avg(field) + end if +; +; ********************************************************************** +; +; Create a (multiline) string describing the field and summarizing its +; statistics. Then, if print_field_stats is set to True, print this +; string to screen. +; +; ********************************************************************** +; + field_dims_str := tostring(field_dims) + field_dims_str := str_join(field_dims_str, ", ") + units := " [" + field_units + "]" + + msg := char_nl + \ +"The specified field's description, units, rank, and dimensions are:" + char_nl + \ +char_nl + \ +" field_desc = " + char_dq + field_desc + char_dq + char_nl + \ +" field_units = " + char_dq + field_units + char_dq + char_nl + \ +" field_rank = " + field_rank + char_nl + \ +" field_dims = (" + field_dims_str + ")" + char_nl + \ +char_nl + \ +"Statistics of this field are:" + char_nl + \ +char_nl + \ +" field_min = " + field_min + units + char_nl + \ +" field_max = " + field_max + units + char_nl + \ +" field_median = " + field_median + units + char_nl + \ +" field_mean = " + field_mean + units +; +; Recast msg as an array (one line per element). This allows for extra +; spaces to be easily prepended at the beginning of each line. +; + msg := str_split(msg, char_nl) + + if (print_field_stats) then + print("" + msg) + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable field_stat_info. +; +; ********************************************************************** +; + field_stat_info := True + + field_stat_info@field_rank = field_rank + field_stat_info@field_dims = field_dims + field_stat_info@field_min = field_min + field_stat_info@field_max = field_max + field_stat_info@field_median = field_median + field_stat_info@field_mean = field_mean + field_stat_info@msg = msg + + return(field_stat_info) + +end + + diff --git a/ush/NCL/lib/calc_lambert_cnfrml_proj_auxil_params.ncl b/ush/NCL/lib/calc_lambert_cnfrml_proj_auxil_params.ncl new file mode 100644 index 0000000000..8241ec6099 --- /dev/null +++ b/ush/NCL/lib/calc_lambert_cnfrml_proj_auxil_params.ncl @@ -0,0 +1,148 @@ +; +; ********************************************************************** +; +; File name: calc_lambert_cnfrml_proj_auxil_params.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function uses the primary parameters that define a Lambert con- +; formal projection with respect to spherical coordinates to calculate a +; set of auxiliary parameters needed in the mathematical expressions for +; calculating the Lambert conformal coordinates (x,y) from the spherical +; coordinates (lon,lat) and vice versa. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("calc_lambert_cnfrml_proj_auxil_params") + +function calc_lambert_cnfrml_proj_auxil_params( \ + lon_ctr:snumeric, lat_ctr:snumeric, \ + lat1:snumeric, lat2:snumeric, radius:snumeric, \ + angle_units:string) + +local curnt_script_proc_func_name, \ + valid_vals_angle_units, valid_vals_str, msg, \ + angle_units_short_lwr, \ + lon_ctr_rad, lat_ctr_rad, lat1_rad, lat2_rad, \ + cos_lat1, cos_lat2, qrtr_pi_geom, tan_ctr, tan1, tan2, \ + n, F, rho_ctr, \ + proj_params + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function calc_lambert_cnfrml_proj_auxil_params" +; +; ********************************************************************** +; +; Verify that the input argument "angle_units" has a valid value. +; +; ********************************************************************** +; + valid_vals_angle_units \ + := (/ "DEG", "DEGS", "DEGREE", "DEGREES", \ + "deg", "degs", "degree", "degrees", \ + "RAD", "RADS", "RADIAN", "RADIANS", \ + "rad", "rads", "radian", "radians" /) + + if (.not. strcmp_exact(valid_vals_angle_units, angle_units)) then + + valid_vals_str \ + := char_dq \ + + str_join(valid_vals_angle_units, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"Input argument " + char_dq + angle_units + char_dq + "is not set to a valid value:" + char_nl + \ +" angle_units = " + char_dq + angle_units + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals_str + char_nl + \ +"Stopping." + char_nl + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; If necessary, convert angles from degrees to radians. +; +; ********************************************************************** +; + angle_units_short_lwr = str_lower(str_get_cols(angle_units, 0, 2)) + if (strcmp_exact(angle_units_short_lwr, "deg")) then + lon_ctr_rad = lon_ctr*rads_per_deg + lat_ctr_rad = lat_ctr*rads_per_deg + lat1_rad = lat1*rads_per_deg + lat2_rad = lat2*rads_per_deg + else + lon_ctr_rad = lon_ctr + lat_ctr_rad = lat_ctr + lat1_rad = lat1 + lat2_rad = lat2 + end if +; +; ********************************************************************** +; +; Calculate convenience quantities. +; +; ********************************************************************** +; + cos_lat1 = cos(lat1_rad) + cos_lat2 = cos(lat2_rad) + + qrtr_pi_geom = 0.25d+0*pi_geom + tan_ctr = tan(qrtr_pi_geom + 0.5d+0*lat_ctr_rad) + tan1 = tan(qrtr_pi_geom + 0.5d+0*lat1_rad) + tan2 = tan(qrtr_pi_geom + 0.5d+0*lat2_rad) +; +; ********************************************************************** +; +; Calculate the auxiliary (or secondary) Lambert conformal projection +; parameters. +; +; ********************************************************************** +; + if (lat1 .ne. lat2) then + n = log(cos_lat1/cos_lat2)/log(tan2/tan1) + else + n = sin(lat1_rad) + end if + F = radius*cos_lat1*(tan1^n)/n + rho_ctr = F/(tan_ctr^n) +; +; ********************************************************************** +; +; Return results as attributes of the logical variable proj_params. +; +; ********************************************************************** +; + proj_params = True + + proj_params@lon_ctr_rad = lon_ctr_rad + proj_params@lat_ctr_rad = lat_ctr_rad + proj_params@lat1_rad = lat1_rad + proj_params@lat2_rad = lat2_rad + proj_params@n = n + proj_params@F = F + proj_params@rho_ctr = rho_ctr + + return(proj_params) + +end + + diff --git a/ush/NCL/lib/calc_rotated_sphr_coords_from_sphr.ncl b/ush/NCL/lib/calc_rotated_sphr_coords_from_sphr.ncl new file mode 100644 index 0000000000..4dd627aafe --- /dev/null +++ b/ush/NCL/lib/calc_rotated_sphr_coords_from_sphr.ncl @@ -0,0 +1,104 @@ +; +; ********************************************************************** +; +; File name: calc_rotated_sphr_coords_from_sphr.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates the Lambert conformal coordinates x and y +; corresponding to the specified spherical coordinates lon (longitude) +; and lat (latitude). +; +; ********************************************************************** +; +loadscript(lib_location + "calc_rotated_sphr_proj_auxil_params.ncl") + +undef("calc_rotated_sphr_coords_from_sphr") + +function calc_rotated_sphr_coords_from_sphr( \ + lon_ctr:snumeric, lat_ctr:snumeric, \ + lat1:snumeric, lat2:snumeric, radius:snumeric, \ + angle_units:string, \ + lon:snumeric, lat:snumeric) + +local proj_params, \ + lon_ctr_rad, lat_ctr_rad, lat1_rad, lat2_rad, \ + n, F, rho_ctr, \ + angle_units_short_lwrcase, \ + lon_rad, lat_rad, rho, n_dlon_rad, \ + x, y, coords_out + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function calc_rotated_sphr_coords_from_sphr" +; +; ********************************************************************** +; +; Calculate the auxiliary Lambert conformal map projection parameters +; that are needed in the calculation of the Lambert conformal coordi- +; nates (x,y) below. +; +; ********************************************************************** +; + proj_params := calc_rotated_sphr_proj_auxil_params( \ + lon_ctr, lat_ctr, lat1, lat2, radius, angle_units) + + lon_ctr_rad = proj_params@lon_ctr_rad + lat_ctr_rad = proj_params@lat_ctr_rad + lat1_rad = proj_params@lat1_rad + lat2_rad = proj_params@lat2_rad + n = proj_params@n + F = proj_params@F + rho_ctr = proj_params@rho_ctr +; +; ********************************************************************** +; +; If necessary, convert longitude and latitude from degrees to radians. +; +; ********************************************************************** +; + angle_units_short_lwrcase = str_lower(str_get_cols(angle_units, 0, 2)) + if (strcmp_exact(angle_units_short_lwrcase, "deg")) then + lon_rad = lon*rads_per_deg + lat_rad = lat*rads_per_deg + else + lon_rad = lon + lat_rad = lat + end if +; +; ********************************************************************** +; +; Calculate the Lambert conformal coordinates (x,y) using the projection +; parameters obtained above and the specified spherical coordinates. +; +; ********************************************************************** +; + rho = F/((tan(0.25d+0*pi_geom + 0.5d+0*lat_rad))^n) + n_dlon_rad = n*(lon_rad - lon_ctr_rad) + x = rho*sin(n_dlon_rad) + y = rho_ctr - rho*cos(n_dlon_rad) +; +; ********************************************************************** +; +; Return results as attributes of the logical variable coords_out. +; +; ********************************************************************** +; + coords_out = True + coords_out@x = x + coords_out@y = y + return(coords_out) + +end + + diff --git a/ush/NCL/lib/calc_sphr_coords_from_rotated_sphr.ncl b/ush/NCL/lib/calc_sphr_coords_from_rotated_sphr.ncl new file mode 100644 index 0000000000..e01b95622d --- /dev/null +++ b/ush/NCL/lib/calc_sphr_coords_from_rotated_sphr.ncl @@ -0,0 +1,105 @@ +; +; ********************************************************************** +; +; File name: calc_sphr_coords_from_rotated_sphr.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates the spherical coordinates (longitude and la- +; titude) corresponding to the specified Lambert conformal coordinates +; x and y. +; +; ********************************************************************** +; +loadscript(lib_location + "calc_rotated_sphr_proj_auxil_params.ncl") + +undef("calc_sphr_coords_from_rotated_sphr") + +function calc_sphr_coords_from_rotated_sphr( \ + lon_ctr:snumeric, lat_ctr:snumeric, \ + lat1:snumeric, lat2:snumeric, radius:snumeric, \ + angle_units:string, \ + x:snumeric, y:snumeric) + +local proj_params, \ + lon_ctr_rad, lat_ctr_rad, lat1_rad, lat2_rad, \ + n, F, rho_ctr, \ + rho_ctr_mns_y, rho, theta, lon_rad, lat_rad, \ + angle_units_short_lwr, lon, lat + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function calc_sphr_coords_from_rotated_sphr" +; +; ********************************************************************** +; +; Calculate the auxiliary Lambert conformal map projection parameters +; thar are needed in the calculation of the spherical coordinates (lon, +; lat) below. +; +; ********************************************************************** +; + proj_params := calc_rotated_sphr_proj_auxil_params( \ + lon_ctr, lat_ctr, lat1, lat2, radius, angle_units) + + lon_ctr_rad = proj_params@lon_ctr_rad + lat_ctr_rad = proj_params@lat_ctr_rad + lat1_rad = proj_params@lat1_rad + lat2_rad = proj_params@lat2_rad + n = proj_params@n + F = proj_params@F + rho_ctr = proj_params@rho_ctr +; +; ********************************************************************** +; +; Calculate the spherical coordinates (lon_rad,lat_rad) using the pro- +; jection parameters obtained above and the specified Lambert conformal +; coordinates. Note that lon_rad and lat_rad are in units of radians. +; +; ********************************************************************** +; + rho_ctr_mns_y = rho_ctr - y + rho = sign_matlab(n)*sqrt(x^2 + rho_ctr_mns_y^2) + theta = atan(x/rho_ctr_mns_y) + lon_rad = lon_ctr_rad + theta/n + lat_rad = 2.0d+0*atan((F/rho)^(1.0d+0/n)) - 0.5d+0*pi_geom +; +; ********************************************************************** +; +; If necessary, convert angles from radians to degrees. +; +; ********************************************************************** +; + angle_units_short_lwr = str_lower(str_get_cols(angle_units, 0, 2)) + if (strcmp_exact(angle_units_short_lwr, "deg")) then + lon = lon_rad*degs_per_rad + lat = lat_rad*degs_per_rad + else + lon = lon_rad + lat = lat_rad + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable coords_out. +; +; ********************************************************************** +; + coords_out = True + coords_out@lon = lon + coords_out@lat = lat + return(coords_out) + +end + + diff --git a/ush/NCL/lib/constants.ncl b/ush/NCL/lib/constants.ncl new file mode 100644 index 0000000000..783b83fe1e --- /dev/null +++ b/ush/NCL/lib/constants.ncl @@ -0,0 +1,29 @@ +; +; ********************************************************************** +; +; Define mathematical and physical constants. +; +; ********************************************************************** +; +; Circumference of a circle divided by its diameter. +; +pi_geom = 4.0d*atan(1.0d) +; +; Unit conversion factors. +; +degs_per_rad = 180.0d/pi_geom +rads_per_deg = 1.0d/degs_per_rad + +meters_per_km = 1.0d+3 +kms_per_meter = 1.0d/meters_per_km + +meters2_per_km2 = meters_per_km^2 +kms2_per_meter2 = 1.0d/meters2_per_km2 + +degC_per_degF = 5.0d+0/9.0d+0 +degF_per_degC = 1.0d+0/degC_per_degF +; +; Radius of the Earth, in meters. +; +rad_Earth = 6371.0d+3 + diff --git a/ush/NCL/lib/convert_from_to_sphr_coords_to_from_rotated_sphr.ncl b/ush/NCL/lib/convert_from_to_sphr_coords_to_from_rotated_sphr.ncl new file mode 100644 index 0000000000..9de7d9cc94 --- /dev/null +++ b/ush/NCL/lib/convert_from_to_sphr_coords_to_from_rotated_sphr.ncl @@ -0,0 +1,162 @@ +; +; ********************************************************************** +; +; File name: convert_from_to_sphr_coords_to_from_rotated_sphr.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function transforms the given longitudes and latitudes from sphe- +; rical to rotated spherical coordinates or vice versa. The positive X- +; axis of the rotated spherical coordinate system intersects the sphere +; at the (non-rotated) longitude and latitude (lon0, lat0). +; +; The input argument dir determines the direction of the transformation, +; as follows. If dir is set to 1, this function assumes that the input +; longitudes and latitudes (lon_in, lat_in) are in non-rotated spherical coor- +; dinates and calculates the corresponding output longitudes and lati- +; tudes (lon_out, lat_out) in rotated spherical coordinates. If dir is +; set to -1, this function assumes that (lon_in, lat_in) are specified in ro- +; tated coordinates and calculates the corresponding output coordinates +; (lon_out, lat_out) in non-rotated spherical coordinates. No other +; values of dir are allowed. +; +; ********************************************************************** +; +undef("convert_from_to_sphr_coords_to_from_rotated_sphr") + +function convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon0:snumeric, lat0:snumeric, \ + angle_units:string, dir:integer, \ + lon_in:snumeric, lat_in:snumeric) + +local lon0_rad, lat0_rad, \ + lon_in_rad, lat_in_rad, \ + lon_in_offset_rad, pmlat0_rad, msg, \ + sin_lon_in_offset, cos_lon_in_offset, \ + sin_pmlat0_rad, cos_pmlat0_rad, \ + sin_lat_in, cos_lat_in, tan_lat_in, \ + numer_atan, denom_atan, \ + lon_out, lat_out, coords_out + +begin +; +; ********************************************************************** +; +; If necessary, convert longitude and latitude from degrees to radians. +; +; ********************************************************************** +; + angle_units_short_lwrcase = str_lower(str_get_cols(angle_units, 0, 2)) + if (strcmp_exact(angle_units_short_lwrcase, "deg")) then + lon0_rad = lon0*rads_per_deg + lat0_rad = lat0*rads_per_deg + lon_in_rad = lon_in*rads_per_deg + lat_in_rad = lat_in*rads_per_deg + else + lon0_rad = lon0 + lat0_rad = lat0 + lon_in_rad = lon_in + lat_in_rad = lat_in + end if +; +; ********************************************************************** +; * +; +; * +; ********************************************************************** +; + if (dir .eq. 1) then + lon_in_offset_rad = lon_in_rad - lon0_rad + pmlat0_rad = lat0_rad + else if (dir .eq. -1) then + lon_in_offset_rad = lon_in_rad + pmlat0_rad = -lat0_rad + else + msg := char_nl + \ +"Disallowed value specified for dir:" + char_nl + \ +" dir = " + dir + char_nl + \ +"Set dir to 1 to transform from spherical to rotated spherical coordi-" + char_nl + \ +"nates, or set dir to -1 to transform from rotated spherical to spheri-" + char_nl + \ +"cal coordinates." + char_nl + \ +"Stopping." + print(msg + "") + exit + end if + end if +; +; ********************************************************************** +; * +; Calculate sines, cosines, and tangents of various angles. +; * +; ********************************************************************** +; + sin_lon_in_offset = sin(lon_in_offset_rad) + cos_lon_in_offset = cos(lon_in_offset_rad) + + sin_pmlat0_rad = sin(pmlat0_rad) + cos_pmlat0_rad = cos(pmlat0_rad) + sin_lat_in = sin(lat_in_rad) + cos_lat_in = cos(lat_in_rad) + tan_lat_in = sin_lat_in/cos_lat_in +; +; ********************************************************************** +; * +; Calculate the transformed longitude lon_out. +; * +; ********************************************************************** +; + numer_atan = sin_lon_in_offset + denom_atan = sin_pmlat0_rad*tan_lat_in + cos_pmlat0_rad*cos_lon_in_offset + lon_out = atan2(numer_atan, denom_atan) + if (dir .eq. -1) then + lon_out = lon_out + lon0_rad + end if +; +; ********************************************************************** +; * +; Make sure that the output value of longitude are in the range -pi <= +; lon < pi. +; * +; ********************************************************************** +; + lon_out := where(lon_out .lt. -pi_geom, lon_out + 2.0d+0*pi_geom, lon_out) + lon_out := where(lon_out .ge. pi_geom, lon_out - 2.0d+0*pi_geom, lon_out) +; +; ********************************************************************** +; * +; Calculate the transformed latitude lat_out. +; * +; ********************************************************************** +; + lat_out = asin(cos_pmlat0_rad*sin_lat_in \ + - sin_pmlat0_rad*cos_lon_in_offset*cos_lat_in) +; +; ********************************************************************** +; +; If necessary, convert output longitude and latitude from radians back +; to degrees. +; +; ********************************************************************** +; + if (strcmp_exact(angle_units_short_lwrcase, "deg")) then + lon_out = lon_out*degs_per_rad + lat_out = lat_out*degs_per_rad + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable coords_out. +; +; ********************************************************************** +; + coords_out = True + coords_out@lon_out = lon_out + coords_out@lat_out = lat_out + return(coords_out) + +end + + + + diff --git a/ush/NCL/lib/convert_lambert_cnfrml_coords_to_sphr.ncl b/ush/NCL/lib/convert_lambert_cnfrml_coords_to_sphr.ncl new file mode 100644 index 0000000000..6cd0bd5f6c --- /dev/null +++ b/ush/NCL/lib/convert_lambert_cnfrml_coords_to_sphr.ncl @@ -0,0 +1,105 @@ +; +; ********************************************************************** +; +; File name: convert_lambert_cnfrml_coords_to_sphr.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates the spherical coordinates (longitude and la- +; titude) corresponding to the specified Lambert conformal coordinates +; x and y. +; +; ********************************************************************** +; +loadscript(lib_location + "calc_lambert_cnfrml_proj_auxil_params.ncl") + +undef("convert_lambert_cnfrml_coords_to_sphr") + +function convert_lambert_cnfrml_coords_to_sphr( \ + lon_ctr:snumeric, lat_ctr:snumeric, \ + lat1:snumeric, lat2:snumeric, radius:snumeric, \ + angle_units:string, \ + x:snumeric, y:snumeric) + +local proj_params, \ + lon_ctr_rad, lat_ctr_rad, lat1_rad, lat2_rad, \ + n, F, rho_ctr, \ + rho_ctr_mns_y, rho, theta, lon_rad, lat_rad, \ + angle_units_short_lwr, lon, lat + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function convert_lambert_cnfrml_coords_to_sphr" +; +; ********************************************************************** +; +; Calculate the auxiliary Lambert conformal map projection parameters +; thar are needed in the calculation of the spherical coordinates (lon, +; lat) below. +; +; ********************************************************************** +; + proj_params := calc_lambert_cnfrml_proj_auxil_params( \ + lon_ctr, lat_ctr, lat1, lat2, radius, angle_units) + + lon_ctr_rad = proj_params@lon_ctr_rad + lat_ctr_rad = proj_params@lat_ctr_rad + lat1_rad = proj_params@lat1_rad + lat2_rad = proj_params@lat2_rad + n = proj_params@n + F = proj_params@F + rho_ctr = proj_params@rho_ctr +; +; ********************************************************************** +; +; Calculate the spherical coordinates (lon_rad,lat_rad) using the pro- +; jection parameters obtained above and the specified Lambert conformal +; coordinates. Note that lon_rad and lat_rad are in units of radians. +; +; ********************************************************************** +; + rho_ctr_mns_y = rho_ctr - y + rho = sign_matlab(n)*sqrt(x^2 + rho_ctr_mns_y^2) + theta = atan(x/rho_ctr_mns_y) + lon_rad = lon_ctr_rad + theta/n + lat_rad = 2.0d+0*atan((F/rho)^(1.0d+0/n)) - 0.5d+0*pi_geom +; +; ********************************************************************** +; +; If necessary, convert angles from radians to degrees. +; +; ********************************************************************** +; + angle_units_short_lwr = str_lower(str_get_cols(angle_units, 0, 2)) + if (strcmp_exact(angle_units_short_lwr, "deg")) then + lon = lon_rad*degs_per_rad + lat = lat_rad*degs_per_rad + else + lon = lon_rad + lat = lat_rad + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable coords_out. +; +; ********************************************************************** +; + coords_out = True + coords_out@lon = lon + coords_out@lat = lat + return(coords_out) + +end + + diff --git a/ush/NCL/lib/convert_sphr_coords_to_lambert_cnfrml.ncl b/ush/NCL/lib/convert_sphr_coords_to_lambert_cnfrml.ncl new file mode 100644 index 0000000000..572147bd32 --- /dev/null +++ b/ush/NCL/lib/convert_sphr_coords_to_lambert_cnfrml.ncl @@ -0,0 +1,104 @@ +; +; ********************************************************************** +; +; File name: convert_sphr_coords_to_lambert_cnfrml.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates the Lambert conformal coordinates x and y +; corresponding to the specified spherical coordinates lon (longitude) +; and lat (latitude). +; +; ********************************************************************** +; +loadscript(lib_location + "calc_lambert_cnfrml_proj_auxil_params.ncl") + +undef("convert_sphr_coords_to_lambert_cnfrml") + +function convert_sphr_coords_to_lambert_cnfrml( \ + lon_ctr:snumeric, lat_ctr:snumeric, \ + lat1:snumeric, lat2:snumeric, radius:snumeric, \ + angle_units:string, \ + lon:snumeric, lat:snumeric) + +local proj_params, \ + lon_ctr_rad, lat_ctr_rad, lat1_rad, lat2_rad, \ + n, F, rho_ctr, \ + angle_units_short_lwrcase, \ + lon_rad, lat_rad, rho, n_dlon_rad, \ + x, y, coords_out + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function convert_sphr_coords_to_lambert_cnfrml" +; +; ********************************************************************** +; +; Calculate the auxiliary Lambert conformal map projection parameters +; that are needed in the calculation of the Lambert conformal coordi- +; nates (x,y) below. +; +; ********************************************************************** +; + proj_params := calc_lambert_cnfrml_proj_auxil_params( \ + lon_ctr, lat_ctr, lat1, lat2, radius, angle_units) + + lon_ctr_rad = proj_params@lon_ctr_rad + lat_ctr_rad = proj_params@lat_ctr_rad + lat1_rad = proj_params@lat1_rad + lat2_rad = proj_params@lat2_rad + n = proj_params@n + F = proj_params@F + rho_ctr = proj_params@rho_ctr +; +; ********************************************************************** +; +; If necessary, convert longitude and latitude from degrees to radians. +; +; ********************************************************************** +; + angle_units_short_lwrcase = str_lower(str_get_cols(angle_units, 0, 2)) + if (strcmp_exact(angle_units_short_lwrcase, "deg")) then + lon_rad = lon*rads_per_deg + lat_rad = lat*rads_per_deg + else + lon_rad = lon + lat_rad = lat + end if +; +; ********************************************************************** +; +; Calculate the Lambert conformal coordinates (x,y) using the projection +; parameters obtained above and the specified spherical coordinates. +; +; ********************************************************************** +; + rho = F/((tan(0.25d+0*pi_geom + 0.5d+0*lat_rad))^n) + n_dlon_rad = n*(lon_rad - lon_ctr_rad) + x = rho*sin(n_dlon_rad) + y = rho_ctr - rho*cos(n_dlon_rad) +; +; ********************************************************************** +; +; Return results as attributes of the logical variable coords_out. +; +; ********************************************************************** +; + coords_out = True + coords_out@x = x + coords_out@y = y + return(coords_out) + +end + + diff --git a/ush/NCL/lib/get_1Dindx_from_2Dinds.ncl b/ush/NCL/lib/get_1Dindx_from_2Dinds.ncl new file mode 100644 index 0000000000..a5eaeb7dc2 --- /dev/null +++ b/ush/NCL/lib/get_1Dindx_from_2Dinds.ncl @@ -0,0 +1,53 @@ +; +; ********************************************************************** +; +; File name: get_1Dindx_from_2Dinds.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns the 1D index of the (j,i)-th element in a 2D ar- +; ray having dimensions given by dims_2Darray. This 1D index is the in- +; dex of the element in the 1D array obtained by applying the built-in +; ndtooned(...) function to the 2D array of specified dimensions. +; +; ********************************************************************** +; +undef("get_1Dindx_from_2Dinds") + +function get_1Dindx_from_2Dinds( \ + i:integer, j:integer, dims2D[2]:integer) + +local nx, ny, indx1D + +begin +; +; ********************************************************************** +; +; Extract the dimensions of the 2D array for which the specified i and j +; indices are valid. +; +; ********************************************************************** +; + nx = dims2D(1) + ny = dims2D(0) +; +; ********************************************************************** +; +; Calculate the 1D index corresonding to the given i and j indices and +; array dimensions. +; +; ********************************************************************** +; + indx1D := j*nx + i +; +; ********************************************************************** +; +; Return the 1D index. +; +; ********************************************************************** +; + return(indx1D) + +end + diff --git a/ush/NCL/lib/get_rect_grid_bdy.ncl b/ush/NCL/lib/get_rect_grid_bdy.ncl new file mode 100644 index 0000000000..77f0ed6d95 --- /dev/null +++ b/ush/NCL/lib/get_rect_grid_bdy.ncl @@ -0,0 +1,205 @@ +; +; ********************************************************************** +; +; File name: get_rect_grid_bdy.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns two 1-D arrays containing the coordinates (say x +; and y) of the points along the boundary of the logically rectangular +; grid specified by the given arrays x_coords and y_coords. +; +; If repeat_last_point is set to True, the first point on the boundary +; is repeated at the end. This is done so that if a polyline object is +; used to plot the grid boundary, the boundary closes on itself. +; +; If index_order is set to "ij", then we assume the first index in the +; input arrays x_coords and y_coords is the one in the x direction (i.e. +; the i-index) and the second index is the one in the y direction (i.e. +; the j-index). If index_order is set to "ji", we assume the opposite. +; Note that normal practice in NCL is to use "ji" index ordering. Thus, +; if index_order is set to "ij", we transpose (the local copies) of the +; input arrays to obtain "ji" indexing. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("get_rect_grid_bdy") + +function get_rect_grid_bdy( \ + x_coords[*][*]:snumeric, y_coords[*][*]:snumeric, \ + repeat_last_point:logical, index_order:string) + +local x, y, \ + dims_x, dims_y, dims_are_equal, dims_x_str, dims_y_str, \ + nx, ny, x_bdy, y_bdy, i, j, \ + grid_info + +begin +; +; ********************************************************************** +; +; Check that index_order has a valid value. +; +; ********************************************************************** +; + if (.not. strcmp_exact(index_order, "ij") .and. \ + .not. strcmp_exact(index_order, "ji")) then + print("") + print("The input argument index_order must be set to either " + \ + char_dq + "ji" + char_dq + " or " + \ + char_dq + "ij" + char_dq + ":") + print(" index_order = " + char_dq + index_order + char_dq) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; The code below assumes that the coordinate arrays use the index order +; (j,i) [as opposed to (i,j)]. Thus, if the given arrays use the order +; (i,j), transpose them to get back to (j,i) order. +; +; ********************************************************************** +; + x = x_coords + y = y_coords + if (strcmp_exact(index_order, "ij")) then + x = transpose(x) + y = transpose(y) + end if +; +; ********************************************************************** +; +; Get the dimensions of the coordinate arrays and check that they are +; identical. +; +; ********************************************************************** +; + dims_x = dimsizes(x) + dims_y = dimsizes(y) + + dims_are_equal = (dims_x .eq. dims_y) + if (.not. all(dims_are_equal)) then + dims_x_str = str_join(tostring(dims_x), ", ") + dims_y_str = str_join(tostring(dims_y), ", ") + print("") + print("The dimensions of the x-coordinate array do not match those of the y-coordinate array:") + print(" dims_x = (" + dims_x_str + ")") + print(" dims_y = (" + dims_y_str + ")") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; For convenience, set nx and ny to the number of grid points in the x +; and y directions, respectively. +; +; ********************************************************************** +; + nx = dims_x(1) + ny = dims_x(0) +; +; ********************************************************************** +; +; Create 1-D arrays to hold the x and y coordinates of the boundary +; points of the grid. Note that initially, these arrays will contain +; only one element; more elements will be appended later below. +; +; ********************************************************************** +; + x_bdy := new((/1/), typeof(x)) + y_bdy := new((/1/), typeof(y)) +; +; ********************************************************************** +; +; Copy in the coordinates of the point at (i,j) = (0,0). +; +; ********************************************************************** +; + i = 0 + j = 0 + x_bdy(0) = x(j,i) + y_bdy(0) = y(j,i) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "southern" boundary +; (j = 0). +; +; ********************************************************************** +; + j = 0 + x_bdy := array_append_record(x_bdy, x(j,1:), 0) + y_bdy := array_append_record(y_bdy, y(j,1:), 0) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "eastern" boundary +; (i = nx). +; +; ********************************************************************** +; + i = nx - 1 + x_bdy := array_append_record(x_bdy, x(1:,i), 0) + y_bdy := array_append_record(y_bdy, y(1:,i), 0) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "northern" boundary +; (j = ny). Note that in specifying the i-index range [i.e. (nx-1:0)], +; we do not specify a negative stride, i.e. we do not use (nx-1:0:-1), +; because in NCL, the order of the elements is automatically reversed if +; the starting index is larger than the ending index. +; +; ********************************************************************** +; + j = ny - 1 + x_bdy := array_append_record(x_bdy, x(j,nx-2:0), 0) + y_bdy := array_append_record(y_bdy, y(j,nx-2:0), 0) +; +; ********************************************************************** +; +; Append the coordinates of the points along the "western" boundary +; (i = 0). Note that in specifying the j-index range [i.e. (ny-1:1)], +; we do not specify a negative stride, i.e. we do not use (ny-1:1:-1), +; because in NCL, the order of the elements is automatically reversed if +; the starting index is larger than the ending index. +; +; ********************************************************************** +; + i = 0 + x_bdy := array_append_record(x_bdy, x(ny-2:1,i), 0) + y_bdy := array_append_record(y_bdy, y(ny-2:1,i), 0) +; +; ********************************************************************** +; +; If repeat_last_point is set to True, repeat the first point at the +; end. +; +; ********************************************************************** +; + if (repeat_last_point) then + x_bdy := array_append_record(x_bdy, (/ x_bdy(0) /), 0) + y_bdy := array_append_record(y_bdy, (/ y_bdy(0) /), 0) + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable grid_info. +; +; ********************************************************************** +; + grid_info := True + + grid_info@x_bdy = x_bdy + grid_info@y_bdy = y_bdy + + return(grid_info) + +end + diff --git a/ush/NCL/lib/get_rect_grid_corners.ncl b/ush/NCL/lib/get_rect_grid_corners.ncl new file mode 100644 index 0000000000..14a606b329 --- /dev/null +++ b/ush/NCL/lib/get_rect_grid_corners.ncl @@ -0,0 +1,196 @@ +; +; ********************************************************************** +; +; File name: get_rect_grid_corners.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns the coordinates of the four corners of a logi- +; cally rectangular grid whose cell vertex coordinates are specified by +; the 2-D arrays x_verts and y_verts. We let x and y refere to the co- +; ordinates in the two directions. If the x coordinate represents lon- +; gitude (which is the case if the logical variable x_is_longitude is +; set to True), this function ensures that the longitudes of the grid +; corners are within the longitude range (-180 deg, 180 deg) or (-pi, +; pi). +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("get_rect_grid_corners") + +function get_rect_grid_corners( \ + x_verts[*][*]:snumeric, y_verts[*][*]:snumeric, \ + x_units:string, y_units:string, \ + x_is_longitude:logical, \ + opts:logical) + +local dims_x, dims_y, dims_are_equal, dims_x_str, dims_y_str, \ + nx, ny, \ + corner_i_inds, corner_j_inds, num_corners, \ + x_corners, y_corners, \ + valid_lon_units, max_lon_allowed, valid_vals, msg, lon_range, \ + fmt_str, x_str, y_str, \ + corner_info + +begin +; +; ********************************************************************** +; +; Get the dimensions of the coordinate arrays and check that they are +; identical. +; +; ********************************************************************** +; + dims_x = dimsizes(x_verts) + dims_y = dimsizes(y_verts) + + dims_are_equal = all(dims_x .eq. dims_y) + if (.not. dims_are_equal) then + dims_x_str = str_join(tostring(dims_x), ", ") + dims_y_str = str_join(tostring(dims_y), ", ") + print("") + print("The dimensions of the x-coordinate array do not match those of the y-coordinate array:") + print(" dims_x = (" + dims_x_str + ")") + print(" dims_y = (" + dims_y_str + ")") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; For convenience, set nx and ny to the number of grid cells in the x +; and y directions, respectively. Note that since we assume that the +; specified coordinates are those of the cell vertices, the number of +; grid cells in each direction is one less than the dimensions of the +; specified arrays. +; +; ********************************************************************** +; + nx = dims_x(1) - 1 + ny = dims_x(0) - 1 +; +; ********************************************************************** +; +; Find the coordinates of the corners of the grid. +; +; ********************************************************************** +; + corner_i_inds := (/ 0, nx, nx, 0 /) + corner_j_inds := (/ 0, 0, ny, ny /) + num_corners = 4 + x_corners := new((/ num_corners /), "double") + y_corners := new((/ num_corners /), "double") + + do c=0, num_corners-1 + x_corners(c) = x_verts(corner_j_inds(c), corner_i_inds(c)) + y_corners(c) = y_verts(corner_j_inds(c), corner_i_inds(c)) + end do +; +; ********************************************************************** +; +; If the x coordinate represents longitude (in which case the logical +; variable x_is_longitude will be True), ensure that the longitudes of +; the corners determined above are all within the valid longitude range. +; +; ********************************************************************** +; + if (x_is_longitude) then + + valid_lon_units = (/ "deg", "degs", "rad", "rads" /) + + if (strcmp_exact(valid_lon_units, x_units)) then + + if (strcmp_exact(x_units, "deg") .or. \ + strcmp_exact(x_units, "degs")) then + max_lon_allowed = 180.0 + else if (strcmp_exact(x_units, "rad") .or. \ + strcmp_exact(x_units, "rads")) then + max_lon_allowed = pi_geom + else + msg := char_nl + \ +"Don't know what the maximum allowed value (max_lon_allowed) should be " + char_nl + \ +"for these units:" + char_nl + \ +" x_units = " + char_dq + x_units + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + end if + + else + + valid_vals \ + := char_dq \ + + str_join(valid_lon_units, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"Unknown units specified for the longitude (x):" + char_nl + \ +" x_units = " + char_dq + x_units + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + + lon_range = 2.0*max_lon_allowed + + do c=0, num_corners-1 + if (x_corners(c) .gt. max_lon_allowed) then + x_corners(c) = x_corners(c) - lon_range + end if + end do + + end if +; +; ********************************************************************** +; +; Create a (multiline) string containing the coordinates of the grid +; corners. Then, if opts@verbose exists and is set to True, print this +; string to screen. +; +; ********************************************************************** +; + fmt_str = "%7.2f" + msg := char_nl + "The specified grid's corner coordinates are:" + do c=0, num_corners-1 + x_str = sprintf(fmt_str, x_corners(c)) + y_str = sprintf(fmt_str, y_corners(c)) + msg := msg + char_nl \ + + " Corner " + (c+1) + ": " \ + + "x = " + x_str + " " + x_units + "; " \ + + "y = " + y_str + " " + y_units + end do +; +; Recast msg as an array (one line per element). This allows for extra +; spaces to be easily prepended at the beginning of each line. +; + msg := str_split(msg, char_nl) + + if (isatt(opts, "verbose") .and. (opts@verbose .eq. True)) then + print("" + msg) + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable corner_info. +; +; ********************************************************************** +; + corner_info := True + + corner_info@x_corners = x_corners + corner_info@y_corners = y_corners + corner_info@msg = msg + + return(corner_info) + +end + + diff --git a/ush/NCL/lib/get_resized_viewport_dims.ncl b/ush/NCL/lib/get_resized_viewport_dims.ncl new file mode 100644 index 0000000000..db7acd355e --- /dev/null +++ b/ush/NCL/lib/get_resized_viewport_dims.ncl @@ -0,0 +1,302 @@ +; +; ********************************************************************** +; +; File name: get_resized_viewport_dims.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function calculates the viewport information [consisting of the +; coordinates of the top-left corner and the dimensions, all in NDC +; units (NDC = Non-Dimensional Coordinates)] for the new viewport that +; a specified plot (plot) must have after it is resized in order for its +; new bounding box to have the specified size (bb_size_new; also in NDC +; units). +; +; Note that bb_size_new is interpreted as the larger of the two dimen- +; sions the the bounding box of the new (i.e. resized plot) assuming the +; aspect ratio of the plot doesn't change during resizing. This means +; that it will be interpreted as the height that we would like the new +; bounding box to have if the original plot is taller than it is wide +; (i.e. if it is in portrait mode), and it will be interpreted as the +; width that we would like the new bounding box to have if the original +; plot is wider than it is tall (i.e. if it is in landscape mode). +; +; Note also that the actual resizing of the plot is not performed by +; this function (because NCL doesn't seem to allow it). That action +; must be performed by the calling script/function/subroutine using the +; viewport information that this function generates. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") + +undef("get_resized_viewport_dims") + +function get_resized_viewport_dims( \ + plot:graphic, + bb_size_new:snumeric, \ + opts:logical) + +local bb_orig, + bb_lft_orig, bb_rgt_orig, bb_top_orig, bb_bot_orig, + bb_width_orig, bb_height_orig, \ + bb_lft_new, bb_rgt_new, bb_top_new, bb_bot_new, \ + bb_width_new, bb_height_new, \ + vpXF_orig, vpYF_orig, vpWidthF_orig, vpHeightF_orig, \ + vpXF_new, vpYF_new, vpWidthF_new, vpHeightF_new, \ + dx_orig, dy_orig, dx_new, dy_new, \ + x_ratio_new_to_orig, y_ratio_new_to_orig, \ + viewport_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line \ + := "========================================================================" + end if +; +; ********************************************************************** +; +; The logical attribute verbose of the options argument (opts) deter- +; mines whether informational messages are printed out to the screen. +; If this attribute is not defined, set it to False. +; +; ********************************************************************** +; + if (.not. isatt(opts, "verbose")) then + opts@verbose = False + end if + + if (opts@verbose) then + print("") + print("" + separator_line) + print("Start of output from function get_resized_viewport_dims(...):") + end if +; +; ********************************************************************** +; +; Check that bb_size_new has a valid value. +; +; ********************************************************************** +; + if ((bb_size_new .lt. 0) .or. (bb_size_new .gt. 1)) then + print("") + print("Error: The bounding box size of the resized plot " + \ + "(bb_size_new) must be " + char_nl + \ + "between 0 and 1:") + print(" bb_size_new = " + bb_size_new) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Get the NDC coordinates of the bounding box of the original plot. +; +; ********************************************************************** +; + bb_orig = NhlGetBB(plot) + bb_lft_orig = bb_orig(2) + bb_rgt_orig = bb_orig(3) + bb_top_orig = bb_orig(0) + bb_bot_orig = bb_orig(1) + + if (opts@verbose) then + print("") + print("The bounds (in NDC units) of the bounding box of the original plot are:") + print("") + print("bb_lft_orig = " + bb_lft_orig) + print("bb_rgt_orig = " + bb_rgt_orig) + print("bb_top_orig = " + bb_top_orig) + print("bb_bot_orig = " + bb_bot_orig) + end if +; +; ********************************************************************** +; +; Calculate the NDC width and height of the bounding box of the original +; plot. +; +; Note that a bounding box is the smallest rectangle in NDC space that +; contains all of a particular object's attributes. For a 2-D XY or +; contour plot (which is what we're considering here), this would in- +; clude the area containing the tickmarks, tickmark labels, the main +; title, axis titles, legend, and anything else associated with the +; plot. This is in contrast to the viewport (which we will also consi- +; der below), which contains only the area within the axes. See +; +; https://www.ncl.ucar.edu/Applications/viewport.shtml +; +; for examples. +; +; ********************************************************************** +; + bb_width_orig = bb_rgt_orig - bb_lft_orig + bb_height_orig = bb_top_orig - bb_bot_orig + + if (opts@verbose) then + print("") + print("The dimensions (in NDC units) of the bounding box of the original plot are:") + print("") + print("bb_width_orig = " + bb_width_orig) + print("bb_height_orig = " + bb_height_orig) + end if +; +; ********************************************************************** +; +; Set or calculate the NDC width, height, and coordinates of the bound- +; ing box of the new resized plot. +; +; ********************************************************************** +; +; If the original plot is taller than it is wide (i.e. in portrait +; mode), take bb_size_new to be the height of the new plot. +; + if (bb_width_orig .le. bb_height_orig) then + bb_height_new = bb_size_new + bb_width_new = (bb_width_orig/bb_height_orig)*bb_height_new +; +; If the original plot is wider than it is tall (i.e. in landscape +; mode), take bb_size_new to be the width of the new plot. +; + else + bb_width_new = bb_size_new + bb_height_new = (bb_height_orig/bb_width_orig)*bb_width_new + end if + + if (opts@verbose) then + print("") + print("The dimensions (in NDC units) of the bounding box of the new plot are:") + print("") + print("bb_width_new = " + bb_width_new) + print("bb_height_new = " + bb_height_new) + end if + + bb_lft_new = (1 - bb_width_new)/2.0 + bb_rgt_new = bb_lft_new + bb_width_new + bb_top_new = (1 + bb_height_new)/2.0 + bb_bot_new = bb_top_new - bb_height_new + + if (opts@verbose) then + print("") + print("The dimensions (in NDC units) of the bounding box of the new plot are:") + print("") + print("bb_lft_new = " + bb_lft_new) + print("bb_rgt_new = " + bb_rgt_new) + print("bb_top_new = " + bb_top_new) + print("bb_bot_new = " + bb_bot_new) + end if +; +; ********************************************************************** +; +; Get the NDC coordinates of the top left point of the viewport of the +; original plot and the NDC width and height of the original plot. +; +; ********************************************************************** +; + getvalues plot + "vpXF" : vpXF_orig + "vpYF" : vpYF_orig + "vpWidthF" : vpWidthF_orig + "vpHeightF" : vpHeightF_orig + end getvalues + + if (opts@verbose) then + print("") + print("The coordinates of the top-left corner and the dimensions (in NDC units) " + char_nl + \ + "of the viewport of the original plot are:") + print("") + print("vpXF_orig = " + vpXF_orig) + print("vpYF_orig = " + vpYF_orig) + print("vpWidthF_orig = " + vpWidthF_orig) + print("vpHeightF_orig = " + vpHeightF_orig) + end if +; +; ********************************************************************** +; +; Calculate the NDC coordinates of the top left point of the viewport of +; the new (resized) plot and the NDC width and height of the new plot. +; +; Recall that the bounding box is larger than the viewport; in particu- +; lar, it includes the viewport as well as the axis titles, plot title, +; etc. Thus, the variables dx_orig and dy_orig calculated below are the +; horizontal and vertical offsets in the original plot from the bounda- +; ries of the bounding box to those of the viewport, and dx_new and dy_- +; new are the analogous quantities for the new (resized) plot. +; +; ********************************************************************** +; + dx_orig = vpXF_orig - bb_lft_orig + dy_orig = bb_top_orig - vpYF_orig + + x_ratio_new_to_orig = bb_width_new/bb_width_orig + y_ratio_new_to_orig = bb_height_new/bb_height_orig + + dx_new = dx_orig*x_ratio_new_to_orig + dy_new = dy_orig*y_ratio_new_to_orig + + vpXF_new = bb_lft_new + dx_new + vpYF_new = bb_top_new - dy_new + + vpWidthF_new = vpWidthF_orig*x_ratio_new_to_orig + vpHeightF_new = vpHeightF_orig*y_ratio_new_to_orig + + if (opts@verbose) then + print("") + print("The coordinates of the top-left corner and the dimensions (in NDC units) " + char_nl + \ + "of the viewport of the new plot are:") + print("") + print("vpXF_new = " + vpXF_new) + print("vpYF_new = " + vpYF_new) + print("vpWidthF_new = " + vpWidthF_new) + print("vpHeightF_new = " + vpHeightF_new) + end if +; +; ********************************************************************** +; +; Resize the plot to its new size by changing its viewport coordinates. +; +; Apparently, we can't change the viewport from within a function (why +; not?), so this must be done from the calling script/procedure/func- +; tion. +; +; ********************************************************************** +; +; setvalues plot +; "vpXF" : vpXF_new +; "vpYF" : vpYF_new +; "vpWidthF" : vpWidthF_new +; "vpHeightF" : vpHeightF_new +; end setvalues +; +; ********************************************************************** +; +; Return results as attributes of the logical variable viewport_info. +; +; ********************************************************************** +; + viewport_info := True + + viewport_info@vpXF = vpXF_new + viewport_info@vpYF = vpYF_new + viewport_info@vpWidthF = vpWidthF_new + viewport_info@vpHeightF = vpHeightF_new + + if (opts@verbose) then + print("") + print("End of output from function set_cnLevels_lbLabels(...).") + print("" + separator_line) + end if + + return(viewport_info) + +end + + diff --git a/ush/NCL/lib/interpol_extrapol_linear.ncl b/ush/NCL/lib/interpol_extrapol_linear.ncl new file mode 100644 index 0000000000..9f5afcfdc6 --- /dev/null +++ b/ush/NCL/lib/interpol_extrapol_linear.ncl @@ -0,0 +1,52 @@ +; +; ********************************************************************** +; +; File name: interpol_extrapol_linear.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function compares each element of the string array str_array to +; the string (scalar) str. It returns a variable (match_found) that +; will be set to True if at least one element of str_array is identical +; to str and False otherwise (i.e. it will be set to False if none of +; the elements of str_array are identical to str). This function also +; returns (as an attribute of match_found) a 1-D logical array (exact_- +; match) having the same dimensions as str_array that will be True at +; those indices at which str_array is identical to str and False every- +; where else. +; +; Note that str_array may be a scalar string, in which case this func- +; tion simply compares two strings. If the two strings are identical, +; then this function returns True in match_found as well as its attri- +; bute match_found@str_array (which in this case will be a scalar). If +; the two strings are not identical, then match_found and match_found@- +; match_by_elem will both be False. +; +; ********************************************************************** +; +undef("interpol_extrapol_linear") + +function interpol_extrapol_linear( \ + x1[*]:snumeric, y1[*]:snumeric, \ + x2[*]:snumeric, y2[*]:snumeric, \ + x[*]:snumeric) + +local slope, y_int, y + +begin +; +; ********************************************************************** +; +; Perform linear interpolation and return the result. +; +; ********************************************************************** +; + slope := (y2 - y1)/(x2 - x1) + y_int := (x2*y1 - x1*y2)/(x2 - x1) + y := slope*x + y_int + return(y) + +end + + diff --git a/ush/NCL/lib/pause.ncl b/ush/NCL/lib/pause.ncl new file mode 100644 index 0000000000..40550f2b78 --- /dev/null +++ b/ush/NCL/lib/pause.ncl @@ -0,0 +1,11 @@ +undef("pause") +procedure pause() +local temp +begin + print("Program paused. Press to continue.") +; temp := systemfunc("read ANS; echo $ANS") + temp := systemfunc("read ANS") + print("Continuing ...") +end + + diff --git a/ush/NCL/lib/read_namelist.ncl b/ush/NCL/lib/read_namelist.ncl new file mode 100644 index 0000000000..f51c0c158f --- /dev/null +++ b/ush/NCL/lib/read_namelist.ncl @@ -0,0 +1,801 @@ +; +; ********************************************************************** +; +; File name: read_namelist.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function reads in the specified Fortran namelist in the speci- +; fied file. It is called as follows: +; +; nl = read_namelist(filename, nl_name) +; +; Here, filename is a string containing the name of (or the full path +; to) the Fortran namelist file, and nl_name is a string containing the +; name of the namelist (since the file may contain more than one name- +; list). The function returns a string nl containing the name of the +; namelist and having attributes with the same names as the member vari- +; ables of the namelist (specified in the file) and having the values +; specified in the file. +; +; This function was inspired by the function "namelist" written by Den- +; nis Shea. +; +; ********************************************************************** +; +load "pause.ncl" + +undef ("read_namelist") +function read_namelist(filename:string, namelist:string) +local \ + ampers_char, \ + comma_char, \ + decimal_char, \ + equal_char, \ + exclam_char, \ + fwdslash_char, \ + newline_char, \ + null_char, \ + quot1_char, \ + quot2_char, \ + space_char, \ +\ + cmmnt_char, \ + elem_delim_char, \ +elem_delim_chars, \ + first_char, \ + last_char, \ + quot_char, \ +\ + num_chars, \ + num_cmmnts, \ + num_decimals, \ + num_lines, \ + num_strings, \ +\ + inds_cmmnts, \ + inds_equals, \ + inds_False, \ + indx_first_equal, \ + indx_line_start, \ + indx_line_end, \ + inds_True, \ +\ + all_lines, \ + all_words, \ + first_word, \ + line, \ +\ + true_str, \ + false_str, \ + RHS_str, \ +\ + attr_name, \ + i, \ + in_quotes, \ + n, \ + pls_mns_pt_digit_chars, \ + RHS, \ + rhs, \ + temp + + +begin +; +; ********************************************************************** +; +; Create the output variable. We will attach to this as attributes the +; values read in from the specified file. The variable itself is set +; to the specified name of the namelist. +; +; ********************************************************************** +; + nl = namelist +; +; ********************************************************************** +; +; Set special characters needed during processing of the namelist file. +; +; ********************************************************************** +; +; Space (int 32). + space_char = tochar(" ") + +; Equal sign (int 61). + equal_char = tochar("=") + +; Comma as value separator (int 44). + comma_char = tochar(",") + +; Period or decimal point to indicate float (int 46). + decimal_char = tochar(".") + +; Ampersand (int 38). + ampers_char = tochar("&") + +; Single quote (int 39). + quot1_char = tochar("'") + +; Forward slash. + fwdslash_char = tochar("/") + +; Exclamation point as comment character. + exclam_char = tochar("!") + +; Double quote (int 34). + quot2_char = integertochar(34) + +; Newline (int 10). + newline_char = integertochar(10) + +; Null character (int 0) + null_char = integertochar(0) +; +; ********************************************************************** +; +; Set the character to assume to be the comment character in the name- +; list file. Also, set the character to assume to be the delimiter +; between array elements in the namelist file. +; +; ********************************************************************** +; + cmmnt_char = exclam_char + +; GSK: 01/18/2017 +; The variable elem_delim_char needs to be removed and replaced by +; the array variable elem_delim_chars everywhere, but that requires +; rewriting some code and testing, so I haven't done it yet. I've only +; performed the replacement in one location where it was needed for +; reading in the FV3 namelist. + + elem_delim_char = space_char +; elem_delim_char = comma_char +elem_delim_chars = (/ space_char, comma_char /) +;elem_delim_chars = (/ comma_char, comma_char /) +; +; ********************************************************************** +; +; Read in the namelist file and save it as a 1-D array of strings. +; Then get the number of lines in the file. +; +; ********************************************************************** +; + all_lines = asciiread(filename, -1, "string") + num_lines = dimsizes(all_lines) +; +; ********************************************************************** +; +; Loop over lines in the file until we get the line on which the speci- +; fied namelist starts. Such a line will start with optional white- +; space, then an @, then followed immediately by the name of the name- +; list, followed by additional optional whitespace and variable specifi- +; cations. Here, we assume that there are no variable specifications +; following the whitespace after the name of the namelist. +; +; ********************************************************************** +; + indx_line_start = -1 + + do n=0, num_lines-1 + +; Strip off leading and trailing spaces and tabs from the current line, +; and replace multiple spaces and/or tabs with a single space. + line := str_squeeze(all_lines(n)) +; If there are no characters in the current line, just move on to the +; next line. + if (strlen(line) .eq. 0) then + continue +; Otherwise, get the first non-whitespace character in the line. + else + + all_words := str_split(line, " ") + first_word := tochar(all_words(0)) + first_char := first_word(0) +; If the first non-whitespace character on the current line is an amper- +; sand, and the word following the ampersand is the name of the speci- +; fied namelist, then this line marks the beginning of the namelist spe- +; cification. Thus, save the line number and exit the loop over all +; lines in the file. + if ((first_char .eq. ampers_char) .and. \ + (first_word(1:) .eq. namelist)) then + indx_line_start = n + break + end if + + end if + + end do + +;print("") +;print("############################################################################################") +;print("indx_line_start = " + indx_line_start) +;print("############################################################################################") +;pause + + if (indx_line_start .eq. -1) then + print("") + print("Could not find starting line of namelist in file:") + print(" filename = " + filename) + print(" namelist = " + namelist) + print(" indx_line_start = " + indx_line_start) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Loop over lines in the file, starting with the one after the one that +; that marks the start of the namelist, until we get the line on which +; the specified namelist ends. Such a line will be the first one after +; the namelist start line that has as its last character a forward +; slash (which is not part of a character string or part of a comment +; at the end of the line). For simplicity, we assume here that the end- +; ing forward slash is on a line of its own (possibly preceded by white- +; space and followed by other characters). +; +; ********************************************************************** +; + indx_line_end = -1 + + do n=indx_line_start+1, num_lines-1 + +; Strip off leading and trailing spaces and tabs from the current line, +; and replace multiple spaces and/or tabs with a single space. + line := str_squeeze(all_lines(n)) +; If there are no characters in the current line, just move on to the +; next line. + if (strlen(line) .eq. 0) then + continue +; Otherwise, get the first non-whitespace character in the line. + else + + all_words := str_split(line, " ") + first_word := tochar(all_words(0)) + first_char := first_word(0) +; If the first non-whitespace character on the current line is a for- +; ward slash, then the line marks the end of the namelist specifica- +; tion. Thus, save the line number and exit the loop over all lines +; in the file. + if (first_char .eq. fwdslash_char) then + indx_line_end = n + break + end if + + end if + + end do + +;print("") +;print("############################################################################################") +;print("indx_line_end = " + indx_line_end) +;print("############################################################################################") +;pause + + if (indx_line_end .eq. -1) then + print("") + print("Could not find ending line of namelist in file:") + print(" filename = " + filename) + print(" namelist = " + namelist) + print(" indx_line_end = " + indx_line_end) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Loop through those lines of the file that define the namelist and pro- +; cess each line. +; +; ********************************************************************** +; + do n=indx_line_start+1, indx_line_end-1 +; +; ********************************************************************** +; +; Strip leading and trailing whitespace from the current line and con- +; vert the result to a 1-D array of characters. +; +; Note that the str_strip(...) function removes leading and trailing +; whitespace, but it does not remove the newline character at the end +; of the string if such a character is present. Thus, we have to re- +; move it separately. From trial-and-error, it seems that even the +; last line in the file will have a newline at the end even if there is +; no blank line after it. +; +; ********************************************************************** +; + line := stringtochar(str_strip(all_lines(n))) + +;print("") +;print("") +;print("############################################################################################") +;print("===>> n = " + n) +;print("line:") +;print("" + line) + +; +; ********************************************************************** +; +; Don't process the current line if any of the following is true: +; +; 1) The line is empty. +; 2) The line starts with the Fortran comment character. +; +; In these cases, simply move on to the next line. +; +; ********************************************************************** +; + if ((strlen(tostring(line)) .eq. 0) .or. \ + (line(0) .eq. cmmnt_char)) then + continue + end if +; +; ********************************************************************** +; +; Get the location of all equal signs in the line. Then keep only the +; location of the first one since this is the only one that can indi- +; cate the separation between the variable name (on the left of it) and +; the value (on the right). If there is no equal sign, print out a +; warning and exit +; +; ********************************************************************** +; + inds_equals := ind(line .eq. equal_char) + if (ismissing(inds_equals(0))) then + print("") + print("No equal sign found on line:") + print(" line = " + line) + print("Stopping.") + exit + else + indx_first_equal := inds_equals(0) + end if +; +; ********************************************************************** +; +; Get the name of the variable from the portion of the current line be- +; fore the first equal sign (which we refer to as the left-hand side). +; This will be the name of an attribute of the output variable of this +; function. +; +; ********************************************************************** +; + attr_name = str_strip(tostring(line(:indx_first_equal-1))) +; +; ********************************************************************** +; +; Extract the string to the right of the equal sign. We refer to this +; as the right-hand side. This right-hand side represents the value +; that the attribute on the left-hand side is to be assigned. +; +; ********************************************************************** +; + RHS := tochar(str_strip(tostring(line(indx_first_equal+1:)))) +;print("HELLO 1111: RHS = " + RHS) +;pause +; +; ********************************************************************** +; +; Get the first (non-whitespace) character on the right-hand side and +; check if it has an allowed value. Note that if this character is ei- +; ther a single or a double quote, it indicates that the right-hand side +; represents a character value and that the single (double) quote is the +; quotation character used to denote character strings (either is valid +; in Fortran, although not simultaneously). +; +; ********************************************************************** +; + first_char := RHS(0) + + pls_mns_pt_digit_chars \ + = (/ "+", "-", ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" /) + + quote_char = null_char + if (first_char .eq. quot1_char) then + is_char_value = True + quote_char = quot1_char + else if (first_char .eq. quot2_char) then + is_char_value = True + quote_char = quot2_char + else if (any(first_char .eq. pls_mns_pt_digit_chars)) then + is_char_value = False + else + print("") + print("Disallowed first character on right-hand side of equal sign:") + print(" first_char = " + first_char) + print("Stopping.") + exit + end if + end if + end if +; +; ********************************************************************** +; +; Consider the case of the right-hand side being of type string. +; +; ********************************************************************** +; + if (is_char_value) then +; +; ********************************************************************** +; +; Split the string containing the right-hand side into several sub- +; strings as determined by the array element delimiter character. +; +; ********************************************************************** +; + RHS_str := tostring(RHS) + if (quote_char .eq. quot1_char) then + rhs := str_split_csv(RHS_str, tostring(elem_delim_char), 1) + else if (quote_char .eq. quot2_char) then + rhs := str_split_csv(RHS_str, tostring(elem_delim_char), 2) + end if + end if +; +; ********************************************************************** +; +; The str_split_csv(...) function returns a 2-D array with the first di- +; mension equal to the number of strings in the input string array. +; Since here we alway pass in a single line (a 1-D string array), this +; first dimension is degenerate (i.e. it is a singleton dimension). +; Use the rm_single_dims(...) function to get rid of this dimension. +; +; ********************************************************************** +; + rhs := rm_single_dims(rhs) +; +; ********************************************************************** +; +; Remove leading and trailing whitespace (which, if present, will be +; outside the quotation marks) and thus unimportant. +; +; ********************************************************************** +; + rhs := str_strip(rhs) +; +; ********************************************************************** +; +; Remove all elements of the string array rhs that are either blank or +; contain missing values. The blank values show up if there are two ar- +; ray element delimiters separated by only whitespace, and the missing +; values show up if there are two delimiters without any other charac- +; ters between them. In either case, there is no information to retain. +; +; ********************************************************************** +; + rhs := rhs(ind(.not. ismissing(rhs) .and. .not. str_is_blank(rhs))) +; +; ********************************************************************** +; +; Process the strings in the rhs array. +; +; ********************************************************************** +; + in_quotes = True + num_strings = dimsizes(rhs) + i = 0 + do while ((i .le. num_strings-1) .and. in_quotes) + + temp := tochar(rhs(i)) + num_chars := strlen(rhs(i)) + + first_char := temp(0) + last_char := temp(num_chars-1) +; +; ********************************************************************** +; +; First, check whether the current string in rhs starts and ends with a +; quotation character. If so, retain only the characters between the +; quotes. +; +; ********************************************************************** +; + if ((first_char .eq. quote_char) .and. \ + (last_char .eq. quote_char)) then + + temp := tochar(rhs(i)) + rhs(i) = tostring(temp(ind(temp .ne. quote_char))) + i = i + 1 +; +; ********************************************************************** +; +; Next, check whether at least the first character is a quotation cha- +; racter. If so, search for the second quote somewhere in the string. +; If it exists and if the characters after it are optional whitespace +; followed by a comment character, then we discard all characters after +; the second quote (and then we also discard the quotes). Otherwise, +; we print out a warning message and stop execution. +; +; ********************************************************************** +; + else if ((first_char .eq. quote_char) .and. \ + (last_char .ne. quote_char)) then +; +; ********************************************************************** +; +; Find the index of the second occurrence of the quotation character, +; if any. Note that we know there will be at least one because the +; first character is a quotation character. +; +; ********************************************************************** +; + temp := ind(tochar(rhs(i)) .eq. quote_char) + num_quotes = dimsizes(temp) + if (num_quotes .gt. 1) then + indx_second_quote := temp(1) + else + print("") + print("Improperly formatted character specification. Cannot " + \ + "find matching quotation character:") + print(" RHS = " + RHS) + print(" quote_char = " + quote_char) + print(" elem_delim_char = " + elem_delim_char) + print(" i = " + i) + print(" rhs(i) = " + rhs(i)) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; If here, second quotation character exists. +; +; ********************************************************************** +; + temp := tochar(rhs(i)) + temp := tochar(str_strip(tostring(temp(indx_second_quote+1:)))) + first_char := temp(0) + if (first_char .eq. cmmnt_char) then + temp := tochar(rhs(i)) + temp := temp(:indx_second_quote) + rhs(i) = tostring(temp(ind(temp .ne. quote_char))) + i = i + 1 + break + else + print("") + print("Improperly formatted character specification. Characters " + \ + "are not quoted:") + print(" RHS = " + RHS) + print(" quote_char = " + quote_char) + print(" elem_delim_char = " + elem_delim_char) + print(" i = " + i) + print(" rhs(i) = " + rhs(i)) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; If the first character in the current string is a comment character, +; it signals the end of the meaningful portion of the line, so we move +; on to the next line (i.e. no need to look at the remaining strings in +; rhs). +; +; ********************************************************************** +; + else if (first_char .eq. cmmnt_char) then + + in_quotes = False + break +; +; ********************************************************************** +; +; If the first character is not a quotation or comment character, some- +; thing must be wrong. In this case, print out a warning and stop exe- +; cution. +; +; ********************************************************************** +; + else + + print("") + print("Improperly formatted character specification. Characters " + \ + "are not quoted:") + print(" RHS = " + RHS) + print(" quote_char = " + quote_char) + print(" elem_delim_char = " + elem_delim_char) + print(" i = " + i) + print(" rhs(i) = " + rhs(i)) + print("Stopping.") + exit + + end if + end if + end if + + end do +; +; ********************************************************************** +; +; Keep only those strings in rhs that were processed as meaningful ele- +; ments of a string array (e.g. don't keep portions that are comments +; in the namelist file). +; +; ********************************************************************** +; + rhs := rhs(:i-1) +; +; ********************************************************************** +; +; Consider the case of the right-hand side being of type logical, inte- +; ger, or float. +; +; ********************************************************************** +; + else +; +; ********************************************************************** +; +; Get the number of comment characters on the right-hand side. If there +; is at least one comment character, keep as the right-hand side only +; those characters before the first comment character. +; +; ********************************************************************** +; + inds_cmmnts := ind(RHS .eq. cmmnt_char) + num_cmmnts = dimsizes(inds_cmmnts) + if ((num_cmmnts .eq. 1) .and. ismissing(inds_cmmnts(0))) + num_cmmnts = 0 + end if + + if (num_cmmnts .ne. 0) then + RHS := RHS(:inds_cmmnts(0)-1) + end if +; +; ********************************************************************** +; +; Squeeze out any extra (repeated) spaces and tabs, e.g. between array +; elements. +; +; ********************************************************************** +; + RHS_str := str_squeeze(tostring(RHS)) + RHS := tochar(RHS_str) +;print("HELLO 2222: RHS = " + RHS) +; +; ********************************************************************** +; +; Consider the case of the right-hand side being of type logical. +; +; ********************************************************************** +; +; The str_match_ic_regex(...) function is only available in NCL version +; 6.3.0 and later, which may not be available for various reasons. So +; try using another method to check whether the right-hand side contains +; logical values. + +; true_str := str_match_ic_regex(RHS_str, "\.t(rue)?\.") +; false_str := str_match_ic_regex(RHS_str, "\.f(alse)?\.") + + true_str := str_match_ic(RHS_str, ".t.") + if (ismissing(true_str)) then + true_str := str_match_ic(RHS_str, ".true.") + end if + + false_str := str_match_ic(RHS_str, ".f.") + if (ismissing(false_str)) then + false_str := str_match_ic(RHS_str, ".false.") + end if + + if ( (.not. ismissing(true_str)) .or. \ + (.not. ismissing(false_str)) ) then + + RHS_str := str_upper(RHS_str) + rhs := str_strip(str_split(RHS_str, tostring(elem_delim_char))) + inds_True := ind((rhs .eq. ".T.") .or. (rhs .eq. ".TRUE.")) + inds_False := ind((rhs .eq. ".F.") .or. (rhs .eq. ".FALSE.")) + + rhs := new(dimsizes(rhs), "logical") + if (.not. ismissing(inds_True(0))) then + rhs(inds_True) = True + end if + if (.not. ismissing(inds_False(0))) then + rhs(inds_False) = False + end if +; +; ********************************************************************** +; +; Consider the right-hand side being of type integer or float. First, +; get the number of decimal points (periods) on the right-hand side. If +; any are present, we will treat the right-hand side as of type float. +; Otherwise, we will treat the right-hand side as of type integer. +; +; ********************************************************************** +; + else + + num_elem_delim_chars := product(dimsizes(elem_delim_chars)) + num_elems := new(num_elem_delim_chars, "integer") +;print("num_elem_delim_chars = " + num_elem_delim_chars) + do i=0, num_elem_delim_chars-1 + temp := str_strip(str_split(RHS_str, tostring(elem_delim_chars(i)))) + num_elems(i) = product(dimsizes(temp)) +;print("BYE 0000: i = " + i) +;print("BYE 1111: num_elems(i) = " + num_elems(i)) + end do + + inds_num_elems_gt_one := ind(num_elems .gt. 1) + ne := product(dimsizes(inds_num_elems_gt_one)) + + if (ne .gt. 1) + + print("") + print("More than one array delimiter character yields " + \ + "a number of array elements that " + newline_char + \ + "is greater than one:") + print(" RHS_str = " + RHS_str) + do i=0, num_elem_delim_chars-1 + print(" i = " + i + \ + "; elem_delim_chars(i) = " + quot2_char + elem_delim_chars(i) + quot2_char + \ + "; num_elems(i) = " + num_elems(i)) + end do + print("Stopping.") + exit + + else if (ne .eq. 1) + + if (.not. ismissing(inds_num_elems_gt_one)) + num_elems := num_elems(inds_num_elems_gt_one) + else + num_elems := 1 + end if + + else + + print("") + print("The variable ne should not be less than 1:") + print(" ne = " + ne) + print("Stopping.") + exit + + end if + end if + + +;a(ind(ismissing(a))) = 0; + +;print("BYE 2222: num_elems = " + num_elems) +;print("BYE 3333: inds_num_elems_gt_one = " + inds_num_elems_gt_one) +;print("BYE 4444: ne = " + ne) +; num_elems := num_elems(inds_num_elems_gt_one) +;print("BYE 5555: num_elems = " + num_elems) + +;print("HELLO 3333: RHS_str = " + RHS_str) +;print("HELLO 4444: temp = " + temp) + + num_decimals = num(RHS .eq. decimal_char) + if (num_decimals .eq. 0) then + rhs := stringtointeger(temp) + else + rhs := stringtofloat(temp) + end if +;print("HELLO 5555: rhs = " + rhs) +;pause + end if + + end if +; +; ********************************************************************** +; +; Assign attribute to the value specified on the right-hand side. +; +; ********************************************************************** +; + nl@$attr_name$ = rhs + + end do +; +; ********************************************************************** +; +; Done with loop over lines in namelist file. Now return the output va- +; riable. +; +; ********************************************************************** +; +;list_vars() + return(nl) + +end + + diff --git a/ush/NCL/lib/repeat_str.ncl b/ush/NCL/lib/repeat_str.ncl new file mode 100644 index 0000000000..dc8c1924f9 --- /dev/null +++ b/ush/NCL/lib/repeat_str.ncl @@ -0,0 +1,47 @@ +; +; ********************************************************************** +; +; File name: repeat_str.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function repeats the specified string (str_in) the specified num- +; ber of times (num_repeats) and returns the result in a new string +; (str_out). If num_repeats is a 1-D array of integers, the result is a +; 1-D array of strings with the ith element of the array containing a +; string that consists of the input string (str_in) repeated num_- +; repeats(i) times. +; +; ********************************************************************** +; +undef("repeat_str") + +function repeat_str(str_in:string, num_repeats[*]:integer) + +local i, num_strings, str_tmp, str_out + +begin + + num_strings = dimsizes(num_repeats) + str_out := new(num_strings, "string") + + do i=0, num_strings-1 + + if (num_repeats(i) .eq. 0) then + str_tmp := "" + else + str_tmp := new(num_repeats(i), string) + str_tmp = str_in ; This must be an equal sign, not a colon-equal. + str_tmp := str_concat(str_tmp) ; This must be a colon-equal sign, not an equal. + end if + + str_out(i) = str_tmp + + end do + + return(str_out) + +end + + diff --git a/ush/NCL/lib/set_cnLevels_lbLabels.ncl b/ush/NCL/lib/set_cnLevels_lbLabels.ncl new file mode 100644 index 0000000000..be9981f9dd --- /dev/null +++ b/ush/NCL/lib/set_cnLevels_lbLabels.ncl @@ -0,0 +1,651 @@ +; +; ********************************************************************** +; +; File name: set_cnLevels_lbLabels.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function generates and returns a 1-D numeric array (cnLevels) +; containing the levels at which to draw contours for a field having the +; specified minimum and maximum values (field_min and field_max). The +; number of such levels we would like this function to generate (i.e. +; the length that we would like cnLevels to be) is specified by the in- +; put argument num_cnLevels, but this is not strictly adhered to; the +; length of cnLevels may be slightly different than this value. +; +; This function also generates (and returns) a string array (lbLabels) +; containing the labels corresponding to the calculated levels. These +; labels can be used to annotate the contour lines (using the cnLineLa- +; belStrings resource) and/or to annotate the labelbar (using the lbLa- +; belStrings resource) in case a labelbar is to be generated for the +; contour plot. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("set_cnLevels_lbLabels") + +function set_cnLevels_lbLabels( \ + field_min:snumeric, field_max:snumeric, num_cnLevels:integer, \ + opts:logical) + +local field_type, \ + field_range, nLevs, cnIntvl, \ + precision, fmt, cnIntvl_E_fmt_str, \ + indx_E, mntsa_cnIntvl_str, expnt_cnIntvl_str, \ + mntsa_cnIntvl, expnt_cnIntvl, expnt_cnIntvl_factor, \ + mntsa_cnLevel_min, cnLevel_min, cnLevel_max, abs_diff, \ + cnLevels, lbLabels, \ + contour_info + +begin +; +; ********************************************************************** +; +; If either field_min or field_max (or both) are set to missing values, +; we cannot calculate any contour values. In this case, set cnLevels to +; an array of missing values of length num_cnLevels, and set lbLabels to +; an array of blank strings of length num_cnLevels. +; +; ********************************************************************** +; + if (ismissing(field_min) .or. ismissing(field_max)) then + + cnLevels := new((/ num_cnLevels /), typeof(field_min)) + cnLevels = default_fillvalue(typeof(cnLevels)) + lbLabels := new((/ num_cnLevels /), string) + lbLabels = "" + + contour_info := True + contour_info@cnLevels = cnLevels + contour_info@lbLabels = lbLabels + + return(contour_info) + + end if +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line \ + := "========================================================================" + end if +; +; ********************************************************************** +; +; The logical attribute verbose of the options argument (opts) deter- +; mines whether informational messages are printed out to the screen. +; If this attribute is not defined, set it to False. +; +; ********************************************************************** +; + if (.not. isatt(opts, "verbose")) then + opts@verbose = False + end if + + if (opts@verbose) then + print("") + print("" + separator_line) + print("Start of output from function set_cnLevels_lbLabels(...):") + end if +; +; ********************************************************************** +; +; Ensure that field_min is less than or equal to field_max. +; +; ********************************************************************** +; + if (.not. (field_min .le. field_max)) then + print("") + print("Error: field_min must be less than or equal to field_max:") + print(" field_min = " + field_min) + print(" field_max = " + field_max) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Get the data type of the field and store it in the variable field_- +; type. In doing so, we first check whether field_min and field_max are +; of the same type. If so, we set field_type to this type. If not, we +; print out an error message and stop. +; +; ********************************************************************** +; + if (strcmp_exact(typeof(field_min), typeof(field_max))) then + field_type = typeof(field_min) + else + print("") + print("Error: field_min and field_max must have the same data type:") + print(" typeof(field_min) = " + typeof(field_min)) + print(" typeof(field_max) = " + typeof(field_max)) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Calculate the range of values for the field, i.e. the difference be- +; tween the maximum and minimum values. Then use this range to calcu- +; late an initial estimate for the contour interval (i.e. the difference +; between any two contour level values), which we denote by cnIntvl. +; +; ********************************************************************** +; + field_range = field_max - field_min + nLevs = num_cnLevels + cnIntvl = field_range/(nLevs - 1) + + if (opts@verbose) then + print("") + print("Input parameters and initial estimate of contour interval:") + print(" field_min = " + field_min) + print(" field_max = " + field_max) + print(" field_range = " + field_range) + print(" field_type = " + field_type) + print(" nLevs = " + nLevs) + print(" cnIntvl = " + cnIntvl) + end if +; +; ********************************************************************** +; +; Consider case of a constant field. +; +; ********************************************************************** +; + if (field_range .eq. 0) then + + print("") + print("Encountered constant field.") + print("Setting all nLevs = " + tostring(nLevs) + \ + " contour levels to same value.") + + cnLevels := new((/nLevs/), field_type) + cnLevels = field_min + + fmt = "%0.2f" + lbLabels = sprintf(fmt, cnLevels) + + contour_info := True + contour_info@cnLevels = cnLevels + contour_info@lbLabels = lbLabels + + if (opts@verbose) then + print("") + print("End of output from function set_cnLevels_lbLabels(...).") + print("" + separator_line) + end if + + return(contour_info) + + end if +; +; ********************************************************************** +; +; Generate a string containing the contour interval (cnIntvl) expressed +; in scientific notation, i.e. in the form +; +; [-]m.ddE±xx, +; +; where the number of "d"s (i.e. the precision) is 2. +; +; ********************************************************************** +; + precision = 2 + fmt = "%0." + precision + "E" + cnIntvl_E_fmt_str := sprintf(fmt, cnIntvl) +; +; ********************************************************************** +; +; Get the portions of the string before the "E" (the mantissa) and after +; (the exponent). +; +; ********************************************************************** +; + indx_E = str_index_of_substr(cnIntvl_E_fmt_str, "E", 1) + mntsa_cnIntvl_str := str_get_cols(cnIntvl_E_fmt_str, 0, indx_E-1) + expnt_cnIntvl_str := str_get_cols(cnIntvl_E_fmt_str, indx_E+1, -1) + + if (opts@verbose) then + print("") + print("After conversion of cnIntvl to a string using formatted " + \ + "sprintf(...):") + print(" fmt = " + char_dq + fmt + char_dq) + print(" cnIntvl_E_fmt_str = " + cnIntvl_E_fmt_str) + print(" mntsa_cnIntvl_str = " + mntsa_cnIntvl_str) + print(" expnt_cnIntvl_str = " + expnt_cnIntvl_str) + end if +; +; ********************************************************************** +; +; Calculate the mantissa and the exponent of cnIntvl by converting their +; string representations back to numerical representations. Note that: +; +; *) The mantissa will be rounded to 3 significant digits. This is be- +; cause in expressing the mantissa in scientific notation above using +; the sprintf(...) function, we set the precision to 2. This is a +; minor adjustment to the mantissa. +; +; *) Due to the output format used in the call to sprintf(...) above, +; the mantissa of cnIntvl is guaranteed to be greater than or equal +; to 1 and less than 10. +; +; Then use the mantissa and exponent of cnIntvl to calculate cnIntvl to +; 3 significant digits. +; +; ********************************************************************** +; + mntsa_cnIntvl = totype(mntsa_cnIntvl_str, field_type) + expnt_cnIntvl = tointeger(expnt_cnIntvl_str) + cnIntvl = mntsa_cnIntvl*10^expnt_cnIntvl + + if (opts@verbose) then + print("") + print("After rounding cnIntvl to " + tostring(precision+1) + \ + " significant digits:") + print(" mntsa_cnIntvl = " + mntsa_cnIntvl) + print(" expnt_cnIntvl = " + expnt_cnIntvl) + print(" cnIntvl = " + cnIntvl) + end if +; +; ********************************************************************** +; +; We now adjust the mantissa of the contour interval (mntsa_cnIntvl) to +; obtain a value that will (later below) generate "nice" values for the +; contour levels, i.e. values that are easily comprehensible in a con- +; tour plot. In this adjustment, we require that mntsa_cnIntvl be one +; of the integers 1, 2, 4, 5, and 10. To determine which of these inte- +; gers mntsa_cnIntvl be set to, we first find the one it is is closest +; to and then reset it to that integer. Thus, the adjustment procedure +; for mntsa_cnIntvl is as follows: +; +; *) If 1.0 <= mntsa_cnIntvl < 1.5, reset mntsa_cnIntvl to 1. +; *) If 1.5 <= mntsa_cnIntvl < 3.0, reset mntsa_cnIntvl to 2. +; *) If 3.0 <= mntsa_cnIntvl < 4.5, reset mntsa_cnIntvl to 4. +; *) If 4.5 <= mntsa_cnIntvl < 7.5, reset mntsa_cnIntvl to 5. +; *) If 7.5 <= mntsa_cnIntvl < 10, reset mntsa_cnIntvl to 10. +; +; ********************************************************************** +; + if ((1.0 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 1.5)) then + mntsa_cnIntvl = 1 + else if ((1.5 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 3.0)) then + mntsa_cnIntvl = 2 + else if ((3.0 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 4.5)) then + mntsa_cnIntvl = 4 + else if ((4.5 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 7.5)) then + mntsa_cnIntvl = 5 + else if ((7.5 .le. mntsa_cnIntvl) .and. (mntsa_cnIntvl .lt. 10.0)) then +; Resetting the mntsa_cnIntvl to 10 is the same as resetting it to 1 and +; incrementing the exponent of cnIntvl (expnt_cnIntvl) by 1. + mntsa_cnIntvl = 1 + expnt_cnIntvl = expnt_cnIntvl + 1 + end if + end if + end if + end if + end if +; +; ********************************************************************** +; +; Since mntsa_cnIntvl is now an integer and will be treated as such in +; the following code, we now change its type to an integer. +; +; ********************************************************************** +; + mntsa_cnIntvl := tointeger(mntsa_cnIntvl) +; +; ********************************************************************** +; +; Use the new integer value of mntsa_cnIntvl to calculate a new cnIntvl. +; +; ********************************************************************** +; + expnt_cnIntvl_factor := 10^expnt_cnIntvl + cnIntvl := mntsa_cnIntvl*expnt_cnIntvl_factor + + if (opts@verbose) then + print("") + print("After adjusting cnIntvl to a " + char_dq + "nice" + char_dq + \ + " integer value:") + print(" mntsa_cnIntvl = " + mntsa_cnIntvl) + print(" expnt_cnIntvl = " + expnt_cnIntvl + \ + " (expnt_cnIntvl_factor = " + expnt_cnIntvl_factor + ")") + print(" cnIntvl = " + cnIntvl) + end if +; +; ********************************************************************** +; +; In order to obtain "nice" values for the contour levels, not only must +; the contour interval have a nice value but so must the minimum contour +; line value cnLevel_min (because we will add multiples of cnIntvl to +; cnLevel_min to obtain all the contour line values). To derive a nice +; value for cnLevel_min, we start by deriving such a value for its man- +; tissa, as described below. +; +; Calculate an initial estimate for the mantissa of the minimum contour +; line value cnLevel_min if cnLevel_min were expressed with an exponent +; that is equal to that of cnIntvl. We denote this mantissa by mntsa_- +; cnLevel_min. Thus, mntsa_cnLevel_min is defined by the expression +; +; cnLevel_min = mntsa_cnLevel_min*10^(expnt_cnIntvl) +; +; Solving this for mntsa_cnLevel_min gives +; +; mntsa_cnLevel_min = cnLevel_min/10^(expnt_cnIntvl) +; +; To obtain an initial estimate for mntsa_cnLevel_min, we set cnLevel_- +; min on the right-hand side to field_min. This gives +; +; mntsa_cnLevel_min = field_min/10^(expnt_cnIntvl) +; +; We use this expression below. +; +; ********************************************************************** +; + mntsa_cnLevel_min = field_min/expnt_cnIntvl_factor +; +; ********************************************************************** +; +; To obtain a "nice" value for cnLevel_min (i.e. a value that is easily +; comprehensible when displayed in a contour plot), we will require that +; its mantissa be an integer. Also, we would like cnLevel_min to be +; less than or equal to field_min (so that all values of the field are +; included in the range [cnLevel_min, cnLevel_max] that we will calcu- +; late). Thus, we now truncate the mntsa_cnLevel_min calculated above +; using NCL's floor(...) function. +; +; ********************************************************************** +; + mntsa_cnLevel_min := tointeger(floor(mntsa_cnLevel_min)) +; +; ********************************************************************** +; +; We do not necessary yet have a "nice" value for mntsa_cnLevel_min, +; i.e. a value that will correspond to a "nice" value for cnLevel_min in +; the contour plot to be generated. Thus, we now decrement our previous +; estimate for mntsa_cnLevel_min (which is now an integer) by 1 as many +; times as necessary until we obtain one that corresponds to a "nice" +; value. (Note that we decrement, not increment, by 1 in order to be +; sure that the value of cnLevel_min we end up with is less than or +; equal to field_min.) What constitutes a "nice" value for mntsa_cnLe- +; vel_min depends on the mantissa of cnIntvl (i.e. mntsa_cnIntvl; recall +; that this is now one of the following integers: 1, 2, 4, and 5) as +; follows: +; +; *) If mntsa_cnIntvl is 1, we define a "nice" value for mntsa_cnLevel_- +; min to be any integer. Since mntsa_cnLevel_min is already an inte- +; ger, we do not need to make any adjustments to it. +; +; *) If mntsa_cnIntvl is 2 or 4, we define a "nice" value for mntsa_cn- +; Level_min to be an even integer. Thus, if mntsa_cnLevel_min is al- +; ready even, we do not make any adjustments to it. If mntsa_cnLe- +; vel_min is odd, we decrement it by 1 to obtain an even integer. +; +; *) If mntsa_cnIntvl is 5, we define a "nice" value for mntsa_cnLevel_- +; min_to be an integer that ends in a 0 or a 5 (i.e. an integer that +; is evenly divisible by 5). Thus, if mntsa_cnLevel_min is already +; divisible by 5, we do not make any adjustments to it. If mntsa_- +; cnLevel_min is not divisible by 5, we repeatedly decrement it by 1 +; until we obtain a value that is divisible by 5. +; +; ********************************************************************** +; + if (mntsa_cnIntvl .eq. 1) then + +; Do nothing. + + else if ((mntsa_cnIntvl .eq. 2) .or. (mntsa_cnIntvl .eq. 4)) then + + if ((mntsa_cnLevel_min%2) .ne. 0) then + mntsa_cnLevel_min = mntsa_cnLevel_min - 1 + end if + + else if (mntsa_cnIntvl .eq. 5) then + + do while ((mntsa_cnLevel_min%5) .ne. 0) + mntsa_cnLevel_min = mntsa_cnLevel_min - 1 + end do + + else + + print("") + print("Error: Disallowed value for mntsa_cnIntvl:") + print(" mntsa_cnIntvl = " + mntsa_cnIntvl) + print("mntsa_cnIntvl must be 1, 2, 4, or 5.") + print("Stopping.") + exit + + end if + end if + end if +; +; ********************************************************************** +; +; Now that we've determined the mantissa and exponent of the first +; (i.e. smallest or minimum) contour level cnLevel_min (the mantissa +; being mntsa_cnLevel_min and the exponent being the same as that of +; cnIntvl, i.e. expnt_cnIntvl), we proceed to calculate cnLevel_min it- +; self. Note that since mntsa_cnLevel_min and expnt_cnIntvl_factor are +; both integers, cnLevel_min will also be an integer. Note also that +; cnLevel_min will be less than field_min by some amount that is less +; than or equal to cnIntvl. +; +; ********************************************************************** +; + cnLevel_min := mntsa_cnLevel_min*expnt_cnIntvl_factor +; +; ********************************************************************** +; +; Now calculate the value of the last (i.e. largest or maximum) contour +; level (cnLevel_max). We do this by first setting cnLevel_max to cnLe- +; vel_min and then repeatedly incrementing it by cnIntvl until it be- +; comes greater than or equal to field_max. Then calculate the number +; of contour levels between cnLevel_min and cnLevel_max, inclusive. +; +; ********************************************************************** +; + cnLevel_max := cnLevel_min + do while (cnLevel_max .lt. field_max) + cnLevel_max = cnLevel_max + cnIntvl + end do + nLevs = tointeger(round((cnLevel_max - cnLevel_min)/cnIntvl + 1, 0)) + + if (opts@verbose) then + print("") + print("Contour level min/max values that include field_min and field_max:") + print(" cnLevel_min = " + cnLevel_min + " (field_min = " + field_min + ")") + print(" cnLevel_max = " + cnLevel_max + " (field_max = " + field_max + ")") + print(" cnIntvl = " + cnIntvl) + print(" nLevs = " + nLevs) + end if +; +; ********************************************************************** +; +; Check that cnLevel_min is indeed less than or equal to field_min and +; that cnLevel_max is indeed greater than or equal to field_max. This +; should be the case by design, but we test to be sure. +; +; ********************************************************************** +; + if (cnLevel_min .gt. field_min) then + print("") + print("cnLevel_min must be less than or equal to field_min in " + \ + "order for the " + char_nl + \ + "contour plot to include all values of the field:") + print(" cnLevel_min = " + cnLevel_min) + print(" field_min = " + field_min) + print("Stopping.") + exit + end if + + if (cnLevel_max .lt. field_max) then + print("") + print("cnLevel_max must be greater than or equal to field_max in " + \ + "order for the " + char_nl + \ + "contour plot to include all values of the field:") + print(" cnLevel_max = " + cnLevel_max) + print(" field_max = " + field_max) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Check that the difference between field_min and cnLevel_min is indeed +; less than or equal to cnIntv. Similary, check that the difference be- +; tween field_max and cnLevel_max is indeed less than or equal to cn- +; Intv. These constraints should be satisfied, but test to be sure. +; +; ********************************************************************** +; + abs_diff = abs(field_min - cnLevel_min) + if (abs_diff .gt. cnIntvl) then + print("") + print("cnLevel_min must be within cnIntvl of field_min:") + print(" field_min = " + field_min) + print(" cnLevel_min = " + cnLevel_min) + print(" cnIntvl = " + cnIntvl) + print(" abs(field_min - cnLevel_min))= " + abs_diff) + print("Stopping.") + exit + end if + + abs_diff = abs(field_max - cnLevel_max) + if (abs_diff .gt. cnIntvl) then + print("") + print("cnLevel_max must be within cnIntvl of field_max:") + print(" field_max = " + field_max) + print(" cnLevel_max = " + cnLevel_max) + print(" cnIntvl = " + cnIntvl) + print(" abs(field_max - cnLevel_max))= " + abs_diff) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; We now have a cnLevel_min and a cnLevel_max that satisfy the inequali- +; ties +; +; cnLevel_min <= field_min <= field_max <= cnLevel_max +; +; and +; +; 0 <= field_min - cnLevel_min <= cnIntvl +; +; and +; +; 0 <= cnLevel_max - field_max <= cnIntvl +; +; Note that during the generation a contour plot in NCL, if the contour +; levels are specified, the contour plot routines add a bin (or color if +; color-filling between contour levels) before the minimum specified +; contour value (to hold field values that are less than the minimum +; contour value) and a bin (or color) after the maximum specified con- +; tour value (to hold field values that are greater than the maximum +; contour value). Thus, if the range [cnLevel_min, cnLevel_max] already +; includes field_min and field_max, no values of the field will fall in +; these two new bins, making them irrelevant. To make these bins rele- +; vant, we now increase cnLevel_min by cnIntvl and decrease cnLevel_max +; by cnIntvl such that we have +; +; field_min <= cnLevel_min <= cnLevel_max <= field_max +; +; and +; +; 0 <= cnLevel_min - field_min <= cnIntvl +; +; and +; +; 0 <= field_max - cnLevel_max <= cnIntvl +; +; With this modification, at least some values of the field will fall +; within the two bins that the NCL contour plotting routines add. +; +; ********************************************************************** +; + cnLevel_min := cnLevel_min + cnIntvl + cnLevel_max := cnLevel_max - cnIntvl + nLevs = tointeger(round((cnLevel_max - cnLevel_min)/cnIntvl + 1, 0)) + + if (opts@verbose) then + print("") + print("Contour level min/max values that exclude field_min and " + \ + "field_max " + char_nl + \ + "(by less than a contour interval):") + print(" cnLevel_min = " + cnLevel_min + " (field_min = " + field_min + ")") + print(" cnLevel_max = " + cnLevel_max + " (field_max = " + field_max + ")") + print(" cnIntvl = " + cnIntvl) + print(" nLevs = " + nLevs) + end if +; +; ********************************************************************** +; +; Construct the numeric array containing the contour levels. Note that +; cnIntvl is not necessarily an integer, so we cannot use +; +; cnLevels := ispan(cnLevel_min, cnLevel_max, cnIntvl) +; +; ********************************************************************** +; + cnLevels := fspan(cnLevel_min, cnLevel_max, nLevs) + + if (opts@verbose) then + print("") + print("Contour level values:") + print(" cnLevels = " + cnLevels) + end if +; +; ********************************************************************** +; +; Construct the string array containing the contour labels. +; +; ********************************************************************** +; + precision = 0 + if (expnt_cnIntvl .lt. 0) then + precision = abs(expnt_cnIntvl) + end if + fmt = "%0." + tostring(precision) + "f" + lbLabels = sprintf(fmt, cnLevels) + + if (opts@verbose) then + print("") + print("Contour level labels (strings) generated using fmt = " + \ + char_dq + fmt + char_dq + ":") + print(" lbLabels = " + lbLabels) + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable contour_info. +; +; ********************************************************************** +; + contour_info := True + + contour_info@cnLevels = totype(cnLevels, field_type) + contour_info@lbLabels = lbLabels + + if (opts@verbose) then + print("") + print("End of output from function set_cnLevels_lbLabels(...).") + print("" + separator_line) + end if + + return(contour_info) + +end + + diff --git a/ush/NCL/lib/special_chars.ncl b/ush/NCL/lib/special_chars.ncl new file mode 100644 index 0000000000..52e8f5ab6e --- /dev/null +++ b/ush/NCL/lib/special_chars.ncl @@ -0,0 +1,11 @@ +; +; ********************************************************************** +; +; Define special characters that can't be directly input into an NCL +; string. +; +; ********************************************************************** +; +char_nl = str_get_nl() +char_dq = str_get_dq() +char_sq = str_get_sq() diff --git a/ush/NCL/lib/strcmp.ncl b/ush/NCL/lib/strcmp.ncl new file mode 100644 index 0000000000..a83f65cda1 --- /dev/null +++ b/ush/NCL/lib/strcmp.ncl @@ -0,0 +1,35 @@ +; +; ********************************************************************** +; +; File name: strcmp.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function compares two strings. It returns True if they are iden- +; tical and False otherwise. It is called as follows: +; +; are_equal = strcmp(str1, str2) +; +; ********************************************************************** +; +undef("strcmp") + +function strcmp(str1:string, str2:string) + +local len1, len2, match_result, are_equal + +begin + + len1 = strlen(str1) + len2 = strlen(str2) + match_result = str_match(str1, str2) + are_equal = False + if ((.not. ismissing(match_result)) .and. (len1 .eq. len2)) then + are_equal = True + end if + return(are_equal) + +end + + diff --git a/ush/NCL/lib/strcmp_exact.ncl b/ush/NCL/lib/strcmp_exact.ncl new file mode 100644 index 0000000000..910fbbd8a4 --- /dev/null +++ b/ush/NCL/lib/strcmp_exact.ncl @@ -0,0 +1,126 @@ +; +; ********************************************************************** +; +; File name: strcmp_exact.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function compares each element of the string array str_array to +; the string (scalar) str. It returns a variable (match_found) that +; will be set to True if at least one element of str_array is identical +; to str and False otherwise (i.e. it will be set to False if none of +; the elements of str_array are identical to str). This function also +; returns (as an attribute of match_found) a 1-D logical array (exact_- +; match) having the same dimensions as str_array that will be True at +; those indices at which str_array is identical to str and False every- +; where else. +; +; Note that str_array may be a scalar string, in which case this func- +; tion simply compares two strings. If the two strings are identical, +; then this function returns True in match_found as well as its attri- +; bute match_found@str_array (which in this case will be a scalar). If +; the two strings are not identical, then match_found and match_found@- +; match_by_elem will both be False. +; +; ********************************************************************** +; +undef("strcmp_exact") + +function strcmp_exact(str_array[*]:string, str[1]:string) + +local match_found, dims, match_by_elem, \ + lens_str_array, len_str, same_num_chars, \ + substr_found, match_found + +begin +; +; ********************************************************************** +; +; Initialize the return variable (match_found) to False. Also, create a +; logical array (match_by_elem) of the same size as str_array and set +; all its elements to False. +; +; Note that ideally, we would like match_by_elem to be an attribute of +; match_found, i.e. match_found@match_by_elem, but apparently NCL does +; not allow arrays that are attributes of another variable to be set to +; the same value everywhere by setting them to a scalar value. Thus, we +; cannot do the following: +; +; match_found@match_by_elem = new(dims, logical) +; match_found@match_by_elem = False +; +; The second line will generate an error. For this reason, below we in- +; stead first work with the non-attribute array match_by_elem and then +; set it to an attribute of match_found later on. +; +; ********************************************************************** +; + match_found = False + dims = dimsizes(str_array) + match_by_elem = new(dims, logical) + match_by_elem = False +; +; ********************************************************************** +; +; Generate a 1-D logical array (same_num_chars) of the same length as +; str_array that is True for those elements of str_array that have the +; same number of characters as str and False for all other elements. +; +; ********************************************************************** +; + lens_str_array = strlen(str_array) + len_str = strlen(str) + same_num_chars = where(lens_str_array .eq. len_str, True, False) +; +; ********************************************************************** +; +; If any of the elements of str_array have the same length as str, then +; continue to try to find exact matches. If not, we already know that +; there are no exact matches and can exit the function with a False re- +; sult. +; +; ********************************************************************** +; + if (any(same_num_chars)) then +; +; ********************************************************************** +; +; Generate a logical array (substr_found) of the same dimensions as +; str_array that is True for those elements of str_array that contain +; str as a substring and False everywhere else. +; +; ********************************************************************** +; + substr_found = str_match_bool(str_array, str) +; +; ********************************************************************** +; +; Set match_by_elem to True for those elements of str_array that are +; identical to str [or, equivalently, for those elements of str_array +; that (1) contain str as a substring and (2) have the same number of +; characters as str] and False everywhere else. +; +; ********************************************************************** +; + match_by_elem \ + = where(substr_found .and. same_num_chars, True, False) + if (any(match_by_elem)) then + match_found = True + end if + + end if +; +; ********************************************************************** +; +; Return result as an attribute of the logical variable match_found. +; +; ********************************************************************** +; + match_found@match_by_elem = match_by_elem + + return(match_found) + +end + + diff --git a/ush/NCL/lib/strpad.ncl b/ush/NCL/lib/strpad.ncl new file mode 100644 index 0000000000..56b6b2f692 --- /dev/null +++ b/ush/NCL/lib/strpad.ncl @@ -0,0 +1,134 @@ +; +; ********************************************************************** +; +; File name: strpad.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function pads each element of the given string array str_array +; [except for the longest one(s)] with the specified single-character +; string pad_char such that all elements of the resulting string all +; have the same length. Whether these elements are padded on the left +; or on the right depends on the value of pad_side. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "repeat_str.ncl") + +undef("strpad") + +function strpad(str_array[*]:string, pad_char[1]:string, pad_side[1]:string) + +local valid_vals_pad_side_left, valid_vals_pad_side_right, \ + valid_vals_pad_side, valid_vals, msg, \ + elem_lens, elem_len_max, num_pad_chars_by_elem, padding_strs, \ + str_array_padded + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function strpad" +; +; ********************************************************************** +; +; Check that pad_side has a valid value. +; +; ********************************************************************** +; + valid_vals_pad_side_left \ + := (/ "l", "L", "left", "Left", "LEFT" /) + valid_vals_pad_side_right \ + := (/ "r", "R", "right", "Right", "RIGHT" /) + valid_vals_pad_side \ + := array_append_record( \ + valid_vals_pad_side_left, valid_vals_pad_side_right, 0) + + if (.not. strcmp_exact(valid_vals_pad_side, pad_side)) then + + valid_vals \ + := char_dq \ + + str_join(valid_vals_pad_side, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"Input argument " + char_dq + "pad_side" + char_dq + " is not set " + \ +"to a valid value:" + char_nl + \ +" pad_side = " + char_dq + pad_side + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Stopping." + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; Check that pad_char is a string of length 1. +; +; ********************************************************************** +; + pad_char_len = strlen(pad_char) + if (pad_char_len .ne. 1) then + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"Input argument " + char_dq + "pad_char" + char_dq + " must be a string " + \ +"containing exactly one character:" + char_nl + \ +" pad_char = " + char_dq + pad_char + char_dq + char_nl + \ +" pad_char_len = " + pad_char_len + char_nl + \ +"Stopping." + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; Create an array whose elements are the padding strings (each consist- +; ing of 0 or more repetitions of pad_char) that need to be prepended or +; appended to the respective elements of str_array such that the result- +; ing array contains elements that all have the same length. +; +; ********************************************************************** +; + elem_lens := strlen(str_array) + elem_len_max := max(elem_lens) + num_pad_chars_by_elem := elem_len_max - elem_lens + padding_strs := repeat_str(pad_char, num_pad_chars_by_elem) +; +; ********************************************************************** +; +; Prepend or append the array of padding strings to str_array. +; +; ********************************************************************** +; + if (strcmp_exact(valid_vals_pad_side_left, pad_side)) then + str_array_padded := padding_strs + str_array + else if (strcmp_exact(valid_vals_pad_side_right, pad_side)) then + str_array_padded := str_array + padding_strs + end if + end if +; +; ********************************************************************** +; +; Return the resulting padded string array. +; +; ********************************************************************** +; + return(str_array_padded) + +end + + diff --git a/ush/NCL/make_FV3_RAP_domain_plots.sh b/ush/NCL/make_FV3_RAP_domain_plots.sh new file mode 100755 index 0000000000..6c09f9bac8 --- /dev/null +++ b/ush/NCL/make_FV3_RAP_domain_plots.sh @@ -0,0 +1,231 @@ +#!/bin/sh -l +#========================================================================== +# Description: This script runs plot_fields.ncl and sets all of the command- +# line arguments. There are 6 examples. The default plot is at +# the bottom on this file and plots FV3 output on a subregion over +# CONUS with an outline of the RAP boundary. Parameters that should +# be modified by the user at the top of this script are: +# +# base_name # Root name of the FV3 netcdf output file +# # .tile[n].nc will be appended in the ncl script +# grid_dir # The location of your input file +# fields # A field to plot from base_name +# nlev # A vertical level for (time,x,y,x) fields +# fcst_index # A time index to plot +# +# There is more documentation at the top of plot_fields.ncl and +# in the README file. +# +# Usage: ./make_FV3_RAP_domain_plots.sh +#========================================================================== + +set -eux + +module load intel +module load ncl/6.4.0 + +RES="96" +#RES="384" + +CRES="C${RES}" + +#base_name="atmos_4xdaily" # Base name of the FV3 output file, .tile[n].nc will be appended +#fields='"u1000", "v1000"' # Fields to plot +base_name="nggps2d" # Base name of the FV3 output file, .tile[n].nc will be appended +fields='"PWATclm", "HGTsfc"' # Fields to plot +nlev="50" # Vertical index to plot for 3D fields +fcst_index="1,2" # Time index '2' or indices '1, 2' of forecast to plot or '"all"' +#fcst_index='"all"' # Time index '2' or indices '1, 2' of forecast to plot or '"all"' + +grid_dir="/scratch2/BMC/gmtb/Julie.Schramm/C96fv3gfs2016092900/INPUT" + +#RAP_grid_fn="/scratch2/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/geo_em.d01.nc" +RAP_grid_fn="/scratch2/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/geo_em.d01.RAP.nc" + +if [ 1 = 1 ]; then +# +# Show FV3 global domain (tiles 1-6) on a global cylindrical projection. +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + fields=\(\/"$fields"/\) \ + nlev=${nlev} \ + fcst_index=\(/${fcst_index}/\) \ + res=${RES} \ + tile_inds=\(/1,2,3,4,5,6/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=False \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=False \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + graphics_type=\"png\" +# +# tile_inds=\(/4/\) \ +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a global cylindrical projection. +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + 'fields=(/"u1000", "v1000"/)' \ + nlev=${nlev} \ + fcst_index=${fcst_index} \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + graphics_type=\"png\" +# +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a sphere (orthogonal spherical projection). +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + 'fields=(/"u1000", "v1000"/)' \ + nlev=${nlev} \ + fcst_index=${fcst_index} \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"ortho\" \ + map_proj_ctr=\(/-105,50/\) \ + graphics_type=\"png\" +# +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tiles 5,6,7) and the original RAP domain outline +# on a cylindrical projection. +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + 'fields=(/"u1000", "v1000"/)' \ + nlev=${nlev} \ + fcst_index=${fcst_index} \ + res=${RES} \ + tile_inds=\(/5,6,7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=True \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=True \ + map_proj=\"cyln\" \ + subreg=\(/-47,-40,15,22/\) \ + graphics_type=\"png\" +# +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a global cylindrical projection (no subregion). +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + 'fields=(/"u1000", "v1000"/)' \ + nlev=${nlev} \ + fcst_index=${fcst_index} \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=False \ + draw_tile_grid=False \ + draw_RAP_domain=True \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + graphics_type=\"png\" +# + +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a global cylindrical projection (no subregion). Drawing tile boundary +# and grid makes a black tile 7 over CONUS. +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + 'fields=(/"u1000", "v1000"/)' \ + nlev=${nlev} \ + fcst_index=${fcst_index} \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=True \ + draw_RAP_domain=False \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + graphics_type=\"png\" +# subreg=\(/-47,-40,15,22/\) \ +# tile_inds=\(/1,2,3,4,5,6/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# subreg=\(/-150,-40,0,70/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# + +fi + +if [ 0 = 1 ]; then +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a subregional cylindrical projection centered over CONUS. +# +# Show FV3 regional domain (tile 7) and the original RAP domain outline +# on a subregional cylindrical projection centered over CONUS. +# +ncl -n plot_fields.ncl \ + grid_dir=\"$grid_dir\" \ + base_name=\"$base_name\" \ + fields=\(\/"$fields"/\) \ + nlev=${nlev} \ + fcst_index=\(\/"$fcst_index"/\) \ + res=${RES} \ + tile_inds=\(/7/\) \ + draw_tile_bdy=True \ + draw_tile_grid=False \ + draw_RAP_domain=False \ + RAP_grid_fn=\"$RAP_grid_fn\" \ + draw_RAP_bdy=True \ + draw_RAP_grid=False \ + map_proj=\"cyln\" \ + subreg=\(/-135,-60,10,60/\) \ + graphics_type=\"png\" +# subreg=\(/-47,-40,15,22/\) \ +# tile_inds=\(/1,2,3,4,5,6/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# subreg=\(/-150,-40,0,70/\) \ +# subreg=\(/-120,-70,20,70/\) \ +# + +fi diff --git a/ush/NCL/make_plot_titles.ncl b/ush/NCL/make_plot_titles.ncl new file mode 100644 index 0000000000..2cb3788f2e --- /dev/null +++ b/ush/NCL/make_plot_titles.ncl @@ -0,0 +1,259 @@ +; +; ********************************************************************** +; +; File name: make_plot_titles.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function generates titles for the plot. These consist of the +; following three strings: +; +; left_str: +; This will be placed at the top left of the plot. +; +; main_str: +; This will be placed at the top center corner of the plot. +; +; right_str: +; This will be placed at the top right of the plot. +; +; Note that these strings will in general contain NCL formatting func- +; tion codes. +; +; ********************************************************************** +; + +undef("make_plot_titles") + +function make_plot_titles( \ + inds_tiles_to_plot[*]:integer, \ + nz_by_tile[*]:integer, \ + vert_indx[1]:integer, \ +\ + field_name[1]:string, \ + field_desc[1]:string, \ + field_units[1]:string, \ + func_xyz_only[1]:logical, \ + func_xyzt_only[1]:logical, \ + field_min_by_tile[*]:snumeric, \ + field_max_by_tile[*]:snumeric, \ + tile_bdy_color[1]:string, \ +\ + show_RAP_grid[1]:logical, \ + plot_RAP_field[1]:logical, \ + field_name_RAP[1]:string, \ + field_desc_RAP[1]:string, \ + field_units_RAP[1]:string, \ + RAP_bdy_color[1]:string, \ +\ + nn[1]:integer) + +local inds_tiles_to_plot_str, fmt_str, vert_indx_str, \ + func_code_zoom, \ + left_str, right_str, main_str, \ + num_newlines_FV3LAM, num_newlines_RAP, num_newlines_to_add, \ + line, field_min_str, field_max_str, \ + num_lines, line_lengths, line_length_max, num_pad_spaces_before, \ + add_half_horiz_space, vert_offset_one_line, vert_offsets, \ + vert_offsets_str + +begin +; +; ********************************************************************** +; +; Create strings containing a list of the tiles being plotted and the +; vertical index. +; +; ********************************************************************** +; + inds_tiles_to_plot_str \ + := str_join(tostring(inds_tiles_to_plot), ",") + + fmt_str = "%i" + vert_indx_str = sprinti(fmt_str, vert_indx) +; +; ********************************************************************** +; +; Set the function code that specifies the factor (in percent) by which +; to change the font size. +; +; ********************************************************************** +; +; func_code_zoom = "~Z100Q~" + func_code_zoom = "~Z75Q~" +; +; ********************************************************************** +; +; First, consider the case in which the RAP grid and/or a RAP field is +; displayed in the plot. In this case, the main middle string will be +; blank, the left string will contain the FV3-LAM grid and/or field in- +; formation, and the right string will contain the RAP grid and/or field +; information. +; +; ********************************************************************** +; + if (show_RAP_grid .or. plot_RAP_field) then + + main_str = "" + + left_str \ + := "~F30~FV3-LAM field info:~C~" \ + + "~F29~" + field_desc + " (" + char_dq + field_name + char_dq + ")" \ + + " [" + field_units + "]" + + if (func_xyz_only .or. func_xyzt_only) then + left_str := left_str + ", k = " + vert_indx_str + end if + + left_str \ + := left_str + "~C~" \ + + "Tile(s) shown: " + inds_tiles_to_plot_str + + if (show_tile_bdies) then + left_str = left_str + "~C~" + "Tile boundaries in " + tile_bdy_color + end if + num_newlines_FV3LAM \ + = dimsizes(str_index_of_substr(left_str, "~C~", 0)) + + right_str \ + := "~F30~RAP field info:~C~" \ + + "~F29~" + field_desc_RAP + " (" + char_dq + field_name_RAP + char_dq + ")" \ + + " [" + field_units_RAP + "]" + if (show_RAP_bdy) then + right_str = right_str + "~C~" + "RAP boundary in " + RAP_bdy_color + end if + num_newlines_RAP \ + = dimsizes(str_index_of_substr(right_str, "~C~", 0)) +; +; right_str may have fewer newlines than left_str. In that case, add +; newlines so that they both have the same number (looks better in the +; plot. +; + num_newlines_to_add = num_newlines_FV3LAM - num_newlines_RAP + if (num_newlines_to_add .ge. 1) then + right_str = right_str + repeat_str("~C~ ", num_newlines_to_add) +; For some reason, after the last newline (~C~), the spacing isn't quite +; correct and some extra vertical space is needed. Insert that here. + right_str = right_str + "~V-10~ " + end if +; +; Prepend the function zoom code to adjust the font size. +; + left_str := func_code_zoom + left_str + right_str := func_code_zoom + right_str +; +; ********************************************************************** +; +; Now consider the case in which the RAP grid and/or a RAP field is not +; displayed in the plot. +; +; ********************************************************************** +; + else +; +; Title at top-left of plot. +; + left_str := new(1, "string") + + line := "Tile(s) shown: " + inds_tiles_to_plot_str + left_str := array_append_record(left_str, line, 0) + + if (show_tile_bdies) then + line := "Tile boundaries in " + tile_bdy_color + left_str := array_append_record(left_str, line, 0) + end if + + if (func_xyz_only .or. func_xyzt_only) then + line := "Vert. index: " + vert_indx_str \ + + " [0,...," + (nz_by_tile(nn)-1) + "]" + else + line := "Vert. indx: N/A" + end if + left_str := array_append_record(left_str, line, 0) + + left_str := left_str(1:) + num_lines = dimsizes(left_str) + if (num_lines .gt. 1) then + left_str(0:num_lines-2) = left_str(0:num_lines-2) + "~C~" + left_str := str_concat(left_str) + end if + left_str := "~F29~" + left_str + left_str := func_code_zoom + left_str +; +; Title at top-right of plot. +; + right_str := new(1, "string") + + line := "Units: " + field_units + right_str := array_append_record(right_str, line, 0) + + fmt_str = "%-11.6g" + + field_min_str = sprintf(fmt_str, field_min_by_tile(nn)) + line := "field_min = " + field_min_str + right_str := array_append_record(right_str, line, 0) + + field_max_str = sprintf(fmt_str, field_max_by_tile(nn)) + line := "field_max = " + field_max_str + right_str := array_append_record(right_str, line, 0) + + right_str := right_str(1:) + num_lines = dimsizes(right_str) + if (num_lines .gt. 1) then + right_str(0:num_lines-2) = right_str(0:num_lines-2) + "~C~" + right_str := str_concat(right_str) + end if + right_str := "~F29~" + right_str + right_str := func_code_zoom + right_str +; +; Main title at top-center of plot. +; + main_str := new(1, "string") + + line := field_desc + " (" + char_dq + field_name + char_dq \ + + ") on FV3-LAM grid" + main_str := array_append_record(main_str, line, 0) + + main_str := main_str(1:) + num_lines = dimsizes(main_str) + line_lengths := strlen(main_str) + line_length_max := max(line_lengths) + num_pad_spaces_before := (line_length_max - line_lengths)/2 + add_half_horiz_space := ((line_length_max - line_lengths)%2 .eq. 1) + + do i=0, num_lines-1 + main_str(i) = repeat_str(" ", num_pad_spaces_before(i)) + main_str(i) + end do + + if (num_lines .gt. 1) then + main_str(0:num_lines-2) = main_str(0:num_lines-2) + "~C~" + main_str := where(add_half_horiz_space, "~H10~" + main_str, main_str) + vert_offset_one_line := -7 + vert_offsets := vert_offset_one_line*ispan(1, num_lines-1, 1) + vert_offsets_str := "~V" + tostring(vert_offsets) + "~" + main_str(1:num_lines-1) = vert_offsets_str + main_str(1:num_lines-1) + main_str := str_concat(main_str) + end if + main_str := "~F29~" + main_str + main_str := func_code_zoom + main_str + + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable title_info. +; +; ********************************************************************** +; + title_info := True + + title_info@left_str = left_str + title_info@main_str = main_str + title_info@right_str = right_str + + return(title_info) + +end + + diff --git a/ush/NCL/plot_FV3LAM_field_native.ncl b/ush/NCL/plot_FV3LAM_field_native.ncl new file mode 100644 index 0000000000..11facf61c2 --- /dev/null +++ b/ush/NCL/plot_FV3LAM_field_native.ncl @@ -0,0 +1,1660 @@ +; +; ********************************************************************** +; +; Type "ncl plot_grid.ncl 'help=True'" on the command line to obtain +; help for this script. +; +; ********************************************************************** +; + +; +; ********************************************************************** +; +; Declare global variables before loading files. This has the same ef- +; fect as declaring these variables on the command line. +; +; ********************************************************************** +; + +;help = True + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/FV3SAR_demo_PASPBL_20190725/expt_dirs/test_GSD_HRRR25km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/FV3SAR_demo_PASPBL_20190725/expt_dirs/test_GSD_HRRR13km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/FV3SAR_demo_PASPBL_20190725/expt_dirs/test_GSD_HRRR3km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/FV3SAR_demo_PASPBL_20190725/expt_dirs/test_GSD_HAFSV0.A" + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/regional_001_old001" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/regional_003_works01" +CDATE="2019052000" + +tile_inds := (/ 1, 7, 4 /) +;tile_inds := (/ 1, 4 /) +;tile_inds := (/ 5, 6 /) +;tile_inds := (/ 5, 7 /) +tile_inds := (/ 5, 6, 7 /) +tile_inds := (/ 1, 5, 6, 7 /) +;tile_inds := (/ 5 /) +;tile_inds := (/ 6 /) +tile_inds := (/ 7 /) +;tile_inds := (/ 6, 7 /) + +show_tile_bdies = True +;show_tile_bdies = False + +tile_bdy_color = "blue" + +show_tile_grids = True +show_tile_grids = False + +file_basename = "atmos_static" +;file_basename = "fv3_history" +file_basename = "fv3_history2d" + +file_basename = "phyf000" +file_basename = "C401_oro_data.tile7.halo0.nc" + +; This is a temporary change for plotting ICs. +;file_basename = "sfc_data.tile7" +;file_basename = "gfs_data.tile7" + + +field_name = "cell_area" +field_name = "sqrt_cell_area" +;field_name = "cell_dx" +;field_name = "cell_dy" +;field_name = "cell_dx_ovr_cell_dy" +;field_name = "min_cell_dx_cell_dy" +;field_name = "angle_cell_dx" +;field_name = "angle_cell_dy" + +field_name = "orog_raw" +;field_name = "orog_filt" + +;field_name = "time" +;field_name = "grid_xt" +;field_name = "vflx_ave" +;field_name = "ref3D" + +;field_name = "spfh" +;field_name = "cnwat" +;field_name = "zsurf" +;field_name = "sltyp" +;field_name = "slc" +;field_name = "smc" +;field_name = "stc" +;field_name = "f10m" +;field_name = "canopy" +;field_name = "vtype" +;field_name = "stype" + +;field_name = "rainwat" + +;field_name = "none" +;field_name = "c0" + + +map_proj = "cyln" +map_proj = "ortho" +; +; This should be set to (0,0) for "cyln" map projection. +; +map_proj_ctr = (/ 0.0, 0.0 /) ; This should be set to (0,0) for "cyln" map projection. +;map_proj_ctr = (/ -106.0, 54.0 /) ; RAP domain. +map_proj_ctr = (/ -97.5, 38.5 /) ; HRRR domain. + +;map_proj_ctr = (/ 6.0, 54.0 /) ; RAP domain corner. + +plot_subreg = True +;plot_subreg = False + +;subreg_limits := (/ -180, 180, -90, 90 /) +;subreg_limits := (/ -75, -45, 30, 60 /) + +subreg_limits := (/ -135, -60, 20, 55 /) ; HRRR domain if using "cyln" map projection. +;subreg_limits := (/ -125, -70, 20, 55 /) ; HRRR domain if using "ortho" map projection. +;subreg_limits := (/ -145, -90, 30, 60 /) ; Northwest corner of HRRR domain. +;subreg_limits := (/ -135, -125, 40, 50 /) ; Northwest corner of HRRR domain, zoomed. +;subreg_limits := (/ -123, -121, 48, 50 /) ; Northwest corner of HRRR domain, zoomed more. +;subreg_limits := (/ -120, -115, 30, 35 /) +;subreg_limits := (/ -125, -120, 15, 25 /) ; Southwest corner of HRRR domain. + +;subreg_limits := (/ -15, 0, 0, 15 /) +;subreg_limits := (/ -30, 0, 0, 30 /) +;subreg_limits := (/ -60, -30, 0, 30 /) +;subreg_limits := (/ -75, -60, 0, 15 /) +;subreg_limits := (/ -70, -65, 5, 10 /) +;subreg_limits := (/ -55, -40, 45, 60 /) +;subreg_limits := (/ -50, -45, 50, 55 /) +;subreg_limits := (/ -10, 5, 0, 15 /) +;subreg_limits := (/ -2, 2, 0, 4 /) +;subreg_limits := (/ -90, -60, -20, 10 /) +;subreg_limits := (/ -80, -70, -10, 0 /) +;subreg_limits := (/ -85, -70, -15, 0 /) +;subreg_limits := (/ -76, -72, -12, -8 /) +;subreg_limits := (/ -75, -45, -15, 0 /) +;subreg_limits := (/ -63, -58, -15, -10 /) +;subreg_limits := (/ 15, 30, 30, 45 /) +;subreg_limits := (/ 14, 16, 36, 38 /) +;subreg_limits := (/ -70, -55, -20, -5 /) +;subreg_limits := (/ 10, 20, 30, 40 /) +;subreg_limits := (/ 15, 20, 30, 35 /) + +remove_rgnl_halo = True +;remove_rgnl_halo = False + + + + +show_RAP_bdy = True +show_RAP_bdy = False + +RAP_bdy_color = "red" + +show_RAP_grid = True +show_RAP_grid = False + +plot_RAP_field = True +plot_RAP_field = False + +field_name_RAP = "cell_area" +field_name_RAP = "sqrt_cell_area" +;field_name_RAP = "MAPFAC_M" +;field_name_RAP = "none" + +; This is for HRRR grib2 file. +field_name_RAP = "VGTYP_P0_L1_GLC0" + +;RAP_dir = "/scratch1/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509" +RAP_dir = "/scratch1/BMC/gsd-fv3-dev/Gerard.Ketefian/regional_FV3_EMC_visit_20180509" +;RAP_grid_fn = "/home/Gerard/fv3_regional/fv3sar_workflow/ush/NCL/plot_grid.ncl" +;RAP_grid_fn = "/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/geo_em.d01.RAP.nc" +;RAP_grid_fn = RAP_dir + "/geo_em.d01.RAP.nc" +RAP_grid_fn = RAP_dir + "/geo_em.d01.HRRR.nc" + +horiz_dist_units = "m" +horiz_dist_units = "km" + + + + + +time_inds_to_plot := (/ 0, 2 /) +time_inds_to_plot := (/ 2 /) +time_inds_to_plot := (/ 0 /) + + +fcst_output_hrs := (/ 0, 1, 2, 3, 4, 5, 6 /) ; Read this in from file, e.g. var_defns.sh. +;fcst_output_hrs := (/ 0, 2, 4, 6 /) ; Read this in from file, e.g. var_defns.sh. +fcst_hrs_to_plot = fcst_output_hrs(time_inds_to_plot) +;print("" + time_inds_to_plot) +;print("" + fcst_hrs_to_plot) +;pause + +vert_inds_to_plot := (/ 0, 10 /) +vert_inds_to_plot := (/ 10 /) +vert_inds_to_plot := (/ 8 /) +;vert_inds_to_plot := (/ 0 /) +;vert_inds_to_plot := (/ 0, 1, 2, 3, 4, 5, 6, 7, 8 /) + + + +separator_line \ +:= "************************************************************************" +;:= "========================================================================" + + +; +; ********************************************************************** +; +; Load files. +; +; ********************************************************************** +; +lib_location = "lib/" + +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "repeat_str.ncl") +loadscript(lib_location + "calc_field_stats.ncl") +loadscript(lib_location + "get_rect_grid_bdy.ncl") +loadscript(lib_location + "set_cnLevels_lbLabels.ncl") + +load "process_plot_params.ncl" +load "read_FV3LAM_grid_native.ncl" +load "read_FV3LAM_gridfield_native.ncl" +load "read_FV3LAM_field_native.ncl" +load "read_FV3LAM_grid_wrtcmp.ncl" +load "read_FV3LAM_field_wrtcmp.ncl" +load "read_RAP_grid.ncl" +load "read_RAP_field.ncl" +load "plot_horiz_field.ncl" +load "set_file_field_names.ncl" +load "get_wrtcmp_grid.ncl" +load "calc_wrtcmp_grid_params_lambert_cnfrml.ncl" +load "calc_wrtcmp_grid_params.ncl" +load "make_plot_titles.ncl" + +begin +; +; ********************************************************************** +; +; Set usage message. +; +; ********************************************************************** +; + usage_msg = \ +" ncl -n plot_grid.ncl \" + char_nl + \ +" 'help=False' \" + char_nl + \ +" 'grid_dir=" + char_dq + "./some_dir/grid" + char_dq + "' \" + char_nl + \ +" 'res=96' \" + char_nl + \ +" 'tile_inds=(/1,2,3/)' \" + char_nl + \ +" 'show_tile_bdies=True' \" + char_nl + \ +" 'show_tile_grids=True' \" + char_nl + \ +" 'plot_RAP_field=True' \" + char_nl + \ +" 'RAP_grid_fn=" + char_dq + "./some_dir/RAP_grid.nc" + char_dq + "' \" + char_nl + \ +" 'show_RAP_bdy=True' \" + char_nl + \ +" 'show_RAP_grid=True' \" + char_nl + \ +" 'map_proj=" + char_dq + "cyln" + char_dq + "' \" + char_nl + \ +" 'map_proj_ctr=(/0,90/)' \" + char_nl + \ +" 'subreg_limits=(/-30,30,-25,25/)' \" + char_nl + \ +" 'graphics_type=" + char_dq + "ncgm" + char_dq + "'" +; +; ********************************************************************** +; +; Set help message. The help message contains the documentation for +; this script and thus should reflect any changes to the code. +; +; ********************************************************************** +; + help_msg = char_nl + \ +"This script generates a 2-D color plot of one or more of the tiles on" + char_nl + \ +"a cubed-sphere grid on top of a map of the continents. Each tile is" + char_nl + \ +"depicted in the output graphics file as a uniformly colored region." + char_nl + \ +char_nl + \ +"An example of a call to this script from the command line is as fol-" + char_nl + \ +"lows:" + char_nl + \ +char_nl + \ +usage_msg + \ +char_nl + \ +char_nl + \ +"The output is a graphics file named" + char_nl + \ +char_nl + \ +" C[res]_grid.[ext]" + char_nl + \ +char_nl + \ +"where res is the specified resolution and ext is the graphics file ex-" + char_nl + \ +"tension (determined by the specified output graphics type graphics_-" + char_nl + \ +"type). The input arguments to this script are:" + char_nl + \ +char_nl + \ +"help:" + char_nl + \ +"This argument specifies whether or not to print out the documentation" + char_nl + \ +"for this script and exit. It is either True or False. Default is" + char_nl + \ +"False. If this is set to True, this script prints out the documenta-" + char_nl + \ +"tion and exits, ignoring all other arguments. To see the documenta-" + char_nl + \ +"tion, type " + char_dq + "ncl plot_grid.ncl 'help=True'" + char_dq + " on the command line in the" + char_nl + \ +"directory of this script." + char_nl + \ +char_nl + \ +"grid_dir:" + char_nl + \ +"This argument specifies the directory in which the grid files are lo-" + char_nl + \ +"cated. It is assumed that these are NetCDF files with names of the" + char_nl + \ +"form" + char_nl + \ +char_nl + \ +" C[res]_grid.tile[N].nc" + char_nl + \ +char_nl + \ +"where res is the resolution specified on the command line and N is the" + char_nl + \ +"tile number. The tile numbers to consider are specified by the input" + char_nl + \ +"argument tile_inds (see below). Default value is the current directo-" + char_nl + \ +"ry, i.e. " + char_dq + "./" + char_dq + "." + char_nl + \ +char_nl + \ +"res:" + char_nl + \ +"This argument specifies the cubed-sphere resolution, i.e. the number" + char_nl + \ +"of cells in each of the two horizontal directions on each of the 6" + char_nl + \ +"tiles of the global cubed-sphere grid. Valid values are: 48, 96, 192," + char_nl + \ +"384, 768, 1152, and 3072." + char_nl + \ +char_nl + \ +"tile_inds:" + char_nl + \ +"This argument specifies the indices of those tiles on the cubed-sphere" + char_nl + \ +"grid that are to be plotted. For example, to plot tiles 1, 3, and 5, " + char_nl + \ +"specify" + char_nl + \ +char_nl + \ +" tile_inds = (/ 1, 3, 5 /)" + char_nl + \ +char_nl + \ +"If this is not specified, all available tiles are plotted (where by " + char_nl + \ +char_dq + "available" + char_dq + ", we mean all tiles for which there exists a grid file in" + char_nl + \ +"grid_dir)." + char_nl + \ +char_nl + \ +"show_tile_bdies:" + char_nl + \ +"This argument specifies whether or not to draw the boundary of each " + char_nl + \ +"specified tile. It is either True or False. Default is True." + char_nl + \ +char_nl + \ +"show_tile_grids:" + char_nl + \ +"This argument specifies whether or not to draw the boundaries of all" + char_nl + \ +"grid cells on each tile that is being plotted. It is either True or " + char_nl + \ +"False. Default is False. For a high-resolution grid, this can make" + char_nl + \ +"it difficult to see the underlying color of the tile in the output" + char_nl + \ +"graphics file (because there would be many grid lines drawn very close" + char_nl + \ +"together)." + char_nl + \ +char_nl + \ +"plot_RAP_field:" + char_nl + \ +"This argument specifies whether or not to draw the original [i.e. pre-" + char_nl + \ +"FV3 RAP (RAPid Refresh) domain]. It is either True or False. Default" + char_nl + \ +"is False. If this is set to True, the RAP domain is added to the plot" + char_nl + \ +"as a uniformly colored region (with a color that is different from any" + char_nl + \ +"of the cubed-sphere tiles)." + char_nl + \ +char_nl + \ +"RAP_grid_fn:" + char_nl + \ +"This argument specifies the full (i.e. including directory) file name" + char_nl + \ +"of the NetCDF file that describes the RAP grid. This is used only if" + char_nl + \ +"plot_RAP_field is set to True." + char_nl + \ +"" + char_nl + \ +"show_RAP_bdy:" + char_nl + \ +"This argument specifies whether or not to draw the boundary of the RAP" + char_nl + \ +"domain. It is either True or False. Default is True. This has no" + char_nl + \ +"effect if plot_RAP_field is set to False." + char_nl + \ +char_nl + \ +"show_RAP_grid:" + char_nl + \ +"This argument specifies whether or not to draw the boundaries of all" + char_nl + \ +"grid cells on the RAP domain. It is either True or False. Default is" + char_nl + \ +"False. For a high-resolution RAP grid, setting this to True can make" + char_nl + \ +"it difficult to see the underlying color of the RAP domain in the out-" + char_nl + \ +"put graphics file (because there would be many grid lines drawn very" + char_nl + \ +"close together. This has no effect if plot_RAP_field is set to" + char_nl + \ +"False." + char_nl + \ +char_nl + \ +"map_proj:" + char_nl + \ +"This argument specifies the map projection to use for the plot. Valid" + char_nl + \ +"values are:" + char_nl + \ +char_nl + \ +" " + char_dq + "cyln" + char_dq + " - for cylindrical-equidistant projection" + char_nl + \ +" " + char_dq + "ortho" + char_dq + " - for orthographic (i.e. on a sphere) projection" + char_nl + \ +;" " + char_dq + "lamb" + char_dq + " - for Lambert equal-area projection" + char_nl + \ +" " + char_dq + "lamb" + char_dq + " - for Lambert conformal projection" + char_nl + \ +char_nl + \ +"If this argument is omitted, a cylindrical-equidistant projection is" + char_nl + \ +"used. " + char_nl + \ +char_nl + \ +"map_proj_ctr:" + char_nl + \ +"This argument specifies the point on the sphere at which to center the" + char_nl + \ +"map projection used for the plot. It consists of the point's longi-" + char_nl + \ +"tude and latitude (in degrees), as follows:" + char_nl + \ +char_nl + \ +" map_proj_ctr = (/ 30, 40 /)" + char_nl + \ +char_nl + \ +"If this is not specified, it is set to (/0,0/) for the cylindrical-" + char_nl + \ +"equidistant and orthographic (i.e. on a sphere) projections and to" + char_nl + \ +"(/0,90/) (i.e. the North Pole) for the Lambert equal-area projection." + char_nl + \ +char_nl + \ +"subreg_limits:" + char_nl + \ +"If using a cylindrical-equidistant map projection, this argument spe-" + char_nl + \ +"cifies the minimum and maximum longitudes and latitudes (in degrees)" + char_nl + \ +"of the subregion to plot. It has the format" + char_nl + \ +char_nl + \ +" subreg_limits = (/ lon_min, lon_max, lat_min, lat_max /)" + char_nl + \ +char_nl + \ +"where lon_min and lon_max are the minimum and maximum values of the" + char_nl + \ +"longitude and lat_min and lat_max are the minimum and maximum values" + char_nl + \ +"of the latitude. If this argument is omitted, the field is plotted on" + char_nl + \ +"the whole globe. It is ignored for projections other than cylindri-" + char_nl + \ +"cal-equidistant." + char_nl + \ +char_nl + \ +"graphics_type:" + char_nl + \ +"This argument specifies the type of graphics file to generate as out-" + char_nl + \ +"put. It can be either " + char_dq + "ncgm" + char_dq + " (NCAR Graphics) or " + char_dq + "png" + char_dq + ". Default is" + char_nl + \ +char_dq + "ncgm" + char_dq + "." + char_nl +; +; ********************************************************************** +; +; Playing around with reading in HRRR grib2 files. +; +; ********************************************************************** +; +;if (True) then +if (False) then + + fn := "1916021000000" + fp := addfile(fn + ".grb2", "r") + +RAP_fn := fn + + var_names := getfilevarnames(fp) + num_vars := dimsizes(var_names) +print("") +print("num_vars = " + num_vars) + var_types := getfilevartypes(fp, var_names) +; var_dim_sizes := getfilevardimsizes(fp) + + do i=0, num_vars-1 + + var_name := var_names(i) + + var_dim_names := getfilevardims(fp, var_name) + var_dim_names_str := tostring(var_dim_names) + var_dim_names_str := str_join(var_dim_names_str, ", ") + var_dim_names_str := "(" + var_dim_names_str + ")" + + var_dim_sizes := getfilevardimsizes(fp, var_name) + var_dim_sizes_str := tostring(var_dim_sizes) + var_dim_sizes_str := str_join(var_dim_sizes_str, ", ") + var_dim_sizes_str := "(" + var_dim_sizes_str + ")" + + var_info \ + := char_dq + var_name + char_dq + "; " \ + + var_types(i) + "; " \ + + var_dim_names_str + " = " \ + + var_dim_sizes_str + + print("") + print("var_info = " + var_info) + + end do + + tmp := fp->$field_name_RAP$ + tmp_min := min(tmp) + tmp_max := max(tmp) +print("") +print("tmp_min = " + tmp_min) +print("tmp_max = " + tmp_max) +pause + +;exit + +end if +; +; ********************************************************************** +; +; Process the global variables (e.g. set on the command line). +; +; ********************************************************************** +; + plot_params := process_plot_params("plot_grid", usage_msg, help_msg) + + gtype = plot_params@gtype + num_tiles_to_plot = plot_params@num_tiles_to_plot + inds_tiles_to_plot = plot_params@inds_tiles_to_plot + cres = plot_params@cres + expt_dir = plot_params@expt_dir + + horiz_dist_units = plot_params@horiz_dist_units + horiz_area_units = plot_params@horiz_area_units + + show_tile_bdies = plot_params@show_tile_bdies + tile_bdy_color = plot_params@tile_bdy_color + show_tile_grids = plot_params@show_tile_grids + field_name = plot_params@field_name + is_gridfield = plot_params@is_gridfield + file_basename = plot_params@file_basename + + show_RAP_bdy = plot_params@show_RAP_bdy + RAP_bdy_color = plot_params@RAP_bdy_color + show_RAP_grid = plot_params@show_RAP_grid + plot_RAP_field = plot_params@plot_RAP_field + field_name_RAP = plot_params@field_name_RAP + + graphics_type = plot_params@graphics_type + map_proj = plot_params@map_proj + map_proj_ctr = plot_params@map_proj_ctr + + remove_rgnl_halo = plot_params@remove_rgnl_halo + + plot_subreg = plot_params@plot_subreg + subreg_limits = plot_params@subreg_limits +; +; ********************************************************************** +; +; Get/construct the write-component grid. +; +; ********************************************************************** +; + +; These should be at the top and go through the process_...() function. + +; show_wrtcmp_grid = True + show_wrtcmp_grid = False + + show_wrtcmp_bdy = True + show_wrtcmp_bdy = False + + wrtcmp_bdy_color = "green" + + +; rd := "/scratch3/BMC/det/Gerard.Ketefian/UFS_CAM_test_instructions/expt_dirs/NX1800_NY1120_A0p21423_Kmns0p23209_HRRR_test_cycl_slurm_01/2017090700" +; rd := "/scratch3/BMC/det/Gerard.Ketefian" +; rd := run_dir + "/2019052000" + rd := expt_dir + "/" + CDATE + "00" + + wrtcmp_config_fn := rd + "/model_configure" +; wrtcmp_config_tmpl_fn = wrtcmp_config_fn + ".tmpl" +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; +;if (False) then + if (show_wrtcmp_grid .or. show_wrtcmp_bdy) then +print("") +print("wrtcmp_config_fn = " + char_dq + wrtcmp_config_fn + char_dq) +pause + grid_info := get_wrtcmp_grid(wrtcmp_config_fn, show_wrtcmp_bdy) + + nx_wrtcmp = grid_info@nx + ny_wrtcmp = grid_info@ny + lon_cntrs_unstruc_wrtcmp = grid_info@lon_cntrs_unstruc + lat_cntrs_unstruc_wrtcmp = grid_info@lat_cntrs_unstruc + lon_verts_unstruc_wrtcmp = grid_info@lon_verts_unstruc + lat_verts_unstruc_wrtcmp = grid_info@lat_verts_unstruc + lon_bdy_wrtcmp = grid_info@lon_bdy + lat_bdy_wrtcmp = grid_info@lat_bdy + lon_grid_cntr_wrtcmp = grid_info@lon_grid_cntr + lat_grid_cntr_wrtcmp = grid_info@lat_grid_cntr + coord_data_type_wrtcmp = grid_info@coord_data_type + + print("") + print("lon_grid_cntr_wrtcmp = " + lon_grid_cntr_wrtcmp + " deg") + print("lat_grid_cntr_wrtcmp = " + lat_grid_cntr_wrtcmp + " deg") +pause + +;lon_ctr_native = lon_grid_cntr_wrtcmp +;lat_ctr_native = lat_grid_cntr_wrtcmp +; +; out := calc_wrtcmp_grid_params( \ +; wrtcmp_config_fn, \ +; lon_ctr_native, lat_ctr_native, \ +; lon_tile_corners_face_midpts_native, \ +; lat_tile_corners_face_midpts_native, \ +; dx_native, dy_native, \ +; angle_units) +; +;print("") +;print("out = " + out) +;pause + + end if +;end if +; +; ********************************************************************** +; +; Read in the FV3-LAM grid. +; +; ********************************************************************** +; + nhalo_T7 = 4 ; Should this be at the top, i.e. defined as a global variable???? + ; or be a requird input that gets processed along with the other + ; command linea arguments? + +; If the following variable is permanently going to be part of this +; script, then the name of the script should be changed to NOT include +; "native", since then it will have the flexibility to plot fields on +; either the native or the wrtcmp grid. + +; read_FV3LAM_wrtcmp = True + read_FV3LAM_wrtcmp = False + + if (read_FV3LAM_wrtcmp) then + + FV3LAM_wrtcmp_fn = expt_dir + "/" + CDATE + "/" + "dynf000.nc" + get_domain_bdy = True + grid_info := read_FV3LAM_grid_wrtcmp( \ + FV3LAM_wrtcmp_fn, \ + get_domain_bdy) + + fp_wrtcmp = grid_info@fp + nx = grid_info@nx + ny = grid_info@ny + lon_cntrs_unstruc = grid_info@lon_cntrs_unstruc + lat_cntrs_unstruc = grid_info@lat_cntrs_unstruc + lon_verts_unstruc = grid_info@lon_verts_unstruc + lat_verts_unstruc = grid_info@lat_verts_unstruc + lon_bdy = grid_info@lon_bdy + lat_bdy = grid_info@lat_bdy + coord_data_type_FV3LAM = grid_info@coord_data_type + + else + + grid_info := read_FV3LAM_grid_native( \ + expt_dir, \ + gtype, \ + cres, \ + inds_tiles_to_plot, \ + show_tile_bdies, \ + nhalo_T7, \ + remove_rgnl_halo) + + grid_fn_tiles_to_plot = grid_info@grid_fn_all_tiles + + nhSG_tiles_to_plot = grid_info@nhSG_all_tiles + nxhSG_tiles_to_plot = grid_info@nxhSG_all_tiles + nyhSG_tiles_to_plot = grid_info@nyhSG_all_tiles + nxSG_tiles_to_plot = grid_info@nxSG_all_tiles + nySG_tiles_to_plot = grid_info@nySG_all_tiles + + nh_tiles_to_plot = grid_info@nh_all_tiles + nxh_tiles_to_plot = grid_info@nxh_all_tiles + nyh_tiles_to_plot = grid_info@nyh_all_tiles + nx_tiles_to_plot = grid_info@nx_all_tiles + ny_tiles_to_plot = grid_info@ny_all_tiles + + remove_halo_tiles_to_plot = grid_info@remove_halo_all_tiles + + lon_cntrs_unstruc = grid_info@lon_cntrs_all_tiles_unstruc + lat_cntrs_unstruc = grid_info@lat_cntrs_all_tiles_unstruc + lon_verts_unstruc = grid_info@lon_verts_all_tiles_unstruc + lat_verts_unstruc = grid_info@lat_verts_all_tiles_unstruc + + lon_bdy = grid_info@lon_bdy_all_tiles + lat_bdy = grid_info@lat_bdy_all_tiles + + lon_tile_cntr_tiles_to_plot = grid_info@lon_tile_cntr_all_tiles + lat_tile_cntr_tiles_to_plot = grid_info@lat_tile_cntr_all_tiles + + lon_tile_corners_face_midpts_tiles_to_plot \ + = grid_info@lon_tile_corners_face_midpts_all_tiles + lat_tile_corners_face_midpts_tiles_to_plot \ + = grid_info@lat_tile_corners_face_midpts_all_tiles + + coord_data_type_FV3LAM = grid_info@coord_data_type + + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + lon_bdy_all_bdies := new(1, coord_data_type_FV3LAM) + lat_bdy_all_bdies := new(1, coord_data_type_FV3LAM) +; +; ********************************************************************** +; +; If show_RAP_bdy, show_RAP_grid, or plot_RAP_field is set to True, read +; in the coordinates of the RAP grid. +; +; ********************************************************************** +; + if (show_RAP_bdy .or. show_RAP_grid .or. plot_RAP_field) then +; +; ********************************************************************** +; +; Read in the RAP grid from file. +; +; ********************************************************************** +; + grid_info := read_RAP_grid(RAP_grid_fn, show_RAP_bdy) + + fp_RAP_grid = grid_info@fp + nx_RAP = grid_info@nx + ny_RAP = grid_info@ny + lon_cntrs_unstruc_RAP = grid_info@lon_cntrs_unstruc + lat_cntrs_unstruc_RAP = grid_info@lat_cntrs_unstruc + lon_verts_unstruc_RAP = grid_info@lon_verts_unstruc + lat_verts_unstruc_RAP = grid_info@lat_verts_unstruc + lon_bdy_RAP = grid_info@lon_bdy + lat_bdy_RAP = grid_info@lat_bdy + lon_grid_cntr_RAP = grid_info@lon_grid_cntr + lat_grid_cntr_RAP = grid_info@lat_grid_cntr + coord_data_type_RAP = grid_info@coord_data_type + + print("") + print("lon_grid_cntr_RAP = " + lon_grid_cntr_RAP + " deg") + print("lat_grid_cntr_RAP = " + lat_grid_cntr_RAP + " deg") + + end if +;; +;; ********************************************************************** +;; +;; Get/construct the write-component grid. +;; +;; ********************************************************************** +;; +; +;; These should be at the top and go through the process_...() function. +; +;; show_wrtcmp_grid = True +; show_wrtcmp_grid = False +; +; show_wrtcmp_bdy = True +;; show_wrtcmp_bdy = False +; +; wrtcmp_bdy_color = "green" +; +; +;; rd := "/scratch3/BMC/det/Gerard.Ketefian/UFS_CAM_test_instructions/expt_dirs/NX1800_NY1120_A0p21423_Kmns0p23209_HRRR_test_cycl_slurm_01/2017090700" +; rd := "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM" +; +; wrtcmp_config_fn := rd + "/model_configure" +; wrtcmp_config_tmpl_fn = wrtcmp_config_fn + ".tmpl" +;; +;; ********************************************************************** +;; +;; +;; +;; ********************************************************************** +;; +; if (show_wrtcmp_grid .or. show_wrtcmp_bdy) then +; +; grid_info := get_wrtcmp_grid(wrtcmp_config_fn, show_wrtcmp_bdy) +; +; nx_wrtcmp = grid_info@nx +; ny_wrtcmp = grid_info@ny +; lon_cntrs_unstruc_wrtcmp = grid_info@lon_cntrs_unstruc +; lat_cntrs_unstruc_wrtcmp = grid_info@lat_cntrs_unstruc +; lon_verts_unstruc_wrtcmp = grid_info@lon_verts_unstruc +; lat_verts_unstruc_wrtcmp = grid_info@lat_verts_unstruc +; lon_bdy_wrtcmp = grid_info@lon_bdy +; lat_bdy_wrtcmp = grid_info@lat_bdy +; lon_grid_cntr_wrtcmp = grid_info@lon_grid_cntr +; lat_grid_cntr_wrtcmp = grid_info@lat_grid_cntr +; coord_data_type_wrtcmp = grid_info@coord_data_type +; +; print("") +; print("lon_grid_cntr_wrtcmp = " + lon_grid_cntr_wrtcmp + " deg") +; print("lat_grid_cntr_wrtcmp = " + lat_grid_cntr_wrtcmp + " deg") +;pause +; +; end if +; +; ********************************************************************** +; +; Initialize the unstructured coordinate arrays that will contain infor- +; mation for all grids (i.e. all tiles on the FV3 cubed-sphere grid that +; are to be plotted and possibly the RAP grid) to the corresponding ar- +; rays for the FV3 grid (i.e. all tiles to be plotted). These arrays +; will be passed to the plotting function(s) to generate plots. +; +; ********************************************************************** +; + lon_cntrs_unstruc_all_grids := lon_cntrs_unstruc + lat_cntrs_unstruc_all_grids := lat_cntrs_unstruc + lon_verts_unstruc_all_grids := lon_verts_unstruc + lat_verts_unstruc_all_grids := lat_verts_unstruc + + num_bdies_to_plot = 0 + if (show_tile_bdies) then + + num_bdies_to_plot = num_bdies_to_plot + num_tiles_to_plot + + lon_bdy_all_bdies \ + := array_append_record(lon_bdy_all_bdies, lon_bdy, 0) + lat_bdy_all_bdies \ + := array_append_record(lat_bdy_all_bdies, lat_bdy, 0) + + end if +; +; ********************************************************************** +; +; If the plots will show the RAP grid and/or a field on the RAP grid, +; then prepend the RAP coordinate arrays to the coordinate arrays that +; will contain coordinate information for all grids. +; +; ********************************************************************** +; + if (show_RAP_grid .or. plot_RAP_field) then +; +; ********************************************************************** +; +; If the RAP coordinate arrays are not of the same data type as the FV3- +; LAM coordinate arrays, convert the data type of the former to that of +; the latter. +; +; ********************************************************************** +; + if (.not. strcmp_exact(coord_data_type_FV3LAM, coord_data_type_RAP)) then + + lon_cntrs_unstruc_RAP \ + := totype(lon_cntrs_unstruc_RAP, coord_data_type_FV3LAM) + + lat_cntrs_unstruc_RAP \ + := totype(lat_cntrs_unstruc_RAP, coord_data_type_FV3LAM) + + lon_verts_unstruc_RAP \ + := totype(lon_verts_unstruc_RAP, coord_data_type_FV3LAM) + + lat_verts_unstruc_RAP \ + := totype(lat_verts_unstruc_RAP, coord_data_type_FV3LAM) + + end if +; +; ********************************************************************** +; +; Prepend RAP coordinates to the corresponding arrays for the FV3LAM. +; This is done for plotting convenience. Note that the RAP coordinates +; are prepended insted of appended so that the RAP grid (and any field +; associated with it) is drawn first and the FV3LAM tiles (and any +; fields on them) are then drawn on top. +; +; ********************************************************************** +; + lon_cntrs_unstruc_all_grids \ + := array_append_record( \ + lon_cntrs_unstruc_RAP, lon_cntrs_unstruc_all_grids, 0) + + lat_cntrs_unstruc_all_grids \ + := array_append_record( \ + lat_cntrs_unstruc_RAP, lat_cntrs_unstruc_all_grids, 0) + + lon_verts_unstruc_all_grids \ + := array_append_record( \ + lon_verts_unstruc_RAP, lon_verts_unstruc_all_grids, 0) + + lat_verts_unstruc_all_grids \ + := array_append_record( \ + lat_verts_unstruc_RAP, lat_verts_unstruc_all_grids, 0) + + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + if (show_wrtcmp_grid) then +; +; ********************************************************************** +; +; If the write-component coordinate arrays are not of the same data type +; as the FV3LAM coordinate arrays, convert the data type of the former +; to that of the latter. +; +; ********************************************************************** +; + if (.not. strcmp_exact(coord_data_type_FV3LAM, coord_data_type_wrtcmp)) then + + lon_cntrs_unstruc_wrtcmp \ + := totype(lon_cntrs_unstruc_wrtcmp, coord_data_type_FV3LAM) + + lat_cntrs_unstruc_wrtcmp \ + := totype(lat_cntrs_unstruc_wrtcmp, coord_data_type_FV3LAM) + + lon_verts_unstruc_wrtcmp \ + := totype(lon_verts_unstruc_wrtcmp, coord_data_type_FV3LAM) + + lat_verts_unstruc_wrtcmp \ + := totype(lat_verts_unstruc_wrtcmp, coord_data_type_FV3LAM) + + end if +; +; ********************************************************************** +; +; Prepend write-component coordinates to the corresponding arrays for the FV3LAM. +; This is done for plotting convenience. Note that the write-component coordinates +; are prepended insted of appended so that the write-component grid (and any field +; associated with it) is drawn first and the FV3LAM tiles (and any +; fields on them) are then drawn on top. +; +; ********************************************************************** +; + lon_cntrs_unstruc_all_grids \ + := array_append_record( \ + lon_cntrs_unstruc_wrtcmp, lon_cntrs_unstruc_all_grids, 0) + + lat_cntrs_unstruc_all_grids \ + := array_append_record( \ + lat_cntrs_unstruc_wrtcmp, lat_cntrs_unstruc_all_grids, 0) + + lon_verts_unstruc_all_grids \ + := array_append_record( \ + lon_verts_unstruc_wrtcmp, lon_verts_unstruc_all_grids, 0) + + lat_verts_unstruc_all_grids \ + := array_append_record( \ + lat_verts_unstruc_wrtcmp, lat_verts_unstruc_all_grids, 0) + + end if +; +; ********************************************************************** +; +; If the plots will show the RAP domain's boundary, then prepend the RAP +; boundary coordinate arrays to the boundary coordinate arrays that will +; contain coordinate information for all grids. +; +; ********************************************************************** +; + if (show_RAP_bdy) then + + num_bdies_to_plot = num_bdies_to_plot + 1 + + if (.not. strcmp_exact(coord_data_type_FV3LAM, coord_data_type_RAP)) then + lon_bdy_RAP := totype(lon_bdy_RAP, coord_data_type_FV3LAM) + lat_bdy_RAP := totype(lat_bdy_RAP, coord_data_type_FV3LAM) + end if + + lon_bdy_all_bdies \ + := array_append_record(lon_bdy_all_bdies, lon_bdy_RAP, 0) + lat_bdy_all_bdies \ + := array_append_record(lat_bdy_all_bdies, lat_bdy_RAP, 0) + + end if +; +; ********************************************************************** +; +; If the plots will show the write-component domain's boundary, then +; prepend the _write-component boundary coordinate arrays to the bounda- +; ry coordinate arrays that will contain coordinate information for all +; grids. +; +; ********************************************************************** +; + if (show_wrtcmp_bdy) then + + num_bdies_to_plot = num_bdies_to_plot + 1 + + if (.not. strcmp_exact(coord_data_type_FV3LAM, coord_data_type_wrtcmp)) then + lon_bdy_wrtcmp := totype(lon_bdy_wrtcmp, coord_data_type_FV3LAM) + lat_bdy_wrtcmp := totype(lat_bdy_wrtcmp, coord_data_type_FV3LAM) + end if + + lon_bdy_all_bdies \ + := array_append_record(lon_bdy_all_bdies, lon_bdy_wrtcmp, 0) + lat_bdy_all_bdies \ + := array_append_record(lat_bdy_all_bdies, lat_bdy_wrtcmp, 0) + + end if +; +; ********************************************************************** +; +; Remove the first elements of lon_bdy_all_bdies and lat_bdy_all_bdies +; (since they are dummy values). +; +; ********************************************************************** +; + num_bdy_pts := dimsizes(lon_bdy_all_bdies) + if (num_bdy_pts .gt. 1) then + lon_bdy_all_bdies := lon_bdy_all_bdies(1:) + lat_bdy_all_bdies := lat_bdy_all_bdies(1:) + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + file_field_info \ + := set_file_field_names( \ + gtype, \ + inds_tiles_to_plot, \ + field_name, \ + is_gridfield, \ +\ + remove_halo_tiles_to_plot, \ +\ + grid_fn_tiles_to_plot, \ + nxhSG_tiles_to_plot, \ + nyhSG_tiles_to_plot, \ + nxSG_tiles_to_plot, \ + nySG_tiles_to_plot, \ +\ + run_dir, \ + file_basename, \ + nxh_tiles_to_plot, \ + nyh_tiles_to_plot, \ + nx_tiles_to_plot, \ + ny_tiles_to_plot, \ +\ + vert_inds_to_plot, \ + time_inds_to_plot, \ +\ + horiz_dist_units, \ + horiz_area_units) + + file_names_by_tile := file_field_info@file_names_by_tile +;file_names_by_tile := expt_dir + "/fix_sar/C401_oro_data.tile7.halo0.nc" +file_names_by_tile := expt_dir + "/fix_lam/C401_oro_data.tile7.halo0.nc" + field_names_by_tile := file_field_info@field_names_by_tile + func_xy_only := file_field_info@func_xy_only + func_xyz_only := file_field_info@func_xyz_only + func_xyt_only := file_field_info@func_xyt_only + func_xyzt_only := file_field_info@func_xyzt_only + average_in_x := file_field_info@average_in_x + average_in_y := file_field_info@average_in_y +; +; ********************************************************************** +; +; Loop through all specified forecast hours and vertical indices and ge- +; nerate plots. +; +; ********************************************************************** +; + num_fcst_hrs = dimsizes(fcst_hrs_to_plot) + num_vert_inds = dimsizes(vert_inds_to_plot) + + do n=0, num_fcst_hrs-1 + do k=0, num_vert_inds-1 + + print("") + print("") + print("" + separator_line) + print("" + separator_line) + print("n = " + n + "; k = " + k) + print("" + separator_line) + print("" + separator_line) + + vert_indx = vert_inds_to_plot(k) + time_indx = time_inds_to_plot(n) + fcst_hr = fcst_hrs_to_plot(n) +; +; ********************************************************************** +; +; Read in the FV3LAM field for the current forecast hour and vertical +; index. +; +; ********************************************************************** +; + if (is_gridfield) then + + field_info \ + := read_FV3LAM_gridfield_native( \ + field_names_by_tile, \ + file_names_by_tile, \ + gtype, inds_tiles_to_plot, \ + nh_tiles_to_plot, \ + nxh_tiles_to_plot, nyh_tiles_to_plot, \ + nx_tiles_to_plot, ny_tiles_to_plot, \ + remove_halo_tiles_to_plot, \ + vert_indx, time_indx, \ + horiz_dist_units, horiz_area_units \ + ) + + else +print("") +print("XXXXXXXXXXX") + + field_info \ + := read_FV3LAM_field_native( \ + field_names_by_tile, \ + file_names_by_tile, \ + gtype, inds_tiles_to_plot, \ + nh_tiles_to_plot, \ + nxh_tiles_to_plot, nyh_tiles_to_plot, \ + nx_tiles_to_plot, ny_tiles_to_plot, \ + remove_halo_tiles_to_plot, \ + vert_indx, time_indx, \ + func_xy_only, func_xyz_only, func_xyt_only, func_xyzt_only, \ + average_in_x, average_in_y) + + end if + +; fp_field_FV3LAM = field_info@fp ; This would in general be an array or list of file pointers. + field_desc := field_info@field_desc + field_units := field_info@field_units + nz_by_tile := field_info@nz_by_tile + nt_by_tile := field_info@nt_by_tile + field_unstruc := field_info@field_by_tile_unstruc + field_min_tiles_to_plot := field_info@field_min_by_tile + field_max_tiles_to_plot := field_info@field_max_by_tile + field_median_tiles_to_plot := field_info@field_median_by_tile + field_mean_tiles_to_plot := field_info@field_mean_by_tile + field_data_type_FV3LAM := field_info@field_data_type +; Not sure why setting field_name to "none" doesn't do this, but do this +; here temporarily to make the field transparent. +;field_unstruc = default_fillvalue(field_data_type_FV3LAM) +; +; ********************************************************************** +; +; Calculate and print out basic statistics of the field over all tiles +; to be plotted. +; +; ********************************************************************** +; + inds_tiles_to_plot_str \ + := str_join(tostring(inds_tiles_to_plot), ", ") + inds_tiles_to_plot_str \ + := str_concat( (/"[tile(s) ", inds_tiles_to_plot_str, "]"/) ) + + msg := \ +"Calculating statistics of field over all FV3 tiles to be plotted " + char_nl + \ +inds_tiles_to_plot_str + " ..." + + print("") + print("" + separator_line) + print("" + msg) + + print_field_stats = False + field_stat_info \ + := calc_field_stats( \ + field_unstruc, field_desc, field_units, print_field_stats) + msg := " " + field_stat_info@msg + print("") + print("" + msg) + + msg := \ +"Done calculating statistics of field over all FV3 tiles to be plotted." + print("") + print("" + msg) + print("" + separator_line) +; +; ********************************************************************** +; +; Save field statistics in appropriate variables. +; +; ********************************************************************** +; + field_min := field_stat_info@field_min + field_max := field_stat_info@field_max + field_median := field_stat_info@field_median + field_mean := field_stat_info@field_mean +; +; ********************************************************************** +; +; Initialize the 1-D unstructured array that will contain the field val- +; ues on all grids (FV3LAM and possibly also RAP) and initialize it to +; the field values on the FV3LAM tile grids. +; +; ********************************************************************** +; + field_unstruc_all_grids := field_unstruc +print("AAAAAAA dimsizes(field_unstruc_all_grids) = " + dimsizes(field_unstruc_all_grids)) +; +; ********************************************************************** +; +; If show_RAP_grid or plot_RAP_field is set to True, read in the speci- +; fied field on the RAP grid. Note that if show_RAP_grid is True but +; plot_RAP_field is False, the field retruned on the RAP grid will con- +; sist of missing values, i.e. the plot will not show a field on the RAP +; domain; it will only show the RAP grid (gridlines). This occurs be- +; cause in this case, during the processing of the variables defined on +; the command line, the original setting (if any) of field_name_RAP is +; ignored, and field_name_RAP is (re)set to "none", causing the read_- +; RAP_field(...) function below to return a field of missing values in +; the field_unstruc attribute of the return variable. +; +; ********************************************************************** +; +field_name_RAP = "AAAA" +field_desc_RAP = "BBBB" +field_units_RAP = "CCCC" + + if (show_RAP_grid .or. plot_RAP_field) then +; +; ********************************************************************** +; +; Read in the specified field on the RAP domain. +; +; ********************************************************************** +; + field_info := read_RAP_field( \ + field_name_RAP, \ + horiz_dist_units, \ + horiz_area_units, \ + RAP_fn, \ + nx_RAP, \ + ny_RAP) + +; fp_field_RAP = field_info@fp + field_desc_RAP := field_info@field_desc + field_units_RAP := field_info@field_units + field_unstruc_RAP := field_info@field_unstruc + field_min_RAP := field_info@field_min + field_max_RAP := field_info@field_max + field_median_RAP := field_info@field_median + field_mean_RAP := field_info@field_mean + field_data_type_RAP := field_info@field_data_type +; +; ********************************************************************** +; +; For plotting convenience, we will combine the fields on the FV3LAM andi +; RAP grids into a single array. For this purpose, if necessary we +; first convert the data type of the RAP field to that of the FV3LAM +; field. +; +; ********************************************************************** +; + if (.not. strcmp_exact(field_data_type_FV3LAM, field_data_type_RAP)) then + field_unstruc_RAP \ + := totype(field_unstruc_RAP, field_data_type_FV3LAM) + end if +; +; ********************************************************************** +; +; For plotting convenience, prepend the RAP field to the array contain- +; ing the FV3LAM field. We prepend instead of append so that the RAP +; field is drawn first and the FV3LAM field on the tiles are then drawn +; on top. +; +; ********************************************************************** +; + field_unstruc_all_grids \ + := array_append_record( \ + field_unstruc_RAP, field_unstruc_all_grids, 0) +print("") +print("BBBBBB dimsizes(field_unstruc_all_grids) = " + dimsizes(field_unstruc_all_grids)) + + end if +; +; ********************************************************************** +; +; Calculate and print out basic statistics of the field, now including +; the RAP field. +; +; ********************************************************************** +; + msg := \ +"Calculating statistics of combined field on all grids ..." + print("") + print("" + separator_line) + print("" + msg) + + print_field_stats = False + field_stat_info \ + := calc_field_stats( \ + field_unstruc_all_grids, field_desc, field_units, print_field_stats) + msg := " " + field_stat_info@msg + print("") + print("" + msg) + + field_min := field_stat_info@field_min + field_max := field_stat_info@field_max + field_median := field_stat_info@field_median + field_mean := field_stat_info@field_mean + + msg := \ +"Done calculating statistics of combined field on all grids." + print("") + print("" + msg) + print("" + separator_line) +; +; ********************************************************************** +; +; Set the name of the graphics file that will contain the plot. We al- +; ways include the name of the field on the first tile to be plotted. +; If there is more than one tile to plot and if the field names happen +; to be different on the various tiles, we add the string "ETC" after +; the field name in the file name to indicate that not all fields are +; the same. +; +; ********************************************************************** +; + fn_graphics = field_names_by_tile(0) + match_found := strcmp_exact(field_names_by_tile, fn_graphics) + match_by_elem := match_found@match_by_elem + if (.not. all(match_by_elem)) then + fn_graphics := fn_graphics + "ETC" + end if + + fmt_str = "%03i" + vert_indx_str = sprinti(fmt_str, vert_indx) + fcst_hr_str = sprinti(fmt_str, fcst_hr) + fn_graphics := cres + "_grid_" + fn_graphics \ + + "_f" + fcst_hr_str + "_k" + vert_indx_str +; +; ********************************************************************** +; +; Generate plot title string(s). +; +; ********************************************************************** +; +nn=0 + title_info \ + := make_plot_titles( \ + inds_tiles_to_plot, \ + nz_by_tile, vert_indx, \ +\ + field_name, field_desc, field_units, \ + func_xyz_only, func_xyzt_only, \ + field_min_tiles_to_plot, field_max_tiles_to_plot, \ + tile_bdy_color, \ +\ + show_RAP_grid, plot_RAP_field, \ + field_name_RAP, field_desc_RAP, field_units_RAP, \ + RAP_bdy_color, \ +\ + nn) + + left_str := title_info@left_str + main_str := title_info@main_str + right_str := title_info@right_str +left_str := "" +main_str := "" +right_str := "" +; +; ********************************************************************** +; +; Set general plotting options that will be passed to the plotting func- +; tion. +; +; ********************************************************************** +; + plot_opts := True + + plot_opts@map_proj = map_proj + plot_opts@map_proj_ctr = map_proj_ctr +; +; Set the flag that determines whether plots will be resized (e.g. to a +; larger area than the default). This would generally be done using the +; gsnMaximize resource, but it's not clear how to use or reset this re- +; source after adding annotations to the plot (annotations in our case +; are the plot titles). Thus, we perform the resizing/maximization man- +; ually. +; + plot_opts@resize_plot = True +; +; Set the size (either width or height) of the bounding box which the +; resized plot will have. Note that this is in NDC (non-dimensional co- +; ordinate, aka page) coordinates. This value must be between 0 and 1. +; + plot_opts@bounding_box_size_NDC = 0.98 + + if (plot_subreg) then + plot_opts@plot_subreg = plot_subreg + plot_opts@subreg_limits = subreg_limits + end if + + plot_opts@left_str = left_str + plot_opts@main_str = main_str + plot_opts@right_str = right_str +; +; ********************************************************************** +; +; Calculate "nice" contour level values to use for making a color con- +; tour plot of the combined FV3LAM and RAP field. +; +; ********************************************************************** +; + msg := \ +"Calculating " + char_dq + "nice" + char_dq + " contour values from " + \ +"the field's minimum and maximum " + char_nl + \ +"values ..." + print("") + print("" + separator_line) + print("" + msg) + + num_cnLevels = 20 + opts := True + opts@verbose = False +; Numbers for custom plot for Jeff. +;field_min = 2.65 +;field_max = 3.6 +;num_cnLevels = 23 +;field_min = 9.0 +;field_min = 8.0 +;field_min = 7.95 +;field_max = 15.5 +;num_cnLevels = 23 + contour_info := set_cnLevels_lbLabels( \ + field_min, field_max, num_cnLevels, opts) + copy_VarAtts(contour_info, plot_opts) + + msg := \ +"Done calculating " + char_dq + "nice" + char_dq + " contour values." + print("") + print("" + msg) + print("" + separator_line) +; +; ********************************************************************** +; +; Set the arrays containing the number of grid points in the x and y di- +; rections for all tiles and grids to be plotted. +; +; ********************************************************************** +; + nx_all_grids \ + := where(remove_halo_tiles_to_plot, \ + nx_tiles_to_plot, nxh_tiles_to_plot) + ny_all_grids \ + := where(remove_halo_tiles_to_plot, \ + ny_tiles_to_plot, nyh_tiles_to_plot) + + if (show_RAP_grid .or. plot_RAP_field) then + nx_all_grids := array_append_record(nx_RAP, nx_all_grids, 0) + ny_all_grids := array_append_record(ny_RAP, ny_all_grids, 0) + end if + if (show_wrtcmp_grid) then + nx_all_grids := array_append_record(nx_wrtcmp, nx_all_grids, 0) + ny_all_grids := array_append_record(ny_wrtcmp, ny_all_grids, 0) + end if +; +; ********************************************************************** +; +; Set attributes of the grid_opts variable. These attributes will be +; used in the plotting function if plotting the grids (gridlines). +; +; ********************************************************************** +; + num_grids_to_plot = num_tiles_to_plot + + if (show_RAP_grid .or. plot_RAP_field) then + num_grids_to_plot = num_grids_to_plot + 1 + end if + + if (show_wrtcmp_grid) then + num_grids_to_plot = num_grids_to_plot + 1 + end if + + if (num_grids_to_plot .gt. 0) then + + plot_grid := new(num_grids_to_plot, "logical") + plot_grid = show_tile_grids + gridline_colors := new(num_grids_to_plot, "string") + gridline_colors = tile_bdy_color + + if (show_RAP_grid .or. plot_RAP_field) then + plot_grid(0) = show_RAP_grid + gridline_colors(0) = RAP_bdy_color + end if + + if (show_wrtcmp_grid) then + plot_grid(1) = show_wrtcmp_grid + gridline_colors(1) = wrtcmp_bdy_color + end if + + grid_opts := True + grid_opts@num_grids = num_grids_to_plot + grid_opts@plot_grid = plot_grid + grid_opts@gridline_colors = gridline_colors + + else + + grid_opts := False + + end if +; +; ********************************************************************** +; +; If the number of tile/grid boundaries to plot is greater than 0, then +; set the dimensions in the x and y directions of each such tile/grid +; and various plotting properties. +; +; ********************************************************************** +; + native_tag = "native" + wrtcmp_tag = "wrtcmp" + extrnl_tag = "extrnl" + + bdy_plot_order := new(num_bdies_to_plot, "string") +;bdy_plot_order(0) = wrtcmp_tag +;bdy_plot_order(1) = extrnl_tag +;bdy_plot_order(2) = native_tag +bdy_plot_order(0) = native_tag + + indx_ptr_start := new(num_bdies_to_plot, "integer") + indx_ptr_end := new(num_bdies_to_plot, "integer") + + bdy_opts := False + + if (num_bdies_to_plot .gt. 0) then + + bdy_plot_order_str := char_dq + bdy_plot_order + char_dq + bdy_plot_order_str := str_join(bdy_plot_order_str, ", ") + bdy_plot_order_str := "(/ " + bdy_plot_order_str + " /)" + + nx_all_bdies := new(num_bdies_to_plot, "integer") + ny_all_bdies := new(num_bdies_to_plot, "integer") + plot_bdy := new(num_bdies_to_plot, "logical") + bdy_colors := new(num_bdies_to_plot, "string") + bdy_line_thicknesses := new(num_bdies_to_plot, "float") + bdy_dash_patterns := new(num_bdies_to_plot, "integer") + + nbdy = 0 + + if (show_tile_bdies) then + + nx_all_bdies(nbdy:num_tiles_to_plot-1) \ + = where(remove_halo_tiles_to_plot, \ + nx_tiles_to_plot, nxh_tiles_to_plot) + ny_all_bdies(nbdy:num_tiles_to_plot-1) \ + = where(remove_halo_tiles_to_plot, \ + ny_tiles_to_plot, nyh_tiles_to_plot) + + plot_bdy(nbdy:num_tiles_to_plot-1) = show_tile_bdies + bdy_colors(nbdy:num_tiles_to_plot-1) = tile_bdy_color + bdy_line_thicknesses(nbdy:num_tiles_to_plot-1) = 4.0 + bdy_dash_patterns(nbdy:num_tiles_to_plot-1) = 0 + + indx_start_native = nbdy + indx_end_native = indx_start_native + num_tiles_to_plot - 1 + nbdy = nbdy + num_tiles_to_plot + + tag := native_tag + if (.not. strcmp_exact(bdy_plot_order, tag)) then + msg := char_nl + \ +"Since show_wrtcmp_bdy is set to True, the string array bdy_plot_order " + char_nl + \ +"must include " + char_dq + tag + char_dq + " as one of its elements:" + char_nl + \ +" bdy_plot_order = " + bdy_plot_order_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + end if + + if (show_RAP_bdy) then + + nx_all_bdies(nbdy) = nx_RAP + ny_all_bdies(nbdy) = ny_RAP + + plot_bdy(nbdy) = show_RAP_bdy + bdy_colors(nbdy) = RAP_bdy_color + bdy_line_thicknesses(nbdy) = 4.0 + bdy_dash_patterns(nbdy) = 1 + + indx_start_extrnl = nbdy + indx_end_extrnl = indx_start_extrnl + nbdy = nbdy + 1 + + tag := extrnl_tag + if (.not. strcmp_exact(bdy_plot_order, tag)) then + msg := char_nl + \ +"Since show_wrtcmp_bdy is set to True, the string array bdy_plot_order " + char_nl + \ +"must include " + char_dq + tag + char_dq + " as one of its elements:" + char_nl + \ +" bdy_plot_order = " + bdy_plot_order_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + end if + + if (show_wrtcmp_bdy) then + + nx_all_bdies(nbdy) = nx_wrtcmp + ny_all_bdies(nbdy) = ny_wrtcmp + + plot_bdy(nbdy) = show_wrtcmp_bdy + bdy_colors(nbdy) = wrtcmp_bdy_color + bdy_line_thicknesses(nbdy) = 4.0 + bdy_dash_patterns(nbdy) = 1 + + indx_start_wrtcmp = nbdy + indx_end_wrtcmp = indx_start_wrtcmp + nbdy = nbdy + 1 + + tag = wrtcmp_tag + if (.not. strcmp_exact(bdy_plot_order, tag)) then + msg := char_nl + \ +"Since show_wrtcmp_bdy is set to True, the string array bdy_plot_order " + char_nl + \ +"must include " + char_dq + tag + char_dq + " as one of its elements:" + char_nl + \ +" bdy_plot_order = " + bdy_plot_order_str + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + end if +; +; Use the tile/grid dimensions in the x and y directions to calculate +; the number of boundary points for each tile/grid. +; + num_bdy_pts_all_bdies := 2*(nx_all_bdies + ny_all_bdies) + 1 +; +; Set attributes of the bdy_opts variable to the various plotting pro- +; perties set above. These attributes will be used in the plotting +; function if plotting tile and/or grid boundaries. +; + bdy_opts := True + bdy_opts@num_bdies = num_bdies_to_plot + bdy_opts@num_bdy_pts_all_bdies = num_bdy_pts_all_bdies + bdy_opts@plot_bdy = plot_bdy + bdy_opts@bdy_colors = bdy_colors + bdy_opts@bdy_line_thicknesses = bdy_line_thicknesses + bdy_opts@bdy_dash_patterns = bdy_dash_patterns + + end if + + + +if (False) then +do i=0, num_bdies_to_plot-1 +print("i = " + i) + if (strcmp_exact(bdy_plot_order(i), "native")) then + indx_ptr_start(i) = indx_start_native + indx_ptr_end(i) = indx_end_native + else if (strcmp_exact(bdy_plot_order(i), "wrtcmp")) then + indx_ptr_start(i) = indx_start_wrtcmp + indx_ptr_end(i) = indx_end_wrtcmp + else if (strcmp_exact(bdy_plot_order(i), "extrnl")) then + indx_ptr_start(i) = indx_start_extrnl + indx_ptr_end(i) = indx_end_extrnl + end if + end if + end if + +end do +end if + +; +; ********************************************************************** +; +; Call the plotting function to generate a color contour plot of speci- +; fied fields, grids, and/or grid boundaries. +; +; ********************************************************************** +; +; Does field_unstruc_all_grids need to have a _FilLValue attribute in +; order for its FillValue points to be ignored? Not sure... +;field_unstruc_all_grids@_FillValue = default_fillvalue(typeof(field_unstruc)) + +; Temporarily make the field all missing/fill values, so we can see grids/boundaries. +;field_unstruc_all_grids = field_unstruc_all_grids@_FillValue + +print("nx_all_grids = " + nx_all_grids) +print("") +print("CCCCCCC dimsizes(field_unstruc_all_grids) = " + dimsizes(field_unstruc_all_grids)) + + plot_info := plot_horiz_field( \ + fn_graphics, \ + nx_all_grids, ny_all_grids, \ + lon_cntrs_unstruc_all_grids, lat_cntrs_unstruc_all_grids, \ + lon_verts_unstruc_all_grids, lat_verts_unstruc_all_grids, \ + lon_bdy_all_bdies, lat_bdy_all_bdies, \ + field_unstruc_all_grids, \ + grid_opts, \ + bdy_opts, \ + plot_opts) + +print("BYE!!!!!!!!!!!!!!!!!!!!!!!") + + + end do + end do + + +end + + + + + + diff --git a/ush/NCL/plot_fields.ncl b/ush/NCL/plot_fields.ncl new file mode 100644 index 0000000000..e0d746dd8c --- /dev/null +++ b/ush/NCL/plot_fields.ncl @@ -0,0 +1,1779 @@ +;========================================================================== +; Description: This script reads FV3 grid information and model output +; fields and generated a 2-D color plot of the required fields +; on top of a map of the continents. The script can be run +; from the command line or the make_FV3_RAP_domain_plots.sh +; script. +; +; Necessary input files: pause.ncl, README, strcmp.ncl +; geo_em.d01.nc (if draw_RAP_domain) +; INPUT/C[res]_grid.tile[].nc +; INPUT/grid_spec.nc +; INPUT/oro_data.nc +; a model output file specified by 'base_name' on the command line +; +; Necessary input parameters: +; +; Output file(s): C[res]_[map_proj]_[field]_hr[hour]_lev[n].png +; +; Usage: See README file + +; Assumptions: You have an FV3 model run directory with an INPUT directory +; containing the grid files for the tiles. +; +; Examples: +; ncl -n plot_fields.ncl 'help=True' # print help using this script +; +; ncl -n plot_fields.ncl \ +; 'help=False' \ +; 'grid_dir="./some_dir/grid"' \ +; 'base_name="nppgs2d"' \ +; 'fields=(/"u1000", "v1000"/)' \ +; 'nlev="60"' \ +; 'fcst_index="(/6/)"' \ +; 'res=96' \ +; 'tile_inds=(/1,2,3/)' \ +; 'draw_tile_bdy=True' \ +; 'draw_tile_grid=True' \ +; 'draw_RAP_domain=True' \ +; 'RAP_grid_fn="./some_dir/RAP_grid.nc"' \ +; 'draw_RAP_bdy=True' \ +; 'draw_RAP_grid=True' \ +; 'map_proj="cyln"' \ +; 'map_proj_ctr=(/0,90/)' \ +; 'subreg=(/-30,30,-25,25/)' \ +; 'graphics_type="ncgm"' +;========================================================================== + +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" +load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" + +load "pause.ncl" +load "read_namelist.ncl" +load "strcmp.ncl" + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + pwd = systemfunc("pwd") + check_files = (/"README"/) ; Add files to check here + nfiles = dimsizes(check_files) + + do i=0,nfiles-1 + ret = systemfunc("test -f " + pwd + "/" + check_files(i) + "; echo $?") + if(ret .eq. 0) then + print("--> " + check_files(i) + ": exists") + else if(ret .eq.1) then + print("Error: " + check_files(i) + ": doesn't exist") + print("Copy " + check_files(i) + " from your original directory to your working directory") + exit + end if + end if + end do +; +; ********************************************************************** +; +; Define special characters that can't be directly input into an NCL +; string. +; +; ********************************************************************** +; + char_dq = integertochar(34) + char_nl = str_get_nl() +; +; ********************************************************************** +; +; Create usage message. +; +; ********************************************************************** +; + usage_msg = \ +" ncl -n plot_fields.ncl \" + char_nl + \ +" 'help=False' \" + char_nl + \ +" 'grid_dir=" + char_dq + "./some_dir/grid" + char_dq + "' \" + char_nl + \ +" 'base_name=" + char_dq + "nggps2d.nc" + char_dq + "' \" + char_nl + \ +" 'fields=(u1000,v1000/)' \" + char_nl + \ +" 'nlev=60' \" + char_nl + \ +" 'fcst_index=(/6/)' \" + char_nl + \ +" 'res=96' \" + char_nl + \ +" 'tile_inds=(/1,2,3/)' \" + char_nl + \ +" 'draw_tile_bdy=True' \" + char_nl + \ +" 'draw_tile_grid=True' \" + char_nl + \ +" 'draw_RAP_domain=True' \" + char_nl + \ +" 'RAP_grid_fn=" + char_dq + "./some_dir/RAP_grid.nc" + char_dq + "' \" + char_nl + \ +" 'draw_RAP_bdy=True' \" + char_nl + \ +" 'draw_RAP_grid=True' \" + char_nl + \ +" 'map_proj=" + char_dq + "cyln" + char_dq + "' \" + char_nl + \ +" 'map_proj_ctr=(/0,90/)' \" + char_nl + \ +" 'subreg=(/-30,30,-25,25/)' \" + char_nl + \ +" 'graphics_type=" + char_dq + "ncgm" + char_dq + "'" +; +; ********************************************************************** +; +; If the variable help is specified to be True on the command line, +; print out the documentation and exit. +; +; ********************************************************************** +; + if (isvar("help")) then + if (help .eq. True) then + help_msg = systemfunc("cat " + pwd + "/" + "README") + print("" + help_msg) + exit + end if + end if +; +; ********************************************************************** +; +; Check whether grid_dir has been specified. If not, set it to the cur- +; rent directory. +; +; ********************************************************************** +; + if (.not. isvar("grid_dir")) then + grid_dir = "./" + end if + +; ********************************************************************** +; +; Check whether the fcst_index has been specified on the command line. +; If not, print out a message and exit. If so, check for indices or 'all' +; +; ********************************************************************** + if (.not. isvar("fcst_index")) then + print("") + print("ERROR: fcst_index has not been specified on the command line:") + print("") + print("Please rerun with a specified resolution. Example:") + print("") + print("" + usage_msg) + print("") + else + if (isint(fcst_index)) then ; Integer indices + print ("fcst_index is an integer" + fcst_index) + else if (isstring(fcst_index)) + print ("fcst_index is a string" + fcst_index) + else + print ("ERROR: Check format of fcst_index.") + exit + end if + end if + n_fcst_index = dimsizes(fcst_index) + end if +; +; ********************************************************************** +; +; Check whether the cubed-sphere resolution (res) has been specified on +; the command line. If not, print out a message and exit. +; +; ********************************************************************** +; + if (.not. isvar("res")) then + print("") + print("The cubed-sphere resolution (res) has not been specified on the command line:") + print("") + print(" isvar(" + char_dq + "res" + char_dq + ") = " + isvar("res")) + print("") + print("Please rerun with a specified resolution. Example:") + print("") + print("" + usage_msg) + print("") + print("For more help, type " + char_dq + "ncl plot_fields.ncl 'help=True'" + char_dq + " on the command line.") + print("Stopping.") + exit + end if + + Cres := "C" + tostring_with_format(res, "%i") +; +; ********************************************************************** +; +; Get the version of NCL being used. This may be needed later below. +; +; ********************************************************************** +; + ncl_ver = get_ncl_version() + ncl_ver = str_sub_str(ncl_ver, ".", "") + ncl_ver = tointeger(ncl_ver) +; +; ********************************************************************** +; +; Open the grid mosaic file and read in the number of tiles for which a +; grid description file is available. Then use that number (possibly +; along with the options passed to the make_hgrid command used to gene- +; rate the grid description files) to determine the cubed-sphere grid +; type, gtype. gtype can be "uniform" (for a globally uniform grid), +; "stretch" (for a global grid that has been stretched/compressed to +; achieve variable resolution), "nest" (for a stretched global grid with +; a nested grid within tile 6), or "regional" (for a regional stand- +; alone grid). Also, set valid_tile_inds, which is an array contain- +; ing the set of valid tile indices for a given gtype. +; +; ********************************************************************** +; +; fn_mosaic := grid_dir + "/" + Cres + "_mosaic.nc" + fn_mosaic := grid_dir + "/grid_spec.nc" + fm = addfile(fn_mosaic, "r") + num_tiles_avail := getfilevardimsizes(fm, "gridtiles") + print("num_tiles_avail = " + num_tiles_avail) + num_tiles_avail := num_tiles_avail(0) + + print("num_tiles_avail = " + num_tiles_avail) + if (num_tiles_avail .eq. 6) then + +; Read in file attributes from the tile 1 grid file. The attribute we +; are interested in is the string containing the call to make_hgrid that +; created the grid. It has information that determines whether this is +; a uniform or a stretched grid (if it is a stretched grid, the call to +; make_hgrid will contain the --do_schmidt flag). + n_tile = 1 + grid_fn := grid_dir + "/" + Cres + "_grid.tile" + n_tile + ".nc" + fg1 = addfile(grid_fn, "r") + + if (ncl_ver .ge. 650) then +; NCL V6.5.0 and later. + file_atts = getfileatts(fg1) + else +; NCL V6.4.0 and earlier. + file_atts = getvaratts(fg1) + end if + + make_hgrid_command = fg1@history + idx_do_schmidt := str_match_ind_regex(make_hgrid_command, "--do_schmidt") + if (ismissing(idx_do_schmidt)) then + gtype = "uniform" + else + gtype = "stretch" + end if + valid_tile_inds = (/ 1, 2, 3, 4, 5, 6 /) + + else if (num_tiles_avail .eq. 7) then + + gtype = "nest" + valid_tile_inds = (/ 1, 2, 3, 4, 5, 6, 7 /) + + else if (num_tiles_avail .eq. 1) then + + gtype = "regional" +; For a regional grid, although tiles 1 through 6 are not used in the +; time-integration, they are still available for visualization. ; valid_tile_inds = (/ 7 /) + valid_tile_inds = (/ 1, 2, 3, 4, 5, 6, 7 /) + + else + + print("") + print("Disallowed total number of tiles on grid:") + print(" num_tiles_avail = " + num_tiles_avail) + print("Cannot set gtype. Stopping.") + exit + + end if + end if + end if + +print("") +print("========>>>> gtype = " + gtype) +; +; ********************************************************************** +; +; Check whether the indices of the tiles (on the cubed sphere) that are +; to be plotted have been specified on the command line in the array +; tile_inds. If so, for clarity, first change the name of the array to +; inds_tiles_to_plot. Then make sure that the tile indices in this ar- +; ray are all valid, i.e. that each index can be found in the list of +; valid indices in valid_tile_inds. If the indices of the tiles to be +; plotted have not been specified on the command line, set them to the +; contents of inds_valid_tiles. +; +; ********************************************************************** +; + if (isvar("tile_inds")) then + +; Change array name. + inds_tiles_to_plot = tile_inds + delete(tile_inds) + +; Keep only unique tile indices and sort them. + inds_tiles_to_plot := get_unique_values(inds_tiles_to_plot) + qsort(inds_tiles_to_plot) + +; Check that each tile index in inds_tiles_to_plot can be found in +; valid_tile_inds. + num_tiles_to_plot = dimsizes(inds_tiles_to_plot) + do nn=0, num_tiles_to_plot-1 + n_tile = inds_tiles_to_plot(nn) + if (.not. any(valid_tile_inds .eq. n_tile)) then + print("") + print("Tile #" + n_tile + " is not a valid tile for the current grid type (gtype):") + print("") + print(" gtype = " + gtype) + print(" valid_tile_inds = " + valid_tile_inds) + print(" inds_tiles_to_plot = " + inds_tiles_to_plot) + print("") + print("Stopping.") + exit + end if + end do + + else + + inds_tiles_to_plot := valid_tile_inds + num_tiles_to_plot = dimsizes(inds_tiles_to_plot) + + end if +; +; ********************************************************************** +; +; Check whether draw_tile_bdy has been specified on the command line. +; If not, set it to True. +; +; ********************************************************************** +; + if (.not. isvar("draw_tile_bdy")) then + draw_tile_bdy = True + end if +; +; ********************************************************************** +; +; Check whether draw_tile_grid has been specified on the command line. +; If not, set it to False. +; +; ********************************************************************** +; + if (.not. isvar("draw_tile_grid")) then + draw_tile_grid = False + end if +; +; ********************************************************************** +; +; Check whether draw_RAP_domain has been specified on the command line. +; If not, set it to False. +; +; ********************************************************************** +; + if (.not. isvar("draw_RAP_domain")) then + draw_RAP_domain = False + end if +; +; ********************************************************************** +; +; If draw_RAP_domain has been specified to be True on the command line, +; make sure that the name of the NetCDF file that describes the RAP grid +; (RAP_grid_fn) has also been specified. If not, print a message and +; exit. +; +; ********************************************************************** +; + if (draw_RAP_domain .and. .not. isvar("RAP_grid_fn")) then + print("") + print("The name of the NetCDF file that describes the RAP grid (RAP_grid_fn) has not been specified on the command line:") + print("") + print(" draw_RAP_domain = " + draw_RAP_domain) + print(" isvar(" + char_dq + "RAP_grid_fn" + char_dq + ") = " + isvar("RAP_grid_fn")) + print("") + print("Please rerun with a specified RAP_grid_fn. Example:") + print("") + print("" + usage_msg) + print("") + print("For more help, type " + char_dq + "ncl plot_fields.ncl 'help=True'" + char_dq + " on the command line.") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Check whether draw_RAP_bdy has been specified on the command line. If +; not, set it to True. +; +; ********************************************************************** +; + if (.not. isvar("draw_RAP_bdy")) then + draw_RAP_bdy = True + end if +; +; ********************************************************************** +; +; Check whether draw_RAP_grid has been specified on the command line. +; If not, set it to False. +; +; ********************************************************************** +; + if (.not. isvar("draw_RAP_grid")) then + draw_RAP_grid = False + end if + +; ********************************************************************** +; +; Check whether map_proj is specified, and if so, whether the specified +; value is valid. Default is to use a cylindrical-equidistant project- +; ion. +; +; ********************************************************************** +; + if (.not. isvar("map_proj")) then + map_proj := "cyln" + end if + + idx_cyln := str_match_ind_regex(map_proj, "^" + "cyln" + "$") + idx_ortho := str_match_ind_regex(map_proj, "^" + "ortho" + "$") + idx_lamb := str_match_ind_regex(map_proj, "^" + "lamb" + "$") + + if (ismissing(idx_cyln) .and. \ + ismissing(idx_ortho) .and. \ + ismissing(idx_lamb)) then + print("") + print("Disallowed value specified for " + char_dq + "map_proj" + \ + char_dq + ":") + print(" map_proj = " + char_dq + map_proj + char_dq) + print("Allowed values are:") + print(" " + char_dq + "cyln" + char_dq + \ + " (for cylindrical-equidistant projection)") + print(" " + char_dq + "ortho" + char_dq + \ + " (for orthographic (i.e. on a sphere) projection)") + print(" " + char_dq + "lamb" + char_dq + \ + " (for Lambert equal-area projection)") + print("Please specify one of these allowed values for " + \ + char_dq + "map_proj" + char_dq + ".") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Check whether map_proj_ctr is specified. If not, set it according to +; the specified map projection. Note that this variable is not used for +; the cylindrical-equidistant map projection. +; +; ********************************************************************** +; + if (.not. isvar("map_proj_ctr")) then + + map_proj_ctr = new((/2/), "float") + + if (.not. ismissing(idx_cyln)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (.not. ismissing(idx_ortho)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (.not. ismissing(idx_lamb)) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 90. + end if + end if + end if + + end if +; +; ********************************************************************** +; +; If the array subreg is specified on the command line, it means we will +; plot only a subregion, not the whole globe. In this case, get the +; minimum and maximum values of the longitude and latitude for the sub- +; region to be plotted. +; +; ********************************************************************** +; + if (isvar("subreg")) then + lon_min = subreg(0) + lon_max = subreg(1) + lat_min = subreg(2) + lat_max = subreg(3) + end if +; +; ********************************************************************** +; +; Check whether graphics_type has been specified on the command line. +; If not, set it to "ncgm". +; +; ********************************************************************** +; + if (.not. isvar("graphics_type")) then + graphics_type := "ncgm" + end if + + idx_ncgm := str_match_ind_regex(graphics_type, "^" + "ncgm" + "$") + idx_png := str_match_ind_regex(graphics_type, "^" + "png" + "$") + + if (ismissing(idx_ncgm) .and. ismissing(idx_png)) then + print("") + print("Disallowed value specified for " + char_dq + "graphics_type" + \ + char_dq + ":") + print(" graphics_type = " + char_dq + graphics_type + char_dq) + print("Allowed values are:") + print(" " + char_dq + "ncgm" + char_dq + \ + " (for type NCAR Graphics output graphics file)") + print(" " + char_dq + "png" + char_dq + \ + " (for type png output graphics file)") + print("Please specify one of these allowed values for " + \ + char_dq + "graphics_type" + char_dq + ".") + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Check that the name of the data file has been specified on the command +; line. If not, print out a message and exit. +; +; ********************************************************************** +; + if (.not. isvar("base_name")) then + print("") + print("The data file has not been specified on the command line:") + print(" isvar(" + char_dq + "base_name" + char_dq + ") = " + isvar("base_name")) + print("Please specify the data file on the command line. Example:") + print("" + usage_msg) + print("Stopping.") + exit + end if + +; ********************************************************************** +; +; Check that the field(s) to plot has been specified on the command line. +; If not, print out a message and exit. +; +; ********************************************************************** +; + if (.not. isvar("fields")) then + print("") + print("The field(s) to plot has not been specified on the command " + \ + "line:") + print(" isvar(" + char_dq + "fields" + char_dq + ") = " + \ + isvar("fields")) + print("Please specify the field(s) to plot on the command line. " + \ + "Example:") + print("" + usage_msg) + print("Stopping.") + exit + else + print ("Fields to be plotted are " + fields) + end if +; +; ********************************************************************** +; +; Read in the coupler_nml namelist from the file input.nml. From this +; namelist, get the starting date of the simulation and construct a date +; string out of it. This string is needed in forming the names of the +; data files. +; +; ********************************************************************** +; + if (False) then ; JLS keep for later + fn_nml = "input.nml" + nl_name = "coupler_nml" + nl := read_namelist(fn_nml, nl_name) + current_date := nl@current_date + yyyy := tostring_with_format(current_date(0), "%04i") + mo := tostring_with_format(current_date(1), "%02i") + dd := tostring_with_format(current_date(2), "%02i") + hh := tostring_with_format(current_date(3), "%02i") + mn := tostring_with_format(current_date(4), "%02i") + ss := tostring_with_format(current_date(5), "%02i") + date_str := yyyy + mo + dd + hh + mn + ss + else + date_str := "yyyymoddhhmnss" + end if +; +; ********************************************************************** +; +; Get tile dimensions and calculate the total number of cells to be +; plotted (i.e. summed over all tiles to be plotted). +; +; ********************************************************************** +; + nx_by_tile = new((/ num_tiles_to_plot /), "integer") + ny_by_tile = new((/ num_tiles_to_plot /), "integer") + + do nn=0, num_tiles_to_plot-1 + n_tile = inds_tiles_to_plot(nn) + grid_fn := grid_dir + "/" + Cres + "_grid.tile" + n_tile + ".nc" + print("") + print("Reading tile dimensions from file:") + print(" grid_fn = " + grid_fn) + fg = addfile(grid_fn, "r") + tile_dims := getfilevardimsizes(fg, "area") + ny_by_tile(nn) = tile_dims(0)/2 + nx_by_tile(nn) = tile_dims(1)/2 + end do + +; ********************************************************************** +; For a regional grid, strip away 3 halo points. +; ********************************************************************** + halo_T7 = 0 + if (strcmp(gtype, "regional")) then + halo_T7 = 3 + end if + + nx_by_tile = nx_by_tile - 2*halo_T7 + ny_by_tile = ny_by_tile - 2*halo_T7 + + nx_tms_ny_by_tile = nx_by_tile*ny_by_tile + num_cells_to_plot_all_tiles = sum(nx_tms_ny_by_tile) +; +; Create arrays to hold the coordinates of the vertices of all cells +; on all tiles to be plotted. Also, create work arrays xpoly and ypoly. +; + num_edges_per_cell = 4 + lon_verts_by_cell := new((/ num_cells_to_plot_all_tiles, num_edges_per_cell /), "double") + lat_verts_by_cell := new((/ num_cells_to_plot_all_tiles, num_edges_per_cell /), "double") + xpoly = new((/ num_edges_per_cell /), "double") + ypoly = new((/ num_edges_per_cell /), "double") +; +; The following is needed in plotting the tile boundaries (i.e. if +; draw_tile_bdy is set to True). +; + if (draw_tile_bdy) then + nx_pls_ny_by_tile = nx_by_tile + ny_by_tile + nx_pls_ny_max = max(nx_pls_ny_by_tile) + lon_bdy_by_tile := new((/ num_tiles_to_plot, 2*nx_pls_ny_max+1 /), "double") + lat_bdy_by_tile := new((/ num_tiles_to_plot, 2*nx_pls_ny_max+1 /), "double") + end if + +;------------------------------------------------------ +; Loop over fields +;------------------------------------------------------ + do ifield = 0, dimsizes(fields) - 1 + field_name = fields(ifield) +; +;------------------------------------------------------ +; Loop over times +;------------------------------------------------------ + file_name = grid_dir + "/../" + base_name + ".tile" + inds_tiles_to_plot(0) + ".nc" + + if (fileexists(file_name)) then + f_unit = addfile(file_name, "r") + else + print ("ERROR: The input file " + file_name + " does not exist") + end if + + if (isfilevar(f_unit, "time")) then + time = f_unit->time + num_times = dimsizes(time) ; Number of time indices in file + if ( fcst_index(0) .eq. "all" ) then + time_inds = ispan(0, num_times-1, 1) ; Use all time indices + else ; Test if user input times are + time_inds = new((/ n_fcst_index /), "integer") + do itest = 0, n_fcst_index-1 ; in the range in file + if (fcst_index(itest) .ge. 1 .and. fcst_index(itest) .le. num_times) then + time_inds(itest) = fcst_index(itest) + else + print ("ERROR: fcst_index is out of the range of 1 and " + num_times) + exit + end if + end do + end if + else + print ("WARNING: No time variable in file " + file_name) + end if + print ("Time indices to plot = " + time_inds) +;------------------------------------------------------ +; Loop over times +; JLS TODO indent two spaces for time loop +;------------------------------------------------------ + do itime = 0, dimsizes(time_inds) - 1 + + tindex = time_inds(itime) + print("Time loop " + itime + " tindex = " + tindex) +; ********************************************************************** +; +; Loop through the specified tiles and read in the grid geometry (i.e. +; coordinates of the cell center and cell vertices) and the value of the +; specified field for each cell. +; +; ********************************************************************** +; + field_min := new((/ num_tiles_to_plot /), "double") + field_max := new((/ num_tiles_to_plot /), "double") + field_median := new((/ num_tiles_to_plot /), "double") + field_mean := new((/ num_tiles_to_plot /), "double") + + n_cell = 0 + + do nn=0, num_tiles_to_plot-1 + + print("") + print("" + separator_line) + print("") + print("nn = " + nn) + + n_tile = inds_tiles_to_plot(nn) + + print("") + print("n_tile = " + n_tile) + +; Get the number of cells in each of the two directions on the current +; tile. + nx = nx_by_tile(nn) + ny = ny_by_tile(nn) + print("") + print("nx = " + nx) + print("ny = " + ny) +; +; Open the NetCDF file containing the grid geometry. +; + grid_fn := grid_dir + "/" + Cres + "_grid.tile" + n_tile + ".nc" + print("") + print("Reading grid geometry from file:") + print(" grid_fn = " + grid_fn) + fg = addfile(grid_fn, "r") +; +; Read in the supergrid coordinates. The supergrid of a given tile is a +; grid having twice the resolution of the actual (i.e. computational) +; grid of that tile. It is used to store the coordintes of both the +; centers and the vertices of the cells on the computational grid. +; + lon_verts_supergrid_crnt_tile := fg->x(:,:) + lat_verts_supergrid_crnt_tile := fg->y(:,:) +; Shave off halo. + print("") + print(dimsizes(lon_verts_supergrid_crnt_tile)) +;pause + temp := dimsizes(lon_verts_supergrid_crnt_tile) + nx_SG = temp(1) + ny_SG = temp(0) +; halo_SGT7 = 7 +; lon_verts_supergrid_crnt_tile \ +; := lon_verts_supergrid_crnt_tile(halo_SGT7:ny_SG-halo_SGT7, halo_SGT7:nx_SG-halo_SGT7) + lon_verts_supergrid_crnt_tile \ + := lon_verts_supergrid_crnt_tile(2*halo_T7:ny_SG-1-2*halo_T7, 2*halo_T7:nx_SG-1-2*halo_T7) + print("") + print(dimsizes(lon_verts_supergrid_crnt_tile)) +;pause +; lat_verts_supergrid_crnt_tile \ +; := lat_verts_supergrid_crnt_tile(halo_SGT7:ny_SG-halo_SGT7, halo_SGT7:nx_SG-halo_SGT7) + lat_verts_supergrid_crnt_tile \ + := lat_verts_supergrid_crnt_tile(2*halo_T7:ny_SG-1-2*halo_T7, 2*halo_T7:nx_SG-1-2*halo_T7) +; +; Get the coordinates of the cell vertices on the current tile. +; + lon_verts_crnt_tile := lon_verts_supergrid_crnt_tile(0::2,0::2) + lat_verts_crnt_tile := lat_verts_supergrid_crnt_tile(0::2,0::2) +; +; Get the coordinates of the cell centers on the current tile. +; + lon_cntrs_crnt_tile := lon_verts_supergrid_crnt_tile(1::2,1::2) + lat_cntrs_crnt_tile := lat_verts_supergrid_crnt_tile(1::2,1::2) +; +; Delete supergrid coordinates to save memory. +; + delete([/ lon_verts_supergrid_crnt_tile, lat_verts_supergrid_crnt_tile /]) + + plot_title = "" + plot_subtitle = "" + field_crnt_tile := new((/ ny, nx /), "double") + field_crnt_tile = default_fillvalue("double") + field_crnt_tile@_FillValue = default_fillvalue("double") + field_crnt_tile(0,0) = 2.2 + field_crnt_tile(ny/2,nx/2) = 5 + field_crnt_tile(ny-1,nx-1) = 10.0 + +;------------------------------------------------------ +; Open input file requested from command line using base_name +; that contains field data +;------------------------------------------------------ + file_name = grid_dir + "/../" + base_name + ".tile" + n_tile + ".nc" + if (fileexists(file_name)) then + f_unit = addfile(file_name, "r") + else + print ("ERROR: The input file " + file_name + " does not exist") + end if +;------------------------------------------------------ +; Check if each field exists in file, if so, get dimensions +;------------------------------------------------------ + if (isfilevar(f_unit, field_name)) then + print ( field_name + " exists in file " + file_name ) + field_dim_names = getfilevardims(f_unit, field_name) + print ("field_dim_names = " + field_dim_names) + field_dim_sizes = getfilevardimsizes(f_unit, field_name) + print ("field_dim_sizes = " + field_dim_sizes) + num_field_dims = dimsizes(field_dim_sizes) + print ("num_field_dims = " + num_field_dims) + else + print ( "Error: " + field_name + " does NOT exist in file " + file_name ) + print ( "Check " + file_name + " for available fields ") + exit + end if +;------------------------------------------------------ +; Check for time variable, read if it exists, check units and convert to hours +;------------------------------------------------------ + if (isfilevar(f_unit, "time")) then + time = f_unit->time + time_units = f_unit->time@units + print ("Time units are in " + time_units) + if ( .not. ismissing(str_index_of_substr(time_units, "hours since", 0)) ) then + print ("Time is in hours") + else if ( .not. ismissing(str_index_of_substr(time_units, "days since", 0)) ) then + print ("Time is in days, convert to hours") + time = time*24. + else + print ("I am not sure what the time units are") + exit + end if + end if + start_date = str_split(time_units, "since") + else + print ("WARNING: No time variable in file " + file_name) + end if + print ("Time in hours = " + time(:)) +;------------------------------------------------------ +; Check if field is 4d (time, pfull, yt, xy) which requires a vertical index +;------------------------------------------------------ + if (num_field_dims.eq.4) then + if (.not. isvar("nlev")) then + print ( "Error: Array " + field_name + " is 3D and needs a vertical index") + print ("Set nlev in command line arguments") + exit + else + ilev = stringtointeger(nlev) ; nlev exists, convert to integer + end if + + ref_pres_full = f_unit->pfull(:) + field_crnt_tile = f_unit->$field_name$(tindex,ilev,:,:) + field_desc = f_unit->$field_name$@long_name + field_units = f_unit->$field_name$@units + plot_title = field_desc + " at pref = " + ref_pres_full(ilev) + " mb (" + field_units + ")" + plot_subtitle = " Start date: " + start_date(2) + " Hour " + time(tindex) + fn_graphics = Cres + "_" + map_proj + "_" + field_name + "_hr" + time(tindex) + "_lev" + nlev + + else if (num_field_dims.eq.3) then ; (time, yt, xt) + + if (strcmp(field_name, "PRESsfc")) then + field_crnt_tile = f_unit->$field_name$(tindex,:,:) + pascals_per_millibar = 100.0d + field_crnt_tile := field_crnt_tile/pascals_per_millibar + plot_title = "Surface pressure (mb)" + else + field_crnt_tile = f_unit->$field_name$(tindex,:,:) + field_desc = f_unit->$field_name$@long_name + field_units = f_unit->$field_name$@units + plot_title = field_desc + " (" + field_units + ")" + end if + + plot_subtitle = " Start date: " + start_date(2) + " Hour " + time(tindex) + fn_graphics = Cres + "_" + map_proj + "_" + field_name + "_hr" + time(tindex) + + else ; num_field_dims is 2 or less + + if (strcmp(field_name, "grid_size")) then + + cell_area_supergrid_crnt_tile := fg->area(:,:) + + do jj=0, 2*ny-2, 2 + do ii=0, 2*nx-2, 2 + j = jj/2 + i = ii/2 + field_crnt_tile(j,i) \ + = cell_area_supergrid_crnt_tile(jj,ii) \ + + cell_area_supergrid_crnt_tile(jj,ii+1) \ + + cell_area_supergrid_crnt_tile(jj+1,ii+1) \ + + cell_area_supergrid_crnt_tile(jj+1,ii) + end do + end do + field_crnt_tile := sqrt(field_crnt_tile) +; Convert distance from meters to kilometers + field_crnt_tile := field_crnt_tile/1000.0 + delete(cell_area_supergrid_crnt_tile) + plot_title = "Grid Size (km)" + +; The following works with tile 7 only!! + else if (strcmp(field_name, "orog_raw")) then + orog_file = grid_dir + "/oro_data.nc" + f_orog = addfile(orog_file, "r") + field_crnt_tile = f_orog->orog_raw + plot_title = "Raw Orography (m)" + +; The following works with tile 7 only!! + else if (strcmp(field_name, "orog_filt")) then + orog_file = grid_dir + "/oro_data.nc" + f_orog = addfile(orog_file, "r") + field_crnt_tile = f_orog->orog_filt + plot_title = "Filtered Orography (m)" + + end if + end if + end if + fn_graphics = Cres + "_" + map_proj + "_" + field_name + + end if ; End if num_field_dims is 4 or less + end if ; End if num_field_dims is 3 or less + + print("plot_title = " + plot_title) +;--------------------------------------------------- +; Done reading data field +;--------------------------------------------------- +; +; If on the first tile, convert the 2-D arrays containing the coordi- +; nates of the cell centers and the field values at cell centers to 1-D +; arrays that will be passed to the plotting routines. If on the se- +; cond, third, etc tile, perform this conversion and then concatenate +; the results to the 1-D arrays generated for previous tiles. +; + if (nn .eq. 0) then + lon_cntrs_by_cell := ndtooned(lon_cntrs_crnt_tile) + lat_cntrs_by_cell := ndtooned(lat_cntrs_crnt_tile) + field_by_cell := ndtooned(field_crnt_tile) + else + lon_cntrs_by_cell := array_append_record(lon_cntrs_by_cell, ndtooned(lon_cntrs_crnt_tile), 0) + lat_cntrs_by_cell := array_append_record(lat_cntrs_by_cell, ndtooned(lat_cntrs_crnt_tile), 0) + field_by_cell := array_append_record(field_by_cell, ndtooned(field_crnt_tile), 0) + end if +; +; Print out some basic statistics of the field. +; + field_min(nn) = min(field_crnt_tile) + field_max(nn) = max(field_crnt_tile) + field_median(nn) = dim_median_n(field_crnt_tile, (/0,1/)) + field_mean(nn) = avg(field_crnt_tile) + + print("") + print("Field min and max values over current tile are:") + print(" field_min = " + field_min(nn)) + print(" field_max = " + field_max(nn)) + print(" field_median = " + field_median(nn)) + print(" field_mean = " + field_mean(nn)) +; print(" dimsizes(field_crnt_tile) = " + dimsizes(field_crnt_tile)) + +;pause +; +; ********************************************************************** +; +; Save the coordinates of the vertices of each cell on the current tile +; in the arrays that will be passed to the plotting functions. +; +; Note that the loop over j must be the outer loop in order for the ver- +; tex coordinates lon_verts_by_cell and lat_verts_by_cell to map cor- +; rectly to the elements of field_by_cell [which is set above using the +; ndtooned(...) function]. Alternatively, the elements of field_by_cell +; can be set in the loop below using +; +; field_by_cell(n_cell-1) = field_crnt_tile(j,i) +; +; ********************************************************************** +; + if (nn .eq. 0) then + indx_start = 0 + else + indx_start = sum(nx_tms_ny_by_tile(0:nn-1)) + end if + indx_end = indx_start + nx_tms_ny_by_tile(nn) - 1 + + v = 0 + lon := ndtooned(lon_verts_crnt_tile(0:ny-1,0:nx-1)) + lat := ndtooned(lat_verts_crnt_tile(0:ny-1,0:nx-1)) + lon_verts_by_cell(indx_start:indx_end,v) = lon + lat_verts_by_cell(indx_start:indx_end,v) = lat + + v = 1 + lon := ndtooned(lon_verts_crnt_tile(0:ny-1,1:nx)) + lat := ndtooned(lat_verts_crnt_tile(0:ny-1,1:nx)) + lon_verts_by_cell(indx_start:indx_end,v) = lon + lat_verts_by_cell(indx_start:indx_end,v) = lat + + v = 2 + lon := ndtooned(lon_verts_crnt_tile(1:ny,1:nx)) + lat := ndtooned(lat_verts_crnt_tile(1:ny,1:nx)) + lon_verts_by_cell(indx_start:indx_end,v) = lon + lat_verts_by_cell(indx_start:indx_end,v) = lat + + v = 3 + lon := ndtooned(lon_verts_crnt_tile(1:ny,0:nx-1)) + lat := ndtooned(lat_verts_crnt_tile(1:ny,0:nx-1)) + lon_verts_by_cell(indx_start:indx_end,v) = lon + lat_verts_by_cell(indx_start:indx_end,v) = lat + + delete([/ lon, lat /]) +; +; For cells that cross over the international date line, modify longi- +; tudes of the vertices so that there is no discontinuity in their val- +; ues. +; +; This may not be necessary since NCL might be smart enough to figure +; this out, but I'm not sure. Needs more testing. +; + v_ref = 0 + do v=1, num_edges_per_cell-1 + abs_del_lon := abs(lon_verts_by_cell(indx_start:indx_end,v) \ + - lon_verts_by_cell(indx_start:indx_end,v_ref)) + is_greater := (lon_verts_by_cell(indx_start:indx_end,v) .gt. \ + lon_verts_by_cell(indx_start:indx_end,v_ref)) + lon_verts_by_cell(indx_start:indx_end,v) \ + = where((abs_del_lon .gt. 180.0) .and. is_greater, \ + lon_verts_by_cell(indx_start:indx_end,v) - 360.0, \ + lon_verts_by_cell(indx_start:indx_end,v)) + lon_verts_by_cell(indx_start:indx_end,v) \ + = where((abs_del_lon .gt. 180.0) .and. (.not. is_greater), \ + lon_verts_by_cell(indx_start:indx_end,v) + 360.0, \ + lon_verts_by_cell(indx_start:indx_end,v)) + end do + delete([/ abs_del_lon, is_greater /]) +; +; ********************************************************************** +; +; If draw_tile_bdy is specified as True, save in an array the coordi- +; nates of those cell vertices that lie on the boundary of the current +; tile. +; +; ********************************************************************** +; + if (draw_tile_bdy) then + + lon_bdy_crnt_tile := new((/ 1 /), "double") + lat_bdy_crnt_tile := new((/ 1 /), "double") +; +; Copy in coordinate of point at (i,j) = (0,0). +; + i = 0 + j = 0 + lon_bdy_crnt_tile(0) = lon_verts_crnt_tile(j,i) + lat_bdy_crnt_tile(0) = lat_verts_crnt_tile(j,i) +; +; Append coordinate values along j=0. +; + j = 0 + lon_bdy_crnt_tile := array_append_record(lon_bdy_crnt_tile, lon_verts_crnt_tile(j,1:), 0) + lat_bdy_crnt_tile := array_append_record(lat_bdy_crnt_tile, lat_verts_crnt_tile(j,1:), 0) +; +; Append coordinate values along i=nx. +; + i = nx + lon_bdy_crnt_tile := array_append_record(lon_bdy_crnt_tile, lon_verts_crnt_tile(1:,i), 0) + lat_bdy_crnt_tile := array_append_record(lat_bdy_crnt_tile, lat_verts_crnt_tile(1:,i), 0) +; +; Append coordinate values along j=ny. Note that in specifying the i- +; index range, i.e. nx-1:0, we do not specify a negative stride, i.e. +; we do not use nx-1:0:-1 because the order of the elements is automati- +; cally reversed if the starting index is larger than the ending index. +; + j = ny + lon_bdy_crnt_tile := array_append_record(lon_bdy_crnt_tile, lon_verts_crnt_tile(j,nx-1:0), 0) + lat_bdy_crnt_tile := array_append_record(lat_bdy_crnt_tile, lat_verts_crnt_tile(j,nx-1:0), 0) +; +; Append coordinate values along i=0. Note that in specifying the j- +; index range, i.e. ny-1:1, we do not specify a negative stride, i.e. +; we do not use ny-1:1:-1 because the order of the elements is automati- +; cally reversed if the starting index is larger than the ending index. +; + i = 0 + lon_bdy_crnt_tile := array_append_record(lon_bdy_crnt_tile, lon_verts_crnt_tile(ny-1:1,i), 0) + lat_bdy_crnt_tile := array_append_record(lat_bdy_crnt_tile, lat_verts_crnt_tile(ny-1:1,i), 0) +; +; Repeat the first point on the tile boundary also as the last point so +; that the polyline object representing the tile boundary closes on it- +; self. +; + lon_bdy_crnt_tile := array_append_record(lon_bdy_crnt_tile, (/ lon_bdy_crnt_tile(0) /), 0) + lat_bdy_crnt_tile := array_append_record(lat_bdy_crnt_tile, (/ lat_bdy_crnt_tile(0) /), 0) +; +; Copy the coordinates of the current tile's boundary from the temporary +; work arrays to the arrays that will be passed to the plotting func- +; tions. +; + nx_pls_ny = nx_pls_ny_by_tile(nn) + lon_bdy_by_tile(nn,0:2*nx_pls_ny) = lon_bdy_crnt_tile + lat_bdy_by_tile(nn,0:2*nx_pls_ny) = lat_bdy_crnt_tile + + end if +; +; ********************************************************************** +; +; Print out the coordinates of the corners of the current tile. +; +; ********************************************************************** +; + corner_i_inds := (/ 0, nx, nx, 0 /) + corner_j_inds := (/ 0, 0, ny, ny /) + num_corners = 4 + corner_lons := new((/ num_corners /), "double") + corner_lats := new((/ num_corners /), "double") + + do c=0, num_corners-1 + corner_lons(c) = lon_verts_crnt_tile(corner_j_inds(c), corner_i_inds(c)) + corner_lats(c) = lat_verts_crnt_tile(corner_j_inds(c), corner_i_inds(c)) + if (corner_lons(c) .gt. 180.0) then + corner_lons(c) = corner_lons(c) - 360.0 + end if + end do +;print("") +;print("lon = " + corner_lons + " deg; lat = " + corner_lats + " deg") +;pause + + print("") + print("Tile corner lon/lat coordinates are:") + do c=0, num_corners-1 + lon := corner_lons(c) + lat := corner_lats(c) + fmt_str = "%7.2f" + lon_str = sprintf(fmt_str, lon) + lat_str = sprintf(fmt_str, lat) + print("Corner " + (c+1) + ": lon = " + lon_str + " deg; lat = " + lat_str + " deg") + end do + + end do ; End loop over tiles +; +; ********************************************************************** +; +; Done with loop over tiles. Print out min and max values of the field +; being plotted. +; +; ********************************************************************** +; + field_min := min(field_by_cell) + field_max := max(field_by_cell) + field_median := dim_median_n(field_by_cell, (/0/)) + field_mean := avg(field_by_cell) + + print("") + print("" + separator_line) + print("") + print("Field min and max values over all tiles to be plotted are:") + print(" field_min = " + field_min) + print(" field_max = " + field_max) + print(" field_median = " + field_median) + print(" field_mean = " + field_mean) + print(" dimsizes(field_by_cell) = " + dimsizes(field_by_cell)) +; +; ********************************************************************** +; +; RAP domain. +; +; ********************************************************************** +; + field_RAP_fillvalue = default_fillvalue("double") + field_RAP_fillvalue@_FillValue = field_RAP_fillvalue + + field_RAP_min = field_RAP_fillvalue + field_RAP_max = field_RAP_fillvalue +;print("field_RAP_max@_FillValue = " + field_RAP_max@_FillValue) +;printVarSummary(field_RAP_max) +;print("ismissing(field_RAP_max = " + ismissing(field_RAP_max)) +;pause + field_RAP_median = field_RAP_fillvalue + field_RAP_mean = field_RAP_fillvalue + + if (draw_RAP_domain) then + + print("") + print("" + separator_line) +; +; Open the NetCDF file describing the RAP grid. +; + print("") + print("Reading RAP grid geometry from file:") + print(" RAP_grid_fn = " + RAP_grid_fn) + fg = addfile(RAP_grid_fn, "r") +; +; Read in the cell center coordinates of the RAP domain. +; + lon_cntrs_RAP := fg->XLONG_M(:,:,:) + lat_cntrs_RAP := fg->XLAT_M(:,:,:) +; +; Read in the cell corner coordinates of the RAP domain. +; + lon_verts_RAP := fg->XLONG_C(:,:,:) + lat_verts_RAP := fg->XLAT_C(:,:,:) +; +; Remove singleton dimensions (e.g. time) and convert to double preci- +; sion. +; + lon_cntrs_RAP := todouble(rm_single_dims(lon_cntrs_RAP)) + lat_cntrs_RAP := todouble(rm_single_dims(lat_cntrs_RAP)) + + lon_verts_RAP := todouble(rm_single_dims(lon_verts_RAP)) + lat_verts_RAP := todouble(rm_single_dims(lat_verts_RAP)) +; +; Get the dimensions of the RAP domain. +; + RAP_dims := dimsizes(lon_cntrs_RAP) + nx_RAP = RAP_dims(1) + ny_RAP = RAP_dims(0) + + print("") + print("nx_RAP = " + nx_RAP) + print("ny_RAP = " + ny_RAP) +; +; Define a field on the RAP grid (at cell centers). +; + field_RAP := new((/ ny_RAP, nx_RAP /), typeof(field_RAP_fillvalue)) + field_RAP = 50 + +; +; Read in the cell edge distances. +; + +; make_hgrid_command = fg1@history + dx = fg@DX + dy = fg@DY + dx_tms_dy = dx*dy + mapfac_mx := fg->MAPFAC_MX(:,:,:) + mapfac_my := fg->MAPFAC_MY(:,:,:) + mapfac_mx := rm_single_dims(mapfac_mx) + mapfac_my := rm_single_dims(mapfac_my) + cell_area := dx_tms_dy/(mapfac_mx*mapfac_my) +; Grid distance in km. + field_RAP = sqrt(cell_area)/1000.0 + + +; +; Add to the arrays containing cell center coordinates (which currently +; contain the center coordinates of cells on the tiles of the cubed- +; sphere grid) the center coordinates of cells on the RAP grid. +; +; lon_cntrs_by_cell := array_append_record(lon_cntrs_by_cell, ndtooned(lon_cntrs_RAP), 0) +; lat_cntrs_by_cell := array_append_record(lat_cntrs_by_cell, ndtooned(lat_cntrs_RAP), 0) + lon_cntrs_by_cell_RAP := ndtooned(lon_cntrs_RAP) + lat_cntrs_by_cell_RAP := ndtooned(lat_cntrs_RAP) +; +; Add to the array containing field values at cell centers (which cur- +; rently contains values for cells on the tiles of the cubed-sphere +; grid) the field values at the centers of cells on the RAP grid. +; +; field := array_append_record(field, ndtooned(field_RAP), 0) + field_by_cell_RAP := ndtooned(field_RAP) +; +; Print out some basic statistics of the field. +; + field_RAP_min = min(field_RAP) + field_RAP_max = max(field_RAP) +;print("field_RAP_max@_FillValue = " + field_RAP_max@_FillValue) +;printVarSummary(field_RAP_max) +;print("ismissing(field_RAP_max = " + ismissing(field_RAP_max)) +;pause + field_RAP_median = dim_median_n(field_RAP, (/0,1/)) + field_RAP_mean = avg(field_RAP) + + print("") + print("Field min and max values over the RAP domain are:") + print(" dimsizes(field_by_cell_RAP) = " + dimsizes(field_by_cell_RAP)) + print(" field_RAP_min = " + field_RAP_min) + print(" field_RAP_max = " + field_RAP_max) + print(" field_RAP_median = " + field_RAP_median) + print(" field_RAP_mean = " + field_RAP_mean) +; +; ********************************************************************** +; +; Save the coordinates of the vertices of each cell on the RAP grid in +; the arrays that will be passed to the plotting functions. +; +; Note that the loop over j must be the outer loop in order for the ver- +; tex coordinates lon_verts_by_cell_RAP and lat_verts_by_cell_RAP to map +; correctly to the elements of field_by_cell_RAP [which is set above +; using the ndtooned(...) function]. Alternatively, the elements of +; field_by_cell_RAP can be set in the loop below using +; +; field_by_cell_RAP(n_cell-1) = field_RAP(j,i) +; +; ********************************************************************** +; + num_cells_to_plot_RAP = nx_RAP*ny_RAP + lon_verts_by_cell_RAP := new((/ num_cells_to_plot_RAP, num_edges_per_cell /), "double") + lat_verts_by_cell_RAP := new((/ num_cells_to_plot_RAP, num_edges_per_cell /), "double") + + v = 0 + lon := ndtooned(lon_verts_RAP(0:ny_RAP-1,0:nx_RAP-1)) + lat := ndtooned(lat_verts_RAP(0:ny_RAP-1,0:nx_RAP-1)) + lon_verts_by_cell_RAP(:,v) = lon + lat_verts_by_cell_RAP(:,v) = lat + + v = 1 + lon := ndtooned(lon_verts_RAP(0:ny_RAP-1,1:nx_RAP)) + lat := ndtooned(lat_verts_RAP(0:ny_RAP-1,1:nx_RAP)) + lon_verts_by_cell_RAP(:,v) = lon + lat_verts_by_cell_RAP(:,v) = lat + + v = 2 + lon := ndtooned(lon_verts_RAP(1:ny_RAP,1:nx_RAP)) + lat := ndtooned(lat_verts_RAP(1:ny_RAP,1:nx_RAP)) + lon_verts_by_cell_RAP(:,v) = lon + lat_verts_by_cell_RAP(:,v) = lat + + v = 3 + lon := ndtooned(lon_verts_RAP(1:ny_RAP,0:nx_RAP-1)) + lat := ndtooned(lat_verts_RAP(1:ny_RAP,0:nx_RAP-1)) + lon_verts_by_cell_RAP(:,v) = lon + lat_verts_by_cell_RAP(:,v) = lat + + delete([/ lon, lat /]) +; +; For cells that cross over the international date line, modify longi- +; tudes of the vertices so that there is no discontinuity in their val- +; ues. +; + v_ref = 0 + do v=1, num_edges_per_cell-1 + abs_del_lon := abs(lon_verts_by_cell_RAP(:,v) - lon_verts_by_cell_RAP(:,v_ref)) + is_greater := (lon_verts_by_cell_RAP(:,v) .gt. lon_verts_by_cell_RAP(:,v_ref)) + lon_verts_by_cell_RAP(:,v) \ + = where((abs_del_lon .gt. 180.0) .and. is_greater, \ + lon_verts_by_cell_RAP(:,v) - 360.0, \ + lon_verts_by_cell_RAP(:,v)) + lon_verts_by_cell_RAP(:,v) \ + = where((abs_del_lon .gt. 180.0) .and. (.not. is_greater), \ + lon_verts_by_cell_RAP(:,v) + 360.0, \ + lon_verts_by_cell_RAP(:,v)) + end do + delete([/ abs_del_lon, is_greater /]) +; +; ********************************************************************** +; +; If draw_RAP_bdy is set to True, save the coordinates of the RAP do- +; main's boundary in arrays that will be passed to the plotting rou- +; tines. +; +; ********************************************************************** +; + if (draw_RAP_bdy) then +; +; Create arrays that will contain the coordinates of points on the boun- +; dary of the RAP domain. Initially, these contain only one element +; each. +; + lon_bdy_RAP := new((/ 1 /), "double") + lat_bdy_RAP := new((/ 1 /), "double") +; +; Copy in coordinate of point at (i,j) = (0,0). +; + i = 0 + j = 0 + lon_bdy_RAP(0) = lon_verts_RAP(j,i) + lat_bdy_RAP(0) = lat_verts_RAP(j,i) +; +; Append coordinate values along j=0. +; + j = 0 + lon_bdy_RAP := array_append_record(lon_bdy_RAP, lon_verts_RAP(j,1:), 0) + lat_bdy_RAP := array_append_record(lat_bdy_RAP, lat_verts_RAP(j,1:), 0) +; +; Append coordinate values along i=nx_RAP. +; + i = nx_RAP + lon_bdy_RAP := array_append_record(lon_bdy_RAP, lon_verts_RAP(1:,i), 0) + lat_bdy_RAP := array_append_record(lat_bdy_RAP, lat_verts_RAP(1:,i), 0) +; +; Append coordinate values along j=ny_RAP. Note that in specifying the +; i-index range, i.e. nx_RAP-1:0, we do not specify a negative stride, +; i.e. we do not use nx_RAP-1:0:-1 because the order of the elements is +; automatically reversed if the starting index is larger than the ending +; index. +; + j = ny_RAP + lon_bdy_RAP := array_append_record(lon_bdy_RAP, lon_verts_RAP(j,nx_RAP-1:0), 0) + lat_bdy_RAP := array_append_record(lat_bdy_RAP, lat_verts_RAP(j,nx_RAP-1:0), 0) +; +; Append coordinate values along i=0. Note that in specifying the j-in- +; dex range, i.e. ny_RAP-1:1, we do not specify a negative stride, i.e. +; we do not use ny_RAP-1:1:-1 because the order of the elements is auto- +; matically reversed if the starting index is larger than the ending in- +; dex. +; + i = 0 + lon_bdy_RAP := array_append_record(lon_bdy_RAP, lon_verts_RAP(ny_RAP-1:1,i), 0) + lat_bdy_RAP := array_append_record(lat_bdy_RAP, lat_verts_RAP(ny_RAP-1:1,i), 0) +; +; Repeat the first point on the RAP boundary also as the last point so +; that the polyline object representing the tile boundary closes on it- +; self. +; + lon_bdy_RAP := array_append_record(lon_bdy_RAP, (/ lon_bdy_RAP(0) /), 0) + lat_bdy_RAP := array_append_record(lat_bdy_RAP, (/ lat_bdy_RAP(0) /), 0) + + end if ; end if draw_RAP_bdy +; +; ********************************************************************** +; +; Print out the coordinates of the corners of the RAP domain. +; +; ********************************************************************** +; + nx = nx_RAP + ny = ny_RAP + + corner_i_inds := (/ 0, nx, nx, 0 /) + corner_j_inds := (/ 0, 0, ny, ny /) + num_corners = 4 + corner_lons := new(( num_corners ), "double") + corner_lats := new(( num_corners ), "double") + + do c=0, num_corners-1 + corner_lons(c) = lon_verts_RAP(corner_j_inds(c), corner_i_inds(c)) + corner_lats(c) = lat_verts_RAP(corner_j_inds(c), corner_i_inds(c)) + if (corner_lons(c) .gt. 180.0) then + corner_lons(c) = corner_lons(c) - 360.0 + end if + end do +;print("") +;print("lon = " + corner_lons + " deg; lat = " + corner_lats + " deg") +;pause + + print("") + print("RAP domain corner lon/lat coordinates are:") + do c=0, num_corners-1 + lon := corner_lons(c) + lat := corner_lats(c) + fmt_str = "%7.2f" + lon_str = sprintf(fmt_str, lon) + lat_str = sprintf(fmt_str, lat) + print("Corner " + (c+1) + ": lon = " + lon_str + " deg; lat = " + lat_str + " deg") + end do + + rem_x = mod(nx_RAP, 2) + rem_y = mod(ny_RAP, 2) + if ((rem_x .eq. 0) .and. (rem_y .eq. 0)) then + i_cntr = nx_RAP/2 + j_cntr = ny_RAP/2 + lon_RAP_cntr = lon_verts_RAP(j_cntr,i_cntr) + lat_RAP_cntr = lat_verts_RAP(j_cntr,i_cntr) + else if ((rem_x .eq. 1) .and. (rem_y .eq. 0)) then + i_cntr = (nx_RAP - 1)/2 + j_cntr = ny_RAP/2 + lon_vpts_RAP := fg->XLONG_V(:,:,:) + lat_vpts_RAP := fg->XLAT_V(:,:,:) + lon_vpts_RAP := todouble(rm_single_dims(lon_vpts_RAP)) + lat_vpts_RAP := todouble(rm_single_dims(lat_vpts_RAP)) + lon_RAP_cntr = lon_vpts_RAP(j_cntr,i_cntr) + lat_RAP_cntr = lat_vpts_RAP(j_cntr,i_cntr) + else if ((rem_x .eq. 0) .and. (rem_y .eq. 1)) then + i_cntr = nx_RAP/2 + j_cntr = (ny_RAP - 1)/2 + lon_upts_RAP := fg->XLONG_U(:,:,:) + lat_upts_RAP := fg->XLAT_U(:,:,:) + lon_upts_RAP := todouble(rm_single_dims(lon_upts_RAP)) + lat_upts_RAP := todouble(rm_single_dims(lat_upts_RAP)) + lon_RAP_cntr = lon_upts_RAP(j_cntr,i_cntr) + lat_RAP_cntr = lat_upts_RAP(j_cntr,i_cntr) + else if ((rem_x .eq. 1) .and. (rem_y .eq. 1)) then + i_cntr = (nx_RAP - 1)/2 + j_cntr = (ny_RAP - 1)/2 + lon_RAP_cntr = lon_cntrs_RAP(j_cntr,i_cntr) + lat_RAP_cntr = lat_cntrs_RAP(j_cntr,i_cntr) + end if + end if + end if + end if + + print("") + print("lon_RAP_cntr = " + lon_RAP_cntr + " deg") + print("lat_RAP_cntr = " + lat_RAP_cntr + " deg") + + end if ; end if draw_RAP_domain +; +; ********************************************************************** +; +; Open a workstation and specify the type of graphics file to generate. +; The type can be "ps", "pdf", "x11", "png", or "ncgm" (and maybe more). +; +; ********************************************************************** +; + if (.not. ismissing(idx_ncgm)) then + wks_type := "ncgm" + else if (.not. ismissing(idx_png)) then + wks_type := "png" + wks_type@wkWidth = 1000 + wks_type@wkHeight = 750 + end if + end if + + wks := gsn_open_wks(wks_type, fn_graphics) + +; Set the colormap. To see the various colormaps, go to: +; +; http://www.ncl.ucar.edu/Document/Graphics/color_table_gallery.shtml +; + gsn_define_colormap(wks, "BlAqGrYeOrReVi200") + +; +; ********************************************************************** +; +; Set contour plot resources and generate color contour plot. +; +; ********************************************************************** +; + print("") + print("#############################################################") + print("") + print("Generating plot in file:") + print(" " + fn_graphics + "." + graphics_type) + +; Specify resources. + rsrc = True + +; Maximize size of plot in frame. + rsrc@gsnMaximize = True + +; Use full colormap, but start at color index 24. + rsrc@gsnSpreadColors = True + rsrc@gsnSpreadColorStart = 24 + +; Turn on contour fill. + rsrc@cnFillOn = True +; Set the fill mode to "CellFill". This means each cell has a single +; color that represents the field value for that cell, and no interopla- +; tion is performed. Other values for this resource can be "AreaFill" +; and "RasterFill", but those require interoplation. + rsrc@cnFillMode = "CellFill" + +; Set sfXArray and sfYArray to the cell center coordinates. + rsrc@sfXArray = lon_cntrs_by_cell + rsrc@sfYArray = lat_cntrs_by_cell + +; Set sfXCellBounds and sfYCellBounds to the cell vertex coordinates. + rsrc@sfXCellBounds = lon_verts_by_cell + rsrc@sfYCellBounds = lat_verts_by_cell + +; Set sfDataArray to the field (which has one value per cell). + rsrc@sfDataArray = field_by_cell + +; If draw_tile_grid is True, then draw the cell edges. + if (draw_tile_grid) then + rsrc@cnCellFillEdgeColor = "black" + end if + +; Set the color for cells containing missing values. This is by default +; "transparent", but we repeat it here for clarity. + rsrc@cnMissingValFillColor = "transparent" + +; Specify opacity of cell colors. +; rsrc@cnFillOpacityF = 0.0 ; Transparent. +; rsrc@cnFillOpacityF = 0.35 + rsrc@cnFillOpacityF = 1.0 ; Opaque. + +; Turn off contour lines (we just want to see colors). + rsrc@cnLinesOn = False +; Turn off contour line labels. + rsrc@cnLineLabelsOn = False + +; rsrc@lbLabelBarOn = False + +; Prevent overlap of labelbar labels. Actually, the default value of +; lbLabelAutoStride is already True for NCL V6.1.0 and later. +; rsrc@lbLabelAutoStride = True +; Turn off labelbar box lines. +; rsrc@lbBoxLinesOn = False + +; Set the plot title. + rsrc@tiMainString = plot_title + plot_subtitle + +; Set the title font size. + rsrc@tiMainFontHeightF = 0.015 + +; Set the latitude and longitude of the center of the map projection co- +; ordinate system. + rsrc@mpCenterLonF = map_proj_ctr(0) + rsrc@mpCenterLatF = map_proj_ctr(1) + +; Set the map projection to use. For the Lambert equal-area projection, +; we rotate the projection such that it is centered at the North Pole. + if (.not. ismissing(idx_cyln)) then + rsrc@mpProjection = "CylindricalEquidistant" + else if (.not. ismissing(idx_ortho)) then + rsrc@mpProjection = "Orthographic" + else if (.not. ismissing(idx_lamb)) then + rsrc@mpProjection = "LambertEqualArea" + end if + end if + end if + +; Improve the resolution of the map outlines. Default is "LowRes". + rsrc@mpDataBaseVersion = "MediumRes" + +; Turn on map tickmarks. + rsrc@pmTickMarkDisplayMode = "Always" + +; If "subreg" is specified, plot only a subregion. Note that this has +; an effect only for the cylindrical-equidistant map projection. + if (isvar("subreg")) then + rsrc@mpMinLonF = lon_min + rsrc@mpMaxLonF = lon_max + rsrc@mpMinLatF = lat_min + rsrc@mpMaxLatF = lat_max + end if + +; Set the minimum and maximum countour levels to plot manually. +; Do this for the first time so it is consistent for all plots + if (itime.eq.0) then + cplot_min = floor(min((/ field_min, field_RAP_min /))) + print("field_min = " + field_min) + print("field_RAP_min = " + field_RAP_min) + print("cplot_min = " + cplot_min) + cplot_max = ceil(max((/ field_max, field_RAP_max /))) + print("") + print("field_max = " + field_max) + print("field_RAP_max = " + field_RAP_max) + print("cplot_max = " + cplot_max) + maxlev = 16 + mnmxint = nice_mnmxintvl( cplot_min, cplot_max, maxlev, False) + rsrc@cnLevelSelectionMode = "ManualLevels" + rsrc@cnMinLevelValF = mnmxint(0) + rsrc@cnMaxLevelValF = mnmxint(1) + rsrc@cnLevelSpacingF = mnmxint(2) + end if + +; Allow for spatially constant fields to be plotted. + rsrc@cnConstFEnableFill = True + rsrc@cnConstFLabelOn = False + +; Do not immediately draw the contour plot nor advance the frame because +; other objects might still need to be added to the plot. + rsrc@gsnDraw = False + rsrc@gsnFrame = False + +; Draw the color contour plot (along with a map). + map = gsn_csm_contour_map(wks, field_by_cell, rsrc) +; +; ********************************************************************** +; +; If draw_tile_bdy is specified as True, draw the boundary of each tile. +; +; ********************************************************************** +; + if (draw_tile_bdy) then + + resp := True + resp@gsLineColor = "blue" + resp@gsLineThicknessF = 4.0 +; +; Note that the graphical id returned by the gsn_add_polyline(...) for +; each tile must be saved at least until the plot is drawn. If it is +; overwritten by the id for the next tile, then the polyline that the +; overwritted graphical id represents will not be drawn. For that rea- +; son, we first define an array of graphical ids and then save the id +; for each tile in an element of the array. +; + id_tile_bdy := new((/ num_tiles_to_plot /), graphic) + do nn=0, num_tiles_to_plot-1 + n_tile = inds_tiles_to_plot(nn) +; print("Drawing boundary of tile #" + n_tile + "...") + id_tile_bdy(nn) = gsn_add_polyline( wks, map, \ + lon_bdy_by_tile(nn,:), lat_bdy_by_tile(nn,:), resp) + end do + + end if +; +; ********************************************************************** +; +; If draw_RAP_domain is specified as True, draw a contour plot on the +; RAP domain. +; +; ********************************************************************** +; + if (draw_RAP_domain) then + +; Specify resources. + rsrc_RAP = True + +; Maximize size of plot in frame. + rsrc_RAP@gsnMaximize = True + +; Use full colormap, but start at color index 24. + rsrc_RAP@gsnSpreadColors = True + rsrc_RAP@gsnSpreadColorStart = 24 + +; Turn on contour fill. + rsrc_RAP@cnFillOn = True +; Set the fill mode to "CellFill". This means each cell has a single +; color that represents the field value for that cell, and no interopla- +; tion is performed. Other values for this resource can be "AreaFill" +; and "RasterFill", but those require interoplation. + rsrc_RAP@cnFillMode = "CellFill" + +; Specify opacity of cell colors. + rsrc_RAP@cnFillOpacityF = 0.0 ; Transparent. +; rsrc_RAP@cnFillOpacityF = 0.35 +; rsrc_RAP@cnFillOpacityF = 1.0 ; Opaque. + +; Set sfXArray and sfYArray to the cell center coordinates. + rsrc_RAP@sfXArray = lon_cntrs_by_cell_RAP + rsrc_RAP@sfYArray = lat_cntrs_by_cell_RAP + +; Set sfXCellBounds and sfYCellBounds to the cell vertex coordinates. + rsrc_RAP@sfXCellBounds = lon_verts_by_cell_RAP + rsrc_RAP@sfYCellBounds = lat_verts_by_cell_RAP + +; Set sfDataArray to the field (which has one value per cell). + rsrc_RAP@sfDataArray = field_by_cell_RAP + +; If draw_RAP_grid is True, then draw the cell edges. + if (draw_RAP_grid) then + rsrc_RAP@cnCellFillEdgeColor = "red" + end if + +; Turn off contour lines (we just want to see colors). + rsrc_RAP@cnLinesOn = False +; Turn off contour line labels. + rsrc_RAP@cnLineLabelsOn = False + +; Prevent overlap of labelbar labels. Actually, the default value of +; lbLabelAutoStride is already True for NCL V6.1.0 and later. + rsrc_RAP@lbLabelAutoStride = True +; Turn off labelbar box lines. + rsrc_RAP@lbBoxLinesOn = False + +; Turn on map tickmarks. + rsrc_RAP@pmTickMarkDisplayMode = "Always" + +; Allow for spatially constant fields to be plotted. + rsrc_RAP@cnConstFEnableFill = True + rsrc_RAP@cnConstFLabelOn = False + +; Set the minimum and maximum countour levels to plot manually. + rsrc_RAP@lbLabelBarOn = False + rsrc_RAP@cnLevelSelectionMode = "ManualLevels" + rsrc_RAP@cnMinLevelValF = cplot_min + rsrc_RAP@cnMaxLevelValF = cplot_max + +; Do not immediately draw the contour plot nor advance the frame because +; other objects might still need to be added to the plot. + rsrc_RAP@gsnDraw = False + rsrc_RAP@gsnFrame = False + +; Draw the color contour plot (without a map since that has already been +; drawn above while generating the FV3 tiles). + map_RAP = gsn_csm_contour(wks, field_by_cell_RAP, rsrc_RAP) + +; If draw_RAP_bdy is set to True, draw a boundary around the RAP domain. + if (draw_RAP_bdy) then + resp := True + resp@gsLineColor = "red" + resp@gsLineThicknessF = 4.0 + id_RAP_bdy = gsn_add_polyline(wks, map, lon_bdy_RAP, lat_bdy_RAP, resp) + end if + +; Overlay the contour plot of the RAP domain on top of the one for the +; cubed-sphere tile(s). + overlay(map, map_RAP) + + end if ; end if draw_RAP_domain +; +; ********************************************************************** +; +; Draw the plot and advance the frame. +; +; ********************************************************************** +; + draw(map) + frame(wks) + + print("") + print("Done generating plot in file:") + print(" " + fn_graphics + "." + graphics_type) + + end do ; End of loop over times + end do ; End of loop over fields + +end + diff --git a/ush/NCL/plot_grid.ncl b/ush/NCL/plot_grid.ncl new file mode 100644 index 0000000000..4b1874fd36 --- /dev/null +++ b/ush/NCL/plot_grid.ncl @@ -0,0 +1,1209 @@ +; +; ********************************************************************** +; +; Type "ncl plot_grid.ncl 'help=True'" on the command line to obtain +; help for this script. +; +; ********************************************************************** +; + +; +; ********************************************************************** +; +; Declare global variables before loading files. This has the same ef- +; fect as declaring these variables on the command line. +; +; ********************************************************************** +; + +;help = True + +;run_dir = "ABCD" +;run_dir = "/home/Gerard/fv3_regional/fv3sar_workflow/ush/NCL" +;run_dir = "/scratch3/BMC/det/Gerard.Ketefian/UFS_CAM_test_instructions/expt_dirs/NX1734_NY1008_A0p21423_Kmns0p23209_HRRR_test_HRRRgrid02" +;run_dir = "/scratch3/BMC/det/Gerard.Ketefian/UFS_CAM_test_instructions/expt_dirs/NX1800_NY1120_A0p21423_Kmns0p23209_HRRR_test_cycl_slurm_01" + +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/regional_001_old001" +expt_dir = "/scratch2/BMC/det/beck/SAR-FV3/run_dirs/real_time2" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/regional_007" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/GFDLgrid_debug_verif" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/GFDLgrid_debug_verif_preprocess_good" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/GFDLgrid_AK_3km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/new_JPgrid" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/RTMA_grid_25km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/regional_003" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/GSD_RAP13km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/GSD_RAP13km_works02" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/RRFS_HRRR3km_from_regional_003" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/regional_002_GSD_HRRR3km" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/expt_dirs/nco_GSD_HRRR3km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_rrfs_v1beta/expt_dirs/regional_002" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_rrfs_v1beta/expt_dirs/FV3_RRFS_v1beta" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_rrfs_v1beta/expt_dirs/FV3_RRFS_v1beta_3km" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/regional_002_25km" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/regional_002_13km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_rrfs_v1beta/expt_dirs/subconus" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_rrfs_v1beta/expt_dirs/nco_GSD_SUBCONUS3km_HRRRX_RAPX_works01" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_WE2E_testing/expt_dirs/try13/regional_002" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_WE2E_testing/expt_dirs/try13/nco_GSD_HRRR3km_HRRRX_RAPX" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_WE2E_testing/expt_dirs/try15/suite_FV3_GSD_SAR_3km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_GSD_HRRR13km" + +CDATE="2017090712" +CDATE="2019052000" +;CDATE="2020031212" +;CDATE="2017090700" +CDATE="2019070100" +;CDATE="2020080100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/suite_FV3_GSD_SAR_3km_works03" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/suite_FV3_GSD_SAR_3km" +CDATE="2019052000" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_GSD_HRRR13km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_CONUS_13km" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_CONUS_13km_HRRRX_RAPX" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_13km_FV3GFS_FV3GFS" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try03/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +CDATE="2019070100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_13km_HRRRX_RAPX" +;CDATE="2020080100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try01/grid_RRFS_CONUS_3km_FV3GFS_FV3GFS" +;CDATE="2019070100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_SUBCONUS_3km" +;CDATE="2019070100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_CONUS_3km_GFDLgrid" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_maximize_CONUS_grids/expt_dirs/try02/grid_RRFS_CONUS_3km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +CDATE="2019070100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_CONUS_25km_GFDLgrid" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_bugfix_adjust_CONUS_grids/expt_dirs/try03/grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +;expt_dir = "/work/noaa/gsd-fv3-dev/gsketefia/UFS/PR_release_branch/expt_dirs/try02/grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_maximize_CONUS_grids/expt_dirs/try02/grid_RRFS_CONUS_25km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +;CDATE="2019070100" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/suite_FV3_GSD_SAR" +;CDATE="2019052000" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_AK_3km" +;expt_dir = "/work/noaa/gsd-fv3-dev/gsketefia/UFS/PR_release_branch/expt_dirs/try01/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_maximize_CONUS_grids/expt_dirs/try02/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +;CDATE="2019052000" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_AK_13km" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_feature_predef_grids/expt_dirs/try01/grid_RRFS_AK_13km_old001" +;expt_dir = "/work/noaa/gsd-fv3-dev/gsketefia/UFS/PR_release_branch/expt_dirs/try02/grid_RRFS_CONUS_13km_ics_FV3GFS_lbcs_FV3GFS_suite_GFS_v15p2" +;CDATE="2019052000" + +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_Jeff_Duda_subhourly_post/expt_dirs/big_grid01/grid_GSD_RAP13km_pregen" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_Jeff_Duda_subhourly_post/expt_dirs/big_grid02/grid_GSD_RAP13km_pregen" +;expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_Jeff_Duda_subhourly_post/expt_dirs/big_grid02/grid_GSD_RAP13km_pregen_old003" +expt_dir = "/scratch2/BMC/det/Gerard.Ketefian/UFS_CAM/PR_Jeff_Duda_subhourly_post/expt_dirs/big_grid02/grid_GSD_RAP13km" +CDATE="2019070100" + +run_dir = expt_dir + "/" + CDATE +print("AAAAAA run_dir = " + run_dir) + +;tile_inds := (/ 1, 7, 4 /) +;tile_inds := (/ 1, 4 /) +;tile_inds := (/ 5, 6 /) +;tile_inds := (/ 5, 7 /) +;tile_inds := (/ 5, 6, 7 /) +;tile_inds := (/ 5 /) +;tile_inds := (/ 6 /) +tile_inds := (/ 7 /) +;tile_inds := (/ 6, 7 /) + +;subreg_limits := (/ -180, 180, -90, 90 /) +;subreg_limits := (/ -75, -45, 30, 60 /) +;subreg_limits := (/ -145, -90, 30, 60 /) +;subreg_limits := (/ -120, -115, 30, 35 /) +;subreg_limits := (/ -15, 0, 0, 15 /) +;subreg_limits := (/ -30, 0, 0, 30 /) +;subreg_limits := (/ -60, -30, 0, 30 /) +;subreg_limits := (/ -75, -60, 0, 15 /) +;subreg_limits := (/ -70, -65, 5, 10 /) +;subreg_limits := (/ -55, -40, 45, 60 /) +;subreg_limits := (/ -50, -45, 50, 55 /) +;subreg_limits := (/ -10, 5, 0, 15 /) +;subreg_limits := (/ -2, 2, 0, 4 /) + +remove_rgnl_halo = True +;remove_rgnl_halo = False + +plot_RAP_field = True +;plot_RAP_field = False + +field_name_RAP = "XLAT_M" +;field_name_RAP = "cell_area" +;field_name_RAP = "VGTYP_P0_L1_GLC0" + +show_RAP_bdy = True +RAP_bdy_color = "red" + +RAP_dir = "/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509" +RAP_dir = "/scratch1/BMC/gsd-fv3-dev/Gerard.Ketefian/regional_FV3_EMC_visit_20180509" +;RAP_dir = "/work/noaa/gsd-fv3-dev/gsketefia/UFS" ; This is on Orion. +;RAP_grid_fn = "/home/Gerard/fv3_regional/fv3sar_workflow/ush/NCL/plot_grid.ncl" +;RAP_grid_fn = "/scratch3/BMC/fim/Gerard.Ketefian/regional_FV3_EMC_visit_20180509/geo_em.d01.RAP.nc" +RAP_grid_fn = RAP_dir + "/geo_em.d01.RAP.nc" +RAP_grid_fn = RAP_dir + "/geo_em.d01.HRRR.nc" + + +map_proj = "cyln" +;map_proj = "ortho" +; +; This should be set to (0,0) for "cyln" map projection. +; +map_proj_ctr = (/ 0.0, 0.0 /) ; This should be set to (0,0) for "cyln" map projection. +;map_proj_ctr = (/ -106.0, 54.0 /) ; RAP domain. +;map_proj_ctr = (/ -106.0, 84.0 /) ; RAP domain. +;map_proj_ctr = (/ 30.0, 60.0 /) ; RAP domain. +;map_proj_ctr = (/ -97.5, 38.5 /) ; HRRR domain. +;map_proj_ctr = (/ 6.0, 54.0 /) ; RAP domain corner. + +;map_proj_ctr = (/ -161.5, 63.0 /) ; Alaska + +;map_proj_ctr = (/ -98.5, 30.0 /) + + +plot_subreg = True +;plot_subreg = False + +subreg_limits := (/ -180, 180, -90, 90 /) +;subreg_limits := (/ -75, -45, 30, 60 /) +;subreg_limits := (/ -155, -45, 60, 90 /) +;subreg_limits := (/ -155, -45, 60, 100 /) +;subreg_limits := (/ -190, -170, 80, 100 /) +;subreg_limits := (/ -55, -45, 80, 90 /) +;subreg_limits := (/ 45, 55, 60, 70 /) +;subreg_limits := (/ 15, 45, 30, 50 /) + + +;subreg_limits := (/ -75, -45, -30, 0 /) ; +;subreg_limits := (/ -40, -35, 25, 30 /) ; + +; The following are to plot regions near the four corners and along two +; of the edges of GSD_RAP13km domain (soon to be renamed to RRFS_NA_13km) +; to ensure that the write-component grid is within the native grid. It's +; easiest to use map_proj = "cyln" to plot these subregions. +;subreg_limits := (/ -155, -130, -25, 0 /) ; +;subreg_limits := (/ -80, -55, -25, 0 /) ; +;subreg_limits := (/ -45, -20, 15, 40 /) +;subreg_limits := (/ 5, 30, 35, 60 /) +;subreg_limits := (/ 125, 150, 35, 60 /) +;subreg_limits := (/ -180, -155, 15, 40 /) + + +;subreg_limits := (/ -128, -67, 23, 51 /) ; HRRR domain if using "cyln" map projection. +;subreg_limits := (/ -135, -60, 20, 55 /) ; HRRR domain if using "cyln" map projection. +;subreg_limits := (/ -125, -70, 20, 55 /) ; HRRR domain if using "ortho" map projection. +;subreg_limits := (/ -105, -95, 20, 30 /) ; Center of southern edge of HRRR domain. + +;subreg_limits := (/ -128, -118, 32, 42 /) ; Center of western edge of HRRR domain. + +;subreg_limits := (/ -120, -75, 20, 55 /) ; Center of HRRR domain, zoomed. +;subreg_limits := (/ -110, -85, 30, 45 /) ; Center of HRRR domain, zoomed more. +;subreg_limits := (/ -100, -97, 36, 39 /) ; Center of HRRR domain, zoomed more. + +;subreg_limits := (/ -135, -60, 20, 55 /) + + + +; Zoom in on midpoint of southern edge of CONUS domain. +;subreg_limits := (/ -103.5, -93.5, 22.5, 26.5 /) ; 10deg x 4deg +;subreg_limits := (/ -100.0, -95.0, 24.0, 26.0 /) ; 5deg x 2deg +;subreg_limits := (/ -99.5, -97.5, 24, 25 /) ; 2deg x 1deg +;subreg_limits := (/ -99, -98, 24.15, 24.65 /) ; 1deg x 0.5deg + +; Zoom in on midpoint of eastern edge of CONUS domain. +;subreg_limits := (/ -71, -66, 33.5, 38.5 /) ; 5deg x 5deg + +; Zoom in on midpoint of northern edge of CONUS domain. +;subreg_limits := (/ -103.5, -93.5, 50.2, 54.2 /) ; 10deg x 4deg +;subreg_limits := (/ -100.0, -95.0, 51.3, 53.3 /) ; 5deg x 2deg +;subreg_limits := (/ -99.5, -97.5, 51.9, 52.9 /) ; 2deg x 1deg +;subreg_limits := (/ -99, -98, 52.3, 52.8 /) ; 1deg x 0.5deg + +; Zoom in on midpoint of western edge of CONUS domain. +;subreg_limits := (/ -128, -123, 33.5, 38.5 /) ; 5deg x 5deg + +; Zoom in on northwest corner of CONUS domain. +;subreg_limits := (/ -129, -99, 32, 52 /) ; 20deg x 20deg +;subreg_limits := (/ -131, -121, 40, 50 /) ; 10deg x 10deg +;subreg_limits := (/ -133, -128, 44, 49 /) ; 5deg x 5deg +;subreg_limits := (/ -133.5, -131.5, 46.2, 48.2 /) ; 2deg x 2deg +;subreg_limits := (/ -134, -133, 47, 48 /) ; 1deg x 1deg + +; Zoom in on southwest corner of CONUS domain. +;subreg_limits := (/ -125, -105, 22, 42 /) ; 20deg x 20deg +;subreg_limits := (/ -124, -114, 22, 32 /) ; 10deg x 10deg +;subreg_limits := (/ -124, -119, 21, 26 /) ; 5deg x 5deg +;subreg_limits := (/ -123.3, -121.3, 21.2, 23.2 /) ; 2deg x 2deg +;subreg_limits := (/ -123.1, -122.1, 21.2, 22.2 /) ; 1deg x 1deg +;subreg_limits := (/ -122.95, -122.45, 21.45, 21.95 /) ; 0.5deg x 0.5deg +;subreg_limits := (/ -122.9, -122.8, 21.45, 21.55 /) ; 0.1deg x 0.1deg +;subreg_limits := (/ -122.85, -122.83, 21.49, 21.51 /) ; 0.02deg x 0.02deg + +; Zoom in on southeast corner of CONUS domain. +;subreg_limits := (/ -88, -68, 18, 38 /) ; 20deg x 20deg +;subreg_limits := (/ -80, -70, 20, 30 /) ; 10deg x 10deg +;subreg_limits := (/ -76, -71, 21, 26 /) ; 5deg x 5deg +;subreg_limits := (/ -73.9, -71.9, 21.0, 23.0 /) ; 2deg x 2deg +;subreg_limits := (/ -73, -72, 21.2, 22.2 /) ; 1deg x 1deg +;subreg_limits := (/ -72.5, -72.0, 21.45, 21.95 /) ; 0.5deg x 0.5deg +;subreg_limits := (/ -72.25, -72.15, 21.45, 21.55 /) ; 0.1deg x 0.1deg +;subreg_limits := (/ -72.17, -72.15, 21.49, 21.51 /) ; 0.02deg x 0.02deg + +; Zoom in on northeast corner of CONUS domain. +;subreg_limits := (/ -78, -58, 32, 52 /) ; 20deg x 20deg +;subreg_limits := (/ -70, -60, 40, 50 /) ; 10deg x 10deg. +;subreg_limits := (/ -65.5, -60.5, 44, 49 /) ; 5deg x 5deg. +;subreg_limits := (/ -63.0, -61.0, 46.2, 48.2 /) ; 2deg x 2deg. +;subreg_limits := (/ -62.2, -61.2, 47, 48 /) ; 1deg x 1deg. + + + + +; EMC's 25km BIG CONUS grid. +;subreg_limits := (/ -145, -50, 10, 65 /) + +; Zoom in on northwest corner of BIG CONUS domain. +;subreg_limits := (/ -139, -136, 51, 54 /) ; 3deg x 3deg + +; Zoom in on southwest corner of BIG CONUS domain. +;subreg_limits := (/ -123, -120, 14, 17 /) ; 3deg x 3deg + +; Zoom in on southeast corner of BIG CONUS domain. +;subreg_limits := (/ -75, -72, 14, 17 /) ; 3deg x 3deg + +; Zoom in on northeast corner of BIG CONUS domain. +;subreg_limits := (/ -59, -56, 51, 54 /) ; 3deg x 3deg + + + + +; EMC's 3km BIG CONUS grid. +;subreg_limits := (/ -145, -50, 10, 65 /) + +; Zoom in on northwest corner of BIG CONUS domain. +;subreg_limits := (/ -137, -134, 47, 50 /) ; 3deg x 3deg + +; Zoom in on southwest corner of BIG CONUS domain. +;subreg_limits := (/ -125, -122, 18.5, 21.5 /) ; 3deg x 3deg + +; Zoom in on southeast corner of BIG CONUS domain. +;subreg_limits := (/ -74, -71, 18.5, 21.5 /) ; 3deg x 3deg + +; Zoom in on northeast corner of BIG CONUS domain. +;subreg_limits := (/ -61, -58, 47, 50 /) ; 3deg x 3deg + + + + +; Alaska domain subregions: +;subreg_limits := (/ -210, -120, 45, 80 /) ; whole AK domain; won't work with cyln projection + +; Zoom in on northwest corner of Alaska domain. +;subreg_limits := (/ 141, 145, 66, 70 /) ; 4deg x 4deg +;subreg_limits := (/ 142, 144, 66, 70 /) ; 2deg x 4deg +;subreg_limits := (/ 142, 144, 67, 69 /) ; 2deg x 2deg + +; Zoom in on southwest corner of Alaska domain. +;subreg_limits := (/ 170, 174, 44, 48 /) ; 4deg x 4deg +;subreg_limits := (/ 170, 173, 44, 47 /) ; 3deg x 3deg +;subreg_limits := (/ 171, 173, 45, 47 /) ; 2deg x 2deg + +; Zoom in on southeast corner of Alaska domain. +;subreg_limits := (/ -137, -133, 44, 48 /) ; 4deg x 4deg +;subreg_limits := (/ -136, -133, 44, 47 /) ; 3deg x 3deg +;subreg_limits := (/ -135.5, -133.5, 44.8, 46.8 /) ; 2deg x 2deg + +; Zoom in on northeast corner of Alaska domain. +;subreg_limits := (/ -108, -102, 65, 71 /) ; 6deg x 6deg +;subreg_limits := (/ -107, -103, 66, 70 /) ; 4deg x 4deg +;subreg_limits := (/ -106, -104, 66, 70 /) ; 2deg x 4deg +;subreg_limits := (/ -106, -104, 67, 69 /) ; 2deg x 2deg + + +;subreg_limits := (/ -135, -60, 15, 60 /) ; RTMA domain if using "ortho" map projection. +;subreg_limits := (/ -128, -126, 34, 36 /) ; Center of western boundary of CONUS + +;subreg_limits := (/ -15, 0, 0, 15 /) +;subreg_limits := (/ -30, 0, 0, 30 /) +;subreg_limits := (/ -60, -30, 0, 30 /) +;subreg_limits := (/ -75, -60, 0, 15 /) +;subreg_limits := (/ -70, -65, 5, 10 /) +;subreg_limits := (/ -55, -40, 45, 60 /) +;subreg_limits := (/ -50, -45, 50, 55 /) +;subreg_limits := (/ -10, 5, 0, 15 /) +;subreg_limits := (/ -2, 2, 0, 4 /) +;subreg_limits := (/ -90, -60, -20, 10 /) +;subreg_limits := (/ -80, -70, -10, 0 /) +;subreg_limits := (/ -85, -70, -15, 0 /) +;subreg_limits := (/ -76, -72, -12, -8 /) +;subreg_limits := (/ -75, -45, -15, 0 /) +;subreg_limits := (/ -63, -58, -15, -10 /) +;subreg_limits := (/ 15, 30, 30, 45 /) +;subreg_limits := (/ 14, 16, 36, 38 /) +;subreg_limits := (/ -70, -55, -20, -5 /) +;subreg_limits := (/ 10, 20, 30, 40 /) +;subreg_limits := (/ 15, 20, 30, 35 /) + + +horiz_dist_units = "m" +horiz_dist_units = "km" + +field_name = "area" +;field_name = "sqrt_area" +;field_name = "dx" +;field_name = "dy" +;field_name = "dx_ovr_dy" +;field_name = "min_dx_dy" +;field_name = "angle_dx" +;field_name = "angle_dy" + +;field_name = "abcd" + +field_name = "orog_raw" +;field_name = "orog_filt" + +;field_name = "time" +;field_name = "grid_xt" +;field_name = "vflx_ave" +;field_name = "ref3D" + +field_name = "sltyp" +field_name = "dswrf" +field_name = "zsurf" + + +show_tile_bdies = True +;show_tile_bdies = False + +show_tile_grids = True +;show_tile_grids = False + + +file_basename = "atmos_static" +;file_basename = "fv3_history" +file_basename = "fv3_history2d" + + +show_wrtcmp_grid = True +show_wrtcmp_grid = False + +show_wrtcmp_bdy = True +;show_wrtcmp_bdy = False + + +separator_line \ +:= "************************************************************************" +;:= "========================================================================" + + +; +; ********************************************************************** +; +; Load files. +; +; ********************************************************************** +; +lib_location = "lib/" + +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "repeat_str.ncl") +loadscript(lib_location + "calc_field_stats.ncl") +loadscript(lib_location + "get_rect_grid_bdy.ncl") +loadscript(lib_location + "set_cnLevels_lbLabels.ncl") +loadscript(lib_location + "append_to_snumeric_array.ncl") + +load "process_plot_params.ncl" +load "read_FV3LAM_grid_native.ncl" +load "read_FV3LAM_field_native.ncl" +load "read_FV3LAM_grid_wrtcmp.ncl" +load "read_FV3LAM_field_wrtcmp.ncl" +load "read_RAP_grid.ncl" +load "read_RAP_field.ncl" +load "plot_horiz_field.ncl" + +load "check_filevar_existence_dims.ncl" + +begin +; +; ********************************************************************** +; +; Set usage message. +; +; ********************************************************************** +; + usage_msg = \ +" ncl -n plot_grid.ncl \" + char_nl + \ +" 'help=False' \" + char_nl + \ +" 'grid_dir=" + char_dq + "./some_dir/grid" + char_dq + "' \" + char_nl + \ +" 'res=96' \" + char_nl + \ +" 'tile_inds=(/1,2,3/)' \" + char_nl + \ +" 'show_tile_bdies=True' \" + char_nl + \ +" 'show_tile_grids=True' \" + char_nl + \ +" 'plot_RAP_field=True' \" + char_nl + \ +" 'RAP_grid_fn=" + char_dq + "./some_dir/RAP_grid.nc" + char_dq + "' \" + char_nl + \ +" 'show_RAP_bdy=True' \" + char_nl + \ +" 'show_RAP_grid=True' \" + char_nl + \ +" 'map_proj=" + char_dq + "cyln" + char_dq + "' \" + char_nl + \ +" 'map_proj_ctr=(/0,90/)' \" + char_nl + \ +" 'subreg_limits=(/-30,30,-25,25/)' \" + char_nl + \ +" 'graphics_type=" + char_dq + "ncgm" + char_dq + "'" +; +; ********************************************************************** +; +; Set help message. The help message contains the documentation for +; this script and thus should reflect any changes to the code. +; +; ********************************************************************** +; + help_msg = char_nl + \ +"This script generates a 2-D color plot of one or more of the tiles on" + char_nl + \ +"a cubed-sphere grid on top of a map of the continents. Each tile is" + char_nl + \ +"depicted in the output graphics file as a uniformly colored region." + char_nl + \ +char_nl + \ +"An example of a call to this script from the command line is as fol-" + char_nl + \ +"lows:" + char_nl + \ +char_nl + \ +usage_msg + \ +char_nl + \ +char_nl + \ +"The output is a graphics file named" + char_nl + \ +char_nl + \ +" C[res]_grid.[ext]" + char_nl + \ +char_nl + \ +"where res is the specified resolution and ext is the graphics file ex-" + char_nl + \ +"tension (determined by the specified output graphics type graphics_-" + char_nl + \ +"type). The input arguments to this script are:" + char_nl + \ +char_nl + \ +"help:" + char_nl + \ +"This argument specifies whether or not to print out the documentation" + char_nl + \ +"for this script and exit. It is either True or False. Default is" + char_nl + \ +"False. If this is set to True, this script prints out the documenta-" + char_nl + \ +"tion and exits, ignoring all other arguments. To see the documenta-" + char_nl + \ +"tion, type " + char_dq + "ncl plot_grid.ncl 'help=True'" + char_dq + " on the command line in the" + char_nl + \ +"directory of this script." + char_nl + \ +char_nl + \ +"grid_dir:" + char_nl + \ +"This argument specifies the directory in which the grid files are lo-" + char_nl + \ +"cated. It is assumed that these are NetCDF files with names of the" + char_nl + \ +"form" + char_nl + \ +char_nl + \ +" C[res]_grid.tile[N].nc" + char_nl + \ +char_nl + \ +"where res is the resolution specified on the command line and N is the" + char_nl + \ +"tile number. The tile numbers to consider are specified by the input" + char_nl + \ +"argument tile_inds (see below). Default value is the current directo-" + char_nl + \ +"ry, i.e. " + char_dq + "./" + char_dq + "." + char_nl + \ +char_nl + \ +"res:" + char_nl + \ +"This argument specifies the cubed-sphere resolution, i.e. the number" + char_nl + \ +"of cells in each of the two horizontal directions on each of the 6" + char_nl + \ +"tiles of the global cubed-sphere grid. Valid values are: 48, 96, 192," + char_nl + \ +"384, 768, 1152, and 3072." + char_nl + \ +char_nl + \ +"tile_inds:" + char_nl + \ +"This argument specifies the indices of those tiles on the cubed-sphere" + char_nl + \ +"grid that are to be plotted. For example, to plot tiles 1, 3, and 5, " + char_nl + \ +"specify" + char_nl + \ +char_nl + \ +" tile_inds = (/ 1, 3, 5 /)" + char_nl + \ +char_nl + \ +"If this is not specified, all available tiles are plotted (where by " + char_nl + \ +char_dq + "available" + char_dq + ", we mean all tiles for which there exists a grid file in" + char_nl + \ +"grid_dir)." + char_nl + \ +char_nl + \ +"show_tile_bdies:" + char_nl + \ +"This argument specifies whether or not to draw the boundary of each " + char_nl + \ +"specified tile. It is either True or False. Default is True." + char_nl + \ +char_nl + \ +"show_tile_grids:" + char_nl + \ +"This argument specifies whether or not to draw the boundaries of all" + char_nl + \ +"grid cells on each tile that is being plotted. It is either True or " + char_nl + \ +"False. Default is False. For a high-resolution grid, this can make" + char_nl + \ +"it difficult to see the underlying color of the tile in the output" + char_nl + \ +"graphics file (because there would be many grid lines drawn very close" + char_nl + \ +"together)." + char_nl + \ +char_nl + \ +"plot_RAP_field:" + char_nl + \ +"This argument specifies whether or not to draw the original [i.e. pre-" + char_nl + \ +"FV3 RAP (RAPid Refresh) domain]. It is either True or False. Default" + char_nl + \ +"is False. If this is set to True, the RAP domain is added to the plot" + char_nl + \ +"as a uniformly colored region (with a color that is different from any" + char_nl + \ +"of the cubed-sphere tiles)." + char_nl + \ +char_nl + \ +"RAP_grid_fn:" + char_nl + \ +"This argument specifies the full (i.e. including directory) file name" + char_nl + \ +"of the NetCDF file that describes the RAP grid. This is used only if" + char_nl + \ +"plot_RAP_field is set to True." + char_nl + \ +"" + char_nl + \ +"show_RAP_bdy:" + char_nl + \ +"This argument specifies whether or not to draw the boundary of the RAP" + char_nl + \ +"domain. It is either True or False. Default is True. This has no" + char_nl + \ +"effect if plot_RAP_field is set to False." + char_nl + \ +char_nl + \ +"show_RAP_grid:" + char_nl + \ +"This argument specifies whether or not to draw the boundaries of all" + char_nl + \ +"grid cells on the RAP domain. It is either True or False. Default is" + char_nl + \ +"False. For a high-resolution RAP grid, setting this to True can make" + char_nl + \ +"it difficult to see the underlying color of the RAP domain in the out-" + char_nl + \ +"put graphics file (because there would be many grid lines drawn very" + char_nl + \ +"close together. This has no effect if plot_RAP_field is set to" + char_nl + \ +"False." + char_nl + \ +char_nl + \ +"map_proj:" + char_nl + \ +"This argument specifies the map projection to use for the plot. Valid" + char_nl + \ +"values are:" + char_nl + \ +char_nl + \ +" " + char_dq + "cyln" + char_dq + " - for cylindrical-equidistant projection" + char_nl + \ +" " + char_dq + "ortho" + char_dq + " - for orthographic (i.e. on a sphere) projection" + char_nl + \ +;" " + char_dq + "lamb" + char_dq + " - for Lambert equal-area projection" + char_nl + \ +" " + char_dq + "lamb" + char_dq + " - for Lambert conformal projection" + char_nl + \ +char_nl + \ +"If this argument is omitted, a cylindrical-equidistant projection is" + char_nl + \ +"used. " + char_nl + \ +char_nl + \ +"map_proj_ctr:" + char_nl + \ +"This argument specifies the point on the sphere at which to center the" + char_nl + \ +"map projection used for the plot. It consists of the point's longi-" + char_nl + \ +"tude and latitude (in degrees), as follows:" + char_nl + \ +char_nl + \ +" map_proj_ctr = (/ 30, 40 /)" + char_nl + \ +char_nl + \ +"If this is not specified, it is set to (/0,0/) for the cylindrical-" + char_nl + \ +"equidistant and orthographic (i.e. on a sphere) projections and to" + char_nl + \ +"(/0,90/) (i.e. the North Pole) for the Lambert equal-area projection." + char_nl + \ +char_nl + \ +"subreg_limits:" + char_nl + \ +"If using a cylindrical-equidistant map projection, this argument spe-" + char_nl + \ +"cifies the minimum and maximum longitudes and latitudes (in degrees)" + char_nl + \ +"of the subregion to plot. It has the format" + char_nl + \ +char_nl + \ +" subreg_limits = (/ lon_min, lon_max, lat_min, lat_max /)" + char_nl + \ +char_nl + \ +"where lon_min and lon_max are the minimum and maximum values of the" + char_nl + \ +"longitude and lat_min and lat_max are the minimum and maximum values" + char_nl + \ +"of the latitude. If this argument is omitted, the field is plotted on" + char_nl + \ +"the whole globe. It is ignored for projections other than cylindri-" + char_nl + \ +"cal-equidistant." + char_nl + \ +char_nl + \ +"graphics_type:" + char_nl + \ +"This argument specifies the type of graphics file to generate as out-" + char_nl + \ +"put. It can be either " + char_dq + "ncgm" + char_dq + " (NCAR Graphics) or " + char_dq + "png" + char_dq + ". Default is" + char_nl + \ +char_dq + "ncgm" + char_dq + "." + char_nl +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + plot_params := process_plot_params("plot_grid", usage_msg, help_msg) + + gtype = plot_params@gtype + num_tiles_to_plot = plot_params@num_tiles_to_plot + inds_tiles_to_plot = plot_params@inds_tiles_to_plot +;print("XXXXXXXXXXXXXXX") +;print("inds_tiles_to_plot = " + inds_tiles_to_plot) + + cres = plot_params@cres + expt_dir = plot_params@expt_dir + + horiz_dist_units = plot_params@horiz_dist_units + horiz_area_units = plot_params@horiz_area_units + + show_tile_bdies = plot_params@show_tile_bdies + tile_bdy_color = plot_params@tile_bdy_color + show_tile_grids = plot_params@show_tile_grids + field_name = plot_params@field_name + is_gridfield = plot_params@is_gridfield + file_basename = plot_params@file_basename + + show_RAP_bdy = plot_params@show_RAP_bdy + RAP_bdy_color = plot_params@RAP_bdy_color + show_RAP_grid = plot_params@show_RAP_grid + plot_RAP_field = plot_params@plot_RAP_field + field_name_RAP = plot_params@field_name_RAP + + graphics_type = plot_params@graphics_type + map_proj = plot_params@map_proj + map_proj_ctr = plot_params@map_proj_ctr + + remove_rgnl_halo = plot_params@remove_rgnl_halo + + plot_subreg = plot_params@plot_subreg + subreg_limits = plot_params@subreg_limits +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; +native = True +;native = False +native@plot_gridlines = True +native@plot_gridlines = False +;native@gridline_color = "black" +native@gridline_color = "red" +native@plot_bdy = True +native@bdy_color = native@gridline_color +native@bdy_line_thickness = 4.0 +;native@bdy_line_thickness = 16.0 +native@bdy_dash_pattern = 1 + +halo = True +;halo = False +halo@plot_gridlines = True +;halo@plot_gridlines = False +halo@gridline_color = "orange" +halo@plot_bdy = True +;halo@plot_bdy = False +halo@bdy_color = halo@gridline_color +halo@bdy_line_thickness = 4.0 +halo@bdy_dash_pattern = 1 + +wrtcmp = True +;wrtcmp = False +wrtcmp@plot_gridlines = True +wrtcmp@plot_gridlines = False +;wrtcmp@gridline_color = "green" +wrtcmp@gridline_color = "blue" +wrtcmp@plot_bdy = True +wrtcmp@bdy_color = wrtcmp@gridline_color +wrtcmp@bdy_line_thickness = 6.0 +wrtcmp@bdy_dash_pattern = 1 + +extrnl = True +extrnl = False +;extrnl@plot_gridlines = True +extrnl@plot_gridlines = False +;extrnl@gridline_color = "red" +extrnl@gridline_color = "green" +extrnl@plot_bdy = True +extrnl@bdy_color = extrnl@gridline_color +extrnl@bdy_line_thickness = 4.0 +extrnl@bdy_dash_pattern = 1 +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; +grid_opts = True +grid_opts@plot_gridlines := new(1, logical) +grid_opts@gridline_colors := new(1, string) + +bdy_opts = True +bdy_opts@num_bdies = 0 +bdy_opts@plot_bdy = new(1, logical) +bdy_opts@bdy_colors = new(1, string) +bdy_opts@bdy_line_thicknesses = new(1, float) +bdy_opts@bdy_dash_patterns = new(1, integer) +; +; ********************************************************************** +; +; Initialize arrays to single-element arrays. These will be appended to +; as necessary. +; +; ********************************************************************** +; +num_grids := 0 + +nx_all := new(1, integer) +ny_all := new(1, integer) +lon_cntrs_unstruc := new(1, double) +lat_cntrs_unstruc := new(1, double) +lon_verts_unstruc := new((/1,4/), double) +lat_verts_unstruc := new((/1,4/), double) +lon_bdy := new(1, double) +lat_bdy := new(1, double) +field_unstruc := new(1, double) +; +; ********************************************************************** +; +; If native is set to True, read in the native FV3LAM grid. +; +; ********************************************************************** +; +if (native .or. halo) then +;if (native) then + + num_grids = num_grids + 1 + + nhalo_T7 = 4 ; Should this be at the top, i.e. defined as a global variable???? + ; or be a requird input that gets processed along with the other + ; command linea arguments? + + grid_info := read_FV3LAM_grid_native( \ + expt_dir, \ + gtype, \ + cres, \ + inds_tiles_to_plot, \ + show_tile_bdies, \ + nhalo_T7, \ + remove_rgnl_halo) + + if (remove_rgnl_halo) then + nx_all := append_to_snumeric_array(nx_all, grid_info@nx_all_tiles) + ny_all := append_to_snumeric_array(ny_all, grid_info@ny_all_tiles) + else + nx_all := append_to_snumeric_array(nx_all, grid_info@nxh_all_tiles) + ny_all := append_to_snumeric_array(ny_all, grid_info@nyh_all_tiles) + end if + + lon_cntrs_unstruc \ + := append_to_snumeric_array(lon_cntrs_unstruc, grid_info@lon_cntrs_all_tiles_unstruc) + lat_cntrs_unstruc \ + := append_to_snumeric_array(lat_cntrs_unstruc, grid_info@lat_cntrs_all_tiles_unstruc) + + lon_verts_unstruc \ + := append_to_snumeric_array(lon_verts_unstruc, grid_info@lon_verts_all_tiles_unstruc) + lat_verts_unstruc \ + := append_to_snumeric_array(lat_verts_unstruc, grid_info@lat_verts_all_tiles_unstruc) + + lon_bdy := append_to_snumeric_array(lon_bdy, grid_info@lon_bdy_all_tiles) + lat_bdy := append_to_snumeric_array(lat_bdy, grid_info@lat_bdy_all_tiles) + + grid_opts@plot_gridlines \ + := array_append_record(grid_opts@plot_gridlines, native@plot_gridlines, 0) + grid_opts@gridline_colors \ + := array_append_record(grid_opts@gridline_colors, native@gridline_color, 0) + + if (native@plot_bdy) then + bdy_opts@num_bdies = bdy_opts@num_bdies + 1 + bdy_opts@plot_bdy \ + := array_append_record(bdy_opts@plot_bdy, native@plot_bdy, 0) + bdy_opts@bdy_colors \ + := array_append_record(bdy_opts@bdy_colors, native@bdy_color, 0) + bdy_opts@bdy_line_thicknesses \ + := array_append_record(bdy_opts@bdy_line_thicknesses, native@bdy_line_thickness, 0) + bdy_opts@bdy_dash_patterns \ + := array_append_record(bdy_opts@bdy_dash_patterns, native@bdy_dash_pattern, 0) + end if + +end if +; +; ********************************************************************** +; +; If halo is set to True, then ... +; +; ********************************************************************** +; +if (halo) then + + num_grids = num_grids + 1 + +; nhalo_T7 = 4 ; Should this be at the top, i.e. defined as a global variable???? +; ; or be a requird input that gets processed along with the other +; ; command linea arguments? +; +; grid_info := read_FV3LAM_grid_native( \ +; expt_dir, \ +; gtype, \ +; cres, \ +; inds_tiles_to_plot, \ +; show_tile_bdies, \ +; nhalo_T7, \ +; False) + + nx_all := append_to_snumeric_array(nx_all, grid_info@nxh_all_tiles) + ny_all := append_to_snumeric_array(ny_all, grid_info@nyh_all_tiles) + + lon_cntrs_unstruc \ + := append_to_snumeric_array(lon_cntrs_unstruc, grid_info@lon_halo_cntrs_all_tiles_unstruc) + lat_cntrs_unstruc \ + := append_to_snumeric_array(lat_cntrs_unstruc, grid_info@lat_halo_cntrs_all_tiles_unstruc) + + lon_verts_unstruc \ + := append_to_snumeric_array(lon_verts_unstruc, grid_info@lon_halo_verts_all_tiles_unstruc) + lat_verts_unstruc \ + := append_to_snumeric_array(lat_verts_unstruc, grid_info@lat_halo_verts_all_tiles_unstruc) + + lon_bdy := append_to_snumeric_array(lon_bdy, grid_info@lon_halo_bdy_all_tiles) + lat_bdy := append_to_snumeric_array(lat_bdy, grid_info@lat_halo_bdy_all_tiles) + + grid_opts@plot_gridlines \ + := array_append_record(grid_opts@plot_gridlines, halo@plot_gridlines, 0) + grid_opts@gridline_colors \ + := array_append_record(grid_opts@gridline_colors, halo@gridline_color, 0) + + if (halo@plot_bdy) then + bdy_opts@num_bdies = bdy_opts@num_bdies + 1 + bdy_opts@plot_bdy \ + := array_append_record(bdy_opts@plot_bdy, halo@plot_bdy, 0) + bdy_opts@bdy_colors \ + := array_append_record(bdy_opts@bdy_colors, halo@bdy_color, 0) + bdy_opts@bdy_line_thicknesses \ + := array_append_record(bdy_opts@bdy_line_thicknesses, halo@bdy_line_thickness, 0) + bdy_opts@bdy_dash_patterns \ + := array_append_record(bdy_opts@bdy_dash_patterns, halo@bdy_dash_pattern, 0) + end if + +end if +; +; ********************************************************************** +; +; If wrtcmp is set to True, read in the write-component grid. +; +; ********************************************************************** +; +if (wrtcmp) then + + num_grids = num_grids + 1 + + FV3LAM_wrtcmp_fn = run_dir + "/" + "dynf000.nc" + get_domain_bdy = True + grid_info := read_FV3LAM_grid_wrtcmp( \ + FV3LAM_wrtcmp_fn, \ + get_domain_bdy) + + nx_all := append_to_snumeric_array(nx_all, grid_info@nx) + ny_all := append_to_snumeric_array(ny_all, grid_info@ny) + + lon_cntrs_unstruc \ + := append_to_snumeric_array(lon_cntrs_unstruc, grid_info@lon_cntrs_unstruc) + lat_cntrs_unstruc \ + := append_to_snumeric_array(lat_cntrs_unstruc, grid_info@lat_cntrs_unstruc) + + lon_verts_unstruc \ + := append_to_snumeric_array(lon_verts_unstruc, grid_info@lon_verts_unstruc) + lat_verts_unstruc \ + := append_to_snumeric_array(lat_verts_unstruc, grid_info@lat_verts_unstruc) + + lon_bdy := append_to_snumeric_array(lon_bdy, grid_info@lon_bdy) + lat_bdy := append_to_snumeric_array(lat_bdy, grid_info@lat_bdy) + + grid_opts@plot_gridlines \ + := array_append_record(grid_opts@plot_gridlines, wrtcmp@plot_gridlines, 0) + grid_opts@gridline_colors \ + := array_append_record(grid_opts@gridline_colors, wrtcmp@gridline_color, 0) + + if (wrtcmp@plot_bdy) then + bdy_opts@num_bdies = bdy_opts@num_bdies + 1 + bdy_opts@plot_bdy \ + := array_append_record(bdy_opts@plot_bdy, wrtcmp@plot_bdy, 0) + bdy_opts@bdy_colors \ + := array_append_record(bdy_opts@bdy_colors, wrtcmp@bdy_color, 0) + bdy_opts@bdy_line_thicknesses \ + := array_append_record(bdy_opts@bdy_line_thicknesses, wrtcmp@bdy_line_thickness, 0) + bdy_opts@bdy_dash_patterns \ + := array_append_record(bdy_opts@bdy_dash_patterns, wrtcmp@bdy_dash_pattern, 0) + end if + +end if + +print("") +printVarSummary(wrtcmp) +; +; ********************************************************************** +; +; If extrnl is set to True, read in the FV3LAM grid. +; +; ********************************************************************** +; +if (extrnl) then + + num_grids = num_grids + 1 + + grid_info := read_RAP_grid(RAP_grid_fn, show_RAP_bdy) + + nx_all := append_to_snumeric_array(nx_all, grid_info@nx) + ny_all := append_to_snumeric_array(ny_all, grid_info@ny) + + lon_cntrs_unstruc \ + := append_to_snumeric_array(lon_cntrs_unstruc, grid_info@lon_cntrs_unstruc) + lat_cntrs_unstruc \ + := append_to_snumeric_array(lat_cntrs_unstruc, grid_info@lat_cntrs_unstruc) + + lon_verts_unstruc \ + := append_to_snumeric_array(lon_verts_unstruc, grid_info@lon_verts_unstruc) + lat_verts_unstruc \ + := append_to_snumeric_array(lat_verts_unstruc, grid_info@lat_verts_unstruc) + + lon_bdy := append_to_snumeric_array(lon_bdy, grid_info@lon_bdy) + lat_bdy := append_to_snumeric_array(lat_bdy, grid_info@lat_bdy) + + grid_opts@plot_gridlines \ + := array_append_record(grid_opts@plot_gridlines, extrnl@plot_gridlines, 0) + grid_opts@gridline_colors \ + := array_append_record(grid_opts@gridline_colors, extrnl@gridline_color, 0) + + if (extrnl@plot_bdy) then + bdy_opts@num_bdies = bdy_opts@num_bdies + 1 + bdy_opts@plot_bdy \ + := array_append_record(bdy_opts@plot_bdy, extrnl@plot_bdy, 0) + bdy_opts@bdy_colors \ + := array_append_record(bdy_opts@bdy_colors, extrnl@bdy_color, 0) + bdy_opts@bdy_line_thicknesses \ + := array_append_record(bdy_opts@bdy_line_thicknesses, extrnl@bdy_line_thickness, 0) + bdy_opts@bdy_dash_patterns \ + := array_append_record(bdy_opts@bdy_dash_patterns, extrnl@bdy_dash_pattern, 0) + end if + +end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; +nx_all := nx_all(1:) +ny_all := ny_all(1:) +lon_cntrs_unstruc := lon_cntrs_unstruc(1:) +lat_cntrs_unstruc := lat_cntrs_unstruc(1:) +lon_verts_unstruc := lon_verts_unstruc(1:,:) +lat_verts_unstruc := lat_verts_unstruc(1:,:) +lon_bdy := lon_bdy(1:) +lat_bdy := lat_bdy(1:) +;field_unstruc := new(1, double) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; +n := dimsizes(grid_opts@plot_gridlines) +if (n .gt. 1) then + grid_opts@plot_gridlines := grid_opts@plot_gridlines(1:) + grid_opts@gridline_colors := (/ grid_opts@gridline_colors(1:) /) +end if + +bdy_opts@plot_bdy := (/ bdy_opts@plot_bdy(1:) /) +bdy_opts@bdy_colors := bdy_opts@bdy_colors(1:) +bdy_opts@bdy_line_thicknesses := bdy_opts@bdy_line_thicknesses(1:) +bdy_opts@bdy_dash_patterns := bdy_opts@bdy_dash_patterns(1:) +bdy_opts@num_bdy_pts_all_bdies := 2*(nx_all + ny_all) + 1 + +print("") +printVarSummary(grid_opts) +print("") +printVarSummary(bdy_opts) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + +;grid_opts := True +;grid_opts@plot_gridlines := new(1, logical) +;grid_opts@gridline_colors := new(1, string) +; +;bdy_opts := True +;bdy_opts@num_bdies = 0 +;bdy_opts@plot_bdy = new(1, logical) +;bdy_opts@bdy_colors = new(1, string) +;bdy_opts@bdy_line_thicknesses = new(1, float) +;bdy_opts@bdy_dash_patterns = new(1, integer) + + +;print("AAAAAA native = " + native) +;if (native) then +; +; grid_opts@plot_gridlines \ +; := array_append_record(grid_opts@plot_gridlines, native@plot_gridlines, 0) +; grid_opts@gridline_colors \ +; := array_append_record(grid_opts@gridline_colors, native@gridline_color, 0) +; +; if (native@plot_bdy) then +; bdy_opts@num_bdies = bdy_opts@num_bdies + 1 +; bdy_opts@plot_bdy \ +; := array_append_record(bdy_opts@plot_bdy, native@plot_bdy, 0) +; bdy_opts@bdy_colors \ +; := array_append_record(bdy_opts@bdy_colors, native@bdy_color, 0) +; bdy_opts@bdy_line_thicknesses \ +; := array_append_record(bdy_opts@bdy_line_thicknesses, native@bdy_line_thickness, 0) +; bdy_opts@bdy_dash_patterns \ +; := array_append_record(bdy_opts@bdy_dash_patterns, native@bdy_dash_pattern, 0) +; end if +; +;end if + +;print("AAAAAA wrtcmp = " + wrtcmp) +;if (wrtcmp) then +; +; grid_opts@plot_gridlines \ +; := array_append_record(grid_opts@plot_gridlines, wrtcmp@plot_gridlines, 0) +; grid_opts@gridline_colors \ +; := array_append_record(grid_opts@gridline_colors, wrtcmp@gridline_color, 0) +; +; if (wrtcmp@plot_bdy) then +; bdy_opts@num_bdies = bdy_opts@num_bdies + 1 +; bdy_opts@plot_bdy \ +; := array_append_record(bdy_opts@plot_bdy, wrtcmp@plot_bdy, 0) +; bdy_opts@bdy_colors \ +; := array_append_record(bdy_opts@bdy_colors, wrtcmp@bdy_color, 0) +; bdy_opts@bdy_line_thicknesses \ +; := array_append_record(bdy_opts@bdy_line_thicknesses, wrtcmp@bdy_line_thickness, 0) +; bdy_opts@bdy_dash_patterns \ +; := array_append_record(bdy_opts@bdy_dash_patterns, wrtcmp@bdy_dash_pattern, 0) +; end if +; +;end if + +;print("AAAAAA extrnl = " + extrnl) +;if (extrnl) then +; +; grid_opts@plot_gridlines +; := array_append_record(grid_opts@plot_gridlines, extrnl@plot_gridlines, 0) +; grid_opts@gridline_colors \ +; := array_append_record(grid_opts@gridline_colors, extrnl@gridline_color, 0) +; +; if (extrnl@plot_bdy) then +; bdy_opts@num_bdies = bdy_opts@num_bdies + 1 +; bdy_opts@plot_bdy \ +; := array_append_record(bdy_opts@plot_bdy, extrnl@plot_bdy, 0) +; bdy_opts@bdy_colors \ +; := array_append_record(bdy_opts@bdy_colors, extrnl@bdy_color, 0) +; bdy_opts@bdy_line_thicknesses \ +; := array_append_record(bdy_opts@bdy_line_thicknesses, extrnl@bdy_line_thickness, 0) +; bdy_opts@bdy_dash_patterns \ +; := array_append_record(bdy_opts@bdy_dash_patterns, extrnl@bdy_dash_pattern, 0) +; end if +; +;end if + +;print("") +;printVarSummary(grid_opts) +; +;n := dimsizes(grid_opts@plot_gridlines) +;if (n .gt. 1) then +; grid_opts@plot_gridlines := grid_opts@plot_gridlines(1:) +; grid_opts@gridline_colors := (/ grid_opts@gridline_colors(1:) /) +;end if +; +;bdy_opts@plot_bdy := (/ bdy_opts@plot_bdy(1:) /) +;bdy_opts@bdy_colors := bdy_opts@bdy_colors(1:) +;bdy_opts@bdy_line_thicknesses := bdy_opts@bdy_line_thicknesses(1:) +;bdy_opts@bdy_dash_patterns := bdy_opts@bdy_dash_patterns(1:) +;bdy_opts@num_bdy_pts_all_bdies = 2*(nx_all + ny_all) + 1 +; +;print("") +;printVarSummary(grid_opts) +;print("") +;printVarSummary(bdy_opts) + +;exit +; +; ********************************************************************** +; +; Set general plotting options that will be passed to the plotting func- +; tion. +; +; ********************************************************************** +; + plot_opts := True + + plot_opts@map_proj = map_proj + plot_opts@map_proj_ctr = map_proj_ctr +; +; Set the flag that determines whether plots will be resized (e.g. to a +; larger area than the default). This would generally be done using the +; gsnMaximize resource, but it's not clear how to use or reset this re- +; source after adding annotations to the plot (annotations in our case +; are the plot titles). Thus, we perform the resizing/maximization man- +; ually. +; + plot_opts@resize_plot = True +; +; Set the size (either width or height) of the bounding box which the +; resized plot will have. Note that this is in NDC (non-dimensional co- +; ordinate, aka page) coordinates. This value must be between 0 and 1. +; + plot_opts@bounding_box_size_NDC = 0.98 + + if (plot_subreg) then + plot_opts@plot_subreg = plot_subreg + plot_opts@subreg_limits = subreg_limits + end if + +;left_str = "AAA" +;main_str = "BBB" +;right_str = "CCC" +left_str = "" +main_str = "" +right_str = "" + + plot_opts@left_str = left_str + plot_opts@main_str = main_str + plot_opts@right_str = right_str +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; +nx_big = sum(nx_all) +ny_big = sum(ny_all) +field_unstruc := new(nx_big*ny_big, double) + + field_min := min(field_unstruc) + field_max := max(field_unstruc) + +;print("field_min = " + field_min) +;print("field_max = " + field_max) +;pause + + print("") + print("" + separator_line) + msg := \ +"Calculating " + char_dq + "nice" + char_dq + " contour values from " + \ +"the field's minimum and maximum " + char_nl + \ +"values ..." + print("" + msg) + +; num_cnLevels = 20 + num_cnLevels = 250 + opts := True +; opts@verbose = True + opts@verbose = False + contour_info := set_cnLevels_lbLabels( \ + field_min, field_max, num_cnLevels, opts) + copy_VarAtts(contour_info, plot_opts) + + print("") + print("Done calculating " + char_dq + "nice" + char_dq + " contour values.") + print("" + separator_line) + +; fn_graphics = cres + "_grid_f" + fcst_hr_str + "_k" + vert_indx_str + fn_graphics = cres + "_grids" + plot_info := plot_horiz_field( \ + fn_graphics, \ + nx_all, ny_all, \ + lon_cntrs_unstruc, lat_cntrs_unstruc, \ + lon_verts_unstruc, lat_verts_unstruc, \ + lon_bdy, lat_bdy, \ + field_unstruc, \ + grid_opts, \ + bdy_opts, \ + plot_opts) + + +print("") +print("BYE") +exit + + +end + + + + + + diff --git a/ush/NCL/plot_horiz_field.ncl b/ush/NCL/plot_horiz_field.ncl new file mode 100644 index 0000000000..35d9ca2122 --- /dev/null +++ b/ush/NCL/plot_horiz_field.ncl @@ -0,0 +1,1093 @@ +; +; ********************************************************************** +; +; File name: plot_horiz_field.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "get_resized_viewport_dims.ncl") + +undef("plot_horiz_field") + +function plot_horiz_field( \ + graphics_fn:string, \ + nx_all_grids:integer, \ + ny_all_grids:integer, \ + lon_cntrs_unstruc:snumeric, \ + lat_cntrs_unstruc:snumeric, \ + lon_verts_unstruc:snumeric, \ + lat_verts_unstruc:snumeric, \ + lon_bdy_all_bdies:snumeric, \ + lat_bdy_all_bdies:snumeric, \ + field_unstruc:snumeric, \ + grid_opts:logical, \ + bdy_opts:logical, \ + plot_opts:logical) + +local valid_map_projs, valid_vals, msg, \ + num_grids, num_cells_all_grids, indx_start, indx_end, i, \ + wks_type, wks, \ + all_fields_missing, \ + rsrc, \ + lon_cntrs_crnt_grid_unstruc, lat_cntrs_crnt_grid_unstruc, \ + lon_verts_crnt_grid_unstruc, lat_verts_crnt_grid_unstruc, \ + field_crnt_grid_unstruc, \ + field_missing, \ + contour_map, contour_overlay, \ + vpXF, vpYF, vpWidthF, vpHeightF, \ + FontHeightF_LR, FontColor_LR, FontHeightF_C, FontColor_C, \ + dx_vert_offset_ndc, amOrthogonalPosF_LR, \ + txres, amres, \ + txid_left_str, annotid_left_str, \ + vpXF_left_str, vpYF_left_str, vpWF_left_str, vpHF_left_str, \ + txid_right_str, annotid_right_str, \ + vpXF_right_str, vpYF_right_str, vpWF_right_str, vpHF_right_str, \ + height_max, amOrthogonalPosF_cntr, \ + txid_cntr_str, annotid_cntr_str, \ + pmAnnoViews, lb_object, \ + lbar_x, lbar_y, lbar_h, lbar_w, lbar_fh, \ + opts, \ + viewport_info, vpXF_new, vpYF_new, vpWidthF_new, vpHeightF_new, \ + num_bdies, show_grid_bdy, temp, \ + bdy_indx_start, bdy_indx_end, id_grid_bdies, \ + resp, lon_crnt_bdy, lat_crnt_bdy, \ + plot_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; If the map projection (map_proj) has not been specified as an attrib- +; ute of plot_opts, set it to a default value. +; +; ********************************************************************** +; + if (.not. isatt(plot_opts, "map_proj")) then + plot_opts@map_proj = "cyln" + end if +; +; ********************************************************************** +; +; Verify that plot_opts@map_proj is set to a valid value. +; +; ********************************************************************** +; + valid_map_projs = (/ "cyln", "ortho", "lamb" /) + + if (.not. strcmp_exact(valid_map_projs, plot_opts@map_proj)) then + + valid_vals \ + := char_dq \ + + str_join(valid_map_projs, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"The map projection (plot_opts@map_proj) is not set to a valid value:" + char_nl + \ +" plot_opts@map_proj = " + char_dq + plot_opts@map_proj + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please provide a valid map projection. " + \ +"Stopping." + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; If the center of the specified map projection (map_proj_ctr) has not +; been specified as an attibute of plot_opts, set it to a default that +; depends on the map projection. map_proj_ctr should be a 1-D array +; having two elements. These two elements are the longitude (in degrees +; east) and latitude (in degrees north), respectively of the center of +; the map projection. +; +; ********************************************************************** +; + if (.not. isatt(plot_opts, "map_proj_ctr")) then + + plot_opts@map_proj_ctr = new((/ 2 /), "float") + + if (strcmp_exact(plot_opts@map_proj, "cyln")) then + plot_opts@map_proj_ctr(0) = 0. + plot_opts@map_proj_ctr(1) = 0. + else if (strcmp_exact(plot_opts@map_proj, "ortho")) then + plot_opts@map_proj_ctr(0) = 0. + plot_opts@map_proj_ctr(1) = 0. + else if (strcmp_exact(plot_opts@map_proj, "lamb")) then + plot_opts@map_proj_ctr(0) = 0. + plot_opts@map_proj_ctr(1) = 90. + end if + end if + end if + + end if +; +; ********************************************************************** +; +; If left_str and right_str have not been specified as attributes of +; plot_opts, set them to default values. +; +; ********************************************************************** +; + if (.not. isatt(plot_opts, "left_str")) then + plot_opts@left_str = "" + end if + + if (.not. isatt(plot_opts, "right_str")) then + plot_opts@right_str = "" + end if +; +; ********************************************************************** +; +; If plot_subreg has not been specified as an attribute of plot_opts, +; set it to a default value. +; +; ********************************************************************** +; + if (.not. isatt(plot_opts, "plot_subreg")) then + plot_opts@plot_subreg = False + end if +; +; ********************************************************************** +; +; Calculate the starting and ending indices in the unstructured coordi- +; nate and field arrays of the data for each grid. +; +; ********************************************************************** +; + num_grids = dimsizes(nx_all_grids) + num_cells_all_grids := nx_all_grids*ny_all_grids + + indx_start := new(num_grids, "integer") + indx_end := new(num_grids, "integer") + +print("num_grids = " + num_grids) +;pause + do i=0, num_grids-1 + if (i .eq. 0) then + indx_start(i) = 0 + else + indx_start(i) = sum(num_cells_all_grids(0:i-1)) + end if + indx_end(i) = sum(num_cells_all_grids(0:i)) - 1 + end do + +print("") +print("(nx_all_grids, ny_all_grids) = " + \ + "(" + nx_all_grids + ", " + ny_all_grids + ")") +pause +; +; ********************************************************************** +; +; Set workstation file type and dimensions and open the workstation. +; +; ********************************************************************** +; + wks_type := "png" + wks_type@wkWidth = 1000 + wks_type@wkHeight = 750 + wks := gsn_open_wks(wks_type, graphics_fn) +; +; ********************************************************************** +; +; Set the colormap. To see the various colormaps, go to: +; +; http://www.ncl.ucar.edu/Document/Graphics/color_table_gallery.shtml +; +; ********************************************************************** +; +; gsn_define_colormap(wks, "BlAqGrYeOrReVi200") + gsn_define_colormap(wks, "3gauss") + + print("") + print("" + separator_line) + print("Generating plot in graphics file:") + print(" graphics_fn = " + char_dq + graphics_fn + "." + wks_type + char_dq) +; +; ********************************************************************** +; +; Set the flag that indicates whether fields on all grids have missing +; values everywhere. If this flag gets set to True, reset the contour +; levels and labelbar (colorbar) labels to indicate that there are no +; valid values in the fields. +; +; ********************************************************************** +; + all_fields_missing := all(ismissing(field_unstruc)) + + if (all_fields_missing) then + plot_opts@cnLevels := default_fillvalue(typeof(field_unstruc)) + plot_opts@lbLabels := "No Valid Field Values" + end if +; +; ********************************************************************** +; +; Set contour plot resources and generate color contour plot. +; +; ********************************************************************** +; + do i=0, num_grids-1 + +print("") +print("i = " + i) +print("indx_start(i) = " + indx_start(i)) +print("indx_end(i) = " + indx_end(i)) +; +; Initialize variable that specifies plot resources. +; + rsrc := True +; +; Use full colormap, but start at color index 24. +; + rsrc@gsnSpreadColors = True + rsrc@gsnSpreadColorStart = 24 +; +; Turn on contour fill. This causes the regions between contour levels +; to be filled with a solid color and/or, if the fill method permits it, +; a fill pattern. +; + rsrc@cnFillOn = True +; +; Set the fill mode to "CellFill". This means each cell has a single +; color that represents the field value for that cell, and no interpola- +; tion is performed. Other values for this resource can be "AreaFill" +; and "RasterFill", but those require interoplation. +; + rsrc@cnFillMode = "CellFill" +; +; Set sfXArray and sfYArray to the cell center coordinates. +; + lon_cntrs_crnt_grid_unstruc \ + := lon_cntrs_unstruc(indx_start(i):indx_end(i)) +;print("dimsizes(lon_cntrs_crnt_grid_unstruc) = " + dimsizes(lon_cntrs_crnt_grid_unstruc)) + lat_cntrs_crnt_grid_unstruc \ + := lat_cntrs_unstruc(indx_start(i):indx_end(i)) +;print("dimsizes(lat_cntrs_crnt_grid_unstruc) = " + dimsizes(lat_cntrs_crnt_grid_unstruc)) + + rsrc@sfXArray = lon_cntrs_crnt_grid_unstruc + rsrc@sfYArray = lat_cntrs_crnt_grid_unstruc +; +; Set sfXCellBounds and sfYCellBounds to the cell vertex coordinates. +; These resources must be set in order if the cnFillMode resource is set +; to "CellFill". +; +;print("XXXXXXXXXXXXXXXXXXXXXXXXXXXX") +;print("dimsizes(lon_verts_unstruc) = " + dimsizes(lon_verts_unstruc)) +;print("indx_start(i) = " + indx_start(i)) +;print("indx_end(i) = " + indx_end(i)) +;pause + lon_verts_crnt_grid_unstruc \ + := lon_verts_unstruc(indx_start(i):indx_end(i),:) +;print("dimsizes(lon_verts_crnt_grid_unstruc) = " + dimsizes(lon_verts_crnt_grid_unstruc)) + lat_verts_crnt_grid_unstruc \ + := lat_verts_unstruc(indx_start(i):indx_end(i),:) +;print("dimsizes(lat_verts_crnt_grid_unstruc) = " + dimsizes(lat_verts_crnt_grid_unstruc)) + + rsrc@sfXCellBounds = lon_verts_crnt_grid_unstruc + rsrc@sfYCellBounds = lat_verts_crnt_grid_unstruc +; +; If the grid_opts@plot_gridlines(i) is set to True, draw the cell edges +; (gridlines) of the current grid. +; +;print("DDDDDDDD") +;print(grid_opts) +;print("EEEEEE i = " + i) +;print(" dimsizes(grid_opts@plot_gridlines(i)) = " + dimsizes(grid_opts@plot_gridlines(i))) +;print(dimsizes(grid_opts@plot_gridlines(i))) +;print(dimsizes(grid_opts@plot_gridlines)) +;tmp := grid_opts@plot_gridlines(i) +tmp := grid_opts@plot_gridlines +;print("FFFFFFFFFFFFFF") +;print("KKKKKKKKKK tmp(i) = " + tmp(i)) +;print("GGGGGGGGGGG") +;print(dimsizes(tmp)) +;print("HHHHHHHHHHH") +;exit +; if (grid_opts@plot_gridlines(i)) then +; if ( False ) then + if (tmp(i)) then +; +; The resource cnCellFillMissingValEdgeColor should ideally set the cell +; edge color of those cells that contain missing values, but it seems to +; have no effect - at least when the field on the current grid contains +; all missing/fill values. For this reason, when the field on a grid +; contains all missing/fill values and grid_opts@plot_gridlines(i) for that +; grid is set to True (i.e. we want to see the gridlines but not a field +; on that grid), we resort to the method below in which we set the cn- +; CellFillEdgeColor resource to the color we want for the gridlines, and +; (later on) we set at least one value in the field to a non-missing +; value and we set the opacity of the contour color to 0 (transparent). +; + rsrc@cnCellFillMissingValEdgeColor = "yellow" +; +; Set the color for the cell edge. Note that this seems to have an ef- +; fect only if at least one element in the field is not a missing value +; (if all elements in the field are set to missing values, then no grid +; is generated). For this reason, if all values of the field on the +; current grid are missing/fill values, we reset at least one element in +; the field array to a non-missing value (e.g. zero), and we set the +; opacity of the contour color to 0 so that it is transparent (so that +; no color is shown, as if the field consisted of missing values every- +; where). +; + rsrc@cnCellFillEdgeColor = grid_opts@gridline_colors(i) + + end if +; +; Extract the portion of the field array that contains the field values +; on the current grid. +; +;print("dimsizes(field_unstruc) = " + dimsizes(field_unstruc)) + field_crnt_grid_unstruc \ + := field_unstruc(indx_start(i):indx_end(i)) +; +; If all values of the field on the current grid are missing/fill val- +; ues, then reset at least one value to a non-missing value (e.g. zero), +; and set the opacity of the field to 0 (transparent). We do this in +; order to be able to see the gridlines in cases in which all values in +; the field on the current grid are missing, and grid_opts@plot_gridlines(i) +; is set to True (because in that case, the cnCellFillMissingValEdgeCo- +; lor resource doesn't seem to have an effect, so we use the cnCellFill- +; EdgeColor resource instead along with setting the opacity to 0). +; + field_missing := all(ismissing(field_crnt_grid_unstruc)) + if (field_missing) then +; +; At least one value in the field must be non-missing in order for cn- +; CellFillEdgeColor to have an effect. +; + field_crnt_grid_unstruc(0) = 0 +; +; We cause the cells that were artificially reset above to non-missing +; values to not appear in the plot by setting the opacity of the field +; to 0 (transparent). +; + rsrc@cnFillOpacityF = 0.0 + + end if +; +; Set sfDataArray to the field on the current grid (which has one value +; per cell). +; + rsrc@sfDataArray = field_crnt_grid_unstruc +; +; Set the color for cells containing missing values. This is by default +; "transparent", but we repeat it here for clarity. +; + rsrc@cnMissingValFillColor = "transparent" + rsrc@cnMissingValFillColor = "yellow" ; This has an effect only if not all values in the field are missing. +; +; Specify opacity of cell colors. +; +; rsrc@cnFillOpacityF = 0.0 ; Transparent. +; rsrc@cnFillOpacityF = 0.1 +; rsrc@cnFillOpacityF = 0.35 +; rsrc@cnFillOpacityF = 1.0 ; Opaque. +; +; If on the base plot (i.e. not an overlay), draw a labelbar (colorbar). +; + if (i .eq. 0) then + rsrc@lbLabelBarOn = True + else + rsrc@lbLabelBarOn = False + end if +; +; Do not draw vertical box separator lines in the labelbar (but this +; doesn't turn off the box around the whole label bar). +; + rsrc@lbBoxSeparatorLinesOn = False +; +; Turn off displaying of text box that says "CONTOUR FROM AAA TO BBB BY +; CCC". +; + rsrc@cnInfoLabelOn = False +; +; Make sure the labelbar is fully opaque regardless of what the opacity +; of the contour plot is set to (via the cnFillOcacityF resource). +; + rsrc@lbOverrideFillOpacity = True +; +; ********************************************************************** +; +; Map-related resources that should be set only for the base plot, not +; for the overlays [since the base plot is the only one that draws a +; map using the gsn_csm_contour_map() function; the overlays use the +; gsn_csm_contour() function]. +; +; ********************************************************************** +; + if (i .eq. 0) then +; +; Set the latitude and longitude of the center of the map projection co- +; ordinate system. +; + rsrc@mpCenterLonF = plot_opts@map_proj_ctr(0) + rsrc@mpCenterLatF = plot_opts@map_proj_ctr(1) +; +; Set the map projection to use. For the Lambert equal-area projection, +; we rotate the projection such that it is centered at the North Pole. +; + if (strcmp_exact(plot_opts@map_proj, "cyln")) then + rsrc@mpProjection = "CylindricalEquidistant" + else if (strcmp_exact(plot_opts@map_proj, "ortho")) then + rsrc@mpProjection = "Orthographic" + else if (strcmp_exact(plot_opts@map_proj, "lamb")) then +; rsrc@mpProjection = "LambertEqualArea" + rsrc@mpProjection = "LambertConformal" + end if + end if + end if +; +; Improve the resolution of the map outlines. Default is "LowRes". +; + rsrc@mpDataBaseVersion = "MediumRes" +; rsrc@mpDataBaseVersion = "HighRes" +; rsrc@mpDataBaseVersion = "Dynamic" + rsrc@mpDataSetName = "Earth..4" + +; rsrc@mpOutlineBoundarySets = "USStates" +; rsrc@mpOutlineBoundarySets = "AllBoundaries" +; rsrc@mpOutlineSpecifiers = (/ "United States:states", "Canada:states", "Mexico:states" /) + rsrc@mpOutlineSpecifiers = (/ "land:states" /) +; rsrc@mpOutlineDrawOrder = "PostDraw" +; +; Plot curves of constant longitude and latitude (regardless of the plot +; projection). +; + rsrc@mpGridAndLimbOn = True + rsrc@mpGridAndLimbOn = False + if (rsrc@mpGridAndLimbOn) then + rsrc@mpGridLonSpacingF = 5.0 + rsrc@mpGridLatSpacingF = 5.0 + end if +; +; If plot_opts@plot_subreg is set to True, plot only a subregion. Note +; that this has an effect only for the cylindrical-equidistant map pro- +; jection. <--- Is this True??? +; + if (plot_opts@plot_subreg) then + rsrc@mpLimitMode = "LatLon" + rsrc@mpMinLonF = plot_opts@subreg_limits(0) + rsrc@mpMaxLonF = plot_opts@subreg_limits(1) + rsrc@mpMinLatF = plot_opts@subreg_limits(2) + rsrc@mpMaxLatF = plot_opts@subreg_limits(3) + end if + + if (strcmp_exact(plot_opts@map_proj, "lamb")) then + + rsrc@mpLimitMode = "LatLon" +; rsrc@mpMinLonF = -128 +; rsrc@mpMaxLonF = -70 +; rsrc@mpMinLatF = 20 +; rsrc@mpMaxLatF = 53 + + rsrc@mpLambertParallel1F = 38.5 + rsrc@mpLambertParallel2F = 38.5 + rsrc@mpLambertMeridianF = -97.5 + +; rsrc@mpLimitMode = "Corners" +; rsrc@mpLeftCornerLonF = plot_opts@lon_min +; rsrc@mpLeftCornerLatF = plot_opts@lat_min +; rsrc@mpRightCornerLonF = plot_opts@lon_max +; rsrc@mpRightCornerLatF = plot_opts@lat_max + rsrc@mpLeftCornerLonF = -122 + rsrc@mpLeftCornerLatF = 15 + rsrc@mpRightCornerLonF = -65 + rsrc@mpRightCornerLatF = 55 + + end if + + end if +; +; ********************************************************************** +; +; Turn on nice tickmarks for labeling longitudes and latitudes. +; +; ********************************************************************** +; + rsrc@pmTickMarkDisplayMode = "Always" +; +; ********************************************************************** +; +; Turn on or off drawing of contour lines. +; +; Note that when cnFillOn is set to True and cnFillMode is set to "Cell- +; Fill", setting cnLinesOn to True draws dashed contour lines everywhere +; instead of drawing solid lines for positive contour values and dashed +; lines for negative values (which is the expected behavior). It is not +; clear why this happens. +; +; It seems the best thing to do is to turn off drawing of contour lines +; since the field may be disontinuous across tiles, in which case the +; contour line drawing algorithm gets confused and the contour lines are +; a mess. Even if the field is not discontinuous across tiles, or if +; there is only one tile, the contour lines don't add much value since +; they are drawn exactly at the transition between colors. +; +; ********************************************************************** +; + rsrc@cnLinesOn = False +; +; ********************************************************************** +; +; If contour lines are turned on, set resources related to them. +; +; ********************************************************************** +; + if (rsrc@cnLinesOn) then +; +; The cnLineLabelDensityF resource can be increased to increase the den- +; sity of the contour line labels. +; + rsrc@cnLineLabelDensityF = 2.0 +; +; If we want to label every contour line, set cnLineLabelInterval to 1. +; If we want to label only every other contour line, set this resource +; to 2, etc. Default is 2. +; + rsrc@cnLineLabelInterval = 1 + + end if +; +; ********************************************************************** +; +; Turn on or off placement of contour line labels. +; +; Note that when cnFillOn is set to True and cnFillMode is set to "Cell- +; Fill", setting cnLineLabelsOn to True seems to make no difference, +; i.e. contour line labels are not placed on the contour lines. This +; seems to do with the fact that in this case, the arrays sfXCellBounds +; and sfYCellBounds are defined. +; +; ********************************************************************** +; +; rsrc@cnLineLabelsOn = True + rsrc@cnLineLabelsOn = False +; +; ********************************************************************** +; +; If contour line labels are turned on, Set resources related to them. +; +; ********************************************************************** +; + if (rsrc@cnLineLabelsOn) then +; +; Set the background color of the box that contains each contour line +; label. If this color is not specified, it seems to default to trans- +; parent (which corresponds to color index -1), although the online ma- +; nual says it's supposed to default to the background color (color in- +; dex 0). +; +; rsrc@cnLineLabelBackgroundColor = "white" + rsrc@cnLineLabelBackgroundColor = "transparent" +; rsrc@cnLineLabelBackgroundColor = 0 +; +; Explicitly set the labels to use for the contour line labels. These +; will be used only if we are placing labels on the contour lines. We +; set these to the set of labels retruned by the function set_cnLevels_- +; lbLabels(...) (which are the same labels that will be used for the la- +; belbar/colorbar labels). +; + rsrc@cnExplicitLineLabelsOn = True + rsrc@cnLineLabelStrings = plot_opts@lbLabels + + end if +; +; ********************************************************************** +; +; Set the method to use for selecting the contour levels. Then set +; other resources accordingly. +; +; ********************************************************************** +; +; rsrc@cnLevelSelectionMode = "AutomaticLevels" +; rsrc@cnLevelSelectionMode = "ManualLevels" + rsrc@cnLevelSelectionMode = "ExplicitLevels" +; rsrc@cnLevelSelectionMode = "EqualSpacedLevels" ; This should not be used! Investigate further. + + if (strcmp_exact(rsrc@cnLevelSelectionMode, "ManualLevels")) then + rsrc@cnMinLevelValF = plot_opts@cnLevel_min + rsrc@cnMaxLevelValF = plot_opts@cnLevel_max + rsrc@cnLevelSpacingF = plot_opts@cnStep + else if (strcmp_exact(rsrc@cnLevelSelectionMode, "ExplicitLevels")) then + rsrc@cnLevels = plot_opts@cnLevels +; else if (strcmp_exact(rsrc@cnLevelSelectionMode, "EqualSpacedLevels")) then +; rsrc@cnMaxLevelCount = plot_opts@nLevs +; rsrc@cnMaxLevelCount = 10 + else + msg := char_nl + \ +"Disallowed value specified for the cnLevelSelectionMode attribute of rsrc:" + char_nl + \ +" rsrc@cnLevelSelectionMode = " + char_dq + rsrc@cnLevelSelectionMode + char_dq + char_nl + \ +"Allowed values are:" + char_nl + \ +" " + char_dq + "ManualLevels" + char_dq + char_nl + \ +" " + char_dq + "ExplicitLevels" + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + end if +; +; ********************************************************************** +; +; Allow the user to explicitly set lbLabelStrings, which specifies the +; set of strings to use as labels for the lablebar (colorbar). Note +; that the flag cnExplicitLabelBarLabelsOn must be set to True in order +; for the plotting routine to use the user-specified value of lbLabel- +; Strings (instead of overwriting it with its own values). Note also +; that the elements of lbLabelStrings may not all appear as labels in +; the labelbar (colorbar). This is because by default, the plotting +; routine ensures that these labels do not overlap by skipping every +; other label, every 2 out of 3 labels, etc, as necessary. +; +; ********************************************************************** +; + rsrc@cnExplicitLabelBarLabelsOn = True + rsrc@lbLabelStrings = plot_opts@lbLabels +; +; ********************************************************************** +; +; Allow for spatially constant fields to be colored in instead of left +; blank. Also, for a spatially constant field, by default the constant +; field informational textbox will appear to inform that the field is +; constant. Turn this off by setting cnConstFLabelOn to False. +; +; ********************************************************************** +; + rsrc@cnConstFEnableFill = True + rsrc@cnConstFLabelOn = False +; +; ********************************************************************** +; +; If no data is available to create the contour plot (e.g. if the whole +; field consists of missing values), the default behavior is to display +; on the plot a text box containing the stirng "NO CONTOUR DATA". Turn +; off displaying of this string. +; +; ********************************************************************** +; + rsrc@cnNoDataLabelOn = False +; +; ********************************************************************** +; +; If available (e.g. from a previous call to this function) as attri- +; butes of plot_opts, retrieve the viewport parameters to use for this +; plot and set them to corresponding attributes in rsrc. These viewport +; values consist of the NDC coordinates of the lower-left corner of the +; viewport and the width and height of the viewport (also in NDC units). +; Note that the viewport for a contour plot conists of the rectagle de- +; lineated by the x and y axes. If the viewport parameters are not spe- +; cified as attributes of plot_opts, they will be set by the plotting +; routine [gsn_csm_contour_map(...)]. +; +; ********************************************************************** +; + if (isatt(plot_opts, "vpXF") .and. \ + isatt(plot_opts, "vpYF") .and. \ + isatt(plot_opts, "vpWidthF") .and. \ + isatt(plot_opts, "vpHeightF")) then + rsrc@vpXF = plot_opts@vpXF + rsrc@vpYF = plot_opts@vpYF + rsrc@vpWidthF = plot_opts@vpWidthF + rsrc@vpHeightF = plot_opts@vpHeightF + end if +; +; ********************************************************************** +; +; Do not immediately draw the contour plot nor advance the frame because +; other objects (e.g. overlays, polylines, etc) might still need to be +; added to the plot. +; +; ********************************************************************** +; + rsrc@gsnDraw = False + rsrc@gsnFrame = False +; +; ********************************************************************** +; +; Generate (but not yet draw) the color contour plot (along with a map). +; If on the first grid, draw a map as well [by calling gsn_csm_contour_- +; map(...)]. We refer to the plot with a map for the first grid as the +; base plot. If on later grids, do not draw a map [by calling gsn_csm_- +; contour(...)], and overlay the contour plot on the base plot. +; +; ********************************************************************** +; + if (i .eq. 0) then + contour_map := gsn_csm_contour_map(wks, field_crnt_grid_unstruc, rsrc) + else + contour_overlay := gsn_csm_contour(wks, field_crnt_grid_unstruc, rsrc) + overlay(contour_map, contour_overlay) + end if + + end do +; +; ********************************************************************** +; +; Get the viewport upper-left point coordinates and width and height of +; the plot. Note that the viewport consists only of the region inside +; the contour plot, i.e. it doesn't include the axis labels, labelbar, +; any plot titles, etc. These coordinates and sizes will be used in +; calculating the coordinates of the locations where the plot title +; strings (three of them: a left, a right, and a center string) will be +; placed. +; +; ********************************************************************** +; + getvalues contour_map + "vpXF" : vpXF + "vpYF" : vpYF + "vpWidthF" : vpWidthF + "vpHeightF" : vpHeightF + end getvalues +; +; ********************************************************************** +; +; Set the font height and color of the left, right, and center title +; strings. +; +; ********************************************************************** +; + FontHeightF_LR = 0.01 + FontColor_LR = "black" + + FontHeightF_C = 1.25*FontHeightF_LR + FontColor_C = "black" +; +; ********************************************************************** +; +; Set the vertical distance (in NDC units) of the offset to use between +; the top of the plot viewport and the bottoms of the left and right +; title strings. We will also use this distance as the offset between +; the top of the left or right title string (whichever is taller) and +; the bottom of the center title string. +; +; ********************************************************************** +; + dx_vert_offset_ndc = 0.01 +; +; ********************************************************************** +; +; Set the coordinate of the left and right title strings in coordinates +; normalized with respect to the viewport size. This will be used in +; specifying the location at which the left and right title string will +; be annotated to the plot. +; +; ********************************************************************** +; + amOrthogonalPosF_LR = -0.5 - dx_vert_offset_ndc*(1.0/vpHeightF) +; +; ********************************************************************** +; +; Create (using gsn_create_text(...)) and then annotate to the plot +; (using gsn_add_annotation(...)) the left title string. +; +; ********************************************************************** +; + txres := True + txres@txFontHeightF = FontHeightF_LR + txres@txFontColor = FontColor_LR + txid_left_str = gsn_create_text(wks, plot_opts@left_str, txres) + + amres := True + amres@amParallelPosF = -0.5 + amres@amOrthogonalPosF = amOrthogonalPosF_LR + amres@amJust = "BottomLeft" + annotid_left_str = gsn_add_annotation(contour_map, txid_left_str, amres) +; +; Get the viewpoint coordinates and width and height of the text box of +; the left title string. +; + getvalues txid_left_str + "vpXF" : vpXF_left_str + "vpYF" : vpYF_left_str + "vpWidthF" : vpWF_left_str + "vpHeightF" : vpHF_left_str + end getvalues +; +; ********************************************************************** +; +; Create (using gsn_create_text(...)) and then annotate to the plot +; (using gsn_add_annotation(...)) the left title string. +; +; ********************************************************************** +; + txres := True + txres@txFontHeightF = FontHeightF_LR + txres@txFontColor = FontColor_LR + txres@txJust = "BottomLeft" + txid_right_str = gsn_create_text(wks, plot_opts@right_str, txres) + + amres := True + amres@amParallelPosF = 0.5 + amres@amOrthogonalPosF = amOrthogonalPosF_LR + amres@amJust = "BottomRight" + annotid_right_str = gsn_add_annotation(contour_map, txid_right_str, amres) +; +; Get the viewpoint coordinates and width and height of the text box of +; the right title string. +; + getvalues txid_right_str + "vpXF" : vpXF_right_str + "vpYF" : vpYF_right_str + "vpWidthF" : vpWF_right_str + "vpHeightF" : vpHF_right_str + end getvalues +; +; ********************************************************************** +; +; Get the height of the taller of the left and right title strings. +; +; ********************************************************************** +; + height_max = max((/ vpHF_left_str, vpHF_right_str /)) +; +; ********************************************************************** +; +; Set the coordinate of the center title string in coordinates normal- +; ized with respect to the viewport size. This will be used in specify- +; ing the location at which the center title string will be annotated to +; the plot. +; +; ********************************************************************** +; + amOrthogonalPosF_cntr \ + = amOrthogonalPosF_LR - height_max*(1.0/vpHeightF) \ + - dx_vert_offset_ndc*(1.0/vpHeightF) +; +; ********************************************************************** +; +; Create (using gsn_create_text(...)) and then annotate to the plot +; (using gsn_add_annotation(...)) the center title string. +; +; ********************************************************************** +; + txres := True + txres@txFontHeightF = FontHeightF_C + txres@txFontColor = FontColor_C + txid_cntr_str = gsn_create_text(wks, plot_opts@main_str, txres) + + amres := True + amres@amParallelPosF = 0.0 ; Horizontally centered above plot. + amres@amOrthogonalPosF = amOrthogonalPosF_cntr + amres@amJust = "BottomCenter" + annotid_cntr_str = gsn_add_annotation(contour_map, txid_cntr_str, amres) +; +; ********************************************************************** +; +; Set labelbar resources to those specified as attributes of plot_op- +; tions, if any. +; +; ********************************************************************** +; + getvalues contour_map@contour + "pmAnnoViews" : pmAnnoViews + end getvalues + lb_object = pmAnnoViews(0) + + if (isatt(plot_opts, "lbar_x") .and. \ + isatt(plot_opts, "lbar_y") .and. \ + isatt(plot_opts, "lbar_w") .and. \ + isatt(plot_opts, "lbar_h") .and. \ + isatt(plot_opts, "lbar_fh")) then + + rsrc@lbAutoManage = False + + setvalues lb_object + "vpXF" : plot_opts@lbar_x + "vpYF" : plot_opts@lbar_y + "vpHeightF" : plot_opts@lbar_h + "vpWidthF" : plot_opts@lbar_w + "lbLabelFontHeightF" : plot_opts@lbar_fh + end setvalues + + end if +; +; ********************************************************************** +; +; Draw NDC (non-dimensional coordinate, aka page coordinates) grid on +; the plot. These range from 0 to 1. This grid helps visualize loca- +; tions of various graphics objects. +; +; ********************************************************************** +; +; drawNDCGrid(wks) +; +; ********************************************************************** +; +; Retrieve the viewport values of the drawable object. These will be +; returned to the calling function/script. +; +; ********************************************************************** +; + getvalues contour_map + "vpXF" : vpXF + "vpYF" : vpYF + "vpWidthF" : vpWidthF + "vpHeightF" : vpHeightF + end getvalues + + getvalues lb_object + "vpXF" : lbar_x + "vpYF" : lbar_y + "vpHeightF" : lbar_h + "vpWidthF" : lbar_w + "lbLabelFontHeightF" : lbar_fh + end getvalues +; +; ********************************************************************** +; +; Resize the plot (if appropriate flag is set to True). +; +; ********************************************************************** +; + if (isatt(plot_opts, "resize_plot") .and. \ + isatt(plot_opts, "bounding_box_size_NDC") .and. \ + plot_opts@resize_plot) then + + opts := True + opts@verbose = False + viewport_info := get_resized_viewport_dims( \ + contour_map, plot_opts@bounding_box_size_NDC, opts) + + vpXF_new = viewport_info@vpXF + vpYF_new = viewport_info@vpYF + vpWidthF_new = viewport_info@vpWidthF + vpHeightF_new = viewport_info@vpHeightF + + setvalues contour_map + "vpXF" : vpXF_new + "vpYF" : vpYF_new + "vpWidthF" : vpWidthF_new + "vpHeightF" : vpHeightF_new + end setvalues + + end if +; +; ********************************************************************** +; +; If bdy_opts is set to True, draw grid boundaries. Note that bdy_opts +; should be set to True only if there is at least one valid set of +; boundary coordinates to plot. +; +; ********************************************************************** +; + if (bdy_opts) then + + num_bdies = bdy_opts@num_bdies + show_grid_bdy = bdy_opts@plot_bdy + + if (.not. isatt(bdy_opts, "bdy_colors")) then + temp := new((/ num_bdies /), "string") + temp = "black" + bdy_opts@bdy_colors := temp + end if + + if (.not. isatt(bdy_opts, "bdy_line_thicknesses")) then + temp := new((/ num_bdies /), "float") + temp = 4.0 + bdy_opts@bdy_line_thicknesses := temp + end if + + if (.not. isatt(bdy_opts, "bdy_dash_patterns")) then + temp := new((/ num_bdies /), "integer") + temp = 0 + bdy_opts@bdy_dash_patterns := temp + end if + + id_grid_bdies := new(num_bdies, "graphic") + bdy_indx_end := -1 +;print("") +;print("dimsizes(id_grid_bdies) = " + dimsizes(id_grid_bdies)) + + do i=0, num_bdies-1 + + bdy_indx_start := bdy_indx_end + 1 + bdy_indx_end \ + := bdy_indx_start + bdy_opts@num_bdy_pts_all_bdies(i) - 1 + + if (show_grid_bdy(i)) then + + resp := True + resp@gsLineColor := bdy_opts@bdy_colors(i) + resp@gsLineThicknessF := bdy_opts@bdy_line_thicknesses(i) + resp@gsLineDashPattern := bdy_opts@bdy_dash_patterns(i) + lon_crnt_bdy := lon_bdy_all_bdies(bdy_indx_start:bdy_indx_end) + lat_crnt_bdy := lat_bdy_all_bdies(bdy_indx_start:bdy_indx_end) + +print("") +print("i = " + i) +print("num_bdies = " + num_bdies) +print("bdy_opts@bdy_colors(i) = " + bdy_opts@bdy_colors(i)) +print("bdy_indx_start = " + bdy_indx_start) +print("bdy_indx_end = " + bdy_indx_end) +;print(resp) + + id_grid_bdies(i) \ + = gsn_add_polyline( \ + wks, contour_map, lon_crnt_bdy, lat_crnt_bdy, resp) +; gsn_add_polyline( \ +; wks, contour_map, lon_crnt_bdy, lat_crnt_bdy, resp) + + end if + + end do + + end if +; +; ********************************************************************** +; +; Draw the plot and advance the frame. +; +; ********************************************************************** +; + draw(contour_map) + frame(wks) + + print("") + print("Done generating graphics file.") + print("" + separator_line) + print("") +; +; ********************************************************************** +; +; Return results as attributes of the logical variable plot_info. In- +; clude here all variables that we might want to pass to the next call +; to this function. +; +; ********************************************************************** +; + plot_info := True + + plot_info@vpXF := vpXF + plot_info@vpYF := vpYF + plot_info@vpWidthF := vpWidthF + plot_info@vpHeightF := vpHeightF + plot_info@lbar_x = lbar_x + plot_info@lbar_y = lbar_y + plot_info@lbar_h = lbar_h + plot_info@lbar_w = lbar_w + plot_info@lbar_fh = lbar_fh + + return(plot_info) + +end + diff --git a/ush/NCL/process_plot_params.ncl b/ush/NCL/process_plot_params.ncl new file mode 100644 index 0000000000..297cd284f6 --- /dev/null +++ b/ush/NCL/process_plot_params.ncl @@ -0,0 +1,1059 @@ +; +; ********************************************************************** +; +; File name: process_plot_params.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +undef("process_plot_params") + +function process_plot_params( \ + caller:string, \ + usage_msg:string, \ + help_msg:string) + +local plot_params + +begin +; +; ********************************************************************** +; +; Set the name of the current script or function. We have to do this +; manually because NCL does not seem to have a built-in method of ob- +; taining this information. +; +; ********************************************************************** +; + curnt_script_proc_func_name \ + := "function process_plot_params(caller, usage_msg, help_msg)" +; +; ********************************************************************** +; +; Verify that the input argument "caller" that specifies the name of the +; script, procedure, or function that calls this procedure has a valid +; value. +; +; ********************************************************************** +; + valid_callers = (/ "plot_grid", "plot_fields" /) + + if (.not. strcmp_exact(valid_callers, caller)) then + + valid_vals \ + := char_dq \ + + str_join(valid_callers, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"ERROR: " + curnt_script_proc_func_name + ":" + char_nl + \ +"Input argument " + char_dq + caller + char_dq + "is not set to a valid value:" + char_nl + \ +" caller = " + char_dq + caller + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Stopping." + char_nl + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; For convenience, set the variable example_usage_and_help_str to a +; string containing an example of how the script/procedure/function that +; calls this function (caller) should be used and how to obtain more +; detailed help. This variable will be used below in forming error mes- +; sages. +; +; ********************************************************************** +; + example_usage_and_help_str := \ +"Example usage:" + char_nl + \ +usage_msg + char_nl + \ +"For more help, run " + char_dq + caller + ".ncl 'help=True'" + char_dq + \ +" on the command line." + char_nl + \ +"Stopping." +; +; ********************************************************************** +; +; Get the version of NCL being used. This may be needed later below. +; +; ********************************************************************** +; + ncl_ver = get_ncl_version() + ncl_ver = str_sub_str(ncl_ver, ".", "") + ncl_ver = tointeger(ncl_ver) +; +; ********************************************************************** +; +; If the variable "help" is specified on the command line and is set to +; True, print out the help message and exit. +; +; ********************************************************************** +; + if (isvar("help")) then + if (help .eq. True) then + print("" + help_msg) + exit + end if + else + help = False + end if +; +; ********************************************************************** +; +; Verify that the experiment directory (expt_dir) has been specified on +; the command line. If so, verify that it exists. +; +; ********************************************************************** +; + if (.not. isvar("expt_dir")) then + + msg := char_nl + \ +"The experiment directory (expt_dir) has not been specified on the com-" + char_nl + \ +"mand line:" + char_nl + \ +" isvar(" + char_dq + "expt_dir" + char_dq + ") = " + isvar("expt_dir") + char_nl + \ +"Please rerun with the experiment directory specified. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + else if (.not. fileexists(expt_dir)) then + + msg := char_nl + \ +"The specified experiment directory (expt_dir) does not exist:" + char_nl + \ +" expt_dir = " + char_dq + expt_dir + char_dq + char_nl + \ +" fileexists(expt_dir) = " + fileexists(expt_dir) + char_nl + \ +"Please rerun with an existing experiment directory. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if + end if +; +; ********************************************************************** +; +; Set the full path to the variable definitions file. This file con- +; tains various experiment and workflow parameters that will be needed +; below. +; +; ********************************************************************** +; + var_defns_fn = expt_dir + "/var_defns.sh" +; +; ********************************************************************** +; +; Read in the grid type (gtype) from the variable definitions file. +; +; ********************************************************************** +; + cmd = "sed --silent --regexp-extended --expression " \ + + "'s/(^gtype=)([" + char_dq + "]*)([A-Za-z]+)([" + char_dq + "]*)(.*)/\3/p' " \ + + var_defns_fn + gtype := systemfunc(cmd) + +; This is a temporary fix. Need this since we removed "gtype" from the +; variable defintions file of the community workflow. +gtype = "regional" +; +; ********************************************************************** +; +; Check that the grid type read in above is valid. +; +; ********************************************************************** +; + valid_gtypes = (/ "uniform", "stretch", "nest", "regional" /) + + if (.not. strcmp_exact(valid_gtypes, gtype)) then + + valid_vals \ + := char_dq \ + + str_join(valid_gtypes, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"The grid type (gtype) is not set to a valid value:" + char_nl + \ +" gtype = " + char_dq + gtype + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with a valid grid type. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; Set the array of valid tile indices corresponding to the grid type set +; above. +; +; ********************************************************************** +; + if (strcmp_exact(gtype, "uniform") .or. \ + strcmp_exact(gtype, "stretch")) then + + valid_tile_inds = (/ 1, 2, 3, 4, 5, 6 /) + + else if (strcmp_exact(gtype, "nest")) then + + valid_tile_inds = (/ 1, 2, 3, 4, 5, 6, 7 /) + + else if (strcmp_exact(gtype, "regional")) then +; +; For a regional grid, we can plot the parent grid (tiles 1 through 6) +; as well as the regional grid (tile 7), but we cannot plot fields on +; the parent grid because that is not used in the time-integration. +; + if (strcmp_exact(caller, "plot_grid")) then + valid_tile_inds = (/ 1, 2, 3, 4, 5, 6, 7 /) + else + valid_tile_inds = (/ 7 /) + end if + + end if + end if + end if +; +; ********************************************************************** +; +; Read in the cubed-sphere resolution (res) from the variable defini- +; tions file. This is the nubmer of grid cells in the two horizontal +; directions on each tile of the global and/or regional grid. +; +; ********************************************************************** +; + cmd = "sed --silent --regexp-extended --expression " \ + + "'s/^[ ]*(CRES=)([" + char_dq + "]*)C([0-9]+)([" + char_dq + "]*)(.*)/\3/p' " \ + + var_defns_fn + res := systemfunc(cmd) +; +; Get the last occurrence of "RES=..." in the variable defintions file +; since that's the one that matters. +; + num_elems = dimsizes(res) + res := res(num_elems-1) +; +; ********************************************************************** +; +; Check that the cubed-sphere resolution read in above is valid. +; +; ********************************************************************** +; +; Note: Can't use this for ESGgrid because that has no such standard values. +; At some point, change this if-statement so that it's entered only for +; GFDLgrid. +if (False) then + valid_reses = (/ "000", "48", "96", "192", "384", "768", "1152", "3072" /) + + if (.not. any(res .eq. valid_reses)) then + + valid_vals := str_join(tostring(valid_reses), ", ") + + msg := char_nl + \ +"The cubed-sphere resolution (res) is not set to a valid value:" + char_nl + \ +" res = " + res + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with a valid cubed-sphere resolution. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if +end if +; +; ********************************************************************** +; +; Set the C-resolution (cres) of the grid. This is a convenience varia- +; ble. It is a string consisting of the character "C" followed by the +; cubed-sphere resolution. +; +; ********************************************************************** +; +; cres := "C" + tostring_with_format(res, "%i") + cres := "C" + res + + + + + + + + + + + + + +; +; ********************************************************************** +; +; If the array containing the indices of the tiles on the cubed sphere +; that are to be plotted (tile_inds) has been specified on the command +; line, make sure that each of these indices is valid, i.e. that each +; index can be found in the list of valid indices in valid_tile_inds. +; +; ********************************************************************** +; + if (isvar("tile_inds")) then +; +; Check rank here, then keep unique values and sort (move up from below). +; Only then check if each index is valid. +; + nn_max = dimsizes(tile_inds) + + do nn=0, nn_max-1 + + indx_tile = tile_inds(nn) + + if (.not. any(valid_tile_inds .eq. indx_tile)) then + + tile_inds_str := "(/ " + str_join(tostring(tile_inds), ", ") + " /)" + valid_vals := str_join(tostring(valid_tile_inds), ", ") + + msg := char_nl + \ +"Tile index " + indx_tile + " (specified in the " + char_dq + "tile_inds" + char_dq + \ +" array) is not valid for the current grid type (gtype):" + char_nl + \ +" gtype = " + char_dq + gtype + char_dq + char_nl + \ +" tile_inds = " + tile_inds_str + char_nl + \ +"Valid tile indices are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with valid tile indices. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if + + end do +; +; ********************************************************************** +; +; If tile_inds has not been defined on the command line, set it to the +; list of valid tile indices (valid_tile_inds). +; +; ********************************************************************** +; + else + + tile_inds := valid_tile_inds + + end if +; +; ********************************************************************** +; +; For clarity, rename the tile_inds array inds_tiles_to_plot. Then keep +; only unique elements of this renamed array and sort them by increasing +; value. Also, calculate the number of tiles to be plotted. +; +; ********************************************************************** +; + inds_tiles_to_plot = tile_inds + delete(tile_inds) + inds_tiles_to_plot := get_unique_values(inds_tiles_to_plot) + qsort(inds_tiles_to_plot) + num_tiles_to_plot = dimsizes(inds_tiles_to_plot) +; +; ********************************************************************** +; +; If show_tile_bdies has not been specified on the command line, set it +; to True. +; +; ********************************************************************** +; + if (.not. isvar("show_tile_bdies")) then + show_tile_bdies = True + end if +; +; ********************************************************************** +; +; If show_tile_bdies has been set to True and tile_bdy_color has not +; been specified on the command line, set the latter to a default value. +; +; ********************************************************************** +; + if (show_tile_bdies .and. .not. isvar("tile_bdy_color")) then + tile_bdy_color := "blue" + end if +; +; ********************************************************************** +; +; If show_tile_grids has not been specified on the command line, set it +; to False. +; +; ********************************************************************** +; + if (.not. isvar("show_tile_grids")) then + show_tile_grids = False + end if +; +; ********************************************************************** +; +; If plot_RAP_field has not been specified on the command line, set it +; to False. +; +; ********************************************************************** +; + if (.not. isvar("plot_RAP_field")) then + plot_RAP_field = False + end if +; +; ********************************************************************** +; +; If plot_RAP_field has been set to True, then... +; +; ********************************************************************** +; + if (plot_RAP_field) then +; +; Make sure that the name of the NetCDF file that describes the RAP grid +; (RAP_grid_fn) has been specified. +; + if (.not. isvar("RAP_grid_fn")) then + + msg := char_nl + \ +"When plot_RAP_field has been set to True, the RAP grid file (RAP_grid_fn) " + char_nl + \ +"must be specified on the command line:" + char_nl + \ +" plot_RAP_field = " + plot_RAP_field + char_nl + \ +" isvar(" + char_dq + "RAP_grid_fn" + char_dq + ") = " + isvar("RAP_grid_fn") + char_nl + \ +"Please rerun with the RAP grid file specified. " + \ +example_usage_and_help_str + print("" + msg) + exit +; +; If RAP_grid_fn has been specified, make sure that it exists. +; + else if (.not. fileexists(RAP_grid_fn)) then + + msg := char_nl + \ +"The specified RAP grid file (RAP_grid_fn) does not exist:" + char_nl + \ +" RAP_grid_fn = " + char_dq + RAP_grid_fn + char_dq + char_nl + \ +" fileexists(RAP_grid_fn) = " + fileexists(RAP_grid_fn) + char_nl + \ +"Please rerun with an existing RAP grid file. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if + end if +; +; Make sure that a field to plot on the RAP grid (field_name_RAP) is +; specified. +; + if (.not. isvar("field_name_RAP")) then + msg := char_nl + \ +"When plot_RAP_field has been set to True, a field to plot on the RAP " + char_nl + \ +"grid (field_name_RAP) must be specified on the command line:" + char_nl + \ +" plot_RAP_field = " + plot_RAP_field + char_nl + \ +" isvar(" + char_dq + "field_name_RAP" + char_dq + ") = " + isvar("field_name_RAP") + char_nl + \ +"Please rerun with a field_name_RAP specified. " + \ +example_usage_and_help_str + print("" + msg) + exit + end if +; +; ********************************************************************** +; +; If plot_RAP_field has been set to False, then set or reset field_- +; name_RAP to "none" so that the plot will not show a field on the RAP +; grid. +; +; ********************************************************************** +; + else + + field_name_RAP = "none" + + end if +; +; ********************************************************************** +; +; If show_RAP_bdy has not been specified on the command line, set it to +; False. +; +; ********************************************************************** +; + if (.not. isvar("show_RAP_bdy")) then + show_RAP_bdy = False + end if +; +; ********************************************************************** +; +; If show_RAP_bdy has been set to True and RAP_bdy_color has not been +; specified on the command line, set the latter to a default value. +; +; ********************************************************************** +; + if (show_RAP_bdy .and. .not. isvar("RAP_bdy_color")) then + RAP_bdy_color := "red" + end if +; +; ********************************************************************** +; +; If show_RAP_grid has not been specified, set it to False. +; +; ********************************************************************** +; + if (.not. isvar("show_RAP_grid")) then + show_RAP_grid = False + end if +; +; ********************************************************************** +; +; If the map projection (map_proj) has not been specified on the command +; line, set it to a default value. +; +; ********************************************************************** +; + if (.not. isvar("map_proj")) then + map_proj := "cyln" + end if +; +; ********************************************************************** +; +; Verify that map_proj is set to a valid value. +; +; ********************************************************************** +; + valid_map_projs = (/ "cyln", "ortho", "lamb" /) + + if (.not. strcmp_exact(valid_map_projs, map_proj)) then + + valid_vals \ + := char_dq \ + + str_join(valid_map_projs, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"The map projection (map_proj) is not set to a valid value:" + char_nl + \ +" map_proj = " + char_dq + map_proj + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with a valid map projection. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; If the center of the specified map projection (map_proj_ctr) has not +; been specified on the command line, set it to a default that depends +; on the map projection. map_proj_ctr should be a 1-D array having two +; elements. These two elements are the longitude (in degrees east) and +; latitude (in degrees north), respectively of the center of the map +; projection. +; +; Note that this variable is not used for <-- Not sure if this is true. I think it is used... +; the cylindrical-equidistant map projection. +; +; ********************************************************************** +; + if (.not. isvar("map_proj_ctr")) then + + map_proj_ctr = new((/2/), "float") + + if (strcmp_exact(map_proj, "cyln")) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (strcmp_exact(map_proj, "ortho")) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 0. + else if (strcmp_exact(map_proj, "lamb")) then + map_proj_ctr(0) = 0. + map_proj_ctr(1) = 90. + end if + end if + end if + + end if +; +; ********************************************************************** +; +; If the units in which to report horizontal distance (horiz_dist_units) +; has not been specified on the command line, set it to a default value. +; +; ********************************************************************** +; + if (.not. isvar("horiz_dist_units")) then + horiz_dist_units := "km" + end if +; +; ********************************************************************** +; +; Verify that horiz_dist_units is set to a valid value. +; +; ********************************************************************** +; + valid_horiz_dist_units = (/ "m", "km" /) + + if (.not. strcmp_exact(valid_horiz_dist_units, horiz_dist_units)) then + + valid_vals \ + := char_dq \ + + str_join(valid_horiz_dist_units, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"The units in which to report horizontal distances (horiz_dist_units) is " + char_nl + \ +"not set to a valid value:" + char_nl + \ +" horiz_dist_units = " + char_dq + horiz_dist_units + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with a valid map projection. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; Set the units in which to report horizontal area (horiz_area_units). +; This depends on the the units in which to report horizontal distance +; (horiz_dist_units). +; +; ********************************************************************** +; + if (strcmp_exact(horiz_dist_units, "m")) then + horiz_area_units := "m^2" + else if (strcmp_exact(horiz_dist_units, "km")) then + horiz_area_units := "km^2" + end if + end if +; +; ********************************************************************** +; +; If plot_subreg is not specified, set it to False. +; +; ********************************************************************** +; + if (.not. isvar("plot_subreg")) then + plot_subreg = False + end if +; +; ********************************************************************** +; +; If plot_subreg is set to True, it means we will plot only a subregion, +; not the whole globe. In this case, verify that the 4-element array +; subreg_limits specifying the limits of the subregion exists and con- +; tains non-missing values. +; +; ********************************************************************** +; + if (plot_subreg) then + + if (.not. isvar("subreg_limits")) then + + msg := char_nl + \ +"When the option to focus the plot on a subregion (plot_subreg) is set " + char_nl + \ +"to True, a 4-element array named " + char_dq + "subreg_limits" + char_dq + \ +" must be specified " + char_nl + \ +"that contains valid subregion limits [in the form (lon_min, lon_max, " + char_nl + \ +"lat_min, lat_max) with units in degrees]:" + char_nl + \ +" plot_subreg = " + plot_subreg + char_nl + \ +" isvar(" + char_dq + "subreg_limits" + char_dq + ") = " + isvar("subreg_limits") + char_nl + \ +"Please rerun with valid subregion limits. " + \ +example_usage_and_help_str + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; If plot_subreg is set to False, the array subreg_limits will not be +; needed, but it must exist in order for this function to return it as +; an attribute of the return variable. Thus, in this case, set subreg_- +; limits to a 4-element array of missing/fill values. +; +; ********************************************************************** +; + else + + subreg_limits := new((/ 4 /), "float") + + end if + + + + + + + + +; +; ********************************************************************** +; +; If the graphics file type (graphics_type) has not been specified on +; the command line, set it to a default value. +; +; ********************************************************************** +; + if (.not. isvar("graphics_type")) then + graphics_type := "png" + end if +; +; ********************************************************************** +; +; Verify that graphics_type is set to a valid value. +; +; ********************************************************************** +; + valid_graphics_types = (/ "png", "ncgm" /) + if (.not. strcmp_exact(valid_graphics_types, graphics_type)) then + + valid_vals \ + := char_dq \ + + str_join(valid_graphics_types, char_dq + ", " + char_dq) \ + + char_dq + + msg := char_nl + \ +"The graphics file type (graphics_type) is not set to a valid value:" + char_nl + \ +" graphics_type = " + char_dq + graphics_type + char_dq + char_nl + \ +"Valid values are:" + char_nl + \ +" " + valid_vals + char_nl + \ +"Please rerun with a valid graphics file type. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if +; +; ********************************************************************** +; +; If the grid type is "regional", then remove_rgnl_halo will be used, so +; it must be defined. Thus, in this case, if it is not defined on the +; command line, we set it to a default value. If the grid type is not +; "regional", remove_rgnl_halo will not be used, but it still needs to +; be defined so that it can be returned to the calling program (see la- +; ter below). Thus, in this case, we set it to False. +; +; ********************************************************************** +; + if (strcmp_exact(gtype, "regional")) then + if (.not. isvar("remove_rgnl_halo")) then + remove_rgnl_halo = False + end if + else + remove_rgnl_halo = False + end if + + + + +; +; ********************************************************************** +; +; Check whether the field name is one that is found in the grid specifi- +; cation file(s). +; +; ********************************************************************** +; + valid_gridfield_names \ + = (/ "cell_area", \ + "sqrt_cell_area", \ + "cell_dx", \ + "cell_dy", \ + "cell_dx_ovr_cell_dy", \ + "min_cell_dx_cell_dy", \ + "angle_cell_dx", \ + "angle_cell_dy" /) + + is_gridfield = False + if (strcmp_exact(valid_gridfield_names, field_name)) then + is_gridfield = True + end if +; +; ********************************************************************** +; +; If the base name of the file from which to read in fields is not spe- +; cified, set it to a blank string. +; +; ********************************************************************** +; + if (.not. isvar("file_basename")) then + + if (is_gridfield) then + + file_basename = "" + + else + + msg := char_nl + \ +"When the field to be plotted is not a grid field [i.e. when is_gridfield " + char_nl + \ +"is False; a grid field is a field that is stored in the grid specification " + char_nl + \ +"file(s)], the base name of the file from which to read in the field [i.e. " + char_nl + \ +"file_basename; this is the file name without an extension (e.g. " + char_dq + ".nc" + char_dq + "), " + char_nl + \ +"the tile number (e.g. " + char_dq + ".tile6" + char_dq + "), and possibly also the halo width (e.g. " + char_nl + \ +char_dq + ".halo4" + char_dq + ")] must be specified:" + char_nl + \ +" is_gridfield = " + is_gridfield + char_nl + \ +" isvar(" + char_dq + "file_basename" + char_dq + ") = " + isvar("file_basename") + char_nl + \ +"Please rerun with a specified file base name. " + \ +example_usage_and_help_str + + print("" + msg) + exit + + end if + + else + + if (is_gridfield) then + + msg := char_nl + \ +"When the field to be plotted is a grid field [i.e. when is_gridfield is " + char_nl + \ +"True; a grid field is a field that is stored in the grid specification " + char_nl + \ +"file(s)], the base name of the file from which to read in the field [i.e. " + char_nl + \ +"file_basename; this is the file name without an extension (e.g. " + char_dq + ".nc" + char_dq + "), " + char_nl + \ +"the tile number (e.g. " + char_dq + ".tile6" + char_dq + "), and possibly also the halo width (e.g. " + char_nl + \ +char_dq + ".halo4" + char_dq + ")] should not be specified on the command line (this file name " + char_nl + \ +"will be formed internally):" + char_nl + \ +" is_gridfield = " + is_gridfield + char_nl + \ +" file_basename = " + char_dq + file_basename + char_dq + " (before resetting to empty string)" + char_nl + \ +"Resetting file_basename to an empty string." + + print("" + msg) + file_basename = "" + + end if + + end if + + + + + +; +; ********************************************************************** +; +; Consider +; +; ********************************************************************** +; + if (strcmp_exact(caller, "plot_grid")) then +; +; ********************************************************************** +; +; If the field to plot (field_name) has not been specified on the command +; line, set it to a default value. +; +; ********************************************************************** +; + if (.not. isvar("field_name")) then +; field_name := "sqrt_cell_area" + field_name := "none" + end if +; +; ********************************************************************** +; +; Verify that field is set to a valid value. +; +; ********************************************************************** +; + valid_gridfield_names \ + = (/ "cell_area", \ + "sqrt_cell_area", \ + "cell_dx", \ + "cell_dy", \ + "cell_dx_ovr_cell_dy", \ + "min_cell_dx_cell_dy", \ + "angle_cell_dx", \ + "angle_cell_dy" /) + + is_gridfield = False + if (strcmp_exact(valid_gridfield_names, field_name)) then + is_gridfield = True + end if +; +; ********************************************************************** +; +; Consider +; +; ********************************************************************** +; + else if (strcmp_exact(caller, "plot_fields")) then +; +; ********************************************************************** +; +; Read in the starting date of the forecast (CDATE) from the variable +; definitions file. +; +; ********************************************************************** +; + +; We cannot read this in from the variable definitions file any longer +; because we chagned from specifying a specific CDATE in that file to +; specifying a range of dates and cycles. Thus, CDATE will have to be +; specified from now on. Check that it is. + +; cmd = "sed --silent --regexp-extended --expression " + \ +; "'s/(^CDATE=)([" + char_dq + "]*)([0-9]+)([" + char_dq + "]*)(.*)/\3/p' " + \ +; var_defns_fn +; CDATE := systemfunc(cmd) + + if (.not. isvar("CDATE")) then + + print("") + print("ERROR: CDATE has not been specified on the command line:") + print("") + print("Please rerun with a specified starting date and hour-of-day. Example:") + print("") + print("" + usage_msg) + print("") + + end if + +;print("CDATE = " + char_dq + CDATE + char_dq) +;exit +; +; ********************************************************************** +; +; Verify that an array named fcst_inds has been specified on the +; command line. This may contain If so, check for indices or 'all' +; +; ********************************************************************** +; + if (.not. isvar("fcst_inds")) then + + print("") + print("ERROR: fcst_inds has not been specified on the command line:") + print("") + print("Please rerun with a specified forecast index. Example:") + print("") + print("" + usage_msg) + print("") + + else + + if (isint(fcst_inds)) then ; Integer indices + print ("fcst_inds is an integer" + fcst_inds) + else if (isstring(fcst_inds)) + print ("fcst_inds is a string" + fcst_inds) + else + print ("ERROR: Check format of fcst_inds.") + exit + end if + end if + n_fcst_inds = dimsizes(fcst_inds) + + end if +; +; ********************************************************************** +; +; Check that the name of the data file has been specified on the command +; line. If not, print out a message and exit. +; +; ********************************************************************** +; + if (.not. isvar("base_name")) then + print("") + print("The data file has not been specified on the command line:") + print(" isvar(" + char_dq + "base_name" + char_dq + ") = " + isvar("base_name")) + print("Please rerun with the data file specified. Example:") + print("" + usage_msg) + print("Stopping.") + exit + end if +; +; ********************************************************************** +; +; Check that the field(s) to plot has been specified on the command line. +; If not, print out a message and exit. +; +; ********************************************************************** +; + if (.not. isvar("fields")) then + print("") + print("The field(s) to plot has not been specified on the command " + \ + "line:") + print(" isvar(" + char_dq + "fields" + char_dq + ") = " + \ + isvar("fields")) + print("Please specify the field(s) to plot on the command line. " + \ + "Example:") + print("" + usage_msg) + print("Stopping.") + exit + else + print ("Fields to be plotted are " + fields) + end if + + end if + end if + + + + +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + plot_params := True + + plot_params@gtype = gtype + plot_params@num_tiles_to_plot = num_tiles_to_plot + plot_params@inds_tiles_to_plot = inds_tiles_to_plot + plot_params@cres = cres + plot_params@expt_dir = expt_dir + + plot_params@horiz_dist_units = horiz_dist_units + plot_params@horiz_area_units = horiz_area_units + + plot_params@show_tile_bdies = show_tile_bdies + plot_params@tile_bdy_color = tile_bdy_color + plot_params@show_tile_grids = show_tile_grids + plot_params@field_name = field_name + plot_params@is_gridfield = is_gridfield + plot_params@file_basename = file_basename + + plot_params@show_RAP_bdy = show_RAP_bdy + plot_params@RAP_bdy_color = RAP_bdy_color + plot_params@show_RAP_grid = show_RAP_grid + plot_params@plot_RAP_field = plot_RAP_field + plot_params@field_name_RAP = field_name_RAP + + plot_params@graphics_type = graphics_type + plot_params@map_proj = map_proj + plot_params@map_proj_ctr = map_proj_ctr + + plot_params@remove_rgnl_halo = remove_rgnl_halo + + plot_params@plot_subreg = plot_subreg + plot_params@subreg_limits = subreg_limits + +; if (strcmp_exact(caller, "plot_grid")) then +; plot_params@field_name = field_name +; else if (strcmp_exact(caller, "plot_fields")) then +;; Add attributes specific to calling plot_fields. +; end if +; end if + + return(plot_params) + + +end + + diff --git a/ush/NCL/read_FV3LAM_field_native.ncl b/ush/NCL/read_FV3LAM_field_native.ncl new file mode 100644 index 0000000000..6a551194a0 --- /dev/null +++ b/ush/NCL/read_FV3LAM_field_native.ncl @@ -0,0 +1,383 @@ +; +; ********************************************************************** +; +; File name: read_FV3LAM_field_native.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "calc_field_stats.ncl") + +load "get_gridfield_info.ncl" + +undef("read_FV3LAM_field_native") + +function read_FV3LAM_field_native( \ + field_names_by_tile[*]:string, \ + file_names_by_tile[*]:string, \ + gtype:string, \ + tile_inds[*]:integer, \ + nh_by_tile[*]:integer, \ + nxh_by_tile[*]:integer, \ + nyh_by_tile[*]:integer, \ + nx_by_tile[*]:integer, \ + ny_by_tile[*]:integer, \ + remove_halo_by_tile[*]:logical, \ + vert_indx:integer, \ + time_indx:integer, \ + func_xy_only:logical, \ + func_xyz_only:logical, \ + func_xyt_only:logical, \ + func_xyzt_only:logical, \ + average_in_x:logical, \ + average_in_y:logical) + +local num_tiles, \ + nn, msg, underline, n_tile, nx, ny, msg_adden, \ + file_name, field_name, \ + fp, \ + field_crnt_tile, field_desc, field_units, \ + field_by_tile_unstruc, \ + field_data_type, \ + print_field_stats, field_stat_info, \ + field_min_by_tile, field_max_by_tile, \ + field_median_by_tile, field_mean_by_tile, \ + field_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Create a string that can be used at the beginning of messages to iden- +; tify this procedure/function as the one generating the messge. +; +; ********************************************************************** +; + id_str := "Message from procedure/function read_FV3LAM_field_native():" +; +; ********************************************************************** +; +; Loop through the specified tiles and read in the grid geometry (i.e. +; coordinates of the cell center and cell vertices) and the value of the +; specified field for each cell. +; +; ********************************************************************** +; + num_tiles = dimsizes(tile_inds) + + nz_by_tile := new(num_tiles, "integer") + nt_by_tile := new(num_tiles, "integer") + + msg := "Looping over tiles to read field(s) from specified file(s) ..." + print("") + print("" + separator_line) + print("" + msg) + + do nn=0, num_tiles-1 + + print("") + msg := "nn = " + nn + print("" + msg) + underline = repeat_str("-", strlen(msg)) + print("" + underline) + + n_tile = tile_inds(nn) + print("") + print(" n_tile = " + n_tile) +; +; ********************************************************************** +; +; Get the number of cells in each of the two (horizontal) directions on +; the current tile. +; +; ********************************************************************** +; + if (remove_halo_by_tile(nn)) then + nx = nx_by_tile(nn) + ny = ny_by_tile(nn) + msg_adden \ + = " (after removing halo of " + nh_by_tile(nn) + " cells)" + else + nx = nxh_by_tile(nn) + ny = nyh_by_tile(nn) + msg_adden = "" + end if + + print("") + print(" Current tile's grid dimensions" + msg_adden + " are:") + print(" nx = " + nx) + print(" ny = " + ny) +; +; ********************************************************************** +; +; Get the file name and field name for the current tile. +; +; ********************************************************************** +; + file_name := file_names_by_tile(nn) + field_name := field_names_by_tile(nn) +; +; ********************************************************************** +; +; Open the file for the current tile for reading. +; +; ********************************************************************** +; + fp = addfile(file_name, "r") +; +; ********************************************************************** +; +; Get the field to plot and store it in the array field_crnt_tile. Al- +; so, set the strings describing the field (field_desc) and its units +; (field_units). +; +; ********************************************************************** +; +; If field_name is set to "none", we create a 2-D array of missing val- +; ues of data type specified by field_data_type_default (e.g. "float" or +; "double"). Note that it doesn't really matter what this default type +; is set to because once non-missing field values are found on any tile, +; the missing values of this default type will be converted to the type +; of the non-missing values. +; + if (strcmp_exact(field_name, "none")) then + + field_data_type_default = "float" + + msg := char_nl + id_str + char_nl + \ +" The field name (field_name) is set to " + char_dq + field_name + char_dq + "." + \ +" Thus, the field will be " + char_nl + \ +" set to an array of missing/fill values of specified default type (" + \ +char_dq + field_data_type_default + char_dq + ") ..." + print("" + msg) + + field_crnt_tile := new((/ ny, nx /), field_data_type_default) + field_desc = "Empty Field" + field_units = "-" + + msg := " Done setting field to an array of missing/fill values." + print("" + msg) +; +; ********************************************************************** +; +; If field_name is not set to "none", we read in the field information +; from file. +; +; ********************************************************************** +; + else + + msg := char_nl + \ +" Reading field from file:" + char_nl + \ +" field_name = " + char_dq + field_name + char_dq + char_nl + \ +" file_name = " + char_dq + file_name + char_dq + print("" + msg) + + dim_sizes = getfilevardimsizes(fp, field_name) + if (func_xy_only) then + field_crnt_tile := fp->$field_name$(:,:) + else if (func_xyz_only) then + nz_by_tile(nn) = dim_sizes(0) + field_crnt_tile := fp->$field_name$(vert_indx,:,:) + else if (func_xyt_only) then + nt_by_tile(nn) = dim_sizes(0) + field_crnt_tile := fp->$field_name$(time_indx,:,:) + else if (func_xyzt_only) then + nz_by_tile(nn) = dim_sizes(1) + nt_by_tile(nn) = dim_sizes(0) + field_crnt_tile := fp->$field_name$(time_indx,vert_indx,:,:) + end if + end if + end if + end if + + field_desc = field_crnt_tile@long_name + field_units = field_crnt_tile@units + + msg := " Done reading field from file." + print("" + msg) + + end if +; +; ********************************************************************** +; +; If on the first tile, convert the 2-D array containing the field val- +; ues at cell centers to a 1-D unstructured array. If on the second, +; third, etc tile, perform this conversion and then concatenate the re- +; sult to the 1-D unstructured array containing the field values on the +; previous tile(s). +; +; ********************************************************************** +; + if (nn .eq. 0) then + + field_by_tile_unstruc := ndtooned(field_crnt_tile) + + else + + field_data_type_prev_tiles = typeof(field_by_tile_unstruc) + field_data_type_crnt_tile = typeof(field_crnt_tile) +; +; If the data type of the field on the tiles considered thus far is not +; the same as that of the field on the current tile, we either perform +; type conversions or exit with an error (depending on the inconsisten- +; cy). +; + if (.not. strcmp_exact(field_data_type_prev_tiles, \ + field_data_type_crnt_tile)) then + + prev_tiles_all_missing := all(ismissing(field_by_tile_unstruc)) + crnt_tile_all_missing := all(ismissing(field_crnt_tile)) + + if (prev_tiles_all_missing .and. (.not. crnt_tile_all_missing)) then + + field_by_tile_unstruc \ + := totype(field_by_tile_unstruc, field_data_type_crnt_tile) + + else if ((.not. prev_tiles_all_missing) .and. crnt_tile_all_missing) then + + field_crnt_tile \ + := totype(field_crnt_tile, field_data_type_prev_tiles) + + else if (prev_tiles_all_missing .and. crnt_tile_all_missing) then + + msg := char_nl + id_str + char_nl + \ +"The field on all previous tiles and on the current tile consists of all " + char_nl + \ +"missing values. In this case, the data type of the missing values on " + char_nl + \ +"the previous tiles should be the same as the data type of the missing " + char_nl + \ +"values on the current tile but is not:" + char_nl + \ +" prev_tiles_all_missing = " + prev_tiles_all_missing + char_nl + \ +" crnt_tile_all_missing = " + crnt_tile_all_missing + char_nl + \ +" field_data_type_prev_tiles = " + char_dq + field_data_type_prev_tiles + char_dq + char_nl + \ +" field_data_type_crnt_tile = " + char_dq + field_data_type_crnt_tile + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if ((.not. prev_tiles_all_missing) .and. \ + (.not. crnt_tile_all_missing)) then + + msg := char_nl + id_str + char_nl + \ +"The field does not contain any missing values on any of the previous " + char_nl + \ +"tiles or on the current tile. In this case, the data type of the values " + char_nl + \ +"on the previous tiles should be the same as the data type of the values " + char_nl + \ +"on current tiles but is not:" + char_nl + \ +" prev_tiles_all_missing = " + prev_tiles_all_missing + char_nl + \ +" crnt_tile_all_missing = " + crnt_tile_all_missing + char_nl + \ +" field_data_type_prev_tiles = " + char_dq + field_data_type_prev_tiles + char_dq + char_nl + \ +" field_data_type_crnt_tile = " + char_dq + field_data_type_crnt_tile + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if + end if + end if + + end if + + field_by_tile_unstruc \ + := array_append_record(field_by_tile_unstruc, ndtooned(field_crnt_tile), 0) + + end if +; +; ********************************************************************** +; +; Get the field's data type (usually "float" or "double"). +; +; ********************************************************************** +; + field_data_type = typeof(field_by_tile_unstruc) +; +; ********************************************************************** +; +; Calculate (and possibly print out) basic statistics of the field. +; +; ********************************************************************** +; + msg := \ +" Calculating statistics of field on the tile " + n_tile + " grid ..." + print("") + print("" + msg) + + print_field_stats = False + field_stat_info \ + := calc_field_stats( \ + field_crnt_tile, field_desc, field_units, print_field_stats) + msg := " " + field_stat_info@msg + print("") + print("" + msg) + + msg := \ +" Done calculating statistics of field on the tile " + n_tile + " grid." + print("") + print("" + msg) +; +; ********************************************************************** +; +; Save field statistics in appropriate arrays. +; +; ********************************************************************** +; + if (nn .eq. 0) then + field_min_by_tile := new((/ num_tiles /), field_data_type) + field_max_by_tile := new((/ num_tiles /), field_data_type) + field_median_by_tile := new((/ num_tiles /), field_data_type) + field_mean_by_tile := new((/ num_tiles /), field_data_type) + end if + + field_min_by_tile(nn) = field_stat_info@field_min + field_max_by_tile(nn) = field_stat_info@field_max + field_median_by_tile(nn) = field_stat_info@field_median + field_mean_by_tile(nn) = field_stat_info@field_mean + + end do + + print("") + print("Done reading field(s) from grid files.") + print("" + separator_line) +; +; ********************************************************************** +; +; Return results as attributes of the logical variable field_info. +; +; ********************************************************************** +; + field_info = True + + field_info@field_desc = field_desc + field_info@field_units = field_units + field_info@nz_by_tile = nz_by_tile + field_info@nt_by_tile = nt_by_tile + field_info@field_by_tile_unstruc = field_by_tile_unstruc + field_info@field_min_by_tile = field_min_by_tile + field_info@field_max_by_tile = field_max_by_tile + field_info@field_median_by_tile = field_median_by_tile + field_info@field_mean_by_tile = field_mean_by_tile + field_info@field_data_type = field_data_type + + return(field_info) + +end + + diff --git a/ush/NCL/read_FV3LAM_field_wrtcmp.ncl b/ush/NCL/read_FV3LAM_field_wrtcmp.ncl new file mode 100644 index 0000000000..440bdb81c9 --- /dev/null +++ b/ush/NCL/read_FV3LAM_field_wrtcmp.ncl @@ -0,0 +1,188 @@ +; +; ********************************************************************** +; +; File name: read_FV3LAM_field_wrtcmp.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "calc_field_stats.ncl") + +undef("read_FV3LAM_field_wrtcmp") + +function read_FV3LAM_field_wrtcmp( \ + field_name:string, \ + horiz_dist_units:string, \ + horiz_area_units:string, \ + wrtcmp_fn:string, \ + nx:integer, \ + ny:integer, \ + vert_indx:integer, \ + time_indx:integer, \ + func_xy_only:logical, \ + func_xyz_only:logical, \ + func_xyt_only:logical, \ + func_xyzt_only:logical \ + ) + +local fp, \ + field_data_type, \ + field_desc, field_units, \ + field_vert, field_cntr, \ + field_unstruc, \ + msg, print_field_stats, field_stat_info, \ + field_min, field_max, field_median, field_mean, \ + field_info + +begin +; +; ********************************************************************** +; +; Open the specified file for reading. +; +; ********************************************************************** +; + print("") + print("" + separator_line) + print("Reading write-component field from file:") + print("") + print(" wrtcmp_fn = " + char_dq + wrtcmp_fn + char_dq) + + fp = addfile(wrtcmp_fn, "r") +; +; ********************************************************************** +; +; Get the data type (i.e. float or double) of the fields in the speci- +; fied file. We assume here that all real-numbered fields are of the +; same type, so we read in the type of only one such field. +; +; ********************************************************************** +; + field_data_type = getfilevartypes(fp, field_name) +; +; ********************************************************************** +; +; Set field-related parameters. +; +; ********************************************************************** +; + if (strcmp_exact(field_name, "none")) then + + field_vert := new((/ ny, nx /), field_data_type) + + field_desc = "Empty Field" + field_units = "-" + + else +; +; Read in the field at grid cell vertices. +; + if (func_xy_only) then + field_vert := fp->$field_name$(:,:) + else if (func_xyz_only) then + field_vert := fp->$field_name$(vert_indx,:,:) + else if (func_xyt_only) then + field_vert := fp->$field_name$(time_indx,:,:) + else if (func_xyzt_only) then + field_vert := fp->$field_name$(time_indx,vert_indx,:,:) + end if + end if + end if + end if + + field_vert := rm_single_dims(field_vert) + + field_desc = field_vert@long_name + field_units = field_vert@units + + end if +; +; ********************************************************************** +; +; Calculate field at cell centers from its values at cell vertices. +; +; ********************************************************************** +; + field_cntr = field_vert(0:ny-1,0:nx-1) \ + + field_vert(0:ny-1,1:nx) \ + + field_vert(1:ny,1:nx) \ + + field_vert(1:ny,0:nx-1) + field_cntr = 0.25*field_cntr +; +; ********************************************************************** +; +; Convert the 2-D array containing the field to a 1-D array in unstruc- +; tured format. +; +; ********************************************************************** +; + field_unstruc := ndtooned(field_cntr) +; +; ********************************************************************** +; +; Calculate (and possibly print out) basic statistics of the field. +; +; ********************************************************************** +; + msg := " Calculating statistics of field on write-component grid ..." + print("") + print("" + msg) + +; print_field_stats = True + print_field_stats = False + field_stat_info \ + := calc_field_stats( \ + field_cntr, field_desc, field_units, print_field_stats) + msg := " " + field_stat_info@msg + print("") + print("" + msg) + + msg := " Done calculating statistics of field on write_component grid." + print("") + print("" + msg) +; +; ********************************************************************** +; +; Save field statistics in appropriate variables. +; +; ********************************************************************** +; + field_min := field_stat_info@field_min + field_max := field_stat_info@field_max + field_median := field_stat_info@field_median + field_mean := field_stat_info@field_mean + + print("") + print("Done reading field from write-component file.") + print("" + separator_line) +; +; ********************************************************************** +; +; Return results as attributes of the logical variable field_info. +; +; ********************************************************************** +; + field_info = True + + field_info@fp = fp + field_info@field_desc = field_desc + field_info@field_units = field_units + field_info@field_unstruc = field_unstruc + field_info@field_min = field_min + field_info@field_max = field_max + field_info@field_median = field_median + field_info@field_mean = field_mean + field_info@field_data_type = field_data_type + + return(field_info) + +end + + diff --git a/ush/NCL/read_FV3LAM_grid_native.ncl b/ush/NCL/read_FV3LAM_grid_native.ncl new file mode 100644 index 0000000000..e676163be0 --- /dev/null +++ b/ush/NCL/read_FV3LAM_grid_native.ncl @@ -0,0 +1,1219 @@ +; +; ********************************************************************** +; +; File name: read_FV3LAM_grid_native.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns the file names, dimensions, cell center coordinates, +; and cell vertex coordinates of the grids associated with the specified +; FV3 cubed-sphere tiles (tile_inds). If get_tile_bdies is set to True, +; it also returns the coordinates of those grid cell vertices that lie on +; the boundary of each specified tile. +; +; The input arguments to this function are as follows: +; +; expt_dir: +; This is the experiment directory created by the FV3SAR workflow generation +; script. The grid specification files corresponding to the cubed-sphere +; tiles are within subdirectories under this directory. +; +; gtype: +; This is a string containing the type of the FV3 cubed-sphere grid being +; read in. For files generated by the FV3SAR workflow, this will be equal +; to "regional". +; +; cres: +; This is the C-resolution of the global cubed-sphere grid that serves +; as the "parent" of the regional grid. It consists of the character +; "C" followed by an interger that is equal to the number of grid cells +; in each of the two horizontal directions (say x and y) on each of the +; six tiles of the parent global grid. Note that this number is in general +; not equal to the number of grid cells on the regional grid (i.e. the +; one on tile 7) because the latter is given by the former multiplied by +; a refinement factor (an integer) that is normally greater than 1. +; +; tile_inds: +; The indices of the tiles (associated with ither the parent global grid +; or the regional grid) to consider in this function. +; +; get_tile_bdies: +; A logical variable that specifies whether arrays containing the coordinates +; of grid cell vertices that lie on the boundary of each tile specified +; in tile_inds are to be extracted and returned. +; +; nhalo_T7: +; The width of the halo (in units of grid cells) included in the grid +; specification file for the regional grid (tile 7). If tile_inds includes +; tile 7, then this is used to form the name of the grid file for that +; tile. Also, if tile_inds includes tile 7 and if remove_rgnl_halo is +; set to True, then a halo of width nhalo_T7 is removed from any arrays +; read in from the tile 7 grid file. This is not used if tile_inds does +; not include tile 7. +; +; remove_rgnl_halo: +; Flag indicating whether to remove a halo of width nhalo_T7 from any +; arrays read in from the tile 7 grid file. This is not used if tile_inds +; does not include tile 7. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "strpad.ncl") +loadscript(lib_location + "get_rect_grid_bdy.ncl") +loadscript(lib_location + "get_rect_grid_corners.ncl") +loadscript(lib_location + "adjust_longitude_range.ncl") + +undef("read_FV3LAM_grid_native") + +function read_FV3LAM_grid_native( \ + expt_dir:string, \ + gtype:string, \ + cres:string, \ + tile_inds:integer, \ + get_tile_bdies:logical, \ + nhalo_T7:integer, \ + remove_rgnl_halo:logical) + +local num_tiles_to_plot, \ +\ + grid_fn_all_tiles, remove_halo_all_tiles, \ +\ + nhSG_all_tiles, nxhSG_all_tiles, nyhSG_all_tiles, \ + nxSG_all_tiles, nySG_all_tiles, \ + nh_all_tiles, nxh_all_tiles, nyh_all_tiles, \ + nx_all_tiles, ny_all_tiles, \ +\ + coord_data_type_all_tiles, \ +\ + nn, msg, underline, n_tile, grid_fn, fp, \ + tile_SG_dims, \ +\ + coord_data_type, match_found, match_by_elem, \ +\ + lon_cntrs_all_tiles_unstruc, lat_cntrs_all_tiles_unstruc, \ + lon_verts_all_tiles_unstruc, lat_verts_all_tiles_unstruc, \ + lon_bdy_all_tiles, lat_bdy_all_tiles, \ +\ + lon_tile_cntr_all_tiles, lat_tile_cntr_all_tiles, \ + lon_tile_corners_face_midpts_all_tiles, \ + lat_tile_corners_face_midpts_all_tiles, \ +\ + nhSG, nxhSG, nyhSG, nxSG, nySG, \ + nh, nxh, nyh, nx, ny, \ + remove_halo, \ +\ + lon_verts_SG_crnt_tile, lat_verts_SG_crnt_tile, \ + lon_verts_crnt_tile, lat_verts_crnt_tile, \ + lon_cntrs_crnt_tile, lat_cntrs_crnt_tile, \ +\ + repeat_last_point, array_order, bdy_info, \ + lon_bdy_crnt_tile, lat_bdy_crnt_tile, \ +\ + x_is_longitude, opts, corner_info, corner_lons, corner_lats, \ + fmt_str, lon_str, lat_str, \ + i_left, i_cntr, i_rght, j_bot, j_mid, j_top, \ + loc_names, i, \ +\ + lon_cntrs_crnt_tile_unstruc, lat_cntrs_crnt_tile_unstruc, \ + lon_verts_crnt_tile_unstruc, lat_verts_crnt_tile_unstruc, \ +\ + grid_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string separator_line that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Loop through the tiles and set the following arrays: +; +; grid_fn_all_tiles: +; Full path to the grid file corresponding to each tile. Note that the +; grid file contains information (coordinates, etc) on the supergrid of +; a given tile, where the supergrid is a grid having twice the resolution +; of the actual (i.e. computational) grid. +; +; remove_halo_all_tiles: +; Logical array that specifies whether the halo cells around a given tile +; should be removed before plotting or other processing. +; +; nhSG_all_tiles: +; Halo width on the supergrid of each tile, in units of supergrid cells. +; Normally, only tile 7 of a regional or nexted grid has a halo, so this +; will be zero for tiles 1 through 6. +; +; nxhSG_all_tiles, nyhSG_all_tiles: +; Number of cells, including the halo, in the x and y directions, +; respectively, on the supergrid of each tile. +; +; nxSG_all_tiles, nySG_all_tiles: +; Number of cells, excluding the halo, in the x and y directions, +; respectively, on the supergrid of each tile. +; +; nh_all_tiles: +; Halo width on the computational grid of each tile, in units of grid +; cells. Normally, only tile 7 of a regional or nexted grid has a halo, +; so this will be zero for tiles 1 through 6. +; +; nxh_all_tiles, nyh_all_tiles: +; Number of cells, including the halo, in the x and y directions, +; respectively, on the computational grid of each tile. +; +; nx_all_tiles, ny_all_tiles: +; Number of cells, excluding the halo, in the x and y directions, +; respectively, on the computational grid of each tile. +; +; coord_data_type_all_tiles: +; The data type of the coordinate arrays in the grid file corresponding +; to each tile. +; +; ********************************************************************** +; + num_tiles_to_plot = dimsizes(tile_inds) + + grid_fn_all_tiles := new((/ num_tiles_to_plot /), "string") + + remove_halo_all_tiles := new((/ num_tiles_to_plot /), "logical") + + nhSG_all_tiles := new((/ num_tiles_to_plot /), "integer") + nxhSG_all_tiles := new((/ num_tiles_to_plot /), "integer") + nyhSG_all_tiles := new((/ num_tiles_to_plot /), "integer") + nxSG_all_tiles := new((/ num_tiles_to_plot /), "integer") + nySG_all_tiles := new((/ num_tiles_to_plot /), "integer") + + nh_all_tiles := new((/ num_tiles_to_plot /), "integer") + nxh_all_tiles := new((/ num_tiles_to_plot /), "integer") + nyh_all_tiles := new((/ num_tiles_to_plot /), "integer") + nx_all_tiles := new((/ num_tiles_to_plot /), "integer") + ny_all_tiles := new((/ num_tiles_to_plot /), "integer") + + coord_data_type_all_tiles := new((/ num_tiles_to_plot /), "string") + + print("") + print("" + separator_line) + print("Setting grid file name and dimensions of each specified tile ...") + + do nn=0, num_tiles_to_plot-1 + + print("") + msg := "nn = " + nn + print("" + msg) + underline = repeat_str("-", strlen(msg)) + print("" + underline) + + n_tile = tile_inds(nn) + print("") + print(" n_tile = " + n_tile) +; +; ********************************************************************** +; +; Set the file name (including path) for the current tile. Then save the +; result in the grid_fn_all_tiles array for later use. +; +; ********************************************************************** +; +; Maybe read in the new parameter DOT_OR_USCORE from the var_defns.sh file. + grid_fn = cres + "_grid.tile" + n_tile +; grid_fn = cres + ".grid.tile" + n_tile + if (strcmp_exact(gtype, "regional") .and. (n_tile .eq. 7)) then + grid_fn = grid_fn + ".halo" + tostring(nhalo_T7) + ".nc" + else + grid_fn = grid_fn + ".nc" + end if +; grid_fn = expt_dir + "/fix_sar/" + grid_fn + grid_fn = expt_dir + "/fix_lam/" + grid_fn + + grid_fn_all_tiles(nn) = grid_fn + print(" grid_fn_all_tiles(" + nn + ") = " + \ + char_dq + grid_fn_all_tiles(nn) + char_dq) +; +; ********************************************************************** +; +; Open the NetCDF file containing the grid specification for the current +; tile. +; +; ********************************************************************** +; + fp = addfile(grid_fn_all_tiles(nn), "r") +; +; ********************************************************************** +; +; Set the halo width (in units of cells). Note that this is zero unless +; we're on a regional or nested grid and and the current tile is tile 7 +; (the regional or nested domain/grid). Also, set the logical variable +; that determines whether the halo should be removed from the current +; tile before any processing is performed. This is set to True only if +; we're on tile 7 of a regional or nested grid and remove_rgnl_halo is +; set to True. +; +; ********************************************************************** +; + nhSG_all_tiles(nn) = 0 + remove_halo_all_tiles(nn) = False + + if ((strcmp_exact(gtype, "regional") .or. \ + strcmp_exact(gtype, "nest")) .and. \ + (n_tile .eq. 7)) then + + nhSG_all_tiles(nn) = 2*nhalo_T7 + if (remove_rgnl_halo) then + remove_halo_all_tiles(nn) = True + end if + + end if + + nh_all_tiles(nn) = nhSG_all_tiles(nn)/2 +; +; ********************************************************************** +; +; Read in the dimensions of the tile's supergrid (which has twice the +; resolution as the tile's grid). From these, calculate the dimensions +; of the supergrid. +; +; ********************************************************************** +; + tile_SG_dims := getfilevardimsizes(fp, "area") + + nxhSG_all_tiles(nn) = tile_SG_dims(1) + nyhSG_all_tiles(nn) = tile_SG_dims(0) + nxSG_all_tiles(nn) = nxhSG_all_tiles(nn) - 2*nhSG_all_tiles(nn) + nySG_all_tiles(nn) = nyhSG_all_tiles(nn) - 2*nhSG_all_tiles(nn) + + print("") + print(" nhSG_all_tiles(" + nn + ") = " + nhSG_all_tiles(nn)) + print(" nxhSG_all_tiles(" + nn + ") = " + nxhSG_all_tiles(nn)) + print(" nyhSG_all_tiles(" + nn + ") = " + nyhSG_all_tiles(nn)) + print(" nxSG_all_tiles(" + nn + ") = " + nxSG_all_tiles(nn)) + print(" nySG_all_tiles(" + nn + ") = " + nySG_all_tiles(nn)) +; +; ********************************************************************** +; +; Calculate the dimensions of the computational grid. +; +; ********************************************************************** +; + nxh_all_tiles(nn) = nxhSG_all_tiles(nn)/2 + nyh_all_tiles(nn) = nyhSG_all_tiles(nn)/2 + nx_all_tiles(nn) = nxh_all_tiles(nn) - 2*nh_all_tiles(nn) + ny_all_tiles(nn) = nyh_all_tiles(nn) - 2*nh_all_tiles(nn) + + print("") + print(" nh_all_tiles(" + nn + ") = " + nh_all_tiles(nn)) + print(" nxh_all_tiles(" + nn + ") = " + nxh_all_tiles(nn)) + print(" nyh_all_tiles(" + nn + ") = " + nyh_all_tiles(nn)) + print(" nx_all_tiles(" + nn + ") = " + nx_all_tiles(nn)) + print(" ny_all_tiles(" + nn + ") = " + ny_all_tiles(nn)) +; +; ********************************************************************** +; +; Get the data type of the x coordinate in the grid specification file. +; We assume here that the x and y coordinates have the same data type. +; +; ********************************************************************** +; + coord_data_type_all_tiles(nn) = getfilevartypes(fp, "x") + + print("") + print(" coord_data_type_all_tiles(" + nn + ") = " + \ + char_dq + coord_data_type_all_tiles(nn) + char_dq) + + end do + + print("") + print("Done setting grid file name and dimensions of each specified tile.") + print("" + separator_line) +; +; ********************************************************************** +; +; Compare the coordinate data types of all tiles. For simplicity, we +; will require that all tiles have the same coordinate data type. If +; this is not the case, print out an error message and exit. +; +; ********************************************************************** +; + coord_data_type := coord_data_type_all_tiles(0) + + if (num_tiles_to_plot .gt. 1) then + + match_found \ + := strcmp_exact( \ + coord_data_type_all_tiles(1:num_tiles_to_plot-1), \ + coord_data_type) + match_by_elem = match_found@match_by_elem + + if (.not. all(match_by_elem)) then + + msg := " coord_data_type_all_tiles(" \ + + ispan(0, num_tiles_to_plot-1, 1) \ + + ") = " + char_dq + coord_data_type_all_tiles + char_dq + msg := str_join(msg, char_nl) + + msg := char_nl + \ +"For simplicity, we require that the coordinate arrays in the files " + char_nl + \ +"corresponding to the specified tiles all have the same data type. In " + char_nl + \ +"this case, they are not:" + char_nl + \ +msg + char_nl + \ +"Stopping." + + print("" + msg) + exit + + end if + + end if + + msg := char_nl + \ +"The data type of the coordinates in the grid specification files for " + char_nl + \ +"all tiles is:" + char_nl + \ +" coord_data_type = " + char_dq + coord_data_type + char_dq + print("" + msg) +; +; ********************************************************************** +; +; Initialize the arrays that will contain the grid and boundary coordinates +; of all specified tiles to 1-element arrays containing missing values +; of type coord_data_type. After the coordinates are appended to these +; arrays in the loop below, the first elements of these arrays will be +; stripped away (since they are created here only to make it convenient +; to append to the arrays). +; +; ********************************************************************** +; + lon_cntrs_all_tiles_unstruc := new(1, coord_data_type) + lat_cntrs_all_tiles_unstruc := new(1, coord_data_type) + lon_verts_all_tiles_unstruc := new((/1,4/), coord_data_type) + lat_verts_all_tiles_unstruc := new((/1,4/), coord_data_type) + lon_bdy_all_tiles := new(1, coord_data_type) + lat_bdy_all_tiles := new(1, coord_data_type) + + lon_halo_cntrs_all_tiles_unstruc := new(1, coord_data_type) + lat_halo_cntrs_all_tiles_unstruc := new(1, coord_data_type) + lon_halo_verts_all_tiles_unstruc := new((/1,4/), coord_data_type) + lat_halo_verts_all_tiles_unstruc := new((/1,4/), coord_data_type) + lon_halo_bdy_all_tiles := new(1, coord_data_type) + lat_halo_bdy_all_tiles := new(1, coord_data_type) +; +; ********************************************************************** +; +; Initialize the arrays that will contain the coorinates of the tile +; centers and the tile corners and midpoints to missing values of type +; coord_data_type. +; +; ********************************************************************** +; + lon_tile_cntr_all_tiles := new((/ num_tiles_to_plot /), coord_data_type) + lat_tile_cntr_all_tiles := new((/ num_tiles_to_plot /), coord_data_type) + + lon_tile_corners_face_midpts_all_tiles \ + := new((/ num_tiles_to_plot, 8 /), coord_data_type) + lat_tile_corners_face_midpts_all_tiles \ + := new((/ num_tiles_to_plot, 8 /), coord_data_type) +; +; ********************************************************************** +; +; Loop through the specified tiles and read in and process coordinate +; arrays. +; +; ********************************************************************** +; + print("") + print("" + separator_line) + print("Reading in grid coordinates of each specified tile from file ...") + + do nn=0, num_tiles_to_plot-1 + + n_tile = tile_inds(nn) + print("") + print(" n_tile = " + n_tile) +; +; ********************************************************************** +; +; Get grid dimensions of current tile. +; +; ********************************************************************** +; + nhSG = nhSG_all_tiles(nn) + nxhSG = nxhSG_all_tiles(nn) + nyhSG = nyhSG_all_tiles(nn) + nxSG = nxSG_all_tiles(nn) + nySG = nySG_all_tiles(nn) + + nh = nh_all_tiles(nn) + nxh = nxh_all_tiles(nn) + nyh = nyh_all_tiles(nn) + nx = nx_all_tiles(nn) + ny = ny_all_tiles(nn) + + remove_halo = remove_halo_all_tiles(nn) +; +; ********************************************************************** +; +; Open the NetCDF file containing the grid specification for the current +; tile. +; +; ********************************************************************** +; + fp = addfile(grid_fn_all_tiles(nn), "r") +; +; ********************************************************************** +; +; Read in the supergrid coordinates. The supergrid of a given tile is a +; grid having twice the resolution of the actual (i.e. computational) +; grid of that tile. It is used to store the coordintes of both the +; centers and the vertices of the cells on the computational grid. +; +; ********************************************************************** +; + lon_verts_SG_crnt_tile := fp->x(:,:) + lat_verts_SG_crnt_tile := fp->y(:,:) + + lon_verts_SG_crnt_tile \ + := adjust_longitude_range(lon_verts_SG_crnt_tile, -180.0d+0, "degs") +; +; ********************************************************************** +; +; Get the coordinates of the cell vertices on the current tile from those +; of the supergrid. +; +; ********************************************************************** +; + lon_verts_crnt_tile := lon_verts_SG_crnt_tile(0::2,0::2) + lat_verts_crnt_tile := lat_verts_SG_crnt_tile(0::2,0::2) +; +; ********************************************************************** +; +; Get the coordinates of the cell centers on the current tile from those +; of the supergrid. +; +; ********************************************************************** +; + lon_cntrs_crnt_tile := lon_verts_SG_crnt_tile(1::2,1::2) + lat_cntrs_crnt_tile := lat_verts_SG_crnt_tile(1::2,1::2) +; +; ********************************************************************** +; +; Set arrays containing the coordinates of just the halo cells (with all +; internal cells' coordinates set to the approprite type of fill value). +; This approach allows us to more conveniently plot just the halo cells +; using the same plotting routines as for the internal cells. +; +; ********************************************************************** +; + lon_halo_cntrs_crnt_tile := lon_cntrs_crnt_tile + lon_halo_cntrs_crnt_tile(nh:nyh-nh,nh:nxh-nh) \ + = default_fillvalue(coord_data_type) + lat_halo_cntrs_crnt_tile := lat_cntrs_crnt_tile + lat_halo_cntrs_crnt_tile(nh:nyh-nh,nh:nxh-nh) \ + = default_fillvalue(coord_data_type) + + lon_halo_verts_crnt_tile := lon_verts_crnt_tile + lon_halo_verts_crnt_tile(nh+1:nyh-nh-1,nh+1:nxh-nh-1) \ + = default_fillvalue(coord_data_type) + lat_halo_verts_crnt_tile := lat_verts_crnt_tile + lat_halo_verts_crnt_tile(nh+1:nyh-nh-1,nh+1:nxh-nh-1) \ + = default_fillvalue(coord_data_type) +; +; ********************************************************************** +; +; If on a regional grid, if the current tile is tile 7 (the regional +; domain/grid), and if remove_rgnl_halo is set to True, then remove a +; halo of width nhalo_T7 cells from each of the coordinate arrays. +; +; ********************************************************************** +; + if (remove_halo) then + + print("") + print(" Removing halo cells from coordinate arrays of tile " + \ + n_tile + " ...") +; +; ********************************************************************** +; +; Remove halo cells from the arrays containing coordinates of the cell +; vertices of the supergrid. +; +; ********************************************************************** +; + lon_verts_SG_crnt_tile \ + := lon_verts_SG_crnt_tile(nhSG:nyhSG-nhSG, nhSG:nxhSG-nhSG) + lat_verts_SG_crnt_tile \ + := lat_verts_SG_crnt_tile(nhSG:nyhSG-nhSG, nhSG:nxhSG-nhSG) +; +; ********************************************************************** +; +; Remove halo cells from the arrays containing the coordinates of cell +; centers of the computational grid. +; +; ********************************************************************** +; + lon_cntrs_crnt_tile \ + := lon_cntrs_crnt_tile(nh:nyh-1-nh, nh:nxh-1-nh) + lat_cntrs_crnt_tile \ + := lat_cntrs_crnt_tile(nh:nyh-1-nh, nh:nxh-1-nh) +; +; ********************************************************************** +; +; Remove halo cells from the arrays containing coordinates of the cell +; vertices of the computational grid. +; +; ********************************************************************** +; + lon_verts_crnt_tile := lon_verts_crnt_tile(nh:nyh-nh, nh:nxh-nh) + lat_verts_crnt_tile := lat_verts_crnt_tile(nh:nyh-nh, nh:nxh-nh) + + print(" Done removing halo cells from coordinate arrays of " + \ + "tile " + n_tile + ".") + + end if +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the coordinates of +; the center of each cell on the current tile. Note that these are 1-D +; arrays, and their size (i.e. the number of elements they contain) is +; equal to the number of cells on the current tile's grid (i.e. nxh*nyh +; or nx*ny). This unstructured format is useful for generating color- +; contour plots of fields on the grid that have one value per cell +; represented by a flat color in that cell. +; +; ********************************************************************** +; + lon_cntrs_crnt_tile_unstruc := ndtooned(lon_cntrs_crnt_tile) + lat_cntrs_crnt_tile_unstruc := ndtooned(lat_cntrs_crnt_tile) + + lon_halo_cntrs_crnt_tile_unstruc := ndtooned(lon_halo_cntrs_crnt_tile) + lat_halo_cntrs_crnt_tile_unstruc := ndtooned(lat_halo_cntrs_crnt_tile) +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the coordinates of +; the vertices of each cell on the current tile. Note that these are +; 2-D arrays whose first dimension size is the number of cells on the +; current tile's grid (i.e. nxh*nyh or nx*ny) and whose second dimension +; size is 4 (since each cell has 4 vertices). This unstructured format +; is useful for generating color-contour plots of fields on the grid +; that have one value per cell represented by a flat color in that cell. +; +; ********************************************************************** +; + +; Get dimensions again because they depend on whether the halo is being +; removed or not (remove_rgnl_halo). + dims := dimsizes(lon_cntrs_crnt_tile) + endx := dims(1) + endy := dims(0) + + lon_verts_crnt_tile_unstruc \ + := (/ ndtooned(lon_verts_crnt_tile(0:endy-1,0:endx-1)), \ + ndtooned(lon_verts_crnt_tile(0:endy-1,1:endx)), \ + ndtooned(lon_verts_crnt_tile(1:endy,1:endx)), \ + ndtooned(lon_verts_crnt_tile(1:endy,0:endx-1)) /) + lon_verts_crnt_tile_unstruc \ + := transpose(lon_verts_crnt_tile_unstruc) + + lat_verts_crnt_tile_unstruc \ + := (/ ndtooned(lat_verts_crnt_tile(0:endy-1,0:endx-1)), \ + ndtooned(lat_verts_crnt_tile(0:endy-1,1:endx)), \ + ndtooned(lat_verts_crnt_tile(1:endy,1:endx)), \ + ndtooned(lat_verts_crnt_tile(1:endy,0:endx-1)) /) + lat_verts_crnt_tile_unstruc \ + := transpose(lat_verts_crnt_tile_unstruc) + + +; Do same for halo coordinates. + lon_halo_verts_crnt_tile_unstruc \ + := (/ ndtooned(lon_halo_verts_crnt_tile(0:nyh-1,0:nxh-1)), \ + ndtooned(lon_halo_verts_crnt_tile(0:nyh-1,1:nxh)), \ + ndtooned(lon_halo_verts_crnt_tile(1:nyh,1:nxh)), \ + ndtooned(lon_halo_verts_crnt_tile(1:nyh,0:nxh-1)) /) + lon_halo_verts_crnt_tile_unstruc \ + := transpose(lon_halo_verts_crnt_tile_unstruc) + + lat_halo_verts_crnt_tile_unstruc \ + := (/ ndtooned(lat_halo_verts_crnt_tile(0:nyh-1,0:nxh-1)), \ + ndtooned(lat_halo_verts_crnt_tile(0:nyh-1,1:nxh)), \ + ndtooned(lat_halo_verts_crnt_tile(1:nyh,1:nxh)), \ + ndtooned(lat_halo_verts_crnt_tile(1:nyh,0:nxh-1)) /) + lat_halo_verts_crnt_tile_unstruc \ + := transpose(lat_halo_verts_crnt_tile_unstruc) + + do i=0, nxh-1 + do j=0, nyh-1 + if ((i .ge. nh) .and. (i .le. nxh-nh-1)) .and. \ + ((j .ge. nh) .and. (j .le. nyh-nh-1)) then + indx = i + j*nxh + lon_halo_verts_crnt_tile_unstruc(indx,:) = default_fillvalue(coord_data_type) + lat_halo_verts_crnt_tile_unstruc(indx,:) = default_fillvalue(coord_data_type) + end if + end do + end do +; +; ********************************************************************** +; +; Append to the unstructured arrays that will contain the coordinates of +; the cell centers and cell vertices on all specified tiles. We refer +; to these as the "all-tiles" arrays. +; +; ********************************************************************** +; + lon_cntrs_all_tiles_unstruc \ + := array_append_record( \ + lon_cntrs_all_tiles_unstruc, lon_cntrs_crnt_tile_unstruc, 0) + lat_cntrs_all_tiles_unstruc \ + := array_append_record( \ + lat_cntrs_all_tiles_unstruc, lat_cntrs_crnt_tile_unstruc, 0) + + lon_verts_all_tiles_unstruc \ + := array_append_record( \ + lon_verts_all_tiles_unstruc, lon_verts_crnt_tile_unstruc, 0) + lat_verts_all_tiles_unstruc \ + := array_append_record( \ + lat_verts_all_tiles_unstruc, lat_verts_crnt_tile_unstruc, 0) + + lon_halo_cntrs_all_tiles_unstruc \ + := array_append_record( \ + lon_halo_cntrs_all_tiles_unstruc, lon_halo_cntrs_crnt_tile_unstruc, 0) + lat_halo_cntrs_all_tiles_unstruc \ + := array_append_record( \ + lat_halo_cntrs_all_tiles_unstruc, lat_halo_cntrs_crnt_tile_unstruc, 0) + + lon_halo_verts_all_tiles_unstruc \ + := array_append_record( \ + lon_halo_verts_all_tiles_unstruc, lon_halo_verts_crnt_tile_unstruc, 0) + lat_halo_verts_all_tiles_unstruc \ + := array_append_record( \ + lat_halo_verts_all_tiles_unstruc, lat_halo_verts_crnt_tile_unstruc, 0) +; +; ********************************************************************** +; +; If get_tile_bdies is True, generate unstructured boundary coordinate +; arrays. +; +; ********************************************************************** +; + if (get_tile_bdies) then +; +; First, get the coordinates of the boundary points on the current tile. +; Here, by "boundary points", we mean those cell vertices that happen to +; lie on the tile's boundary. +; + repeat_last_point = True + array_order = "ji" + bdy_info := get_rect_grid_bdy( \ + lon_verts_crnt_tile, lat_verts_crnt_tile, \ + repeat_last_point, array_order) + lon_bdy_crnt_tile := bdy_info@x_bdy + lat_bdy_crnt_tile := bdy_info@y_bdy +; +; Append to the arrays that will contain the coordinates of the boundary +; points on all specified tiles. We refer to these as the "all-tiles" +; arrays. +; + lon_bdy_all_tiles \ + := array_append_record(lon_bdy_all_tiles, lon_bdy_crnt_tile, 0) + lat_bdy_all_tiles \ + := array_append_record(lat_bdy_all_tiles, lat_bdy_crnt_tile, 0) + + +; Do same for halo coordinates. +; +; First, get the coordinates of the boundary points on the current tile. +; Here, by "boundary points", we mean those cell vertices that happen to +; lie on the tile's boundary. +; + repeat_last_point = True + array_order = "ji" + bdy_info := get_rect_grid_bdy( \ + lon_halo_verts_crnt_tile, lat_halo_verts_crnt_tile, \ + repeat_last_point, array_order) + lon_halo_bdy_crnt_tile := bdy_info@x_bdy + lat_halo_bdy_crnt_tile := bdy_info@y_bdy +; +; Append to the arrays that will contain the coordinates of the boundary +; points on all specified tiles. We refer to these as the "all-tiles" +; arrays. +; + lon_halo_bdy_all_tiles \ + := array_append_record(lon_halo_bdy_all_tiles, lon_halo_bdy_crnt_tile, 0) + lat_halo_bdy_all_tiles \ + := array_append_record(lat_halo_bdy_all_tiles, lat_halo_bdy_crnt_tile, 0) + + end if +; +; ********************************************************************** +; +; Find and print out the coordinates of the corners of the current tile. +; +; ********************************************************************** +; + x_is_longitude = True + opts := True + opts@verbose = False + corner_info := get_rect_grid_corners( \ + lon_verts_crnt_tile, lat_verts_crnt_tile, \ + "deg", "deg", x_is_longitude, opts) + corner_lons := corner_info@x_corners + corner_lats := corner_info@y_corners + + print("") + print(" Tile corner lon/lat coordinates are:") + fmt_str = "%7.2f" + do c=0, dimsizes(corner_lons)-1 + lon_str = sprintf(fmt_str, corner_lons(c)) + lat_str = sprintf(fmt_str, corner_lats(c)) + print(" Corner " + (c+1) + ": lon = " + lon_str + " deg; " + \ + "lat = " + lat_str + " deg") + end do +; +; ********************************************************************** +; +; Set the i-indices of the domain's left (west) boundary, center, and +; right (east) boundary and the j-indices of the bottom (south) boundary, +; middle (center), and top (north) boundary in the arrays containing the +; coordinates of the supergrid. +; +; ********************************************************************** +; + if (remove_halo) then + + i_left = 0 + i_cntr = nxSG/2 + i_rght = nxSG + + j_bot = 0 + j_mid = nySG/2 + j_top = nySG + + else + + i_left = 0 + i_cntr = nxhSG/2 + i_rght = nxhSG + + j_bot = 0 + j_mid = nyhSG/2 + j_top = nyhSG + + end if +; +; ********************************************************************** +; +; Check whether any of the four faces of the current tile cross the +; international date line (IDL). This is important because if so, we +; will not be able to identify the southwest (SW), southeast (SE), +; northwest (NW), and northeast (NE) corners of the tile. We perform +; this check for each face by checking whether there is a jump in the +; longitudes of grid cell corner points that lie on the face as we move +; along the face. +; +; Note that if one (or both) of the poles lies within the tile, then one +; of the tile faces must cross the IDL. Thus, the IDL crossing check +; below will be triggered if one or both poles lie within the tile, but +; the triggering of this check does not necessarily imply that one or +; both poles lie within the tile (i.e. crossing of the IDL by a tile +; boundary is a necessary but not sufficient condition for one or both +; poles to lie within the tile). Below, if the IDL crossing check is +; triggered, we do not go further to check whether or not one or both +; poles lie within the tile (because that test is more complex). +; +; ********************************************************************** +; + face_id_strs := (/ "bottom", "right", "top", "left" /) + num_faces := dimsizes(face_id_strs) +if (False) then +; abs_dlon_cutoff := 0.0d+0 ; For debugging only. + abs_dlon_cutoff := 180.0d+0 + + fmt_str = "%8.4f" + abs_dlon_cutoff_str = sprintf(fmt_str, abs_dlon_cutoff) + + face_id_strs := (/ "bottom", "right", "top", "left" /) + num_faces := dimsizes(face_id_strs) + do i=0, num_faces-1 + + face_id_str := face_id_strs(i) + if (strcmp_exact(face_id_str, "bottom")) then + lon_crnt_face := lon_verts_SG_crnt_tile(j_bot,:) + else if (strcmp_exact(face_id_str, "right")) then + lon_crnt_face := lon_verts_SG_crnt_tile(:,i_rght) + else if (strcmp_exact(face_id_str, "top")) then + lon_crnt_face := lon_verts_SG_crnt_tile(j_top,:) + else if (strcmp_exact(face_id_str, "left")) then + lon_crnt_face := lon_verts_SG_crnt_tile(:,i_left) + end if + end if + end if + end if + + num_face_pts := dimsizes(lon_crnt_face) + dlon := lon_crnt_face(1:num_face_pts-1) - lon_crnt_face(0:num_face_pts-2) + abs_dlon_max := max(abs(dlon)) + + if (abs_dlon_max .ge. abs_dlon_cutoff) then + abs_dlon_max_str = sprintf(fmt_str, abs_dlon_max) + lat_str = sprintf(fmt_str, abs_dlon_max) + msg := char_nl + \ +"The " + char_dq + face_id_str + char_dq + " boundary of the current tile " + \ +"crosses the international date " + char_nl + \ +"line (IDL) because there is a jump in longitude (abs_dlon_max) from one " + char_nl + \ +"grid point to the next along that boundary with a magnitude that is greater " + char_nl + \ +"than or equal to the maximum allowed value specified by " + char_dq + "abs_dlon_cutoff" + char_dq + ":" + char_nl + \ +" abs_dlon_max = " + abs_dlon_max_str + " deg" + char_nl + \ +" abs_dlon_cutoff = " + abs_dlon_cutoff_str + " deg" + char_nl + \ +"Please express the longitude and latitude of the grid points in a rotated" + char_nl + \ +"lat/lon coordinate system to avoid this problem." + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + end do +end if +; +; ********************************************************************** +; +; Save in lon_tile_corners_crnt_tile and lat_tile_corners_crnt_tile the +; longitudes and latitudes of the four corners of the current tile, +; starting with the lower left corner and proceeding counterclockwise to +; the upper right corner. +; +; ********************************************************************** +; + num_corners := 4 + lon_tile_corners_crnt_tile := new((/ num_corners /), coord_data_type) + lat_tile_corners_crnt_tile := new((/ num_corners /), coord_data_type) + + i = 0 + lon_tile_corners_crnt_tile(i) \ + = lon_verts_SG_crnt_tile(j_bot, i_left) + lat_tile_corners_crnt_tile(i) \ + = lat_verts_SG_crnt_tile(j_bot, i_left) + + i = i + 1 + lon_tile_corners_crnt_tile(i) \ + = lon_verts_SG_crnt_tile(j_bot, i_rght) + lat_tile_corners_crnt_tile(i) \ + = lat_verts_SG_crnt_tile(j_bot, i_rght) + + i = i + 1 + lon_tile_corners_crnt_tile(i) \ + = lon_verts_SG_crnt_tile(j_top, i_rght) + lat_tile_corners_crnt_tile(i) \ + = lat_verts_SG_crnt_tile(j_top, i_rght) + + i = i + 1 + lon_tile_corners_crnt_tile(i) \ + = lon_verts_SG_crnt_tile(j_top, i_left) + lat_tile_corners_crnt_tile(i) \ + = lat_verts_SG_crnt_tile(j_top, i_left) +; +; ********************************************************************** +; +; Save in lon_face_midpts_crnt_tile and lat_face_midpts_crnt_tile the +; longitudes and latitudes of the midpoints of the four faces of the +; current tile, starting with the bottom face and proceeding counterclockwise +; to the left face. +; +; ********************************************************************** +; +; num_faces := 4 + lon_face_midpts_crnt_tile := new((/ num_faces /), coord_data_type) + lat_face_midpts_crnt_tile := new((/ num_faces /), coord_data_type) + + i = 0 + lon_face_midpts_crnt_tile(i) = lon_verts_SG_crnt_tile(j_bot, i_cntr) + lat_face_midpts_crnt_tile(i) = lat_verts_SG_crnt_tile(j_bot, i_cntr) + + i = i + 1 + lon_face_midpts_crnt_tile(i) = lon_verts_SG_crnt_tile(j_mid, i_rght) + lat_face_midpts_crnt_tile(i) = lat_verts_SG_crnt_tile(j_mid, i_rght) + + i = i + 1 + lon_face_midpts_crnt_tile(i) = lon_verts_SG_crnt_tile(j_top, i_cntr) + lat_face_midpts_crnt_tile(i) = lat_verts_SG_crnt_tile(j_top, i_cntr) + + i = i + 1 + lon_face_midpts_crnt_tile(i) = lon_verts_SG_crnt_tile(j_mid, i_left) + lat_face_midpts_crnt_tile(i) = lat_verts_SG_crnt_tile(j_mid, i_left) +; +; ********************************************************************** +; +; Now find the indices into lon_tile_corners_crnt_tile (or +; lat_tile_corners_crnt_tile) of the southwest, southeast, northeast, +; and northwest corners of the current tile. +; +; ********************************************************************** +; + indx_SW := new(1, "integer") + indx_SE := new(1, "integer") + indx_NE := new(1, "integer") + indx_NW := new(1, "integer") + + do i=0, num_corners-1 + + ip1 = i + 1 + if (ip1 .gt. num_corners-1) then + ip1 = 0 + end if + + ip2 = ip1 + 1 + if (ip2 .gt. num_corners-1) then + ip2 = 0 + end if + + ip3 = ip2 + 1 + if (ip3 .gt. num_corners-1) then + ip3 = 0 + end if + + lon_i := lon_tile_corners_crnt_tile(i) + lat_i := lat_tile_corners_crnt_tile(i) + + lon_ip1 := lon_tile_corners_crnt_tile(ip1) + lat_ip1 := lat_tile_corners_crnt_tile(ip1) + + lon_ip2 := lon_tile_corners_crnt_tile(ip2) + lat_ip2 := lat_tile_corners_crnt_tile(ip2) + + lon_ip3 := lon_tile_corners_crnt_tile(ip3) + lat_ip3 := lat_tile_corners_crnt_tile(ip3) + + if (ismissing(indx_SW) .and. \ + (lon_i .lt. lon_ip1) .and. \ + (lon_i .lt. lon_ip2) .and. \ + (lat_i .lt. lat_ip2) .and. \ + (lat_i .lt. lat_ip3)) then + indx_SW = i + end if + + if (ismissing(indx_SE) .and. \ + (lon_i .gt. lon_ip2) .and. \ + (lon_i .gt. lon_ip3) .and. \ + (lat_i .lt. lat_ip1) .and. \ + (lat_i .lt. lat_ip2)) then + indx_SE := i + end if + + if (ismissing(indx_NE) .and. \ + (lon_i .gt. lon_ip1) .and. \ + (lon_i .gt. lon_ip2) .and. \ + (lat_i .gt. lat_ip2) .and. \ + (lat_i .gt. lat_ip3)) then + indx_NE := i + end if + + if (ismissing(indx_NW) .and. \ + (lon_i .lt. lon_ip2) .and. \ + (lon_i .lt. lon_ip3) .and. \ + (lat_i .gt. lat_ip1) .and. \ + (lat_i .gt. lat_ip2)) then + indx_NW := i + end if + + end do + +indx_SW := (/ 0 /) +indx_SE := (/ 1 /) +indx_NE := (/ 2 /) +indx_NW := (/ 3 /) +; +; ********************************************************************** +; +; Now rearrange the lon_tile_corners_crnt_tile and lat_tile_corners_crnt_tile +; arrays so that the first element corresponds to the southwest corner of +; the tile, the second corresponds to the southeast corner, the third +; corresponds to the northeast corner, and the fourth corresponds to the +; northwest corner. Also, rearange the lon_face_midpts_crnt_tile and +; lat_face_midpts_crnt_tile arrays so that the first element corresponds +; to the southern face, the second corresponds to the eastern face, the +; third corresponds to the northern face, and the fourth corresponds to +; the western face. +; +; ********************************************************************** +; +; IMPORTANT NOTE: +; For a global cubed-sphere grid, for three of the tiles (the ones over +; the north and south poles and the one that straddles the IDL), the +; indices of the SW, SE, NE, and NW corners of the tile will not be set +; (they will remain set to their initial missing values), so the check +; below will be triggered. Something more complex needs to be done for +; such tiles, but we do not worry about it here for now since we're only +; dealing with regional domains. +; + inds_reorder := (/ indx_SW, indx_SE, indx_NE, indx_NW /) + if (any(ismissing(inds_reorder))) then + msg := char_nl + \ +"One or more of the indices for the SW, SE, NE, and NW corners of the " + char_nl + \ +"current tile have not been set:" + char_nl + \ +" indx_SW = " + indx_SW + char_nl + \ +" indx_SE = " + indx_SE + char_nl + \ +" indx_NE = " + indx_NE + char_nl + \ +" indx_NW = " + indx_NW + char_nl + \ +"Stopping." + print("" + msg) + exit + end if + + lon_tile_corners_crnt_tile := lon_tile_corners_crnt_tile(inds_reorder) + lat_tile_corners_crnt_tile := lat_tile_corners_crnt_tile(inds_reorder) + + lon_face_midpts_crnt_tile := lon_face_midpts_crnt_tile(inds_reorder) + lat_face_midpts_crnt_tile := lat_face_midpts_crnt_tile(inds_reorder) +; +; ********************************************************************** +; +; Now save the reordered tile corner and tile face midpoint coordinate +; arrays for the current tile in the arrays containing the coordinates +; for all tiles. +; +; ********************************************************************** +; + inds = (/ 0, 2, 4, 6 /) + + lon_tile_corners_face_midpts_all_tiles(nn,inds) \ + = lon_tile_corners_crnt_tile + lon_tile_corners_face_midpts_all_tiles(nn,inds+1) \ + = lon_face_midpts_crnt_tile + + lat_tile_corners_face_midpts_all_tiles(nn,inds) \ + = lat_tile_corners_crnt_tile + lat_tile_corners_face_midpts_all_tiles(nn,inds+1) \ + = lat_face_midpts_crnt_tile +; +; ********************************************************************** +; +; Calculate the coordinates of the center of the current tile as well as +; the coordinates of the tile corners and the midpoints of the four tile +; faces. +; +; ********************************************************************** +; + lon_tile_cntr_all_tiles(nn) = lon_verts_SG_crnt_tile(j_mid, i_cntr) + lat_tile_cntr_all_tiles(nn) = lat_verts_SG_crnt_tile(j_mid, i_cntr) +; +; ********************************************************************** +; +; Print out the coordinates of tile corners and tile face midpoints. +; +; ********************************************************************** +; + lon_str := sprintf("%10.6f", lon_tile_corners_face_midpts_all_tiles(nn,:)) + lat_str := sprintf("%10.6f", lat_tile_corners_face_midpts_all_tiles(nn,:)) + + loc_names := (/ "SW_corner", "S_face_midpt", \ + "SE_corner", "E_face_midpt", \ + "NE_corner", "N_face_midpt", \ + "NW_corner", "W_face_midpt" /) + loc_names := strpad(loc_names + ":", " ", "right") + lon_str := strpad(lon_str + " deg", " ", "left") + lat_str := strpad(lat_str + " deg", " ", "left") + msg := loc_names + " lon = " + lon_str + "; lat = " + lat_str + msg := " " + msg + msg := array_append_record( \ + (/ \ +"Longitudes and latitudes of the corners and face midpoints of tile #" + n_tile, \ +"are:" \ + /), msg, 0) + msg := " " + msg + msg := str_join(msg, char_nl) + print("") + print("" + msg) + end do + + print("") + print("Done reading in grid coordinates of each specified tile.") + print("" + separator_line) +; +; ********************************************************************** +; +; Remove the first elements in the unstructured arrays containing the +; coordinates of the grid cells and tile boundaries. Recall that these +; first elements were defined to make it convenient to append the coordinates +; of each consecutive tile; they contain missing values of type coord_data_type. +; +; ********************************************************************** +; + lon_cntrs_all_tiles_unstruc := lon_cntrs_all_tiles_unstruc(1:) + lat_cntrs_all_tiles_unstruc := lat_cntrs_all_tiles_unstruc(1:) + lon_verts_all_tiles_unstruc := lon_verts_all_tiles_unstruc(1:,:) + lat_verts_all_tiles_unstruc := lat_verts_all_tiles_unstruc(1:,:) + + lon_halo_cntrs_all_tiles_unstruc := lon_halo_cntrs_all_tiles_unstruc(1:) + lat_halo_cntrs_all_tiles_unstruc := lat_halo_cntrs_all_tiles_unstruc(1:) + lon_halo_verts_all_tiles_unstruc := lon_halo_verts_all_tiles_unstruc(1:,:) + lat_halo_verts_all_tiles_unstruc := lat_halo_verts_all_tiles_unstruc(1:,:) + + if (get_tile_bdies) then + lon_bdy_all_tiles := lon_bdy_all_tiles(1:) + lat_bdy_all_tiles := lat_bdy_all_tiles(1:) + lon_halo_bdy_all_tiles := lon_halo_bdy_all_tiles(1:) + lat_halo_bdy_all_tiles := lat_halo_bdy_all_tiles(1:) + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable grid_info. +; +; ********************************************************************** +; + grid_info := True + + grid_info@fp = fp + grid_info@grid_fn_all_tiles = grid_fn_all_tiles + + grid_info@nhSG_all_tiles = nhSG_all_tiles + grid_info@nxhSG_all_tiles = nxhSG_all_tiles + grid_info@nyhSG_all_tiles = nyhSG_all_tiles + grid_info@nxSG_all_tiles = nxSG_all_tiles + grid_info@nySG_all_tiles = nySG_all_tiles + + grid_info@nh_all_tiles = nh_all_tiles + grid_info@nxh_all_tiles = nxh_all_tiles + grid_info@nyh_all_tiles = nyh_all_tiles + grid_info@nx_all_tiles = nx_all_tiles + grid_info@ny_all_tiles = ny_all_tiles + + grid_info@remove_halo_all_tiles = remove_halo_all_tiles + + grid_info@lon_cntrs_all_tiles_unstruc = lon_cntrs_all_tiles_unstruc + grid_info@lat_cntrs_all_tiles_unstruc = lat_cntrs_all_tiles_unstruc + grid_info@lon_verts_all_tiles_unstruc = lon_verts_all_tiles_unstruc + grid_info@lat_verts_all_tiles_unstruc = lat_verts_all_tiles_unstruc + + grid_info@lon_bdy_all_tiles = lon_bdy_all_tiles + grid_info@lat_bdy_all_tiles = lat_bdy_all_tiles + + grid_info@lon_halo_cntrs_all_tiles_unstruc = lon_halo_cntrs_all_tiles_unstruc + grid_info@lat_halo_cntrs_all_tiles_unstruc = lat_halo_cntrs_all_tiles_unstruc + grid_info@lon_halo_verts_all_tiles_unstruc = lon_halo_verts_all_tiles_unstruc + grid_info@lat_halo_verts_all_tiles_unstruc = lat_halo_verts_all_tiles_unstruc + + grid_info@lon_halo_bdy_all_tiles = lon_halo_bdy_all_tiles + grid_info@lat_halo_bdy_all_tiles = lat_halo_bdy_all_tiles + + grid_info@lon_tile_cntr_all_tiles = lon_tile_cntr_all_tiles + grid_info@lat_tile_cntr_all_tiles = lat_tile_cntr_all_tiles + + grid_info@lon_tile_corners_face_midpts_all_tiles \ + = lon_tile_corners_face_midpts_all_tiles + grid_info@lat_tile_corners_face_midpts_all_tiles \ + = lat_tile_corners_face_midpts_all_tiles + + grid_info@coord_data_type = coord_data_type + + return(grid_info) + +end + diff --git a/ush/NCL/read_FV3LAM_grid_wrtcmp.ncl b/ush/NCL/read_FV3LAM_grid_wrtcmp.ncl new file mode 100644 index 0000000000..6ed3001613 --- /dev/null +++ b/ush/NCL/read_FV3LAM_grid_wrtcmp.ncl @@ -0,0 +1,544 @@ +; +; ********************************************************************** +; +; File name: read_FV3LAM_grid_wrtcmp.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns the dimensions, cell center coordinates, and +; cell vertex coordinates of the grid that discretizes the FV3-LAM's +; write-component output domain. The file to read is specified by +; FV3LAM_wrtcmp_fn. If get_domain_bdy is set to True, this function +; also returns the coordinates of the cell vertices lying on the boundary +; of the domain. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "get_rect_grid_bdy.ncl") +loadscript(lib_location + "interpol_extrapol_linear.ncl") +loadscript(lib_location + "convert_from_to_sphr_coords_to_from_rotated_sphr.ncl") + +undef("read_FV3LAM_grid_wrtcmp") + +function read_FV3LAM_grid_wrtcmp( \ + FV3LAM_wrtcmp_fn:string, \ + get_domain_bdy:logical) + +local fp, \ + coord_data_type, \ + coord_sys, \ + lon_verts, lat_verts, \ + lon_cntrs, lat_cntrs, \ + dims, nx, ny, \ + lon_cntrs_unstruc, lat_cntrs_unstruc, \ + lon_verts_unstruc, lat_verts_unstruc, \ + repeat_last_point, array_order, bdy_info, lon_bdy, lat_bdy, \ + x_is_longitude, opts, corner_info, corner_lons, corner_lats, \ + fmt_str, c, lon_str, lat_str, \ + grid_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Open the specified FV3-LAM wrtcmp-generated output file for reading. +; +; ********************************************************************** +; + print("") + print("" + separator_line) + print("Reading in FV3LAM's write-component grid coordinates from file ...") + print("") + print(" FV3LAM_wrtcmp_fn = " + char_dq + FV3LAM_wrtcmp_fn + char_dq) + + fp = addfile(FV3LAM_wrtcmp_fn, "r") +; +; ********************************************************************** +; +; Get the data type (i.e. float or double) of the coordinate arrays in +; the specified file. We assume here that all coordinate arrays are of +; the same type, so we read in the type of only one such coordinate ar- +; ray. +; +; ********************************************************************** +; + coord_data_type = getfilevartypes(fp, "grid_xt") +; +; ********************************************************************** +; +; Read in the coordinate system in which the grid is generated. +; +; ********************************************************************** +; + coord_sys := fp@grid +; +; ********************************************************************** +; +; Read in the cell center coordinates. +; +; ********************************************************************** +; + if (strcmp_exact(coord_sys, "rotated_latlon") .or. \ + strcmp_exact(coord_sys, "lambert_conformal")) then + + lon_cntrs := fp->lon(:,:) + lat_cntrs := fp->lat(:,:) + + else + + print("") + print("This function does not yet support this coordinate system:") + print(" coord_sys = " + char_dq + coord_sys + char_dq) + print("Stopping.") + exit + + end if +; +; ********************************************************************** +; +; Get the grid dimensions. +; +; ********************************************************************** +; + dims := dimsizes(lon_cntrs) + nx = dims(1) + ny = dims(0) + + print("") + print(" nx = " + nx) + print(" ny = " + ny) + +; +; ********************************************************************** +; +; If the grid encompasses the international date line (IDL, e.g. because +; it includes one of the poles), then the extrapolations performed below +; to obtain the cell vertex coordinates along the boundary of the grid +; may be invalid because the coordinates themselves are not continuous on +; the domain (because there will be a jump in longitude across the IDL). +; To get around this problem, transform the write-component coordinates +; read in above to a rotated latlon coordinate system that has is IDL +; moved such that it is outside of the write-component domain. In this +; coordinate system, the coordinates will be continuous and thus the +; extrapolations below will be valid. +; +; Once all quantities that this function needs to return are calculated +; in the rotated latlon coordinate system, they will be transformed back +; to obtain their values in the non-rotated coordinate system (see further +; below). +; +; IMPORTANT: +; Probably will have to include code similar to the following in the file +; read_FV3LAM_grid_native.ncl. +; +; ********************************************************************** +; + nxm1 := nx - 1 + nym1 := ny - 1 + nxp1 := nx + 1 + nyp1 := ny + 1 + + diffx_lon_iph := lon_cntrs(:,1:nxm1) - lon_cntrs(:,0:nxm1-1) + diffy_lon_jph := lon_cntrs(1:nym1,:) - lon_cntrs(0:nym1-1,:) + + diffx_lon_abs_max := max(abs(diffx_lon_iph)) + diffy_lon_abs_max := max(abs(diffy_lon_jph)) + diff_lon_abs_max := 180.0d+0 + + transform_to_rotated_latlon = False + if ((diffx_lon_abs_max .gt. diff_lon_abs_max) .or. \ + (diffy_lon_abs_max .gt. diff_lon_abs_max)) then +; Set the flag to perform the unrotated-to-rotated latlon transformation +; (and back again later on). + transform_to_rotated_latlon = True +; Read in from the specified file the coordinates of the center of the +; grid (in non-rotated latlon coordinates). + file_global_atts = getfileatts(fp) + lon0 := fp@cen_lon + lat0 := fp@cen_lat + end if +; +; If necessary, transform the grid cell center coordinates from the +; unrotated to a rotated latlon coordinate system. +; + if (transform_to_rotated_latlon) then + + angle_units = "deg" + dir = 1 + rotated_sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon0, lat0, angle_units, dir, \ + lon_cntrs, lat_cntrs) + lon_cntrs := rotated_sphr_coords@lon_out + lat_cntrs := rotated_sphr_coords@lat_out + + end if +; +; ********************************************************************** +; +; Calculate cell vertex coordinates from cell center coordinates. For +; vertices that are in the interior of the write-component domain, we +; simply averate the four neighboring cell center coordinates to obtain +; the coordinates of the vertex. For vertices that lie on the boundary +; of the domain, we perform linear extrapolation using the coordinates +; of vertices that lie within the domain (and whose coordinates we have +; already calculated using the coordinates of the cell centers). +; +; ********************************************************************** +; + lon_verts := new((/ nyp1, nxp1 /), coord_data_type) + lat_verts := new((/ nyp1, nxp1 /), coord_data_type) +;lon_verts = -98.5d+0 +;lat_verts = 37.5d+0 +; +; Average the coordinates of the four neighboring center points around +; each vertex that is in the interior of the domain/grid to obtain the +; coordinates of that internal vertex. +; + lon_verts(1:nym1,1:nxm1) \ + = (lon_cntrs(0:nym1-1,0:nxm1-1) \ + + lon_cntrs(0:nym1-1,1:nxm1) \ + + lon_cntrs(1:nym1,1:nxm1) \ + + lon_cntrs(1:nym1,0:nxm1-1))/4.0d+0 + + lat_verts(1:nym1,1:nxm1) \ + = (lat_cntrs(0:nym1-1,0:nxm1-1) \ + + lat_cntrs(0:nym1-1,1:nxm1) \ + + lat_cntrs(1:nym1,1:nxm1) \ + + lat_cntrs(1:nym1,0:nxm1-1))/4.0d+0 +; +; Create integer (index) arrays needed in the extrapolations below in the +; x direction. +; + ivec1 := new(nym1, "integer") + ivec2 := new(nym1, "integer") + ivec3 := new(nym1, "integer") +; +; Extrapolate to obtain coordinates of vertices along the left boundary +; (but not including the vertices on the bottom-left and top-left corners +; of the grid). +; + i1 = 1 + i2 = 2 + i3 = 0 + ivec1 = i1 + ivec2 = i2 + ivec3 = i3 + lon_verts(1:nym1,i3) \ + = interpol_extrapol_linear( \ + ivec1, lon_verts(1:nym1,i1), ivec2, lon_verts(1:nym1,i2), ivec3) + lat_verts(1:nym1,i3) \ + = interpol_extrapol_linear( \ + ivec1, lat_verts(1:nym1,i1), ivec2, lat_verts(1:nym1,i2), ivec3) +; +; Extrapolate to obtain coordinates of vertices along the right boundary +; (but not including the vertices on the bottom-right and top-right corners +; of the grid). +; + i1 = nx - 2 + i2 = nx - 1 + i3 = nx + ivec1 = i1 + ivec2 = i2 + ivec3 = i3 + lon_verts(1:nym1,i3) \ + = interpol_extrapol_linear( \ + ivec1, lon_verts(1:nym1,i1), ivec2, lon_verts(1:nym1,i2), ivec3) + lat_verts(1:nym1,i3) \ + = interpol_extrapol_linear( \ + ivec1, lat_verts(1:nym1,i1), ivec2, lat_verts(1:nym1,i2), ivec3) +; +; Create integer (index) arrays needed in the extrapolations below in the +; y direction. +; + jvec1 := new(nxm1, "integer") + jvec2 := new(nxm1, "integer") + jvec3 := new(nxm1, "integer") +; +; Extrapolate to obtain coordinates of vertices along the bottom boundary +; (but not including the vertices on the bottom-left and bottom-right +; corners of the grid). +; + j1 = 1 + j2 = 2 + j3 = 0 + jvec1 = j1 + jvec2 = j2 + jvec3 = j3 + lon_verts(j3,1:nxm1) \ + = interpol_extrapol_linear( \ + jvec1, lon_verts(j1,1:nxm1), jvec2, lon_verts(j2,1:nxm1), jvec3) + lat_verts(j3,1:nxm1) \ + = interpol_extrapol_linear( \ + jvec1, lat_verts(j1,1:nxm1), jvec2, lat_verts(j2,1:nxm1), jvec3) +; +; Extrapolate to obtain coordinates of vertices along the top boundary +; (but not including the vertices on the top-left and top-right corners +; of the grid). +; + j1 = ny - 2 + j2 = ny - 1 + j3 = ny + jvec1 = j1 + jvec2 = j2 + jvec3 = j3 + lon_verts(j3,1:nxm1) \ + = interpol_extrapol_linear( \ + jvec1, lon_verts(j1,1:nxm1), jvec2, lon_verts(j2,1:nxm1), jvec3) + lat_verts(j3,1:nxm1) \ + = interpol_extrapol_linear( \ + jvec1, lat_verts(j1,1:nxm1), jvec2, lat_verts(j2,1:nxm1), jvec3) +; +; ********************************************************************** +; +; Extrapolate to obtain the coordinates of the vertex on the bottom-left +; corner of the grid. +; +; ********************************************************************** +; + i1 = 1 + i2 = 2 + i3 = 0 + j3 = 0 + lon_verts(j3,i3) \ + = interpol_extrapol_linear( \ + i1, lon_verts(j3,i1), i2, lon_verts(j3,i2), i3) + + j1 = 1 + j2 = 2 + j3 = 0 + i3 = 0 + lat_verts(j3,i3) \ + = interpol_extrapol_linear( \ + j1, lat_verts(j1,i3), i2, lat_verts(j2,i3), j3) +; +; ********************************************************************** +; +; Extrapolate to obtain the coordinates of the vertex on the bottom-right +; corner of the grid. +; +; ********************************************************************** +; + i1 = nx - 2 + i2 = nx - 1 + i3 = nx + j3 = 0 + lon_verts(j3,i3) \ + = interpol_extrapol_linear( \ + i1, lon_verts(j3,i1), i2, lon_verts(j3,i2), i3) + + j1 = 1 + j2 = 2 + j3 = 0 + i3 = nx + lat_verts(j3,i3) \ + = interpol_extrapol_linear( \ + j1, lat_verts(j1,i3), j2, lat_verts(j2,i3), j3) +; +; ********************************************************************** +; +; Extrapolate to obtain the coordinates of the vertex on the top-right +; corner of the grid. +; +; ********************************************************************** +; + i1 = nx - 2 + i2 = nx - 1 + i3 = nx + j3 = ny + lon_verts(j3,i3) \ + = interpol_extrapol_linear( \ + i1, lon_verts(j3,i1), i2, lon_verts(j3,i2), i3) + + j1 = ny - 2 + j2 = ny - 1 + j3 = ny + i3 = nx + lat_verts(j3,i3) \ + = interpol_extrapol_linear( \ + j1, lat_verts(j1,i3), j2, lat_verts(j2,i3), j3) +; +; ********************************************************************** +; +; Extrapolate to obtain the coordinates of the vertex on the top-left +; corner of the grid. +; +; ********************************************************************** +; + i1 = 1 + i2 = 2 + i3 = 0 + j3 = ny + lon_verts(j3,i3) \ + = interpol_extrapol_linear( \ + i1, lon_verts(j3,i1), i2, lon_verts(j3,i2), i3) + + j1 = ny - 2 + j2 = ny - 1 + j3 = ny + i3 = 0 + lat_verts(j3,i3) \ + = interpol_extrapol_linear( \ + j1, lat_verts(j1,i3), j2, lat_verts(j2,i3), j3) +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the coordinates of +; the center of each cell on the grid. Note that these are 1-D arrays, +; and their size (i.e. the number of elements they contain) is equal to +; the number of cells on the grid (i.e. nx*ny). This unstructured for- +; mat is useful in generating color-contour plots of fields on the grid +; that have one value per cell represented by a flat color in that cell. +; +; ********************************************************************** +; + lon_cntrs_unstruc := ndtooned(lon_cntrs) + lat_cntrs_unstruc := ndtooned(lat_cntrs) +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the coordinates of +; the vertices of each cell on the grid. Note that these are 2-D arrays +; whose first dimension size is the number of cells on the grid (i.e. +; nx*ny) and whose second dimension size is 4 (since each cell has 4 +; vertices). This unstructured format is useful in generating color- +; contour plots of fields on the grid that have one value per cell re- +; presented by a flat color in that cell. +; +; ********************************************************************** +; + lon_verts_unstruc \ + := (/ ndtooned(lon_verts(0:nym1,0:nxm1)), \ + ndtooned(lon_verts(0:nym1,1:nx)), \ + ndtooned(lon_verts(1:ny,1:nx)), \ + ndtooned(lon_verts(1:ny,0:nxm1)) /) + lon_verts_unstruc := transpose(lon_verts_unstruc) + + lat_verts_unstruc \ + := (/ ndtooned(lat_verts(0:nym1,0:nxm1)), \ + ndtooned(lat_verts(0:nym1,1:nx)), \ + ndtooned(lat_verts(1:ny,1:nx)), \ + ndtooned(lat_verts(1:ny,0:nxm1)) /) + lat_verts_unstruc := transpose(lat_verts_unstruc) +; +; ********************************************************************** +; +; If get_domain_bdy is True, get the coordinates of the boundary points +; on the grid. Here, by "boundary points", we mean those cell vertices +; that happen to lie on the grid's boundary. +; +; ********************************************************************** +; + if (get_domain_bdy) then + repeat_last_point = True + array_order = "ji" + bdy_info := get_rect_grid_bdy( \ + lon_verts, lat_verts, \ + repeat_last_point, array_order) + lon_bdy := bdy_info@x_bdy + lat_bdy := bdy_info@y_bdy + end if +; +; ********************************************************************** +; +; Find and print out the coordinates of the corners of the grid. +; +; ********************************************************************** +; + x_is_longitude = True + opts := True + opts@verbose = False + corner_info := get_rect_grid_corners( \ + lon_verts, lat_verts, \ + "deg", "deg", x_is_longitude, opts) + corner_lons := corner_info@x_corners + corner_lats := corner_info@y_corners + + print("") + print(" The write-component grid's corner lon/lat coordinates are:") + fmt_str = "%7.2f" + do c=0, dimsizes(corner_lons)-1 + lon_str = sprintf(fmt_str, corner_lons(c)) + lat_str = sprintf(fmt_str, corner_lats(c)) + print(" Corner " + (c+1) + ": lon = " + lon_str + " deg; " + \ + "lat = " + lat_str + " deg") + end do + + print("") + print("Done reading in FV3-LAM's write-component grid coordinates from file.") + print("" + separator_line) +; +; ********************************************************************** +; +; If the original latlon grid coordinates read in from the file were +; transformed above to a rotated coordinate system because they include +; the international date line, then transform the results obtained above +; back to the non-rotated latlon coordinate system before returning them. +; +; ********************************************************************** +; + if (transform_to_rotated_latlon) then + + dir = -1 + + sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon0, lat0, angle_units, dir, \ + lon_cntrs_unstruc, lat_cntrs_unstruc) + lon_cntrs_unstruc := sphr_coords@lon_out + lat_cntrs_unstruc := sphr_coords@lat_out + + sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon0, lat0, angle_units, dir, \ + lon_verts_unstruc, lat_verts_unstruc) + lon_verts_unstruc := sphr_coords@lon_out + lat_verts_unstruc := sphr_coords@lat_out + + sphr_coords \ + := convert_from_to_sphr_coords_to_from_rotated_sphr( \ + lon0, lat0, angle_units, dir, \ + lon_bdy, lat_bdy) + lon_bdy := sphr_coords@lon_out + lat_bdy := sphr_coords@lat_out + + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable grid_info. +; +; ********************************************************************** +; + grid_info := True + + grid_info@fp = fp + grid_info@nx = nx + grid_info@ny = ny + grid_info@lon_cntrs_unstruc = lon_cntrs_unstruc + grid_info@lat_cntrs_unstruc = lat_cntrs_unstruc + grid_info@lon_verts_unstruc = lon_verts_unstruc + grid_info@lat_verts_unstruc = lat_verts_unstruc + grid_info@lon_bdy = lon_bdy + grid_info@lat_bdy = lat_bdy + grid_info@coord_data_type = coord_data_type + + return(grid_info) + +end + diff --git a/ush/NCL/read_FV3LAM_gridfield_native.ncl b/ush/NCL/read_FV3LAM_gridfield_native.ncl new file mode 100644 index 0000000000..287b68a054 --- /dev/null +++ b/ush/NCL/read_FV3LAM_gridfield_native.ncl @@ -0,0 +1,686 @@ +; +; ********************************************************************** +; +; File name: read_FV3LAM_gridfield_native.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "calc_field_stats.ncl") + +load "get_gridfield_info.ncl" + +undef("read_FV3LAM_gridfield_native") + +function read_FV3LAM_gridfield_native( \ + field_names_by_tile[*]:string, \ + file_names_by_tile[*]:string, \ + gtype:string, \ + tile_inds[*]:integer, \ + nh_by_tile[*]:integer, \ + nxh_by_tile[*]:integer, \ + nyh_by_tile[*]:integer, \ + nx_by_tile[*]:integer, \ + ny_by_tile[*]:integer, \ + remove_halo_by_tile[*]:logical, \ + vert_indx:integer, \ + time_indx:integer, \ + horiz_dist_units:string, \ + horiz_area_units:string \ + ) + +local calc_dA_cell_cntrs, \ + calc_dx_cell_cntrs, \ + calc_dy_cell_cntrs, \ + calc_dx_cell_faces, \ + calc_dy_cell_faces, \ + calc_angle_dx_cell_cntrs, \ + calc_angle_dy_cell_cntrs, \ +; + field_desc, field_units, \ +; + num_tiles, \ + field_min_by_tile, field_max_by_tile, \ + field_median_by_tile, field_mean_by_tile, \ + nn, msg, underline, n_tile, nx, ny, msg_adden, \ + fp, \ + field_data_type, \ +; + dA_SG_crnt_tile, \ + quarter_dA_lb_crnt_tile, quarter_dA_rb_crnt_tile, \ + quarter_dA_rt_crnt_tile, quarter_dA_lt_crnt_tile, \ + dA_crnt_tile, \ +; + dx_SG_crnt_tile, \ + half_dx_left_crnt_tile, half_dx_right_crnt_tile, \ + dx_cntr_crnt_tile, \ +; + dy_SG_crnt_tile, \ + half_dy_bot_crnt_tile, half_dy_top_crnt_tile, \ + dy_cntr_crnt_tile, \ +; + dx_face_crnt_tile, \ + dy_face_crnt_tile, \ +; + angle_dx_SG_crnt_tile, angle_dx_cntr_crnt_tile, \ +; + angle_dy_SG_crnt_tile, angle_dy_cntr_crnt_tile, \ +; + dims_SG_with_halo, dims_with_halo, \ +; + field_crnt_tile, \ +; + dxmin_crnt_tile, dymin_crnt_tile, min_dx_dy_crnt_tile, \ +; + dims_with_halo, nx_with_halo, ny_with_halo, \ +; + field_by_tile_unstruc, \ +; + print_field_stats, field_stat_info, msg, \ +; + field_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Create a string that can be used at the beginning of messages to iden- +; tify this procedure/function as the one generating the messge. +; +; ********************************************************************** +; + id_str := "Message from procedure/function read_FV3LAM_gridfield_native():" +; +; ********************************************************************** +; +; Loop through the specified tiles and read in the grid geometry (i.e. +; coordinates of the cell center and cell vertices) and the value of the +; specified field for each cell. +; +; ********************************************************************** +; + num_tiles = dimsizes(tile_inds) + + msg := "Looping over tiles to read field(s) from specified file(s) ..." + print("") + print("" + separator_line) + print("" + msg) + + do nn=0, num_tiles-1 + + print("") + msg := "nn = " + nn + print("" + msg) + underline = repeat_str("-", strlen(msg)) + print("" + underline) + + n_tile = tile_inds(nn) + print("") + print(" n_tile = " + n_tile) +; +; ********************************************************************** +; +; Get the number of cells in each of the two (horizontal) directions on +; the current tile. +; +; ********************************************************************** +; + if (remove_halo_by_tile(nn)) then + nx = nx_by_tile(nn) + ny = ny_by_tile(nn) + msg_adden \ + = " (after removing halo of " + nh_by_tile(nn) + " cells)" + else + nx = nxh_by_tile(nn) + ny = nyh_by_tile(nn) + msg_adden = "" + end if + + print("") + print(" Current tile's grid dimensions" + msg_adden + " are:") + print(" nx = " + nx) + print(" ny = " + ny) +; +; ********************************************************************** +; +; Get the file name and field name for the current tile. +; +; ********************************************************************** +; + file_name := file_names_by_tile(nn) + field_name := field_names_by_tile(nn) +; +; ********************************************************************** +; +; Open the file for the current tile for reading. +; +; ********************************************************************** +; + fp = addfile(file_name, "r") +; +; ********************************************************************** +; +; Set the logical variables that determine the field to be calculated +; (or simply obtained from file). Also, set the strings describing the +; field (field_desc) and its units (field_units). +; +; ********************************************************************** +; + gridfield_info \ + := get_gridfield_info(field_name, horiz_dist_units, horiz_area_units) + + field_desc := gridfield_info@gridfield_desc + field_units := gridfield_info@gridfield_units + filevar_names := gridfield_info@filevar_names + calc_dA_cell_cntrs := gridfield_info@calc_dA_cell_cntrs + calc_dx_cell_cntrs := gridfield_info@calc_dx_cell_cntrs + calc_dy_cell_cntrs := gridfield_info@calc_dy_cell_cntrs + calc_dx_cell_faces := gridfield_info@calc_dx_cell_faces + calc_dy_cell_faces := gridfield_info@calc_dy_cell_faces + calc_angle_dx_cell_cntrs := gridfield_info@calc_angle_dx_cell_cntrs + calc_angle_dy_cell_cntrs := gridfield_info@calc_angle_dy_cell_cntrs +; +; ********************************************************************** +; +; Read one or more fields from the grid file. +; +; ********************************************************************** +; + print("") + print(" Reading field(s) from file:") + print(" file_names_by_tile(" + nn + ") = " + char_dq + file_name + char_dq) +; +; ********************************************************************** +; +; Calculate cell areas. +; +; ********************************************************************** +; + if (calc_dA_cell_cntrs) then + + dA_SG_crnt_tile := fp->area(:,:) + + quarter_dA_lb_crnt_tile := dA_SG_crnt_tile(0::2,0::2) + quarter_dA_rb_crnt_tile := dA_SG_crnt_tile(0::2,1::2) + quarter_dA_rt_crnt_tile := dA_SG_crnt_tile(1::2,1::2) + quarter_dA_lt_crnt_tile := dA_SG_crnt_tile(1::2,0::2) + + dA_crnt_tile := quarter_dA_lb_crnt_tile \ + + quarter_dA_rb_crnt_tile \ + + quarter_dA_rt_crnt_tile \ + + quarter_dA_lt_crnt_tile + + delete([/ dA_SG_crnt_tile, \ + quarter_dA_lb_crnt_tile, \ + quarter_dA_rb_crnt_tile, \ + quarter_dA_rt_crnt_tile, \ + quarter_dA_lt_crnt_tile /]) + + end if +; +; ********************************************************************** +; +; Calculate cell size in x direction along cell centerlines. +; +; ********************************************************************** +; + if (calc_dx_cell_cntrs) then + + dx_SG_crnt_tile := fp->dx(:,:) + + half_dx_left_crnt_tile := dx_SG_crnt_tile(1::2,0::2) + half_dx_right_crnt_tile := dx_SG_crnt_tile(1::2,1::2) + + dx_cntr_crnt_tile \ + := half_dx_left_crnt_tile + half_dx_right_crnt_tile + + delete([/ dx_SG_crnt_tile, \ + half_dx_left_crnt_tile, \ + half_dx_right_crnt_tile /]) + + end if +; +; ********************************************************************** +; +; Calculate cell size in y direction along cell centerlines. +; +; ********************************************************************** +; + if (calc_dy_cell_cntrs) then + + dy_SG_crnt_tile := fp->dy(:,:) + + half_dy_bot_crnt_tile := dy_SG_crnt_tile(0::2,1::2) + half_dy_top_crnt_tile := dy_SG_crnt_tile(1::2,1::2) + + dy_cntr_crnt_tile \ + := half_dy_bot_crnt_tile + half_dy_top_crnt_tile + + delete([/ dy_SG_crnt_tile, \ + half_dy_bot_crnt_tile, \ + half_dy_top_crnt_tile /]) + + end if +; +; ********************************************************************** +; +; Calculate cell size in x direction along cell faces. +; +; ********************************************************************** +; + if (calc_dx_cell_faces) then + + dx_SG_crnt_tile := fp->dx(:,:) + + half_dx_left_crnt_tile := dx_SG_crnt_tile(0::2,0::2) + half_dx_right_crnt_tile := dx_SG_crnt_tile(0::2,1::2) + + dx_face_crnt_tile \ + := half_dx_left_crnt_tile + half_dx_right_crnt_tile + + delete([/ dx_SG_crnt_tile, \ + half_dx_left_crnt_tile, \ + half_dx_right_crnt_tile /]) + + end if +; +; ********************************************************************** +; +; Calculate cell size in y direction along cell faces. +; +; ********************************************************************** +; + if (calc_dy_cell_faces) then + + dy_SG_crnt_tile := fp->dy(:,:) + + half_dy_bot_crnt_tile := dy_SG_crnt_tile(0::2,0::2) + half_dy_top_crnt_tile := dy_SG_crnt_tile(1::2,0::2) + + dy_face_crnt_tile \ + := half_dy_bot_crnt_tile + half_dy_top_crnt_tile + + delete([/ dy_SG_crnt_tile, \ + half_dy_bot_crnt_tile, \ + half_dy_top_crnt_tile /]) + + end if +; +; ********************************************************************** +; +; Calculate grid x-angle with respect to geographic east. +; +; ********************************************************************** +; + if (calc_angle_dx_cell_cntrs) then + + angle_dx_SG_crnt_tile := fp->angle_dx(:,:) + angle_dx_cntr_crnt_tile := angle_dx_SG_crnt_tile(1::2,1::2) + delete([/ angle_dx_SG_crnt_tile /]) + + end if +; +; ********************************************************************** +; +; Calculate grid y-angle with respect to geographic north. +; +; ********************************************************************** +; + if (calc_angle_dy_cell_cntrs) then + + angle_dy_SG_crnt_tile := fp->angle_dy(:,:) + angle_dy_cntr_crnt_tile := angle_dy_SG_crnt_tile(1::2,1::2) + delete([/ angle_dy_SG_crnt_tile /]) + + end if + + print(" Done reading field(s) from file.") +; +; ********************************************************************** +; +; Get or calculate the field to plot and store it in the array field_- +; crnt_tile. +; +; ********************************************************************** +; +; If field_name is set to "none", we create a 2-D array of missing val- +; ues of whatever data type the fields are in the file. Note that if +; the current tile is tile 7, the dimensions of this array will include +; the halo. The halo will be removed later below if the grid type is +; regional, the current tile is tile 7, and remove_rgnl_halo is set to +; True. +; + if (strcmp_exact(field_name, "none")) then + + dims_SG_with_halo = getfilevardimsizes(fp, "area") + dims_with_halo = dims_SG_with_halo/2 + field_data_type_default = getfilevartypes(fp, "area") + field_crnt_tile := new(dims_with_halo, field_data_type_default) + + else if (strcmp_exact(field_name, "cell_area")) then + + field_crnt_tile := dA_crnt_tile + delete(dA_crnt_tile) + if (strcmp_exact(field_units, "km^2")) then + field_crnt_tile := field_crnt_tile*kms2_per_meter2 + end if + + else if (strcmp_exact(field_name, "sqrt_cell_area")) then + + field_crnt_tile := sqrt(dA_crnt_tile) + delete(dA_crnt_tile) + if (strcmp_exact(field_units, "km")) then + field_crnt_tile := field_crnt_tile*kms_per_meter + end if + + else if (strcmp_exact(field_name, "cell_dx")) then + + field_crnt_tile := dx_cntr_crnt_tile + delete(dx_cntr_crnt_tile) + if (strcmp_exact(field_units, "km")) then + field_crnt_tile := field_crnt_tile*kms_per_meter + end if + + else if (strcmp_exact(field_name, "cell_dy")) then + + field_crnt_tile := dy_cntr_crnt_tile + delete(dy_cntr_crnt_tile) + if (strcmp_exact(field_units, "km")) then + field_crnt_tile := field_crnt_tile*kms_per_meter + end if + + else if (strcmp_exact(field_name, "cell_dx_ovr_cell_dy")) then + + field_crnt_tile := dx_cntr_crnt_tile/dy_cntr_crnt_tile + delete([/ dx_cntr_crnt_tile, dy_cntr_crnt_tile /]) + + else if (strcmp_exact(field_name, "min_cell_dx_cell_dy")) then + + dxmin_crnt_tile \ + := where(dx_face_crnt_tile(0:ny-1,:) .lt. dx_face_crnt_tile(1:,:), \ + dx_face_crnt_tile(0:ny-1,:), dx_face_crnt_tile(1:,:)) + + dymin_crnt_tile \ + := where(dy_face_crnt_tile(:,0:nx-1) .lt. dy_face_crnt_tile(:,1:), \ + dy_face_crnt_tile(:,0:nx-1), dy_face_crnt_tile(:,1:)) + + min_dx_dy_crnt_tile \ + := where(dxmin_crnt_tile .lt. dymin_crnt_tile, \ + dxmin_crnt_tile, dymin_crnt_tile) + + field_crnt_tile := min_dx_dy_crnt_tile + + delete([/ dxmin_crnt_tile, \ + dymin_crnt_tile, \ + min_dx_dy_crnt_tile /]) + + if (strcmp_exact(field_units, "km")) then + field_crnt_tile := field_crnt_tile*kms_per_meter + end if + + else if (strcmp_exact(field_name, "angle_cell_dx")) then + + field_crnt_tile := angle_dx_cntr_crnt_tile + delete(angle_dx_cntr_crnt_tile) + + else if (strcmp_exact(field_name, "angle_cell_dy")) then + + field_crnt_tile := angle_dy_cntr_crnt_tile + delete(angle_dy_cntr_crnt_tile) +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + else + + if (func_xy_only) then + field_crnt_tile := fp->$field_name$(:,:) + else if (func_xyz_only) then + field_crnt_tile := fp->$field_name$(vert_indx,:,:) + else if (func_xyt_only) then + field_crnt_tile := fp->$field_name$(time_indx,:,:) + else if (func_xyzt_only) then + field_crnt_tile := fp->$field_name$(time_indx,vert_indx,:,:) + end if + end if + end if + end if + + field_desc = field_crnt_tile@long_name + field_units = field_crnt_tile@units + + end if + end if + end if + end if + end if + end if + end if + end if + end if +; +; ********************************************************************** +; +; If on a regional grid and on tile 7 and if remove_rgnl_halo is set to +; True, remove the halo from the field calculated above (field_crnt_- +; tile). +; +; ********************************************************************** +; + if (remove_halo_by_tile(nn)) then + + print("") + print(" Removing halo cells from field (" + \ + char_dq + field_name + char_dq + \ + ") on tile " + n_tile + " ...") + + field_crnt_tile \ + := field_crnt_tile( \ + nh_by_tile(nn):nyh_by_tile(nn)-1-nh_by_tile(nn), \ + nh_by_tile(nn):nxh_by_tile(nn)-1-nh_by_tile(nn)) + + print(" Done removing halo cells from field on tile " + n_tile + ".") + + end if +; +; ********************************************************************** +; +; If on the first tile, convert the 2-D array containing the field val- +; ues at cell centers to a 1-D unstructured array. If on the second, +; third, etc tile, perform this conversion and then concatenate the re- +; sult to the 1-D unstructured array containing the field values on the +; previous tile(s). +; +; ********************************************************************** +; + if (nn .eq. 0) then + + field_by_tile_unstruc := ndtooned(field_crnt_tile) + + else + + field_data_type_prev_tiles = typeof(field_by_tile_unstruc) + field_data_type_crnt_tile = typeof(field_crnt_tile) +; +; If the data type of the field on the tiles considered thus far is not +; the same as that of the field on the current tile, we either perform +; type conversions or exit with an error (depending on the inconsisten- +; cy). +; + if (.not. strcmp_exact(field_data_type_prev_tiles, \ + field_data_type_crnt_tile)) then + + prev_tiles_all_missing := all(ismissing(field_by_tile_unstruc)) + crnt_tile_all_missing := all(ismissing(field_crnt_tile)) + + if (prev_tiles_all_missing .and. (.not. crnt_tile_all_missing)) then + + field_by_tile_unstruc \ + := totype(field_by_tile_unstruc, field_data_type_crnt_tile) + + else if ((.not. prev_tiles_all_missing) .and. crnt_tile_all_missing) then + + field_crnt_tile \ + := totype(field_crnt_tile, field_data_type_prev_tiles) + + else if (prev_tiles_all_missing .and. crnt_tile_all_missing) then + + msg := char_nl + id_str + char_nl + \ +"The field on all previous tiles and on the current tile consists of all " + char_nl + \ +"missing values. In this case, the data type of the missing values on " + char_nl + \ +"the previous tiles should be the same as the data type of the missing " + char_nl + \ +"values on the current tile but is not:" + char_nl + \ +" prev_tiles_all_missing = " + prev_tiles_all_missing + char_nl + \ +" crnt_tile_all_missing = " + crnt_tile_all_missing + char_nl + \ +" field_data_type_prev_tiles = " + char_dq + field_data_type_prev_tiles + char_dq + char_nl + \ +" field_data_type_crnt_tile = " + char_dq + field_data_type_crnt_tile + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if ((.not. prev_tiles_all_missing) .and. \ + (.not. crnt_tile_all_missing)) then + + msg := char_nl + id_str + char_nl + \ +"The field does not contain any missing values on any of the previous " + char_nl + \ +"tiles or on the current tile. In this case, the data type of the values " + char_nl + \ +"on the previous tiles should be the same as the data type of the values " + char_nl + \ +"on current tiles but is not:" + char_nl + \ +" prev_tiles_all_missing = " + prev_tiles_all_missing + char_nl + \ +" crnt_tile_all_missing = " + crnt_tile_all_missing + char_nl + \ +" field_data_type_prev_tiles = " + char_dq + field_data_type_prev_tiles + char_dq + char_nl + \ +" field_data_type_crnt_tile = " + char_dq + field_data_type_crnt_tile + char_dq + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if + end if + end if + + end if + + field_by_tile_unstruc \ + := array_append_record(field_by_tile_unstruc, ndtooned(field_crnt_tile), 0) + + end if +; +; ********************************************************************** +; +; Get the field's data type (usually "float" or "double"). +; +; ********************************************************************** +; + field_data_type = typeof(field_by_tile_unstruc) +; +; ********************************************************************** +; +; Calculate (and possibly print out) basic statistics of the field. +; +; ********************************************************************** +; + msg := " Calculating statistics of field on the tile " + n_tile \ + + " grid ..." + print("") + print("" + msg) + + print_field_stats = False + field_stat_info \ + := calc_field_stats( \ + field_crnt_tile, field_desc, field_units, print_field_stats) + msg := " " + field_stat_info@msg + print("") + print("" + msg) + + msg := " Done calculating statistics of field on the tile " + n_tile \ + + " grid." + print("") + print("" + msg) +; +; ********************************************************************** +; +; Save field statistics in appropriate arrays. +; +; ********************************************************************** +; + if (nn .eq. 0) then + field_min_by_tile := new((/ num_tiles /), field_data_type) + field_max_by_tile := new((/ num_tiles /), field_data_type) + field_median_by_tile := new((/ num_tiles /), field_data_type) + field_mean_by_tile := new((/ num_tiles /), field_data_type) + end if + + field_min_by_tile(nn) = field_stat_info@field_min + field_max_by_tile(nn) = field_stat_info@field_max + field_median_by_tile(nn) = field_stat_info@field_median + field_mean_by_tile(nn) = field_stat_info@field_mean + + end do + + print("") + print("Done reading field(s) from grid files.") + print("" + separator_line) +; +; ********************************************************************** +; +; Set to missing values the variables containing the vertical and time +; dimensions of the field on each tile. These need to be returned only +; for consistency with the read_FV3LAM_field_native(...) function. +; +; ********************************************************************** +; + nz_by_tile := new(num_tiles, "integer") + nt_by_tile := new(num_tiles, "integer") +; +; ********************************************************************** +; +; Return results as attributes of the logical variable field_info. +; +; ********************************************************************** +; + field_info = True + + field_info@field_desc = field_desc + field_info@field_units = field_units + field_info@field_by_tile_unstruc = field_by_tile_unstruc + field_info@nz_by_tile = nz_by_tile + field_info@nt_by_tile = nt_by_tile + field_info@field_min_by_tile = field_min_by_tile + field_info@field_max_by_tile = field_max_by_tile + field_info@field_median_by_tile = field_median_by_tile + field_info@field_mean_by_tile = field_mean_by_tile + field_info@field_data_type = field_data_type + + return(field_info) + +end + + + + + + + diff --git a/ush/NCL/read_RAP_field.ncl b/ush/NCL/read_RAP_field.ncl new file mode 100644 index 0000000000..fa0a3bb279 --- /dev/null +++ b/ush/NCL/read_RAP_field.ncl @@ -0,0 +1,336 @@ +; +; ********************************************************************** +; +; File name: read_RAP_field.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns +; +; ********************************************************************** +; +loadscript(lib_location + "pause.ncl") +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "constants.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "calc_field_stats.ncl") + +undef("read_RAP_field") + +function read_RAP_field( \ + field_name:string, \ + horiz_dist_units:string, \ + horiz_area_units:string, \ + RAP_fn:string, \ + nx:integer, \ + ny:integer \ + ) + +local fp, \ + field_data_type, \ + calc_dx_cell_cntrs, calc_dy_cell_cntrs, \ + field_desc, field_units, \ + dx_nondim, mapfac_mx, dx_cntr, \ + dy_nondim, mapfac_my, dy_cntr, \ + field, dxmin, dymin, min_dx_dy, \ + field_unstruc, \ + msg, print_field_stats, field_stat_info, \ + field_min, field_max, field_median, field_mean, \ + field_info + +begin +; +; ********************************************************************** +; +; Open the specified file for reading. +; +; ********************************************************************** +; + print("") + print("" + separator_line) + print("Reading RAP field from file:") + print("") + print(" RAP_fn = " + char_dq + RAP_fn + char_dq) + +; Modify for grib2 file. +RAP_fn = RAP_fn + ".grb2" + + fp = addfile(RAP_fn, "r") +; +; ********************************************************************** +; +; Get the data type (i.e. float or double) of the fields in the speci- +; fied file. We assume here that all real-numbered fields are of the +; same type, so we read in the type of only one such field. +; +; ********************************************************************** +; +; field_data_type = getfilevartypes(fp, "MAPFAC_M") +; Modify for grib2 file. + field_data_type = getfilevartypes(fp, field_name) +; +; ********************************************************************** +; +; Set field-related parameters. +; +; ********************************************************************** +; + calc_dx_cell_cntrs = False + calc_dy_cell_cntrs = False + + if (strcmp_exact(field_name, "none")) then + + field_desc = "Empty Field" + field_units = "-" + + else if (strcmp_exact(field_name, "cell_area")) then + + calc_dx_cell_cntrs = True + calc_dy_cell_cntrs = True + field_desc = "Cell Area" + field_units = horiz_area_units + + else if (strcmp_exact(field_name, "sqrt_cell_area")) then + + calc_dx_cell_cntrs = True + calc_dy_cell_cntrs = True + field_desc = "Square Root of Cell Area" + field_units = horiz_dist_units + + else if (strcmp_exact(field_name, "cell_dx")) then + + calc_dx_cell_cntrs = True + field_desc = "Cell Size in x-Direction Along Cell Centerline" + field_units = horiz_dist_units + + else if (strcmp_exact(field_name, "cell_dy")) then + + calc_dy_cell_cntrs = True + field_desc = "Cell Size in y-Direction Along Cell Centerline" + field_units = horiz_dist_units + + else if (strcmp_exact(field_name, "cell_dx_ovr_cell_dy")) then + + calc_dx_cell_cntrs = True + calc_dy_cell_cntrs = True + field_desc = "Ratio of dx to dy (dx/dy)" + field_units = "-" + + else if (strcmp_exact(field_name, "min_cell_dx_cell_dy")) then + + calc_dx_cell_cntrs = True + calc_dy_cell_cntrs = True + field_desc = "MIN(dx, dy)" + field_units = horiz_dist_units + + else if (strcmp_exact(field_name, "VGTYP_P0_L1_GLC0")) then + + field_desc = "Vegetation type" + field_units = "-" + + else + + field_desc = "Unknown Field" + field_units = "?" + + end if + end if + end if + end if + end if + end if + end if + end if +; +; ********************************************************************** +; +; Calculate cell size in x direction along cell centerlines. +; +; ********************************************************************** +; + if (calc_dx_cell_cntrs) then + + dx_nondim := fp@DX + mapfac_mx := fp->MAPFAC_MX(:,:,:) + mapfac_mx := rm_single_dims(mapfac_mx) + dx_cntr := dx_nondim/mapfac_mx + delete([/ mapfac_mx /]) + + end if +; +; ********************************************************************** +; +; Calculate cell size in y direction along cell centerlines. +; +; ********************************************************************** +; + if (calc_dy_cell_cntrs) then + + dy_nondim := fp@DY + mapfac_my := fp->MAPFAC_MY(:,:,:) + mapfac_my := rm_single_dims(mapfac_my) + dy_cntr := dy_nondim/mapfac_my + delete([/ mapfac_my /]) + + end if +; +; ********************************************************************** +; +; Get or calculate the field to plot and store it in the array RAP. +; +; ********************************************************************** +; + if (strcmp_exact(field_name, "none")) then + + field := new((/ ny, nx /), field_data_type) + + else if (strcmp_exact(field_name, "cell_area")) then + + field := dx_cntr*dy_cntr + delete([/ dx_cntr, dy_cntr /]) + + else if (strcmp_exact(field_name, "sqrt_cell_area")) then + + field := sqrt(dx_cntr*dy_cntr) + delete([/ dx_cntr, dy_cntr /]) + + else if (strcmp_exact(field_name, "cell_dx")) then + + field := dx_cntr + delete([/ dx_cntr /]) + + else if (strcmp_exact(field_name, "cell_dy")) then + + field := dy_cntr + delete([/ dy_cntr /]) + + else if (strcmp_exact(field_name, "cell_dx_ovr_cell_dy")) then + + field := dx_cntr/dy_cntr + delete([/ dx_cntr, dy_cntr /]) + + else if (strcmp_exact(field_name, "min_cell_dx_cell_dy")) then + + field := sqrt(dx_cntr*dy_cntr) + delete([/ dx_cntr, dy_cntr /]) + + dxmin := where(dx_cntr(0:ny-1,:) .lt. dx_cntr(1:,:), \ + dx_cntr(0:ny-1,:), dx_cntr(1:,:)) + + dymin := where(dy_cntr(:,0:nx-1) .lt. dy_cntr(:,1:), \ + dy_cntr(:,0:nx-1), dy_cntr(:,1:)) + + min_dx_dy := where(dxmin .lt. dymin, dxmin, dymin) + + field := min_dx_dy + + delete([/ dxmin, dymin, min_dx_dy /]) + + else + +; field := new((/ ny, nx /), field_data_type) +; Modify for HRRR grib2 file. + field := fp->$field_name$ + + end if + end if + end if + end if + end if + end if + end if +; +; ********************************************************************** +; +; Perform unit conversions if necessary. +; +; ********************************************************************** +; + if (strcmp_exact(field_name, "cell_area")) then + + if (strcmp_exact(field_units, "km^2")) then + field := field*totype(kms2_per_meter2, field_data_type) + end if + + else if (strcmp_exact(field_name, "sqrt_cell_area") .or. \ + strcmp_exact(field_name, "cell_dx") .or. \ + strcmp_exact(field_name, "cell_dy") .or. \ + strcmp_exact(field_name, "min_cell_dx_cell_dy")) + + if (strcmp_exact(field_units, "km")) then + field := field*totype(kms_per_meter, field_data_type) + end if + + end if + end if +; +; ********************************************************************** +; +; Convert the 2-D array containing the field to a 1-D array in unstruc- +; tured format. +; +; ********************************************************************** +; + field_unstruc := ndtooned(field) +; +; ********************************************************************** +; +; Calculate (and possibly print out) basic statistics of the field. +; +; ********************************************************************** +; + msg := " Calculating statistics of field on RAP grid ..." + print("") + print("" + msg) + +; print_field_stats = True + print_field_stats = False + field_stat_info \ + := calc_field_stats( \ + field, field_desc, field_units, print_field_stats) + msg := " " + field_stat_info@msg + print("") + print("" + msg) + + msg := " Done calculating statistics of field on RAP grid." + print("") + print("" + msg) +; +; ********************************************************************** +; +; Save field statistics in appropriate variables. +; +; ********************************************************************** +; + field_min := field_stat_info@field_min + field_max := field_stat_info@field_max + field_median := field_stat_info@field_median + field_mean := field_stat_info@field_mean + + print("") + print("Done reading RAP field from file.") + print("" + separator_line) +; +; ********************************************************************** +; +; Return results as attributes of the logical variable field_info. +; +; ********************************************************************** +; + field_info = True + + field_info@fp = fp + field_info@field_desc = field_desc + field_info@field_units = field_units + field_info@field_unstruc = field_unstruc + field_info@field_min = field_min + field_info@field_max = field_max + field_info@field_median = field_median + field_info@field_mean = field_mean + field_info@field_data_type = field_data_type + + return(field_info) + +end + diff --git a/ush/NCL/read_RAP_grid.ncl b/ush/NCL/read_RAP_grid.ncl new file mode 100644 index 0000000000..7b2ac7871d --- /dev/null +++ b/ush/NCL/read_RAP_grid.ncl @@ -0,0 +1,269 @@ +; +; ********************************************************************** +; +; File name: read_RAP_grid.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function returns the dimensions, cell center coordinates, and +; cell vertex coordinates of the grid encompassing the RAP domain speci- +; fied in the file RAP_grid_fn. If get_domain_bdy is set to True, it +; also returns the coordinates of the cell vertices lying on the bounda- +; ry of the domain. +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") +loadscript(lib_location + "get_rect_grid_bdy.ncl") + +undef("read_RAP_grid") + +function read_RAP_grid( \ + RAP_grid_fn:string, \ + get_domain_bdy:logical) + +local fp, \ + coord_data_type, \ + lon_cntrs, lat_cntrs, \ + lon_verts, lat_verts, \ + dims, nx, ny, \ + lon_cntrs_unstruc, lat_cntrs_unstruc, \ + lon_verts_unstruc, lat_verts_unstruc, \ + repeat_last_point, array_order, bdy_info, lon_bdy, lat_bdy, \ + x_is_longitude, opts, corner_info, corner_lons, corner_lats, \ + fmt_str, c, lon_str, lat_str, \ + grid_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; Open the specified file for reading. +; +; ********************************************************************** +; + print("") + print("" + separator_line) + print("Reading in grid coordinates of the RAP domain from file:") + print("") + print(" RAP_grid_fn = " + char_dq + RAP_grid_fn + char_dq) + + fp = addfile(RAP_grid_fn, "r") +; +; ********************************************************************** +; +; Get the data type (i.e. float or double) of the coordinate arrays in +; the specified file. We assume here that all coordinate arrays are of +; the same type, so we read in the type of only one such coordinate ar- +; ray. +; +; ********************************************************************** +; + coord_data_type = getfilevartypes(fp, "XLONG_M") +; +; ********************************************************************** +; +; Read in the cell center coordinates. +; +; ********************************************************************** +; + lon_cntrs := fp->XLONG_M(:,:,:) + lat_cntrs := fp->XLAT_M(:,:,:) +; +; ********************************************************************** +; +; Read in the cell vertex coordinates. +; +; ********************************************************************** +; + lon_verts := fp->XLONG_C(:,:,:) + lat_verts := fp->XLAT_C(:,:,:) +; +; ********************************************************************** +; +; Remove singleton dimensions (e.g. time) from the coordinate arrays. +; +; ********************************************************************** +; + lon_cntrs := rm_single_dims(lon_cntrs) + lat_cntrs := rm_single_dims(lat_cntrs) + + lon_verts := rm_single_dims(lon_verts) + lat_verts := rm_single_dims(lat_verts) +; +; ********************************************************************** +; +; Get the grid dimensions. +; +; ********************************************************************** +; + dims := dimsizes(lon_cntrs) + nx = dims(1) + ny = dims(0) + + print("") + print(" nx = " + nx) + print(" ny = " + ny) +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the coordinates of +; the center of each cell on the grid. Note that these are 1-D arrays, +; and their size (i.e. the number of elements they contain) is equal to +; the number of cells on the grid (i.e. nx*ny). This unstructured for- +; mat is useful in generating color-contour plots of fields on the grid +; that have one value per cell represented by a flat color in that cell. +; +; ********************************************************************** +; + lon_cntrs_unstruc := ndtooned(lon_cntrs) + lat_cntrs_unstruc := ndtooned(lat_cntrs) +; +; ********************************************************************** +; +; Create arrays in unstructured format that contain the coordinates of +; the vertices of each cell on the grid. Note that these are 2-D arrays +; whose first dimension size is the number of cells on the grid (i.e. +; nx*ny) and whose second dimension size is 4 (since each cell has 4 +; vertices). This unstructured format is useful in generating color- +; contour plots of fields on the grid that have one value per cell re- +; presented by a flat color in that cell. +; +; ********************************************************************** +; + lon_verts_unstruc \ + := (/ ndtooned(lon_verts(0:ny-1,0:nx-1)), \ + ndtooned(lon_verts(0:ny-1,1:nx)), \ + ndtooned(lon_verts(1:ny,1:nx)), \ + ndtooned(lon_verts(1:ny,0:nx-1)) /) + lon_verts_unstruc := transpose(lon_verts_unstruc) + + lat_verts_unstruc \ + := (/ ndtooned(lat_verts(0:ny-1,0:nx-1)), \ + ndtooned(lat_verts(0:ny-1,1:nx)), \ + ndtooned(lat_verts(1:ny,1:nx)), \ + ndtooned(lat_verts(1:ny,0:nx-1)) /) + lat_verts_unstruc := transpose(lat_verts_unstruc) +; +; ********************************************************************** +; +; If get_domain_bdy is specified to be True, save in a pair of 1-D ar- +; rays the coordinates of those cell vertices that lie on the boundary +; of the grid. +; +; ********************************************************************** +; + if (get_domain_bdy) then + repeat_last_point = True + array_order = "ji" + bdy_info := get_rect_grid_bdy( \ + lon_verts, lat_verts, \ + repeat_last_point, array_order) + lon_bdy := bdy_info@x_bdy + lat_bdy := bdy_info@y_bdy + else + lon_bdy := default_fillvalue(coord_data_type) + lat_bdy := default_fillvalue(coord_data_type) + end if +; +; ********************************************************************** +; +; Find and print out the coordinates of the corners of the grid. +; +; ********************************************************************** +; + x_is_longitude = True + opts := True + opts@verbose = False + corner_info := get_rect_grid_corners( \ + lon_verts, lat_verts, \ + "deg", "deg", x_is_longitude, opts) + corner_lons := corner_info@x_corners + corner_lats := corner_info@y_corners + + print("") + print(" The RAP domain's corner lon/lat coordinates are:") + fmt_str = "%7.2f" + do c=0, dimsizes(corner_lons)-1 + lon_str = sprintf(fmt_str, corner_lons(c)) + lat_str = sprintf(fmt_str, corner_lats(c)) + print(" Corner " + (c+1) + ": lon = " + lon_str + " deg; " + \ + "lat = " + lat_str + " deg") + end do + + print("") + print("Done reading in RAP grid coordinates from file.") + print("" + separator_line) +; +; ********************************************************************** +; +; Calculate the coordinates of the center of the RAP grid. +; +; ********************************************************************** +; + rem_nx = mod(nx, 2) + rem_ny = mod(ny, 2) + + if ((rem_nx .eq. 0) .and. (rem_ny .eq. 0)) then + i_cntr = nx/2 + j_cntr = ny/2 + lon_grid_cntr := lon_verts(j_cntr,i_cntr) + lat_grid_cntr := lat_verts(j_cntr,i_cntr) + else if ((rem_nx .eq. 1) .and. (rem_ny .eq. 0)) then + i_cntr = (nx - 1)/2 + j_cntr = ny/2 + lon_grid_cntr := fp->XLONG_V(:,j_cntr,i_cntr) + lat_grid_cntr := fp->XLAT_V(:,j_cntr,i_cntr) + else if ((rem_nx .eq. 0) .and. (rem_ny .eq. 1)) then + i_cntr = nx/2 + j_cntr = (ny - 1)/2 + lon_grid_cntr := fp->XLONG_U(:,j_cntr,i_cntr) + lat_grid_cntr := fp->XLAT_U(:,j_cntr,i_cntr) + else if ((rem_nx .eq. 1) .and. (rem_ny .eq. 1)) then + i_cntr = (nx - 1)/2 + j_cntr = (ny - 1)/2 + lon_grid_cntr := lon_cntrs(j_cntr,i_cntr) + lat_grid_cntr := lat_cntrs(j_cntr,i_cntr) + end if + end if + end if + end if +; +; ********************************************************************** +; +; Return results as attributes of the logical variable grid_info. +; +; ********************************************************************** +; + grid_info := True + + grid_info@fp = fp + grid_info@nx = nx + grid_info@ny = ny + grid_info@lon_cntrs_unstruc = lon_cntrs_unstruc + grid_info@lat_cntrs_unstruc = lat_cntrs_unstruc + grid_info@lon_verts_unstruc = lon_verts_unstruc + grid_info@lat_verts_unstruc = lat_verts_unstruc + grid_info@lon_bdy = lon_bdy + grid_info@lat_bdy = lat_bdy + grid_info@lon_grid_cntr = lon_grid_cntr + grid_info@lat_grid_cntr = lat_grid_cntr + grid_info@coord_data_type = coord_data_type + + return(grid_info) + +end + diff --git a/ush/NCL/set_file_field_names.ncl b/ush/NCL/set_file_field_names.ncl new file mode 100644 index 0000000000..bbfb1e94ea --- /dev/null +++ b/ush/NCL/set_file_field_names.ncl @@ -0,0 +1,587 @@ +; +; ********************************************************************** +; +; File name: set_file_field_names.ncl +; Author: Gerard Ketefian +; +; Description: +; ^^^^^^^^^^^ +; This function +; +; ********************************************************************** +; +loadscript(lib_location + "special_chars.ncl") +loadscript(lib_location + "strcmp_exact.ncl") + +load "check_filevar_existence_dims.ncl" + +undef("set_file_field_names") + +function set_file_field_names( \ + gtype:string, \ + tile_inds[*]:integer, \ + field_name:string, \ + is_gridfield:logical, \ +; + remove_halo_by_tile[*]:logical, \ +; + grid_files_by_tile[*]:string, \ + nxhSG_by_tile[*]:integer, \ + nyhSG_by_tile[*]:integer, \ + nxSG_by_tile[*]:integer, \ + nySG_by_tile[*]:integer, \ +; + run_dir:string, \ + file_basename:string, \ + nxh_by_tile[*]:integer, \ + nyh_by_tile[*]:integer, \ + nx_by_tile[*]:integer, \ + ny_by_tile[*]:integer, \ +; + vert_inds[*]:integer, \ + time_inds[*]:integer, \ +; + horiz_dist_units:string, \ + horiz_area_units:string) + + +local num_tiles, \ + file_names_by_tile, \ + field_names_by_tile, \ + msg, \ + nn, \ + underline, \ + n_tile, \ + file_name, \ + gridfield_info, \ + filevar_names, \ + nxhSG_or_nxh_by_tile, \ + nyhSG_or_nyh_by_tile, \ + filevar_names_str, \ + num_filevars, \ + indx_fv, \ + var_info_prev_tile, \ + var_info, \ + + fp_field_file, \ + var_rank, \ + var_dim_names, \ + var_dim_sizes, \ + func_xy_only, \ + func_xyz_only, \ + func_xyt_only, \ + func_xyzt_only, \ + average_in_x, \ + average_in_y, \ +\ + n_tile_prev, \ +\ + fp_field_file_prev_tile, \ + var_rank_prev_tile, \ + var_dim_names_prev_tile, \ + var_dim_sizes_prev_tile, \ + func_xy_only_prev_tile, \ + func_xyz_only_prev_tile, \ + func_xyt_only_prev_tile, \ + func_xyzt_only_prev_tile, \ + average_in_x_prev_tile, \ + average_in_y_prev_tile, \ +\ + var_dim_names_differ, \ + var_dim_names_prev_tile_str, \ + var_dim_names_str, \ + var_dim_sizes_prev_tile_str, \ + var_dim_sizes_str, \ +\ + file_field_info + +begin +; +; ********************************************************************** +; +; If not already defined, define the string (separator_line) that serves +; as a separator line between different sections of printout. +; +; ********************************************************************** +; + if (.not. isvar("separator_line")) then + separator_line := repeat_str("=", 72) + end if +; +; ********************************************************************** +; +; +; +; ********************************************************************** +; + if (is_gridfield) then + + gridfield_info \ + := get_gridfield_info(field_name, horiz_dist_units, horiz_area_units) + filevar_names := gridfield_info@filevar_names + + xdim_by_tile \ + := where(remove_halo_by_tile, nxSG_by_tile, nxhSG_by_tile) + ydim_by_tile \ + := where(remove_halo_by_tile, nySG_by_tile, nyhSG_by_tile) + + else + + filevar_names := field_name + + xdim_by_tile \ + := where(remove_halo_by_tile, nx_by_tile, nxh_by_tile) + ydim_by_tile \ + := where(remove_halo_by_tile, ny_by_tile, nyh_by_tile) + + end if + +print("") +print("xdim_by_tile = " + xdim_by_tile) +print("") +print("ydim_by_tile = " + ydim_by_tile) + + filevar_names_str \ + := "(" + char_dq \ + + str_join(filevar_names, char_dq + ", " + char_dq) \ + + char_dq + ")" + print(" filevar_names = " + filevar_names_str) +pause +; +; ********************************************************************** +; +; Loop through the specified tiles and form the file name corresponding +; to each tile. Also, set the field name for each tile. Note that the +; reason for having a separate field name for each tile is that the +; files corresponding to certain tiles may not exist (e.g. if we're con- +; sidering a tile other than tile 7 for a regional grid). In that case, +; the field on those tiles will not be available, so for those tiles, we +; must set the field name to "none" to obtain a field array filled with +; missing/fill values. +; +; ********************************************************************** +; + num_tiles := dimsizes(tile_inds) + + file_names_by_tile = new((/ num_tiles /), "string") + field_names_by_tile = new((/ num_tiles /), "string") + + print("") + print("" + separator_line) + msg := \ +"Setting file and field name for each specified tile ..." + char_nl + \ +"[The field name for a tile will be set to " + char_dq + "none" + char_dq + \ +" if a file for that tile " + char_nl + \ +"does not exist, e.g. if the tile in consideration is #5, but we are on a " + char_nl + \ +"regional grid (in which case files/fields are only available on tile #7).]" + print("" + msg) + + do nn=0, num_tiles-1 + + print("") + msg := "nn = " + nn + print("" + msg) + underline = repeat_str("-", strlen(msg)) + print("" + underline) + + n_tile = tile_inds(nn) + print("") + print(" n_tile = " + n_tile) +; +; ********************************************************************** +; +; Generate the file name for the current tile. +; +; ********************************************************************** +; + if (is_gridfield) then + + file_name := grid_files_by_tile(nn) + file_names_by_tile(nn) = file_name + + else + + file_name := run_dir + "/" + file_basename + if (.not. strcmp_exact(gtype, "regional")) then + file_name := file_name + ".tile" + tostring(n_tile) + end if + file_name := file_name + ".nc" + file_names_by_tile(nn) = file_name + + end if + + print(" file_names_by_tile(" + nn + ") = " + \ + char_dq + file_names_by_tile(nn) + char_dq) +; +; ********************************************************************** +; +; Generate the field name for the current tile. +; +; ********************************************************************** +; + field_names_by_tile(nn) = field_name +; +; If we're dealing with a regional grid (for which physical fields are +; available only on tile 7), and if we're not on tile 7 (i.e. we are on +; one of the "parent" global tiles 1 through 6), then only grid-related +; fields (such as horizontal area of cells) will be available on this +; tile. Thus, if we're not considering a grid-rleated field, we must +; set the field name on this tile to "none". +; + if (strcmp_exact(gtype, "regional") .and. \ + (n_tile .ne. 7) .and. \ + (.not. is_gridfield)) then + + field_names_by_tile(nn) = "none" + msg := char_nl + \ +" The specified field is not available on the current tile:" + char_nl + \ +" n_tile = " + n_tile + char_nl + \ +" field_name = " + char_dq + field_name + char_dq + char_nl + \ +" Setting the field name for the current tile to " + char_dq + "none" + char_dq + ":" + char_nl + \ +" field_names_by_tile(" + nn + ") = " + char_dq + field_names_by_tile(nn) + char_dq + print("" + msg) + + else + + print(" field_names_by_tile(" + nn + ") = " + \ + char_dq + field_names_by_tile(nn) + char_dq) + + end if + + end do + + print("") + print("Done setting file and field name for each specified tile.") + print("" + separator_line) +; +; ********************************************************************** +; +; Call a function that runs various checks on the specified field. This +; function will: +; +; 1) Verify that the field exists as a as a variable in the file. +; 2) Verify that its functional dependence on space and time is one of +; the following: +; a) Function of only the two horizontal directions but not the ver- +; tical direction or time. In this case, the func_xy_only attrib- +; ute of the returned variable will be set to True. +; b) Function of only the two horizontal directions and the vertical +; direction but not time. In this case, the func_xyz_only attrib- +; ute of the returned variable will be set to True. +; c) Function of only the two horizontal directions and time but not +; the vertical direction. In this case, the func_xyt_only attrib- +; ute of the returned variable will be set to True. +; d) Function of the two horizontal directions, the vertical direc- +; tion, and time. In this case, the func_xyzt_only attribute of +; the returned variable will be set to True. +; 3) Verify that the specified vertical and/or time indices do not ex- +; ceed the array bounds of the variable that represents the specified +; field. +; 4) Return: +; a) The rank, dimension names, and dimension sizes of the variable +; that represents the field. +; b) The functional dependence of the field on x, y, z, and t. +; +; ********************************************************************** +; +; +; ********************************************************************** +; +; If the name of the field to be plotted on the current tile is NOT +; "none" (i.e. it is a valid field), perfrom some basic checks on the +; variable and set the logical variables that describe the functional +; dependence of the field on space and time (i.e. its dependence on the +; independent variables) and those that describe whether the field needs +; to be averaged in the x and y directions. +; +; ********************************************************************** +; + msg := \ +"Checking existence and dimensions of all variables in all specified tiles..." + print("") + print("" + separator_line) + print("" + msg) + + num_filevars = dimsizes(filevar_names) + do indx_fv=0, num_filevars-1 + +print("") +print("indx_fv = " + indx_fv) +print("filevar_names(indx_fv) = " + char_dq + filevar_names(indx_fv) + char_dq) +;pause +; +; Delete var_info and/or var_info_prev_tile if they already exist from +; loop over variables. +; + if (isvar("var_info")) then + delete(var_info) + end if + + if (isvar("var_info_prev_tile")) then + delete(var_info_prev_tile) + end if + + do nn=0, num_tiles-1 +;print("") +;print(" nn = " + nn) +;print(" field_names_by_tile(nn) = " + char_dq + field_names_by_tile(nn) + char_dq) +;pause + + if (.not. strcmp_exact(field_names_by_tile(nn), "none")) then + + if ((nn .gt. 0) .and. isvar("var_info")) then + var_info_prev_tile := var_info + end if + + var_info := check_filevar_existence_dims( \ + file_names_by_tile(nn), \ + filevar_names(indx_fv), \ + xdim_by_tile(nn), \ + ydim_by_tile(nn), \ + vert_inds_to_plot, \ + time_inds_to_plot) + + fp_field_file = var_info@fp + var_rank = var_info@var_rank + var_dim_names = var_info@var_dim_names + var_dim_sizes = var_info@var_dim_sizes + func_xy_only = var_info@func_xy_only + func_xyz_only = var_info@func_xyz_only + func_xyt_only = var_info@func_xyt_only + func_xyzt_only = var_info@func_xyzt_only + average_in_x = var_info@average_in_x + average_in_y = var_info@average_in_y +; +; ********************************************************************** +; +; If we've called for the previous tile the function that performs +; checks on the variable, then... +; +; ********************************************************************** +; + if ((nn .gt. 0) .and. isvar("var_info_prev_tile")) then + + n_tile_prev = tile_inds(nn-1) + + var_rank_prev_tile := var_info_prev_tile@var_rank + var_dim_names_prev_tile := var_info_prev_tile@var_dim_names + var_dim_sizes_prev_tile := var_info_prev_tile@var_dim_sizes + func_xy_only_prev_tile := var_info_prev_tile@func_xy_only + func_xyz_only_prev_tile := var_info_prev_tile@func_xyz_only + func_xyt_only_prev_tile := var_info_prev_tile@func_xyt_only + func_xyzt_only_prev_tile := var_info_prev_tile@func_xyzt_only + average_in_x_prev_tile := var_info_prev_tile@average_in_x + average_in_y_prev_tile := var_info_prev_tile@average_in_y + + if (var_rank .eq. var_rank_prev_tile) then + var_dim_names_differ := False + do i=0, var_rank_prev_tile-1 + if (.not. strcmp_exact(var_dim_names, var_dim_names_prev_tile(i))) then + var_dim_names_differ := True + break + end if + end do + end if + + if (var_rank .ne. var_rank_prev_tile) then + + msg := char_nl + \ +"The variable's rank (var_rank) changed from tile " + n_tile_prev + \ +" to tile " + n_tile + ":" + char_nl + \ +" var_rank_prev_tile = " + var_rank_prev_tile + char_nl + \ +" var_rank = " + var_rank + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (var_dim_names_differ) then + + var_dim_names_prev_tile_str \ + := str_join(var_dim_names_prev_tile, char_dq + ", " + char_dq) + var_dim_names_prev_tile_str \ + := "(" + char_dq + var_dim_names_prev_tile_str + char_dq + ")" + + var_dim_names_str \ + := str_join(var_dim_names, char_dq + ", " + char_dq) + var_dim_names_str \ + := "(" + char_dq + var_dim_names_str + char_dq + ")" + + msg := char_nl + \ +"The variable's dimension names (var_dim_names) changed from tile " + \ +n_tile_prev + " to " + char_nl + \ +"tile " + n_tile + ":" + char_nl + \ +" var_dim_names_prev_tile = " + var_dim_names_prev_tile_str + char_nl + \ +" var_dim_names = " + var_dim_names_str + char_nl + \ +"Stopping." + print("" + msg) + exit +; +; The following check may have to be removed since for a nested grid, +; the global tiles will not have the same dimensions as the nested tile, +; so requiring them to be the same doesn't make sense. Not sure why I +; put this in... I think for a given tile, the fields in filevar_names +; all need to have the same dimensions since they may be used together +; to calculate a new variable (e.g. filevar_names may contain dx and dy, +; and we may want to plot dy/dx). In that case, this check has to be +; fixed so that it compares fields within a tile, not a field between +; tiles. So, need to fix this... +; + else if (any(var_dim_sizes .ne. var_dim_sizes_prev_tile)) then + + var_dim_sizes_prev_tile_str \ + := "(" + str_join(tostring(var_dim_sizes_prev_tile), ", ") + ")" + var_dim_sizes_str \ + := "(" + str_join(tostring(var_dim_sizes), ", ") + ")" + + msg := char_nl + \ +"The variable's dimension sizes (var_dim_sizes) changed from tile " + \ +n_tile_prev + " to " + char_nl + \ +"tile " + n_tile + ":" + char_nl + \ +" var_dim_sizes_prev_tile = " + var_dim_sizes_prev_tile_str + char_nl + \ +" var_dim_sizes = " + var_dim_sizes_str + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (func_xy_only .ne. func_xy_only_prev_tile) then + + msg := char_nl + \ +"The variable's functional dependence status on only the horizontal " + char_nl + \ +"coordinates x and y (func_xy_only) changed from tile " + n_tile_prev + " to " + \ +"tile " + n_tile + ":" + char_nl + \ +" func_xy_only_prev_tile = " + func_xy_only_prev_tile + char_nl + \ +" func_xy_only = " + func_xy_only + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (func_xyz_only .ne. func_xyz_only_prev_tile) then + + msg := char_nl + \ +"The variable's functional dependence status on only the horizontal " + char_nl + \ +"coordinates x and y and the vertical coordinate (func_xyz_only) " + char_nl + \ +"changed from tile " + n_tile_prev + " to tile " + n_tile + ":" + char_nl + \ +" func_xyz_only_prev_tile = " + func_xyz_only_prev_tile + char_nl + \ +" func_xyz_only = " + func_xyz_only + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (func_xyt_only .ne. func_xyt_only_prev_tile) then + + msg := char_nl + \ +"The variable's functional dependence status on only the horizontal " + char_nl + \ +"coordinates x and y and time (func_xyt_only) changed from tile " + n_tile_prev + char_nl + \ +"to tile " + n_tile + ":" + char_nl + \ +" func_xyt_only_prev_tile = " + func_xyt_only_prev_tile + char_nl + \ +" func_xyt_only = " + func_xyt_only + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (func_xyzt_only .ne. func_xyzt_only_prev_tile) then + + msg := char_nl + \ +"The variable's functional dependence status on the horizontal coordinates " + char_nl + \ +"x and y, the vertical coordinate, and time (func_xyzt_only) changed from " + char_nl + \ +"tile " + n_tile_prev + " to tile " + n_tile + ":" + char_nl + \ +" func_xyzt_only_prev_tile = " + func_xyzt_only_prev_tile + char_nl + \ +" func_xyzt_only = " + func_xyzt_only + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (average_in_x .ne. average_in_x_prev_tile) then + + msg := char_nl + \ +"The averaging in the x direction needed to obtain the variable's values " + char_nl + \ +"at cell centers (average_in_x) changed from tile " + n_tile_prev + \ +" to tile " + n_tile + ":" + char_nl + \ +" average_in_x_prev_tile = " + average_in_x_prev_tile + char_nl + \ +" average_in_x = " + average_in_x + char_nl + \ +"Stopping." + print("" + msg) + exit + + else if (average_in_y .ne. average_in_y_prev_tile) then + + msg := char_nl + \ +"The averaging in the x direction needed to obtain the variable's values " + char_nl + \ +"at cell centers (average_in_y) changed from tile " + n_tile_prev + \ +" to tile " + n_tile + ":" + char_nl + \ +" average_in_y_prev_tile = " + average_in_y_prev_tile + char_nl + \ +" average_in_y = " + average_in_y + char_nl + \ +"Stopping." + print("" + msg) + exit + + end if + end if + end if + end if + end if + end if + end if + end if + end if + + end if ; Closes "if ((nn .gt. 0) .and. isvar("var_info_prev_tile")) then" +; +; ********************************************************************** +; +; If the name of the field to be plotted on the current tile is "none" +; (i.e. it is not a valid field), set the logical variables that de- +; scribe the functional dependence of the field on space and time (i.e. +; its dependence on the independent variables) and those that describe +; whether the field needs to be averaged in the x and y directions all +; to False. +; +; ********************************************************************** +; + else + +; var_rank = default_fillvalue("integer") +; var_dim_names = default_fillvalue("integer") +; var_dim_sizes = default_fillvalue("integer") + func_xy_only = False + func_xyz_only = False + func_xyt_only = False + func_xyzt_only = False + average_in_x = False + average_in_y = False + + end if ; Closes "if (.not. strcmp_exact(field_names_by_tile(nn), "none")) then + + end do + + end do + + msg := \ +"Done checking existence and dimensions of all variables in all speci-" + char_nl + \ +"fied tiles." + print("") + print("" + msg) + print("" + separator_line) +;pause +; +; ********************************************************************** +; +; Return results as attributes of the logical variable file_field_info. +; +; ********************************************************************** +; + file_field_info := True + + file_field_info@file_names_by_tile = file_names_by_tile + file_field_info@field_names_by_tile = field_names_by_tile + file_field_info@func_xy_only = func_xy_only + file_field_info@func_xyz_only = func_xyz_only + file_field_info@func_xyt_only = func_xyt_only + file_field_info@func_xyzt_only = func_xyzt_only + file_field_info@average_in_x = average_in_x + file_field_info@average_in_y = average_in_y + + return(file_field_info) + +end + diff --git a/ush/NOMADS_get_extrn_mdl_files.sh b/ush/NOMADS_get_extrn_mdl_files.sh new file mode 100755 index 0000000000..789eeff3dc --- /dev/null +++ b/ush/NOMADS_get_extrn_mdl_files.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# Command line arguments +if [ -z "$1" -o -z "$2" ]; then + echo "Usage: $0 yyyymmdd hh file_fmt nfcst nfcst_int" + echo "yyymmdd and hh are required and other variables are optional" + exit +fi +## date (year month day) and time (hour) +yyyymmdd=$1 #i.e. "20191224" +hh=$2 #i.e. "12" +## +## file format (grib2 or nemsio), the default format is grib2 +if [ "$#" -ge 3 ]; then + file_fmt=$3 +else + file_fmt="grib2" +fi +## forecast length, the default value are 6 hours +if [ "$#" -ge 4 ]; then + nfcst=$4 +else + nfcst=6 +fi +## forecast interval, the default interval are 3 hours +if [ "$#" -ge 5 ]; then + nfcst_int=$5 +else + nfcst_int=3 +fi + +# Get the data (do not need to edit anything after this point!) +yyyymm=$((yyyymmdd/100)) +#din_loc_ic=`./xmlquery DIN_LOC_IC --value` +mkdir -p gfs.$yyyymmdd/$hh +echo "Download files to $din_loc_ic/$yyyymm/$yyyymmdd ..." +cd gfs.$yyyymmdd/$hh + +#getting online analysis data +if [ $file_fmt == "grib2" ] || [ $file_fmt == "GRIB2" ]; then + wget --tries=2 -c https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.$yyyymmdd/$hh/gfs.t${hh}z.pgrb2.0p25.f000 +else + wget --tries=2 -c https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.$yyyymmdd/$hh/gfs.t${hh}z.atmanl.nemsio + wget --tries=2 -c https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.$yyyymmdd/$hh/gfs.t${hh}z.sfcanl.nemsio +fi + +#getting online forecast data +ifcst=$nfcst_int +while [ $ifcst -le $nfcst ] +do +echo $ifcst + if [ $ifcst -le 99 ]; then + if [ $ifcst -le 9 ]; then + ifcst_str="00"$ifcst + else + ifcst_str="0"$ifcst + fi + else + ifcst_str="$ifcst" + fi + echo $ifcst_str +# +if [ $file_fmt == "grib2" ] || [ $file_fmt == "GRIB2" ]; then + wget --tries=2 -c https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.$yyyymmdd/$hh/gfs.t${hh}z.pgrb2.0p25.f${ifcst_str} +else + wget --tries=2 -c https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.$yyyymmdd/$hh/gfs.t${hh}z.atmf${ifcst_str}.nemsio + wget --tries=2 -c https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.$yyyymmdd/$hh/gfs.t${hh}z.sfcf${ifcst_str}.nemsio +fi +# +ifcst=$[$ifcst+$nfcst_int] +done diff --git a/ush/Python/environment.yml b/ush/Python/environment.yml new file mode 100644 index 0000000000..8e08987ce0 --- /dev/null +++ b/ush/Python/environment.yml @@ -0,0 +1,15 @@ +name: pygraf +channels: + - conda-forge + - defaults +dependencies: + - python=3.7* + - basemap=1.2* + - basemap-data-hires=1.2.1 + - pynio=1.5.5 + - matplotlib=3.2* + - metpy=0.12.1 + - pylint=2.4* + - pytest=6.1* + - pyyaml=5.3.1 + - xarray=0.15.1 diff --git a/ush/Python/plot_allvars.py b/ush/Python/plot_allvars.py new file mode 100755 index 0000000000..3af564e522 --- /dev/null +++ b/ush/Python/plot_allvars.py @@ -0,0 +1,811 @@ +################################################################################ +#### Python Script Documentation Block +# +# Script name: plot_allvars.py +# Script description: Generates plots from FV3-LAM post processed grib2 output +# over the CONUS +# +# Authors: Ben Blake Org: NOAA/NWS/NCEP/EMC Date: 2020-05-07 +# David Wright Org: University of Michigan +# +# Instructions: Make sure all the necessary modules can be imported. +# The following command line arguments are needed: +# 1. Cycle date/time in YYYYMMDDHH format +# 2. Starting forecast hour +# 3. Ending forecast hour +# 4. Forecast hour increment +# 5. EXPT_DIR: Experiment directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR/YYYYMMDDHH/postprd/ +# 6. CARTOPY_DIR: Base directory of cartopy shapefiles +# -Shapefiles cannot be directly downloaded to NOAA +# machines from the internet, so shapefiles need to +# be downloaded if geopolitical boundaries are +# desired on the maps. +# -File structure should be: +# CARTOPY_DIR/shapefiles/natural_earth/cultural/*.shp +# -More information regarding files needed to setup +# display maps in Cartopy, see SRW App Users' Guide +# 7. POST_OUTPUT_DOMAIN_NAME: Name of native domain +# used in forecast and in constructing the names +# of the post output files. +# +# To create plots for a forecast on the RRFS_CONUS_25km +# grid for hours 20-24 from the 5/7 00Z cycle with +# hourly output: +# python plot_allvars.py 2020050700 20 24 1 \ +# /path/to/expt_dirs/experiment/name \ +# /path/to/base/cartopy/maps RRFS_CONUS_25km +# +# The variable domains in this script can be set to either +# 'conus' for a CONUS map or 'regional' where the map +# is defined from variables in the grib2 files +# +################################################################################ + +#-------------Import modules --------------------------# +import pygrib +import cartopy.crs as ccrs +from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER +import cartopy.feature as cfeature +import matplotlib +matplotlib.use('Agg') +import io +import matplotlib.pyplot as plt +import dateutil.relativedelta, dateutil.parser +from PIL import Image +from matplotlib.gridspec import GridSpec +import numpy as np +import time,os,sys,multiprocessing +import multiprocessing.pool +from scipy import ndimage +import pyproj +import argparse +import cartopy + +#--------------Define some functions ------------------# + +def ndate(cdate,hours): + if not isinstance(cdate, str): + if isinstance(cdate, int): + cdate=str(cdate) + else: + sys.exit('NDATE: Error - input cdate must be string or integer. Exit!') + if not isinstance(hours, int): + if isinstance(hours, str): + hours=int(hours) + else: + sys.exit('NDATE: Error - input delta hour must be a string or integer. Exit!') + + indate=cdate.strip() + hh=indate[8:10] + yyyy=indate[0:4] + mm=indate[4:6] + dd=indate[6:8] + #set date/time field + parseme=(yyyy+' '+mm+' '+dd+' '+hh) + datetime_cdate=dateutil.parser.parse(parseme) + valid=datetime_cdate+dateutil.relativedelta.relativedelta(hours=+hours) + vyyyy=str(valid.year) + vm=str(valid.month).zfill(2) + vd=str(valid.day).zfill(2) + vh=str(valid.hour).zfill(2) + return vyyyy+vm+vd+vh + + +def clear_plotables(ax,keep_ax_lst,fig): + #### - step to clear off old plottables but leave the map info - #### + if len(keep_ax_lst) == 0 : + print("clear_plotables WARNING keep_ax_lst has length 0. Clearing ALL plottables including map info!") + cur_ax_children = ax.get_children()[:] + if len(cur_ax_children) > 0: + for a in cur_ax_children: + if a not in keep_ax_lst: + # if the artist isn't part of the initial set up, remove it + a.remove() + + +def compress_and_save(filename): + #### - compress and save the image - #### + ram = io.BytesIO() + plt.savefig(ram, format='png', bbox_inches='tight', dpi=150) + ram.seek(0) + im = Image.open(ram) + im2 = im.convert('RGB')#.convert('P', palette=Image.ADAPTIVE) + im2.save(filename, format='PNG') + +def cmap_t2m(): + # Create colormap for 2-m temperature + # Modified version of the ncl_t2m colormap + r=np.array([255,128,0, 70, 51, 0, 255,0, 0, 51, 255,255,255,255,255,171,128,128,36,162,255]) + g=np.array([0, 0, 0, 70, 102,162,255,92,128,185,255,214,153,102,0, 0, 0, 68, 36,162,255]) + b=np.array([255,128,128,255,255,255,255,0, 0, 102,0, 112,0, 0, 0, 56, 0, 68, 36,162,255]) + xsize=np.arange(np.size(r)) + r = r/255. + g = g/255. + b = b/255. + red = [] + green = [] + blue = [] + for i in range(len(xsize)): + xNorm=np.float(i)/(np.float(np.size(r))-1.0) + red.append([xNorm,r[i],r[i]]) + green.append([xNorm,g[i],g[i]]) + blue.append([xNorm,b[i],b[i]]) + colorDict = {"red":red, "green":green, "blue":blue} + cmap_t2m_coltbl = matplotlib.colors.LinearSegmentedColormap('CMAP_T2M_COLTBL',colorDict) + return cmap_t2m_coltbl + + +def cmap_q2m(): + # Create colormap for 2-m dew point temperature + r=np.array([255,179,96,128,0, 0, 51, 0, 0, 0, 133,51, 70, 0, 128,128,180]) + g=np.array([255,179,96,128,92,128,153,155,155,255,162,102,70, 0, 0, 0, 0]) + b=np.array([255,179,96,0, 0, 0, 102,155,255,255,255,255,255,128,255,128,128]) + xsize=np.arange(np.size(r)) + r = r/255. + g = g/255. + b = b/255. + red = [] + green = [] + blue = [] + for i in range(len(xsize)): + xNorm=np.float(i)/(np.float(np.size(r))-1.0) + red.append([xNorm,r[i],r[i]]) + green.append([xNorm,g[i],g[i]]) + blue.append([xNorm,b[i],b[i]]) + colorDict = {"red":red, "green":green, "blue":blue} + cmap_q2m_coltbl = matplotlib.colors.LinearSegmentedColormap('CMAP_Q2M_COLTBL',colorDict) + cmap_q2m_coltbl.set_over(color='deeppink') + return cmap_q2m_coltbl + + +def rotate_wind(true_lat,lov_lon,earth_lons,uin,vin,proj,inverse=False): + # Rotate winds from LCC relative to earth relative (or vice-versa if inverse==true) + # This routine is vectorized and *should* work on any size 2D vg and ug arrays. + # Program will quit if dimensions are too large. + # + # Input args: + # true_lat = True latitidue for LCC projection (single value in degrees) + # lov_lon = The LOV value from grib (e.g. - -95.0) (single value in degrees) + # Grib doc says: "Lov = orientation of the grid; i.e. the east longitude value of + # the meridian which is parallel to the Y-axis (or columns of the grid) + # along which latitude increases as the Y-coordinate increases (the + # orientation longitude may or may not appear on a particular grid). + # + # earth_lons = Earth relative longitudes (can be an array, in degrees) + # uin, vin = Input winds to rotate + # + # Returns: + # uout, vout = Output, rotated winds + #----------------------------------------------------------------------------------------------------- + + # Get size and length of input u winds, if not 2d, raise an error + q=np.shape(uin) + ndims=len(q) + if ndims > 2: + # Raise error and quit! + raise SystemExit("Input winds for rotation have greater than 2 dimensions!") + if lov_lon > 0.: lov_lon=lov_lon-360. + dtr=np.pi/180.0 # Degrees to radians + + if not isinstance(inverse, bool): + raise TypeError("**kwarg inverse must be of type bool.") + + # Compute rotation constant which is also + # known as the Lambert cone constant. In the case + # of a polar stereographic projection, this is one. + # See the following pdf for excellent documentation + # http://www.dtcenter.org/met/users/docs/write_ups/velocity.pdf + if proj.lower()=='lcc': + rotcon_p=np.sin(true_lat*dtr) + elif proj.lower() in ['stere','spstere', 'npstere']: + rotcon_p=1.0 + else: + raise SystemExit("Unsupported map projection: "+proj.lower()+" for wind rotation.") + + angles = rotcon_p*(earth_lons-lov_lon)*dtr + sinx2 = np.sin(angles) + cosx2 = np.cos(angles) + + # Steps below are elementwise products, not matrix mutliplies + if inverse==False: + # Return the earth relative winds + uout = cosx2*uin+sinx2*vin + vout =-sinx2*uin+cosx2*vin + elif inverse==True: + # Return the grid relative winds + uout = cosx2*uin-sinx2*vin + vout = sinx2*uin+cosx2*vin + + return uout,vout + + +#-------------Start of script -------------------------# + +# Define required positional arguments +parser = argparse.ArgumentParser() +parser.add_argument("Cycle date/time in YYYYMMDDHH format") +parser.add_argument("Starting forecast hour") +parser.add_argument("Ending forecast hour") +parser.add_argument("Forecast hour increment") +parser.add_argument("Path to experiment directory") +parser.add_argument("Path to base directory of cartopy shapefiles") +parser.add_argument("Name of native domain used in forecast (and in constructing post file names)") +args = parser.parse_args() + +# Read date/time, forecast hour, and directory paths from command line +ymdh = str(sys.argv[1]) +ymd = ymdh[0:8] +year = int(ymdh[0:4]) +month = int(ymdh[4:6]) +day = int(ymdh[6:8]) +hour = int(ymdh[8:10]) +cyc = str(hour).zfill(2) +print(year, month, day, hour) + +# Define the range of forecast hours to create plots for +start_fhr = int(sys.argv[2]) +end_fhr = int(sys.argv[3]) +increment_fhr = int(sys.argv[4]) +if (start_fhr == end_fhr) or (increment_fhr == 0): + fhours = [start_fhr] +else: + num = int(((end_fhr - start_fhr) / increment_fhr) + 1) + fhours = np.linspace(start_fhr,end_fhr,num,dtype='int') +print(fhours) + +EXPT_DIR = str(sys.argv[5]) +CARTOPY_DIR = str(sys.argv[6]) +POST_OUTPUT_DOMAIN_NAME = str(sys.argv[7]).lower() + +# Loop over forecast hours +for fhr in fhours: + fhour = str(fhr).zfill(3) + print('Working on forecast hour '+fhour) + itime = ymdh + vtime = ndate(itime,int(fhr)) + +# Define the location of the input file + data1 = pygrib.open(EXPT_DIR+'/'+ymdh+'/postprd/rrfs.t'+cyc+'z.prslev.f'+fhour+'.'+POST_OUTPUT_DOMAIN_NAME+'.grib2') + +# Get the lats and lons + grids = [data1] + lats = [] + lons = [] + lats_shift = [] + lons_shift = [] + + for data in grids: + # Unshifted grid for contours and wind barbs + lat, lon = data[1].latlons() + lats.append(lat) + lons.append(lon) + + # Shift grid for pcolormesh + lat1 = data[1]['latitudeOfFirstGridPointInDegrees'] + lon1 = data[1]['longitudeOfFirstGridPointInDegrees'] + try: + nx = data[1]['Nx'] + ny = data[1]['Ny'] + except: + nx = data[1]['Ni'] + ny = data[1]['Nj'] + dx = data[1]['DxInMetres'] + dy = data[1]['DyInMetres'] + pj = pyproj.Proj(data[1].projparams) + llcrnrx, llcrnry = pj(lon1,lat1) + llcrnrx = llcrnrx - (dx/2.) + llcrnry = llcrnry - (dy/2.) + x = llcrnrx + dx*np.arange(nx) + y = llcrnry + dy*np.arange(ny) + x,y = np.meshgrid(x,y) + lon, lat = pj(x, y, inverse=True) + lats_shift.append(lat) + lons_shift.append(lon) + +# Unshifted lat/lon arrays grabbed directly using latlons() method + lat = lats[0] + lon = lons[0] + +# Shifted lat/lon arrays for pcolormesh + lat_shift = lats_shift[0] + lon_shift = lons_shift[0] + + Lat0 = data1[1]['LaDInDegrees'] + Lon0 = data1[1]['LoVInDegrees'] + print(Lat0) + print(Lon0) + +# Specify plotting domains +# User can add domains here, just need to specify lat/lon information below +# (if dom == 'conus' block) + domains=['conus'] # Other option is 'regional' + +################################################### +# Read in all variables and calculate differences # +################################################### + t1a = time.perf_counter() + +# Sea level pressure + slp = data1.select(name='Pressure reduced to MSL')[0].values * 0.01 + slpsmooth = ndimage.filters.gaussian_filter(slp, 13.78) + +# 2-m temperature + tmp2m = data1.select(name='2 metre temperature')[0].values + tmp2m = (tmp2m - 273.15)*1.8 + 32.0 + +# 2-m dew point temperature + dew2m = data1.select(name='2 metre dewpoint temperature')[0].values + dew2m = (dew2m - 273.15)*1.8 + 32.0 + +# 10-m wind speed + uwind = data1.select(name='10 metre U wind component')[0].values * 1.94384 + vwind = data1.select(name='10 metre V wind component')[0].values * 1.94384 +# Rotate winds from grid relative to Earth relative + uwind, vwind = rotate_wind(Lat0,Lon0,lon,uwind,vwind,'lcc',inverse=False) + wspd10m = np.sqrt(uwind**2 + vwind**2) + +# Surface-based CAPE + cape = data1.select(name='Convective available potential energy',typeOfLevel='surface')[0].values + +# Surface-based CIN + cin = data1.select(name='Convective inhibition',typeOfLevel='surface')[0].values + +# 500 mb height, wind, vorticity + z500 = data1.select(name='Geopotential Height',level=500)[0].values * 0.1 + z500 = ndimage.filters.gaussian_filter(z500, 6.89) + vort500 = data1.select(name='Absolute vorticity',level=500)[0].values * 100000 + vort500 = ndimage.filters.gaussian_filter(vort500,1.7225) + vort500[vort500 > 1000] = 0 # Mask out undefined values on domain edge + u500 = data1.select(name='U component of wind',level=500)[0].values * 1.94384 + v500 = data1.select(name='V component of wind',level=500)[0].values * 1.94384 +# Rotate winds from grid relative to Earth relative + u500, v500 = rotate_wind(Lat0,Lon0,lon,u500,v500,'lcc',inverse=False) + +# 250 mb winds + u250 = data1.select(name='U component of wind',level=250)[0].values * 1.94384 + v250 = data1.select(name='V component of wind',level=250)[0].values * 1.94384 +# Rotate winds from grid relative to Earth relative + u250, v250 = rotate_wind(Lat0,Lon0,lon,u250,v250,'lcc',inverse=False) + wspd250 = np.sqrt(u250**2 + v250**2) + +# Total precipitation + qpf = data1.select(name='Total Precipitation',lengthOfTimeRange=fhr)[0].values * 0.0393701 + +# Composite reflectivity + refc = data1.select(name='Maximum/Composite radar reflectivity')[0].values + + if (fhr > 0): +# Max/Min Hourly 2-5 km Updraft Helicity + maxuh25 = data1.select(stepType='max',parameterName="199",topLevel=5000,bottomLevel=2000)[0].values + minuh25 = data1.select(stepType='min',parameterName="200",topLevel=5000,bottomLevel=2000)[0].values + maxuh25[maxuh25 < 10] = 0 + minuh25[minuh25 > -10] = 0 + uh25 = maxuh25 + minuh25 + + + t2a = time.perf_counter() + t3a = round(t2a-t1a, 3) + print(("%.3f seconds to read all messages") % t3a) + + +######################################## +# START PLOTTING FOR EACH DOMAIN # +######################################## + + def main(): + + # Number of processes must coincide with the number of domains to plot + #pool = multiprocessing.Pool(len(domains)) + #pool.map(plot_all,domains) + + # To avoid import multiprocessing recursively on MacOS etc. + # Anyway since we only have one domain for SRW application + for dom in domains: + plot_all(dom) + + def plot_all(dom): + + t1dom = time.perf_counter() + + # Map corners for each domain + if dom == 'conus': + llcrnrlon = -120.5 + llcrnrlat = 21.0 + urcrnrlon = -64.5 + urcrnrlat = 49.0 + lat_0 = 35.4 + lon_0 = -97.6 + extent=[llcrnrlon-3,urcrnrlon-6,llcrnrlat-1,urcrnrlat+2] + elif dom == 'regional': + llcrnrlon = np.min(lon) + llcrnrlat = np.min(lat) + urcrnrlon = np.max(lon) + urcrnrlat = np.max(lat) + lat_0 = Lat0 + lon_0 = Lon0 + extent=[llcrnrlon,urcrnrlon,llcrnrlat-1,urcrnrlat] + + + # create figure and axes instances + fig = plt.figure(figsize=(10,10)) + ax1 = fig.add_axes([0.1,0.1,0.8,0.8]) + + # Define where Cartopy Maps are located + cartopy.config['data_dir'] = CARTOPY_DIR + + back_res='50m' + back_img='on' + + # set up the map background with cartopy + myproj=ccrs.LambertConformal(central_longitude=lon_0, central_latitude=lat_0, false_easting=0.0, + false_northing=0.0, secant_latitudes=None, standard_parallels=None, + globe=None) + ax = plt.axes(projection=myproj) + ax.set_extent(extent) + + fline_wd = 0.5 # line width + falpha = 0.3 # transparency + + # natural_earth +# land=cfeature.NaturalEarthFeature('physical','land',back_res, +# edgecolor='face',facecolor=cfeature.COLORS['land'], +# alpha=falpha) + lakes=cfeature.NaturalEarthFeature('physical','lakes',back_res, + edgecolor='blue',facecolor='none', + linewidth=fline_wd,alpha=falpha) + coastline=cfeature.NaturalEarthFeature('physical','coastline', + back_res,edgecolor='blue',facecolor='none', + linewidth=fline_wd,alpha=falpha) + states=cfeature.NaturalEarthFeature('cultural','admin_1_states_provinces', + back_res,edgecolor='black',facecolor='none', + linewidth=fline_wd,linestyle=':',alpha=falpha) + borders=cfeature.NaturalEarthFeature('cultural','admin_0_countries', + back_res,edgecolor='red',facecolor='none', + linewidth=fline_wd,alpha=falpha) + + # All lat lons are earth relative, so setup the associated projection correct for that data + transform = ccrs.PlateCarree() + + # high-resolution background images + if back_img=='on': + img = plt.imread(CARTOPY_DIR+'/raster_files/NE1_50M_SR_W.tif') + ax.imshow(img, origin='upper', transform=transform) + +# ax.add_feature(land) + ax.add_feature(lakes) + ax.add_feature(states) + ax.add_feature(borders) + ax.add_feature(coastline) + + # Map/figure has been set up here, save axes instances for use again later + keep_ax_lst = ax.get_children()[:] + + +################################ + # Plot SLP +################################ + t1 = time.perf_counter() + print(('Working on slp for '+dom)) + + units = 'mb' + clevs = [976,980,984,988,992,996,1000,1004,1008,1012,1016,1020,1024,1028,1032,1036,1040,1044,1048,1052] + clevsdif = [-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12] + cm = plt.cm.Spectral_r + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs1_a = plt.pcolormesh(lon_shift,lat_shift,slp,transform=transform,cmap=cm,norm=norm) + cbar1 = plt.colorbar(cs1_a,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + cs1_b = plt.contour(lon_shift,lat_shift,slpsmooth,np.arange(940,1060,4),colors='black',linewidths=1.25,transform=transform) + plt.clabel(cs1_b,np.arange(940,1060,4),inline=1,fmt='%d',fontsize=8) + ax.text(.5,1.03,'FV3-LAM SLP ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/slp_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot slp for: '+dom) % t3) + + +################################# + # Plot 2-m T +################################# + t1 = time.perf_counter() + print(('Working on t2m for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = '\xb0''F' + clevs = np.linspace(-16,134,51) + cm = plt.cm.Spectral_r #cmap_t2m() + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,tmp2m,transform=transform,cmap=cm,norm=norm) + cs_1.cmap.set_under('white') + cs_1.cmap.set_over('white') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=[-16,-4,8,20,32,44,56,68,80,92,104,116,128],extend='both') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + ax.text(.5,1.03,'FV3-LAM 2-m Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/2mt_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 2mt for: '+dom) % t3) + + +################################# + # Plot 2-m Dew Point +################################# + t1 = time.perf_counter() + print(('Working on 2mdew for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = '\xb0''F' + clevs = np.linspace(-5,80,35) + cm = cmap_q2m() + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,dew2m,transform=transform,cmap=cm,norm=norm) + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + ax.text(.5,1.03,'FV3-LAM 2-m Dew Point Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/2mdew_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 2mdew for: '+dom) % t3) + + +################################# + # Plot 10-m WSPD +################################# + t1 = time.perf_counter() + print(('Working on 10mwspd for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'kts' + # Places a wind barb every ~180 km, optimized for CONUS domain + skip = round(177.28*(dx/1000.)**-.97) + print('skipping every '+str(skip)+' grid points to plot') + barblength = 4 + + clevs = [5,10,15,20,25,30,35,40,45,50,55,60] + colorlist = ['turquoise','dodgerblue','blue','#FFF68F','#E3CF57','peru','brown','crimson','red','fuchsia','DarkViolet'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,wspd10m,transform=transform,cmap=cm,vmin=5,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + plt.barbs(lon_shift[::skip,::skip],lat_shift[::skip,::skip],uwind[::skip,::skip],vwind[::skip,::skip],length=barblength,linewidth=0.5,color='black',transform=transform) + ax.text(.5,1.03,'FV3-LAM 10-m Winds ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/10mwind_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 10mwspd for: '+dom) % t3) + + +################################# + # Plot Surface-Based CAPE/CIN +################################# + t1 = time.perf_counter() + print(('Working on surface-based CAPE/CIN for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'J/kg' + clevs = [100,250,500,1000,1500,2000,2500,3000,3500,4000,4500,5000] + clevs2 = [-2000,-500,-250,-100,-25] + colorlist = ['blue','dodgerblue','cyan','mediumspringgreen','#FAFAD2','#EEEE00','#EEC900','darkorange','crimson','darkred','darkviolet'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,cape,transform=transform,cmap=cm,vmin=100,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + cs_1b = plt.contourf(lon_shift,lat_shift,cin,clevs2,colors='none',hatches=['**','++','////','..'],transform=transform) + ax.text(.5,1.05,'FV3-LAM Surface-Based CAPE (shaded) and CIN (hatched) ('+units+') \n <-500 (*), -500<-250 (+), -250<-100 (/), -100<-25 (.) \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/sfcape_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot surface-based CAPE/CIN for: '+dom) % t3) + + +################################# + # Plot 500 mb HGT/WIND/VORT +################################# + t1 = time.perf_counter() + print(('Working on 500 mb Hgt/Wind/Vort for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'x10${^5}$ s${^{-1}}$' + skip = round(177.28*(dx/1000.)**-.97) + barblength = 4 + + vortlevs = [16,20,24,28,32,36,40] + colorlist = ['yellow','gold','goldenrod','orange','orangered','red'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(vortlevs, cm.N) + + cs1_a = plt.pcolormesh(lon_shift,lat_shift,vort500,transform=transform,cmap=cm,norm=norm) + cs1_a.cmap.set_under('white') + cs1_a.cmap.set_over('darkred') + cbar1 = plt.colorbar(cs1_a,orientation='horizontal',pad=0.05,shrink=0.6,ticks=vortlevs,extend='both') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + plt.barbs(lon_shift[::skip,::skip],lat_shift[::skip,::skip],u500[::skip,::skip],v500[::skip,::skip],length=barblength,linewidth=0.5,color='steelblue',transform=transform) + cs1_b = plt.contour(lon_shift,lat_shift,z500,np.arange(486,600,6),colors='black',linewidths=1,transform=transform) + plt.clabel(cs1_b,np.arange(486,600,6),inline_spacing=1,fmt='%d',fontsize=8) + ax.text(.5,1.03,'FV3-LAM 500 mb Heights (dam), Winds (kts), and $\zeta$ ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/500_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 500 mb Hgt/Wind/Vort for: '+dom) % t3) + + +################################# + # Plot 250 mb WIND +################################# + t1 = time.perf_counter() + print(('Working on 250 mb WIND for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'kts' + skip = round(177.28*(dx/1000.)**-.97) + + barblength = 4 + + clevs = [50,60,70,80,90,100,110,120,130,140,150] + colorlist = ['turquoise','deepskyblue','dodgerblue','#1874CD','blue','beige','khaki','peru','brown','crimson'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,wspd250,transform=transform,cmap=cm,vmin=50,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('red') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + plt.barbs(lon_shift[::skip,::skip],lat_shift[::skip,::skip],u250[::skip,::skip],v250[::skip,::skip],length=barblength,linewidth=0.5,color='black',transform=transform) + ax.text(.5,1.03,'FV3-LAM 250 mb Winds ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/250wind_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 250 mb WIND for: '+dom) % t3) + +################################# + # Plot Total QPF +################################# + if (fhr > 0): # Do not make total QPF plot for forecast hour 0 + t1 = time.perf_counter() + print(('Working on total qpf for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'in' + clevs = [0.01,0.1,0.25,0.5,0.75,1,1.25,1.5,1.75,2,2.5,3,4,5,7,10,15,20] + clevsdif = [-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3] + colorlist = ['chartreuse','limegreen','green','blue','dodgerblue','deepskyblue','cyan','mediumpurple','mediumorchid','darkmagenta','darkred','crimson','orangered','darkorange','goldenrod','gold','yellow'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,qpf,transform=transform,cmap=cm,vmin=0.01,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('pink') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=8) + cbar1.ax.set_xticklabels(clevs) + cbar1.ax.tick_params(labelsize=8) + ax.text(.5,1.03,'FV3-LAM '+fhour+'-hr Accumulated Precipitation ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/qpf_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot total qpf for: '+dom) % t3) + +################################# + # Plot composite reflectivity +################################# + t1 = time.perf_counter() + print(('Working on composite reflectivity for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'dBZ' + clevs = np.linspace(5,70,14) + clevsdif = [20,1000] + colorlist = ['turquoise','dodgerblue','mediumblue','lime','limegreen','green','#EEEE00','#EEC900','darkorange','red','firebrick','darkred','fuchsia'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,refc,transform=transform,cmap=cm,vmin=5,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + ax.text(.5,1.03,'FV3-LAM Composite Reflectivity ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/refc_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot composite reflectivity for: '+dom) % t3) + + +################################# + # Plot Max/Min Hourly 2-5 km UH +################################# + if (fhr > 0): # Do not make max/min hourly 2-5 km UH plot for forecast hour 0 + t1 = time.perf_counter() + print(('Working on Max/Min Hourly 2-5 km UH for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + clear_plotables(ax,keep_ax_lst,fig) + + units = 'm${^2}$ s$^{-2}$' + clevs = [-150,-100,-75,-50,-25,-10,0,10,25,50,75,100,150,200,250,300] +# alternative colormap for just max UH if you don't want to plot the min UH too +# colorlist = ['white','skyblue','mediumblue','green','orchid','firebrick','#EEC900','DarkViolet'] + colorlist = ['blue','#1874CD','dodgerblue','deepskyblue','turquoise','#E5E5E5','#E5E5E5','#EEEE00','#EEC900','darkorange','orangered','red','firebrick','mediumvioletred','darkviolet'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = plt.pcolormesh(lon_shift,lat_shift,uh25,transform=transform,cmap=cm,norm=norm) + cs_1.cmap.set_under('darkblue') + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar1.set_label(units,fontsize=8) + cbar1.ax.tick_params(labelsize=8) + ax.text(.5,1.03,'FV3-LAM 1-h Max/Min 2-5 km Updraft Helicity ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR+'/'+ymdh+'/postprd/uh25_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot Max/Min Hourly 2-5 km UH for: '+dom) % t3) + + +###################################################### + + t3dom = round(t2-t1dom, 3) + print(("%.3f seconds to plot all variables for forecast hour "+fhour) % t3dom) + plt.clf() + +###################################################### + + main() + diff --git a/ush/Python/plot_allvars_diff.py b/ush/Python/plot_allvars_diff.py new file mode 100755 index 0000000000..ec85df2e5b --- /dev/null +++ b/ush/Python/plot_allvars_diff.py @@ -0,0 +1,1101 @@ +################################################################################ +#### Python Script Documentation Block +# +# Script name: plot_allvars_diff.py +# Script description: Generates difference plots from FV3-LAM post processed +# grib2 output over the CONUS +# +# Authors: Ben Blake Org: NOAA/NWS/NCEP/EMC Date: 2020-08-24 +# David Wright Org: University of Michigan +# +# Instructions: Make sure all the necessary modules can be imported. +# The following command line arguments are needed: +# 1. Cycle date/time in YYYYMMDDHH format +# 2. Starting forecast hour +# 3. Ending forecast hour +# 4. Forecast hour increment +# 5. EXPT_DIR_1: Experiment 1 directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR_1/YYYYMMDDHH/postprd/ +# 6. EXPT_DIR_2: Experiment 2 directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR_2/YYYYMMDDHH/postprd/ +# 7. CARTOPY_DIR: Base directory of cartopy shapefiles +# -Shapefiles cannot be directly downloaded to NOAA +# machines from the internet, so shapefiles need to +# be downloaded if geopolitical boundaries are +# desired on the maps. +# -File structure should be: +# CARTOPY_DIR/shapefiles/natural_earth/cultural/*.shp +# -More information regarding files needed to setup +# display maps in Cartopy, see SRW App Users' Guide +# 8. POST_OUTPUT_DOMAIN_NAME: Name of native domain +# used in forecasts and in constructing the names +# of the post output files. This must be the same +# for both forecasts. +# +# To create difference plots for two forecasts on the +# RRFS_CONUS_25km grid for hours 20-24 from the 5/7 +# 00Z cycle with hourly output: +# python plot_allvars_diff.py 2020050700 20 24 1 \ +# /path/to/expt_dir_1 /path/to/expt_dir_2 \ +# /path/to/base/cartopy/maps RRFS_CONUS_25km +# +# The variable domains in this script can be set to either +# 'conus' for a CONUS map or 'regional' where the map +# is defined from variables in the grib2 files +# +################################################################################ + +#-------------Import modules --------------------------# +import pygrib +import cartopy.crs as ccrs +from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER +import cartopy.feature as cfeature +import matplotlib +matplotlib.use('Agg') +import io +import matplotlib.pyplot as plt +import dateutil.relativedelta, dateutil.parser +from PIL import Image +from matplotlib.gridspec import GridSpec +import numpy as np +import time,os,sys,multiprocessing +import multiprocessing.pool +from scipy import ndimage +import pyproj +import argparse +import cartopy + +#--------------Define some functions ------------------# + +def ndate(cdate,hours): + if not isinstance(cdate, str): + if isinstance(cdate, int): + cdate=str(cdate) + else: + sys.exit('NDATE: Error - input cdate must be string or integer. Exit!') + if not isinstance(hours, int): + if isinstance(hours, str): + hours=int(hours) + else: + sys.exit('NDATE: Error - input delta hour must be a string or integer. Exit!') + + indate=cdate.strip() + hh=indate[8:10] + yyyy=indate[0:4] + mm=indate[4:6] + dd=indate[6:8] + #set date/time field + parseme=(yyyy+' '+mm+' '+dd+' '+hh) + datetime_cdate=dateutil.parser.parse(parseme) + valid=datetime_cdate+dateutil.relativedelta.relativedelta(hours=+hours) + vyyyy=str(valid.year) + vm=str(valid.month).zfill(2) + vd=str(valid.day).zfill(2) + vh=str(valid.hour).zfill(2) + return vyyyy+vm+vd+vh + + +def clear_plotables(ax,keep_ax_lst,fig): + #### - step to clear off old plottables but leave the map info - #### + if len(keep_ax_lst) == 0 : + print("clear_plotables WARNING keep_ax_lst has length 0. Clearing ALL plottables including map info!") + cur_ax_children = ax.get_children()[:] + if len(cur_ax_children) > 0: + for a in cur_ax_children: + if a not in keep_ax_lst: + # if the artist isn't part of the initial set up, remove it + a.remove() + + +def compress_and_save(filename): + #### - compress and save the image - #### + ram = io.BytesIO() + plt.savefig(ram, format='png', bbox_inches='tight', dpi=150) + ram.seek(0) + im = Image.open(ram) + im2 = im.convert('RGB')#.convert('P', palette=Image.ADAPTIVE) + im2.save(filename, format='PNG') + +def cmap_t2m(): + # Create colormap for 2-m temperature + # Modified version of the ncl_t2m colormap + r=np.array([255,128,0, 70, 51, 0, 255,0, 0, 51, 255,255,255,255,255,171,128,128,36,162,255]) + g=np.array([0, 0, 0, 70, 102,162,255,92,128,185,255,214,153,102,0, 0, 0, 68, 36,162,255]) + b=np.array([255,128,128,255,255,255,255,0, 0, 102,0, 112,0, 0, 0, 56, 0, 68, 36,162,255]) + xsize=np.arange(np.size(r)) + r = r/255. + g = g/255. + b = b/255. + red = [] + green = [] + blue = [] + for i in range(len(xsize)): + xNorm=np.float(i)/(np.float(np.size(r))-1.0) + red.append([xNorm,r[i],r[i]]) + green.append([xNorm,g[i],g[i]]) + blue.append([xNorm,b[i],b[i]]) + colorDict = {"red":red, "green":green, "blue":blue} + cmap_t2m_coltbl = matplotlib.colors.LinearSegmentedColormap('CMAP_T2M_COLTBL',colorDict) + return cmap_t2m_coltbl + + +def cmap_q2m(): + # Create colormap for 2-m dew point temperature + r=np.array([255,179,96,128,0, 0, 51, 0, 0, 0, 133,51, 70, 0, 128,128,180]) + g=np.array([255,179,96,128,92,128,153,155,155,255,162,102,70, 0, 0, 0, 0]) + b=np.array([255,179,96,0, 0, 0, 102,155,255,255,255,255,255,128,255,128,128]) + xsize=np.arange(np.size(r)) + r = r/255. + g = g/255. + b = b/255. + red = [] + green = [] + blue = [] + for i in range(len(xsize)): + xNorm=np.float(i)/(np.float(np.size(r))-1.0) + red.append([xNorm,r[i],r[i]]) + green.append([xNorm,g[i],g[i]]) + blue.append([xNorm,b[i],b[i]]) + colorDict = {"red":red, "green":green, "blue":blue} + cmap_q2m_coltbl = matplotlib.colors.LinearSegmentedColormap('CMAP_Q2M_COLTBL',colorDict) + cmap_q2m_coltbl.set_over(color='deeppink') + return cmap_q2m_coltbl + + +def rotate_wind(true_lat,lov_lon,earth_lons,uin,vin,proj,inverse=False): + # Rotate winds from LCC relative to earth relative (or vice-versa if inverse==true) + # This routine is vectorized and *should* work on any size 2D vg and ug arrays. + # Program will quit if dimensions are too large. + # + # Input args: + # true_lat = True latitidue for LCC projection (single value in degrees) + # lov_lon = The LOV value from grib (e.g. - -95.0) (single value in degrees) + # Grib doc says: "Lov = orientation of the grid; i.e. the east longitude value of + # the meridian which is parallel to the Y-axis (or columns of the grid) + # along which latitude increases as the Y-coordinate increases (the + # orientation longitude may or may not appear on a particular grid). + # + # earth_lons = Earth relative longitudes (can be an array, in degrees) + # uin, vin = Input winds to rotate + # + # Returns: + # uout, vout = Output, rotated winds + #----------------------------------------------------------------------------------------------------- + + # Get size and length of input u winds, if not 2d, raise an error + q=np.shape(uin) + ndims=len(q) + if ndims > 2: + # Raise error and quit! + raise SystemExit("Input winds for rotation have greater than 2 dimensions!") + if lov_lon > 0.: lov_lon=lov_lon-360. + dtr=np.pi/180.0 # Degrees to radians + + if not isinstance(inverse, bool): + raise TypeError("**kwarg inverse must be of type bool.") + + # Compute rotation constant which is also + # known as the Lambert cone constant. In the case + # of a polar stereographic projection, this is one. + # See the following pdf for excellent documentation + # http://www.dtcenter.org/met/users/docs/write_ups/velocity.pdf + if proj.lower()=='lcc': + rotcon_p=np.sin(true_lat*dtr) + elif proj.lower() in ['stere','spstere', 'npstere']: + rotcon_p=1.0 + else: + raise SystemExit("Unsupported map projection: "+proj.lower()+" for wind rotation.") + + angles = rotcon_p*(earth_lons-lov_lon)*dtr + sinx2 = np.sin(angles) + cosx2 = np.cos(angles) + + # Steps below are elementwise products, not matrix mutliplies + if inverse==False: + # Return the earth relative winds + uout = cosx2*uin+sinx2*vin + vout =-sinx2*uin+cosx2*vin + elif inverse==True: + # Return the grid relative winds + uout = cosx2*uin-sinx2*vin + vout = sinx2*uin+cosx2*vin + + return uout,vout + + +#-------------Start of script -------------------------# + +# Define required positional arguments +parser = argparse.ArgumentParser() +parser.add_argument("Cycle date/time in YYYYMMDDHH format") +parser.add_argument("Starting forecast hour") +parser.add_argument("Ending forecast hour") +parser.add_argument("Forecast hour increment") +parser.add_argument("Path to experiment 1 directory") +parser.add_argument("Path to experiment 2 directory") +parser.add_argument("Path to base directory of cartopy shapefiles") +parser.add_argument("Name of native domain used in forecasts (and in constructing post file names)") +args = parser.parse_args() + +# Read date/time, forecast hour, and directory paths from command line +ymdh = str(sys.argv[1]) +ymd = ymdh[0:8] +year = int(ymdh[0:4]) +month = int(ymdh[4:6]) +day = int(ymdh[6:8]) +hour = int(ymdh[8:10]) +cyc = str(hour).zfill(2) +print(year, month, day, hour) + +# Define the range of forecast hours to create plots for +start_fhr = int(sys.argv[2]) +end_fhr = int(sys.argv[3]) +increment_fhr = int(sys.argv[4]) +if (start_fhr == end_fhr) or (increment_fhr == 0): + fhours = [start_fhr] +else: + num = int(((end_fhr - start_fhr) / increment_fhr) + 1) + fhours = np.linspace(start_fhr,end_fhr,num,dtype='int') +print(fhours) + +EXPT_DIR_1 = str(sys.argv[5]) +EXPT_DIR_2 = str(sys.argv[6]) +CARTOPY_DIR = str(sys.argv[7]) +POST_OUTPUT_DOMAIN_NAME = str(sys.argv[8]).lower() + +# Loop over forecast hours +for fhr in fhours: + fhour = str(fhr).zfill(3) + print('Working on forecast hour '+fhour) + itime = ymdh + vtime = ndate(itime,int(fhr)) + + +# Define the location of the input files + data1 = pygrib.open(EXPT_DIR_1+'/'+ymdh+'/postprd/rrfs.t'+cyc+'z.prslev.f'+fhour+'.'+POST_OUTPUT_DOMAIN_NAME+'.grib2') + data2 = pygrib.open(EXPT_DIR_2+'/'+ymdh+'/postprd/rrfs.t'+cyc+'z.prslev.f'+fhour+'.'+POST_OUTPUT_DOMAIN_NAME+'.grib2') + +# Get the lats and lons + grids = [data1, data2] + lats = [] + lons = [] + lats_shift = [] + lons_shift = [] + + for data in grids: + # Unshifted grid for contours and wind barbs + lat, lon = data[1].latlons() + lats.append(lat) + lons.append(lon) + + # Shift grid for pcolormesh + lat1 = data[1]['latitudeOfFirstGridPointInDegrees'] + lon1 = data[1]['longitudeOfFirstGridPointInDegrees'] + try: + nx = data[1]['Nx'] + ny = data[1]['Ny'] + except: + nx = data[1]['Ni'] + ny = data[1]['Nj'] + dx = data[1]['DxInMetres'] + dy = data[1]['DyInMetres'] + pj = pyproj.Proj(data[1].projparams) + llcrnrx, llcrnry = pj(lon1,lat1) + llcrnrx = llcrnrx - (dx/2.) + llcrnry = llcrnry - (dy/2.) + x = llcrnrx + dx*np.arange(nx) + y = llcrnry + dy*np.arange(ny) + x,y = np.meshgrid(x,y) + lon, lat = pj(x, y, inverse=True) + lats_shift.append(lat) + lons_shift.append(lon) + +# Unshifted lat/lon arrays grabbed directly using latlons() method + lat = lats[0] + lon = lons[0] + lat2 = lats[1] + lon2 = lons[1] + +# Shifted lat/lon arrays for pcolormesh + lat_shift = lats_shift[0] + lon_shift = lons_shift[0] + lat2_shift = lats_shift[1] + lon2_shift = lons_shift[1] + + Lat0 = data1[1]['LaDInDegrees'] + Lon0 = data1[1]['LoVInDegrees'] + print(Lat0) + print(Lon0) + +# Specify plotting domains +# User can add domains here, just need to specify lat/lon information below +# (if dom == 'conus' block) + domains=['conus'] # Other option is 'regional' + +################################################### +# Read in all variables and calculate differences # +################################################### + t1a = time.perf_counter() + +# Sea level pressure + slp_1 = data1.select(name='Pressure reduced to MSL')[0].values * 0.01 + slpsmooth_1 = ndimage.filters.gaussian_filter(slp_1, 13.78) + slp_2 = data2.select(name='Pressure reduced to MSL')[0].values * 0.01 + slpsmooth_2 = ndimage.filters.gaussian_filter(slp_2, 13.78) + slp_diff = slp_2 - slp_1 + +# 2-m temperature + tmp2m_1 = data1.select(name='2 metre temperature')[0].values + tmp2m_1 = (tmp2m_1 - 273.15)*1.8 + 32.0 + tmp2m_2 = data2.select(name='2 metre temperature')[0].values + tmp2m_2 = (tmp2m_2 - 273.15)*1.8 + 32.0 + tmp2m_diff = tmp2m_2 - tmp2m_1 + +# 2-m dew point temperature + dew2m_1 = data1.select(name='2 metre dewpoint temperature')[0].values + dew2m_1 = (dew2m_1 - 273.15)*1.8 + 32.0 + dew2m_2 = data2.select(name='2 metre dewpoint temperature')[0].values + dew2m_2 = (dew2m_2 - 273.15)*1.8 + 32.0 + dew2m_diff = dew2m_2 - dew2m_1 + +# 10-m wind speed + uwind_1 = data1.select(name='10 metre U wind component')[0].values * 1.94384 + vwind_1 = data1.select(name='10 metre V wind component')[0].values * 1.94384 + uwind_2 = data2.select(name='10 metre U wind component')[0].values * 1.94384 + vwind_2 = data2.select(name='10 metre V wind component')[0].values * 1.94384 +# Rotate winds from grid relative to Earth relative + uwind_1, vwind_1 = rotate_wind(Lat0,Lon0,lon,uwind_1,vwind_1,'lcc',inverse=False) + uwind_2, vwind_2 = rotate_wind(Lat0,Lon0,lon2,uwind_2,vwind_2,'lcc',inverse=False) + wspd10m_1 = np.sqrt(uwind_1**2 + vwind_1**2) + wspd10m_2 = np.sqrt(uwind_2**2 + vwind_2**2) + wspd10m_diff = wspd10m_2 - wspd10m_1 + +# Surface-based CAPE + cape_1 = data1.select(name='Convective available potential energy',typeOfLevel='surface')[0].values + cape_2 = data2.select(name='Convective available potential energy',typeOfLevel='surface')[0].values + cape_diff = cape_2 - cape_1 + +# Surface-based CIN + cin_1 = data1.select(name='Convective inhibition',typeOfLevel='surface')[0].values + cin_2 = data2.select(name='Convective inhibition',typeOfLevel='surface')[0].values + cin_diff = cin_2 - cin_1 + +# 500 mb height, wind, vorticity + z500_1 = data1.select(name='Geopotential Height',level=500)[0].values * 0.1 + z500_1 = ndimage.filters.gaussian_filter(z500_1, 6.89) + z500_2 = data2.select(name='Geopotential Height',level=500)[0].values * 0.1 + z500_2 = ndimage.filters.gaussian_filter(z500_2, 6.89) + z500_diff = z500_2 - z500_1 + vort500_1 = data1.select(name='Absolute vorticity',level=500)[0].values * 100000 + vort500_1 = ndimage.filters.gaussian_filter(vort500_1,1.7225) + vort500_1[vort500_1 > 1000] = 0 # Mask out undefined values on domain edge + vort500_2 = data2.select(name='Absolute vorticity',level=500)[0].values * 100000 + vort500_2 = ndimage.filters.gaussian_filter(vort500_2,1.7225) + vort500_2[vort500_2 > 1000] = 0 # Mask out undefined values on domain edge + u500_1 = data1.select(name='U component of wind',level=500)[0].values * 1.94384 + u500_2 = data2.select(name='U component of wind',level=500)[0].values * 1.94384 + v500_1 = data1.select(name='V component of wind',level=500)[0].values * 1.94384 + v500_2 = data2.select(name='V component of wind',level=500)[0].values * 1.94384 +# Rotate winds from grid relative to Earth relative + u500_1, v500_1 = rotate_wind(Lat0,Lon0,lon,u500_1,v500_1,'lcc',inverse=False) + u500_2, v500_2 = rotate_wind(Lat0,Lon0,lon2,u500_2,v500_2,'lcc',inverse=False) + +# 250 mb winds + u250_1 = data1.select(name='U component of wind',level=250)[0].values * 1.94384 + u250_2 = data2.select(name='U component of wind',level=250)[0].values * 1.94384 + v250_1 = data1.select(name='V component of wind',level=250)[0].values * 1.94384 + v250_2 = data2.select(name='V component of wind',level=250)[0].values * 1.94384 +# Rotate winds from grid relative to Earth relative + u250_1, v250_1 = rotate_wind(Lat0,Lon0,lon,u250_1,v250_1,'lcc',inverse=False) + u250_2, v250_2 = rotate_wind(Lat0,Lon0,lon2,u250_2,v250_2,'lcc',inverse=False) + wspd250_1 = np.sqrt(u250_1**2 + v250_1**2) + wspd250_2 = np.sqrt(u250_2**2 + v250_2**2) + wspd250_diff = wspd250_2 - wspd250_1 + +# Total precipitation + qpf_1 = data1.select(name='Total Precipitation',lengthOfTimeRange=fhr)[0].values * 0.0393701 + qpf_2 = data2.select(name='Total Precipitation',lengthOfTimeRange=fhr)[0].values * 0.0393701 + qpf_diff = qpf_2 - qpf_1 + +# Composite reflectivity + refc_1 = data1.select(name='Maximum/Composite radar reflectivity')[0].values + refc_2 = data2.select(name='Maximum/Composite radar reflectivity')[0].values + + if (fhr > 0): +# Max/Min Hourly 2-5 km Updraft Helicity + maxuh25_1 = data1.select(stepType='max',parameterName="199",topLevel=5000,bottomLevel=2000)[0].values + maxuh25_2 = data2.select(stepType='max',parameterName="199",topLevel=5000,bottomLevel=2000)[0].values + minuh25_1 = data1.select(stepType='min',parameterName="200",topLevel=5000,bottomLevel=2000)[0].values + minuh25_2 = data2.select(stepType='min',parameterName="200",topLevel=5000,bottomLevel=2000)[0].values + maxuh25_1[maxuh25_1 < 10] = 0 + maxuh25_2[maxuh25_2 < 10] = 0 + minuh25_1[minuh25_1 > -10] = 0 + minuh25_2[minuh25_2 > -10] = 0 + uh25_1 = maxuh25_1 + minuh25_1 + uh25_2 = maxuh25_2 + minuh25_2 + uh25_diff = uh25_2 - uh25_1 + + + t2a = time.perf_counter() + t3a = round(t2a-t1a, 3) + print(("%.3f seconds to read all messages") % t3a) + + +######################################## +# START PLOTTING FOR EACH DOMAIN # +######################################## + + def main(): + + # Number of processes must coincide with the number of domains to plot + #pool = multiprocessing.Pool(len(domains)) + #pool.map(plot_all,domains) + + # To avoid import multiprocessing recursively on MacOS/Windows etc. + # Anyway since we only have one domain for SRW application + for dom in domains: + plot_all(dom) + + def plot_all(dom): + + t1dom = time.perf_counter() + + # Map corners for each domain + if dom == 'conus': + llcrnrlon = -120.5 + llcrnrlat = 21.0 + urcrnrlon = -64.5 + urcrnrlat = 49.0 + lat_0 = 35.4 + lon_0 = -97.6 + extent=[llcrnrlon-3,urcrnrlon-6,llcrnrlat-1,urcrnrlat+2] + elif dom == 'regional': + llcrnrlon = np.min(lon) + llcrnrlat = np.min(lat) + urcrnrlon = np.max(lon) + urcrnrlat = np.max(lat) + lat_0 = Lat0 + lon_0 = Lon0 + extent=[llcrnrlon,urcrnrlon,llcrnrlat-1,urcrnrlat] + + + # create figure and axes instances + fig = plt.figure(figsize=(10,10)) + gs = GridSpec(9,9,wspace=0.0,hspace=0.0) + + # Define where Cartopy Maps are located + cartopy.config['data_dir'] = CARTOPY_DIR + + back_res='50m' + back_img='on' + + # set up the map background with cartopy + myproj=ccrs.LambertConformal(central_longitude=lon_0, central_latitude=lat_0, false_easting=0.0, + false_northing=0.0, secant_latitudes=None, standard_parallels=None, + globe=None) + ax1 = fig.add_subplot(gs[0:4,0:4], projection=myproj) + ax2 = fig.add_subplot(gs[0:4,5:], projection=myproj) + ax3 = fig.add_subplot(gs[5:,1:8], projection=myproj) + ax1.set_extent(extent) + ax2.set_extent(extent) + ax3.set_extent(extent) + + fline_wd = 0.5 # line width + falpha = 0.3 # transparency + + # natural_earth +# land=cfeature.NaturalEarthFeature('physical','land',back_res, +# edgecolor='face',facecolor=cfeature.COLORS['land'], +# alpha=falpha) + lakes=cfeature.NaturalEarthFeature('physical','lakes',back_res, + edgecolor='blue',facecolor='none', + linewidth=fline_wd,alpha=falpha) + coastline=cfeature.NaturalEarthFeature('physical','coastline', + back_res,edgecolor='blue',facecolor='none', + linewidth=fline_wd,alpha=falpha) + states=cfeature.NaturalEarthFeature('cultural','admin_1_states_provinces', + back_res,edgecolor='black',facecolor='none', + linewidth=fline_wd,linestyle=':',alpha=falpha) + borders=cfeature.NaturalEarthFeature('cultural','admin_0_countries', + back_res,edgecolor='red',facecolor='none', + linewidth=fline_wd,alpha=falpha) + + # All lat lons are earth relative, so setup the associated projection correct for that data + transform = ccrs.PlateCarree() + + # high-resolution background images + if back_img=='on': + img = plt.imread(CARTOPY_DIR+'/raster_files/NE1_50M_SR_W.tif') + ax1.imshow(img, origin='upper', transform=transform) + ax2.imshow(img, origin='upper', transform=transform) + ax3.imshow(img, origin='upper', transform=transform) + +# ax.add_feature(land) + ax1.add_feature(lakes) + ax1.add_feature(states) + ax1.add_feature(borders) + ax1.add_feature(coastline) + ax2.add_feature(lakes) + ax2.add_feature(states) + ax2.add_feature(borders) + ax2.add_feature(coastline) + ax3.add_feature(lakes) + ax3.add_feature(states) + ax3.add_feature(borders) + ax3.add_feature(coastline) + +# Map/figure has been set up here, save axes instances for use again later + keep_ax_lst_1 = ax1.get_children()[:] + keep_ax_lst_2 = ax2.get_children()[:] + keep_ax_lst_3 = ax3.get_children()[:] + +# colors for difference plots, only need to define once + diffcolors = ['blue','#1874CD','dodgerblue','deepskyblue','turquoise','white','white','#EEEE00','#EEC900','darkorange','orangered','red'] + + +################################ + # Plot SLP +################################ + t1 = time.perf_counter() + print(('Working on slp for '+dom)) + + units = 'mb' + clevs = [976,980,984,988,992,996,1000,1004,1008,1012,1016,1020,1024,1028,1032,1036,1040,1044,1048,1052] + clevsdiff = [-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12] + cm = plt.cm.Spectral_r + cmdiff = matplotlib.colors.ListedColormap(diffcolors) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs1_a = ax1.pcolormesh(lon_shift,lat_shift,slp_1,transform=transform,cmap=cm,norm=norm) + cbar1 = plt.colorbar(cs1_a,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=5) + cs1_b = ax1.contour(lon_shift,lat_shift,slpsmooth_1,np.arange(940,1060,4),colors='black',linewidths=1.25,transform=transform) + plt.clabel(cs1_b,np.arange(940,1060,4),inline=1,fmt='%d',fontsize=6) + ax1.text(.5,1.03,'FV3-LAM SLP ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs2_a = ax2.pcolormesh(lon2_shift,lat2_shift,slp_2,transform=transform,cmap=cm,norm=norm) + cbar2 = plt.colorbar(cs2_a,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=5) + cs2_b = ax2.contour(lon2_shift,lat2_shift,slpsmooth_2,np.arange(940,1060,4),colors='black',linewidths=1.25,transform=transform) + plt.clabel(cs2_b,np.arange(940,1060,4),inline=1,fmt='%d',fontsize=6) + ax2.text(.5,1.03,'FV3-LAM-2 SLP ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,slp_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=5) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM SLP ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/slp_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot slp for: '+dom) % t3) + + +################################# + # Plot 2-m T +################################# + t1 = time.perf_counter() + print(('Working on t2m for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = '\xb0''F' + clevs = np.linspace(-16,134,51) + clevsdiff = [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] +# cm = plt.cm.Spectral_r + cm = cmap_t2m() + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,tmp2m_1,transform=transform,cmap=cm,norm=norm) + cs_1.cmap.set_under('white') + cs_1.cmap.set_over('white') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=[-16,-4,8,20,32,44,56,68,80,92,104,116,128],extend='both') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=5) + ax1.text(.5,1.03,'FV3-LAM 2-m Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,tmp2m_2,transform=transform,cmap=cm,norm=norm) + cs_2.cmap.set_under('white') + cs_2.cmap.set_over('white') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,ticks=[-16,-4,8,20,32,44,56,68,80,92,104,116,128],extend='both') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=5) + ax2.text(.5,1.03,'FV3-LAM-2 2-m Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,tmp2m_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM 2-m Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/2mt_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 2mt for: '+dom) % t3) + + +################################# + # Plot 2-m Dew Point +################################# + t1 = time.perf_counter() + print(('Working on 2mdew for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = '\xb0''F' + clevs = np.linspace(-5,80,35) + clevsdiff = [-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12] + cm = cmap_q2m() + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,dew2m_1,transform=transform,cmap=cm,norm=norm) + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=6) + ax1.text(.5,1.03,'FV3-LAM 2-m Dew Point Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,dew2m_2,transform=transform,cmap=cm,norm=norm) + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=6) + ax2.text(.5,1.03,'FV3-LAM-2 2-m Dew Point Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,dew2m_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM 2-m Dew Point Temperature ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/2mdew_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 2mdew for: '+dom) % t3) + + +################################# + # Plot 10-m WSPD +################################# + t1 = time.perf_counter() + print(('Working on 10mwspd for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'kts' + # Places a wind barb every ~180 km, optimized for CONUS domain + skip = round(177.28*(dx/1000.)**-.97) + print('skipping every '+str(skip)+' grid points to plot') + barblength = 4 + + clevs = [5,10,15,20,25,30,35,40,45,50,55,60] + clevsdiff = [-12,-10,-8,-6,-4,-2,0,2,4,6,8,10,12] + colorlist = ['turquoise','dodgerblue','blue','#FFF68F','#E3CF57','peru','brown','crimson','red','fuchsia','DarkViolet'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,wspd10m_1,transform=transform,cmap=cm,vmin=5,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=6) + ax1.barbs(lon_shift[::skip,::skip],lat_shift[::skip,::skip],uwind_1[::skip,::skip],vwind_1[::skip,::skip],length=barblength,linewidth=0.5,color='black',transform=transform) + ax1.text(.5,1.03,'FV3-LAM 10-m Winds ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,wspd10m_2,transform=transform,cmap=cm,vmin=5,norm=norm) + cs_2.cmap.set_under('white',alpha=0.) + cs_2.cmap.set_over('black') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=6) + ax2.barbs(lon2_shift[::skip,::skip],lat2_shift[::skip,::skip],uwind_2[::skip,::skip],vwind_2[::skip,::skip],length=barblength,linewidth=0.5,color='black',transform=transform) + ax2.text(.5,1.03,'FV3-LAM-2 10-m Winds ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,wspd10m_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM 10-m Winds ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/10mwind_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 10mwspd for: '+dom) % t3) + + +################################# + # Plot Surface-Based CAPE/CIN +################################# + t1 = time.perf_counter() + print(('Working on surface-based CAPE/CIN for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'J/kg' + clevs = [100,250,500,1000,1500,2000,2500,3000,3500,4000,4500,5000] + clevs2 = [-2000,-500,-250,-100,-25] + clevsdiff = [-2000,-1500,-1000,-500,-250,-100,0,100,250,500,1000,1500,2000] + colorlist = ['blue','dodgerblue','cyan','mediumspringgreen','#FAFAD2','#EEEE00','#EEC900','darkorange','crimson','darkred','darkviolet'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,cape_1,transform=transform,cmap=cm,vmin=100,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=4) + cs_1b = ax1.contourf(lon_shift,lat_shift,cin_1,clevs2,colors='none',hatches=['**','++','////','..'],transform=transform) + ax1.text(.5,1.05,'FV3-LAM Surface-Based CAPE (shaded) and CIN (hatched) ('+units+') \n <-500 (*), -500<-250 (+), -250<-100 (/), -100<-25 (.) \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,cape_2,transform=transform,cmap=cm,vmin=100,norm=norm) + cs_2.cmap.set_under('white',alpha=0.) + cs_2.cmap.set_over('black') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=4) + cs_2b = ax2.contourf(lon2_shift,lat2_shift,cin_2,clevs2,colors='none',hatches=['**','++','////','..'],transform=transform) + ax2.text(.5,1.05,'FV3-LAM-2 Surface-Based CAPE (shaded) and CIN (hatched) ('+units+') \n <-500 (*), -500<-250 (+), -250<-100 (/), -100<-25 (.) \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,cape_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM Surface-Based CAPE ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/sfcape_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot surface-based CAPE/CIN for: '+dom) % t3) + + +################################# + # Plot 500 mb HGT/WIND/VORT +################################# + t1 = time.perf_counter() + print(('Working on 500 mb Hgt/Wind/Vort for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'x10${^5}$ s${^{-1}}$' + skip = round(177.28*(dx/1000.)**-.97) + print('skipping every '+str(skip)+' grid points to plot') + barblength = 4 + + vortlevs = [16,20,24,28,32,36,40] + clevsdiff = [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6] + colorlist = ['yellow','gold','goldenrod','orange','orangered','red'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(vortlevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs1_a = ax1.pcolormesh(lon_shift,lat_shift,vort500_1,transform=transform,cmap=cm,norm=norm) + cs1_a.cmap.set_under('white') + cs1_a.cmap.set_over('darkred') + cbar1 = plt.colorbar(cs1_a,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=vortlevs,extend='both') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=6) + ax1.barbs(lon_shift[::skip,::skip],lat_shift[::skip,::skip],u500_1[::skip,::skip],v500_1[::skip,::skip],length=barblength,linewidth=0.5,color='steelblue',transform=transform) + cs1_b = ax1.contour(lon_shift,lat_shift,z500_1,np.arange(486,600,6),colors='black',linewidths=1,transform=transform) + plt.clabel(cs1_b,np.arange(486,600,6),inline_spacing=1,fmt='%d',fontsize=8) + ax1.text(.5,1.03,'FV3-LAM 500 mb Heights (dam), Winds (kts), and $\zeta$ ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs2_a = ax2.pcolormesh(lon2_shift,lat2_shift,vort500_2,transform=transform,cmap=cm,norm=norm) + cs2_a.cmap.set_under('white') + cs2_a.cmap.set_over('darkred') + cbar2 = plt.colorbar(cs2_a,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,ticks=vortlevs,extend='both') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=6) + ax2.barbs(lon2_shift[::skip,::skip],lat2_shift[::skip,::skip],u500_2[::skip,::skip],v500_2[::skip,::skip],length=barblength,linewidth=0.5,color='steelblue',transform=transform) + cs2_b = ax2.contour(lon2_shift,lat2_shift,z500_2,np.arange(486,600,6),colors='black',linewidths=1,transform=transform) + plt.clabel(cs2_b,np.arange(486,600,6),inline_spacing=1,fmt='%d',fontsize=8) + ax2.text(.5,1.03,'FV3-LAM-2 500 mb Heights (dam), Winds (kts), and $\zeta$ ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=8,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,z500_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM 500-mb Heights (dam) \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/500_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 500 mb Hgt/Wind/Vort for: '+dom) % t3) + + +################################# + # Plot 250 mb WIND +################################# + t1 = time.perf_counter() + print(('Working on 250 mb WIND for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'kts' + skip = round(177.28*(dx/1000.)**-.97) + print('skipping every '+str(skip)+' grid points to plot') + barblength = 4 + + clevs = [50,60,70,80,90,100,110,120,130,140,150] + clevsdiff = [-30,-25,-20,-15,-10,-5,0,5,10,15,20,25,30] + colorlist = ['turquoise','deepskyblue','dodgerblue','#1874CD','blue','beige','khaki','peru','brown','crimson'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,wspd250_1,transform=transform,cmap=cm,vmin=50,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('red') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=6) + ax1.barbs(lon_shift[::skip,::skip],lat_shift[::skip,::skip],u250_1[::skip,::skip],v250_1[::skip,::skip],length=barblength,linewidth=0.5,color='black',transform=transform) + ax1.text(.5,1.03,'FV3-LAM 250 mb Winds ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,wspd250_2,transform=transform,cmap=cm,vmin=50,norm=norm) + cs_2.cmap.set_under('white',alpha=0.) + cs_2.cmap.set_over('red') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=6) + ax2.barbs(lon2_shift[::skip,::skip],lat2_shift[::skip,::skip],u250_2[::skip,::skip],v250_2[::skip,::skip],length=barblength,linewidth=0.5,color='black',transform=transform) + ax2.text(.5,1.03,'FV3-LAM-2 250 mb Winds ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,wspd250_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM 250-mb Winds ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/250wind_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot 250 mb WIND for: '+dom) % t3) + + +################################# + # Plot Total QPF +################################# + if (fhr > 0): # Do not make total QPF plot for forecast hour 0 + t1 = time.perf_counter() + print(('Working on total qpf for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'in' + clevs = [0.01,0.1,0.25,0.5,0.75,1,1.25,1.5,1.75,2,2.5,3,4,5,7,10,15,20] + clevsdiff = [-3,-2.5,-2,-1.5,-1,-0.5,0,0.5,1,1.5,2,2.5,3] + colorlist = ['chartreuse','limegreen','green','blue','dodgerblue','deepskyblue','cyan','mediumpurple','mediumorchid','darkmagenta','darkred','crimson','orangered','darkorange','goldenrod','gold','yellow'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,qpf_1,transform=transform,cmap=cm,vmin=0.01,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('pink') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,extend='max') + cbar1.set_label(units,fontsize=6) + cbar1.ax.set_xticklabels([0.1,0.5,1,1.5,2,3,5,10,20]) + cbar1.ax.tick_params(labelsize=6) + ax1.text(.5,1.03,'FV3-LAM '+fhour+'-hr Accumulated Precipitation ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,qpf_2,transform=transform,cmap=cm,vmin=0.01,norm=norm) + cs_2.cmap.set_under('white',alpha=0.) + cs_2.cmap.set_over('pink') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,extend='max') + cbar2.set_label(units,fontsize=6) + cbar2.ax.set_xticklabels([0.1,0.5,1,1.5,2,3,5,10,20]) + cbar2.ax.tick_params(labelsize=6) + ax2.text(.5,1.03,'FV3-LAM-2 '+fhour+'-hr Accumulated Precipitation ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,qpf_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM '+fhour+'-hr Accumulated Precipitation ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/qpf_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot total qpf for: '+dom) % t3) + + +################################# + # Plot Max/Min Hourly 2-5 km UH +################################# +# Do not make max/min hourly 2-5 km UH plot for forecast hour 0 + t1 = time.perf_counter() + print(('Working on Max/Min Hourly 2-5 km UH for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'm${^2}$ s$^{-2}$' + clevs = [-150,-100,-75,-50,-25,-10,0,10,25,50,75,100,150,200,250,300] +# alternative colormap for just max UH if you don't want to plot the min UH too +# colorlist = ['white','skyblue','mediumblue','green','orchid','firebrick','#EEC900','DarkViolet'] + colorlist = ['blue','#1874CD','dodgerblue','deepskyblue','turquoise','#E5E5E5','#E5E5E5','#EEEE00','#EEC900','darkorange','orangered','red','firebrick','mediumvioletred','darkviolet'] + cm = matplotlib.colors.ListedColormap(colorlist) + cmdiff = matplotlib.colors.ListedColormap(diffcolors) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + normdiff = matplotlib.colors.BoundaryNorm(clevsdiff, cmdiff.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,uh25_1,transform=transform,cmap=cm,norm=norm) + cs_1.cmap.set_under('darkblue') + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=6) + ax1.text(.5,1.03,'FV3-LAM 1-h Max/Min 2-5 km Updraft Helicity ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,uh25_2,transform=transform,cmap=cm,norm=norm) + cs_2.cmap.set_under('darkblue') + cs_2.cmap.set_over('black') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=6) + ax2.text(.5,1.03,'FV3-LAM-2 1-h Max/Min 2-5 km Updraft Helicity ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs = ax3.pcolormesh(lon2_shift,lat2_shift,uh25_diff,transform=transform,cmap=cmdiff,norm=normdiff) + cs.cmap.set_under('darkblue') + cs.cmap.set_over('darkred') + cbar3 = plt.colorbar(cs,ax=ax3,orientation='horizontal',pad=0.05,shrink=0.6,extend='both') + cbar3.set_label(units,fontsize=6) + cbar3.ax.tick_params(labelsize=6) + ax3.text(.5,1.03,'FV3-LAM-2 - FV3-LAM 1-h Max/Min 2-5 km Updraft Helicity ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/uh25_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot Max/Min Hourly 2-5 km UH for: '+dom) % t3) + + +################################# + # Plot composite reflectivity +################################# + t1 = time.perf_counter() + print(('Working on composite reflectivity for '+dom)) + + # Clear off old plottables but keep all the map info + cbar1.remove() + cbar2.remove() + cbar3.remove() + clear_plotables(ax1,keep_ax_lst_1,fig) + clear_plotables(ax2,keep_ax_lst_2,fig) + clear_plotables(ax3,keep_ax_lst_3,fig) + + units = 'dBZ' + clevs = np.linspace(5,70,14) + clevsdiff = [20,1000] + colorlist = ['turquoise','dodgerblue','mediumblue','lime','limegreen','green','#EEEE00','#EEC900','darkorange','red','firebrick','darkred','fuchsia'] + cm = matplotlib.colors.ListedColormap(colorlist) + norm = matplotlib.colors.BoundaryNorm(clevs, cm.N) + + cs_1 = ax1.pcolormesh(lon_shift,lat_shift,refc_1,transform=transform,cmap=cm,vmin=5,norm=norm) + cs_1.cmap.set_under('white',alpha=0.) + cs_1.cmap.set_over('black') + cbar1 = plt.colorbar(cs_1,ax=ax1,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar1.set_label(units,fontsize=6) + cbar1.ax.tick_params(labelsize=6) + ax1.text(.5,1.03,'FV3-LAM Composite Reflectivity ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax1.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + cs_2 = ax2.pcolormesh(lon2_shift,lat2_shift,refc_2,transform=transform,cmap=cm,vmin=5,norm=norm) + cs_2.cmap.set_under('white',alpha=0.) + cs_2.cmap.set_over('black') + cbar2 = plt.colorbar(cs_2,ax=ax2,orientation='horizontal',pad=0.05,shrink=0.6,ticks=clevs,extend='max') + cbar2.set_label(units,fontsize=6) + cbar2.ax.tick_params(labelsize=6) + ax2.text(.5,1.03,'FV3-LAM-2 Composite Reflectivity ('+units+') \n initialized: '+itime+' valid: '+vtime + ' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax2.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + csdiff = ax3.contourf(lon_shift,lat_shift,refc_1,clevsdiff,colors='red',transform=transform) + csdiff2 = ax3.contourf(lon2_shift,lat2_shift,refc_2,clevsdiff,colors='dodgerblue',transform=transform) + ax3.text(.5,1.03,'FV3-LAM (red) and FV3-LAM-2 (blue) Composite Reflectivity > 20 ('+units+') \n initialized: '+itime+' valid: '+vtime+' (f'+fhour+')',horizontalalignment='center',fontsize=6,transform=ax3.transAxes,bbox=dict(facecolor='white',alpha=0.85,boxstyle='square,pad=0.2')) + + compress_and_save(EXPT_DIR_1+'/'+ymdh+'/postprd/refc_diff_'+dom+'_f'+fhour+'.png') + t2 = time.perf_counter() + t3 = round(t2-t1, 3) + print(('%.3f seconds to plot composite reflectivity for: '+dom) % t3) + + +###################################################### + + t3dom = round(t2-t1dom, 3) + print(("%.3f seconds to plot all variables for: "+dom) % t3dom) + plt.clf() + +###################################################### + + main() + diff --git a/ush/Python/qsub_job.sh b/ush/Python/qsub_job.sh new file mode 100755 index 0000000000..df3ff20be3 --- /dev/null +++ b/ush/Python/qsub_job.sh @@ -0,0 +1,57 @@ +#!/bin/sh +#PBS -A an_account +#PBS -q regular +#PBS -l select=1:mpiprocs=24:ncpus=24 +#PBS -l walltime=00:20:00 +#PBS -N plot_allvars +#PBS -j oe -o plot_allvars.out + +# Prior to submitting the script the following environment variables +# must be set using export or setenv +# HOMErrfs=/path-to/ufs-srweather-app/regional_workflow +# EXPTDIR=/path-to/expt_dirs/your_experiment + +cd ${HOMErrfs}/ush/Python +set -x + +source /etc/profile.d/modules.sh + +############ +# Python environment for Cheyenne +############ +module load ncarenv +module load conda/latest +conda activate /glade/p/ral/jntp/UFS_SRW_app/conda/python_graphics + +############ +# Path to shape files +############ +#Cheyenne: +SHAPE_FILES=/glade/p/ral/jntp/UFS_SRW_app/tools/NaturalEarth + +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export FCST_START=3 +export FCST_END=${FCST_LEN_HRS} +export FCST_INC=3 + +# Usage statement: Make sure all the necessary modules can be imported. +# The following command line arguments are needed: +# 1. Cycle date/time in YYYYMMDDHH format +# 2. Starting forecast hour in HHH format +# 3. Ending forecast hour in HHH format +# 4. Forecast hour increment +# 5. EXPT_DIR: Experiment directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR/YYYYMMDDHH/postprd/ +# 6. CARTOPY_DIR: Base directory of cartopy shapefiles +# -File structure should be: +# CARTOPY_DIR/shapefiles/natural_earth/cultural/*.shp +# 7. POST_OUTPUT_DOMAIN_NAME: Name of native domain +# used in forecast and in constructing the names +# of the post output files. + + +python plot_allvars.py ${CDATE} ${FCST_START} ${FCST_END} ${FCST_INC} \ + ${EXPTDIR} ${SHAPE_FILES} ${POST_OUTPUT_DOMAIN_NAME} diff --git a/ush/Python/qsub_job_diff.sh b/ush/Python/qsub_job_diff.sh new file mode 100755 index 0000000000..d2b1425c6a --- /dev/null +++ b/ush/Python/qsub_job_diff.sh @@ -0,0 +1,63 @@ +#!/bin/sh +#PBS -A an_account +#PBS -q regular +#PBS -l select=1:mpiprocs=24:ncpus=24 +#PBS -l walltime=00:30:00 +#PBS -N plot_allvars_diff +#PBS -j oe -o plot_allvars_diff.out + +# Prior to submitting the script the following environment variables +# must be set using export or setenv +# HOMErrfs=/path-to/ufs-srweather-app/regional_workflow +# EXPTDIR1=/path-to/expt_dirs/your_experiment1 +# EXPTDIR2=/path-to/expt_dirs/your_experiment2 + +cd ${HOMErrfs}/ush/Python +set -x + +source /etc/profile.d/modules.sh + +############ +# Python environment for Cheyenne +############ +module load ncarenv +module load conda/latest +conda activate /glade/p/ral/jntp/UFS_SRW_app/conda/python_graphics + +############ +# Path to shape files +############ +#Cheyenne: +SHAPE_FILES=/glade/p/ral/jntp/UFS_SRW_app/tools/NaturalEarth + +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR1}/var_defns.sh" +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export FCST_START=3 +export FCST_END=${FCST_LEN_HRS} +export FCST_INC=3 + +# Usage statement: Make sure all the necessary modules can be imported. +# The following command line arguments are needed: +# 1. Cycle date/time in YYYYMMDDHH format +# 2. Starting forecast hour in HHH format +# 3. Ending forecast hour in HHH format +# 4. Forecast hour increment +# 5. EXPT_DIR_1: Experiment 1 directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR_1/YYYYMMDDHH/postprd/ +# 6. EXPT_DIR_2: Experiment 2 directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR_2/YYYYMMDDHH/postprd/ +# 7. CARTOPY_DIR: Base directory of cartopy shapefiles +# -File structure should be: +# CARTOPY_DIR/shapefiles/natural_earth/cultural/*.shp +# 8. POST_OUTPUT_DOMAIN_NAME: Name of native domain +# used in forecasts and in constructing the names +# of the post output files. This must be the same +# for both forecasts. + +python plot_allvars_diff.py ${CDATE} ${FCST_START} ${FCST_END} ${FCST_INC} \ + ${EXPTDIR1} ${EXPTDIR2} \ + ${SHAPE_FILES} \ + ${POST_OUTPUT_DOMAIN_NAME} diff --git a/ush/Python/sq_job.sh b/ush/Python/sq_job.sh new file mode 100755 index 0000000000..d4a5947462 --- /dev/null +++ b/ush/Python/sq_job.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +#SBATCH --account=an_account +#SBATCH --qos=batch +#SBATCH --ntasks=4 +#SBATCH --time=0:20:00 +#SBATCH --job-name="plot_allvars" +#SBATCH --out=plot_allvars.out + +# Prior to submitting the script the following environment variables +# must be set using export or setenv +# HOMErrfs=/path-to/ufs-srweather-app/regional_workflow +# EXPTDIR=/path-to/expt_dirs/your_experiment + +cd ${HOMErrfs}/ush/Python +set -x +. /apps/lmod/lmod/init/sh + +module purge +module load hpss + +############ +# Python environment for Jet and Hera +module use -a /contrib/miniconda3/modulefiles +module load miniconda3 +conda activate pygraf + +############ +# Python environment for Orion +############ +#module use -a /apps/contrib/miniconda3-noaa-gsl/modulefiles +#module load miniconda3 +#conda activate pygraf + +############ +# Python environment for Gaea +############ +#module use /lustre/f2/pdata/esrl/gsd/contrib/modulefiles +#module load miniconda3/4.8.3-regional-workflow + +############ +# Path to shape files +############ +#Hera: +SHAPE_FILES=/scratch2/BMC/det/UFS_SRW_app/v1p0/fix_files/NaturalEarth +#Jet: +#SHAPE_FILES=/lfs4/BMC/wrfruc/FV3-LAM/NaturalEarth +#Orion: +#SHAPE_FILES=/work/noaa/gsd-fv3-dev/UFS_SRW_App/v1p0/fix_files/NaturalEarth +#Gaea: +#SHAPE_FILES=/lustre/f2/pdata/esrl/gsd/ufs/NaturalEarth + +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export FCST_START=6 +export FCST_END=${FCST_LEN_HRS} +export FCST_INC=6 + +# Usage statement: Make sure all the necessary modules can be imported. +# The following command line arguments are needed: +# 1. Cycle date/time in YYYYMMDDHH format +# 2. Starting forecast hour in HHH format +# 3. Ending forecast hour in HHH format +# 4. Forecast hour increment +# 5. EXPT_DIR: Experiment directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR/YYYYMMDDHH/postprd/ +# 6. CARTOPY_DIR: Base directory of cartopy shapefiles +# -File structure should be: +# CARTOPY_DIR/shapefiles/natural_earth/cultural/*.shp +# 7. POST_OUTPUT_DOMAIN_NAME: Name of native domain +# used in forecast and in constructing the names +# of the post output files. + + +python plot_allvars.py ${CDATE} ${FCST_START} ${FCST_END} ${FCST_INC} \ + ${EXPTDIR} ${SHAPE_FILES} ${POST_OUTPUT_DOMAIN_NAME} diff --git a/ush/Python/sq_job_diff.sh b/ush/Python/sq_job_diff.sh new file mode 100755 index 0000000000..e7be0595f5 --- /dev/null +++ b/ush/Python/sq_job_diff.sh @@ -0,0 +1,85 @@ +#!/bin/sh + +#SBATCH --account=an_account +#SBATCH --qos=batch +#SBATCH --ntasks=8 +#SBATCH --time=0:30:00 +#SBATCH --job-name="plot_allvars_diff" +#SBATCH --out=plot_allvars.out + +# Prior to submitting the script the following environment variables +# must be set using export or setenv +# HOMErrfs=/path-to/ufs-srweather-app/regional_workflow +# EXPTDIR1=/path-to/expt_dirs/your_experiment1 +# EXPTDIR2=/path-to/expt_dirs/your_experiment2 + +cd ${HOMErrfs}/ush/Python +set -x +. /apps/lmod/lmod/init/sh + +module purge +module load hpss + +############ +# Python environment for Jet and Hera +############ +module use -a /contrib/miniconda3/modulefiles +module load miniconda3 +conda activate pygraf + +############ +# Python environment for Orion +############ +#module use -a /apps/contrib/miniconda3-noaa-gsl/modulefiles +#module load miniconda3 +#conda activate pygraf + +############ +# Python environment for Gaea +############ +#module use /lustre/f2/pdata/esrl/gsd/contrib/modulefiles +#module load miniconda3/4.8.3-regional-workflow + +############ +# Path to shape files +############ +#Hera: +SHAPE_FILES=/scratch2/BMC/det/UFS_SRW_app/v1p0/fix_files/NaturalEarth +#Jet: +#SHAPE_FILES=/lfs4/BMC/wrfruc/FV3-LAM/NaturalEarth +#Orion: +#SHAPE_FILES=/work/noaa/gsd-fv3-dev/UFS_SRW_App/v1p0/fix_files/NaturalEarth +#Gaea: +#SHAPE_FILES=/lustre/f2/pdata/esrl/gsd/ufs/NaturalEarth + +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR1}/var_defns.sh" +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export FCST_START=6 +export FCST_END=${FCST_LEN_HRS} +export FCST_INC=3 + +# Usage statement: Make sure all the necessary modules can be imported. +# The following command line arguments are needed: +# 1. Cycle date/time in YYYYMMDDHH format +# 2. Starting forecast hour +# 3. Ending forecast hour +# 4. Forecast hour increment +# 5. EXPT_DIR_1: Experiment 1 directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR_1/YYYYMMDDHH/postprd/ +# 6. EXPT_DIR_2: Experiment 2 directory +# -Postprocessed data should be found in the directory: +# EXPT_DIR_2/YYYYMMDDHH/postprd/ +# 7. CARTOPY_DIR: Base directory of cartopy shapefiles +# -File structure should be: +# CARTOPY_DIR/shapefiles/natural_earth/cultural/*.shp +# 8. POST_OUTPUT_DOMAIN_NAME: Name of native domain +# used in forecasts and in constructing the names +# of the post output files. This must be the same +# for both forecasts. + +python plot_allvars_diff.py ${CDATE} ${FCST_START} ${FCST_END} ${FCST_INC} \ + ${EXPTDIR1} ${EXPTDIR2} \ + ${SHAPE_FILES} \ + ${POST_OUTPUT_DOMAIN_NAME} diff --git a/ush/UFS_plot_domains.py b/ush/UFS_plot_domains.py new file mode 100755 index 0000000000..a6e629bd15 --- /dev/null +++ b/ush/UFS_plot_domains.py @@ -0,0 +1,175 @@ +#!/usr/bin/env python + +import matplotlib.pyplot as plt +from mpl_toolkits.basemap import Basemap +from matplotlib.path import Path +import matplotlib.patches as patches +import numpy as np + +#### User-defined variables + + +# Computational grid definitions +ESGgrid_LON_CTR=-153.0 +ESGgrid_LAT_CTR=61.0 +ESGgrid_DELX=3000.0 +ESGgrid_DELY=3000.0 +ESGgrid_NX=1344 +ESGgrid_NY=1152 + +# Write component grid definitions + +WRTCMP_nx=1340 +WRTCMP_ny=1132 +WRTCMP_lon_lwr_left=151.5 +WRTCMP_lat_lwr_left=42.360 +WRTCMP_dx=ESGgrid_DELX +WRTCMP_dy=ESGgrid_DELY + +# Plot-specific definitions + +plot_res='i' # background map resolution + +#Note: Resolution can be 'c' (crude), 'l' (low), 'i' (intermediate), 'h' (high), or 'f' (full) +# To plot maps with higher resolution than low, +# you will need to download and install the basemap-data-hires package + + +#### END User-defined variables + + + +ESGgrid_width = ESGgrid_NX * ESGgrid_DELX +ESGgrid_height = ESGgrid_NY * ESGgrid_DELY + +big_grid_width=np.ceil(ESGgrid_width*1.25) +big_grid_height=np.ceil(ESGgrid_height*1.25) + +WRTCMP_width = WRTCMP_nx * WRTCMP_dx +WRTCMP_height = WRTCMP_ny * WRTCMP_dy + +fig = plt.figure() + +#ax1 = plt.axes +ax1 = plt.subplot2grid((1,1), (0,0)) + +map1 = Basemap(projection='gnom', resolution=plot_res, lon_0 = ESGgrid_LON_CTR, lat_0 = ESGgrid_LAT_CTR, + width = big_grid_width, height=big_grid_height) + +map1.drawmapboundary(fill_color='#9999FF') +map1.fillcontinents(color='#ddaa66',lake_color='#9999FF') +map1.drawcoastlines() + +map2 = Basemap(projection='gnom', lon_0 = ESGgrid_LON_CTR, lat_0 = ESGgrid_LAT_CTR, + width = ESGgrid_width, height=ESGgrid_height) + +#map2.drawmapboundary(fill_color='#9999FF') +#map2.fillcontinents(color='#ddaa66',lake_color='#9999FF') +#map2.drawcoastlines() + + +map3 = Basemap(llcrnrlon= WRTCMP_lon_lwr_left, llcrnrlat=WRTCMP_lat_lwr_left, width=WRTCMP_width, height=WRTCMP_height, + resolution=plot_res, projection='lcc', lat_0 = ESGgrid_LAT_CTR, lon_0 = ESGgrid_LON_CTR) + +#map3.drawmapboundary(fill_color='#9999FF') +#map3.fillcontinents(color='#ddaa66',lake_color='#9999FF',alpha=0.5) +#map3.drawcoastlines() + + +#Draw gnomonic compute grid rectangle: + +lbx1, lby1 = map1(*map2(map2.xmin, map2.ymin, inverse= True)) +ltx1, lty1 = map1(*map2(map2.xmin, map2.ymax, inverse= True)) +rtx1, rty1 = map1(*map2(map2.xmax, map2.ymax, inverse= True)) +rbx1, rby1 = map1(*map2(map2.xmax, map2.ymin, inverse= True)) + +verts1 = [ + (lbx1, lby1), # left, bottom + (ltx1, lty1), # left, top + (rtx1, rty1), # right, top + (rbx1, rby1), # right, bottom + (lbx1, lby1), # ignored + ] + +codes2 = [Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY, + ] + +path = Path(verts1, codes2) +patch = patches.PathPatch(path, facecolor='r', lw=2,alpha=0.5) +ax1.add_patch(patch) + + +#Draw lambert write grid rectangle: + +# Define a function to get the lambert points in the gnomonic space + +def get_lambert_points(gnomonic_map, lambert_map,pps): + print("Hello from a function") + + # This function takes the lambert domain we have defined, lambert_map, as well as + # pps (the number of points to interpolate and draw for each side of the lambert "rectangle"), + # and returns an array of two lists: one a list of tuples of the 4*ppf + 4 vertices mapping the approximate shape + # of the lambert domain on the gnomonic map, the other a list of "draw" instructions to be used by + # the PathPatch function + + # pps is recommended 10 or less due to time of calculation + + # Start array with bottom left point, "MOVETO" instruction + vertices = [gnomonic_map(*lambert_map(lambert_map.xmin, lambert_map.ymin, inverse= True))] + instructions = [Path.MOVETO] + + # Next generate the rest of the left side + lefty = np.linspace(lambert_map.ymin, lambert_map.ymax, num=pps+1, endpoint=False) + + for y in lefty[1:]: + vertices.append(tuple(gnomonic_map(*lambert_map(lambert_map.xmin, y, inverse= True)))) + instructions.append(Path.LINETO) + + # Next generate the top of the domain + topx = np.linspace(lambert_map.xmin, lambert_map.xmax, num=pps+1, endpoint=False) + + for x in topx: + vertices.append(tuple(gnomonic_map(*lambert_map(x, lambert_map.ymax, inverse= True)))) + instructions.append(Path.LINETO) + + # Next generate the right side of the domain + righty = np.linspace(lambert_map.ymax, lambert_map.ymin, num=pps+1, endpoint=False) + + for y in righty: + vertices.append(tuple(gnomonic_map(*lambert_map(lambert_map.xmax, y, inverse= True)))) + instructions.append(Path.LINETO) + + + # Finally generate the bottom of the domain + bottomx = np.linspace(lambert_map.xmax, lambert_map.xmin, num=pps+1, endpoint=False) + + for x in bottomx: + vertices.append(tuple(gnomonic_map(*lambert_map(x, lambert_map.ymin, inverse= True)))) + instructions.append(Path.LINETO) + + # Need to replace final instruction with Path.CLOSEPOLY + instructions[-1] = Path.CLOSEPOLY + + print ("vertices=",vertices) + print ("instructions=",instructions) + + return vertices,instructions + +# Call the function we just defined to generate a polygon roughly approximating the lambert "rectangle" in gnomonic space + +verts3,codes3=get_lambert_points(map1, map3,10) + +# Now draw! + +path = Path(verts3, codes3) +patch = patches.PathPatch(path, facecolor='w', lw=2,alpha=0.5) +ax1.add_patch(patch) + + +plt.show() + + diff --git a/ush/bash_utils/boolify.sh b/ush/bash_utils/boolify.sh new file mode 100644 index 0000000000..fe32090fda --- /dev/null +++ b/ush/bash_utils/boolify.sh @@ -0,0 +1,69 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function used to change a variety of input boolean +# strings to standard TRUE and FALSE +# +#----------------------------------------------------------------------- +# + +function boolify() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the name of this function and input. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" + local input uc_input + + if [ "$#" -eq 1 ]; then + input="$1" + else + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} string + +where: + + string: + This is the string that should be converted to TRUE or FALSE +" + fi + + uc_input=$(echo_uppercase $input) + if [ "$uc_input" = "TRUE" ] || \ + [ "$uc_input" = "YES" ]; then + echo "TRUE" + elif [ "$uc_input" = "FALSE" ] || \ + [ "$uc_input" = "NO" ]; then + echo "FALSE" + fi + + # + #----------------------------------------------------------------------- + # + # Restore the shell options saved at the beginning of this script/func- + # tion. + # + #----------------------------------------------------------------------- + # + { restore_shell_opts; } > /dev/null 2>&1 +} diff --git a/ush/bash_utils/change_case.sh b/ush/bash_utils/change_case.sh new file mode 100644 index 0000000000..2bd82d1306 --- /dev/null +++ b/ush/bash_utils/change_case.sh @@ -0,0 +1,239 @@ +# +#----------------------------------------------------------------------- +# +# This file defines functions used to change string to all uppercase or +# all lowercase +# +#----------------------------------------------------------------------- +# + + +# +#----------------------------------------------------------------------- +# +# Function to echo the given string as an uppercase string +# +#----------------------------------------------------------------------- +# +function echo_uppercase() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Get information about the script or function that calls this function. +# Note that caller_name will be set as follows: +# +# 1) If the caller is a function, caller_name will be set to the name of +# that function. +# 2) If the caller is a sourced script, caller_name will be set to +# "script". Note that a sourced script cannot be the top level +# script since by defintion, it is sourced by another script or func- +# tion. +# 3) If the caller is the top-level script, caller_name will be set to +# "main". +# +# Thus, if caller_name is set to "script" or "main", the caller is a +# script, and if it is set to anything else, the caller is a function. +# +#----------------------------------------------------------------------- +# + local caller_fp=$( $READLINK -f "${BASH_SOURCE[1]}" ) + local caller_fn=$( basename "${caller_fp}" ) + local caller_dir=$( dirname "${caller_fp}" ) + local caller_name="${FUNCNAME[1]}" +# +# Get input string + + local input + + if [ "$#" -eq 1 ]; then + + input="$1" + +# +#----------------------------------------------------------------------- +# +# If no arguments or more than one, print out a usage message and exit. +# +#----------------------------------------------------------------------- +# + else + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} string + +where: + + string: + This is the string that should be converted to uppercase and echoed. +" + + fi + +# Echo the input string as upperercase + +echo $input| tr '[a-z]' '[A-Z]' + +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + + +} + + +# +#----------------------------------------------------------------------- +# +# Function to echo the given string as a lowercase string +# +#----------------------------------------------------------------------- +# +function echo_lowercase() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Get information about the script or function that calls this function. +# Note that caller_name will be set as follows: +# +# 1) If the caller is a function, caller_name will be set to the name of +# that function. +# 2) If the caller is a sourced script, caller_name will be set to +# "script". Note that a sourced script cannot be the top level +# script since by defintion, it is sourced by another script or func- +# tion. +# 3) If the caller is the top-level script, caller_name will be set to +# "main". +# +# Thus, if caller_name is set to "script" or "main", the caller is a +# script, and if it is set to anything else, the caller is a function. +# +#----------------------------------------------------------------------- +# + local caller_fp=$( $READLINK -f "${BASH_SOURCE[1]}" ) + local caller_fn=$( basename "${caller_fp}" ) + local caller_dir=$( dirname "${caller_fp}" ) + local caller_name="${FUNCNAME[1]}" +# +# Get input string + + local input + + if [ "$#" -eq 1 ]; then + + input="$1" + +# +#----------------------------------------------------------------------- +# +# If no arguments or more than one, print out a usage message and exit. +# +#----------------------------------------------------------------------- +# + else + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} string + +where: + + string: + This is the string that should be converted to lowercase and echoed. +" + + fi + +# Echo the input string as lowercase + +echo $input| tr '[A-Z]' '[a-z]' + +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + + +} + diff --git a/ush/bash_utils/check_for_preexist_dir_file.sh b/ush/bash_utils/check_for_preexist_dir_file.sh new file mode 100644 index 0000000000..dac2688a31 --- /dev/null +++ b/ush/bash_utils/check_for_preexist_dir_file.sh @@ -0,0 +1,170 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that checks for a preexisting version of +# the specified directory or file and, if present, deals with it according +# to the specified method. +# +#----------------------------------------------------------------------- +# +function check_for_preexist_dir_file() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 2 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} dir_or_file method + +where the arguments are defined as follows: + + dir_or_file: + Name of directory or file to check for a preexisting version. + + method: + String specifying the action to take if a preexisting version of + dir_or_file is found. Valid values are \"delete\", \"rename\", and \"quit\". +" + + fi +# +#----------------------------------------------------------------------- +# +# Set local variables to appropriate input arguments. +# +#----------------------------------------------------------------------- +# + local dir_or_file="$1" + local method="$2" +# +#----------------------------------------------------------------------- +# +# Set the valid values that method can take on and check to make sure +# the specified value is valid. +# +#----------------------------------------------------------------------- +# + local valid_vals_method=( "delete" "rename" "quit" ) + check_var_valid_value "method" "valid_vals_method" +# +#----------------------------------------------------------------------- +# +# Check if dir_or_file already exists. If so, act depending on the value +# of method. +# +#----------------------------------------------------------------------- +# + if [ -e "${dir_or_file}" ]; then + + case "$method" in +# +#----------------------------------------------------------------------- +# +# If method is set to "delete", we remove the preexisting directory or +# file. +# +#----------------------------------------------------------------------- +# + "delete") + + rm_vrfy -rf "${dir_or_file}" + ;; +# +#----------------------------------------------------------------------- +# +# If method is set to "rename", we move (rename) the preexisting directory +# or file. +# +#----------------------------------------------------------------------- +# + "rename") + + local i=1 + local old_indx=$( printf "%03d" "$i" ) + local old_dir_or_file="${dir_or_file}_old${old_indx}" + while [ -e "${old_dir_or_file}" ]; do + i=$[$i+1] + old_indx=$( printf "%03d" "$i" ) + old_dir_or_file="${dir_or_file}_old${old_indx}" + done + + print_info_msg "$VERBOSE" " +Specified directory or file (dir_or_file) already exists: + dir_or_file = \"${dir_or_file}\" +Moving (renaming) preexisting directory or file to: + old_dir_or_file = \"${old_dir_or_file}\"" + + mv_vrfy "${dir_or_file}" "${old_dir_or_file}" + ;; +# +#----------------------------------------------------------------------- +# +# If method is set to "quit", we simply exit with a nonzero status. Note +# that "exit" is different than "return" because it will cause the calling +# script (in which this file/function is sourced) to stop execution. +# +#----------------------------------------------------------------------- +# + "quit") + + print_err_msg_exit "\ +Specified directory or file (dir_or_file) already exists: + dir_or_file = \"${dir_or_file}\"" + ;; + + esac + + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + + diff --git a/ush/bash_utils/check_var_valid_value.sh b/ush/bash_utils/check_var_valid_value.sh new file mode 100644 index 0000000000..576ad6b1b8 --- /dev/null +++ b/ush/bash_utils/check_var_valid_value.sh @@ -0,0 +1,145 @@ +# +#----------------------------------------------------------------------- +# +# This function checks whether the specified variable contains a valid +# value (where the set of valid values is also specified). +# +#----------------------------------------------------------------------- +# +function check_var_valid_value() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} var_name valid_var_values_array_name [msg] + +where the arguments are defined as follows: + + var_name: + The name of the variable whose value we want to check for validity. + + valid_var_values_array_name: + The name of the array containing a list of valid values that var_name + can take on. + + msg + Optional argument specifying the first portion of the error message to + print out if var_name does not have a valid value. +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local var_name \ + valid_var_values_array_name \ + var_value \ + valid_var_values_at \ + valid_var_values \ + err_msg \ + valid_var_values_str +# +#----------------------------------------------------------------------- +# +# Set local variable values. +# +#----------------------------------------------------------------------- +# + var_name="$1" + valid_var_values_array_name="$2" + + var_value=${!var_name} + valid_var_values_at="$valid_var_values_array_name[@]" + valid_var_values=("${!valid_var_values_at}") + + if [ "$#" -eq 3 ]; then + err_msg="$3" + else + err_msg="\ +The value specified in ${var_name} is not supported: + ${var_name} = \"${var_value}\"" + fi +# +#----------------------------------------------------------------------- +# +# If var_value contains a dollar sign, we assume the corresponding variable +# (var_name) is a template variable, i.e. one whose value contains a +# reference to another variable, e.g. +# +# MY_VAR='\${ANOTHER_VAR}' +# +# In this case, we do nothing since it does not make sense to check +# whether var_value is a valid value (since its contents have not yet +# been expanded). If var_value doesn't contain a dollar sign, it must +# contain a literal string. In this case, we check whether it is equal +# to one of the elements of the array valid_var_values. If not, we +# print out an error message and exit the calling script. +# +#----------------------------------------------------------------------- +# + if [[ "${var_value}" != *'$'* ]]; then + is_element_of "valid_var_values" "${var_value}" || { \ + valid_var_values_str=$(printf "\"%s\" " "${valid_var_values[@]}"); + print_err_msg_exit "\ +${err_msg} +${var_name} must be set to one of the following: + ${valid_var_values_str}"; \ + } + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/function. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/count_files.sh b/ush/bash_utils/count_files.sh new file mode 100644 index 0000000000..c80f342cb1 --- /dev/null +++ b/ush/bash_utils/count_files.sh @@ -0,0 +1,86 @@ +# +#----------------------------------------------------------------------- +# +# This function returns the number of files in the current directory +# that end with the specified extension (file_extension). +# +#----------------------------------------------------------------------- +# +function count_files() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 1 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} file_extension + +where file_extension is the file extension to use for counting files. +The file count returned will be equal to the number of files in the cur- +rent directory that end with \".${file_extension}\". +" + + fi +# +#----------------------------------------------------------------------- +# +# Count the number of files and then print it to stdout. +# +#----------------------------------------------------------------------- +# + local file_extension="$1" + local glob_pattern="*.${file_extension}" + local num_files=$( ls -1 ${glob_pattern} 2>/dev/null | wc -l ) + print_info_msg "${num_files}" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/create_symlink_to_file.sh b/ush/bash_utils/create_symlink_to_file.sh new file mode 100644 index 0000000000..c14a35bdc6 --- /dev/null +++ b/ush/bash_utils/create_symlink_to_file.sh @@ -0,0 +1,163 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that is used to create a symbolic link +# ("symlink") to the specified target file ("target"). It checks for +# the existence of the target file and fails (with an appropriate error +# message) if that target does not exist or is not a file. Also, the +# argument "relative" determines whether a relative or an absolute path +# to the symlink is used. Note that on some platforms, relative symlinks +# are not supported. In those cases, an absolute path is used regardless +# of the setting of "relative". +# +#----------------------------------------------------------------------- +# +function create_symlink_to_file() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names for this script/function. Then +# process the arguments provided to this script/function (which should +# consist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# + local valid_args=( \ +"target" \ +"symlink" \ +"relative" \ + ) + process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# + print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Verify that the required arguments to this function have been specified. +# If not, print out an error message and exit. +# +#----------------------------------------------------------------------- +# + if [ -z "${target}" ]; then + print_err_msg_exit "\ +The argument \"target\" specifying the target of the symbolic link that +this function will create was not specified in the call to this function: + target = \"$target\"" + fi + + if [ -z "${symlink}" ]; then + print_err_msg_exit "\ +The argument \"symlink\" specifying the symbolic link that this function +will create was not specified in the call to this function: + symlink = \"$symlink\"" + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local valid_vals_relative \ + relative_flag +# +#----------------------------------------------------------------------- +# +# If "relative" is not set (i.e. if it is set to a null string), reset +# it to a default value of "TRUE". Then check that it is set to a vaild +# value. +# +#----------------------------------------------------------------------- +# + relative=${relative:-"TRUE"} + + valid_vals_relative=("TRUE" "true" "YES" "yes" "FALSE" "false" "NO" "no") + check_var_valid_value "relative" "valid_vals_relative" +# +#----------------------------------------------------------------------- +# +# Make sure that the target file exists and is a file. +# +#----------------------------------------------------------------------- +# + if [ ! -f "${target}" ]; then + print_err_msg_exit "\ +Cannot create symlink to specified target file because the latter does +not exist or is not a file: + target = \"$target\"" + fi +# +#----------------------------------------------------------------------- +# +# Set the flag that specifies whether or not a relative symlink should +# be created. +# +#----------------------------------------------------------------------- +# + relative_flag="" + if [ "${relative}" = "TRUE" ]; then + relative_flag="${RELATIVE_LINK_FLAG}" + fi +# +#----------------------------------------------------------------------- +# +# Create the symlink. +# +# Important note: +# In the ln_vrfy command below, do not quote ${relative_flag} because if +# is quoted (either single or double quotes) but happens to be a null +# string, it will be treated as the (empty) name of (or path to) the +# target and will cause an error. +# +#----------------------------------------------------------------------- +# + ln_vrfy -sf ${relative_flag} "$target" "$symlink" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/define_macos_utilities.sh b/ush/bash_utils/define_macos_utilities.sh new file mode 100644 index 0000000000..d89780944d --- /dev/null +++ b/ush/bash_utils/define_macos_utilities.sh @@ -0,0 +1,44 @@ +# +#----------------------------------------------------------------------- +# +# This script defines MacOS-specific UNIX command-line utilities that +# mimic the functionality of the GNU equivalents. +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# +# Check if we are on a Darwin machine; if so we need to use the gnu-like +# equivalent of readlink and sed. +# +#----------------------------------------------------------------------- +# +darwinerror () { + + utility=$1 + echo >&2 " +For Darwin-based operating systems (MacOS), the '${utility}' utility is required to run the UFS SRW Application. +Reference the User's Guide for more information about platform requirements. +Aborting. +" + exit 1 +} + + if [[ $(uname -s) == Darwin ]]; then + export READLINK=greadlink + command -v $READLINK >/dev/null 2>&1 || darwinerror $READLINK + export SED=gsed + command -v $SED >/dev/null 2>&1 || darwinerror $SED + export DATE_UTIL=gdate + command -v $DATE_UTIL >/dev/null 2>&1 || darwinerror $DATE_UTIL + export LN_UTIL=gln + command -v $LN_UTIL >/dev/null 2>&1 || darwinerror $LN_UTIL + else + export READLINK=readlink + export SED=sed + export DATE_UTIL=date + export LN_UTIL=ln + fi + diff --git a/ush/bash_utils/filesys_cmds_vrfy.sh b/ush/bash_utils/filesys_cmds_vrfy.sh new file mode 100644 index 0000000000..d147fc1079 --- /dev/null +++ b/ush/bash_utils/filesys_cmds_vrfy.sh @@ -0,0 +1,276 @@ +# +#----------------------------------------------------------------------- +# +# This is a generic function that executes the specified command (e.g. +# "cp", "mv", etc) with the specified options/arguments and then verifies +# that the command executed without errors. The first argument to this +# function is the command to execute while the remaining ones are the +# options/arguments to be passed to that command. +# +#----------------------------------------------------------------------- +# +function filesys_cmd_vrfy() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Get information about the script or function that calls this function. +# Note that caller_name will be set as follows: +# +# 1) If the caller is a function, caller_name will be set to the name of +# that function. +# 2) If the caller is a sourced script, caller_name will be set to +# "script". Note that a sourced script cannot be the top level +# script since by defintion, it is sourced by another script or +# function. +# 3) If the caller is the top-level script, caller_name will be set to +# "main". +# +# Thus, if caller_name is set to "script" or "main", the caller is a +# script, and if it is set to anything else, the caller is a function. +# +# Below, the index into FUNCNAME and BASH_SOURCE is 2 (not 1 as is usually +# the case) because this function is called by functions such as cp_vrfy, +# mv_vrfy, rm_vrfy, ln_vrfy, mkdir_vrfy, and cd_vrfy, but these are just +# wrappers, and in the error and informational messages, we are really +# interested in the scripts/functions that in turn call these wrappers. +# +#----------------------------------------------------------------------- +# + local caller_fp=$( $READLINK -f "${BASH_SOURCE[2]}" ) + local caller_fn=$( basename "${caller_fp}" ) + local caller_dir=$( dirname "${caller_fp}" ) + local caller_name="${FUNCNAME[2]}" +# +#----------------------------------------------------------------------- +# +# Declare local variables that are used later below. +# +#----------------------------------------------------------------------- +# + local cmd \ + output \ + exit_code \ + double_space \ + script_or_function +# +#----------------------------------------------------------------------- +# +# Check that at least one argument is supplied. +# +#----------------------------------------------------------------------- +# + if [ "$#" -lt 1 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} cmd [args_to_cmd] + +where \"cmd\" is the name of the command to execute and \"args_to_cmd\" +are zero or more options and arguments to pass to that command. +" + + fi +# +#----------------------------------------------------------------------- +# +# The first argument to this function is the command to execute while +# the remaining ones are the arguments to that command. Extract the +# command and save it in the variable "cmd". Then shift the argument +# list so that $@ contains the arguments to the command but not the +# name of the command itself. +# +#----------------------------------------------------------------------- +# + cmd="$1" + shift +# +#----------------------------------------------------------------------- +# +# Pass the arguments to the command and execute it, saving the outputs +# to stdout and stderr in the variable "output". Also, save the exit +# code from the execution. +# +#----------------------------------------------------------------------- +# + local output=$( "$cmd" "$@" 2>&1 ) + local exit_code=$? +# +#----------------------------------------------------------------------- +# +# If output is not empty, it will be printed to stdout below either as +# an error message or an informational message. In either case, format +# it by adding a double space to the beginning of each line. +# +#----------------------------------------------------------------------- +# + if [ -n "$output" ]; then + local double_space=" " + output="${double_space}${output}" + output=${output/$'\n'/$'\n'${double_space}} + fi +# +#----------------------------------------------------------------------- +# +# If the exit code from the execution of cmd above is nonzero, print out +# an error message and exit. +# +#----------------------------------------------------------------------- +# + if [ "${caller_name}" = "main" ] || \ + [ "${caller_name}" = "script" ]; then + local script_or_function="the script" + else + local script_or_function="function \"${caller_name}\"" + fi + + if [ ${exit_code} -ne 0 ]; then + + print_err_msg_exit "\ +Call to function \"${cmd}_vrfy\" failed. This function was called from +${script_or_function} in file: + + \"${caller_fp}\" + +Error message from \"${cmd}_vrfy\" function's \"$cmd\" operation: +$output" + + fi +# +#----------------------------------------------------------------------- +# +# If the exit code from the execution of cmd above is zero, continue. +# +# First, check if cmd is set to "cd". If so, the execution of cmd above +# in a separate subshell [which is what happens when using the $("$cmd") +# construct above] will change directory in that subshell but not in the +# current shell. Thus, rerun the "cd" command in the current shell. +# +#----------------------------------------------------------------------- +# + if [ "$cmd" = "cd" ]; then + "$cmd" "$@" 2>&1 > /dev/null + fi +# +#----------------------------------------------------------------------- +# +# If output is not empty, print out whatever message it contains (e.g. +# it might contain a warning or other informational message). +# +#----------------------------------------------------------------------- +# + if [ -n "$output" ]; then + + print_info_msg " +\"${cmd}_vrfy\" operation returned with a message. This command was +issued from ${script_or_function} in file: + + \"${caller_fp}\" + +Message from \"${cmd}_vrfy\" function's \"$cmd\" operation: +$output" + + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + + +# +#----------------------------------------------------------------------- +# +# The following are functions are counterparts of common filesystem +# commands "with verification", i.e. they execute a filesystem command +# (such as "cp" and "mv") and then verify that the execution was successful. +# +# These functions are called using the "filesys_cmd_vrfy" function defined +# above. In each of these functions, we: +# +# 1) Save current shell options (in a global array) and then set new +# options for this script/function. +# 2) Call the generic function "filesys_cmd_vrfy" with the command of +# interest (e.g. "cp") as the first argument and the arguments passed +# in as the rest. +# 3) Restore the shell options saved at the beginning of the function. +# +#----------------------------------------------------------------------- +# + +function cp_vrfy() { + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + filesys_cmd_vrfy "cp" "$@" + { restore_shell_opts; } > /dev/null 2>&1 +} + +function mv_vrfy() { + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + filesys_cmd_vrfy "mv" "$@" + { restore_shell_opts; } > /dev/null 2>&1 +} + +function rm_vrfy() { + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + filesys_cmd_vrfy "rm" "$@" + { restore_shell_opts; } > /dev/null 2>&1 +} + +function ln_vrfy() { + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + filesys_cmd_vrfy "$LN_UTIL" "$@" + { restore_shell_opts; } > /dev/null 2>&1 +} + +function mkdir_vrfy() { + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + filesys_cmd_vrfy "mkdir" "$@" + { restore_shell_opts; } > /dev/null 2>&1 +} + +function cd_vrfy() { + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + filesys_cmd_vrfy "cd" "$@" + { restore_shell_opts; } > /dev/null 2>&1 +} + diff --git a/ush/bash_utils/get_bash_file_contents.sh b/ush/bash_utils/get_bash_file_contents.sh new file mode 100644 index 0000000000..fdfb626922 --- /dev/null +++ b/ush/bash_utils/get_bash_file_contents.sh @@ -0,0 +1,71 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that returns the contents of a bash script/ +# function with all empty lines, comment lines, and leading and trailing +# whitespace removed. Arguments are as follows: +# +# fp: +# The relative or full path to the file containing the bash script or +# function. +# +# output_varname_contents: +# Name of the output variable that will contain the (processed) contents +# of the file. This is the output of the function. +# +#----------------------------------------------------------------------- +# +function get_bash_file_contents() { + + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + + local valid_args=( \ + "fp" \ + "outvarname_contents" \ + ) + process_args valid_args "$@" + print_input_args "valid_args" + # + # Verify that the required arguments to this function have been specified. + # If not, print out an error message and exit. + # + if [ -z "$fp" ]; then + print_err_msg_exit "\ +The argument \"fp\" specifying the relative or full path to the file to +read was not specified in the call to this function: + fp = \"$fp\"" + fi + + local contents \ + crnt_line + # + # Read in all lines in the file. In doing so: + # + # 1) Concatenate any line ending with the bash line continuation character + # (a backslash) with the following line. + # 2) Remove any leading and trailing whitespace. + # + # Note that these two actions are automatically performed by the "read" + # utility in the while-loop below. + # + contents="" + while read crnt_line; do + contents="${contents}${crnt_line} +" + done < "$fp" + # + # Strip out any comment and empty lines from contents. + # + contents=$( printf "${contents}" | \ + $SED -r -e "/^#.*/d" `# Remove comment lines.` \ + -e "/^$/d" `# Remove empty lines.` \ + ) + # + # Set output variables. + # + printf -v ${outvarname_contents} "%s" "${contents}" + + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/get_charvar_from_netcdf.sh b/ush/bash_utils/get_charvar_from_netcdf.sh new file mode 100644 index 0000000000..ac70cf68da --- /dev/null +++ b/ush/bash_utils/get_charvar_from_netcdf.sh @@ -0,0 +1,228 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source the variable definitions file and the bash utility functions. +# +#----------------------------------------------------------------------- +# +#. $USHDIR/source_util_funcs.sh + +# +#----------------------------------------------------------------------- +# +# For a description of this function, see the usage message below. +# +#----------------------------------------------------------------------- +# +function get_charvar_from_netcdf() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + num_required_args=2 + if [ "$#" -ne "${num_required_args}" ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments required: ${num_required_args} + Number of arguments specified: $# + +Usage: + + ${func_name} nc_file nc_var_name + +This function searches a specified NetCDF file and extracts from it the +value of the specified scalar variable. + +The arguments to this function are defined as follows: + + nc_file: + The name of the NetCDF file. This can be just the file name, a relative + path, or an absolute path. + + nc_var_name: + The name of the variable in the NetCDF file whose value will be extracted. + +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local nc_file \ + nc_var_name \ + nc_var_value +# +#----------------------------------------------------------------------- +# +# Set the name of the manage_externals configuration file [which may be +# the absolute path to the file or a relative path (relative to the cur- +# rent working directory)], the name of the external in that file whose +# property value we want to extract, and the name of the property under +# that external. +# +#----------------------------------------------------------------------- +# + nc_file="$1" + nc_var_name="$2" +# +#----------------------------------------------------------------------- +# +# Use "sed" to extract the line in the configuration file containing the +# value of the specified property for the specified external (if such a +# line exists). To explain how the "sed" command below does this, we +# first number the lines in that command, as follows: +# +# (1) line=$( sed -r -n \ +# (2) -e "/^[ ]*\[${external_name}\]/!b" \ +# (3) -e ":SearchForLine" \ +# (4) -e "s/(${regex_search})/\1/;t FoundLine" \ +# (5) -e "n;bSearchForLine" \ +# (6) -e ":FoundLine" \ +# (7) -e "p;q" \ +# (8) "${externals_cfg_fp}" \ +# (9) ) +# +# This command works as follows. First, on line (1), the -r flag speci- +# fies that extended regular expressions should be allowed, and the -n +# flag suppresses the printing of each line in the file that sed pro- +# cesses. +# +# Line (2) checks for all lines in the file [which is specified on line +# (8)] that do NOT start with zero or more spaces followed by the exter- +# nal name in square brackets. (The ! before the "b" causes the nega- +# tion.) For each such line, the "b" causes the rest of the sed com- +# mands [specified by the arguments to the "-e" flags on lines (3) +# through (7)] to be skipped and for sed to read in the next line in the +# file. Note that if no line is found that starts with zero or more +# spaces followed by the external name in square brackets, sed will +# reach the end of the file and quit [and lines (3) through (6) will ne- +# ver be executed], and the variable "line" will get assigned to a null +# string. +# +# Lines (3) through (5) form a while-loop. After finding a line in the +# file that does start with zero or more spaces followed by the external +# name in square brackets, we pass through line (3) (which just defines +# the location of the SearchForLine label; it does not execute any com- +# mands) and execute line (4). This line checks whether the current +# line in the file has the form specified by the regular expression in +# regex_search but doesn't change the line (since the whole line is +# substuted back in via the parentheses around ${regex_search} and the +# \1). If not, sed moves on to line (5), which clears the contents of +# the pattern buffer and reads the next line in the file into it (be- +# cause of the "n" command). Execution then moves back to line 3 (be- +# cause of the "bSearchForLine" command). If the current line in the +# file does have the form specified by regex_search, line (5) places the +# current line in the file in the pattern buffer (whithout modifying +# it), and execution moves on to line (6) [because a substitution was +# successfully made on line 4, so the "t FoundLine" command moves the +# execution to line (6)]. Thus, once line (1) finds the start of the +# section for the specified external, lines (3) through (6) loop until a +# line defining the specified property is found (or the end of the file +# is reached). If and when this happens, sed execution moves to line +# (6). +# +# Line (6) just defines the location of the FoundLine label, so it +# doesn't actually execute any commands, and execution moves to line +# (7). On this line, the "p" command prints out the contents of the +# pattern buffer, which is the first line in the file after the start +# of the specified external that defines the property. Then the "q" +# command simply quits execution since we have found the line we are +# looking for. +# +#----------------------------------------------------------------------- +# + nc_var_value=$( ncdump -v "${nc_var_name}" "${nc_file}" | \ + $SED -r -e '1,/data:/d' \ + -e '/^[ ]*'${nc_var_name}'/d' \ + -e '/^}$/d' \ + -e 's/.*"(.*)".*/\1/' \ + -e '/^$/d' \ + ) || print_err_msg_exit "\ +Attempt to extract the value of the NetCDF variable spcecified by nc_var_name +from the file specified by nc_file failed: + nc_file = \"${nc_file}\" + nc_var_name = \"${nc_var_name}\"" +# +#----------------------------------------------------------------------- +# +# If the variable "line" is empty, it means the sed command above was +# not able to find a line in the configuration file that defines the +# specified property for the specified external. In this case, print +# out an error messge and exit. +# +#----------------------------------------------------------------------- +# + if [ -z "${nc_var_value}" ]; then + + print_err_msg_exit "\ +In the specified NetCDF file (nc_file), the specified variable (nc_var_name) +was not found: + nc_file = \"${nc_file}\" + nc_var_name = \"${nc_var_name}\" + nc_var_value = \"${nc_var_value}\"" +# +#----------------------------------------------------------------------- +# +# If nc_var_value is not empty, it means the sed command above was able to find +# a line in the configuration file that defines the specified property +# for the specified external. In this case, extract the property value +# from nc_var_value and print it to stdout. +# +#----------------------------------------------------------------------- +# + else + + printf "%s\n" "${nc_var_value}" + + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the start of this script/function. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} diff --git a/ush/bash_utils/get_elem_inds.sh b/ush/bash_utils/get_elem_inds.sh new file mode 100644 index 0000000000..89a9c41227 --- /dev/null +++ b/ush/bash_utils/get_elem_inds.sh @@ -0,0 +1,180 @@ +# +#----------------------------------------------------------------------- +# +# For a description of this function, see the usage message below. +# +#----------------------------------------------------------------------- +# +function get_elem_inds() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 2 ] && [ "$#" -ne 3 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} array_name str_to_match [inds_to_return] + +This function prints to stdout the indices of those elements of a given +array that match (i.e. are equal to) a given string. It can return the +index of the first matched element, the index of the last matched ele- +ment, or the indices of all matched elements. The return code +from this function will be zero if at least one match is found and non- +zero if no matches are found. + +The arguments to this function are defined as follows: + + array_name: + The name of the array in which to search for str_to_match. Note that + this is the name of the array, not the array itself. + + str_to_match: + The string to match in array_name. + + inds_to_return: + Optional argument that specifies the subset of the indices of the ar- + ray elements that match str_to_match to print to stdout. Must be set + to \"first\", \"last\", or \"all\" (but is case insensitive). If set to + \"first\", the index of only the first matched element is printed. If + set to \"last\", the index of only the last matched element is printed. + If set to \"all\", the indices of all matched elements are printed. De- + fault is \"all\". +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local array_name \ + str_to_match \ + inds_to_return \ + array_name_at \ + array \ + valid_vals_inds_to_return \ + match_inds \ + num_matches \ + num_elems \ + n +# +#----------------------------------------------------------------------- +# +# Set local variables to appropriate input arguments. +# +#----------------------------------------------------------------------- +# + array_name="$1" + str_to_match="$2" + + inds_to_return="all" + if [ "$#" -eq 3 ]; then + inds_to_return="$3" + fi + + array_name_at="$array_name[@]" + array=("${!array_name_at}") +# +#----------------------------------------------------------------------- +# +# Change all letters in inds_to_return to lower case. Then check whe- +# ther it has a valid value. +# +#----------------------------------------------------------------------- +# + inds_to_return=$(echo_lowercase $inds_to_return) + valid_vals_inds_to_return=( "first" "last" "all" ) + check_var_valid_value "inds_to_return" "valid_vals_inds_to_return" +# +#----------------------------------------------------------------------- +# +# Initialize the array match_inds to an empty array. This will contain +# the indices of any matched elements. Then loop through the elements +# of the given array and check whether each element is equal to str_to_- +# match. If so, save the index of that element as an element of match_- +# inds. If inds_to_return is set to "first", we break out of the loop +# after finding the first match in order to not waste computation. +# +#----------------------------------------------------------------------- +# + match_inds=() + num_matches=0 + + num_elems=${#array[@]} + for (( n=0; n<${num_elems}; n++ )); do + if [ "${array[$n]}" = "${str_to_match}" ]; then + match_inds[${num_matches}]=$n + num_matches=$((num_matches+1)) + if [ "${inds_to_return}" = "first" ]; then + break + fi + fi + done +# +#----------------------------------------------------------------------- +# +# Find the number of matches. If it is more than zero, print the indi- +# ces of the matched elements to stdout. +# +#----------------------------------------------------------------------- +# + num_matches=${#match_inds[@]} + if [ ${num_matches} -gt 0 ]; then + if [ "${inds_to_return}" = "last" ]; then + printf "%s\n" "${match_inds[-1]}" + else + printf "%s\n" "${match_inds[@]}" + fi + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} diff --git a/ush/bash_utils/get_manage_externals_config_property.sh b/ush/bash_utils/get_manage_externals_config_property.sh new file mode 100644 index 0000000000..370d448f2a --- /dev/null +++ b/ush/bash_utils/get_manage_externals_config_property.sh @@ -0,0 +1,242 @@ +# +#----------------------------------------------------------------------- +# +# For a description of this function, see the usage message below. +# +#----------------------------------------------------------------------- +# +function get_manage_externals_config_property() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 3 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} externals_cfg_fp external_name property_name + +This function searches a specified manage_externals configuration file +and extracts from it the value of the specified property of the external +with the specified name (e.g. the relative path in which the external +has been/will be cloned by the manage_externals utility). + +The arguments to this function are defined as follows: + + externals_cfg_fp: + The absolute or relative path to the manage_externals configuration + file that will be searched. + + external_name: + The name of the external to search for in the manage_externals confi- + guration file specified by externals_cfg_fp. + + property_name: + The name of the property whose value to obtain (for the external spe- + cified by external_name). +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local externals_cfg_fp \ + external_name \ + property_name \ + regex_search \ + line \ + property_value +# +#----------------------------------------------------------------------- +# +# Set the name of the manage_externals configuration file [which may be +# the absolute path to the file or a relative path (relative to the cur- +# rent working directory)], the name of the external in that file whose +# property value we want to extract, and the name of the property under +# that external. +# +#----------------------------------------------------------------------- +# + externals_cfg_fp="$1" + external_name="$2" + property_name="$3" +# +#----------------------------------------------------------------------- +# +# Check that the specified manage_externals configuration file exists. +# If not, print out an error message and exit. +# +#----------------------------------------------------------------------- +# + if [ ! -f "${externals_cfg_fp}" ]; then + print_err_msg_exit "\ +The specified manage_externals configuration file (externals_cfg_fp) +does not exist: + externals_cfg_fp = \"${externals_cfg_fp}\"" + fi +# +#----------------------------------------------------------------------- +# +# Use "sed" to extract the line in the configuration file containing the +# value of the specified property for the specified external (if such a +# line exists). To explain how the "sed" command below does this, we +# first number the lines in that command, as follows: +# +# (1) line=$( sed -r -n \ +# (2) -e "/^[ ]*\[${external_name}\]/!b" \ +# (3) -e ":SearchForLine" \ +# (4) -e "s/(${regex_search})/\1/;t FoundLine" \ +# (5) -e "n;bSearchForLine" \ +# (6) -e ":FoundLine" \ +# (7) -e "p;q" \ +# (8) "${externals_cfg_fp}" \ +# (9) ) +# +# This command works as follows. First, on line (1), the -r flag speci- +# fies that extended regular expressions should be allowed, and the -n +# flag suppresses the printing of each line in the file that sed pro- +# cesses. +# +# Line (2) checks for all lines in the file [which is specified on line +# (8)] that do NOT start with zero or more spaces followed by the exter- +# nal name in square brackets. (The ! before the "b" causes the nega- +# tion.) For each such line, the "b" causes the rest of the sed com- +# mands [specified by the arguments to the "-e" flags on lines (3) +# through (7)] to be skipped and for sed to read in the next line in the +# file. Note that if no line is found that starts with zero or more +# spaces followed by the external name in square brackets, sed will +# reach the end of the file and quit [and lines (3) through (6) will ne- +# ver be executed], and the variable "line" will get assigned to a null +# string. +# +# Lines (3) through (5) form a while-loop. After finding a line in the +# file that does start with zero or more spaces followed by the external +# name in square brackets, we pass through line (3) (which just defines +# the location of the SearchForLine label; it does not execute any com- +# mands) and execute line (4). This line checks whether the current +# line in the file has the form specified by the regular expression in +# regex_search but doesn't change the line (since the whole line is +# substuted back in via the parentheses around ${regex_search} and the +# \1). If not, sed moves on to line (5), which clears the contents of +# the pattern buffer and reads the next line in the file into it (be- +# cause of the "n" command). Execution then moves back to line 3 (be- +# cause of the "bSearchForLine" command). If the current line in the +# file does have the form specified by regex_search, line (5) places the +# current line in the file in the pattern buffer (whithout modifying +# it), and execution moves on to line (6) [because a substitution was +# successfully made on line 4, so the "t FoundLine" command moves the +# execution to line (6)]. Thus, once line (1) finds the start of the +# section for the specified external, lines (3) through (6) loop until a +# line defining the specified property is found (or the end of the file +# is reached). If and when this happens, sed execution moves to line +# (6). +# +# Line (6) just defines the location of the FoundLine label, so it +# doesn't actually execute any commands, and execution moves to line +# (7). On this line, the "p" command prints out the contents of the +# pattern buffer, which is the first line in the file after the start +# of the specified external that defines the property. Then the "q" +# command simply quits execution since we have found the line we are +# looking for. +# +#----------------------------------------------------------------------- +# + regex_search="^[ ]*(${property_name})[ ]*=[ ]*([^ ]*).*" + line=$( $SED -r -n \ + -e "/^[ ]*\[${external_name}\]/!b" \ + -e ":SearchForLine" \ + -e "s/(${regex_search})/\1/;t FoundLine" \ + -e "n;bSearchForLine" \ + -e ":FoundLine" \ + -e "p;q" \ + "${externals_cfg_fp}" \ + ) +# +#----------------------------------------------------------------------- +# +# If the variable "line" is empty, it means the sed command above was +# not able to find a line in the configuration file that defines the +# specified property for the specified external. In this case, print +# out an error messge and exit. +# +#----------------------------------------------------------------------- +# + if [ -z "${line}" ]; then + + print_err_msg_exit "\ +In the specified manage_externals configuration file (externals_cfg_fp), +the specified property (property_name) was not found for the the speci- +fied external (external_name): + externals_cfg_fp = \"${externals_cfg_fp}\" + external_name = \"${external_name}\" + property_name = \"${property_name}\"" +# +#----------------------------------------------------------------------- +# +# If line is not empty, it means the sed command above was able to find +# a line in the configuration file that defines the specified property +# for the specified external. In this case, extract the property value +# from line and print it to stdout. +# +#----------------------------------------------------------------------- +# + else + + property_value=$( printf "%s" "${line}" | \ + $SED -r -n -e "s/${regex_search}/\2/p" ) + printf "%s\n" "${property_value}" + + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} diff --git a/ush/bash_utils/interpol_to_arbit_CRES.sh b/ush/bash_utils/interpol_to_arbit_CRES.sh new file mode 100644 index 0000000000..bc4c6e8336 --- /dev/null +++ b/ush/bash_utils/interpol_to_arbit_CRES.sh @@ -0,0 +1,154 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that is used to interpolate (or extrapo- +# late) a grid cell size-dependent property to an arbitrary cubed-sphere +# resolution using arrays that specify a set of property values for a +# corresponding set of resolutions. +# +#----------------------------------------------------------------------- +# +function interpol_to_arbit_CRES() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 3 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} RES RES_array prop_array + +where the arguments are defined as follows: + + RES: + The cubed-sphere resolution at which to find the value of a property. + This is in units of number of cells (in either of the two horizontal + directions) on any one of the tiles of a cubed-sphere grid. + + RES_array: + The name of the array containing the cubed-sphere resolutions for + which corresponding property values are given (in prop_array). These + are assumed to be given from smallest to largest. + + prop_array: + The name of the array containing the values of the property corres- + ponding to the cubed-sphere resolutions in RES_array. +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables and initialize some. +# +#----------------------------------------------------------------------- +# + local RES="$1" + local RES_array_name_at="$2[@]" + local prop_array_name_at="$3[@]" + + local RES_array=("${!RES_array_name_at}") + local prop_array=("${!prop_array_name_at}") + + local num_valid_RESes i_min i_max i RES1 RES2 prop1 prop2 \ + m_slope y_intcpt prop +# +#----------------------------------------------------------------------- +# +# If RES is less than or equal to the smallest value in RES_array, set +# the property value to the one corresponding to the smallest value in +# RES_array. Similarly, if RES is larger than the largest value in +# RES_array, set the property value to the one corresponding to the +# largest value in RES_array. If RES is somewhere in between the small- +# est and largest values in RES_array, find the property value by line- +# arly interpolating between the two RES_array elements between which +# RES lies. +# +#----------------------------------------------------------------------- +# + num_valid_RESes="${#RES_array[@]}" + + i_min=0 + i_max=$( bc -l <<< "$num_valid_RESes - 1" ) + + if [ "${RES}" -le "${RES_array[$i_min]}" ]; then + + prop="${prop_array[$i_min]}" + + elif [ "${RES}" -gt "${RES_array[$i_max]}" ]; then + + prop="${prop_array[$i_max]}" + + else + + for (( i=0; i<$((num_valid_RESes-1)); i++ )); do + + if [ "$RES" -gt "${RES_array[$i]}" ] && \ + [ "$RES" -le "${RES_array[$i+1]}" ]; then + RES1="${RES_array[$i]}" + RES2="${RES_array[$i+1]}" + prop1="${prop_array[$i]}" + prop2="${prop_array[$i+1]}" + m_slope=$( bc -l <<< "($prop2 - $prop1)/($RES2 - $RES1)" ) + y_intcpt=$( bc -l <<< "($RES2*$prop1 - $RES1*$prop2)/($RES2 - $RES1)" ) + prop=$( bc -l <<< "$m_slope*$RES + $y_intcpt" ) + break + fi + + done + + fi + + prop=$( printf "%e\n" $prop ) + echo "$prop" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/is_array.sh b/ush/bash_utils/is_array.sh new file mode 100644 index 0000000000..c831f313e2 --- /dev/null +++ b/ush/bash_utils/is_array.sh @@ -0,0 +1,100 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that is used to check whether a specified +# variable is a bash array. It is called as follows: +# +# is_array var_name +# +# Here, var_name is the name of the variable to check to determine whe- +# ther or not it is an array. If the variable is an array, this func- +# tion will return a 0, and if it is not, this function will return a 1. +# +#----------------------------------------------------------------------- +# +function is_array() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 1 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} var_name + +where var_name is the name of the variable to check to determine whether +or not it is an array. +" + + fi +# +#----------------------------------------------------------------------- +# +# Set local variables to appropriate input arguments. +# +#----------------------------------------------------------------------- +# + local var_name="$1" + local declare_output=$( declare -p "$var_name" 2> /dev/null ) + local regex="^declare -[aA] ${var_name}(=|$)" + printf "%s" "$declare_output" | grep --extended-regexp "$regex" >/dev/null + is_an_array="$?" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Return the variable "is_an_array". +# +#----------------------------------------------------------------------- +# + return ${is_an_array} + +} + diff --git a/ush/bash_utils/is_element_of.sh b/ush/bash_utils/is_element_of.sh new file mode 100644 index 0000000000..3ae9ce1cc5 --- /dev/null +++ b/ush/bash_utils/is_element_of.sh @@ -0,0 +1,153 @@ +# +#----------------------------------------------------------------------- +# +# For a description of this function, see the usage message below. +# +#----------------------------------------------------------------------- +# +function is_element_of() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 2 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} array_name str_to_match + +This function checks whether the specified array contains the specified +string, i.e. whether at least one of the elements of the array is equal +to the string. The return code from this function will be zero if at +least one match is found and nonzero if no matches are found. + +The arguments to this function are defined as follows: + + array_name: + The name of the array in which to search for str_to_match. Note that + this is the name of the array, not the array itself. + + str_to_match: + The string to search for in array_name. + +Use this function in a script as follows: + + . ./is_element_of.sh + array_name=("1" "2" "3 4" "5") + + str_to_match="2" + is_element_of "${str_to_match}" array_name + echo $? # Should output 0. + + str_to_match="3 4" + is_element_of "${str_to_match}" array_name + echo $? # Should output 0. + + str_to_match="6" + is_element_of "${str_to_match}" array_name + echo $? # Should output 1. +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local array_name \ + str_to_match \ + array_name_at \ + array \ + found_match \ + num_elems \ + n +# +#----------------------------------------------------------------------- +# +# Set local variables to appropriate input arguments. +# +#----------------------------------------------------------------------- +# + array_name="$1" + str_to_match="$2" + + array_name_at="$array_name[@]" + array=("${!array_name_at:-}") +# +#----------------------------------------------------------------------- +# +# Initialize the return variable found_match to 1 (false). Then loop +# through the elements of the array and check whether each element is +# equal to str_to_match. Once a match is found, reset found_match to 0 +# (true) and break out of the loop. +# +#----------------------------------------------------------------------- +# + found_match=1 + num_elems=${#array[@]} + for (( n=0; n<${num_elems}; n++ )); do + if [ "${array[$n]}" = "${str_to_match}" ]; then + found_match=0 + break + fi + done +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Return the variable found_match. +# +#----------------------------------------------------------------------- +# + return ${found_match} + +} + diff --git a/ush/bash_utils/print_input_args.sh b/ush/bash_utils/print_input_args.sh new file mode 100644 index 0000000000..d5ba5bd53c --- /dev/null +++ b/ush/bash_utils/print_input_args.sh @@ -0,0 +1,192 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that prints to stdout the names and val- +# ues of a specified list of variables that are the valid arguments to +# the script or function that calls this function. It is mainly used +# for debugging to check that the argument values passed to the calling +# script/function have been set correctly. Note that if a global varia- +# ble named VERBOSE is not defined, the message will be printed out. If +# a global variable named VERBOSE is defined, then the message will be +# printed out only if VERBOSE is set to TRUE. +# +#----------------------------------------------------------------------- +# +function print_input_args() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Get information about the script or function that calls this function. +# Note that caller_name will be set as follows: +# +# 1) If the caller is a function, caller_name will be set to the name of +# that function. +# 2) If the caller is a sourced script, caller_name will be set to +# "script". Note that a sourced script cannot be the top level +# script since by defintion, it is sourced by another script or func- +# tion. +# 3) If the caller is the top-level script, caller_name will be set to +# "main". +# +# Thus, if caller_name is set to "script" or "main", the caller is a +# script, and if it is set to anything else, the caller is a function. +# +#----------------------------------------------------------------------- +# + local caller_fp=$( $READLINK -f "${BASH_SOURCE[1]}" ) + local caller_fn=$( basename "${caller_fp}" ) + local caller_dir=$( dirname "${caller_fp}" ) + local caller_name="${FUNCNAME[1]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 1 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} array_name_valid_caller_args + +where array_name_valid_caller_args is the name of the array containing +the names of valid arguments that can be passed to the calling script or +function. +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local array_name_valid_caller_args \ + valid_caller_args \ + script_or_function \ + msg \ + num_valid_args \ + i \ + line +# +#----------------------------------------------------------------------- +# +# Get the array containing the list of valid argument names that can be +# passed to the calling script/function. Note that if this is set to an +# empty array in the calling script/function [e.g. using the notation +# some_array=()], then it will (for whatever reason) not be defined in +# the scope of this function. For this reason, we need the if-statement +# below to check for this case. Then get the number of valid arguments. +# +#----------------------------------------------------------------------- +# + array_name_valid_caller_args="$1" + valid_arg_names_0th="${array_name_valid_caller_args}[0]" + if [ ${!valid_arg_names_0th:-"__unset__"} = "__unset__" ]; then + valid_caller_args=() + else + valid_caller_args_at="${array_name_valid_caller_args}[@]" + valid_caller_args=("${!valid_caller_args_at}") + fi + num_valid_caller_args="${#valid_caller_args[@]}" +# +#----------------------------------------------------------------------- +# +# Set the message to print to stdout. Note that if the number of valid +# arguments is zero, then we simply print out a message stating this fact. +# +#----------------------------------------------------------------------- +# + if [ "${caller_name}" = "main" ] || \ + [ "${caller_name}" = "script" ]; then + script_or_function="the script" + else + script_or_function="function \"${caller_name}\"" + fi + + if [ ${num_valid_caller_args} -eq 0 ]; then + + msg=" +No arguments have been passed to ${script_or_function} in file + + \"${caller_fp}\" +" + + else + + msg=" +The arguments to ${script_or_function} in file + + \"${caller_fp}\" + +have been set as follows: +" + + for (( i=0; i<${num_valid_caller_args}; i++ )); do + line=$( declare -p "${valid_caller_args[$i]}" ) + msg=$( printf "%s\n%s" "$msg" " $line" ) + done + + fi +# +#----------------------------------------------------------------------- +# +# If a global variable named DEBUG is not defined, print out the message. +# If it is defined, print out the message only if DEBUG is set to "TRUE". +# +#----------------------------------------------------------------------- +# + if [ -z ${DEBUG+x} ]; then + print_info_msg "$msg" + else + print_info_msg "$DEBUG" "$msg" + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/print_msg.sh b/ush/bash_utils/print_msg.sh new file mode 100644 index 0000000000..d837329421 --- /dev/null +++ b/ush/bash_utils/print_msg.sh @@ -0,0 +1,320 @@ +# +#----------------------------------------------------------------------- +# +# This file defines functions used in printing formatted output to std- +# out (e.g. informational and error messages). +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Function to print informational messages using printf. +# +#----------------------------------------------------------------------- +# +function print_info_msg() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Get information about the script or function that calls this function. +# Note that caller_name will be set as follows: +# +# 1) If the caller is a function, caller_name will be set to the name of +# that function. +# 2) If the caller is a sourced script, caller_name will be set to +# "script". Note that a sourced script cannot be the top level +# script since by defintion, it is sourced by another script or func- +# tion. +# 3) If the caller is the top-level script, caller_name will be set to +# "main". +# +# Thus, if caller_name is set to "script" or "main", the caller is a +# script, and if it is set to anything else, the caller is a function. +# +#----------------------------------------------------------------------- +# + local caller_fp=$( $READLINK -f "${BASH_SOURCE[1]}" ) + local caller_fn=$( basename "${caller_fp}" ) + local caller_dir=$( dirname "${caller_fp}" ) + local caller_name="${FUNCNAME[1]}" +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local verbose \ + info_msg +# +#----------------------------------------------------------------------- +# +# If one argument is supplied, we assume it is the message to print out. +# between informational lines that are always printed. +# +#----------------------------------------------------------------------- +# + if [ "$#" -eq 1 ]; then + + verbose="TRUE" + info_msg="$1" + + elif [ "$#" -eq 2 ]; then + + verbose="$1" + info_msg="$2" +# +#----------------------------------------------------------------------- +# +# If no arguments or more than two arguments are supplied, print out a +# usage message and exit. +# +#----------------------------------------------------------------------- +# + else + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} [verbose] info_msg + +where the arguments are defined as follows: + + verbose: + This is an optional argument. If set to \"TRUE\", info_msg will be + printed to stdout. Otherwise, info_msg will not be printed. + + info_msg: + This is the informational message to print to stdout. + +This function prints an informational message to stdout. If one argu- +ment is passed in, then that argument is assumed to be info_msg and is +printed. If two arguments are passed in, then the first is assumed to +be verbose and the second info_msg. In this case, info_msg gets printed +only if verbose is set to \"TRUE\". +" + + fi +# +#----------------------------------------------------------------------- +# +# If verbose is set to "TRUE", print out the message. +# +#----------------------------------------------------------------------- +# + if [ "$verbose" = "TRUE" ]; then + printf "%s\n" "${info_msg}" + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 +} + + + + +# +#----------------------------------------------------------------------- +# +# Function to print out an error message to stderr using printf and then +# exit. +# +#----------------------------------------------------------------------- +# +function print_err_msg_exit() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Get information about the script or function that calls this function. +# Note that caller_name will be set as follows: +# +# 1) If the caller is a function, caller_name will be set to the name of +# that function. +# 2) If the caller is a sourced script, caller_name will be set to +# "script". Note that a sourced script cannot be the top level +# script since by defintion, it is sourced by another script or func- +# tion. +# 3) If the caller is the top-level script, caller_name will be set to +# "main". +# +# Thus, if caller_name is set to "script" or "main", the caller is a +# script, and if it is set to anything else, the caller is a function. +# +#----------------------------------------------------------------------- +# + local caller_fp=$( $READLINK -f "${BASH_SOURCE[1]}" ) + local caller_fn=$( basename "${caller_fp}" ) + local caller_dir=$( dirname "${caller_fp}" ) + local caller_name="${FUNCNAME[1]}" +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local msg_header \ + msg_footer \ + err_msg +# +#----------------------------------------------------------------------- +# +# Set the message header and footer. +# +#----------------------------------------------------------------------- +# + if [ "${caller_name}" = "main" ] || \ + [ "${caller_name}" = "script" ]; then + + msg_header=$( printf "\n\ +ERROR: + From script: \"${caller_fn}\" + Full path to script: \"${caller_fp}\" +" + ) + + else + + msg_header=$( printf "\n\ +ERROR: + From function: \"${caller_name}\" + In file: \"${caller_fn}\" + Full path to file: \"${caller_fp}\" +" + ) + + fi + + msg_footer=$( printf "\nExiting with nonzero status." ) +# +#----------------------------------------------------------------------- +# +# Check number of arguments and, if necessary, print out a usage message +# and exit. +# +#----------------------------------------------------------------------- +# + if [ "$#" -gt 1 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} err_msg + +where err_msg is an optional error message to print to stderr. Note +that a header and a footer are always added to err_msg. Thus, if err_- +msg is not specified, the message that is printed will consist of only +the header and footer. +" +# +#----------------------------------------------------------------------- +# +# If an argument is listed, set err_msg to that argument. Otherwise, +# set it to a null string. Then print out the complete error message to +# stderr and exit. +# +#----------------------------------------------------------------------- +# + else + + if [ "$#" -eq 0 ]; then + err_msg="" + elif [ "$#" -eq 1 ]; then + err_msg="\n$1" + fi + + printf "${msg_header}${err_msg}${msg_footer}\n" 1>&2 + exit 1 + + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. This statement will not be reached due to the preceeding exit +# statement, but we include it here for completeness (i.e. there should +# be a call to restore_shell_opts that matches a preceeding call to +# save_shell_opts). +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/process_args.sh b/ush/bash_utils/process_args.sh new file mode 100644 index 0000000000..203bdedcf7 --- /dev/null +++ b/ush/bash_utils/process_args.sh @@ -0,0 +1,389 @@ +# +#----------------------------------------------------------------------- +# +# This function processes a list of variable name and value pairs passed +# to it as a set of arguments, starting with the second argument. We +# refer to these pairs as argument-value pairs (or "arg-val" pairs for +# short) because the variable names in these pairs represent the names +# of arguments to the script or function that calls this function (which +# we refer to here as the "caller"). The first argument to this func- +# tion being the name of an array that contains a list of valid argument +# names that the caller is allowed to accept. Each arg-val pair must +# have the form +# +# ARG_NAME=VAR_VALUE +# +# where ARG_NAME is the name of an argument and VAR_VALUE is the value +# to set that argument to. For each arg-val pair, this function creates +# a global variable named ARG_NAME and assigns to it the value VAR_VAL- +# UE. +# +# The purpose of this function is to provide a mechanism by which a pa- +# rent script, say parent.sh, can pass variable values to a child script +# or function, say child.sh, that makes it very clear which arguments of +# child.sh are being set and to what values. For example, parent.sh can +# call child.sh as follows: +# +# ... +# child.sh arg3="Hello" arg2="bye" arg4=("this" "is" "an" "array") +# ... +# +# Then child.sh can use this function (process_args) as follows to pro- +# cess the arg-val pairs passed to it: +# +# ... +# valid_args=( "arg1" "arg2" "arg3" "arg4" ) +# process_args valid_args "$@" +# ... +# +# Here, valid_args is an array that defines or "declares" the argument +# list for child.sh, i.e. it defines the variable names that child.sh is +# allowed to accept as arguments. Its name is passed to process_args as +# the first argument. The "$@" appearing in the call to process_args +# passes to process_args the list of arg-val pairs that parent.sh passes +# to child.sh as the second through N-th arguments. In the example +# above, "$@" represents: +# +# arg3="Hello" arg2="bye" arg4=("this" "is" "an" "array") +# +# After the call to process_args in child.sh, the variables arg1, arg2, +# arg3, and arg4 will be set as follows in child.sh: +# +# arg1="" +# arg2="bye" +# arg3="Hello" +# arg4=("this" "is" "an" "array") +# +# Note that: +# +# 1) The set of arg-val pairs may list only a subset of the list of arg- +# uments declared in valid_args; the unlisted arguments will be set +# to the null string. In the example above, arg1 is set to the null +# string because it is not specified in any of the arg-val pairs in +# the call to child.sh in parent.sh. +# +# 2) The arg-val pairs in the call to child.sh do not have to be in the +# same order as the list of "declared" arguments in child.sh. For +# instance, in the example above, the arg-val pair for arg3 is listed +# before the one for arg2. +# +# 3) An argument can be set to an array by starting and ending the value +# portion of its arg-val pair with opening and closing parentheses, +# repsectively, and listing the elements within (each one in a set of +# double-quotes and separated fromt the next by whitespace). In the +# example above, this is done for arg4. +# +# 4) If the value portion of an arg-val pair contains an argument that +# is not defined in the array valid_args in child.sh, the call to +# process_args in child.sh will result in an error message and exit +# from the caller. +# +#----------------------------------------------------------------------- +# +function process_args() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -lt 1 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} array_name_valid_arg_names \ + arg_val_pair1 \ + ... \ + arg_val_pairN + +where the arguments are defined as follows: + + array_name_valid_arg_names: + The name of the array containing a list of valid argument names. + + arg_val_pair1 ... arg_val_pairN: + A list of N argument-value pairs. These have the form + + arg1=\"val1\" ... argN=\"valN\" + + where each argument name (argI) needs to be in the list of valid argu- + ment names specified in array_name_valid_arg_names. Note that not all + the valid arguments listed in array_name_valid_arg_names need to be + set, and the argument-value pairs can be in any order, i.e. they don't + have to follow the order of arguments listed in valid_arg_names_ar- + ray_name. +" + + fi +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local array_name_valid_arg_names \ + valid_arg_names_at \ + valid_arg_names \ + num_valid_args \ + num_arg_val_pairs \ + i valid_arg_name arg_already_specified \ + arg_val_pair arg_name arg_value is_array \ + err_msg cmd_line +# +#----------------------------------------------------------------------- +# +# Get the array containing the list of valid argument names that can be +# passed to the calling script/function. Note that if this is set to an +# empty array in the calling script/function [e.g. using the notation +# some_array=()], then it will (for whatever reason) not be defined in +# the scope of this function. For this reason, we need the if-statement +# below to check for this case. +# +#----------------------------------------------------------------------- +# + array_name_valid_arg_names="$1" + valid_arg_names_0th="${array_name_valid_arg_names}[0]" + if [ ${!valid_arg_names_0th:-"__unset__"} = "__unset__" ]; then + valid_arg_names=() + else + valid_arg_names_at="${array_name_valid_arg_names}[@]" + valid_arg_names=("${!valid_arg_names_at}") + fi +# +#----------------------------------------------------------------------- +# +# Get the number of valid arguments. Also, set a string containing the +# list of all valid arguments with each one placed in double quotes. +# +#----------------------------------------------------------------------- +# + num_valid_args=${#valid_arg_names[@]} + if [ ${num_valid_args} -eq 0 ]; then + valid_arg_names_str="" + else + valid_arg_names_str=$( printf "\"%s\" " "${valid_arg_names[@]}" ) + fi + +# +# Instead of the if-statement above, the following could be used, but it +# is too difficult to understand... +# +# valid_arg_names_str=$( printf "\"%s\" " ${valid_arg_names[@]+"${valid_arg_names[@]}"} ) + +# +#----------------------------------------------------------------------- +# +# Get the number of argument-value pairs (or arg-val pairs, for short) +# being passed into this function. These consist of all arguments +# starting with the 2nd, so we subtract 1 from the total number of argu- +# ments. +# +#----------------------------------------------------------------------- +# + num_arg_val_pairs=$(( $# - 1 )) +# +#----------------------------------------------------------------------- +# +# Make sure that the number of arg-val pairs is less than or equal to +# the number of valid arguments. +# +#----------------------------------------------------------------------- +# + if [ "${num_arg_val_pairs}" -gt "${num_valid_args}" ]; then + print_err_msg_exit "\ +The number of argument-value pairs specified on the command line (num_- +arg_val_pairs) must be less than or equal to the number of valid argu- +ments (num_valid_args) specified in the array valid_arg_names: + num_arg_val_pairs = ${num_arg_val_pairs} + num_valid_args = ${num_valid_args} + valid_arg_names = ( ${valid_arg_names_str})" + fi +# +#----------------------------------------------------------------------- +# +# If the number of valid arguments is zero, i.e. the array valid_arg_names +# contains no elements, then there are no script/function arguments to +# set. In this case, reset the shell options to what they were before +# entering this function and simply return to the calling script/function. +# +#----------------------------------------------------------------------- +# + if [ ${num_valid_args} -eq 0 ]; then + { restore_shell_opts; } > /dev/null 2>&1 + return + fi +# +#----------------------------------------------------------------------- +# +# Make sure that none of the elements of the array containing the list +# of valid arguments contain spaces or are empty. +# +#----------------------------------------------------------------------- +# + for (( i=0; i<${num_valid_args}; i++ )); do + + valid_arg_name="${valid_arg_names[$i]}" + +# Remove spaces (if any exist) from the current valid argument name. + valid_arg_name_no_spaces=$( \ + printf "%s\n" "${valid_arg_name}" | $SED -r -e 's/[[:space:]]//g' ) + + if [ "${valid_arg_name_no_spaces}" != "${valid_arg_name}" ]; then + print_err_msg_exit "\ +The name of an argument in the list of valid arguments (valid_arg_names) +cannot contain any spaces, but the element with index i=${i} contains at +least one space: + valid_arg_names = ( ${valid_arg_names_str}) + valid_arg_names[$i] = \"${valid_arg_names[$i]}\"" + fi + + if [ -z ${valid_arg_name} ]; then + print_err_msg_exit "\ +The list of valid arguments (valid_arg_names) cannot contain empty elements, +but the element with index i=${i} is empty: + valid_arg_names = ( ${valid_arg_names_str}) + valid_arg_names[$i] = \"${valid_arg_names[$i]}\"" + fi + + done +# +#----------------------------------------------------------------------- +# +# Initialize all valid arguments to the null string. Note that the +# scope of this initialization is global, i.e. the calling script or +# function will be aware of these initializations. Also, initialize +# each element of the array arg_already_specified to "false". This ar- +# ray keeps track of whether each valid argument has already been set +# to a value by an arg-val specification. +# +#----------------------------------------------------------------------- +# + for (( i=0; i<${num_valid_args}; i++ )); do + valid_arg_name="${valid_arg_names[$i]}" + eval ${valid_arg_name}="" + arg_already_specified[$i]="false" + done +# +#----------------------------------------------------------------------- +# +# Loop over the list of arg-val pairs and set argument values. +# +#----------------------------------------------------------------------- +# + for arg_val_pair in "${@:2}"; do + + arg_name=$(echo ${arg_val_pair} | cut -f1 -d=) + arg_value=$(echo ${arg_val_pair} | cut -f2 -d=) +# +# If the first character of the argument's value is an opening parenthe- +# sis and its last character is a closing parenthesis, then the argument +# is an array. Check for this and set the is_array flag accordingly. +# + is_array="false" + if [ "${arg_value:0:1}" = "(" ] && \ + [ "${arg_value: -1}" = ")" ]; then + is_array="true" + fi +# +#----------------------------------------------------------------------- +# +# Make sure that the argument name specified by the current argument- +# value pair is valid. +# +#----------------------------------------------------------------------- +# + err_msg="\ +The specified argument name (arg_name) in the current argument-value +pair (arg_val_pair) is not valid: + arg_val_pair = \"${arg_val_pair}\" + arg_name = \"${arg_name}\"" + check_var_valid_value "arg_name" "valid_arg_names" "${err_msg}" +# +#----------------------------------------------------------------------- +# +# Loop through the list of valid argument names and find the one that +# the current arg-val pair corresponds to. Then set that argument to +# the specified value. +# +#----------------------------------------------------------------------- +# + for (( i=0; i<${num_valid_args}; i++ )); do + + valid_arg_name="${valid_arg_names[$i]}" + if [ "${arg_name}" = "${valid_arg_name}" ]; then +# +# Check whether the current argument has already been set by a previous +# arg-val pair on the command line. If not, proceed to set the argument +# to the specified value. If so, print out an error message and exit +# the calling script. +# + if [ "${arg_already_specified[$i]}" = "false" ]; then + arg_already_specified[$i]="true" + if [ "${is_array}" = "true" ]; then + eval ${arg_name}=${arg_value} + else + eval ${arg_name}=\"${arg_value}\" + fi + else + cmd_line=$( printf "\'%s\' " "${@:1}" ) + print_err_msg_exit "\ +The current argument has already been assigned a value on the command +line: + arg_name = \"${arg_name}\" + cmd_line = ${cmd_line} +Please assign values to arguments only once on the command line." + fi + fi + + done + + done +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/save_restore_shell_opts.sh b/ush/bash_utils/save_restore_shell_opts.sh new file mode 100644 index 0000000000..b561b6cea3 --- /dev/null +++ b/ush/bash_utils/save_restore_shell_opts.sh @@ -0,0 +1,58 @@ +# +#----------------------------------------------------------------------- +# +# This file defines functions used to save and restore the state of the +# shell options. The function save_shell_opts() appends the current set +# of shell options to the end of a global array named shell_opts_array, +# while the function restore_shell_opts() restores the shell options +# stored in the last element of shell_opts_array (and removes that ele- +# ment from the array). +# +#----------------------------------------------------------------------- +# + + +function save_shell_opts() { +# +# Get the current set of shell options and save them in the local varia- +# ble shell_opts. +# + local shell_opts="$(set +o)"$'\n'"set -$-" + shell_opts=${shell_opts//$'\n'/ } + shell_opts=$( printf "%s\n" "$shell_opts" | $SED -r -e "s/set ([+-])/\1/g" ) +# +# Store the current set of shell options in the global array shell_- +# opts_array so we can reuse them later. +# + shell_opts_array+=("${shell_opts}") +# +} +#} > /dev/null 2>&1 # This will redirect both stdout and stderr to null + # even if xtrace is enabled when the function gets + # called. + + +function restore_shell_opts() { +# +# Get the last element of the shell_opts_array global array containing +# a sequense of shell options. We assume here that the last set of op- +# tions saved in this array is the one we want to restore. +# + local shell_opts=${shell_opts_array[*]: -1} +# +# Delete the last element of the global array. +# + local index=("${!shell_opts_array[@]}") + unset 'shell_opts_array[${index[@]: -1}]' +# +# Issue the "set" command followed by the appropriate shell options. +# Note that we don't put double quotes around $shell_opts because that +# would cause the contents of shell_opts to be treated as a single argu- +# ment to "set", which is not what we want. +# + set $shell_opts +# +} +#} > /dev/null 2>&1 # This will redirect both stdout and stderr to null + # even if xtrace is enabled when the function gets + # called. diff --git a/ush/bash_utils/set_bash_param.sh b/ush/bash_utils/set_bash_param.sh new file mode 100644 index 0000000000..dd22206077 --- /dev/null +++ b/ush/bash_utils/set_bash_param.sh @@ -0,0 +1,144 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that replaces placeholder values of vari- +# ables in several different types of files with actual values. +# +#----------------------------------------------------------------------- +# +function set_bash_param() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 3 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} file_full_path param value + +where the arguments are defined as follows: + + file_full_path: + Full path to the file in which the specified parameter's value will be + set. + + param: + Name of the parameter whose value will be set. + + value: + Value to set the parameter to. +" + + fi +# +#----------------------------------------------------------------------- +# +# Set local variables to appropriate input arguments. +# +#----------------------------------------------------------------------- +# + local file_full_path="$1" + local param="$2" + local value="$3" +# +#----------------------------------------------------------------------- +# +# Extract just the file name from the full path. +# +#----------------------------------------------------------------------- +# + local file="${file_full_path##*/}" +# +#----------------------------------------------------------------------- +# +# Print out an informational message. +# +#----------------------------------------------------------------------- +# + print_info_msg "\ +Setting parameter \"$param\" in file \"$file\" to \"$value\" ..." +# +#----------------------------------------------------------------------- +# +# The procedure we use to set the value of the specified parameter de- +# pends on the file the parameter is in. Compare the file name to sev- +# eral known file names and set the regular expression to search for +# (regex_search) and the one to replace with (regex_replace) according- +# ly. See the default configuration file (config_defaults.sh) for defi- +# nitions of the known file names. +# +#----------------------------------------------------------------------- +# + local regex_search="(^\s*$param=)(\".*\")?([^ \"]*)?(\(.*\))?(\s*[#].*)?" + local regex_replace="\1\"$value\"\5" +# +#----------------------------------------------------------------------- +# +# Use grep to determine whether regex_search exists in the specified +# file. If so, perform the regex replacement using sed. If not, print +# out an error message and exit. +# +#----------------------------------------------------------------------- +# + grep -q -E "${regex_search}" "${file_full_path}" || { \ + print_err_msg_exit "\ +Specified file (file_full_path) does not contain the searched-for regu- +lar expression (regex_search): + file_full_path = \"${file_full_path}\" + param = \"$param\" + value = \"$value\" + regex_search = ${regex_search}" + }; + + $SED -i -r -e "s%${regex_search}%${regex_replace}%" "${file_full_path}" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/bash_utils/set_file_param.sh b/ush/bash_utils/set_file_param.sh new file mode 100644 index 0000000000..3e0d133494 --- /dev/null +++ b/ush/bash_utils/set_file_param.sh @@ -0,0 +1,195 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that replaces placeholder values of vari- +# ables in several different types of files with actual values. +# +#----------------------------------------------------------------------- +# +function set_file_param() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# + if [ "$#" -ne 3 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Function name: \"${func_name}\" + Number of arguments specified: $# + +Usage: + + ${func_name} file_fp param value + +where the arguments are defined as follows: + + file_fp: + Full path to the file in which the specified parameter's value will be + set. + + param: + Name of the parameter whose value will be set. + + value: + Value to set the parameter to. +" + + fi +# +#----------------------------------------------------------------------- +# +# Set local variables to appropriate input arguments. +# +#----------------------------------------------------------------------- +# + local file_fp="$1" + local param="$2" + local value="$3" +# +#----------------------------------------------------------------------- +# +# Extract just the file name from the full path. +# +#----------------------------------------------------------------------- +# + local file="${file_fp##*/}" +# +#----------------------------------------------------------------------- +# +# If VERBOSE is set to "TRUE", print out an informational message. +# +#----------------------------------------------------------------------- +# + print_info_msg "$DEBUG" "\ +Setting parameter \"$param\" in file \"$file\" to \"$value\" ..." +# +#----------------------------------------------------------------------- +# +# The procedure we use to set the value of the specified parameter de- +# pends on the file the parameter is in. Compare the file name to sev- +# eral known file names and set the regular expression to search for +# (regex_search) and the one to replace with (regex_replace) according- +# ly. See the default configuration file (config_defaults.sh) for defi- +# nitions of the known file names. +# +#----------------------------------------------------------------------- +# + local regex_search="" + local regex_replace="" + + case $file in +# + "${WFLOW_XML_FN}") + regex_search="(^\s*.*)" + regex_replace="\1$value\3" + ;; +# + "${RGNL_GRID_NML_FN}") + regex_search="^(\s*$param\s*=)(.*)" + regex_replace="\1 $value" + ;; +# + "${FV3_NML_FN}") + regex_search="^(\s*$param\s*=)(.*)" + regex_replace="\1 $value" + ;; +# + "${DIAG_TABLE_FN}") + regex_search="(.*)(<$param>)(.*)" + regex_replace="\1$value\3" + ;; +# + "${MODEL_CONFIG_FN}") + regex_search="^(\s*$param:\s*)(.*)" + regex_replace="\1$value" + ;; +# + "${GLOBAL_VAR_DEFNS_FN}") + regex_search="(^\s*$param=)(\".*\")?([^ \"]*)?(\(.*\))?(\s*[#].*)?" + regex_replace="\1$value\5" +# set_bash_param "${file_fp}" "$param" "$value" + ;; +# +#----------------------------------------------------------------------- +# +# If "file" is set to a disallowed value, print out an error message and +# exit. +# +#----------------------------------------------------------------------- +# + *) + print_err_msg_exit "\ +The regular expressions for performing search and replace have not been +specified for this file: + file = \"$file\"" + ;; +# + esac +# +#----------------------------------------------------------------------- +# +# Use grep to determine whether regex_search exists in the specified +# file. If so, perform the regex replacement using sed. If not, print +# out an error message and exit. +# +#----------------------------------------------------------------------- +# + grep -q -E "${regex_search}" "${file_fp}" + + if [ $? -eq 0 ]; then + $SED -i -r -e "s%${regex_search}%${regex_replace}%" "${file_fp}" + else + print_err_msg_exit "\ +The specified file (file_fp) does not contain the searched-for regular +expression (regex_search): + file_fp = \"${file_fp}\" + param = \"$param\" + value = \"$value\" + regex_search = ${regex_search}" + fi +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/calculate_cost.py b/ush/calculate_cost.py new file mode 100755 index 0000000000..010b892232 --- /dev/null +++ b/ush/calculate_cost.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +import os +import unittest +import argparse + +from python_utils import set_env_var, import_vars, export_vars, load_config_file, flatten_dict + +from set_predef_grid_params import set_predef_grid_params +from set_gridparams_ESGgrid import set_gridparams_ESGgrid +from set_gridparams_GFDLgrid import set_gridparams_GFDLgrid + +def calculate_cost(config_fn): + global PREDEF_GRID_NAME, QUILTING, GRID_GEN_METHOD + + #import all environment variables + import_vars() + + #get grid config parameters (predefined or custom) + if PREDEF_GRID_NAME: + set_env_var('QUILTING',False) + set_predef_grid_params() + import_vars() + else: + cfg_u = load_config_file(config_fn) + cfg_u = flatten_dict(cfg_u) + import_vars(dictionary=cfg_u) + + #number of gridpoints (nx*ny) depends on grid generation method + if GRID_GEN_METHOD == "GFDLgrid": + (\ + LON_CTR,LAT_CTR,NX,NY,NHW,STRETCH_FAC, + ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG \ + ) = \ + set_gridparams_GFDLgrid( \ + lon_of_t6_ctr=GFDLgrid_LON_T6_CTR, \ + lat_of_t6_ctr=GFDLgrid_LAT_T6_CTR, \ + res_of_t6g=GFDLgrid_NUM_CELLS, \ + stretch_factor=GFDLgrid_STRETCH_FAC, \ + refine_ratio_t6g_to_t7g=GFDLgrid_REFINE_RATIO, \ + istart_of_t7_on_t6g=GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G, \ + iend_of_t7_on_t6g=GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G, \ + jstart_of_t7_on_t6g=GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G, \ + jend_of_t7_on_t6g=GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G) + + elif GRID_GEN_METHOD == "ESGgrid": + (\ + LON_CTR,LAT_CTR,NX,NY,PAZI, + NHW,STRETCH_FAC,DEL_ANGLE_X_SG,DEL_ANGLE_Y_SG, + NEG_NX_OF_DOM_WITH_WIDE_HALO, + NEG_NY_OF_DOM_WITH_WIDE_HALO \ + ) = \ + set_gridparams_ESGgrid( \ + lon_ctr=ESGgrid_LON_CTR, \ + lat_ctr=ESGgrid_LAT_CTR, \ + nx=ESGgrid_NX, \ + ny=ESGgrid_NY, \ + pazi=ESGgrid_PAZI, \ + halo_width=ESGgrid_WIDE_HALO_WIDTH, \ + delx=ESGgrid_DELX, \ + dely=ESGgrid_DELY) + + cost = [DT_ATMOS, NX*NY] + + #reference grid (6-hour forecast on RRFS_CONUS_25km) + PREDEF_GRID_NAME="RRFS_CONUS_25km" + + export_vars() + set_predef_grid_params() + import_vars() + cost.extend([DT_ATMOS, ESGgrid_NX*ESGgrid_NY]) + + return cost + +#interface +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=\ + 'Calculates parameters needed for calculating cost.') + parser.add_argument('--cfg','-c',dest='cfg',required=True, + help='config file containing grip params') + args = parser.parse_args() + + params = calculate_cost(args.cfg) + print(' '.join(map(str,params))) + +class Testing(unittest.TestCase): + def test_calculate_cost(self): + USHDIR = os.path.dirname(os.path.abspath(__file__)) + config_fn = os.path.join(USHDIR, "config.community.sh") + params = calculate_cost(config_fn) + self.assertCountEqual(params, [36, 1987440, 36, 28689]) + + def setUp(self): + set_env_var('DEBUG',False) + set_env_var('PREDEF_GRID_NAME',"RRFS_CONUS_3km") + set_env_var('DT_ATMOS',36) + set_env_var('LAYOUT_X',18) + set_env_var('LAYOUT_Y',36) + set_env_var('BLOCKSIZE',28) + set_env_var('QUILTING',False) + set_env_var('RADIUS_EARTH',6371200.0) + set_env_var('DEGS_PER_RADIAN',57.2957795131) + diff --git a/ush/check_expt_config_vars.sh b/ush/check_expt_config_vars.sh new file mode 100644 index 0000000000..c55a392295 --- /dev/null +++ b/ush/check_expt_config_vars.sh @@ -0,0 +1,110 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that checks that all experiment variables +# set in the user-specified experiment configuration file are defined (by +# being assigned default values) in the default experiment configuration +# file. If a variable is found in the former that is not defined in the +# latter, this function exits with an error message. +# +# This check is performed in order to prevent the user from defining +# arbitrary variables in the user-specified configuration file; the +# latter should be used to specify only varaibles that have already been +# defined in the default configuration file. +# +# Arguments are as follows: +# +# default_config_fp: +# The relative or full path to the default experiment configuration file. +# +# config_fp: +# The relative or full path to the user-specified experiment configuration +# file. +# +#----------------------------------------------------------------------- +# +function check_expt_config_vars() { + + . ${scrfunc_dir}/source_util_funcs.sh + + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + + local valid_args=( \ + "default_config_fp" \ + "config_fp" \ + ) + process_args valid_args "$@" + print_input_args "valid_args" + + local var_list_default \ + var_list_user \ + crnt_line \ + var_name \ + regex_search + # + # Get the list of variable definitions, first from the default experiment + # configuration file and then from the user-specified experiment + # configuration file. + # + get_bash_file_contents fp="${default_config_fp}" \ + outvarname_contents="var_list_default" + + get_bash_file_contents fp="${config_fp}" \ + outvarname_contents="var_list_user" + # + # Loop through each line/variable in var_list_user. For each line, + # extract the the name of the variable that is being set (say VAR) and + # check that this variable is set somewhere in the default configuration + # file by verifying that a line that starts with "VAR=" exists in + # var_list_default. + # + while read crnt_line; do + # + # Note that a variable name will be found only if the equal sign immediately + # follows the variable name. + # + var_name=$( printf "%s" "${crnt_line}" | $SED -n -r -e "s/^([^ =\"]*)=.*/\1/p" ) + + if [ -z "${var_name}" ]; then + + print_info_msg " +The current line (crnt_line) of the user-specified experiment configuration +file (config_fp) does not contain a variable name (i.e. var_name is empty): + config_fp = \"${config_fp}\" + crnt_line = \"${crnt_line}\" + var_name = \"${var_name}\" +Skipping to next line." + + else + # + # Use grep to search for the variable name (followed by an equal sign, + # all at the beginning of a line) in the list of variables in the default + # configuration file. + # + # Note that we use a herestring to input into grep the list of variables + # in the default configuration file. grep will return with a zero status + # if the specified string (regex_search) is not found in the default + # variables list and a nonzero status otherwise. Note also that we + # redirect the output of grep to null because we are only interested in + # its exit status. + # + regex_search="^${var_name}=" + grep "${regex_search}" <<< "${var_list_default}" > /dev/null 2>&1 || \ + print_err_msg_exit "\ +The variable (var_name) defined on the current line (crnt_line) of the +user-specified experiment configuration file (config_fp) does not appear +in the default experiment configuration file (default_config_fp): + config_fp = \"${config_fp}\" + default_config_fp = \"${default_config_fp}\" + crnt_line = \"${crnt_line}\" + var_name = \"${var_name}\" +Please assign a default value to this variable in the default configuration +file and rerun." + + fi + + done <<< "${var_list_user}" + + { restore_shell_opts; } > /dev/null 2>&1 + +} diff --git a/ush/check_ruc_lsm.py b/ush/check_ruc_lsm.py new file mode 100644 index 0000000000..fdf288f30a --- /dev/null +++ b/ush/check_ruc_lsm.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import os +import unittest + +from python_utils import set_env_var, print_input_args, \ + load_xml_file, has_tag_with_value + +def check_ruc_lsm(ccpp_phys_suite_fp): + """ This file defines a function that checks whether the RUC land surface + model (LSM) parameterization is being called by the selected physics suite. + + Args: + ccpp_phys_suite_fp: full path to CCPP physics suite xml file + Returns: + Boolean + """ + + print_input_args(locals()) + + tree = load_xml_file(ccpp_phys_suite_fp) + has_ruc = has_tag_with_value(tree, "scheme", "lsm_ruc") + return has_ruc + +class Testing(unittest.TestCase): + def test_check_ruc_lsm(self): + self.assertTrue( check_ruc_lsm(ccpp_phys_suite_fp=f"test_data{os.sep}suite_FV3_GSD_SAR.xml") ) + def setUp(self): + set_env_var('DEBUG',True) + diff --git a/ush/cmp_expt_to_baseline.sh b/ush/cmp_expt_to_baseline.sh new file mode 100755 index 0000000000..b7459593ab --- /dev/null +++ b/ush/cmp_expt_to_baseline.sh @@ -0,0 +1,411 @@ +#!/bin/sh -l +#----------------------------------------------------------------------- +# Description: Compare experiment to a baseline. Can be run with one +# or two command line arguments. With one argument, it +# assumes this is your experiment directory and creates a +# directory for the baseline based on your experiment's +# setup (by reading in the var_defns.sh file in your ex- +# periment directory). With two arguments, it takes the +# first one to be your experiment directory and the second +# the baseline directory. +# +# Usage: ./cmp_expt_to_baseline.sh ${expt_dir} [${baseline_dir}] +# +# Assumptions: RUNDIR1 and RUNDIR2 have the same subdirectory structure. +# nccmp is available as module load +# Script has only been tested on theia +#----------------------------------------------------------------------- + +# Do these need to be machine specific, e.g. by using modulefiles? +module load intel +module load nccmp +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Source bash utility functions. +# +#----------------------------------------------------------------------- +# +. ${scrfunc_dir}/source_util_funcs.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Process arguments. +# +#----------------------------------------------------------------------- +# +if [ $# -eq 0 ] || [ $# -gt 2 ]; then + + printf " +ERROR from script ${scrfunc_fn}: +Only 1 or 2 arguments may be specified. Usage: + + > ${scrfunc_fn} expt_dir [baseline_dir] + +where expt_dir is the experiment directory and baseline_dir is an op- +tional baseline directory. +Exiting with nonzero exit code. +" + exit 1 + +fi +# +#----------------------------------------------------------------------- +# +# Set the experiment directory and make sure that it exists. +# +#----------------------------------------------------------------------- +# +expt_dir="$1" +if [ ! -d "${expt_dir}" ]; then + print_err_msg_exit "\ +The specified experiment directory (expt_dir) does not exist: + expt_dir = \"$expt_dir\" +Exiting script with nonzero return code." +fi +# +#----------------------------------------------------------------------- +# +# Read the variable definitions file in the experiment directory. +# +#----------------------------------------------------------------------- +# +. ${expt_dir}/var_defns.sh +CDATE="${DATE_FIRST_CYCL[0]}${CYCL_HRS[0]}" +# +#----------------------------------------------------------------------- +# +# If two arguments are specified, then take the second one to be the di- +# rectory for the baseline. If only one argument is specified, form a +# baseline directory name from the parameters used in the experiment di- +# rectory. If any other number of arguments is specified, print out an +# error message and exit. +# +#----------------------------------------------------------------------- +# +if [ $# -eq 2 ]; then + + baseline_dir="$2" + +else + + baseline_dir="/scratch2/BMC/det/regional_FV3/regr_baselines" + if [ -n ${PREDEF_GRID_NAME} ]; then + baseline_dir="${baseline_dir}/${PREDEF_GRID_NAME}" + else + printf "\ +The experiment must be run on one of the predefined domains. Thus, +PREDEF_GRID_NAME cannot be empty: + PREDEF_GRID_NAME = \"${PREDEF_GRID_NAME}\" +Exiting script with nonzero return code. +" + exit 1 + fi + baseline_dir="${baseline_dir}/${CCPP_PHYS_SUITE}phys" + baseline_dir="${baseline_dir}/ICs-${EXTRN_MDL_NAME_ICS}_LBCs-${EXTRN_MDL_NAME_LBCS}" + baseline_dir="${baseline_dir}/$CDATE" + +fi +# +# Make sure that the baseline directory exists. +# +if [ ! -d "${baseline_dir}" ]; then + printf "\n +A baseline directory corresponding to the configuration used in the ex- +periment directory (expt_dir) does not exist: + expt_dir = \"$expt_dir\" + baseline_dir (missing) = \"$baseline_dir\" +Exiting script with nonzero return code." + exit 1 +fi +# +#----------------------------------------------------------------------- +# +# Print out the experiment and baseline directories. +# +#----------------------------------------------------------------------- +# +print_info_msg " +The experiment and baseline directories are: + expt_dir = \"$expt_dir\" + baseline_dir = \"$baseline_dir\"" +# +#----------------------------------------------------------------------- +# +# Set the array containing the names of the subdirectories that will be +# compared. +# +#----------------------------------------------------------------------- +# +# This list should also include $CDATE/postprd since that contains the +# post-processed grib files, but those files' names don't end in a +# standard file extension, e.g. .grb, etc. Must look into this more. +# "grid" \ +# "orog" \ +# "sfc_climo" \ +subdirs=( "." \ + "fix_lam" \ + "$CDATE/${EXTRN_MDL_NAME_ICS}/ICS" \ + "$CDATE/${EXTRN_MDL_NAME_LBCS}/LBCS" \ + "$CDATE/INPUT" \ + "$CDATE/RESTART" \ + "$CDATE" \ + ) +# +#----------------------------------------------------------------------- +# +# Set the array that defines the file extensions to compare in each sub- +# directory. +# +#----------------------------------------------------------------------- +# +#declare -a file_extensions=( "nc" "nemsio" "grb" ) +declare -a file_extensions=( "nc" "grb" ) +#declare -a file_extensions=( "nc" ) +# +#----------------------------------------------------------------------- +# +# Initialize file counts to 0. These are defined as follows: +# +# nfiles_total: +# The number of files in the experiment directory that we attempted to +# compare to the corresponding file in the baseline directory. +# +# nfiles_missing: +# The number of files (out of nfiles_total) that are missing from the +# baseline directory. +# +# nfiles_different: +# The number of files that exist in both the experiment and baseline di- +# rectories and are different. +# +#----------------------------------------------------------------------- +# +nfiles_total=0 +nfiles_missing=0 +nfiles_different=0 +# +#----------------------------------------------------------------------- +# +# Loop over the specified subdirectories. For each subdirectory, com- +# pare files having the specified extensions for the experiment and the +# baseline. +# +#----------------------------------------------------------------------- +# +for subdir in "${subdirs[@]}"; do + + msg="Comparing files in subdirectory \"$subdir\" ..." + msglen=${#msg} + printf "\n%s\n" "$msg" + printf "%0.s=" $(seq 1 $msglen) + printf "\n" + + for file_ext in "${file_extensions[@]}"; do + + msg="Comparing files with extension \"${file_ext}\" ..." + msglen=${#msg} + printf "\n%s\n" " $msg" + printf " " + printf "%0.s~" $(seq 1 $msglen) + printf "\n" + +# cmp_files_btwn_dirs "$expt_dir/$subdir" "${baseline_dir}/$subdir" "${ext}" || { \ +# printf " +#Call to file comparison function failed. Exiting with nonzero exit code. +#"; +# exit 1; } +# +#----------------------------------------------------------------------- +# +# +#----------------------------------------------------------------------- +# + if [ "$file_ext" = "nemsio" ] || [ "$file_ext" = "grb" ]; then + compare_tool="cmp" + elif [ "$file_ext" = "nc" ]; then + compare_tool="nccmp -d" + else + printf "\ +The file comparison tool to use for this file extension has not been +specified: + file_ext = \"${file_ext}\" +Please specify the compare tool and rerun. +Exiting script with nonzero exit code. +" + fi +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# + cd ${expt_dir}/$subdir + num_files=$( ls -1 *.${file_ext} 2>/dev/null | wc -l ) +# num_files=$( count_files *.${file_ext} 2>/dev/null | wc -l ) + printf " + Number of files with extension \"${file_ext}\" in subdirectory \"$subdir\" + of the experiment directory is: ${num_files} +" + + if [ "${num_files}" -eq "0" ]; then + printf "\ + Skipping comparison of files with extension \"${file_ext}\" in this subdirectory. +" + else + + fn_len_max=0 + for fn in *.${file_ext}; do + fn_len=${#fn} + if [ ${fn_len} -gt ${fn_len_max} ]; then + fn_len_max=${fn_len} + fi + done + compare_msg_pre=" Comparing file " + msg_len_max=$(( fn_len_max + ${#compare_msg_pre} )) + + for fn in *.${file_ext}; do + + nfiles_total=$(( $nfiles_total + 1 )) + + fn1="$fn" + fn2="${baseline_dir}/$subdir/$fn" + if [ ! -e "$fn2" ]; then # Check if file exists in baseline directory. + + printf " + File specified by fn exists in subdirectory \"$subdir\" of the + experiment directory but not in that of the the baseline directory: + fn = \"$fn\" + subdir = \"$subdir\" + Incrementing missing file count and moving to next file or sub- + directory.\n" + nfiles_missing=$(( nfiles_missing + 1 )) + + else + + msg="${compare_msg_pre}\"$fn\"" + msg_len="${#msg}" + num_dots=$(( msg_len_max - msg_len + 7 )) + dots_str=$( printf "%0.s." $(seq 1 ${num_dots} ) ) + msg="${msg} ${dots_str}" + + printf "$msg" + eval_output=$( eval ${compare_tool} $fn1 $fn2 2>&1 ) + + if [ $? -eq 0 ]; then + printf " Files are identical.\n" + else + printf " FILES ARE DIFFERENT!!!\n" + printf "\ + Error message from \"${compare_tool}\" command is: +${eval_output} +" + nfiles_different=$(( $nfiles_different + 1 )) + fi + + fi + + done # Loop over files of the same extension. + + fi # Number of files > 0 + + done # Loop over file extensions. + +done # Loop over subdirectories. +# +#----------------------------------------------------------------------- +# +# Print out final results. +# +#----------------------------------------------------------------------- +# +msg="Summary of regression test:" +msglen=${#msg} +msg="$msg" +printf "\n%s\n" "$msg" +printf "%0.s=" $(seq 1 $msglen) +printf "\n" + +file_extensions_str=$(printf "\"%s\" " "${file_extensions[@]}"); +file_extensions_str="( ${file_extensions_str})" + +printf " + expt_dir = \"$expt_dir\" + baseline_dir = \"$baseline_dir\" + + file_extensions = ${file_extensions_str} + nfiles_total = ${nfiles_total} + nfiles_missing = ${nfiles_missing} + nfiles_different = ${nfiles_different} + +where + + file_extensions: + Array containing the file extensions considered when comparing files. + Only files ending with one of these extensions are compared. + + nfiles_total: + The number of files in the experiment directory that we attempted to + compare to the corresponding file in the baseline directory. + + nfiles_missing: + The number of files (out of nfiles_total) that are missing from the + baseline directory. + + nfiles_different: + The number of files that exist in both the experiment and baseline di- + rectories and are different. + +" + +if [ ${nfiles_missing} -eq 0 ] && [ ${nfiles_different} -eq 0 ]; then + result_str="PASS :)" + exit_code=0 +else + + exit_code=1 + if [ ${nfiles_missing} -ne 0 ] && [ ${nfiles_different} -eq 0 ]; then + result_str="FAIL (due to missing files)" + elif [ ${nfiles_missing} -eq 0 ] && [ ${nfiles_different} -ne 0 ]; then + result_str="FAIL (due to differing files)" + elif [ ${nfiles_missing} -ne 0 ] && [ ${nfiles_different} -ne 0 ]; then + result_str="FAIL (due to missing and differing files)" + fi + +fi + +printf "Final result of regression test: ${result_str}\n" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + +exit ${exit_code} + diff --git a/ush/cmp_rundirs_ncfiles.sh b/ush/cmp_rundirs_ncfiles.sh new file mode 100755 index 0000000000..c650454877 --- /dev/null +++ b/ush/cmp_rundirs_ncfiles.sh @@ -0,0 +1,100 @@ +#!/bin/sh -l + +module load nccmp +# +#----------------------------------------------------------------------- +# +# Define generic function to compare NetCDF files in two directories. +# +#----------------------------------------------------------------------- +# +function cmp_ncfiles_one_dir() { + + local dir1="$1" + local dir2="$2" + local subdir="$3" + local fileext="$4" + + local fn="" + local msg="" + + cd $dir1/$subdir + + for fn in *.$fileext; do + + fn1="$fn" + if [ -f "$fn1" ] && [ ! -L "$fn1" ]; then # Check if regular file and not a symlink. + + fn2="$dir2/$subdir/$fn" + if [ -e "$fn2" ]; then # Check if file exists. + + if [ -f "$fn2" ] && [ ! -L "$fn2" ]; then # Check if regular file and not a symlink. + + printf "\nComparing file \"$fn\" in subdirectory \"$subdir\" ...\n" + nccmp -d $fn1 $fn2 +# nccmp -dS $fn1 $fn2 +# nccmp -d -t 1e-3 $fn1 $fn2 +# nccmp -d --precision='%g10.5' $fn1 $fn2 + + if [ $? = 0 ]; then + msg=$( printf "%s" "Files are identical." ) + elif [ $? = 1 ]; then + msg=$( printf "%s" "===>>> FILES ARE DIFFERENT!!!" ) + else + msg=$( printf "%s" "FATAL ERROR. Exiting script." ) + exit 1 + fi + + printf "%s\n" "$msg" + + else + printf "\n%s\n" "File \"$fn\" in \"$dir2/$subdir\" is a symbolic link. Skipping." + fi + + else + printf "\n%s\n" "File \"$fn\" does not exist in \"$dir2/$subdir\"." + printf "\n%s\n" "Exiting script." + exit 1 + fi + + else + printf "\n%s\n" "File \"$fn\" in \"$dir1/$subdir\" is a symbolic link. Skipping." + fi + + done + +} +# +#----------------------------------------------------------------------- +# +# Get the two run directories to compare from command-line arguments. +# Then compare NetCDF files in the run directories as well as in their +# INPUT subdirectories. +# +#----------------------------------------------------------------------- +# +#set -x + +rundir1="$( readlink -f $1 )" +rundir2="$( readlink -f $2 )" + +printf "\n" +printf "%s\n" "rundir1 = \"$rundir1\"" +printf "%s\n" "rundir2 = \"$rundir2\"" + +subdirs=("INPUT" ".") + +for subdir in "${subdirs[@]}"; do + + msg=$( printf "%s" "Comparing files in subdirectory \"$subdir\" ..." ) + msglen=${#msg} + printf "\n%s\n" "$msg" + printf "%0.s=" $(seq 1 $msglen) + printf "\n" + + cmp_ncfiles_one_dir "$rundir1" "$rundir2" "$subdir" "nc" + +done + + + diff --git a/ush/config.community.sh b/ush/config.community.sh new file mode 100644 index 0000000000..e483a4b597 --- /dev/null +++ b/ush/config.community.sh @@ -0,0 +1,65 @@ +MACHINE="hera" +ACCOUNT="an_account" +EXPT_SUBDIR="test_community" + +COMPILER="intel" +VERBOSE="TRUE" + +RUN_ENVIR="community" +PREEXISTING_DIR_METHOD="rename" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +QUILTING="TRUE" + +DO_ENSEMBLE="FALSE" +NUM_ENS_MEMBERS="2" + +CCPP_PHYS_SUITE="FV3_GFS_v16" +FCST_LEN_HRS="12" +LBC_SPEC_INTVL_HRS="6" + +DATE_FIRST_CYCL="20190615" +DATE_LAST_CYCL="20190615" +CYCL_HRS=( "18" ) + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" + +FV3GFS_FILE_FMT_ICS="grib2" +FV3GFS_FILE_FMT_LBCS="grib2" + +WTIME_RUN_FCST="02:00:00" + +MODEL="FV3_GFS_v16_CONUS_25km" +METPLUS_PATH="path/to/METPlus" +MET_INSTALL_DIR="path/to/MET" +CCPA_OBS_DIR="/path/to/processed/CCPA/data" +MRMS_OBS_DIR="/path/to/processed/MRMS/data" +NDAS_OBS_DIR="/path/to/processed/NDAS/data" + +RUN_TASK_MAKE_GRID="TRUE" +RUN_TASK_MAKE_OROG="TRUE" +RUN_TASK_MAKE_SFC_CLIMO="TRUE" +RUN_TASK_GET_OBS_CCPA="FALSE" +RUN_TASK_GET_OBS_MRMS="FALSE" +RUN_TASK_GET_OBS_NDAS="FALSE" +RUN_TASK_VX_GRIDSTAT="FALSE" +RUN_TASK_VX_POINTSTAT="FALSE" +RUN_TASK_VX_ENSGRID="FALSE" +RUN_TASK_VX_ENSPOINT="FALSE" + +# +# Uncomment the following line in order to use user-staged external model +# files with locations and names as specified by EXTRN_MDL_SOURCE_BASEDIR_ICS/ +# LBCS and EXTRN_MDL_FILES_ICS/LBCS. +# +#USE_USER_STAGED_EXTRN_FILES="TRUE" +# +# The following is specifically for Hera. It will have to be modified +# if on another platform, using other dates, other external models, etc. +# Uncomment the following EXTRN_MDL_*_ICS/LBCS only when USE_USER_STAGED_EXTRN_FILES=TRUE +# +#EXTRN_MDL_SOURCE_BASEDIR_ICS="/scratch2/BMC/det/UFS_SRW_App/develop/input_model_data/FV3GFS/grib2/2019061518" +#EXTRN_MDL_FILES_ICS=( "gfs.t18z.pgrb2.0p25.f000" ) +#EXTRN_MDL_SOURCE_BASEDIR_LBCS="/scratch2/BMC/det/UFS_SRW_App/develop/input_model_data/FV3GFS/grib2/2019061518" +#EXTRN_MDL_FILES_LBCS=( "gfs.t18z.pgrb2.0p25.f006" "gfs.t18z.pgrb2.0p25.f012") diff --git a/ush/config.nco.sh b/ush/config.nco.sh new file mode 100644 index 0000000000..556aa65218 --- /dev/null +++ b/ush/config.nco.sh @@ -0,0 +1,51 @@ +MACHINE="hera" +ACCOUNT="an_account" +EXPT_SUBDIR="test_nco" + +COMPILER="intel" +VERBOSE="TRUE" + +RUN_ENVIR="nco" +PREEXISTING_DIR_METHOD="rename" + +USE_CRON_TO_RELAUNCH="TRUE" +CRON_RELAUNCH_INTVL_MNTS="3" + +PREDEF_GRID_NAME="RRFS_CONUS_25km" +QUILTING="TRUE" + +CCPP_PHYS_SUITE="FV3_GFS_v16" + +FCST_LEN_HRS="6" +LBC_SPEC_INTVL_HRS="3" + +DATE_FIRST_CYCL="20220407" +DATE_LAST_CYCL="20220407" +CYCL_HRS=( "00" ) + +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" + +FV3GFS_FILE_FMT_ICS="grib2" +FV3GFS_FILE_FMT_LBCS="grib2" + +WTIME_RUN_FCST="01:00:00" + +WRITE_DOPOST="TRUE" + +# +# Output directory: {NET}/{model_ver}/{RUN}.YYYYMMDD/ +# Output file name: {NET}.tHHz.[var_name].f###.{POST_OUTPUT_DOMAIN_NAME}.grib2 +# +POST_OUTPUT_DOMAIN_NAME="conus_25km" +NET="rrfs" +model_ver="v1.0" +RUN="rrfs_test" +# +# The following must be modified for different platforms and users. +# +COMIN="/scratch1/NCEPDEV/rstprod/com/gfs/prod" # Path to directory containing files from the external model. +DOMAIN_PREGEN_BASEDIR="/scratch2/BMC/det/UFS_SRW_App/develop/FV3LAM_pregen" # Path to directory containing the pregenerated grid, orography, and surface climatology "fixed" files to use for the experiment. +STMP="/path/to/stmp/directory" # Path to directory STMP that mostly contains input files. +PTMP="/path/to/ptmp/directory" # Path to directory PTMP in which the experiment's output files will be placed. + diff --git a/ush/config_defaults.sh b/ush/config_defaults.sh new file mode 100644 index 0000000000..3eab91ba0d --- /dev/null +++ b/ush/config_defaults.sh @@ -0,0 +1,2027 @@ +# +#----------------------------------------------------------------------- +# +# This file sets the experiment's configuration variables (which are +# global shell variables) to their default values. For many of these +# variables, the valid values that they may take on are defined in the +# file $USHDIR/valid_param_vals.py. +# +#----------------------------------------------------------------------- +# + +# +#----------------------------------------------------------------------- +# +# Set the RUN_ENVIR variable that is listed and described in the WCOSS +# Implementation Standards document: +# +# NCEP Central Operations +# WCOSS Implementation Standards +# January 19, 2022 +# Version 11.0.0 +# +# RUN_ENVIR is described in this document as follows: +# +# Set to "nco" if running in NCO's production environment. Used to +# distinguish between organizations. +# +# Valid values are "nco" and "community". Here, we use it to generate +# and run the experiment either in NCO mode (if RUN_ENVIR is set to "nco") +# or in community mode (if RUN_ENVIR is set to "community"). This has +# implications on the experiment variables that need to be set and the +# the directory structure used. +# +#----------------------------------------------------------------------- +# +RUN_ENVIR="nco" +# +#----------------------------------------------------------------------- +# +# mach_doc_start +# Set machine and queue parameters. Definitions: +# +# MACHINE: +# Machine on which the workflow will run. If you are NOT on a named, +# supported platform, and you want to use the Rocoto workflow manager, +# you will need set MACHINE="linux" and WORKFLOW_MANAGER="rocoto". This +# combination will assume a Slurm batch manager when generating the XML. +# Please see ush/valid_param_vals.py for a full list of supported +# platforms. +# +# MACHINE_FILE: +# Path to a configuration file with machine-specific settings. If none +# is provided, setup.sh will attempt to set the path to for a supported +# platform. +# +# ACCOUNT: +# The account under which to submit jobs to the queue. +# +# WORKFLOW_MANAGER: +# The workflow manager to use (e.g. rocoto). This is set to "none" by +# default, but if the machine name is set to a platform that supports +# rocoto, this will be overwritten and set to "rocoto". If set +# explicitly to rocoto along with the use of the MACHINE=linux target, +# the configuration layer assumes a Slurm batch manager when generating +# the XML. Valid options: "rocoto" or "none" +# +# NCORES_PER_NODE: +# The number of cores available per node on the compute platform. Set +# for supported platforms in setup.sh, but is now also configurable for +# all platforms. +# +# LMOD_PATH: +# Path to the LMOD sh file on your Linux system. Is set automatically +# for supported machines. +# +# BUILD_MOD_FN: +# Name of build module file to load before running a workflow task. If +# this is not specified by the user in the experiment configuration file +# (EXPT_CONFIG_FN), it will be set automatically for supported machines. +# +# WFLOW_MOD_FN: +# Name of workflow module file to load before (re)launching the experiment's +# ROCOTO workflow (using the "rocotorun" command). If this is not specified +# by the user in the experiment configuration file (EXPT_CONFIG_FN), it +# will be set automatically for supported machines. +# +# SCHED: +# The job scheduler to use (e.g. slurm). Set this to an empty string in +# order for the experiment generation script to set it depending on the +# machine. +# +# PARTITION_DEFAULT: +# If using the slurm job scheduler (i.e. if SCHED is set to "slurm"), +# the default partition to which to submit workflow tasks. If a task +# does not have a specific variable that specifies the partition to which +# it will be submitted (e.g. PARTITION_HPSS, PARTITION_FCST; see below), +# it will be submitted to the partition specified by this variable. If +# this is not set or is set to an empty string, it will be (re)set to a +# machine-dependent value. This is not used if SCHED is not set to +# "slurm". +# +# QUEUE_DEFAULT: +# The default queue or QOS (if using the slurm job scheduler, where QOS +# is Quality of Service) to which workflow tasks are submitted. If a +# task does not have a specific variable that specifies the queue to which +# it will be submitted (e.g. QUEUE_HPSS, QUEUE_FCST; see below), it will +# be submitted to the queue specified by this variable. If this is not +# set or is set to an empty string, it will be (re)set to a machine- +# dependent value. +# +# PARTITION_HPSS: +# If using the slurm job scheduler (i.e. if SCHED is set to "slurm"), +# the partition to which the tasks that get or create links to external +# model files [which are needed to generate initial conditions (ICs) and +# lateral boundary conditions (LBCs)] are submitted. If this is not set +# or is set to an empty string, it will be (re)set to a machine-dependent +# value. This is not used if SCHED is not set to "slurm". +# +# QUEUE_HPSS: +# The queue or QOS to which the tasks that get or create links to external +# model files [which are needed to generate initial conditions (ICs) and +# lateral boundary conditions (LBCs)] are submitted. If this is not set +# or is set to an empty string, it will be (re)set to a machine-dependent +# value. +# +# PARTITION_FCST: +# If using the slurm job scheduler (i.e. if SCHED is set to "slurm"), +# the partition to which the task that runs forecasts is submitted. If +# this is not set or set to an empty string, it will be (re)set to a +# machine-dependent value. This is not used if SCHED is not set to +# "slurm". +# +# QUEUE_FCST: +# The queue or QOS to which the task that runs a forecast is submitted. +# If this is not set or set to an empty string, it will be (re)set to a +# machine-dependent value. +# +# mach_doc_end +# +#----------------------------------------------------------------------- +# +MACHINE="BIG_COMPUTER" +MACHINE_FILE="" +ACCOUNT="project_name" +WORKFLOW_MANAGER="none" +NCORES_PER_NODE="" +LMOD_PATH="" +BUILD_MOD_FN="" +WFLOW_MOD_FN="" +SCHED="" +PARTITION_DEFAULT="" +QUEUE_DEFAULT="" +PARTITION_HPSS="" +QUEUE_HPSS="" +PARTITION_FCST="" +QUEUE_FCST="" +# +#----------------------------------------------------------------------- +# +# Set run commands for platforms without a workflow manager. These values +# will be ignored unless WORKFLOW_MANAGER="none". Definitions: +# +# RUN_CMD_UTILS: +# The run command for pre-processing utilities (shave, orog, sfc_climo_gen, +# etc.) Can be left blank for smaller domains, in which case the executables +# will run without MPI. +# +# RUN_CMD_FCST: +# The run command for the model forecast step. This will be appended to +# the end of the variable definitions file, so it can reference other +# variables. +# +# RUN_CMD_POST: +# The run command for post-processing (UPP). Can be left blank for smaller +# domains, in which case UPP will run without MPI. +# +#----------------------------------------------------------------------- +# +RUN_CMD_UTILS="mpirun -np 1" +RUN_CMD_FCST='mpirun -np \${PE_MEMBER01}' +RUN_CMD_POST="mpirun -np 1" +# +#----------------------------------------------------------------------- +# +# Set cron-associated parameters. Definitions: +# +# USE_CRON_TO_RELAUNCH: +# Flag that determines whether or not to add a line to the user's cron +# table to call the experiment launch script every CRON_RELAUNCH_INTVL_MNTS +# minutes. +# +# CRON_RELAUNCH_INTVL_MNTS: +# The interval (in minutes) between successive calls of the experiment +# launch script by a cron job to (re)launch the experiment (so that the +# workflow for the experiment kicks off where it left off). +# +#----------------------------------------------------------------------- +# +USE_CRON_TO_RELAUNCH="FALSE" +CRON_RELAUNCH_INTVL_MNTS="03" +# +#----------------------------------------------------------------------- +# +# dir_doc_start +# Set directories. Definitions: +# +# EXPT_BASEDIR: +# The base directory in which the experiment directory will be created. +# If this is not specified or if it is set to an empty string, it will +# default to ${SR_WX_APP_TOP_DIR}/../expt_dirs. +# +# EXPT_SUBDIR: +# The name that the experiment directory (without the full path) will +# have. The full path to the experiment directory, which will be contained +# in the variable EXPTDIR, will be: +# +# EXPTDIR="${EXPT_BASEDIR}/${EXPT_SUBDIR}" +# +# This cannot be empty. If set to a null string here, it must be set to +# a (non-empty) value in the user-defined experiment configuration file. +# +# dir_doc_end +# +# EXEC_SUBDIR: +# The name of the subdirectory of ufs-srweather-app where executables are +# installed. +#----------------------------------------------------------------------- +# +EXPT_BASEDIR="" +EXPT_SUBDIR="" +EXEC_SUBDIR="bin" +# +#----------------------------------------------------------------------- +# +# Set variables that are only used in NCO mode (i.e. when RUN_ENVIR is +# set to "nco"). Definitions: +# +# COMIN: +# Directory containing files generated by the external model (FV3GFS, NAM, +# HRRR, etc) that the initial and lateral boundary condition generation tasks +# need in order to create initial and boundary condition files for a given +# cycle on the native FV3-LAM grid. +# +# envir, NET, model_ver, RUN: +# Standard environment variables defined in the NCEP Central Operations WCOSS +# Implementation Standards document as follows: +# +# envir: +# Set to "test" during the initial testing phase, "para" when running +# in parallel (on a schedule), and "prod" in production. +# +# NET: +# Model name (first level of com directory structure) +# +# model_ver: +# Version number of package in three digits (second level of com directory) +# +# RUN: +# Name of model run (third level of com directory structure). +# In general, same as $NET +# +# STMP: +# The beginning portion of the directory that will contain cycle-dependent +# model input files, symlinks to cycle-independent input files, and raw +# (i.e. before post-processing) forecast output files for a given cycle. +# For a cycle that starts on the date specified by yyyymmdd and hour +# specified by hh (where yyyymmdd and hh are as described above) [so that +# the cycle date (cdate) is given by cdate="${yyyymmdd}${hh}"], the +# directory in which the aforementioned files will be located is: +# +# $STMP/tmpnwprd/$RUN/$cdate +# +# PTMP: +# The beginning portion of the directory that will contain the output +# files from the post-processor (UPP) for a given cycle. For a cycle +# that starts on the date specified by yyyymmdd and hour specified by hh +# (where yyyymmdd and hh are as described above), the directory in which +# the UPP output files will be placed will be: +# +# $PTMP/com/$NET/$model_ver/$RUN.$yyyymmdd/$hh +# +#----------------------------------------------------------------------- +# +COMIN="/path/of/directory/containing/data/files/for/IC/LBCS" +STMP="/base/path/of/directory/containing/model/input/and/raw/output/files" +envir="para" +NET="rrfs" +model_ver="v1.0.0" +RUN="rrfs" +STMP="/base/path/of/directory/containing/model/input/and/raw/output/files" +PTMP="/base/path/of/directory/containing/postprocessed/output/files" +# +#----------------------------------------------------------------------- +# +# Set the separator character(s) to use in the names of the grid, mosaic, +# and orography fixed files. +# +# Ideally, the same separator should be used in the names of these fixed +# files as the surface climatology fixed files (which always use a "." +# as the separator), i.e. ideally, DOT_OR_USCORE should be set to "." +# +#----------------------------------------------------------------------- +# +DOT_OR_USCORE="_" +# +#----------------------------------------------------------------------- +# +# Set file names. Definitions: +# +# EXPT_CONFIG_FN: +# Name of the user-specified configuration file for the forecast experiment. +# +# CONSTANTS_FN: +# Name of the file containing definitions of various mathematical, physical, +# and SRW App contants. +# +# RGNL_GRID_NML_FN: +# Name of file containing the namelist settings for the code that generates +# a "ESGgrid" type of regional grid. +# +# FV3_NML_BASE_SUITE_FN: +# Name of Fortran namelist file containing the forecast model's base suite +# namelist, i.e. the portion of the namelist that is common to all physics +# suites. +# +# FV3_NML_YAML_CONFIG_FN: +# Name of YAML configuration file containing the forecast model's namelist +# settings for various physics suites. +# +# FV3_NML_BASE_ENS_FN: +# Name of Fortran namelist file containing the forecast model's base +# ensemble namelist, i.e. the the namelist file that is the starting point +# from which the namelist files for each of the enesemble members are +# generated. +# +# FV3_EXEC_FN: +# Name to use for the forecast model executable when it is copied from +# the directory in which it is created in the build step to the executables +# directory (EXECDIR; this is set during experiment generation). +# +# DIAG_TABLE_TMPL_FN: +# Name of a template file that specifies the output fields of the forecast +# model (ufs-weather-model: diag_table) followed by [dot_ccpp_phys_suite]. +# Its default value is the name of the file that the ufs weather model +# expects to read in. +# +# FIELD_TABLE_TMPL_FN: +# Name of a template file that specifies the tracers in IC/LBC files of the +# forecast model (ufs-weather-mode: field_table) followed by [dot_ccpp_phys_suite]. +# Its default value is the name of the file that the ufs weather model expects +# to read in. +# +# MODEL_CONFIG_TMPL_FN: +# Name of a template file that contains settings and configurations for the +# NUOPC/ESMF main component (ufs-weather-model: model_config). Its default +# value is the name of the file that the ufs weather model expects to read in. +# +# NEMS_CONFIG_TMPL_FN: +# Name of a template file that contains information about the various NEMS +# components and their run sequence (ufs-weather-model: nems.configure). +# Its default value is the name of the file that the ufs weather model expects +# to read in. +# +# FCST_MODEL: +# Name of forecast model (default=ufs-weather-model) +# +# WFLOW_XML_FN: +# Name of the rocoto workflow XML file that the experiment generation +# script creates and that defines the workflow for the experiment. +# +# GLOBAL_VAR_DEFNS_FN: +# Name of file (a shell script) containing the defintions of the primary +# experiment variables (parameters) defined in this default configuration +# script and in the user-specified configuration as well as secondary +# experiment variables generated by the experiment generation script. +# This file is sourced by many scripts (e.g. the J-job scripts corresponding +# to each workflow task) in order to make all the experiment variables +# available in those scripts. +# +# EXTRN_MDL_VAR_DEFNS_FN: +# Name of file (a shell script) containing the defintions of variables +# associated with the external model from which ICs or LBCs are generated. This +# file is created by the GET_EXTRN_*_TN task because the values of the variables +# it contains are not known before this task runs. The file is then sourced by +# the MAKE_ICS_TN and MAKE_LBCS_TN tasks. +# +# WFLOW_LAUNCH_SCRIPT_FN: +# Name of the script that can be used to (re)launch the experiment's rocoto +# workflow. +# +# WFLOW_LAUNCH_LOG_FN: +# Name of the log file that contains the output from successive calls to +# the workflow launch script (WFLOW_LAUNCH_SCRIPT_FN). +# +#----------------------------------------------------------------------- +# +EXPT_CONFIG_FN="config.sh" +CONSTANTS_FN="constants.sh" + +RGNL_GRID_NML_FN="regional_grid.nml" + +FV3_NML_BASE_SUITE_FN="input.nml.FV3" +FV3_NML_YAML_CONFIG_FN="FV3.input.yml" +FV3_NML_BASE_ENS_FN="input.nml.base_ens" +FV3_EXEC_FN="ufs_model" + +DATA_TABLE_TMPL_FN="" +DIAG_TABLE_TMPL_FN="" +FIELD_TABLE_TMPL_FN="" +MODEL_CONFIG_TMPL_FN="" +NEMS_CONFIG_TMPL_FN="" + +FCST_MODEL="ufs-weather-model" +WFLOW_XML_FN="FV3LAM_wflow.xml" +GLOBAL_VAR_DEFNS_FN="var_defns.sh" +EXTRN_MDL_VAR_DEFNS_FN="extrn_mdl_var_defns.sh" +WFLOW_LAUNCH_SCRIPT_FN="launch_FV3LAM_wflow.sh" +WFLOW_LAUNCH_LOG_FN="log.launch_FV3LAM_wflow" +# +#----------------------------------------------------------------------- +# +# Set forecast parameters. Definitions: +# +# DATE_FIRST_CYCL: +# Starting date of the first forecast in the set of forecasts to run. +# Format is "YYYYMMDD". Note that this does not include the hour-of-day. +# +# DATE_LAST_CYCL: +# Starting date of the last forecast in the set of forecasts to run. +# Format is "YYYYMMDD". Note that this does not include the hour-of-day. +# +# CYCL_HRS: +# An array containing the hours of the day at which to launch forecasts. +# Forecasts are launched at these hours on each day from DATE_FIRST_CYCL +# to DATE_LAST_CYCL, inclusive. Each element of this array must be a +# two-digit string representing an integer that is less than or equal to +# 23, e.g. "00", "03", "12", "23". +# +# INCR_CYCL_FREQ: +# Increment in hours for Cycle Frequency (cycl_freq). +# Default is 24, which means cycle_freq=24:00:00 +# +# FCST_LEN_HRS: +# The length of each forecast, in integer hours. +# +#----------------------------------------------------------------------- +# +DATE_FIRST_CYCL="YYYYMMDD" +DATE_LAST_CYCL="YYYYMMDD" +CYCL_HRS=( "HH1" "HH2" ) +INCR_CYCL_FREQ="24" +FCST_LEN_HRS="24" +# +#----------------------------------------------------------------------- +# +# Set model_configure parameters. Definitions: +# +# DT_ATMOS: +# The main forecast model integraton time step. As described in the +# forecast model documentation, "It corresponds to the frequency with +# which the top level routine in the dynamics is called as well as the +# frequency with which the physics is called." +# +# CPL: parameter for coupling +# (set automatically based on FCST_MODEL in ush/setup.sh) +# (ufs-weather-model:FALSE, fv3gfs_aqm:TRUE) +# +# RESTART_INTERVAL: +# frequency of the output restart files (unit:hour). +# Default=0: restart files are produced at the end of a forecast run +# For example, RESTART_INTERVAL="1": restart files are produced every hour +# with the prefix "YYYYMMDD.HHmmSS." in the RESTART directory +# +# WRITE_DOPOST: +# Flag that determines whether or not to use the inline post feature +# [i.e. calling the Unified Post Processor (UPP) from within the weather +# model]. If this is set to "TRUE", the RUN_POST_TN task is deactivated +# (i.e. RUN_TASK_RUN_POST is set to "FALSE") to avoid unnecessary +# computations. +# +#----------------------------------------------------------------------- +# +DT_ATMOS="" +RESTART_INTERVAL="0" +WRITE_DOPOST="FALSE" +# +#----------------------------------------------------------------------- +# +# Set METplus parameters. Definitions: +# +# MODEL: +# String that specifies a descriptive name for the model being verified. +# +# MET_INSTALL_DIR: +# Location to top-level directory of MET installation. +# +# METPLUS_PATH: +# Location to top-level directory of METplus installation. +# +# CCPA_OBS_DIR: +# User-specified location of top-level directory where CCPA hourly +# precipitation files used by METplus are located. This parameter needs +# to be set for both user-provided observations and for observations +# that are retrieved from the NOAA HPSS (if the user has access) via +# the get_obs_ccpa_tn task (activated in workflow by setting +# RUN_TASK_GET_OBS_CCPA="TRUE"). In the case of pulling observations +# directly from NOAA HPSS, the data retrieved will be placed in this +# directory. Please note, this path must be defind as +# /full-path-to-obs/ccpa/proc. METplus is configured to verify 01-, +# 03-, 06-, and 24-h accumulated precipitation using hourly CCPA files. +# METplus configuration files require the use of predetermined directory +# structure and file names. Therefore, if the CCPA files are user +# provided, they need to follow the anticipated naming structure: +# {YYYYMMDD}/ccpa.t{HH}z.01h.hrap.conus.gb2, where YYYY is the 4-digit +# valid year, MM the 2-digit valid month, DD the 2-digit valid day of +# the month, and HH the 2-digit valid hour of the day. In addition, a +# caveat is noted for using hourly CCPA data. There is a problem with +# the valid time in the metadata for files valid from 19 - 00 UTC (or +# files under the '00' directory). The script to pull the CCPA data +# from the NOAA HPSS has an example of how to account for this as well +# as organizing the data into a more intuitive format: +# scripts/exregional_get_ccpa_files.sh. When a fix +# is provided, it will be accounted for in the +# exregional_get_ccpa_files.sh script. +# +# MRMS_OBS_DIR: +# User-specified location of top-level directory where MRMS composite +# reflectivity files used by METplus are located. This parameter needs +# to be set for both user-provided observations and for observations +# that are retrieved from the NOAA HPSS (if the user has access) via the +# get_obs_mrms_tn task (activated in workflow by setting +# RUN_TASK_GET_OBS_MRMS="TRUE"). In the case of pulling observations +# directly from NOAA HPSS, the data retrieved will be placed in this +# directory. Please note, this path must be defind as +# /full-path-to-obs/mrms/proc. METplus configuration files require the +# use of predetermined directory structure and file names. Therefore, if +# the MRMS files are user provided, they need to follow the anticipated +# naming structure: +# {YYYYMMDD}/MergedReflectivityQCComposite_00.50_{YYYYMMDD}-{HH}{mm}{SS}.grib2, +# where YYYY is the 4-digit valid year, MM the 2-digit valid month, DD +# the 2-digit valid day of the month, HH the 2-digit valid hour of the +# day, mm the 2-digit valid minutes of the hour, and SS is the two-digit +# valid seconds of the hour. In addition, METplus is configured to look +# for a MRMS composite reflectivity file for the valid time of the +# forecast being verified; since MRMS composite reflectivity files do +# not always exactly match the valid time, a script, within the main +# script to retrieve MRMS data from the NOAA HPSS, is used to identify +# and rename the MRMS composite reflectivity file to match the valid +# time of the forecast. The script to pull the MRMS data from the NOAA +# HPSS has an example of the expected file naming structure: +# scripts/exregional_get_mrms_files.sh. This script +# calls the script used to identify the MRMS file closest to the valid +# time: ush/mrms_pull_topofhour.py. +# +# NDAS_OBS_DIR: +# User-specified location of top-level directory where NDAS prepbufr +# files used by METplus are located. This parameter needs to be set for +# both user-provided observations and for observations that are +# retrieved from the NOAA HPSS (if the user has access) via the +# get_obs_ndas_tn task (activated in workflow by setting  +# RUN_TASK_GET_OBS_NDAS="TRUE"). In the case of pulling observations +# directly from NOAA HPSS, the data retrieved will be placed in this +# directory. Please note, this path must be defind as +# /full-path-to-obs/ndas/proc. METplus is configured to verify +# near-surface variables hourly and upper-air variables at times valid +# at 00 and 12 UTC with NDAS prepbufr files. METplus configuration files +# require the use of predetermined file names. Therefore, if the NDAS +# files are user provided, they need to follow the anticipated naming +# structure: prepbufr.ndas.{YYYYMMDDHH}, where YYYY is the 4-digit valid +# year, MM the 2-digit valid month, DD the 2-digit valid day of the +# month, and HH the 2-digit valid hour of the day. The script to pull +# the NDAS data from the NOAA HPSS has an example of how to rename the +# NDAS data into a more intuitive format with the valid time listed in +# the file name: scripts/exregional_get_ndas_files.sh +# +#----------------------------------------------------------------------- +# +MODEL="" +MET_INSTALL_DIR="" +MET_BIN_EXEC="bin" +METPLUS_PATH="" +CCPA_OBS_DIR="" +MRMS_OBS_DIR="" +NDAS_OBS_DIR="" +# +#----------------------------------------------------------------------- +# +# Set initial and lateral boundary condition generation parameters. +# Definitions: +# +# EXTRN_MDL_NAME_ICS: +#`The name of the external model that will provide fields from which +# initial condition (including and surface) files will be generated for +# input into the forecast model. +# +# EXTRN_MDL_NAME_LBCS: +#`The name of the external model that will provide fields from which +# lateral boundary condition (LBC) files will be generated for input into +# the forecast model. +# +# LBC_SPEC_INTVL_HRS: +# The interval (in integer hours) with which LBC files will be generated. +# We will refer to this as the boundary update interval. Note that the +# model specified in EXTRN_MDL_NAME_LBCS must have data available at a +# frequency greater than or equal to that implied by LBC_SPEC_INTVL_HRS. +# For example, if LBC_SPEC_INTVL_HRS is set to 6, then the model must have +# data availble at least every 6 hours. It is up to the user to ensure +# that this is the case. +# +# EXTRN_MDL_ICS_OFFSET_HRS: +# Users may wish to start a forecast from a forecast of a previous cycle +# of an external model. This variable sets the number of hours earlier +# the external model started than when the FV3 forecast configured here +# should start. For example, the forecast should start from a 6 hour +# forecast of the GFS, then EXTRN_MDL_ICS_OFFSET_HRS=6. + +# EXTRN_MDL_LBCS_OFFSET_HRS: +# Users may wish to use lateral boundary conditions from a forecast that +# was started earlier than the initial time for the FV3 forecast +# configured here. This variable sets the number of hours earlier +# the external model started than when the FV3 forecast configured here +# should start. For example, the forecast should use lateral boundary +# conditions from the GFS started 6 hours earlier, then +# EXTRN_MDL_LBCS_OFFSET_HRS=6. +# Note: the default value is model-dependent and set in +# set_extrn_mdl_params.py +# +# FV3GFS_FILE_FMT_ICS: +# If using the FV3GFS model as the source of the ICs (i.e. if EXTRN_MDL_NAME_ICS +# is set to "FV3GFS"), this variable specifies the format of the model +# files to use when generating the ICs. +# +# FV3GFS_FILE_FMT_LBCS: +# If using the FV3GFS model as the source of the LBCs (i.e. if +# EXTRN_MDL_NAME_LBCS is set to "FV3GFS"), this variable specifies the +# format of the model files to use when generating the LBCs. +# +#----------------------------------------------------------------------- +# +EXTRN_MDL_NAME_ICS="FV3GFS" +EXTRN_MDL_NAME_LBCS="FV3GFS" +LBC_SPEC_INTVL_HRS="6" +EXTRN_MDL_ICS_OFFSET_HRS="0" +EXTRN_MDL_LBCS_OFFSET_HRS="" +FV3GFS_FILE_FMT_ICS="nemsio" +FV3GFS_FILE_FMT_LBCS="nemsio" +# +#----------------------------------------------------------------------- +# +# Base directories in which to search for external model files. +# +# EXTRN_MDL_SYSBASEDIR_ICS: +# Base directory on the local machine containing external model files for +# generating ICs on the native grid. The way the full path containing +# these files is constructed depends on the user-specified external model +# for ICs, i.e. EXTRN_MDL_NAME_ICS. +# +# EXTRN_MDL_SYSBASEDIR_LBCS: +# Same as EXTRN_MDL_SYSBASEDIR_ICS but for LBCs. +# +# Note that these must be defined as null strings here so that if they +# are specified by the user in the experiment configuration file, they +# remain set to those values, and if not, they get set to machine-dependent +# values. +# +#----------------------------------------------------------------------- +# +EXTRN_MDL_SYSBASEDIR_ICS='' +EXTRN_MDL_SYSBASEDIR_LBCS='' +# +#----------------------------------------------------------------------- +# +# User-staged external model directories and files. Definitions: +# +# USE_USER_STAGED_EXTRN_FILES: +# Flag that determines whether or not the workflow will look for the +# external model files needed for generating ICs and LBCs in user-specified +# directories. +# +# EXTRN_MDL_SOURCE_BASEDIR_ICS: +# Directory in which to look for external model files for generating ICs. +# If USE_USER_STAGED_EXTRN_FILES is set to "TRUE", the workflow looks in +# this directory (specifically, in a subdirectory under this directory +# named "YYYYMMDDHH" consisting of the starting date and cycle hour of +# the forecast, where YYYY is the 4-digit year, MM the 2-digit month, DD +# the 2-digit day of the month, and HH the 2-digit hour of the day) for +# the external model files specified by the array EXTRN_MDL_FILES_ICS +# (these files will be used to generate the ICs on the native FV3-LAM +# grid). This variable is not used if USE_USER_STAGED_EXTRN_FILES is +# set to "FALSE". +# +# EXTRN_MDL_FILES_ICS: +# Array containing templates of the names of the files to search for in +# the directory specified by EXTRN_MDL_SOURCE_BASEDIR_ICS. This +# variable is not used if USE_USER_STAGED_EXTRN_FILES is set to "FALSE". +# A single template should be used for each model file type that is +# meant to be used. You may use any of the Python-style templates +# allowed in the ush/retrieve_data.py script. To see the full list of +# supported templates, run that script with a -h option. Here is an example of +# setting FV3GFS nemsio input files: +# EXTRN_MDL_FILES_ICS=( gfs.t{hh}z.atmf{fcst_hr:03d}.nemsio \ +# gfs.t{hh}z.sfcf{fcst_hr:03d}.nemsio ) +# Or for FV3GFS grib files: +# EXTRN_MDL_FILES_ICS=( gfs.t{hh}z.pgrb2.0p25.f{fcst_hr:03d} ) +# +# EXTRN_MDL_SOURCE_BASEDIR_LBCS: +# Analogous to EXTRN_MDL_SOURCE_BASEDIR_ICS but for LBCs instead of ICs. +# +# EXTRN_MDL_FILES_LBCS: +# Analogous to EXTRN_MDL_FILES_ICS but for LBCs instead of ICs. +# +# EXTRN_MDL_DATA_STORES: +# A list of data stores where the scripts should look for external model +# data. The list is in priority order. If disk information is provided +# via USE_USER_STAGED_EXTRN_FILES or a known location on the platform, +# the disk location will be highest priority. Options are disk, hpss, +# aws, and nomads. +# +#----------------------------------------------------------------------- +# +USE_USER_STAGED_EXTRN_FILES="FALSE" +EXTRN_MDL_SOURCE_BASEDIR_ICS="" +EXTRN_MDL_FILES_ICS="" +EXTRN_MDL_SOURCE_BASEDIR_LBCS="" +EXTRN_MDL_FILES_LBCS="" +EXTRN_MDL_DATA_STORES="" +# +#----------------------------------------------------------------------- +# +# Set NOMADS online data associated parameters. Definitions: +# +# NOMADS: +# Flag controlling whether or not using NOMADS online data. +# +# NOMADS_file_type: +# Flag controlling the format of data. +# +#----------------------------------------------------------------------- +# +NOMADS="FALSE" +NOMADS_file_type="nemsio" +# +#----------------------------------------------------------------------- +# +# Set CCPP-associated parameters. Definitions: +# +# CCPP_PHYS_SUITE: +# The physics suite that will run using CCPP (Common Community Physics +# Package). The choice of physics suite determines the forecast model's +# namelist file, the diagnostics table file, the field table file, and +# the XML physics suite definition file that are staged in the experiment +# directory or the cycle directories under it. +# +#----------------------------------------------------------------------- +# +CCPP_PHYS_SUITE="FV3_GFS_v16" +# +#----------------------------------------------------------------------- +# +# Set GRID_GEN_METHOD. This variable specifies the method to use to +# generate a regional grid in the horizontal. The values that it can +# take on are: +# +# * "GFDLgrid": +# This setting will generate a regional grid by first generating a +# "parent" global cubed-sphere grid and then taking a portion of tile +# 6 of that global grid -- referred to in the grid generation scripts +# as "tile 7" even though it doesn't correspond to a complete tile -- +# and using it as the regional grid. Note that the forecast is run on +# only on the regional grid (i.e. tile 7, not tiles 1 through 6). +# +# * "ESGgrid": +# This will generate a regional grid using the map projection developed +# by Jim Purser of EMC. +# +# Note that: +# +# 1) If the experiment is using one of the predefined grids (i.e. if +# PREDEF_GRID_NAME is set to the name of one of the valid predefined +# grids), then GRID_GEN_METHOD will be reset to the value of +# GRID_GEN_METHOD for that grid. This will happen regardless of +# whether or not GRID_GEN_METHOD is assigned a value in the user- +# specified experiment configuration file, i.e. any value it may be +# assigned in the experiment configuration file will be overwritten. +# +# 2) If the experiment is not using one of the predefined grids (i.e. if +# PREDEF_GRID_NAME is set to a null string), then GRID_GEN_METHOD must +# be set in the experiment configuration file. Otherwise, it will +# remain set to a null string, and the experiment generation will +# fail because the generation scripts check to ensure that it is set +# to a non-empty string before creating the experiment directory. +# +#----------------------------------------------------------------------- +# +GRID_GEN_METHOD="" +# +#----------------------------------------------------------------------- +# +# Set parameters specific to the "GFDLgrid" method of generating a regional +# grid (i.e. for GRID_GEN_METHOD set to "GFDLgrid"). The following +# parameters will be used only if GRID_GEN_METHOD is set to "GFDLgrid". +# In this grid generation method: +# +# * The regional grid is defined with respect to a "parent" global cubed- +# sphere grid. Thus, all the parameters for a global cubed-sphere grid +# must be specified in order to define this parent global grid even +# though the model equations are not integrated on (they are integrated +# only on the regional grid). +# +# * GFDLgrid_NUM_CELLS is the number of grid cells in either one of the +# two horizontal directions x and y on any one of the 6 tiles of the +# parent global cubed-sphere grid. The mapping from GFDLgrid_NUM_CELLS +# to a nominal resolution (grid cell size) for a uniform global grid +# (i.e. Schmidt stretch factor GFDLgrid_STRETCH_FAC set to 1) for +# several values of GFDLgrid_NUM_CELLS is as follows: +# +# GFDLgrid_NUM_CELLS typical cell size +# ------------------ ----------------- +# 192 50 km +# 384 25 km +# 768 13 km +# 1152 8.5 km +# 3072 3.2 km +# +# Note that these are only typical cell sizes. The actual cell size on +# the global grid tiles varies somewhat as we move across a tile. +# +# * Tile 6 has arbitrarily been chosen as the tile to use to orient the +# global parent grid on the sphere (Earth). This is done by specifying +# GFDLgrid_LON_T6_CTR and GFDLgrid_LAT_T6_CTR, which are the longitude +# and latitude (in degrees) of the center of tile 6. +# +# * Setting the Schmidt stretching factor GFDLgrid_STRETCH_FAC to a value +# greater than 1 shrinks tile 6, while setting it to a value less than +# 1 (but still greater than 0) expands it. The remaining 5 tiles change +# shape as necessary to maintain global coverage of the grid. +# +# * The cell size on a given global tile depends on both GFDLgrid_NUM_CELLS +# and GFDLgrid_STRETCH_FAC (since changing GFDLgrid_NUM_CELLS changes +# the number of cells in the tile, and changing GFDLgrid_STRETCH_FAC +# modifies the shape and size of the tile). +# +# * The regional grid is embedded within tile 6 (i.e. it doesn't extend +# beyond the boundary of tile 6). Its exact location within tile 6 is +# is determined by specifying the starting and ending i and j indices +# of the regional grid on tile 6, where i is the grid index in the x +# direction and j is the grid index in the y direction. These indices +# are stored in the variables +# +# GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G +# GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G +# GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G +# GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G +# +# * In the forecast model code and in the experiment generation and workflow +# scripts, for convenience the regional grid is denoted as "tile 7" even +# though it doesn't map back to one of the 6 faces of the cube from +# which the parent global grid is generated (it maps back to only a +# subregion on face 6 since it is wholly confined within tile 6). Tile +# 6 may be referred to as the "parent" tile of the regional grid. +# +# * GFDLgrid_REFINE_RATIO is the refinement ratio of the regional grid +# (tile 7) with respect to the grid on its parent tile (tile 6), i.e. +# it is the number of grid cells along the boundary of the regional +# grid that abut one cell on tile 6. Thus, the cell size on the regional +# grid depends not only on GFDLgrid_NUM_CELLS and GFDLgrid_STRETCH_FAC +# (because the cell size on tile 6 depends on these two parameters) +# but also on GFDLgrid_REFINE_RATIO. Note that as on the tiles of the +# global grid, the cell size on the regional grid is not uniform but +# varies as we move across the grid. +# +# Definitions of parameters that need to be specified when GRID_GEN_METHOD +# is set to "GFDLgrid": +# +# GFDLgrid_LON_T6_CTR: +# Longitude of the center of tile 6 (in degrees). +# +# GFDLgrid_LAT_T6_CTR: +# Latitude of the center of tile 6 (in degrees). +# +# GFDLgrid_NUM_CELLS: +# Number of grid cells in each of the two horizontal directions (x and +# y) on each tile of the parent global grid. +# +# GFDLgrid_STRETCH_FAC: +# Stretching factor used in the Schmidt transformation applied to the +# parent cubed-sphere grid. +# +# GFDLgrid_REFINE_RATIO: +# Cell refinement ratio for the regional grid, i.e. the number of cells +# in either the x or y direction on the regional grid (tile 7) that abut +# one cell on its parent tile (tile 6). +# +# GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G: +# i-index on tile 6 at which the regional grid (tile 7) starts. +# +# GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G: +# i-index on tile 6 at which the regional grid (tile 7) ends. +# +# GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G: +# j-index on tile 6 at which the regional grid (tile 7) starts. +# +# GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G: +# j-index on tile 6 at which the regional grid (tile 7) ends. +# +# GFDLgrid_USE_NUM_CELLS_IN_FILENAMES: +# Flag that determines the file naming convention to use for grid, +# orography, and surface climatology files (or, if using pregenerated +# files, the naming convention that was used to name these files). +# These files usually start with the string "C${RES}_", where RES is an +# integer. In the global forecast model, RES is the number of grid +# cells in each of the two horizontal directions (x and y) on each tile +# of the global grid (defined here as GFDLgrid_NUM_CELLS). If this flag +# is set to "TRUE", RES will be set to GFDLgrid_NUM_CELLS just as in the +# global forecast model. If it is set to "FALSE", we calculate (in the +# grid generation task) an "equivalent global uniform cubed-sphere +# resolution" -- call it RES_EQUIV -- and then set RES equal to it. +# RES_EQUIV is the number of grid points in each of the x and y directions +# on each tile that a global UNIFORM (i.e. stretch factor of 1) cubed- +# sphere grid would have to have in order to have the same average grid +# size as the regional grid. This is a more useful indicator of the grid +# size because it takes into account the effects of GFDLgrid_NUM_CELLS, +# GFDLgrid_STRETCH_FAC, and GFDLgrid_REFINE_RATIO in determining the +# regional grid's typical grid size, whereas simply setting RES to +# GFDLgrid_NUM_CELLS doesn't take into account the effects of +# GFDLgrid_STRETCH_FAC and GFDLgrid_REFINE_RATIO on the regional grid's +# resolution. Nevertheless, some users still prefer to use +# GFDLgrid_NUM_CELLS in the file names, so we allow for that here by +# setting this flag to "TRUE". +# +# Note that: +# +# 1) If the experiment is using one of the predefined grids (i.e. if +# PREDEF_GRID_NAME is set to the name of one of the valid predefined +# grids), then: +# +# a) If the value of GRID_GEN_METHOD for that grid is "GFDLgrid", then +# these parameters will get reset to the values for that grid. +# This will happen regardless of whether or not they are assigned +# values in the user-specified experiment configuration file, i.e. +# any values they may be assigned in the experiment configuration +# file will be overwritten. +# +# b) If the value of GRID_GEN_METHOD for that grid is "ESGgrid", then +# these parameters will not be used and thus do not need to be reset +# to non-empty strings. +# +# 2) If the experiment is not using one of the predefined grids (i.e. if +# PREDEF_GRID_NAME is set to a null string), then: +# +# a) If GRID_GEN_METHOD is set to "GFDLgrid" in the user-specified +# experiment configuration file, then these parameters must be set +# in that configuration file. +# +# b) If GRID_GEN_METHOD is set to "ESGgrid" in the user-specified +# experiment configuration file, then these parameters will not be +# used and thus do not need to be reset to non-empty strings. +# +#----------------------------------------------------------------------- +# +GFDLgrid_LON_T6_CTR="" +GFDLgrid_LAT_T6_CTR="" +GFDLgrid_NUM_CELLS="" +GFDLgrid_STRETCH_FAC="" +GFDLgrid_REFINE_RATIO="" +GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G="" +GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G="" +GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G="" +GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G="" +GFDLgrid_USE_NUM_CELLS_IN_FILENAMES="" +# +#----------------------------------------------------------------------- +# +# Set parameters specific to the "ESGgrid" method of generating a regional +# grid (i.e. for GRID_GEN_METHOD set to "ESGgrid"). Definitions: +# +# ESGgrid_LON_CTR: +# The longitude of the center of the grid (in degrees). +# +# ESGgrid_LAT_CTR: +# The latitude of the center of the grid (in degrees). +# +# ESGgrid_DELX: +# The cell size in the zonal direction of the regional grid (in meters). +# +# ESGgrid_DELY: +# The cell size in the meridional direction of the regional grid (in +# meters). +# +# ESGgrid_NX: +# The number of cells in the zonal direction on the regional grid. +# +# ESGgrid_NY: +# The number of cells in the meridional direction on the regional grid. +# +# ESGgrid_WIDE_HALO_WIDTH: +# The width (in units of number of grid cells) of the halo to add around +# the regional grid before shaving the halo down to the width(s) expected +# by the forecast model. +# +# ESGgrid_PAZI: +# The rotational parameter for the ESG grid (in degrees). +# +# In order to generate grid files containing halos that are 3-cell and +# 4-cell wide and orography files with halos that are 0-cell and 3-cell +# wide (all of which are required as inputs to the forecast model), the +# grid and orography tasks first create files with halos around the regional +# domain of width ESGgrid_WIDE_HALO_WIDTH cells. These are first stored +# in files. The files are then read in and "shaved" down to obtain grid +# files with 3-cell-wide and 4-cell-wide halos and orography files with +# 0-cell-wide (i.e. no halo) and 3-cell-wide halos. For this reason, we +# refer to the original halo that then gets shaved down as the "wide" +# halo, i.e. because it is wider than the 0-cell-wide, 3-cell-wide, and +# 4-cell-wide halos that we will eventually end up with. Note that the +# grid and orography files with the wide halo are only needed as intermediates +# in generating the files with 0-cell-, 3-cell-, and 4-cell-wide halos; +# they are not needed by the forecast model. +# NOTE: Probably don't need to make ESGgrid_WIDE_HALO_WIDTH a user-specified +# variable. Just set it in the function set_gridparams_ESGgrid.py. +# +# Note that: +# +# 1) If the experiment is using one of the predefined grids (i.e. if +# PREDEF_GRID_NAME is set to the name of one of the valid predefined +# grids), then: +# +# a) If the value of GRID_GEN_METHOD for that grid is "GFDLgrid", then +# these parameters will not be used and thus do not need to be reset +# to non-empty strings. +# +# b) If the value of GRID_GEN_METHOD for that grid is "ESGgrid", then +# these parameters will get reset to the values for that grid. +# This will happen regardless of whether or not they are assigned +# values in the user-specified experiment configuration file, i.e. +# any values they may be assigned in the experiment configuration +# file will be overwritten. +# +# 2) If the experiment is not using one of the predefined grids (i.e. if +# PREDEF_GRID_NAME is set to a null string), then: +# +# a) If GRID_GEN_METHOD is set to "GFDLgrid" in the user-specified +# experiment configuration file, then these parameters will not be +# used and thus do not need to be reset to non-empty strings. +# +# b) If GRID_GEN_METHOD is set to "ESGgrid" in the user-specified +# experiment configuration file, then these parameters must be set +# in that configuration file. +# +#----------------------------------------------------------------------- +# +ESGgrid_LON_CTR="" +ESGgrid_LAT_CTR="" +ESGgrid_DELX="" +ESGgrid_DELY="" +ESGgrid_NX="" +ESGgrid_NY="" +ESGgrid_WIDE_HALO_WIDTH="" +ESGgrid_PAZI="" +# +#----------------------------------------------------------------------- +# +# Set computational parameters for the forecast. Definitions: +# +# LAYOUT_X, LAYOUT_Y: +# The number of MPI tasks (processes) to use in the two horizontal +# directions (x and y) of the regional grid when running the forecast +# model. +# +# BLOCKSIZE: +# The amount of data that is passed into the cache at a time. +# +# Here, we set these parameters to null strings. This is so that, for +# any one of these parameters: +# +# 1) If the experiment is using a predefined grid, then if the user +# sets the parameter in the user-specified experiment configuration +# file (EXPT_CONFIG_FN), that value will be used in the forecast(s). +# Otherwise, the default value of the parameter for that predefined +# grid will be used. +# +# 2) If the experiment is not using a predefined grid (i.e. it is using +# a custom grid whose parameters are specified in the experiment +# configuration file), then the user must specify a value for the +# parameter in that configuration file. Otherwise, the parameter +# will remain set to a null string, and the experiment generation +# will fail because the generation scripts check to ensure that all +# the parameters defined in this section are set to non-empty strings +# before creating the experiment directory. +# +#----------------------------------------------------------------------- +# +LAYOUT_X="" +LAYOUT_Y="" +BLOCKSIZE="" +# +#----------------------------------------------------------------------- +# +# Set write-component (quilting) parameters. Definitions: +# +# QUILTING: +# Flag that determines whether or not to use the write component for +# writing output files to disk. +# +# WRTCMP_write_groups: +# The number of write groups (i.e. groups of MPI tasks) to use in the +# write component. +# +# WRTCMP_write_tasks_per_group: +# The number of MPI tasks to allocate for each write group. +# +# PRINT_ESMF: +# Flag for whether or not to output extra (debugging) information from +# ESMF routines. Must be "TRUE" or "FALSE". Note that the write +# component uses ESMF library routines to interpolate from the native +# forecast model grid to the user-specified output grid (which is defined +# in the model configuration file MODEL_CONFIG_FN in the forecast's run +# directory). +# +#----------------------------------------------------------------------- +# +QUILTING="TRUE" +PRINT_ESMF="FALSE" + +WRTCMP_write_groups="1" +WRTCMP_write_tasks_per_group="20" + +WRTCMP_output_grid="''" +WRTCMP_cen_lon="" +WRTCMP_cen_lat="" +WRTCMP_lon_lwr_left="" +WRTCMP_lat_lwr_left="" +# +# The following are used only for the case of WRTCMP_output_grid set to +# "'rotated_latlon'". +# +WRTCMP_lon_upr_rght="" +WRTCMP_lat_upr_rght="" +WRTCMP_dlon="" +WRTCMP_dlat="" +# +# The following are used only for the case of WRTCMP_output_grid set to +# "'lambert_conformal'". +# +WRTCMP_stdlat1="" +WRTCMP_stdlat2="" +WRTCMP_nx="" +WRTCMP_ny="" +WRTCMP_dx="" +WRTCMP_dy="" +# +#----------------------------------------------------------------------- +# +# Set PREDEF_GRID_NAME. This parameter specifies a predefined regional +# grid, as follows: +# +# * If PREDEF_GRID_NAME is set to a valid predefined grid name, the grid +# generation method GRID_GEN_METHOD, the (native) grid parameters, and +# the write-component grid parameters are set to predefined values for +# the specified grid, overwriting any settings of these parameters in +# the user-specified experiment configuration file. In addition, if +# the time step DT_ATMOS and the computational parameters LAYOUT_X, +# LAYOUT_Y, and BLOCKSIZE are not specified in that configuration file, +# they are also set to predefined values for the specified grid. +# +# * If PREDEF_GRID_NAME is set to an empty string, it implies the user +# is providing the native grid parameters in the user-specified +# experiment configuration file (EXPT_CONFIG_FN). In this case, the +# grid generation method GRID_GEN_METHOD, the native grid parameters, +# and the write-component grid parameters as well as the time step +# forecast model's main time step DT_ATMOS and the computational +# parameters LAYOUT_X, LAYOUT_Y, and BLOCKSIZE must be set in that +# configuration file; otherwise, the values of all of these parameters +# in this default experiment configuration file will be used. +# +# Setting PREDEF_GRID_NAME provides a convenient method of specifying a +# commonly used set of grid-dependent parameters. The predefined grid +# parameters are specified in the script +# +# $SR_WX_APP_TOP_DIR/ush/set_predef_grid_params.py +# +#----------------------------------------------------------------------- +# +PREDEF_GRID_NAME="" +# +#----------------------------------------------------------------------- +# +# Set PREEXISTING_DIR_METHOD. This variable determines the method to use +# use to deal with preexisting directories [e.g ones generated by previous +# calls to the experiment generation script using the same experiment name +# (EXPT_SUBDIR) as the current experiment]. This variable must be set to +# one of "delete", "rename", and "quit". The resulting behavior for each +# of these values is as follows: +# +# * "delete": +# The preexisting directory is deleted and a new directory (having the +# same name as the original preexisting directory) is created. +# +# * "rename": +# The preexisting directory is renamed and a new directory (having the +# same name as the original preexisting directory) is created. The new +# name of the preexisting directory consists of its original name and +# the suffix "_oldNNN", where NNN is a 3-digit integer chosen to make +# the new name unique. +# +# * "quit": +# The preexisting directory is left unchanged, but execution of the +# currently running script is terminated. In this case, the preexisting +# directory must be dealt with manually before rerunning the script. +# +#----------------------------------------------------------------------- +# +PREEXISTING_DIR_METHOD="delete" +# +#----------------------------------------------------------------------- +# +# Set flags for more detailed messages. Defintitions: +# +# VERBOSE: +# This is a flag that determines whether or not the experiment generation +# and workflow task scripts tend to print out more informational messages. +# +# DEBUG: +# This is a flag that determines whether or not very detailed debugging +# messages are printed to out. Note that if DEBUG is set to TRUE, then +# VERBOSE will also get reset to TRUE if it isn't already. +# +#----------------------------------------------------------------------- +# +VERBOSE="TRUE" +DEBUG="FALSE" +# +#----------------------------------------------------------------------- +# +# Set the names of the various rocoto workflow tasks. +# +#----------------------------------------------------------------------- +# +MAKE_GRID_TN="make_grid" +MAKE_OROG_TN="make_orog" +MAKE_SFC_CLIMO_TN="make_sfc_climo" +GET_EXTRN_ICS_TN="get_extrn_ics" +GET_EXTRN_LBCS_TN="get_extrn_lbcs" +MAKE_ICS_TN="make_ics" +MAKE_LBCS_TN="make_lbcs" +RUN_FCST_TN="run_fcst" +RUN_POST_TN="run_post" +GET_OBS="get_obs" +GET_OBS_CCPA_TN="get_obs_ccpa" +GET_OBS_MRMS_TN="get_obs_mrms" +GET_OBS_NDAS_TN="get_obs_ndas" +VX_TN="run_vx" +VX_GRIDSTAT_TN="run_gridstatvx" +VX_GRIDSTAT_REFC_TN="run_gridstatvx_refc" +VX_GRIDSTAT_RETOP_TN="run_gridstatvx_retop" +VX_GRIDSTAT_03h_TN="run_gridstatvx_03h" +VX_GRIDSTAT_06h_TN="run_gridstatvx_06h" +VX_GRIDSTAT_24h_TN="run_gridstatvx_24h" +VX_POINTSTAT_TN="run_pointstatvx" +VX_ENSGRID_TN="run_ensgridvx" +VX_ENSGRID_03h_TN="run_ensgridvx_03h" +VX_ENSGRID_06h_TN="run_ensgridvx_06h" +VX_ENSGRID_24h_TN="run_ensgridvx_24h" +VX_ENSGRID_REFC_TN="run_ensgridvx_refc" +VX_ENSGRID_RETOP_TN="run_ensgridvx_retop" +VX_ENSGRID_MEAN_TN="run_ensgridvx_mean" +VX_ENSGRID_PROB_TN="run_ensgridvx_prob" +VX_ENSGRID_MEAN_03h_TN="run_ensgridvx_mean_03h" +VX_ENSGRID_PROB_03h_TN="run_ensgridvx_prob_03h" +VX_ENSGRID_MEAN_06h_TN="run_ensgridvx_mean_06h" +VX_ENSGRID_PROB_06h_TN="run_ensgridvx_prob_06h" +VX_ENSGRID_MEAN_24h_TN="run_ensgridvx_mean_24h" +VX_ENSGRID_PROB_24h_TN="run_ensgridvx_prob_24h" +VX_ENSGRID_PROB_REFC_TN="run_ensgridvx_prob_refc" +VX_ENSGRID_PROB_RETOP_TN="run_ensgridvx_prob_retop" +VX_ENSPOINT_TN="run_enspointvx" +VX_ENSPOINT_MEAN_TN="run_enspointvx_mean" +VX_ENSPOINT_PROB_TN="run_enspointvx_prob" +# +#----------------------------------------------------------------------- +# +# Set flags (and related directories) that determine whether various +# workflow tasks should be run. Note that the MAKE_GRID_TN, MAKE_OROG_TN, +# and MAKE_SFC_CLIMO_TN are all cycle-independent tasks, i.e. if they +# are to be run, they do so only once at the beginning of the workflow +# before any cycles are run. Definitions: +# +# RUN_TASK_MAKE_GRID: +# Flag that determines whether the MAKE_GRID_TN task is to be run. If +# this is set to "TRUE", the grid generation task is run and new grid +# files are generated. If it is set to "FALSE", then the scripts look +# for pregenerated grid files in the directory specified by GRID_DIR +# (see below). +# +# GRID_DIR: +# The directory in which to look for pregenerated grid files if +# RUN_TASK_MAKE_GRID is set to "FALSE". +# +# RUN_TASK_MAKE_OROG: +# Same as RUN_TASK_MAKE_GRID but for the MAKE_OROG_TN task. +# +# OROG_DIR: +# Same as GRID_DIR but for the MAKE_OROG_TN task. +# +# RUN_TASK_MAKE_SFC_CLIMO: +# Same as RUN_TASK_MAKE_GRID but for the MAKE_SFC_CLIMO_TN task. +# +# SFC_CLIMO_DIR: +# Same as GRID_DIR but for the MAKE_SFC_CLIMO_TN task. +# +# DOMAIN_PREGEN_BASEDIR: +# The base directory containing pregenerated grid, orography, and surface +# climatology files. This is an alternative for setting GRID_DIR, +# OROG_DIR, and SFC_CLIMO_DIR individually +# +# For the pregenerated grid specified by PREDEF_GRID_NAME, +# these "fixed" files are located in: +# +# ${DOMAIN_PREGEN_BASEDIR}/${PREDEF_GRID_NAME} +# +# The workflow scripts will create a symlink in the experiment directory +# that will point to a subdirectory (having the name of the grid being +# used) under this directory. This variable should be set to a null +# string in this file, but it can be specified in the user-specified +# workflow configuration file (EXPT_CONFIG_FN). +# +# RUN_TASK_GET_EXTRN_ICS: +# Flag that determines whether the GET_EXTRN_ICS_TN task is to be run. +# +# RUN_TASK_GET_EXTRN_LBCS: +# Flag that determines whether the GET_EXTRN_LBCS_TN task is to be run. +# +# RUN_TASK_MAKE_ICS: +# Flag that determines whether the MAKE_ICS_TN task is to be run. +# +# RUN_TASK_MAKE_LBCS: +# Flag that determines whether the MAKE_LBCS_TN task is to be run. +# +# RUN_TASK_RUN_FCST: +# Flag that determines whether the RUN_FCST_TN task is to be run. +# +# RUN_TASK_RUN_POST: +# Flag that determines whether the RUN_POST_TN task is to be run. +# +# RUN_TASK_VX_GRIDSTAT: +# Flag that determines whether the grid-stat verification task is to be +# run. +# +# RUN_TASK_VX_POINTSTAT: +# Flag that determines whether the point-stat verification task is to be +# run. +# +# RUN_TASK_VX_ENSGRID: +# Flag that determines whether the ensemble-stat verification for gridded +# data task is to be run. +# +# RUN_TASK_VX_ENSPOINT: +# Flag that determines whether the ensemble point verification task is +# to be run. If this flag is set, both ensemble-stat point verification +# and point verification of ensemble-stat output is computed. +# +#----------------------------------------------------------------------- +# +RUN_TASK_MAKE_GRID="TRUE" +GRID_DIR="/path/to/pregenerated/grid/files" + +RUN_TASK_MAKE_OROG="TRUE" +OROG_DIR="/path/to/pregenerated/orog/files" + +RUN_TASK_MAKE_SFC_CLIMO="TRUE" +SFC_CLIMO_DIR="/path/to/pregenerated/surface/climo/files" + +DOMAIN_PREGEN_BASEDIR="" + +RUN_TASK_GET_EXTRN_ICS="TRUE" +RUN_TASK_GET_EXTRN_LBCS="TRUE" +RUN_TASK_MAKE_ICS="TRUE" +RUN_TASK_MAKE_LBCS="TRUE" +RUN_TASK_RUN_FCST="TRUE" +RUN_TASK_RUN_POST="TRUE" + +RUN_TASK_GET_OBS_CCPA="FALSE" +RUN_TASK_GET_OBS_MRMS="FALSE" +RUN_TASK_GET_OBS_NDAS="FALSE" +RUN_TASK_VX_GRIDSTAT="FALSE" +RUN_TASK_VX_POINTSTAT="FALSE" +RUN_TASK_VX_ENSGRID="FALSE" +RUN_TASK_VX_ENSPOINT="FALSE" +# +#----------------------------------------------------------------------- +# +# Flag that determines whether MERRA2 aerosol climatology data and +# lookup tables for optics properties are obtained +# +#----------------------------------------------------------------------- +# +USE_MERRA_CLIMO="FALSE" +# +#----------------------------------------------------------------------- +# +# Set the array parameter containing the names of all the fields that the +# MAKE_SFC_CLIMO_TN task generates on the native FV3-LAM grid. +# +#----------------------------------------------------------------------- +# +SFC_CLIMO_FIELDS=( \ +"facsf" \ +"maximum_snow_albedo" \ +"slope_type" \ +"snowfree_albedo" \ +"soil_type" \ +"substrate_temperature" \ +"vegetation_greenness" \ +"vegetation_type" \ +) +# +#----------------------------------------------------------------------- +# +# Set parameters associated with the fixed (i.e. static) files. Definitions: +# +# FIXgsm: +# System directory in which the majority of fixed (i.e. time-independent) +# files that are needed to run the FV3-LAM model are located +# +# FIXaer: +# System directory where MERRA2 aerosol climatology files are located +# +# FIXlut: +# System directory where the lookup tables for optics properties are located +# +# TOPO_DIR: +# The location on disk of the static input files used by the make_orog +# task (orog.x and shave.x). Can be the same as FIXgsm. +# +# SFC_CLIMO_INPUT_DIR: +# The location on disk of the static surface climatology input fields, used by +# sfc_climo_gen. These files are only used if RUN_TASK_MAKE_SFC_CLIMO=TRUE +# +# FNGLAC, ..., FNMSKH: +# Names of (some of the) global data files that are assumed to exist in +# a system directory specified (this directory is machine-dependent; +# the experiment generation scripts will set it and store it in the +# variable FIXgsm). These file names also appear directly in the forecast +# model's input namelist file. +# +# FIXgsm_FILES_TO_COPY_TO_FIXam: +# If not running in NCO mode, this array contains the names of the files +# to copy from the FIXgsm system directory to the FIXam directory under +# the experiment directory. Note that the last element has a dummy value. +# This last element will get reset by the workflow generation scripts to +# the name of the ozone production/loss file to copy from FIXgsm. The +# name of this file depends on the ozone parameterization being used, +# and that in turn depends on the CCPP physics suite specified for the +# experiment. Thus, the CCPP physics suite XML must first be read in to +# determine the ozone parameterizaton and then the name of the ozone +# production/loss file. These steps are carried out elsewhere (in one +# of the workflow generation scripts/functions). +# +# FV3_NML_VARNAME_TO_FIXam_FILES_MAPPING: +# This array is used to set some of the namelist variables in the forecast +# model's namelist file that represent the relative or absolute paths of +# various fixed files (the first column of the array, where columns are +# delineated by the pipe symbol "|") to the full paths to these files in +# the FIXam directory derived from the corresponding workflow variables +# containing file names (the second column of the array). +# +# FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING: +# This array is used to set some of the namelist variables in the forecast +# model's namelist file that represent the relative or absolute paths of +# various fixed files (the first column of the array, where columns are +# delineated by the pipe symbol "|") to the full paths to surface climatology +# files (on the native FV3-LAM grid) in the FIXLAM directory derived from +# the corresponding surface climatology fields (the second column of the +# array). +# +# CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING: +# This array specifies the mapping to use between the symlinks that need +# to be created in each cycle directory (these are the "files" that FV3 +# looks for) and their targets in the FIXam directory. The first column +# of the array specifies the symlink to be created, and the second column +# specifies its target file in FIXam (where columns are delineated by the +# pipe symbol "|"). +# +#----------------------------------------------------------------------- +# +# Because the default values are dependent on the platform, we set these +# to a null string which will then be overwritten in setup.sh unless the +# user has specified a different value in config.sh +FIXgsm="" +FIXaer="" +FIXlut="" +TOPO_DIR="" +SFC_CLIMO_INPUT_DIR="" + +FNGLAC="global_glacier.2x2.grb" +FNMXIC="global_maxice.2x2.grb" +FNTSFC="RTGSST.1982.2012.monthly.clim.grb" +FNSNOC="global_snoclim.1.875.grb" +FNZORC="igbp" +FNAISC="CFSR.SEAICE.1982.2012.monthly.clim.grb" +FNSMCC="global_soilmgldas.t126.384.190.grb" +FNMSKH="seaice_newland.grb" + +FIXgsm_FILES_TO_COPY_TO_FIXam=( \ +"$FNGLAC" \ +"$FNMXIC" \ +"$FNTSFC" \ +"$FNSNOC" \ +"$FNAISC" \ +"$FNSMCC" \ +"$FNMSKH" \ +"global_climaeropac_global.txt" \ +"fix_co2_proj/global_co2historicaldata_2010.txt" \ +"fix_co2_proj/global_co2historicaldata_2011.txt" \ +"fix_co2_proj/global_co2historicaldata_2012.txt" \ +"fix_co2_proj/global_co2historicaldata_2013.txt" \ +"fix_co2_proj/global_co2historicaldata_2014.txt" \ +"fix_co2_proj/global_co2historicaldata_2015.txt" \ +"fix_co2_proj/global_co2historicaldata_2016.txt" \ +"fix_co2_proj/global_co2historicaldata_2017.txt" \ +"fix_co2_proj/global_co2historicaldata_2018.txt" \ +"fix_co2_proj/global_co2historicaldata_2019.txt" \ +"fix_co2_proj/global_co2historicaldata_2020.txt" \ +"fix_co2_proj/global_co2historicaldata_2021.txt" \ +"global_co2historicaldata_glob.txt" \ +"co2monthlycyc.txt" \ +"global_h2o_pltc.f77" \ +"global_hyblev.l65.txt" \ +"global_zorclim.1x1.grb" \ +"global_sfc_emissivity_idx.txt" \ +"global_tg3clim.2.6x1.5.grb" \ +"global_solarconstant_noaa_an.txt" \ +"global_albedo4.1x1.grb" \ +"geo_em.d01.lat-lon.2.5m.HGT_M.nc" \ +"HGT.Beljaars_filtered.lat-lon.30s_res.nc" \ +"replace_with_FIXgsm_ozone_prodloss_filename" \ +) + +# +# It is possible to remove this as a workflow variable and make it only +# a local one since it is used in only one script. +# +FV3_NML_VARNAME_TO_FIXam_FILES_MAPPING=( \ +"FNGLAC | $FNGLAC" \ +"FNMXIC | $FNMXIC" \ +"FNTSFC | $FNTSFC" \ +"FNSNOC | $FNSNOC" \ +"FNAISC | $FNAISC" \ +"FNSMCC | $FNSMCC" \ +"FNMSKH | $FNMSKH" \ +) +#"FNZORC | $FNZORC" \ + +FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING=( \ +"FNALBC | snowfree_albedo" \ +"FNALBC2 | facsf" \ +"FNTG3C | substrate_temperature" \ +"FNVEGC | vegetation_greenness" \ +"FNVETC | vegetation_type" \ +"FNSOTC | soil_type" \ +"FNVMNC | vegetation_greenness" \ +"FNVMXC | vegetation_greenness" \ +"FNSLPC | slope_type" \ +"FNABSC | maximum_snow_albedo" \ +) + +CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING=( \ +"aerosol.dat | global_climaeropac_global.txt" \ +"co2historicaldata_2010.txt | fix_co2_proj/global_co2historicaldata_2010.txt" \ +"co2historicaldata_2011.txt | fix_co2_proj/global_co2historicaldata_2011.txt" \ +"co2historicaldata_2012.txt | fix_co2_proj/global_co2historicaldata_2012.txt" \ +"co2historicaldata_2013.txt | fix_co2_proj/global_co2historicaldata_2013.txt" \ +"co2historicaldata_2014.txt | fix_co2_proj/global_co2historicaldata_2014.txt" \ +"co2historicaldata_2015.txt | fix_co2_proj/global_co2historicaldata_2015.txt" \ +"co2historicaldata_2016.txt | fix_co2_proj/global_co2historicaldata_2016.txt" \ +"co2historicaldata_2017.txt | fix_co2_proj/global_co2historicaldata_2017.txt" \ +"co2historicaldata_2018.txt | fix_co2_proj/global_co2historicaldata_2018.txt" \ +"co2historicaldata_2019.txt | fix_co2_proj/global_co2historicaldata_2019.txt" \ +"co2historicaldata_2020.txt | fix_co2_proj/global_co2historicaldata_2020.txt" \ +"co2historicaldata_2021.txt | fix_co2_proj/global_co2historicaldata_2021.txt" \ +"co2historicaldata_glob.txt | global_co2historicaldata_glob.txt" \ +"co2monthlycyc.txt | co2monthlycyc.txt" \ +"global_h2oprdlos.f77 | global_h2o_pltc.f77" \ +"global_albedo4.1x1.grb | global_albedo4.1x1.grb" \ +"global_zorclim.1x1.grb | global_zorclim.1x1.grb" \ +"global_tg3clim.2.6x1.5.grb | global_tg3clim.2.6x1.5.grb" \ +"sfc_emissivity_idx.txt | global_sfc_emissivity_idx.txt" \ +"solarconstant_noaa_an.txt | global_solarconstant_noaa_an.txt" \ +"global_o3prdlos.f77 | " \ +) +# +#----------------------------------------------------------------------- +# +# For each workflow task, set the parameters to pass to the job scheduler +# (e.g. slurm) that will submit a job for each task to be run. These +# parameters include the number of nodes to use to run the job, the MPI +# processes per node, the maximum walltime to allow for the job to complete, +# and the maximum number of times to attempt to run each task. +# +#----------------------------------------------------------------------- +# +# Number of nodes. +# +NNODES_MAKE_GRID="1" +NNODES_MAKE_OROG="1" +NNODES_MAKE_SFC_CLIMO="2" +NNODES_GET_EXTRN_ICS="1" +NNODES_GET_EXTRN_LBCS="1" +NNODES_MAKE_ICS="4" +NNODES_MAKE_LBCS="4" +NNODES_RUN_FCST="" # This is calculated in the workflow generation scripts, so no need to set here. +NNODES_RUN_POST="2" +NNODES_GET_OBS_CCPA="1" +NNODES_GET_OBS_MRMS="1" +NNODES_GET_OBS_NDAS="1" +NNODES_VX_GRIDSTAT="1" +NNODES_VX_POINTSTAT="1" +NNODES_VX_ENSGRID="1" +NNODES_VX_ENSGRID_MEAN="1" +NNODES_VX_ENSGRID_PROB="1" +NNODES_VX_ENSPOINT="1" +NNODES_VX_ENSPOINT_MEAN="1" +NNODES_VX_ENSPOINT_PROB="1" +# +# Number of MPI processes per node. +# +PPN_MAKE_GRID="24" +PPN_MAKE_OROG="24" +PPN_MAKE_SFC_CLIMO="24" +PPN_GET_EXTRN_ICS="1" +PPN_GET_EXTRN_LBCS="1" +PPN_MAKE_ICS="12" +PPN_MAKE_LBCS="12" +PPN_RUN_FCST="" # will be calculated from NCORES_PER_NODE and OMP_NUM_THREADS in setup.sh +PPN_RUN_POST="24" +PPN_GET_OBS_CCPA="1" +PPN_GET_OBS_MRMS="1" +PPN_GET_OBS_NDAS="1" +PPN_VX_GRIDSTAT="1" +PPN_VX_POINTSTAT="1" +PPN_VX_ENSGRID="1" +PPN_VX_ENSGRID_MEAN="1" +PPN_VX_ENSGRID_PROB="1" +PPN_VX_ENSPOINT="1" +PPN_VX_ENSPOINT_MEAN="1" +PPN_VX_ENSPOINT_PROB="1" +# +# Walltimes. +# +WTIME_MAKE_GRID="00:20:00" +WTIME_MAKE_OROG="00:20:00" +WTIME_MAKE_SFC_CLIMO="00:20:00" +WTIME_GET_EXTRN_ICS="00:45:00" +WTIME_GET_EXTRN_LBCS="00:45:00" +WTIME_MAKE_ICS="00:30:00" +WTIME_MAKE_LBCS="00:30:00" +WTIME_RUN_FCST="04:30:00" +WTIME_RUN_POST="00:15:00" +WTIME_GET_OBS_CCPA="00:45:00" +WTIME_GET_OBS_MRMS="00:45:00" +WTIME_GET_OBS_NDAS="02:00:00" +WTIME_VX_GRIDSTAT="02:00:00" +WTIME_VX_POINTSTAT="01:00:00" +WTIME_VX_ENSGRID="01:00:00" +WTIME_VX_ENSGRID_MEAN="01:00:00" +WTIME_VX_ENSGRID_PROB="01:00:00" +WTIME_VX_ENSPOINT="01:00:00" +WTIME_VX_ENSPOINT_MEAN="01:00:00" +WTIME_VX_ENSPOINT_PROB="01:00:00" +# +# Maximum number of attempts. +# +MAXTRIES_MAKE_GRID="2" +MAXTRIES_MAKE_OROG="2" +MAXTRIES_MAKE_SFC_CLIMO="2" +MAXTRIES_GET_EXTRN_ICS="1" +MAXTRIES_GET_EXTRN_LBCS="1" +MAXTRIES_MAKE_ICS="1" +MAXTRIES_MAKE_LBCS="1" +MAXTRIES_RUN_FCST="1" +MAXTRIES_RUN_POST="2" +MAXTRIES_GET_OBS_CCPA="1" +MAXTRIES_GET_OBS_MRMS="1" +MAXTRIES_GET_OBS_NDAS="1" +MAXTRIES_VX_GRIDSTAT="1" +MAXTRIES_VX_GRIDSTAT_REFC="1" +MAXTRIES_VX_GRIDSTAT_RETOP="1" +MAXTRIES_VX_GRIDSTAT_03h="1" +MAXTRIES_VX_GRIDSTAT_06h="1" +MAXTRIES_VX_GRIDSTAT_24h="1" +MAXTRIES_VX_POINTSTAT="1" +MAXTRIES_VX_ENSGRID="1" +MAXTRIES_VX_ENSGRID_REFC="1" +MAXTRIES_VX_ENSGRID_RETOP="1" +MAXTRIES_VX_ENSGRID_03h="1" +MAXTRIES_VX_ENSGRID_06h="1" +MAXTRIES_VX_ENSGRID_24h="1" +MAXTRIES_VX_ENSGRID_MEAN="1" +MAXTRIES_VX_ENSGRID_PROB="1" +MAXTRIES_VX_ENSGRID_MEAN_03h="1" +MAXTRIES_VX_ENSGRID_PROB_03h="1" +MAXTRIES_VX_ENSGRID_MEAN_06h="1" +MAXTRIES_VX_ENSGRID_PROB_06h="1" +MAXTRIES_VX_ENSGRID_MEAN_24h="1" +MAXTRIES_VX_ENSGRID_PROB_24h="1" +MAXTRIES_VX_ENSGRID_PROB_REFC="1" +MAXTRIES_VX_ENSGRID_PROB_RETOP="1" +MAXTRIES_VX_ENSPOINT="1" +MAXTRIES_VX_ENSPOINT_MEAN="1" +MAXTRIES_VX_ENSPOINT_PROB="1" + +# +#----------------------------------------------------------------------- +# +# Allows an extra parameter to be passed to slurm via XML Native +# command +# +SLURM_NATIVE_CMD="" +# +#----------------------------------------------------------------------- +# +# Set parameters associated with subhourly forecast model output and +# post-processing. +# +# SUB_HOURLY_POST: +# Flag that indicates whether the forecast model will generate output +# files on a sub-hourly time interval (e.g. 10 minutes, 15 minutes, etc). +# This will also cause the post-processor to process these sub-hourly +# files. If ths is set to "TRUE", then DT_SUBHOURLY_POST_MNTS should be +# set to a value between "00" and "59". +# +# DT_SUB_HOURLY_POST_MNTS: +# Time interval in minutes between the forecast model output files. If +# SUB_HOURLY_POST is set to "TRUE", this needs to be set to a two-digit +# integer between "01" and "59". This is not used if SUB_HOURLY_POST is +# not set to "TRUE". Note that if SUB_HOURLY_POST is set to "TRUE" but +# DT_SUB_HOURLY_POST_MNTS is set to "00", SUB_HOURLY_POST will get reset +# to "FALSE" in the experiment generation scripts (there will be an +# informational message in the log file to emphasize this). +# +#----------------------------------------------------------------------- +# +SUB_HOURLY_POST="FALSE" +DT_SUBHOURLY_POST_MNTS="00" +# +#----------------------------------------------------------------------- +# +# Set parameters for customizing the post-processor (UPP). Definitions: +# +# USE_CUSTOM_POST_CONFIG_FILE: +# Flag that determines whether a user-provided custom configuration file +# should be used for post-processing the model data. If this is set to +# "TRUE", then the workflow will use the custom post-processing (UPP) +# configuration file specified in CUSTOM_POST_CONFIG_FP. Otherwise, a +# default configuration file provided in the UPP repository will be +# used. +# +# CUSTOM_POST_CONFIG_FP: +# The full path to the custom post flat file, including filename, to be +# used for post-processing. This is only used if CUSTOM_POST_CONFIG_FILE +# is set to "TRUE". +# +# POST_OUTPUT_DOMAIN_NAME: +# Domain name (in lowercase) used in constructing the names of the output +# files generated by UPP [which is called either by running the RUN_POST_TN +# task or by activating the inline post feature (WRITE_DOPOST set to "TRUE")]. +# The post output files are named as follows: +# +# $NET.tHHz.[var_name].f###.${POST_OUTPUT_DOMAIN_NAME}.grib2 +# +# If using a custom grid, POST_OUTPUT_DOMAIN_NAME must be specified by +# the user. If using a predefined grid, POST_OUTPUT_DOMAIN_NAME defaults +# to PREDEF_GRID_NAME. Note that this variable is first changed to lower +# case before being used to construct the file names. +# +#----------------------------------------------------------------------- +# +USE_CUSTOM_POST_CONFIG_FILE="FALSE" +CUSTOM_POST_CONFIG_FP="" +POST_OUTPUT_DOMAIN_NAME="" +# +#----------------------------------------------------------------------- +# +# Set parameters associated with outputting satellite fields in the UPP +# grib2 files using the Community Radiative Transfer Model (CRTM). +# +# USE_CRTM: +# Flag that defines whether external CRTM coefficient files have been +# staged by the user in order to output synthetic statellite products +# available within the UPP. If this is set to "TRUE", then the workflow +# will check for these files in the directory CRTM_DIR. Otherwise, it is +# assumed that no satellite fields are being requested in the UPP +# configuration. +# +# CRTM_DIR: +# This is the path to the top CRTM fix file directory. This is only used +# if USE_CRTM is set to "TRUE". +# +#----------------------------------------------------------------------- +# +USE_CRTM="FALSE" +CRTM_DIR="" +# +#----------------------------------------------------------------------- +# +# Set parameters associated with running ensembles. Definitions: +# +# DO_ENSEMBLE: +# Flag that determines whether to run a set of ensemble forecasts (for +# each set of specified cycles). If this is set to "TRUE", NUM_ENS_MEMBERS +# forecasts are run for each cycle, each with a different set of stochastic +# seed values. Otherwise, a single forecast is run for each cycle. +# +# NUM_ENS_MEMBERS: +# The number of ensemble members to run if DO_ENSEMBLE is set to "TRUE". +# This variable also controls the naming of the ensemble member directories. +# For example, if this is set to "8", the member directories will be named +# mem1, mem2, ..., mem8. If it is set to "08" (note the leading zero), +# the member directories will be named mem01, mem02, ..., mem08. Note, +# however, that after reading in the number of characters in this string +# (in order to determine how many leading zeros, if any, should be placed +# in the names of the member directories), the workflow generation scripts +# strip away those leading zeros. Thus, in the variable definitions file +# (GLOBAL_VAR_DEFNS_FN), this variable appear with its leading zeros +# stripped. This variable is not used if DO_ENSEMBLE is not set to "TRUE". +# +#----------------------------------------------------------------------- +# +DO_ENSEMBLE="FALSE" +NUM_ENS_MEMBERS="1" +# +#----------------------------------------------------------------------- +# +# Set default ad-hoc stochastic physics options. +# For detailed documentation of these parameters, see: +# https://stochastic-physics.readthedocs.io/en/ufs_public_release/namelist_options.html +# +#----------------------------------------------------------------------- +# +DO_SHUM="FALSE" +DO_SPPT="FALSE" +DO_SKEB="FALSE" +ISEED_SPPT="1" +ISEED_SHUM="2" +ISEED_SKEB="3" +NEW_LSCALE="TRUE" +SHUM_MAG="0.006" #Variable "shum" in input.nml +SHUM_LSCALE="150000" +SHUM_TSCALE="21600" #Variable "shum_tau" in input.nml +SHUM_INT="3600" #Variable "shumint" in input.nml +SPPT_MAG="0.7" #Variable "sppt" in input.nml +SPPT_LOGIT="TRUE" +SPPT_LSCALE="150000" +SPPT_TSCALE="21600" #Variable "sppt_tau" in input.nml +SPPT_INT="3600" #Variable "spptint" in input.nml +SPPT_SFCLIMIT="TRUE" +SKEB_MAG="0.5" #Variable "skeb" in input.nml +SKEB_LSCALE="150000" +SKEB_TSCALE="21600" #Variable "skeb_tau" in input.nml +SKEB_INT="3600" #Variable "skebint" in input.nml +SKEBNORM="1" +SKEB_VDOF="10" +USE_ZMTNBLCK="FALSE" +# +#----------------------------------------------------------------------- +# +# Set default SPP stochastic physics options. Each SPP option is an array, +# applicable (in order) to the scheme/parameter listed in SPP_VAR_LIST. +# Enter each value of the array in config.sh as shown below without commas +# or single quotes (e.g., SPP_VAR_LIST=( "pbl" "sfc" "mp" "rad" "gwd" ). +# Both commas and single quotes will be added by Jinja when creating the +# namelist. +# +# Note that SPP is currently only available for specific physics schemes +# used in the RAP/HRRR physics suite. Users need to be aware of which SDF +# is chosen when turning this option on. +# +# Patterns evolve and are applied at each time step. +# +#----------------------------------------------------------------------- +# +DO_SPP="false" +SPP_VAR_LIST=( "pbl" "sfc" "mp" "rad" "gwd" ) +SPP_MAG_LIST=( "0.2" "0.2" "0.75" "0.2" "0.2" ) #Variable "spp_prt_list" in input.nml +SPP_LSCALE=( "150000.0" "150000.0" "150000.0" "150000.0" "150000.0" ) +SPP_TSCALE=( "21600.0" "21600.0" "21600.0" "21600.0" "21600.0" ) #Variable "spp_tau" in input.nml +SPP_SIGTOP1=( "0.1" "0.1" "0.1" "0.1" "0.1") +SPP_SIGTOP2=( "0.025" "0.025" "0.025" "0.025" "0.025" ) +SPP_STDDEV_CUTOFF=( "1.5" "1.5" "2.5" "1.5" "1.5" ) +ISEED_SPP=( "4" "5" "6" "7" "8" ) +# +#----------------------------------------------------------------------- +# +# Turn on SPP in Noah or RUC LSM (support for Noah MP is in progress). +# Please be aware of the SDF that you choose if you wish to turn on LSM +# SPP. +# +# SPP in LSM schemes is handled in the &nam_sfcperts namelist block +# instead of in &nam_sppperts, where all other SPP is implemented. +# +# Perturbations to soil moisture content (SMC) are only applied at the +# first time step. +# +# LSM perturbations include SMC - soil moisture content (volume fraction), +# VGF - vegetation fraction, ALB - albedo, SAL - salinity, +# EMI - emissivity, ZOL - surface roughness (cm), and STC - soil temperature. +# +# Only five perturbations at a time can be applied currently, but all seven +# are shown below. In addition, only one unique iseed value is allowed +# at the moment, and is used for each pattern. +# +DO_LSM_SPP="false" #If true, sets lndp_type=2, lndp_model_type=2 +LSM_SPP_TSCALE=( "21600" "21600" "21600" "21600" "21600" "21600" "21600" ) +LSM_SPP_LSCALE=( "150000" "150000" "150000" "150000" "150000" "150000" "150000" ) +ISEED_LSM_SPP=( "9" ) +LSM_SPP_VAR_LIST=( "smc" "vgf" "alb" "sal" "emi" "zol" "stc" ) +LSM_SPP_MAG_LIST=( "0.017" "0.001" "0.001" "0.001" "0.001" "0.001" "0.2" ) +LSM_SPP_EACH_STEP="true" #Sets lndp_each_step=.true. +# +#----------------------------------------------------------------------- +# +# HALO_BLEND: +# Number of rows into the computational domain that should be blended +# with the LBCs. To shut halo blending off, this can be set to zero. +# +#----------------------------------------------------------------------- +# +HALO_BLEND="10" +# +#----------------------------------------------------------------------- +# +# USE_FVCOM: +# Flag set to update surface conditions in FV3-LAM with fields generated +# from the Finite Volume Community Ocean Model (FVCOM). This will +# replace lake/sea surface temperature, ice surface temperature, and ice +# placement. FVCOM data must already be interpolated to the desired +# FV3-LAM grid. This flag will be used in make_ics to modify sfc_data.nc +# after chgres_cube is run by running the routine process_FVCOM.exe +# +# FVCOM_WCSTART: +# Define if this is a "warm" start or a "cold" start. Setting this to +# "warm" will read in sfc_data.nc generated in a RESTART directory. +# Setting this to "cold" will read in the sfc_data.nc generated from +# chgres_cube in the make_ics portion of the workflow. +# +# FVCOM_DIR: +# User defined directory where FVCOM data already interpolated to FV3-LAM +# grid is located. File name in this path should be "fvcom.nc" to allow +# +# FVCOM_FILE: +# Name of file located in FVCOM_DIR that has FVCOM data interpolated to +# FV3-LAM grid. This file will be copied later to a new location and name +# changed to fvcom.nc +# +#------------------------------------------------------------------------ +# +USE_FVCOM="FALSE" +FVCOM_WCSTART="cold" +FVCOM_DIR="/user/defined/dir/to/fvcom/data" +FVCOM_FILE="fvcom.nc" +# +#----------------------------------------------------------------------- +# +# COMPILER: +# Type of compiler invoked during the build step. +# +#------------------------------------------------------------------------ +# +COMPILER="intel" +# +#----------------------------------------------------------------------- +# +# KMP_AFFINITY_*: +# From Intel: "The Intel® runtime library has the ability to bind OpenMP +# threads to physical processing units. The interface is controlled using +# the KMP_AFFINITY environment variable. Depending on the system (machine) +# topology, application, and operating system, thread affinity can have a +# dramatic effect on the application speed. +# +# Thread affinity restricts execution of certain threads (virtual execution +# units) to a subset of the physical processing units in a multiprocessor +# computer. Depending upon the topology of the machine, thread affinity can +# have a dramatic effect on the execution speed of a program." +# +# For more information, see the following link: +# https://software.intel.com/content/www/us/en/develop/documentation/cpp- +# compiler-developer-guide-and-reference/top/optimization-and-programming- +# guide/openmp-support/openmp-library-support/thread-affinity-interface- +# linux-and-windows.html +# +# OMP_NUM_THREADS_*: +# The number of OpenMP threads to use for parallel regions. +# +# OMP_STACKSIZE_*: +# Controls the size of the stack for threads created by the OpenMP +# implementation. +# +# Note that settings for the make_grid and make_orog tasks are not +# included below as they do not use parallelized code. +# +#----------------------------------------------------------------------- +# +KMP_AFFINITY_MAKE_OROG="disabled" +OMP_NUM_THREADS_MAKE_OROG="6" +OMP_STACKSIZE_MAKE_OROG="2048m" + +KMP_AFFINITY_MAKE_SFC_CLIMO="scatter" +OMP_NUM_THREADS_MAKE_SFC_CLIMO="1" +OMP_STACKSIZE_MAKE_SFC_CLIMO="1024m" + +KMP_AFFINITY_MAKE_ICS="scatter" +OMP_NUM_THREADS_MAKE_ICS="1" +OMP_STACKSIZE_MAKE_ICS="1024m" + +KMP_AFFINITY_MAKE_LBCS="scatter" +OMP_NUM_THREADS_MAKE_LBCS="1" +OMP_STACKSIZE_MAKE_LBCS="1024m" + +KMP_AFFINITY_RUN_FCST="scatter" +OMP_NUM_THREADS_RUN_FCST="2" # atmos_nthreads in model_configure +OMP_STACKSIZE_RUN_FCST="1024m" + +KMP_AFFINITY_RUN_POST="scatter" +OMP_NUM_THREADS_RUN_POST="1" +OMP_STACKSIZE_RUN_POST="1024m" +# +#----------------------------------------------------------------------- +# diff --git a/ush/constants.sh b/ush/constants.sh new file mode 100644 index 0000000000..f5bce884e8 --- /dev/null +++ b/ush/constants.sh @@ -0,0 +1,65 @@ +# +#----------------------------------------------------------------------- +# +# Mathematical and physical constants. +# +#----------------------------------------------------------------------- +# + +# Pi. +PI_GEOM="3.14159265358979323846264338327" + +# Degrees per radian. +DEGS_PER_RADIAN=$( bc -l <<< "360.0/(2.0*${PI_GEOM})" ) + +# Radius of the Earth in meters. +RADIUS_EARTH="6371200.0" +# +#----------------------------------------------------------------------- +# +# Valid values that a user may set a boolean variable to (e.g. in the +# SRW App's experiment configuration file). +# +#----------------------------------------------------------------------- +# +valid_vals_BOOLEAN=("TRUE" "true" "YES" "yes" "FALSE" "false" "NO" "no") +# +#----------------------------------------------------------------------- +# +# Any regional model must be supplied lateral boundary conditions (in +# addition to initial conditions) to be able to perform a forecast. In +# the FV3-LAM model, these boundary conditions (BCs) are supplied using +# a "halo" of grid cells around the regional domain that extend beyond +# the boundary of the domain. The model is formulated such that along +# with files containing these BCs, it needs as input the following files +# (in NetCDF format): +# +# 1) A grid file that includes a halo of 3 cells beyond the boundary of +# the domain. +# 2) A grid file that includes a halo of 4 cells beyond the boundary of +# the domain. +# 3) A (filtered) orography file without a halo, i.e. a halo of width +# 0 cells. +# 4) A (filtered) orography file that includes a halo of 4 cells beyond +# the boundary of the domain. +# +# Note that the regional grid is referred to as "tile 7" in the code. +# We will let: +# +# * NH0 denote the width (in units of number of cells on tile 7) of +# the 0-cell-wide halo, i.e. NH0 = 0; +# +# * NH3 denote the width (in units of number of cells on tile 7) of +# the 3-cell-wide halo, i.e. NH3 = 3; and +# +# * NH4 denote the width (in units of number of cells on tile 7) of +# the 4-cell-wide halo, i.e. NH4 = 4. +# +# We define these variables next. +# +#----------------------------------------------------------------------- +# +NH0=0 +NH3=3 +NH4=4 + diff --git a/ush/create_diag_table_file.py b/ush/create_diag_table_file.py new file mode 100644 index 0000000000..0ac892727f --- /dev/null +++ b/ush/create_diag_table_file.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse +import unittest +from textwrap import dedent + +from python_utils import import_vars, set_env_var, print_input_args, \ + print_info_msg, print_err_msg_exit, cfg_to_yaml_str, \ + load_shell_config + +from fill_jinja_template import fill_jinja_template + +def create_diag_table_file(run_dir): + """ Creates a diagnostic table file for each cycle to be run + + Args: + run_dir: run directory + Returns: + Boolean + """ + + print_input_args(locals()) + + #import all environment variables + import_vars() + + #create a diagnostic table file within the specified run directory + print_info_msg(f''' + Creating a diagnostics table file (\"{DIAG_TABLE_FN}\") in the specified + run directory... + + run_dir = \"{run_dir}\"''', verbose=VERBOSE) + + diag_table_fp = os.path.join(run_dir, DIAG_TABLE_FN) + + print_info_msg(f''' + + Using the template diagnostics table file: + + diag_table_tmpl_fp = {DIAG_TABLE_TMPL_FP} + + to create: + + diag_table_fp = \"{diag_table_fp}\"''', verbose=VERBOSE) + + settings = { + 'starttime': CDATE, + 'cres': CRES + } + settings_str = cfg_to_yaml_str(settings) + + print_info_msg(dedent(f''' + The variable \"settings\" specifying values to be used in the \"{DIAG_TABLE_FN}\" + file has been set as follows:\n + settings =\n\n''') + settings_str,verbose=VERBOSE) + + #call fill jinja + try: + fill_jinja_template(["-q", "-u", settings_str, "-t", DIAG_TABLE_TMPL_FP, "-o", diag_table_fp]) + except: + print_err_msg_exit(dedent(f''' + Call to python script fill_jinja_template.py to create a \"{DIAG_TABLE_FN}\" + file from a jinja2 template failed. Parameters passed to this script are: + Full path to template diag table file: + DIAG_TABLE_TMPL_FP = \"{DIAG_TABLE_TMPL_FP}\" + Full path to output diag table file: + diag_table_fp = \"{diag_table_fp}\" + Namelist settings specified on command line:\n + settings =\n\n''') + settings_str) + return False + return True + +def parse_args(argv): + """ Parse command line arguments""" + parser = argparse.ArgumentParser( + description='Creates diagnostic table file.' + ) + + parser.add_argument('-r', '--run-dir', + dest='run_dir', + required=True, + help='Run directory.') + + parser.add_argument('-p', '--path-to-defns', + dest='path_to_defns', + required=True, + help='Path to var_defns file.') + + return parser.parse_args(argv) + +if __name__ == '__main__': + args = parse_args(sys.argv[1:]) + cfg = load_shell_config(args.path_to_defns) + import_vars(dictionary=cfg) + create_diag_table_file(args.run_dir) + +class Testing(unittest.TestCase): + def test_create_diag_table_file(self): + path = os.path.join(os.getenv('USHDIR'), "test_data") + self.assertTrue(create_diag_table_file(run_dir=path)) + def setUp(self): + USHDIR = os.path.dirname(os.path.abspath(__file__)) + DIAG_TABLE_FN="diag_table" + DIAG_TABLE_TMPL_FP = os.path.join(USHDIR,"templates",f"{DIAG_TABLE_FN}.FV3_GFS_v15p2") + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + set_env_var("USHDIR",USHDIR) + set_env_var("DIAG_TABLE_FN",DIAG_TABLE_FN) + set_env_var("DIAG_TABLE_TMPL_FP",DIAG_TABLE_TMPL_FP) + set_env_var("CRES","C48") + set_env_var("CDATE","2021010106") + diff --git a/ush/create_model_configure_file.py b/ush/create_model_configure_file.py new file mode 100644 index 0000000000..0ae12cd069 --- /dev/null +++ b/ush/create_model_configure_file.py @@ -0,0 +1,292 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse +import unittest +from datetime import datetime +from textwrap import dedent + +from python_utils import import_vars, set_env_var, print_input_args, str_to_type, \ + print_info_msg, print_err_msg_exit, lowercase, cfg_to_yaml_str, \ + load_shell_config + +from fill_jinja_template import fill_jinja_template + +def create_model_configure_file(cdate,run_dir,sub_hourly_post,dt_subhourly_post_mnts,dt_atmos): + """ Creates a model configuration file in the specified + run directory + + Args: + cdate: cycle date + run_dir: run directory + sub_hourly_post + dt_subhourly_post_mnts + dt_atmos + Returns: + Boolean + """ + + print_input_args(locals()) + + #import all environment variables + import_vars() + + # + #----------------------------------------------------------------------- + # + # Create a model configuration file in the specified run directory. + # + #----------------------------------------------------------------------- + # + print_info_msg(f''' + Creating a model configuration file (\"{MODEL_CONFIG_FN}\") in the specified + run directory (run_dir): + run_dir = \"{run_dir}\"''', verbose=VERBOSE) + # + # Extract from cdate the starting year, month, day, and hour of the forecast. + # + yyyy=cdate.year + mm=cdate.month + dd=cdate.day + hh=cdate.hour + # + # Set parameters in the model configure file. + # + dot_quilting_dot=f".{lowercase(str(QUILTING))}." + dot_print_esmf_dot=f".{lowercase(str(PRINT_ESMF))}." + dot_cpl_dot=f".{lowercase(str(CPL))}." + dot_write_dopost=f".{lowercase(str(WRITE_DOPOST))}." + # + #----------------------------------------------------------------------- + # + # Create a multiline variable that consists of a yaml-compliant string + # specifying the values that the jinja variables in the template + # model_configure file should be set to. + # + #----------------------------------------------------------------------- + # + settings = { + 'PE_MEMBER01': PE_MEMBER01, + 'print_esmf': dot_print_esmf_dot, + 'start_year': yyyy, + 'start_month': mm, + 'start_day': dd, + 'start_hour': hh, + 'nhours_fcst': FCST_LEN_HRS, + 'dt_atmos': DT_ATMOS, + 'cpl': dot_cpl_dot, + 'atmos_nthreads': OMP_NUM_THREADS_RUN_FCST, + 'restart_interval': RESTART_INTERVAL, + 'write_dopost': dot_write_dopost, + 'quilting': dot_quilting_dot, + 'output_grid': WRTCMP_output_grid + } + # + # If the write-component is to be used, then specify a set of computational + # parameters and a set of grid parameters. The latter depends on the type + # (coordinate system) of the grid that the write-component will be using. + # + if QUILTING: + settings.update({ + 'write_groups': WRTCMP_write_groups, + 'write_tasks_per_group': WRTCMP_write_tasks_per_group, + 'cen_lon': WRTCMP_cen_lon, + 'cen_lat': WRTCMP_cen_lat, + 'lon1': WRTCMP_lon_lwr_left, + 'lat1': WRTCMP_lat_lwr_left + }) + + if WRTCMP_output_grid == "lambert_conformal": + settings.update({ + 'stdlat1': WRTCMP_stdlat1, + 'stdlat2': WRTCMP_stdlat2, + 'nx': WRTCMP_nx, + 'ny': WRTCMP_ny, + 'dx': WRTCMP_dx, + 'dy': WRTCMP_dy, + 'lon2': "", + 'lat2': "", + 'dlon': "", + 'dlat': "", + }) + elif WRTCMP_output_grid == "regional_latlon" or \ + WRTCMP_output_grid == "rotated_latlon": + settings.update({ + 'lon2': WRTCMP_lon_upr_rght, + 'lat2': WRTCMP_lat_upr_rght, + 'dlon': WRTCMP_dlon, + 'dlat': WRTCMP_dlat, + 'stdlat1': "", + 'stdlat2': "", + 'nx': "", + 'ny': "", + 'dx': "", + 'dy': "" + }) + # + # If sub_hourly_post is set to "TRUE", then the forecast model must be + # directed to generate output files on a sub-hourly interval. Do this + # by specifying the output interval in the model configuration file + # (MODEL_CONFIG_FN) in units of number of forecat model time steps (nsout). + # nsout is calculated using the user-specified output time interval + # dt_subhourly_post_mnts (in units of minutes) and the forecast model's + # main time step dt_atmos (in units of seconds). Note that nsout is + # guaranteed to be an integer because the experiment generation scripts + # require that dt_subhourly_post_mnts (after conversion to seconds) be + # evenly divisible by dt_atmos. Also, in this case, the variable output_fh + # [which specifies the output interval in hours; + # see the jinja model_config template file] is set to 0, although this + # doesn't matter because any positive of nsout will override output_fh. + # + # If sub_hourly_post is set to "FALSE", then the workflow is hard-coded + # (in the jinja model_config template file) to direct the forecast model + # to output files every hour. This is done by setting (1) output_fh to 1 + # here, and (2) nsout to -1 here which turns off output by time step interval. + # + # Note that the approach used here of separating how hourly and subhourly + # output is handled should be changed/generalized/simplified such that + # the user should only need to specify the output time interval (there + # should be no need to specify a flag like sub_hourly_post); the workflow + # should then be able to direct the model to output files with that time + # interval and to direct the post-processor to process those files + # regardless of whether that output time interval is larger than, equal + # to, or smaller than one hour. + # + if sub_hourly_post: + nsout=(dt_subhourly_post_mnts*60) // dt_atmos + output_fh=0 + else: + output_fh=1 + nsout=-1 + + settings.update({ + 'output_fh': output_fh, + 'nsout': nsout + }) + + settings_str = cfg_to_yaml_str(settings) + + print_info_msg(dedent(f''' + The variable \"settings\" specifying values to be used in the \"{MODEL_CONFIG_FN}\" + file has been set as follows:\n + settings =\n\n''') + settings_str,verbose=VERBOSE) + # + #----------------------------------------------------------------------- + # + # Call a python script to generate the experiment's actual MODEL_CONFIG_FN + # file from the template file. + # + #----------------------------------------------------------------------- + # + model_config_fp=os.path.join(run_dir, MODEL_CONFIG_FN) + + try: + fill_jinja_template(["-q", "-u", settings_str, "-t", MODEL_CONFIG_TMPL_FP, "-o", model_config_fp]) + except: + print_err_msg_exit(dedent(f''' + Call to python script fill_jinja_template.py to create a \"{MODEL_CONFIG_FN}\" + file from a jinja2 template failed. Parameters passed to this script are: + Full path to template model config file: + MODEL_CONFIG_TMPL_FP = \"{MODEL_CONFIG_TMPL_FP}\" + Full path to output model config file: + model_config_fp = \"{model_config_fp}\" + Namelist settings specified on command line:\n + settings =\n\n''') + settings_str) + return False + + return True + +def parse_args(argv): + """ Parse command line arguments""" + parser = argparse.ArgumentParser( + description='Creates model configuration file.' + ) + + parser.add_argument('-r', '--run-dir', + dest='run_dir', + required=True, + help='Run directory.') + + parser.add_argument('-c', '--cdate', + dest='cdate', + required=True, + help='Date string in YYYYMMDD format.') + + parser.add_argument('-s', '--sub-hourly-post', + dest='sub_hourly_post', + required=True, + help='Set sub hourly post to either TRUE/FALSE by passing corresponding string.') + + parser.add_argument('-d', '--dt-subhourly-post-mnts', + dest='dt_subhourly_post_mnts', + required=True, + help='Subhourly post minitues.') + + parser.add_argument('-t', '--dt-atmos', + dest='dt_atmos', + required=True, + help='Forecast model\'s main time step.') + + parser.add_argument('-p', '--path-to-defns', + dest='path_to_defns', + required=True, + help='Path to var_defns file.') + + return parser.parse_args(argv) + +if __name__ == '__main__': + args = parse_args(sys.argv[1:]) + cfg = load_shell_config(args.path_to_defns) + import_vars(dictionary=cfg) + create_model_configure_file( \ + run_dir = args.run_dir, \ + cdate = str_to_type(args.cdate), \ + sub_hourly_post = str_to_type(args.sub_hourly_post), \ + dt_subhourly_post_mnts = str_to_type(args.dt_subhourly_post_mnts), \ + dt_atmos = str_to_type(args.dt_atmos) ) + +class Testing(unittest.TestCase): + def test_create_model_configure_file(self): + path = os.path.join(os.getenv('USHDIR'), "test_data") + self.assertTrue(\ + create_model_configure_file( \ + run_dir=path, + cdate=datetime(2021,1,1), + sub_hourly_post=True, + dt_subhourly_post_mnts=4, + dt_atmos=1) ) + def setUp(self): + USHDIR = os.path.dirname(os.path.abspath(__file__)) + MODEL_CONFIG_FN='model_configure' + MODEL_CONFIG_TMPL_FP = os.path.join(USHDIR, "templates", MODEL_CONFIG_FN) + + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + set_env_var('QUILTING',True) + set_env_var('PRINT_ESMF',True) + set_env_var('CPL',True) + set_env_var('WRITE_DOPOST',True) + set_env_var("USHDIR",USHDIR) + set_env_var('MODEL_CONFIG_FN',MODEL_CONFIG_FN) + set_env_var("MODEL_CONFIG_TMPL_FP",MODEL_CONFIG_TMPL_FP) + set_env_var('PE_MEMBER01',24) + set_env_var('FCST_LEN_HRS',72) + set_env_var('DT_ATMOS',1) + set_env_var('OMP_NUM_THREADS_RUN_FCST',1) + set_env_var('RESTART_INTERVAL',4) + + set_env_var('WRTCMP_write_groups',1) + set_env_var('WRTCMP_write_tasks_per_group',2) + set_env_var('WRTCMP_output_grid',"lambert_conformal") + set_env_var('WRTCMP_cen_lon',-97.5) + set_env_var('WRTCMP_cen_lat',35.0) + set_env_var('WRTCMP_stdlat1',35.0) + set_env_var('WRTCMP_stdlat2',35.0) + set_env_var('WRTCMP_nx',199) + set_env_var('WRTCMP_ny',111) + set_env_var('WRTCMP_lon_lwr_left',-121.23349066) + set_env_var('WRTCMP_lat_lwr_left',23.41731593) + set_env_var('WRTCMP_dx',3000.0) + set_env_var('WRTCMP_dy',3000.0) + diff --git a/ush/fill_jinja_template.py b/ush/fill_jinja_template.py new file mode 100755 index 0000000000..74c3489081 --- /dev/null +++ b/ush/fill_jinja_template.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python3 + +''' +This utility fills in a user-supplied Jinja template from either a YAML file, or +command line arguments. + +The user configuration file and commandline arguments should be YAML-formatted. +This script will support a single- or two-level YAML config file. For example: + + 1. expt1: + date_first_cycl: !datetime 2019043000 + date_last_cycl: !datetime 2019050100 + cycl_freq: !!str 12:00:00 + + expt2: + date_first_cycl: !datetime 2019061012 + date_last_cycl: !datetime 2019061212 + cycl_freq: !!str 12:00:00 + + 2. date_first_cycl: !datetime 2019043000 + date_last_cycl: !datetime 2019050100 + cycl_freq: !!str 12:00:00 + + In Case 1, provide the name of the file and the section title, e.g. expt2, + to the -c command line argument. Only provide the name of the file in -c + option if it's configured as in Case 2 above. + + +Supported YAML Tags: + + The script supports additional YAML configuration tags. + + !datetime Converts an input string formatted as YYYYMMDDHH[mm[ss]] to a + Python datetime object + !join Uses os.path.join to join a list as a path. + +Expected behavior: + + - The template file is required. Script fails if not provided. + - Command line arguments in the -u setting override the -c settings. + +''' + +import datetime as dt +import os +import sys + +import argparse +import jinja2 as j2 +from jinja2 import meta +import yaml + + +def join(loader, node): + + ''' Uses os to join a list as a path. ''' + + return os.path.join(*loader.construct_sequence(node)) + +def to_datetime(loader, node): + + ''' Converts a date string with format YYYYMMDDHH[MM[SS]] to a datetime + object. ''' + + value = loader.construct_scalar(node) + val_len = len(value) + + + # Check that the input string contains only numbers and is expected length. + if val_len not in [10, 12, 14] or not value.isnumeric(): + msg = f'{value} does not conform to input format YYYYMMDDHH[MM[SS]]' + raise ValueError(msg) + + # Use a subset of the string corresponding to the input length of the string + # 2 chosen here since Y is a 4 char year. + date_format = '%Y%m%d%H%M%S'[0:val_len-2] + + return dt.datetime.strptime(value, date_format) + +yaml.add_constructor('!datetime', to_datetime, Loader=yaml.SafeLoader) +yaml.add_constructor('!join', join, Loader=yaml.SafeLoader) + +def file_exists(arg): + + ''' Checks whether a file exists, and returns the path if it does. ''' + + if not os.path.exists(arg): + msg = f'{arg} does not exist!' + raise argparse.ArgumentTypeError(msg) + + return arg + +def config_exists(arg): + + ''' + Checks whether the config file exists and if it contains the input + section. Returns the config as a Python dict. + ''' + + if len(arg) > 2: + msg = f'{len(arg)} arguments were provided for config. Only 2 allowed!' + raise argparse.ArgumentTypeError(msg) + + file_name = file_exists(arg[0]) + section_name = arg[1] if len(arg) == 2 else None + + # Load the YAML file into a dictionary + with open(file_name, 'r') as fn: + cfg = yaml.load(fn, Loader=yaml.SafeLoader) + + if section_name: + try: + cfg = cfg[section_name] + except KeyError: + msg = f'Section {section_name} does not exist in top level of {file_name}' + raise argparse.ArgumentTypeError(msg) + + return cfg + + +def load_config(arg): + + ''' + Check to ensure that the provided config file exists. If it does, load it + with YAML's safe loader and return the resulting dict. + ''' + + # Check for existence of file + if not os.path.exists(arg): + msg = f'{arg} does not exist!' + raise argparse.ArgumentTypeError(msg) + + return yaml.safe_load(arg) + +def load_str(arg): + + ''' Load a dict string safely using YAML. Return the resulting dict. ''' + + return yaml.load(arg, Loader=yaml.SafeLoader) + +def path_ok(arg): + + ''' + Check whether the path to the file exists, and is writeable. Return the path + if it passes all checks, otherwise raise an error. + ''' + + # Get the absolute path provided by arg + dir_name = os.path.abspath(os.path.dirname(arg)) + + # Ensure the arg path exists, and is writable. Raise error if not. + if os.path.lexists(dir_name) and os.access(dir_name, os.W_OK): + return arg + + msg = f'{arg} is not a writable path!' + raise argparse.ArgumentTypeError(msg) + + +def parse_args(argv): + + ''' + Function maintains the arguments accepted by this script. Please see + Python's argparse documenation for more information about settings of each + argument. + ''' + + parser = argparse.ArgumentParser( + description='Fill in a Rocoto XML template.' + ) + + # Optional + parser.add_argument('-c', '--config', + help='Full path to a YAML user config file, and a \ + top-level section to use (optional).', + nargs='*', + type=load_config, + ) + parser.add_argument('-q', '--quiet', + action='store_true', + help='Suppress all output', + ) + parser.add_argument('-u', '--user_config', + help='Command-line user config options in YAML-formatted string', + type=load_str, + ) + # Required + parser.add_argument('-t', '--xml_template', + dest='template', + help='Full path to the jinja template', + required=True, + type=file_exists, + ) + parser.add_argument('-o', '--outxml', + dest='outxml', + help='Full path to the output Rocoto XML file.', + required=True, + type=path_ok, + ) + return parser.parse_args(argv) + +def update_dict(dest, newdict, quiet=False): + + ''' + Overwrites all values in dest dictionary section with key/value pairs from + newdict. Does not support multi-layer update. + + Turn off print statements with quiet=True. + + Input: + dest A dict that is to be updated. + newdict A dict containing sections and keys corresponding to + those in dest and potentially additional ones, that will be used to + update the dest dict. + quiet An optional boolean flag to turn off output. + Output: + None + Result: + The dest dict is updated in place. + ''' + + if not quiet: + print('*' * 50) + + for key, value in newdict.items(): + if not quiet: + print(f'Overriding {key:>20} = {value}') + + # Set key in dict + dest[key] = value + + if not quiet: + print('*' * 50) + + +def fill_jinja_template(argv): + + ''' + Loads a Jinja template, determines its necessary undefined variables, + retrives them from user supplied settings, and renders the final result. + ''' + + # parse args + cla = parse_args(argv) + if cla.config: + cla.config = config_exists(cla.config) + + # Create a Jinja Environment to load the template. + env = j2.Environment(loader=j2.FileSystemLoader(cla.template)) + template_source = env.loader.get_source(env, '') + template = env.get_template('') + parsed_content = env.parse(template_source) + + # Gather all of the undefined variables in the template. + template_vars = meta.find_undeclared_variables(parsed_content) + + # Read in the config options from the provided (optional) YAML file + cfg = cla.config if cla.config is not None else {} + + # Update cfg with (optional) command-line entries, overriding those in YAML file + if cla.user_config: + update_dict(cfg, cla.user_config, quiet=cla.quiet) + + # Loop through all the undefined Jinja template variables, and grab the + # required values from the config file. + tvars = {} + for var in template_vars: + + if cfg.get(var, "NULL") == "NULL": + raise KeyError(f'{var} does not exist in user-supplied settings!') + + if not cla.quiet: + print(f'{var:>25}: {cfg.get(var)}') + + tvars[var] = cfg.get(var) + + # Fill in XML template + xml_contents = template.render(**tvars) + with open(cla.outxml, 'w') as fn: + fn.write(xml_contents) + + +if __name__ == '__main__': + + fill_jinja_template(sys.argv[1:]) diff --git a/ush/generate_FV3LAM_wflow.py b/ush/generate_FV3LAM_wflow.py new file mode 100755 index 0000000000..65a3d16824 --- /dev/null +++ b/ush/generate_FV3LAM_wflow.py @@ -0,0 +1,1054 @@ +#!/usr/bin/env python3 + +import os +import sys +import platform +import subprocess +from multiprocessing import Process +from textwrap import dedent +from datetime import datetime,timedelta + +from python_utils import print_info_msg, print_err_msg_exit, import_vars, cp_vrfy, cd_vrfy,\ + rm_vrfy, ln_vrfy, mkdir_vrfy, mv_vrfy, run_command, date_to_str, \ + define_macos_utilities, create_symlink_to_file, check_for_preexist_dir_file, \ + cfg_to_yaml_str, find_pattern_in_str + +from setup import setup +from set_FV3nml_sfc_climo_filenames import set_FV3nml_sfc_climo_filenames +from get_crontab_contents import add_crontab_line +from fill_jinja_template import fill_jinja_template +from set_namelist import set_namelist + +def python_error_handler(): + """ Error handler for missing packages """ + + print_err_msg_exit(''' + Errors found: check your python environment + + Instructions for setting up python environments can be found on the web: + https://github.com/ufs-community/ufs-srweather-app/wiki/Getting-Started + ''', stack_trace=False) + +# Check for non-standard python packages +try: + import jinja2 + import yaml + import f90nml +except ImportError as error: + print_info_msg(error.__class__.__name__ + ": " + str(error)) + python_error_handler() + +def generate_FV3LAM_wflow(): + """ Function to setup a forecast experiment and create a workflow + (according to the parameters specified in the config file + + Args: + None + Returns: + None + """ + + print(dedent(''' + ======================================================================== + ======================================================================== + + Starting experiment generation... + + ======================================================================== + ========================================================================''')) + + #set ushdir + ushdir = os.path.dirname(os.path.abspath(__file__)) + + #check python version + major,minor,patch = platform.python_version_tuple() + if int(major) < 3 or int(minor) < 6: + print_info_msg(f''' + + Error: python version must be 3.6 or higher + python version: {major}.{minor}''') + + #define macros + define_macos_utilities() + + # + #----------------------------------------------------------------------- + # + # Source the file that defines and then calls the setup function. The + # setup function in turn first sources the default configuration file + # (which contains default values for the experiment/workflow parameters) + # and then sources the user-specified configuration file (which contains + # user-specified values for a subset of the experiment/workflow parame- + # ters that override their default values). + # + #----------------------------------------------------------------------- + # + setup() + + #import all environment variables + import_vars() + + # + #----------------------------------------------------------------------- + # + # Set the full path to the experiment's rocoto workflow xml file. This + # file will be placed at the top level of the experiment directory and + # then used by rocoto to run the workflow. + # + #----------------------------------------------------------------------- + # + WFLOW_XML_FP = os.path.join(EXPTDIR, WFLOW_XML_FN) + + # + #----------------------------------------------------------------------- + # + # Create a multiline variable that consists of a yaml-compliant string + # specifying the values that the jinja variables in the template rocoto + # XML should be set to. These values are set either in the user-specified + # workflow configuration file (EXPT_CONFIG_FN) or in the setup.sh script + # sourced above. Then call the python script that generates the XML. + # + #----------------------------------------------------------------------- + # + if WORKFLOW_MANAGER == "rocoto": + + template_xml_fp = os.path.join(TEMPLATE_DIR, WFLOW_XML_FN) + + print_info_msg(f''' + Creating rocoto workflow XML file (WFLOW_XML_FP) from jinja template XML + file (template_xml_fp): + template_xml_fp = \"{template_xml_fp}\" + WFLOW_XML_FP = \"{WFLOW_XML_FP}\"''') + + ensmem_indx_name = "" + uscore_ensmem_name = "" + slash_ensmem_subdir = "" + if DO_ENSEMBLE: + ensmem_indx_name = "mem" + uscore_ensmem_name = f"_mem#{ensmem_indx_name}#" + slash_ensmem_subdir = f"/mem#{ensmem_indx_name}#" + + #get time string + d = DATE_FIRST_CYCL + timedelta(seconds=DT_ATMOS) + time_str = d.strftime("%M:%S") + + cycl_hrs_str = [ f"{c:02d}" for c in CYCL_HRS ] + cdate_first_cycl = DATE_FIRST_CYCL + timedelta(hours=CYCL_HRS[0]) + + # Dictionary of settings + settings = { + # + # Parameters needed by the job scheduler. + # + 'account': ACCOUNT, + 'sched': SCHED, + 'partition_default': PARTITION_DEFAULT, + 'queue_default': QUEUE_DEFAULT, + 'partition_hpss': PARTITION_HPSS, + 'queue_hpss': QUEUE_HPSS, + 'partition_fcst': PARTITION_FCST, + 'queue_fcst': QUEUE_FCST, + 'machine': MACHINE, + 'slurm_native_cmd': SLURM_NATIVE_CMD, + # + # Workflow task names. + # + 'make_grid_tn': MAKE_GRID_TN, + 'make_orog_tn': MAKE_OROG_TN, + 'make_sfc_climo_tn': MAKE_SFC_CLIMO_TN, + 'get_extrn_ics_tn': GET_EXTRN_ICS_TN, + 'get_extrn_lbcs_tn': GET_EXTRN_LBCS_TN, + 'make_ics_tn': MAKE_ICS_TN, + 'make_lbcs_tn': MAKE_LBCS_TN, + 'run_fcst_tn': RUN_FCST_TN, + 'run_post_tn': RUN_POST_TN, + 'get_obs_ccpa_tn': GET_OBS_CCPA_TN, + 'get_obs_ndas_tn': GET_OBS_NDAS_TN, + 'get_obs_mrms_tn': GET_OBS_MRMS_TN, + 'vx_tn': VX_TN, + 'vx_gridstat_tn': VX_GRIDSTAT_TN, + 'vx_gridstat_refc_tn': VX_GRIDSTAT_REFC_TN, + 'vx_gridstat_retop_tn': VX_GRIDSTAT_RETOP_TN, + 'vx_gridstat_03h_tn': VX_GRIDSTAT_03h_TN, + 'vx_gridstat_06h_tn': VX_GRIDSTAT_06h_TN, + 'vx_gridstat_24h_tn': VX_GRIDSTAT_24h_TN, + 'vx_pointstat_tn': VX_POINTSTAT_TN, + 'vx_ensgrid_tn': VX_ENSGRID_TN, + 'vx_ensgrid_refc_tn': VX_ENSGRID_REFC_TN, + 'vx_ensgrid_retop_tn': VX_ENSGRID_RETOP_TN, + 'vx_ensgrid_03h_tn': VX_ENSGRID_03h_TN, + 'vx_ensgrid_06h_tn': VX_ENSGRID_06h_TN, + 'vx_ensgrid_24h_tn': VX_ENSGRID_24h_TN, + 'vx_ensgrid_mean_tn': VX_ENSGRID_MEAN_TN, + 'vx_ensgrid_prob_tn': VX_ENSGRID_PROB_TN, + 'vx_ensgrid_mean_03h_tn': VX_ENSGRID_MEAN_03h_TN, + 'vx_ensgrid_prob_03h_tn': VX_ENSGRID_PROB_03h_TN, + 'vx_ensgrid_mean_06h_tn': VX_ENSGRID_MEAN_06h_TN, + 'vx_ensgrid_prob_06h_tn': VX_ENSGRID_PROB_06h_TN, + 'vx_ensgrid_mean_24h_tn': VX_ENSGRID_MEAN_24h_TN, + 'vx_ensgrid_prob_24h_tn': VX_ENSGRID_PROB_24h_TN, + 'vx_ensgrid_prob_refc_tn': VX_ENSGRID_PROB_REFC_TN, + 'vx_ensgrid_prob_retop_tn': VX_ENSGRID_PROB_RETOP_TN, + 'vx_enspoint_tn': VX_ENSPOINT_TN, + 'vx_enspoint_mean_tn': VX_ENSPOINT_MEAN_TN, + 'vx_enspoint_prob_tn': VX_ENSPOINT_PROB_TN, + # + # Entity used to load the module file for each GET_OBS_* task. + # + 'get_obs': GET_OBS, + # + # Number of nodes to use for each task. + # + 'nnodes_make_grid': NNODES_MAKE_GRID, + 'nnodes_make_orog': NNODES_MAKE_OROG, + 'nnodes_make_sfc_climo': NNODES_MAKE_SFC_CLIMO, + 'nnodes_get_extrn_ics': NNODES_GET_EXTRN_ICS, + 'nnodes_get_extrn_lbcs': NNODES_GET_EXTRN_LBCS, + 'nnodes_make_ics': NNODES_MAKE_ICS, + 'nnodes_make_lbcs': NNODES_MAKE_LBCS, + 'nnodes_run_fcst': NNODES_RUN_FCST, + 'nnodes_run_post': NNODES_RUN_POST, + 'nnodes_get_obs_ccpa': NNODES_GET_OBS_CCPA, + 'nnodes_get_obs_mrms': NNODES_GET_OBS_MRMS, + 'nnodes_get_obs_ndas': NNODES_GET_OBS_NDAS, + 'nnodes_vx_gridstat': NNODES_VX_GRIDSTAT, + 'nnodes_vx_pointstat': NNODES_VX_POINTSTAT, + 'nnodes_vx_ensgrid': NNODES_VX_ENSGRID, + 'nnodes_vx_ensgrid_mean': NNODES_VX_ENSGRID_MEAN, + 'nnodes_vx_ensgrid_prob': NNODES_VX_ENSGRID_PROB, + 'nnodes_vx_enspoint': NNODES_VX_ENSPOINT, + 'nnodes_vx_enspoint_mean': NNODES_VX_ENSPOINT_MEAN, + 'nnodes_vx_enspoint_prob': NNODES_VX_ENSPOINT_PROB, + # + # Number of cores used for a task + # + 'ncores_run_fcst': PE_MEMBER01, + 'native_run_fcst': f"--cpus-per-task {OMP_NUM_THREADS_RUN_FCST} --exclusive", + # + # Number of logical processes per node for each task. If running without + # threading, this is equal to the number of MPI processes per node. + # + 'ppn_make_grid': PPN_MAKE_GRID, + 'ppn_make_orog': PPN_MAKE_OROG, + 'ppn_make_sfc_climo': PPN_MAKE_SFC_CLIMO, + 'ppn_get_extrn_ics': PPN_GET_EXTRN_ICS, + 'ppn_get_extrn_lbcs': PPN_GET_EXTRN_LBCS, + 'ppn_make_ics': PPN_MAKE_ICS, + 'ppn_make_lbcs': PPN_MAKE_LBCS, + 'ppn_run_fcst': PPN_RUN_FCST, + 'ppn_run_post': PPN_RUN_POST, + 'ppn_get_obs_ccpa': PPN_GET_OBS_CCPA, + 'ppn_get_obs_mrms': PPN_GET_OBS_MRMS, + 'ppn_get_obs_ndas': PPN_GET_OBS_NDAS, + 'ppn_vx_gridstat': PPN_VX_GRIDSTAT, + 'ppn_vx_pointstat': PPN_VX_POINTSTAT, + 'ppn_vx_ensgrid': PPN_VX_ENSGRID, + 'ppn_vx_ensgrid_mean': PPN_VX_ENSGRID_MEAN, + 'ppn_vx_ensgrid_prob': PPN_VX_ENSGRID_PROB, + 'ppn_vx_enspoint': PPN_VX_ENSPOINT, + 'ppn_vx_enspoint_mean': PPN_VX_ENSPOINT_MEAN, + 'ppn_vx_enspoint_prob': PPN_VX_ENSPOINT_PROB, + # + # Maximum wallclock time for each task. + # + 'wtime_make_grid': WTIME_MAKE_GRID, + 'wtime_make_orog': WTIME_MAKE_OROG, + 'wtime_make_sfc_climo': WTIME_MAKE_SFC_CLIMO, + 'wtime_get_extrn_ics': WTIME_GET_EXTRN_ICS, + 'wtime_get_extrn_lbcs': WTIME_GET_EXTRN_LBCS, + 'wtime_make_ics': WTIME_MAKE_ICS, + 'wtime_make_lbcs': WTIME_MAKE_LBCS, + 'wtime_run_fcst': WTIME_RUN_FCST, + 'wtime_run_post': WTIME_RUN_POST, + 'wtime_get_obs_ccpa': WTIME_GET_OBS_CCPA, + 'wtime_get_obs_mrms': WTIME_GET_OBS_MRMS, + 'wtime_get_obs_ndas': WTIME_GET_OBS_NDAS, + 'wtime_vx_gridstat': WTIME_VX_GRIDSTAT, + 'wtime_vx_pointstat': WTIME_VX_POINTSTAT, + 'wtime_vx_ensgrid': WTIME_VX_ENSGRID, + 'wtime_vx_ensgrid_mean': WTIME_VX_ENSGRID_MEAN, + 'wtime_vx_ensgrid_prob': WTIME_VX_ENSGRID_PROB, + 'wtime_vx_enspoint': WTIME_VX_ENSPOINT, + 'wtime_vx_enspoint_mean': WTIME_VX_ENSPOINT_MEAN, + 'wtime_vx_enspoint_prob': WTIME_VX_ENSPOINT_PROB, + # + # Maximum number of tries for each task. + # + 'maxtries_make_grid': MAXTRIES_MAKE_GRID, + 'maxtries_make_orog': MAXTRIES_MAKE_OROG, + 'maxtries_make_sfc_climo': MAXTRIES_MAKE_SFC_CLIMO, + 'maxtries_get_extrn_ics': MAXTRIES_GET_EXTRN_ICS, + 'maxtries_get_extrn_lbcs': MAXTRIES_GET_EXTRN_LBCS, + 'maxtries_make_ics': MAXTRIES_MAKE_ICS, + 'maxtries_make_lbcs': MAXTRIES_MAKE_LBCS, + 'maxtries_run_fcst': MAXTRIES_RUN_FCST, + 'maxtries_run_post': MAXTRIES_RUN_POST, + 'maxtries_get_obs_ccpa': MAXTRIES_GET_OBS_CCPA, + 'maxtries_get_obs_mrms': MAXTRIES_GET_OBS_MRMS, + 'maxtries_get_obs_ndas': MAXTRIES_GET_OBS_NDAS, + 'maxtries_vx_gridstat': MAXTRIES_VX_GRIDSTAT, + 'maxtries_vx_gridstat_refc': MAXTRIES_VX_GRIDSTAT_REFC, + 'maxtries_vx_gridstat_retop': MAXTRIES_VX_GRIDSTAT_RETOP, + 'maxtries_vx_gridstat_03h': MAXTRIES_VX_GRIDSTAT_03h, + 'maxtries_vx_gridstat_06h': MAXTRIES_VX_GRIDSTAT_06h, + 'maxtries_vx_gridstat_24h': MAXTRIES_VX_GRIDSTAT_24h, + 'maxtries_vx_pointstat': MAXTRIES_VX_POINTSTAT, + 'maxtries_vx_ensgrid': MAXTRIES_VX_ENSGRID, + 'maxtries_vx_ensgrid_refc': MAXTRIES_VX_ENSGRID_REFC, + 'maxtries_vx_ensgrid_retop': MAXTRIES_VX_ENSGRID_RETOP, + 'maxtries_vx_ensgrid_03h': MAXTRIES_VX_ENSGRID_03h, + 'maxtries_vx_ensgrid_06h': MAXTRIES_VX_ENSGRID_06h, + 'maxtries_vx_ensgrid_24h': MAXTRIES_VX_ENSGRID_24h, + 'maxtries_vx_ensgrid_mean': MAXTRIES_VX_ENSGRID_MEAN, + 'maxtries_vx_ensgrid_prob': MAXTRIES_VX_ENSGRID_PROB, + 'maxtries_vx_ensgrid_mean_03h': MAXTRIES_VX_ENSGRID_MEAN_03h, + 'maxtries_vx_ensgrid_prob_03h': MAXTRIES_VX_ENSGRID_PROB_03h, + 'maxtries_vx_ensgrid_mean_06h': MAXTRIES_VX_ENSGRID_MEAN_06h, + 'maxtries_vx_ensgrid_prob_06h': MAXTRIES_VX_ENSGRID_PROB_06h, + 'maxtries_vx_ensgrid_mean_24h': MAXTRIES_VX_ENSGRID_MEAN_24h, + 'maxtries_vx_ensgrid_prob_24h': MAXTRIES_VX_ENSGRID_PROB_24h, + 'maxtries_vx_ensgrid_prob_refc': MAXTRIES_VX_ENSGRID_PROB_REFC, + 'maxtries_vx_ensgrid_prob_retop': MAXTRIES_VX_ENSGRID_PROB_RETOP, + 'maxtries_vx_enspoint': MAXTRIES_VX_ENSPOINT, + 'maxtries_vx_enspoint_mean': MAXTRIES_VX_ENSPOINT_MEAN, + 'maxtries_vx_enspoint_prob': MAXTRIES_VX_ENSPOINT_PROB, + # + # Flags that specify whether to run the preprocessing or + # verification-related tasks. + # + 'run_task_make_grid': RUN_TASK_MAKE_GRID, + 'run_task_make_orog': RUN_TASK_MAKE_OROG, + 'run_task_make_sfc_climo': RUN_TASK_MAKE_SFC_CLIMO, + 'run_task_get_extrn_ics': RUN_TASK_GET_EXTRN_ICS, + 'run_task_get_extrn_lbcs': RUN_TASK_GET_EXTRN_LBCS, + 'run_task_make_ics': RUN_TASK_MAKE_ICS, + 'run_task_make_lbcs': RUN_TASK_MAKE_LBCS, + 'run_task_run_fcst': RUN_TASK_RUN_FCST, + 'run_task_run_post': RUN_TASK_RUN_POST, + 'run_task_get_obs_ccpa': RUN_TASK_GET_OBS_CCPA, + 'run_task_get_obs_mrms': RUN_TASK_GET_OBS_MRMS, + 'run_task_get_obs_ndas': RUN_TASK_GET_OBS_NDAS, + 'run_task_vx_gridstat': RUN_TASK_VX_GRIDSTAT, + 'run_task_vx_pointstat': RUN_TASK_VX_POINTSTAT, + 'run_task_vx_ensgrid': RUN_TASK_VX_ENSGRID, + 'run_task_vx_enspoint': RUN_TASK_VX_ENSPOINT, + # + # Number of physical cores per node for the current machine. + # + 'ncores_per_node': NCORES_PER_NODE, + # + # Directories and files. + # + 'jobsdir': JOBSDIR, + 'logdir': LOGDIR, + 'scriptsdir': SCRIPTSDIR, + 'cycle_basedir': CYCLE_BASEDIR, + 'global_var_defns_fp': GLOBAL_VAR_DEFNS_FP, + 'load_modules_run_task_fp': LOAD_MODULES_RUN_TASK_FP, + # + # External model information for generating ICs and LBCs. + # + 'extrn_mdl_name_ics': EXTRN_MDL_NAME_ICS, + 'extrn_mdl_name_lbcs': EXTRN_MDL_NAME_LBCS, + # + # Parameters that determine the set of cycles to run. + # + 'date_first_cycl': date_to_str(DATE_FIRST_CYCL,format="%Y%m%d"), + 'date_last_cycl': date_to_str(DATE_LAST_CYCL,format="%Y%m%d"), + 'cdate_first_cycl': cdate_first_cycl, + 'cycl_hrs': cycl_hrs_str, + 'cycl_freq': f"{INCR_CYCL_FREQ:02d}:00:00", + # + # Forecast length (same for all cycles). + # + 'fcst_len_hrs': FCST_LEN_HRS, + # + # Inline post + # + 'write_dopost': WRITE_DOPOST, + # + # METPlus-specific information + # + 'model': MODEL, + 'met_install_dir': MET_INSTALL_DIR, + 'met_bin_exec': MET_BIN_EXEC, + 'metplus_path': METPLUS_PATH, + 'vx_config_dir': VX_CONFIG_DIR, + 'metplus_conf': METPLUS_CONF, + 'met_config': MET_CONFIG, + 'ccpa_obs_dir': CCPA_OBS_DIR, + 'mrms_obs_dir': MRMS_OBS_DIR, + 'ndas_obs_dir': NDAS_OBS_DIR, + # + # Ensemble-related parameters. + # + 'do_ensemble': DO_ENSEMBLE, + 'num_ens_members': NUM_ENS_MEMBERS, + 'ndigits_ensmem_names': f"{NDIGITS_ENSMEM_NAMES}", + 'ensmem_indx_name': ensmem_indx_name, + 'uscore_ensmem_name': uscore_ensmem_name, + 'slash_ensmem_subdir': slash_ensmem_subdir, + # + # Parameters associated with subhourly post-processed output + # + 'sub_hourly_post': SUB_HOURLY_POST, + 'delta_min': DT_SUBHOURLY_POST_MNTS, + 'first_fv3_file_tstr': f"000:{time_str}" + } + # End of "settings" variable. + settings_str = cfg_to_yaml_str(settings) + + print_info_msg(dedent(f''' + The variable \"settings\" specifying values of the rococo XML variables + has been set as follows: + #----------------------------------------------------------------------- + settings =\n\n''') + settings_str, verbose=VERBOSE) + + # + # Call the python script to generate the experiment's actual XML file + # from the jinja template file. + # + try: + fill_jinja_template(["-q", "-u", settings_str, "-t", template_xml_fp, "-o", WFLOW_XML_FP]) + except: + print_err_msg_exit(dedent(f''' + Call to python script fill_jinja_template.py to create a rocoto workflow + XML file from a template file failed. Parameters passed to this script + are: + Full path to template rocoto XML file: + template_xml_fp = \"{template_xml_fp}\" + Full path to output rocoto XML file: + WFLOW_XML_FP = \"{WFLOW_XML_FP}\" + Namelist settings specified on command line:\n + settings =\n\n''') + settings_str) + # + #----------------------------------------------------------------------- + # + # Create a symlink in the experiment directory that points to the workflow + # (re)launch script. + # + #----------------------------------------------------------------------- + # + print_info_msg(f''' + Creating symlink in the experiment directory (EXPTDIR) that points to the + workflow launch script (WFLOW_LAUNCH_SCRIPT_FP): + EXPTDIR = \"{EXPTDIR}\" + WFLOW_LAUNCH_SCRIPT_FP = \"{WFLOW_LAUNCH_SCRIPT_FP}\"''',verbose=VERBOSE) + + create_symlink_to_file(WFLOW_LAUNCH_SCRIPT_FP, + os.path.join(EXPTDIR,WFLOW_LAUNCH_SCRIPT_FN), + False) + # + #----------------------------------------------------------------------- + # + # If USE_CRON_TO_RELAUNCH is set to TRUE, add a line to the user's cron + # table to call the (re)launch script every CRON_RELAUNCH_INTVL_MNTS mi- + # nutes. + # + #----------------------------------------------------------------------- + # + if USE_CRON_TO_RELAUNCH: + add_crontab_line() + # + #----------------------------------------------------------------------- + # + # Create the FIXam directory under the experiment directory. In NCO mode, + # this will be a symlink to the directory specified in FIXgsm, while in + # community mode, it will be an actual directory with files copied into + # it from FIXgsm. + # + #----------------------------------------------------------------------- + # + # First, consider NCO mode. + # + if RUN_ENVIR == "nco": + + ln_vrfy(f'''-fsn "{FIXgsm}" "{FIXam}"''') + # + # Resolve the target directory that the FIXam symlink points to and check + # that it exists. + # + try: + path_resolved = os.path.realpath(FIXam) + except: + path_resolved = FIXam + if not os.path.exists(path_resolved): + print_err_msg_exit(f''' + In order to be able to generate a forecast experiment in NCO mode (i.e. + when RUN_ENVIR set to \"nco\"), the path specified by FIXam after resolving + all symlinks (path_resolved) must be an existing directory (but in this + case isn't): + RUN_ENVIR = \"{RUN_ENVIR}\" + FIXam = \"{FIXam}\" + path_resolved = \"{path_resolved}\" + Please ensure that path_resolved is an existing directory and then rerun + the experiment generation script.''') + # + # Now consider community mode. + # + else: + + print_info_msg(f''' + Copying fixed files from system directory (FIXgsm) to a subdirectory + (FIXam) in the experiment directory: + FIXgsm = \"{FIXgsm}\" + FIXam = \"{FIXam}\"''',verbose=VERBOSE) + + check_for_preexist_dir_file(FIXam,"delete") + mkdir_vrfy("-p",FIXam) + mkdir_vrfy("-p",os.path.join(FIXam,"fix_co2_proj")) + + num_files=len(FIXgsm_FILES_TO_COPY_TO_FIXam) + for i in range(num_files): + fn=f"{FIXgsm_FILES_TO_COPY_TO_FIXam[i]}" + cp_vrfy(os.path.join(FIXgsm,fn), os.path.join(FIXam,fn)) + # + #----------------------------------------------------------------------- + # + # Copy MERRA2 aerosol climatology data. + # + #----------------------------------------------------------------------- + # + if USE_MERRA_CLIMO: + print_info_msg(f''' + Copying MERRA2 aerosol climatology data files from system directory + (FIXaer/FIXlut) to a subdirectory (FIXclim) in the experiment directory: + FIXaer = \"{FIXaer}\" + FIXlut = \"{FIXlut}\" + FIXclim = \"{FIXclim}\"''',verbose=VERBOSE) + + check_for_preexist_dir_file(FIXclim,"delete") + mkdir_vrfy("-p", FIXclim) + + cp_vrfy(os.path.join(FIXaer,"merra2.aerclim*.nc"), FIXclim) + cp_vrfy(os.path.join(FIXlut,"optics*.dat"), FIXclim) + # + #----------------------------------------------------------------------- + # + # Copy templates of various input files to the experiment directory. + # + #----------------------------------------------------------------------- + # + print_info_msg(f''' + Copying templates of various input files to the experiment directory...''', + verbose=VERBOSE) + + print_info_msg(f''' + Copying the template data table file to the experiment directory...''', + verbose=VERBOSE) + cp_vrfy(DATA_TABLE_TMPL_FP,DATA_TABLE_FP) + + print_info_msg(f''' + Copying the template field table file to the experiment directory...''', + verbose=VERBOSE) + cp_vrfy(FIELD_TABLE_TMPL_FP,FIELD_TABLE_FP) + + print_info_msg(f''' + Copying the template NEMS configuration file to the experiment directory...''', + verbose=VERBOSE) + cp_vrfy(NEMS_CONFIG_TMPL_FP,NEMS_CONFIG_FP) + # + # Copy the CCPP physics suite definition file from its location in the + # clone of the FV3 code repository to the experiment directory (EXPT- + # DIR). + # + print_info_msg(f''' + Copying the CCPP physics suite definition XML file from its location in + the forecast model directory sturcture to the experiment directory...''', + verbose=VERBOSE) + cp_vrfy(CCPP_PHYS_SUITE_IN_CCPP_FP,CCPP_PHYS_SUITE_FP) + # + # Copy the field dictionary file from its location in the + # clone of the FV3 code repository to the experiment directory (EXPT- + # DIR). + # + print_info_msg(f''' + Copying the field dictionary file from its location in the forecast + model directory sturcture to the experiment directory...''', + verbose=VERBOSE) + cp_vrfy(FIELD_DICT_IN_UWM_FP,FIELD_DICT_FP) + # + #----------------------------------------------------------------------- + # + # Set parameters in the FV3-LAM namelist file. + # + #----------------------------------------------------------------------- + # + print_info_msg(f''' + Setting parameters in weather model's namelist file (FV3_NML_FP): + FV3_NML_FP = \"{FV3_NML_FP}\"''') + # + # Set npx and npy, which are just NX plus 1 and NY plus 1, respectively. + # These need to be set in the FV3-LAM Fortran namelist file. They represent + # the number of cell vertices in the x and y directions on the regional + # grid. + # + npx=NX+1 + npy=NY+1 + # + # For the physics suites that use RUC LSM, set the parameter kice to 9, + # Otherwise, leave it unspecified (which means it gets set to the default + # value in the forecast model). + # + # NOTE: + # May want to remove kice from FV3.input.yml (and maybe input.nml.FV3). + # + kice=None + if SDF_USES_RUC_LSM: + kice=9 + # + # Set lsoil, which is the number of input soil levels provided in the + # chgres_cube output NetCDF file. This is the same as the parameter + # nsoill_out in the namelist file for chgres_cube. [On the other hand, + # the parameter lsoil_lsm (not set here but set in input.nml.FV3 and/or + # FV3.input.yml) is the number of soil levels that the LSM scheme in the + # forecast model will run with.] Here, we use the same approach to set + # lsoil as the one used to set nsoill_out in exregional_make_ics.sh. + # See that script for details. + # + # NOTE: + # May want to remove lsoil from FV3.input.yml (and maybe input.nml.FV3). + # Also, may want to set lsm here as well depending on SDF_USES_RUC_LSM. + # + lsoil=4 + if ( EXTRN_MDL_NAME_ICS == "HRRR" or \ + EXTRN_MDL_NAME_ICS == "RAP" ) and \ + ( SDF_USES_RUC_LSM ): + lsoil=9 + # + # Create a multiline variable that consists of a yaml-compliant string + # specifying the values that the namelist variables that are physics- + # suite-independent need to be set to. Below, this variable will be + # passed to a python script that will in turn set the values of these + # variables in the namelist file. + # + # IMPORTANT: + # If we want a namelist variable to be removed from the namelist file, + # in the "settings" variable below, we need to set its value to the + # string "null". This is equivalent to setting its value to + # !!python/none + # in the base namelist file specified by FV3_NML_BASE_SUITE_FP or the + # suite-specific yaml settings file specified by FV3_NML_YAML_CONFIG_FP. + # + # It turns out that setting the variable to an empty string also works + # to remove it from the namelist! Which is better to use?? + # + settings = {} + settings['atmos_model_nml'] = { + 'blocksize': BLOCKSIZE, + 'ccpp_suite': CCPP_PHYS_SUITE + } + settings['fv_core_nml'] = { + 'target_lon': LON_CTR, + 'target_lat': LAT_CTR, + 'nrows_blend': HALO_BLEND, + # + # Question: + # For a ESGgrid type grid, what should stretch_fac be set to? This depends + # on how the FV3 code uses the stretch_fac parameter in the namelist file. + # Recall that for a ESGgrid, it gets set in the function set_gridparams_ESGgrid(.sh) + # to something like 0.9999, but is it ok to set it to that here in the + # FV3 namelist file? + # + 'stretch_fac': STRETCH_FAC, + 'npx': npx, + 'npy': npy, + 'layout': [LAYOUT_X, LAYOUT_Y], + 'bc_update_interval': LBC_SPEC_INTVL_HRS + } + settings['gfs_physics_nml'] = { + 'kice': kice or None, + 'lsoil': lsoil or None, + 'do_shum': DO_SHUM, + 'do_sppt': DO_SPPT, + 'do_skeb': DO_SKEB, + 'do_spp': DO_SPP, + 'n_var_spp': N_VAR_SPP, + 'n_var_lndp': N_VAR_LNDP, + 'lndp_type': LNDP_TYPE, + 'fhcyc': FHCYC_LSM_SPP_OR_NOT + } + # + # Add to "settings" the values of those namelist variables that specify + # the paths to fixed files in the FIXam directory. As above, these namelist + # variables are physcs-suite-independent. + # + # Note that the array FV3_NML_VARNAME_TO_FIXam_FILES_MAPPING contains + # the mapping between the namelist variables and the names of the files + # in the FIXam directory. Here, we loop through this array and process + # each element to construct each line of "settings". + # + dummy_run_dir=os.path.join(EXPTDIR,"any_cyc") + if DO_ENSEMBLE: + dummy_run_dir=os.path.join(dummy_run_dir,"any_ensmem") + + regex_search="^[ ]*([^| ]+)[ ]*[|][ ]*([^| ]+)[ ]*$" + num_nml_vars=len(FV3_NML_VARNAME_TO_FIXam_FILES_MAPPING) + namsfc_dict = {} + for i in range(num_nml_vars): + + mapping=f"{FV3_NML_VARNAME_TO_FIXam_FILES_MAPPING[i]}" + tup = find_pattern_in_str(regex_search, mapping) + nml_var_name = tup[0] + FIXam_fn = tup[1] + + fp="\"\"" + if FIXam_fn: + fp=os.path.join(FIXam,FIXam_fn) + # + # If not in NCO mode, for portability and brevity, change fp so that it + # is a relative path (relative to any cycle directory immediately under + # the experiment directory). + # + if RUN_ENVIR != "nco": + fp = os.path.relpath(os.path.realpath(fp), start=dummy_run_dir) + # + # Add a line to the variable "settings" that specifies (in a yaml-compliant + # format) the name of the current namelist variable and the value it should + # be set to. + # + namsfc_dict[nml_var_name] = fp + # + # Add namsfc_dict to settings + # + settings['namsfc'] = namsfc_dict + # + # Use netCDF4 when running the North American 3-km domain due to file size. + # + if PREDEF_GRID_NAME == "RRFS_NA_3km": + settings['fms2_io_nml'] = { + 'netcdf_default_format': 'netcdf4' + } + # + # Add the relevant tendency-based stochastic physics namelist variables to + # "settings" when running with SPPT, SHUM, or SKEB turned on. If running + # with SPP or LSM SPP, set the "new_lscale" variable. Otherwise only + # include an empty "nam_stochy" stanza. + # + nam_stochy_dict = {} + if DO_SPPT: + nam_stochy_dict.update({ + 'iseed_sppt': ISEED_SPPT, + 'new_lscale': NEW_LSCALE, + 'sppt': SPPT_MAG, + 'sppt_logit': SPPT_LOGIT, + 'sppt_lscale': SPPT_LSCALE, + 'sppt_sfclimit': SPPT_SFCLIMIT, + 'sppt_tau': SPPT_TSCALE, + 'spptint': SPPT_INT, + 'use_zmtnblck': USE_ZMTNBLCK + }) + + if DO_SHUM: + nam_stochy_dict.update({ + 'iseed_shum': ISEED_SHUM, + 'new_lscale': NEW_LSCALE, + 'shum': SHUM_MAG, + 'shum_lscale': SHUM_LSCALE, + 'shum_tau': SHUM_TSCALE, + 'shumint': SHUM_INT + }) + + if DO_SKEB: + nam_stochy_dict.update({ + 'iseed_skeb': ISEED_SKEB, + 'new_lscale': NEW_LSCALE, + 'skeb': SKEB_MAG, + 'skeb_lscale': SKEB_LSCALE, + 'skebnorm': SKEBNORM, + 'skeb_tau': SKEB_TSCALE, + 'skebint': SKEB_INT, + 'skeb_vdof': SKEB_VDOF + }) + + if DO_SPP or DO_LSM_SPP: + nam_stochy_dict.update({ + 'new_lscale': NEW_LSCALE + }) + + settings['nam_stochy'] = nam_stochy_dict + # + # Add the relevant SPP namelist variables to "settings" when running with + # SPP turned on. Otherwise only include an empty "nam_sppperts" stanza. + # + nam_sppperts_dict = {} + if DO_SPP: + nam_sppperts_dict = { + 'iseed_spp': ISEED_SPP, + 'spp_lscale': SPP_LSCALE, + 'spp_prt_list': SPP_MAG_LIST, + 'spp_sigtop1': SPP_SIGTOP1, + 'spp_sigtop2': SPP_SIGTOP2, + 'spp_stddev_cutoff': SPP_STDDEV_CUTOFF, + 'spp_tau': SPP_TSCALE, + 'spp_var_list': SPP_VAR_LIST + } + + settings['nam_sppperts'] = nam_sppperts_dict + # + # Add the relevant LSM SPP namelist variables to "settings" when running with + # LSM SPP turned on. + # + nam_sfcperts_dict = {} + if DO_LSM_SPP: + nam_sfcperts_dict = { + 'lndp_type': LNDP_TYPE, + 'lndp_model_type': LNDP_MODEL_TYPE, + 'lndp_tau': LSM_SPP_TSCALE, + 'lndp_lscale': LSM_SPP_LSCALE, + 'iseed_lndp': ISEED_LSM_SPP, + 'lndp_var_list': LSM_SPP_VAR_LIST, + 'lndp_prt_list': LSM_SPP_MAG_LIST + } + + settings['nam_sfcperts'] = nam_sfcperts_dict + + settings_str = cfg_to_yaml_str(settings) + + print_info_msg(dedent(f''' + The variable \"settings\" specifying values of the weather model's + namelist variables has been set as follows: + + settings =\n\n''') + settings_str, verbose=VERBOSE) + # + #----------------------------------------------------------------------- + # + # Call the set_namelist.py script to create a new FV3 namelist file (full + # path specified by FV3_NML_FP) using the file FV3_NML_BASE_SUITE_FP as + # the base (i.e. starting) namelist file, with physics-suite-dependent + # modifications to the base file specified in the yaml configuration file + # FV3_NML_YAML_CONFIG_FP (for the physics suite specified by CCPP_PHYS_SUITE), + # and with additional physics-suite-independent modificaitons specified + # in the variable "settings" set above. + # + #----------------------------------------------------------------------- + # + try: + set_namelist(["-q", "-n", FV3_NML_BASE_SUITE_FP, "-c", FV3_NML_YAML_CONFIG_FP, + CCPP_PHYS_SUITE, "-u", settings_str, "-o", FV3_NML_FP]) + except: + print_err_msg_exit(dedent(f''' + Call to python script set_namelist.py to generate an FV3 namelist file + failed. Parameters passed to this script are: + Full path to base namelist file: + FV3_NML_BASE_SUITE_FP = \"{FV3_NML_BASE_SUITE_FP}\" + Full path to yaml configuration file for various physics suites: + FV3_NML_YAML_CONFIG_FP = \"{FV3_NML_YAML_CONFIG_FP}\" + Physics suite to extract from yaml configuration file: + CCPP_PHYS_SUITE = \"{CCPP_PHYS_SUITE}\" + Full path to output namelist file: + FV3_NML_FP = \"{FV3_NML_FP}\" + Namelist settings specified on command line:\n + settings =\n\n''') + settings_str) + # + # If not running the MAKE_GRID_TN task (which implies the workflow will + # use pregenerated grid files), set the namelist variables specifying + # the paths to surface climatology files. These files are located in + # (or have symlinks that point to them) in the FIXLAM directory. + # + # Note that if running the MAKE_GRID_TN task, this action usually cannot + # be performed here but must be performed in that task because the names + # of the surface climatology files depend on the CRES parameter (which is + # the C-resolution of the grid), and this parameter is in most workflow + # configurations is not known until the grid is created. + # + if not RUN_TASK_MAKE_GRID: + + set_FV3nml_sfc_climo_filenames() + # + #----------------------------------------------------------------------- + # + # To have a record of how this experiment/workflow was generated, copy + # the experiment/workflow configuration file to the experiment directo- + # ry. + # + #----------------------------------------------------------------------- + # + cp_vrfy(os.path.join(USHDIR,EXPT_CONFIG_FN), EXPTDIR) + # + #----------------------------------------------------------------------- + # + # For convenience, print out the commands that need to be issued on the + # command line in order to launch the workflow and to check its status. + # Also, print out the line that should be placed in the user's cron table + # in order for the workflow to be continually resubmitted. + # + #----------------------------------------------------------------------- + # + if WORKFLOW_MANAGER == "rocoto": + wflow_db_fn=f"{os.path.splitext(WFLOW_XML_FN)[0]}.db" + rocotorun_cmd=f"rocotorun -w {WFLOW_XML_FN} -d {wflow_db_fn} -v 10" + rocotostat_cmd=f"rocotostat -w {WFLOW_XML_FN} -d {wflow_db_fn} -v 10" + + print_info_msg(f''' + ======================================================================== + ======================================================================== + + Experiment generation completed. The experiment directory is: + + EXPTDIR=\"{EXPTDIR}\" + + ======================================================================== + ======================================================================== + ''') + # + #----------------------------------------------------------------------- + # + # If rocoto is required, print instructions on how to load and use it + # + #----------------------------------------------------------------------- + # + if WORKFLOW_MANAGER == "rocoto": + + print_info_msg(f''' + To launch the workflow, first ensure that you have a compatible version + of rocoto available. For most pre-configured platforms, rocoto can be + loaded via a module: + + > module load rocoto + + For more details on rocoto, see the User's Guide. + + To launch the workflow, first ensure that you have a compatible version + of rocoto loaded. For example, to load version 1.3.1 of rocoto, use + + > module load rocoto/1.3.1 + + (This version has been tested on hera; later versions may also work but + have not been tested.) + + To launch the workflow, change location to the experiment directory + (EXPTDIR) and issue the rocotrun command, as follows: + + > cd {EXPTDIR} + > {rocotorun_cmd} + + To check on the status of the workflow, issue the rocotostat command + (also from the experiment directory): + + > {rocotostat_cmd} + + Note that: + + 1) The rocotorun command must be issued after the completion of each + task in the workflow in order for the workflow to submit the next + task(s) to the queue. + + 2) In order for the output of the rocotostat command to be up-to-date, + the rocotorun command must be issued immediately before issuing the + rocotostat command. + + For automatic resubmission of the workflow (say every 3 minutes), the + following line can be added to the user's crontab (use \"crontab -e\" to + edit the cron table): + + */3 * * * * cd {EXPTDIR} && ./launch_FV3LAM_wflow.sh called_from_cron=\"TRUE\" + ''') + # + # If necessary, run the NOMADS script to source external model data. + # + if NOMADS: + print("Getting NOMADS online data") + print(f"NOMADS_file_type= {NOMADS_file_type}") + cd_vrfy(EXPTDIR) + NOMADS_script = os.path.join(USHDIR, "NOMADS_get_extrn_mdl_files.h") + run_command(f'''{NOMADS_script} {date_to_str(DATE_FIRST_CYCL,format="%Y%m%d")} \ + {CYCL_HRS} {NOMADS_file_type} {FCST_LEN_HRS} {LBC_SPEC_INTVL_HRS}''') + + +# +#----------------------------------------------------------------------- +# +# Start of the script that will call the experiment/workflow generation +# function defined above. +# +#----------------------------------------------------------------------- +# +if __name__ == "__main__": + # + #----------------------------------------------------------------------- + # + # Set directories. + # + #----------------------------------------------------------------------- + # + ushdir=os.path.dirname(os.path.abspath(__file__)) + # + # Set the name of and full path to the temporary file in which we will + # save some experiment/workflow variables. The need for this temporary + # file is explained below. + # + tmp_fn="tmp" + tmp_fp=os.path.join(ushdir, tmp_fn) + rm_vrfy("-f",tmp_fp) + # + # Set the name of and full path to the log file in which the output from + # the experiment/workflow generation function will be saved. + # + log_fn="log.generate_FV3LAM_wflow" + log_fp=os.path.join(ushdir, log_fn) + rm_vrfy("-f",log_fp) + # + # Call the generate_FV3LAM_wflow function defined above to generate the + # experiment/workflow. Note that we pipe the output of the function + # (and possibly other commands) to the "tee" command in order to be able + # to both save it to a file and print it out to the screen (stdout). + # The piping causes the call to the function (and the other commands + # grouped with it using the curly braces, { ... }) to be executed in a + # subshell. As a result, the experiment/workflow variables that the + # function sets are not available outside of the grouping, i.e. they are + # not available at and after the call to "tee". Since some of these va- + # riables are needed after the call to "tee" below, we save them in a + # temporary file and read them in outside the subshell later below. + # + def workflow_func(): + retval=1 + generate_FV3LAM_wflow() + retval=0 + run_command(f'''echo "{EXPTDIR}" >> "{tmp_fp}"''') + run_command(f'''echo "{retval}" >> "{tmp_fp}"''') + + # create tee functionality + tee = subprocess.Popen(["tee", log_fp], stdin=subprocess.PIPE) + os.dup2(tee.stdin.fileno(), sys.stdout.fileno()) + os.dup2(tee.stdin.fileno(), sys.stderr.fileno()) + + #create workflow process + p = Process(target=workflow_func) + p.start() + p.join() + + # + # Read in experiment/workflow variables needed later below from the tem- + # porary file created in the subshell above containing the call to the + # generate_FV3LAM_wflow function. These variables are not directly + # available here because the call to generate_FV3LAM_wflow above takes + # place in a subshell (due to the fact that we are then piping its out- + # put to the "tee" command). Then remove the temporary file. + # + (_,exptdir,_)=run_command(f'''sed "1q;d" "{tmp_fp}"''') + (_,retval,_)=run_command(f''' sed "2q;d" "{tmp_fp}"''') + if retval: + retval = int(retval) + else: + retval = 1 + rm_vrfy(tmp_fp) + # + # If the call to the generate_FV3LAM_wflow function above was success- + # ful, move the log file in which the "tee" command saved the output of + # the function to the experiment directory. + # + if retval == 0: + mv_vrfy(log_fp,exptdir) + # + # If the call to the generate_FV3LAM_wflow function above was not suc- + # cessful, print out an error message and exit with a nonzero return + # code. + # + else: + print_err_msg_exit(f''' + Experiment generation failed. Check the log file from the ex- + periment/workflow generation script in the file specified by log_fp: + log_fp = \"{log_fp}\" + Stopping.''') + diff --git a/ush/get_crontab_contents.py b/ush/get_crontab_contents.py new file mode 100644 index 0000000000..69bdad9faa --- /dev/null +++ b/ush/get_crontab_contents.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 + +import os +import sys +import unittest +import argparse +from datetime import datetime + +from python_utils import import_vars, set_env_var, print_input_args, \ + run_command, define_macos_utilities, print_info_msg + +def get_crontab_contents(called_from_cron): + """ + #----------------------------------------------------------------------- + # + # This function returns the contents of the user's + # cron table as well as the command to use to manipulate the cron table + # (i.e. the "crontab" command, but on some platforms the version or + # location of this may change depending on other circumstances, e.g. on + # Cheyenne, this depends on whether a script that wants to call "crontab" + # is itself being called from a cron job). Arguments are as follows: + # + # called_from_cron: + # Boolean flag that specifies whether this function (and the scripts or + # functions that are calling it) are called as part of a cron job. Must + # be set to "TRUE" or "FALSE". + # + # outvarname_crontab_cmd: + # Name of the output variable that will contain the command to issue for + # the system "crontab" command. + # + # outvarname_crontab_contents: + # Name of the output variable that will contain the contents of the + # user's cron table. + # + #----------------------------------------------------------------------- + """ + + print_input_args(locals()) + + #import selected env vars + IMPORTS = ["MACHINE", "USER"] + import_vars(env_vars=IMPORTS) + + __crontab_cmd__="crontab" + # + # On Cheyenne, simply typing "crontab" will launch the crontab command + # at "/glade/u/apps/ch/opt/usr/bin/crontab". This is a containerized + # version of crontab that will work if called from scripts that are + # themselves being called as cron jobs. In that case, we must instead + # call the system version of crontab at /usr/bin/crontab. + # + if MACHINE == "CHEYENNE": + if called_from_cron: + __crontab_cmd__="/usr/bin/crontab" + (_,__crontab_contents__,_)=run_command(f'''{__crontab_cmd__} -l''') + + # replace single quotes (hopefully in comments) with double quotes + __crontab_contents__ = __crontab_contents__.replace("'", '"') + + return __crontab_cmd__, __crontab_contents__ + +def add_crontab_line(): + """ Add crontab line to cron table """ + + #import selected env vars + IMPORTS = ["MACHINE", "USER", "CRONTAB_LINE", "VERBOSE", "EXPTDIR"] + import_vars(env_vars=IMPORTS) + + # + # Make a backup copy of the user's crontab file and save it in a file. + # + time_stamp = datetime.now().strftime("%F_%T") + crontab_backup_fp=os.path.join(EXPTDIR,f"crontab.bak.{time_stamp}") + print_info_msg(f''' + Copying contents of user cron table to backup file: + crontab_backup_fp = \"{crontab_backup_fp}\"''',verbose=VERBOSE) + + global called_from_cron + try: called_from_cron + except: called_from_cron = False + + # Get crontab contents + crontab_cmd,crontab_contents = get_crontab_contents(called_from_cron=called_from_cron) + + # Create backup + run_command(f'''printf "%s" '{crontab_contents}' > "{crontab_backup_fp}"''') + + # Add crontab line + if CRONTAB_LINE in crontab_contents: + + print_info_msg(f''' + The following line already exists in the cron table and thus will not be + added: + CRONTAB_LINE = \"{CRONTAB_LINE}\"''') + + else: + + print_info_msg(f''' + Adding the following line to the user's cron table in order to automatically + resubmit SRW workflow: + CRONTAB_LINE = \"{CRONTAB_LINE}\"''',verbose=VERBOSE) + + #add new line to crontab contents if it doesn't have one + NEWLINE_CHAR="" + if crontab_contents and crontab_contents[-1] != "\n": + NEWLINE_CHAR="\n" + + #add the crontab line + run_command(f'''printf "%s%b%s\n" '{crontab_contents}' '{NEWLINE_CHAR}' '{CRONTAB_LINE}' | {crontab_cmd}''') + +def delete_crontab_line(called_from_cron): + """ Delete crontab line after job is complete i.e. either SUCCESS/FAILURE + but not IN PROGRESS status""" + + print_input_args(locals()) + + #import selected env vars + IMPORTS = ["MACHINE", "USER", "CRONTAB_LINE"] + import_vars(env_vars=IMPORTS) + + # + # Get the full contents of the user's cron table. + # + (crontab_cmd,crontab_contents) = get_crontab_contents(called_from_cron) + # + # Remove the line in the contents of the cron table corresponding to the + # current forecast experiment (if that line is part of the contents). + # Then record the results back into the user's cron table. + # + if (CRONTAB_LINE + '\n') in crontab_contents: + crontab_contents = crontab_contents.replace(CRONTAB_LINE+'\n','') + else: + crontab_contents = crontab_contents.replace(CRONTAB_LINE,'') + + run_command(f'''echo '{crontab_contents}' | {crontab_cmd}''') + +def parse_args(argv): + """ Parse command line arguments for deleting crontab line. + This is needed because it is called from shell script + """ + parser = argparse.ArgumentParser( + description='Crontab job manupilation program.' + ) + + parser.add_argument('-d', '--delete', + dest='delete', + action='store_true', + help='Delete crontab line.') + + parser.add_argument('-c', '--called-from-cron', + dest='called_from_cron', + action='store_true', + help='Called from cron.') + + return parser.parse_args(argv) + +if __name__ == '__main__': + args = parse_args(sys.argv[1:]) + if args.delete: + delete_crontab_line(args.called_from_cron) + +class Testing(unittest.TestCase): + def test_get_crontab_contents(self): + crontab_cmd,crontab_contents = get_crontab_contents(called_from_cron=True) + self.assertEqual(crontab_cmd, "crontab") + def setUp(self): + define_macos_utilities(); + set_env_var('DEBUG',False) + set_env_var('MACHINE', 'HERA') diff --git a/ush/get_layout.sh b/ush/get_layout.sh new file mode 100755 index 0000000000..878f1b30d9 --- /dev/null +++ b/ush/get_layout.sh @@ -0,0 +1,147 @@ +#!/bin/bash -f +########################################################### +# get layout for given nx and ny +# INPUT: nx, ny, number of cpu to be used (optional). +# Output: suggested nx, ny, layout_x, layout_y +# email to: Linlin.Pan@noaa.gov for any questions. +# +########################################################### +if [ "$#" -lt 2 ]; then + echo "You must enter number of grid points in x and y directions" + exit +else + nx=$1 + ny=$2 + echo "nx= $nx, ny= $ny" +fi + +if [ "$#" -eq 3 ]; then + nlayout=$3 + echo "ncups= $nlayout" + layout_x=$(echo "sqrt($nlayout*$nx/$ny)" |bc ) + if [ $layout_x -gt $nx ]; then + $layout_x=$nx + fi +# using even number + if [ $((layout_x%2)) -gt 0 ] ; then + if [ $nx -gt $ny ] ; then + layout_x=$((layout_x+1)) + else + layout_x=$((layout_x-1)) + fi + fi + if [ $layout_x -eq 0 ] ; then + layout_x=2 + fi + if [ $layout_x -gt 24 ]; then + layout_x=24 + fi +# get layout_y + layout_y=$((nlayout/layout_x)) + if [ $((layout_y%2)) -gt 0 ] ; then + layout_y=$((layout_y+1)) + fi + if [ $layout_y -gt 24 ] && [ $layout_x -ne 24 ] ; then + layout_y=24 + layout_x=$((nlayout/layout_y)) + if [ $((layout_x%2)) -gt 0 ] ; then + layout_x=$((layout_x+1)) + fi + fi + if [ $nx -gt $ny ] && [ $layout_x -lt $layout_y ] ; then + temp=$layout_x + layout_x=$layout_y + layout_y=$temp + fi +# get nx, ny + if [ $((nx%layout_x)) -gt 0 ] ; then + nx=$((nx/layout_x*layout_x+layout_x)) + else + nx=$((nx/layout_x*layout_x)) + fi + if [ $((ny%layout_y)) -gt 0 ] ; then + ny=$((ny/layout_y*layout_y+layout_y)) + else + ny=$((ny/layout_y*layout_y)) + fi + echo "suggested layout_x= $layout_x, layout_y $layout_y, and total = $((layout_x*layout_y))" + echo "suggested nx= $nx, ny= $ny" + exit +fi + +nxy=$((nx * ny)) + +if [ $nxy -le 22000 ]; then # 22000 is from predefined HRRR 25km domain + layout_x=2 + layout_y=2 + nx=$((nx+nx%2)) + ny=$((ny+ny%2)) + +elif [ $nxy -gt 22000 ] && [ $nxy -le 81900 ]; then #81900 is obtained from predefined HRRR 13km domain + nlayout=$(((4+96*nxy/81900))) + layout_x=$(echo "sqrt($nlayout)" |bc ) + if [ $layout_x -gt $nx ]; then + $layout_x=$nx + fi + if [ $((layout_x%2)) -gt 0 ] ; then + if [ $nx -gt $ny ] ; then + layout_x=$((layout_x+1)) + else + layout_x=$((layout_x-1)) + fi + fi + layout_y=$((nlayout/layout_x)) + if [ $((layout_y%2)) -gt 0 ] ; then + layout_y=$((layout_y+1)) + fi + if [ $((nx%layout_x)) -gt 0 ] ; then + nx=$((nx/layout_x*layout_x+layout_x)) + else + nx=$((nx/layout_x*layout_x)) + fi + if [ $((ny%layout_y)) -gt 0 ] ; then + ny=$((ny/layout_y*layout_y+layout_y)) + else + ny=$((ny/layout_y*layout_y)) + fi + +elif [ $nxy -gt 81900 ]; then + nlayout=$(((100+716*nxy/1747872))) # 1747872 is obtained from predefined HRRR 3km domain. + layout_x=$(echo "sqrt($nlayout)" |bc ) + if [ $layout_x -gt $nx ]; then + $layout_x=$nx + fi + if [ $layout_x -gt 24 ] ; then + layout_x=24 + layout_y=$((nlayout/layout_x)) + layout_y=$((layout_y+layout_y%2)) + if [ $nx -gt $ny ] && [ $layout_x -lt $layout_y ]; then + layout_x=$layout_y + layout_y=24 + fi + else + layout_y=$((nlayout/layout_x)) + layout_y=$((layout_y+layout_y%2)) + if [ $nx -gt $ny ] && [ $layout_x -lt $layout_y ]; then + temp=$layout_x + layout_x=$layout_y + layout_y=$temp + fi + fi + if [ $((nx%layout_x)) -gt 0 ] ; then + nx=$((nx/layout_x*layout_x+layout_x)) + else + nx=$((nx/layout_x*layout_x)) + fi + if [ $((ny%layout_y)) -gt 0 ] ; then + ny=$((ny/layout_y*layout_y+layout_y)) + else + ny=$((ny/layout_y*layout_y)) + fi +else + echo "Error: nxy= $nxy " + exit +fi + +echo "suggested layout_x= $layout_x, layout_y=$layout_y, total= $((layout_x*layout_y))" +echo "suggested nx= $nx, ny= $ny" diff --git a/ush/init_env.sh b/ush/init_env.sh new file mode 100644 index 0000000000..d883766325 --- /dev/null +++ b/ush/init_env.sh @@ -0,0 +1,51 @@ +# +#----------------------------------------------------------------------- +# +# This file defines a function that sources scripts (usually system +# scripts) to initialize various commands in the environment, e.g. the +# "module" command. The full paths to these scripts are specified in +# the machine files in the array ENV_INIT_SCRIPTS_FPS. +# +# env_init_scripts_fps: +# Full paths to the system scripts to source. +# +#----------------------------------------------------------------------- +# +function init_env() { + + { save_shell_opts; set -u +x; } > /dev/null 2>&1 + + local valid_args=( \ + "env_init_scripts_fps" \ + ) + process_args valid_args "$@" + print_input_args "valid_args" + + local num_scripts \ + n \ + fp + + num_scripts="${#env_init_scripts_fps[@]}" + for (( n=0; n<${num_scripts}; n++ )); do + fp="${env_init_scripts_fps[$n]}" + print_info_msg "$DEBUG" "\ +Attempting to source script: + fp = \"$fp\"" + if [ -f "$fp" ]; then + # The scripts being sourced here may have undefined variables, but since + # they are system scripts outside of the SRW App, they cannot be changed. + # Thus, we allow for undefined variables by temporarily using "set +u". + set +u + source "$fp" && print_info_msg "$DEBUG" "Succeeded." + set -u + else + print_err_msg_exit "\ +The script to source does not exist or is not a regular file: + fp = \"$fp\"" + fi + + done + + { restore_shell_opts; } > /dev/null 2>&1 + +} diff --git a/ush/launch_FV3LAM_wflow.sh b/ush/launch_FV3LAM_wflow.sh new file mode 100755 index 0000000000..1f7f692026 --- /dev/null +++ b/ush/launch_FV3LAM_wflow.sh @@ -0,0 +1,418 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Set shell options. +# +#----------------------------------------------------------------------- +# +set -u +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +if [[ $(uname -s) == Darwin ]]; then + command -v greadlink >/dev/null 2>&1 || { \ + echo >&2 "\ +For Darwin-based operating systems (MacOS), the 'greadlink' utility is +required to run the UFS SRW Application. Reference the User's Guide for +more information about platform requirements. Aborting."; \ + exit 1; \ + } + scrfunc_fp=$( greadlink -f "${BASH_SOURCE[0]}" ) +else + scrfunc_fp=$( readlink -f "${BASH_SOURCE[0]}" ) +fi +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the experiment directory. We assume that there is a symlink to +# this script in the experiment directory, and this script is called via +# that symlink. Thus, finding the directory in which the symlink is +# located will give us the experiment directory. We find this by first +# obtaining the directory portion (i.e. the portion without the name of +# this script) of the command that was used to called this script (i.e. +# "$0") and then use the "readlink -f" command to obtain the corresponding +# absolute path. This will work for all four of the following ways in +# which the symlink in the experiment directory pointing to this script +# may be called: +# +# 1) Call this script from the experiment directory: +# > cd /path/to/experiment/directory +# > launch_FV3LAM_wflow.sh +# +# 2) Call this script from the experiment directory but using "./" before +# the script name: +# > cd /path/to/experiment/directory +# > ./launch_FV3LAM_wflow.sh +# +# 3) Call this script from any directory using the absolute path to the +# symlink in the experiment directory: +# > /path/to/experiment/directory/launch_FV3LAM_wflow.sh +# +# 4) Call this script from a directory that is several levels up from the +# experiment directory (but not necessarily at the root directory): +# > cd /path/to +# > experiment/directory/launch_FV3LAM_wflow.sh +# +# Note that given just a file name, e.g. the name of this script without +# any path before it, the "dirname" command will return a ".", e.g. in +# bash, +# +# > exptdir=$( dirname "launch_FV3LAM_wflow.sh" ) +# > echo $exptdir +# +# will print out ".". +# +#----------------------------------------------------------------------- +# +exptdir=$( dirname "$0" ) +if [[ $(uname -s) == Darwin ]]; then + command -v greadlink >/dev/null 2>&1 || { \ + echo >&2 "\ +For Darwin-based operating systems (MacOS), the 'greadlink' utility is +required to run the UFS SRW Application. Reference the User's Guide for +more information about platform requirements. Aborting."; + exit 1; + } + exptdir=$( greadlink -f "$exptdir" ) +else + exptdir=$( readlink -f "$exptdir" ) +fi +# +#----------------------------------------------------------------------- +# +# Source necessary files. +# +#----------------------------------------------------------------------- +# +. $exptdir/var_defns.sh +. $USHDIR/source_util_funcs.sh +. $USHDIR/source_machine_file.sh +. $USHDIR/constants.sh +. $USHDIR/init_env.sh +# +#----------------------------------------------------------------------- +# +# Declare arguments. +# +#----------------------------------------------------------------------- +# +valid_args=( \ + "called_from_cron" \ + ) +process_args valid_args "$@" +print_input_args "valid_args" +# +#----------------------------------------------------------------------- +# +# Make sure called_from_cron is set to a valid value. +# +#----------------------------------------------------------------------- +# +called_from_cron=${called_from_cron:-"FALSE"} +check_var_valid_value "called_from_cron" "valid_vals_BOOLEAN" +called_from_cron=$(boolify "${called_from_cron}") +# +#----------------------------------------------------------------------- +# +# Initialize the environment, e.g. by making the "module" command as well +# as others available. +# +#----------------------------------------------------------------------- +# +env_init_scripts_fps_str="( "$(printf "\"%s\" " "${ENV_INIT_SCRIPTS_FPS[@]}")")" +init_env env_init_scripts_fps="${env_init_scripts_fps_str}" +# +#----------------------------------------------------------------------- +# +# Set the name of the experiment. We take this to be the name of the +# experiment subdirectory (i.e. the string after the last "/" in the +# full path to the experiment directory). +# +#----------------------------------------------------------------------- +# +expt_name="${EXPT_SUBDIR}" +# +#----------------------------------------------------------------------- +# +# Load necessary modules. +# +#----------------------------------------------------------------------- +# +module use "${SR_WX_APP_TOP_DIR}/modulefiles" +module load "${WFLOW_MOD_FN}" > /dev/null 2>&1 || print_err_msg_exit "\ +Loading of platform-specific module file (WFLOW_MOD_FN) for the workflow +task failed: + WFLOW_MOD_FN = \"${WFLOW_MOD_FN}\"" +# +#----------------------------------------------------------------------- +# +# Set file names. These include the rocoto database file and the log +# file in which to store output from this script (aka the workflow +# launch script). +# +#----------------------------------------------------------------------- +# +rocoto_xml_bn=$( basename "${WFLOW_XML_FN}" ".xml" ) +rocoto_database_fn="${rocoto_xml_bn}.db" +launch_log_fn="log.launch_${rocoto_xml_bn}" +# +#----------------------------------------------------------------------- +# +# Initialize the default status of the workflow to "IN PROGRESS". +# +#----------------------------------------------------------------------- +# +wflow_status="IN PROGRESS" +# +#----------------------------------------------------------------------- +# +# Change location to the experiment directory. +# +#----------------------------------------------------------------------- +# +cd_vrfy "$exptdir" +# +#----------------------------------------------------------------------- +# +# Issue the rocotorun command to (re)launch the next task in the workflow. +# Then check for error messages in the output of rocotorun. If any are +# found, it means the end-to-end run of the workflow failed, so set the +# status of the workflow to "FAILURE". +# +#----------------------------------------------------------------------- +# +tmp_fn="rocotorun_output.txt" +rocotorun_cmd="rocotorun -w \"${WFLOW_XML_FN}\" -d \"${rocoto_database_fn}\" -v 10" +eval ${rocotorun_cmd} > ${tmp_fn} 2>&1 || \ + print_err_msg_exit "\ +Call to \"rocotorun\" failed with return code $?." +rocotorun_output=$( cat "${tmp_fn}" ) +rm "${tmp_fn}" + +error_msg="sbatch: error: Batch job submission failed:" +while read -r line; do + grep_output=$( printf "%s" "$line" | grep "${error_msg}" ) + if [ $? -eq 0 ]; then + wflow_status="FAILURE" + break + fi +done <<< "${rocotorun_output}" +# +#----------------------------------------------------------------------- +# +# Issue the rocotostat command to obtain a table specifying the status +# of each task. Then check for dead tasks in the output of rocotostat. +# If any are found, it means the end-to-end run of the workflow failed, +# so set the status of the workflow (wflow_status) to "FAILURE". +# +#----------------------------------------------------------------------- +# +rocotostat_cmd="rocotostat -w \"${WFLOW_XML_FN}\" -d \"${rocoto_database_fn}\" -v 10" +rocotostat_output=$( eval ${rocotostat_cmd} 2>&1 || \ + print_err_msg_exit "\ +Call to \"rocotostat\" failed with return code $?." + ) + +error_msg="DEAD" +while read -r line; do + grep_output=$( printf "%s" "$line" | grep "${error_msg}" ) + if [ $? -eq 0 ]; then + wflow_status="FAILURE" + break + fi +done <<< "${rocotostat_output}" +# +#----------------------------------------------------------------------- +# +# Place the outputs of the rocotorun and rocotostat commands obtained +# above into the launch log file. +# +#----------------------------------------------------------------------- +# +printf "%s" " + +======================================================================== +Start of output from script \"${scrfunc_fn}\". +======================================================================== + +Running rocotorun command (rocotorun_cmd): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + rocotorun_cmd = \'${rocotorun_cmd}\' + +Output of rocotorun_cmd is: +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +${rocotorun_output} + +Running rocotostat command (rocotostat_cmd): +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + rocotostat_cmd = \'${rocotostat_cmd}\' + +Output of rocotostat_cmd is: +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +${rocotostat_output} +" >> "${WFLOW_LAUNCH_LOG_FN}" 2>&1 +# +#----------------------------------------------------------------------- +# +# Use the rocotostat command with the "-s" flag to obtain a summary of +# the status of each cycle in the workflow. The output of this command +# has the following format: +# +# CYCLE STATE ACTIVATED DEACTIVATED +# 201905200000 Active Nov 07 2019 00:23:30 - +# ... +# +# Thus, the first row is a header line containing the column titles, and +# the remaining rows each correspond to one cycle in the workflow. Below, +# we are interested in the first and second columns of each row. The +# first column is a string containing the start time of the cycle (in the +# format YYYYMMDDHHmm, where YYYY is the 4-digit year, MM is the 2-digit +# month, DD is the 2-digit day of the month, HH is the 2-digit hour of +# the day, and mm is the 2-digit minute of the hour). The second column +# is a string containing the state of the cycle. This can be "Active" +# or "Done". Below, we read in and store these two columns in (1-D) +# arrays. +# +#----------------------------------------------------------------------- +# +rocotostat_output=$( rocotostat -w "${WFLOW_XML_FN}" -d "${rocoto_database_fn}" -v 10 -s ) + +regex_search="^[ ]*([0-9]+)[ ]+([A-Za-z]+)[ ]+.*" +cycle_str=() +cycle_status=() +i=0 +while read -r line; do +# +# Note that the first line in rocotostat_output is a header line containing +# the column titles. Thus, we ignore it and consider only the remaining +# lines (of which there is one per cycle). +# + if [ $i -gt 0 ]; then + im1=$((i-1)) + cycle_str[im1]=$( echo "$line" | $SED -r -n -e "s/${regex_search}/\1/p" ) + cycle_status[im1]=$( echo "$line" | $SED -r -n -e "s/${regex_search}/\2/p" ) + fi + i=$((i+1)) +done <<< "${rocotostat_output}" +# +#----------------------------------------------------------------------- +# +# Get the number of cycles. Then count the number of completed cycles +# by finding the number of cycles for which the corresponding element in +# the cycle_status array is set to "Done". +# +#----------------------------------------------------------------------- +# +num_cycles_total=${#cycle_str[@]} +num_cycles_completed=0 +for (( i=0; i<=$((num_cycles_total-1)); i++ )); do + if [ "${cycle_status[i]}" = "Done" ]; then + num_cycles_completed=$((num_cycles_completed+1)) + fi +done +# +#----------------------------------------------------------------------- +# +# If the number of completed cycles is equal to the total number of cycles, +# it means the end-to-end run of the workflow was successful. In this +# case, we reset the wflow_status to "SUCCESS". +# +#----------------------------------------------------------------------- +# +if [ ${num_cycles_completed} -eq ${num_cycles_total} ]; then + wflow_status="SUCCESS" +fi +# +#----------------------------------------------------------------------- +# +# Print informational messages about the workflow to the launch log file, +# including the workflow status. +# +#----------------------------------------------------------------------- +# +printf "%s" " + +Summary of workflow status: +~~~~~~~~~~~~~~~~~~~~~~~~~~ + + ${num_cycles_completed} out of ${num_cycles_total} cycles completed. + Workflow status: ${wflow_status} + +======================================================================== +End of output from script \"${scrfunc_fn}\". +======================================================================== + +" >> ${WFLOW_LAUNCH_LOG_FN} 2>&1 +# +#----------------------------------------------------------------------- +# +# If the workflow status (wflow_status) has been set to either "SUCCESS" +# or "FAILURE", indicate this by appending an appropriate workflow +# completion message to the end of the launch log file. +# +#----------------------------------------------------------------------- +# +if [ "${wflow_status}" = "SUCCESS" ] || \ + [ "${wflow_status}" = "FAILURE" ]; then + + msg=" +The end-to-end run of the workflow for the forecast experiment specified +by expt_name has completed with the following workflow status (wflow_status): + expt_name = \"${expt_name}\" + wflow_status = \"${wflow_status}\" +" +# +# If a cron job was being used to periodically relaunch the workflow, we +# now remove the entry in the crontab corresponding to the workflow +# because the end-to-end run of the workflow has now either succeeded or +# failed and will remain in that state without manual user intervention. +# Thus, there is no need to try to relaunch it. We also append a message +# to the completion message above to indicate this. +# + if [ "${USE_CRON_TO_RELAUNCH}" = "TRUE" ]; then + + msg="${msg}\ +Thus, there is no need to relaunch the workflow via a cron job. Removing +from the crontab the line (CRONTAB_LINE) that calls the workflow launch +script for this experiment: + CRONTAB_LINE = \"${CRONTAB_LINE}\" +" +# +# Remove CRONTAB_LINE from cron table +# + if [ "${called_from_cron}" = "TRUE" ]; then + MACHINE=$MACHINE CRONTAB_LINE=$CRONTAB_LINE \ + python3 $USHDIR/get_crontab_contents.py --delete --called-from-cron + else + MACHINE=$MACHINE CRONTAB_LINE=$CRONTAB_LINE \ + python3 $USHDIR/get_crontab_contents.py --delete + fi + fi +# +# Print the workflow completion message to the launch log file. +# + printf "%s" "$msg" >> ${WFLOW_LAUNCH_LOG_FN} 2>&1 +# +# If the stdout from this script is being sent to the screen (e.g. it is +# not being redirected to a file), then also print out the workflow +# completion message to the screen. +# + if [ -t 1 ]; then + printf "%s" "$msg" + fi + +fi diff --git a/ush/link_fix.py b/ush/link_fix.py new file mode 100755 index 0000000000..56fccc8567 --- /dev/null +++ b/ush/link_fix.py @@ -0,0 +1,399 @@ +#!/usr/bin/env python3 + +import unittest +import os +import sys +import argparse +import glob + +from python_utils import import_vars, set_env_var, print_input_args, \ + print_info_msg, print_err_msg_exit, create_symlink_to_file, \ + define_macos_utilities, check_var_valid_value, \ + cd_vrfy, mkdir_vrfy, find_pattern_in_str, load_shell_config + +def link_fix(verbose, file_group): + """ This file defines a function that ... + Args: + verbose: True or False + file_group: could be on of ["grid", "orog", "sfc_climo"] + Returns: + a string: resolution + """ + + print_input_args(locals()) + + valid_vals_file_group=["grid", "orog", "sfc_climo"] + check_var_valid_value(file_group, valid_vals_file_group) + + #import all environement variables + import_vars() + + # + #----------------------------------------------------------------------- + # + # Create symlinks in the FIXLAM directory pointing to the grid files. + # These symlinks are needed by the make_orog, make_sfc_climo, make_ic, + # make_lbc, and/or run_fcst tasks. + # + # Note that we check that each target file exists before attempting to + # create symlinks. This is because the "ln" command will create sym- + # links to non-existent targets without returning with a nonzero exit + # code. + # + #----------------------------------------------------------------------- + # + print_info_msg(f'Creating links in the FIXLAM directory to the grid files...', + verbose=verbose) + # + #----------------------------------------------------------------------- + # + # Create globbing patterns for grid, orography, and surface climatology + # files. + # + # + # For grid files (i.e. file_group set to "grid"), symlinks are created + # in the FIXLAM directory to files (of the same names) in the GRID_DIR. + # These symlinks/files and the reason each is needed is listed below: + # + # 1) "C*.mosaic.halo${NHW}.nc" + # This mosaic file for the wide-halo grid (i.e. the grid with a ${NHW}- + # cell-wide halo) is needed as an input to the orography filtering + # executable in the orography generation task. The filtering code + # extracts from this mosaic file the name of the file containing the + # grid on which it will generate filtered topography. Note that the + # orography generation and filtering are both performed on the wide- + # halo grid. The filtered orography file on the wide-halo grid is then + # shaved down to obtain the filtered orography files with ${NH3}- and + # ${NH4}-cell-wide halos. + # + # The raw orography generation step in the make_orog task requires the + # following symlinks/files: + # + # a) C*.mosaic.halo${NHW}.nc + # The script for the make_orog task extracts the name of the grid + # file from this mosaic file; this name should be + # "C*.grid.tile${TILE_RGNL}.halo${NHW}.nc". + # + # b) C*.grid.tile${TILE_RGNL}.halo${NHW}.nc + # This is the + # The script for the make_orog task passes the name of the grid + # file (extracted above from the mosaic file) to the orography + # generation executable. The executable then + # reads in this grid file and generates a raw orography + # file on the grid. The raw orography file is initially renamed "out.oro.nc", + # but for clarity, it is then renamed "C*.raw_orog.tile${TILE_RGNL}.halo${NHW}.nc". + # + # c) The fixed files thirty.second.antarctic.new.bin, landcover30.fixed, + # and gmted2010.30sec.int. + # + # The orography filtering step in the make_orog task requires the + # following symlinks/files: + # + # a) C*.mosaic.halo${NHW}.nc + # This is the mosaic file for the wide-halo grid. The orography + # filtering executable extracts from this file the name of the grid + # file containing the wide-halo grid (which should be + # "${CRES}.grid.tile${TILE_RGNL}.halo${NHW}.nc"). The executable then + # looks for this grid file IN THE DIRECTORY IN WHICH IT IS RUNNING. + # Thus, before running the executable, the script creates a symlink in this run directory that + # points to the location of the actual wide-halo grid file. + # + # b) C*.raw_orog.tile${TILE_RGNL}.halo${NHW}.nc + # This is the raw orography file on the wide-halo grid. The script + # for the make_orog task copies this file to a new file named + # "C*.filtered_orog.tile${TILE_RGNL}.halo${NHW}.nc" that will be + # used as input to the orography filtering executable. The executable + # will then overwrite the contents of this file with the filtered orography. + # Thus, the output of the orography filtering executable will be + # the file C*.filtered_orog.tile${TILE_RGNL}.halo${NHW}.nc. + # + # The shaving step in the make_orog task requires the following: + # + # a) C*.filtered_orog.tile${TILE_RGNL}.halo${NHW}.nc + # This is the filtered orography file on the wide-halo grid. + # This gets shaved down to two different files: + # + # i) ${CRES}.oro_data.tile${TILE_RGNL}.halo${NH0}.nc + # This is the filtered orography file on the halo-0 grid. + # + # ii) ${CRES}.oro_data.tile${TILE_RGNL}.halo${NH4}.nc + # This is the filtered orography file on the halo-4 grid. + # + # Note that the file names of the shaved files differ from that of + # the initial unshaved file on the wide-halo grid in that the field + # after ${CRES} is now "oro_data" (not "filtered_orog") to comply + # with the naming convention used more generally. + # + # 2) "C*.mosaic.halo${NH4}.nc" + # This mosaic file for the grid with a 4-cell-wide halo is needed as + # an input to the surface climatology generation executable. The + # surface climatology generation code reads from this file the number + # of tiles (which should be 1 for a regional grid) and the tile names. + # More importantly, using the ESMF function ESMF_GridCreateMosaic(), + # it creates a data object of type esmf_grid; the grid information + # in this object is obtained from the grid file specified in the mosaic + # file, which should be "C*.grid.tile${TILE_RGNL}.halo${NH4}.nc". The + # dimensions specified in this grid file must match the ones specified + # in the (filtered) orography file "C*.oro_data.tile${TILE_RGNL}.halo${NH4}.nc" + # that is also an input to the surface climatology generation executable. + # If they do not, then the executable will crash with an ESMF library + # error (something like "Arguments are incompatible"). + # + # Thus, for the make_sfc_climo task, the following symlinks/files must + # exist: + # a) "C*.mosaic.halo${NH4}.nc" + # b) "C*.grid.tile${TILE_RGNL}.halo${NH4}.nc" + # c) "C*.oro_data.tile${TILE_RGNL}.halo${NH4}.nc" + # + # 3) + # + # + #----------------------------------------------------------------------- + # + # + if file_group == "grid": + fns=[ + f"C*{DOT_OR_USCORE}mosaic.halo{NHW}.nc", + f"C*{DOT_OR_USCORE}mosaic.halo{NH4}.nc", + f"C*{DOT_OR_USCORE}mosaic.halo{NH3}.nc", + f"C*{DOT_OR_USCORE}grid.tile{TILE_RGNL}.halo{NHW}.nc", + f"C*{DOT_OR_USCORE}grid.tile{TILE_RGNL}.halo{NH3}.nc", + f"C*{DOT_OR_USCORE}grid.tile{TILE_RGNL}.halo{NH4}.nc" + ] + fps=[ os.path.join(GRID_DIR,itm) for itm in fns] + run_task=f"{RUN_TASK_MAKE_GRID}" + # + elif file_group == "orog": + fns=[ + f"C*{DOT_OR_USCORE}oro_data.tile{TILE_RGNL}.halo{NH0}.nc", + f"C*{DOT_OR_USCORE}oro_data.tile{TILE_RGNL}.halo{NH4}.nc" + ] + if CCPP_PHYS_SUITE == "FV3_HRRR": + fns+=[ + f"C*{DOT_OR_USCORE}oro_data_ss.tile{TILE_RGNL}.halo{NH0}.nc", + f"C*{DOT_OR_USCORE}oro_data_ls.tile{TILE_RGNL}.halo{NH0}.nc", + ] + fps=[ os.path.join(OROG_DIR,itm) for itm in fns] + run_task=f"{RUN_TASK_MAKE_OROG}" + # + # The following list of symlinks (which have the same names as their + # target files) need to be created made in order for the make_ics and + # make_lbcs tasks (i.e. tasks involving chgres_cube) to work. + # + elif file_group == "sfc_climo": + num_fields=len(SFC_CLIMO_FIELDS) + fns=[None] * (2 * num_fields) + for i in range(num_fields): + ii=2*i + fns[ii]=f"C*.{SFC_CLIMO_FIELDS[i]}.tile{TILE_RGNL}.halo{NH0}.nc" + fns[ii+1]=f"C*.{SFC_CLIMO_FIELDS[i]}.tile{TILE_RGNL}.halo{NH4}.nc" + fps=[ os.path.join(SFC_CLIMO_DIR,itm) for itm in fns] + run_task=f"{RUN_TASK_MAKE_SFC_CLIMO}" + # + + # + #----------------------------------------------------------------------- + # + # Find all files matching the globbing patterns and make sure that they + # all have the same resolution (an integer) in their names. + # + #----------------------------------------------------------------------- + # + i=0 + res_prev="" + res="" + fp_prev="" + + for pattern in fps: + files = glob.glob(pattern) + for fp in files: + + fn = os.path.basename(fp) + + regex_search = "^C([0-9]*).*" + res = find_pattern_in_str(regex_search, fn) + if res is None: + print_err_msg_exit(f''' + The resolution could not be extracted from the current file's name. The + full path to the file (fp) is: + fp = \"{fp}\" + This may be because fp contains the * globbing character, which would + imply that no files were found that match the globbing pattern specified + in fp.''') + else: + res = res[0] + + if ( i > 0 ) and ( res != res_prev ): + print_err_msg_exit(f''' + The resolutions (as obtained from the file names) of the previous and + current file (fp_prev and fp, respectively) are different: + fp_prev = \"{fp_prev}\" + fp = \"{fp}\" + Please ensure that all files have the same resolution.''') + + i=i+1 + fp_prev=f"{fp}" + res_prev=res + # + #----------------------------------------------------------------------- + # + # Replace the * globbing character in the set of globbing patterns with + # the resolution. This will result in a set of (full paths to) specific + # files. + # + #----------------------------------------------------------------------- + # + fps=[ itm.replace('*',res) for itm in fps] + # + #----------------------------------------------------------------------- + # + # In creating the various symlinks below, it is convenient to work in + # the FIXLAM directory. We will change directory back to the original + # later below. + # + #----------------------------------------------------------------------- + # + SAVE_DIR=os.getcwd() + cd_vrfy(FIXLAM) + # + #----------------------------------------------------------------------- + # + # Use the set of full file paths generated above as the link targets to + # create symlinks to these files in the FIXLAM directory. + # + #----------------------------------------------------------------------- + # + # If the task in consideration (which will be one of the pre-processing + # tasks MAKE_GRID_TN, MAKE_OROG_TN, and MAKE_SFC_CLIMO_TN) was run, then + # the target files will be located under the experiment directory. In + # this case, we use relative symlinks in order the experiment directory + # more portable and the symlinks more readable. However, if the task + # was not run, then pregenerated grid, orography, or surface climatology + # files will be used, and those will be located in an arbitrary directory + # (specified by the user) that is somwehere outside the experiment + # directory. Thus, in this case, there isn't really an advantage to using + # relative symlinks, so we use symlinks with absolute paths. + # + if run_task: + relative_link_flag=True + else: + relative_link_flag=False + + for fp in fps: + fn=os.path.basename(fp) + create_symlink_to_file(fp,fn,relative_link_flag) + # + #----------------------------------------------------------------------- + # + # Set the C-resolution based on the resolution appearing in the file + # names. + # + #----------------------------------------------------------------------- + # + cres=f"C{res}" + # + #----------------------------------------------------------------------- + # + # If considering grid files, create a symlink to the halo4 grid file + # that does not contain the halo size in its name. This is needed by + # the tasks that generate the initial and lateral boundary condition + # files. + # + #----------------------------------------------------------------------- + # + if file_group == "grid": + target=f"{cres}{DOT_OR_USCORE}grid.tile{TILE_RGNL}.halo{NH4}.nc" + symlink=f"{cres}{DOT_OR_USCORE}grid.tile{TILE_RGNL}.nc" + create_symlink_to_file(target,symlink,True) + # + #----------------------------------------------------------------------- + # + # If considering surface climatology files, create symlinks to the surface + # climatology files that do not contain the halo size in their names. + # These are needed by the task that generates the initial condition files. + # + #----------------------------------------------------------------------- + # + if file_group == "sfc_climo": + + tmp=[ f"{cres}.{itm}" for itm in SFC_CLIMO_FIELDS] + fns_sfc_climo_with_halo_in_fn=[ f"{itm}.tile{TILE_RGNL}.halo{NH4}.nc" for itm in tmp] + fns_sfc_climo_no_halo_in_fn=[ f"{itm}.tile{TILE_RGNL}.nc" for itm in tmp] + + for i in range(num_fields): + target=f"{fns_sfc_climo_with_halo_in_fn[i]}" + symlink=f"{fns_sfc_climo_no_halo_in_fn[i]}" + create_symlink_to_file(target, symlink, True) + # + # In order to be able to specify the surface climatology file names in + # the forecast model's namelist file, in the FIXLAM directory a symlink + # must be created for each surface climatology field that has "tile1" in + # its name (and no "halo") and which points to the corresponding "tile7.halo0" + # file. + # + tmp=[ f"{cres}.{itm}" for itm in SFC_CLIMO_FIELDS ] + fns_sfc_climo_tile7_halo0_in_fn=[ f"{itm}.tile{TILE_RGNL}.halo{NH0}.nc" for itm in tmp ] + fns_sfc_climo_tile1_no_halo_in_fn=[ f"{itm}.tile1.nc" for itm in tmp ] + + for i in range(num_fields): + target=f"{fns_sfc_climo_tile7_halo0_in_fn[i]}" + symlink=f"{fns_sfc_climo_tile1_no_halo_in_fn[i]}" + create_symlink_to_file(target,symlink,True) + # + #----------------------------------------------------------------------- + # + # Change directory back to original one. + # + #----------------------------------------------------------------------- + # + cd_vrfy(SAVE_DIR) + + return res + +def parse_args(argv): + """ Parse command line arguments""" + parser = argparse.ArgumentParser( + description='Creates symbolic links to FIX directories.' + ) + + parser.add_argument('-f', '--file-group', + dest='file_group', + required=True, + help='File group, could be one of ["grid", "orog", "sfc_climo"].') + + parser.add_argument('-p', '--path-to-defns', + dest='path_to_defns', + required=True, + help='Path to var_defns file.') + + return parser.parse_args(argv) + +if __name__ == '__main__': + args = parse_args(sys.argv[1:]) + cfg = load_shell_config(args.path_to_defns) + import_vars(dictionary=cfg) + link_fix(VERBOSE, args.file_group) + +class Testing(unittest.TestCase): + def test_link_fix(self): + res = link_fix(verbose=True, file_group="grid") + self.assertTrue( res == "3357") + def setUp(self): + define_macos_utilities() + TEST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_data"); + FIXLAM = os.path.join(TEST_DIR, "expt", "fix_lam") + mkdir_vrfy("-p",FIXLAM) + set_env_var("FIXLAM",FIXLAM) + set_env_var("DOT_OR_USCORE","_") + set_env_var("TILE_RGNL",7) + set_env_var("NH0",0) + set_env_var("NHW",6) + set_env_var("NH4",4) + set_env_var("NH3",3) + set_env_var("GRID_DIR",TEST_DIR + os.sep + "RRFS_CONUS_3km") + set_env_var("RUN_TASK_MAKE_GRID","FALSE") + set_env_var("OROG_DIR",TEST_DIR + os.sep + "RRFS_CONUS_3km") + set_env_var("RUN_TASK_MAKE_OROG","FALSE") + set_env_var("SFC_CLIMO_DIR",TEST_DIR + os.sep + "RRFS_CONUS_3km") + set_env_var("RUN_TASK_MAKE_SFC_CLIMO","FALSE") + set_env_var("CCPP_PHYS_SUITE","FV3_GSD_SAR") diff --git a/ush/load_modules_run_task.sh b/ush/load_modules_run_task.sh new file mode 100755 index 0000000000..385ff824b2 --- /dev/null +++ b/ush/load_modules_run_task.sh @@ -0,0 +1,195 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# Source necessary files. +# +#----------------------------------------------------------------------- +# +. ${GLOBAL_VAR_DEFNS_FP} +. $USHDIR/source_util_funcs.sh +. $USHDIR/source_machine_file.sh +. $USHDIR/init_env.sh +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# +{ save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# +scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) +scrfunc_fn=$( basename "${scrfunc_fp}" ) +scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Check arguments. +# +#----------------------------------------------------------------------- +# +if [ "$#" -ne 2 ]; then + + print_err_msg_exit " +Incorrect number of arguments specified: + + Number of arguments specified: $# + +Usage: + + ${scrfunc_fn} task_name jjob_fp + +where the arguments are defined as follows: + + task_name: + The name of the rocoto task for which this script will load modules + and launch the J-job. + + jjob_fp + The full path to the J-job script corresponding to task_name. This + script will launch this J-job using the \"exec\" command (which will + first terminate this script and then launch the j-job; see man page of + the \"exec\" command). +" + +fi +# +#----------------------------------------------------------------------- +# +# Initialize the environment, e.g. by making available the "module" +# command as well as others. +# +#----------------------------------------------------------------------- +# +env_init_scripts_fps_str="( "$(printf "\"%s\" " "${ENV_INIT_SCRIPTS_FPS[@]}")")" +init_env env_init_scripts_fps="${env_init_scripts_fps_str}" +# +#----------------------------------------------------------------------- +# +# Get the task name and the name of the J-job script. +# +#----------------------------------------------------------------------- +# +task_name="$1" +jjob_fp="$2" +# +#----------------------------------------------------------------------- +# +# Loading ufs-srweather-app build module files +# +#----------------------------------------------------------------------- +# +machine=$(echo_lowercase $MACHINE) + +source "${SR_WX_APP_TOP_DIR}/etc/lmod-setup.sh" +module use "${SR_WX_APP_TOP_DIR}/modulefiles" +module load "${BUILD_MOD_FN}" || print_err_msg_exit "\ +Loading of platform- and compiler-specific module file (BUILD_MOD_FN) +for the workflow task specified by task_name failed: + task_name = \"${task_name}\" + BUILD_MOD_FN = \"${BUILD_MOD_FN}\"" +# +#----------------------------------------------------------------------- +# +# Set the directory (modules_dir) in which the module files for the va- +# rious workflow tasks are located. Also, set the name of the module +# file for the specified task. +# +# A module file is a file whose first line is the "magic cookie" string +# '#%Module'. It is interpreted by the "module load ..." command. It +# sets environment variables (including prepending/appending to paths) +# and loads modules. +# +# The UFS SRW App repository contains module files for the +# workflow tasks in the template rocoto XML file for the FV3-LAM work- +# flow that need modules not loaded in the BUILD_MOD_FN above. +# +# The full path to a module file for a given task is +# +# $SR_WX_APP_TOP_DIR/modulefiles/$machine/${task_name}.local +# +# where SR_WX_APP_TOP_DIR is the base directory of the App, machine is the +# name of the machine that we're running on (in lowercase), and task_- +# name is the name of the current task (an input to this script). +# +#----------------------------------------------------------------------- +# +modules_dir="$SR_WX_APP_TOP_DIR/modulefiles/tasks/$machine" +modulefile_name="${task_name}" +default_modules_dir="$SR_WX_APP_TOP_DIR/modulefiles" +# +#----------------------------------------------------------------------- +# +# Load the module file for the specified task on the current machine. +# +#----------------------------------------------------------------------- +# + +print_info_msg "$VERBOSE" " +Loading modules for task \"${task_name}\" ..." + +module use "${modules_dir}" || print_err_msg_exit "\ +Call to \"module use\" command failed." + +# +# Load the .local module file if available for the given task +# +modulefile_local="${task_name}.local" +if [ -f ${modules_dir}/${modulefile_local} ]; then + module load "${modulefile_local}" || print_err_msg_exit "\ + Loading .local module file (in directory specified by mod- + ules_dir) for the specified task (task_name) failed: + task_name = \"${task_name}\" + modulefile_local = \"${modulefile_local}\" + modules_dir = \"${modules_dir}\"" +fi + +module list + + +# Modules that use conda and need an environment activated will set the +# SRW_ENV variable to the name of the environment to be activated. That +# must be done within the script, and not inside the module. Do that +# now. + +if [ -n "${SRW_ENV:-}" ] ; then + set +u + conda activate ${SRW_ENV} + set -u +fi + +# +#----------------------------------------------------------------------- +# +# Use the exec command to terminate the current script and launch the +# J-job for the specified task. +# +#----------------------------------------------------------------------- +# +print_info_msg "$VERBOSE" " +Launching J-job (jjob_fp) for task \"${task_name}\" ... + jjob_fp = \"${jjob_fp}\" +" +exec "${jjob_fp}" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the beginning of this script/func- +# tion. +# +#----------------------------------------------------------------------- +# +{ restore_shell_opts; } > /dev/null 2>&1 + + diff --git a/ush/machine/cheyenne.sh b/ush/machine/cheyenne.sh new file mode 100644 index 0000000000..2118c9867b --- /dev/null +++ b/ush/machine/cheyenne.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + location="" + case ${external_model} in + + "FV3GFS") + location='/glade/p/ral/jntp/UFS_CAM/COMGFS/gfs.${yyyymmdd}/${hh}' + ;; + + esac + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE="${NCORES_PER_NODE:-36}" +SCHED=${SCHED:-"pbspro"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"regular"} +QUEUE_HPSS=${QUEUE_HPSS:-"regular"} +QUEUE_FCST=${QUEUE_FCST:-"regular"} + +# UFS SRW App specific paths +staged_data_dir="/glade/p/ral/jntp/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"${staged_data_dir}/FV3LAM_pregen"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +RUN_CMD_UTILS='mpirun -np $nprocs' +RUN_CMD_FCST='mpirun -np ${PE_MEMBER01}' +RUN_CMD_POST='mpirun -np $nprocs' + +# MET/METplus-Related Paths +MET_INSTALL_DIR=${MET_INSTALL_DIR:-"/glade/p/ral/jntp/MET/MET_releases/10.1.1"} +METPLUS_PATH=${METPLUS_PATH:-"/glade/p/ral/jntp/MET/METplus/METplus-4.1.1"} +CCPA_OBS_DIR=${CCPA_OBS_DIR:-"${staged_data_dir}/obs_data/ccpa/proc"} +MRMS_OBS_DIR=${MRMS_OBS_DIR:-"${staged_data_dir}/obs_data/mrms/proc"} +NDAS_OBS_DIR=${NDAS_OBS_DIR:-"${staged_data_dir}/obs_data/ndas/proc"} +MET_BIN_EXEC=${MET_BIN_EXEC:-"bin"} + +# Test Data Locations +TEST_COMIN="${staged_data_dir}/COMGFS" +TEST_PREGEN_BASEDIR="${staged_data_dir}/FV3LAM_pregen" +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" diff --git a/ush/machine/gaea.sh b/ush/machine/gaea.sh new file mode 100755 index 0000000000..036b005e90 --- /dev/null +++ b/ush/machine/gaea.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + case ${external_model} in + + "FV3GFS") + location='/lustre/f2/dev/Mark.Potts/EPIC/SRW/model_data/FV3GFS/${yyyymmdd}${hh}' + ;; + + esac + echo ${location:-} +} + + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_ICS})} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +SLURM_NATIVE_CMD="-M c3" +NCORES_PER_NODE=${NCORES_PER_NODE:-32} +SCHED=${SCHED:-"slurm"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"normal"} +QUEUE_HPSS=${QUEUE_DEFAULT:-"normal"} +QUEUE_FCST=${QUEUE_DEFAULT:-"normal"} +WTIME_MAKE_LBCS="00:60:00" + +# UFS SRW App specific paths +staged_data_dir="/lustre/f2/pdata/ncep_shared/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" + +RUN_CMD_SERIAL="time" +#Run Commands currently differ for GNU/openmpi +#RUN_CMD_UTILS='mpirun --mca btl tcp,vader,self -np $nprocs' +#RUN_CMD_FCST='mpirun --mca btl tcp,vader,self -np ${PE_MEMBER01}' +#RUN_CMD_POST='mpirun --mca btl tcp,vader,self -np $nprocs' +RUN_CMD_UTILS='srun --mpi=pmi2 -n $nprocs' +RUN_CMD_FCST='srun --mpi=pmi2 -n ${PE_MEMBER01}' +RUN_CMD_POST='srun --mpi=pmi2 -n $nprocs' + +# MET Installation Locations +MET_INSTALL_DIR=${MET_INSTALL_DIR:-"/usw/met/10.1.2"} +METPLUS_PATH=${METPLUS_PATH:-"/usw/met/METplus/METplus-4.1.3"} +CCPA_OBS_DIR=${CCPA_OBS_DIR:-"${staged_data_dir}/obs_data/ccpa/proc"} +MRMS_OBS_DIR=${MRMS_OBS_DIR:-"${staged_data_dir}/obs_data/mrms/proc"} +NDAS_OBS_DIR=${NDAS_OBS_DIR:-"${staged_data_dir}/obs_data/ndas/proc"} +MET_BIN_EXEC=${MET_BIN_EXEC:-"bin"} + +# Test Data Locations diff --git a/ush/machine/hera.sh b/ush/machine/hera.sh new file mode 100644 index 0000000000..b34610d44e --- /dev/null +++ b/ush/machine/hera.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + # Hera does not currently have any files staged on disk. + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + location="" + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +EXTRN_MDL_DATA_STORES=${EXTRN_MDL_DATA_STORES:-"hpss aws nomads"} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE=${NCORES_PER_NODE:-40} +SCHED=${SCHED:-"slurm"} +PARTITION_DEFAULT=${PARTITION_DEFAULT:-"hera"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"batch"} +PARTITION_HPSS=${PARTITION_HPSS:-"service"} +QUEUE_HPSS=${QUEUE_HPSS:-"batch"} +PARTITION_FCST=${PARTITION_FCST:-"hera"} +QUEUE_FCST=${QUEUE_FCST:-"batch"} + +# UFS SRW App specific paths +staged_data_dir="/scratch2/BMC/det/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"${staged_data_dir}/FV3LAM_pregen"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +RUN_CMD_UTILS="srun" +RUN_CMD_FCST="srun" +RUN_CMD_POST="srun" + +# MET/METplus-Related Paths +MET_INSTALL_DIR=${MET_INSTALL_DIR:-"/contrib/met/10.1.1"} +METPLUS_PATH=${METPLUS_PATH:-"/contrib/METplus/METplus-4.1.1"} +CCPA_OBS_DIR=${CCPA_OBS_DIR:-"${staged_data_dir}/obs_data/ccpa/proc"} +MRMS_OBS_DIR=${MRMS_OBS_DIR:-"${staged_data_dir}/obs_data/mrms/proc"} +NDAS_OBS_DIR=${NDAS_OBS_DIR:-"${staged_data_dir}/obs_data/ndas/proc"} +MET_BIN_EXEC=${MET_BIN_EXEC:-"bin"} + +# Test Data Locations +TEST_COMIN="${staged_data_dir}/COMGFS" +TEST_PREGEN_BASEDIR="${staged_data_dir}/FV3LAM_pregen" +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" +TEST_ALT_EXTRN_MDL_SYSBASEDIR_ICS="/scratch2/BMC/det/UFS_SRW_app/dummy_FV3GFS_sys_dir" +TEST_ALT_EXTRN_MDL_SYSBASEDIR_LBCS="/scratch2/BMC/det/UFS_SRW_app/dummy_FV3GFS_sys_dir" diff --git a/ush/machine/jet.sh b/ush/machine/jet.sh new file mode 100644 index 0000000000..ced5345de4 --- /dev/null +++ b/ush/machine/jet.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + location="" + case ${external_model} in + + "FV3GFS") + case $external_file_fmt in + "nemsio") + location='/public/data/grids/gfs/nemsio' + ;; + "grib2") + location='/public/data/grids/gfs/0p25deg/grib2' + ;; + "netcdf") + location='/public/data/grids/gfs/anl/netcdf/' + ;; + esac + ;; + "RAP") + location='/public/data/grids/rap/full/wrfprs/grib2' + ;; + "HRRR") + location='/public/data/grids/hrrr/conus/wrfprs/grib2' + ;; + + esac + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +EXTRN_MDL_DATA_STORES=${EXTRN_MDL_DATA_STORES:-"hpss aws nomads"} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE=${NCORES_PER_NODE:-24} +SCHED=${SCHED:-"slurm"} +PARTITION_DEFAULT=${PARTITION_DEFAULT:-"sjet,vjet,kjet,xjet"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"batch"} +PARTITION_HPSS=${PARTITION_HPSS:-"service"} +QUEUE_HPSS=${QUEUE_HPSS:-"batch"} +PARTITION_FCST=${PARTITION_FCST:-"sjet,vjet,kjet,xjet"} +QUEUE_FCST=${QUEUE_FCST:-"batch"} + +# UFS SRW App specific paths +staged_data_dir="/mnt/lfs4/BMC/wrfruc/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"${staged_data_dir}/FV3LAM_pregen"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +RUN_CMD_UTILS="srun" +RUN_CMD_FCST="srun" +RUN_CMD_POST="srun" + +# MET/METplus-Related Paths +MET_INSTALL_DIR=${MET_INSTALL_DIR:-"/contrib/met/10.1.1"} +METPLUS_PATH=${METPLUS_PATH:-"/contrib/met/METplus/METplus-4.1.1"} +CCPA_OBS_DIR=${CCPA_OBS_DIR:-"${staged_data_dir}/obs_data/ccpa/proc"} +MRMS_OBS_DIR=${MRMS_OBS_DIR:-"${staged_data_dir}/obs_data/mrms/proc"} +NDAS_OBS_DIR=${NDAS_OBS_DIR:-"${staged_data_dir}/obs_data/ndas/proc"} +MET_BIN_EXEC=${MET_BIN_EXEC:-"bin"} + +# Test Data Locations +TEST_COMIN="${staged_data_dir}/COMGFS" +TEST_PREGEN_BASEDIR="${staged_data_dir}/FV3LAM_pregen" +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" diff --git a/ush/machine/linux.sh b/ush/machine/linux.sh new file mode 100644 index 0000000000..cdf055eb4b --- /dev/null +++ b/ush/machine/linux.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -x + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + case ${external_model} in + + "FV3GFS") + location='/home/username/DATA/UFS/FV3GFS/' + ;; + *) + print_info_msg"\ + External model \'${external_model}\' does not have a default + location on Linux systems. " + ;; + + esac + echo ${location:-} +} + + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_ICS})} + + System scripts to source to initialize various commands within workflow + scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="none" +NCORES_PER_NODE=${NCORES_PER_NODE:-8} +SCHED=${SCHED:-"none"} + +# UFS SRW App specific paths +FIXgsm=${FIXgsm:-"/home/username/DATA/UFS/fix/fix_am"} +FIXaer=${FIXaer:-"/home/username/DATA/UFS/fix/fix_aer"} +FIXlut=${FIXlut:-"/home/username/DATA/UFS/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"/home/username/DATA/UFS/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"/home/username/DATA/UFS/fix/fix_sfc_climo"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +#Run Commands currently differ for GNU/openmpi +RUN_CMD_UTILS='mpirun -n 4' +RUN_CMD_FCST='mpirun -n ${PE_MEMBER01} ' +RUN_CMD_POST='mpirun -n 4 ' + +# MET Installation Locations + diff --git a/ush/machine/macos.sh b/ush/machine/macos.sh new file mode 100644 index 0000000000..42d70c5684 --- /dev/null +++ b/ush/machine/macos.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +set -x + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + case ${external_model} in + + "FV3GFS") + location='/Users/username/DATA/UFS/FV3GFS/' + ;; + *) + print_info_msg"\ + External model \'${external_model}\' does not have a default + location on MacOSX. " + ;; + + esac + echo ${location:-} +} + + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_ICS})} + + System scripts to source to initialize various commands within workflow + scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="none" +NCORES_PER_NODE=${NCORES_PER_NODE:-8} +SCHED=${SCHED:-"none"} + +# UFS SRW App specific paths +FIXgsm=${FIXgsm:-"/Users/username/DATA/UFS/fix/fix_am"} +FIXaer=${FIXaer:-"/Users/username/DATA/UFS/fix/fix_aer"} +FIXlut=${FIXlut:-"/Users/username/DATA/UFS/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"/Users/username/DATA/UFS/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"/Users/username/DATA/UFS/fix/fix_sfc_climo"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +#Run Commands currently differ for GNU/openmpi +RUN_CMD_UTILS='mpirun -n 4' +RUN_CMD_FCST='mpirun -n ${PE_MEMBER01} ' +RUN_CMD_POST='mpirun -n 4 ' + +# MET Installation Locations + diff --git a/ush/machine/noaacloud.sh b/ush/machine/noaacloud.sh new file mode 100755 index 0000000000..62a698da8a --- /dev/null +++ b/ush/machine/noaacloud.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +set -x + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + case ${external_model} in + + "FV3GFS") + location='/contrib/GST/model_data/FV3GFS/${yyyymmdd}${hh}' + ;; + + esac + echo ${location:-} +} +export PROJ_LIB=/contrib/GST/miniconda/envs/regional_workflow/share/proj +export OPT=/contrib/EPIC/hpc-modules +export PATH=${PATH}:/contrib/GST/miniconda/envs/regional_workflow/bin + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_ICS})} + +EXTRN_MDL_DATA_STORES=${EXTRN_MDL_DATA_STORES:-"aws nomads"} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE=${NCORES_PER_NODE:-36} +SCHED=${SCHED:-"slurm"} + +# UFS SRW App specific paths +staged_data_dir="/contrib/EPIC/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" + +RUN_CMD_SERIAL="time" +#Run Commands currently differ for GNU/openmpi +#RUN_CMD_UTILS='mpirun --mca btl tcp,vader,self -np $nprocs' +#RUN_CMD_FCST='mpirun --mca btl tcp,vader,self -np ${PE_MEMBER01}' +#RUN_CMD_POST='mpirun --mca btl tcp,vader,self -np $nprocs' +RUN_CMD_UTILS='mpiexec -np $nprocs' +RUN_CMD_FCST='mpiexec -np ${PE_MEMBER01}' +RUN_CMD_POST='mpiexec -np $nprocs' + +export build_mod_fn="wflow_noaacloud" +BUILD_MOD_FN="wflow_noaacloud" + +# MET Installation Locations +# MET Plus is not yet supported on noaacloud +. /contrib/EPIC/.bash_conda diff --git a/ush/machine/odin.sh b/ush/machine/odin.sh new file mode 100644 index 0000000000..58d360a633 --- /dev/null +++ b/ush/machine/odin.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + staged_data_dir="/scratch/ywang/UFS_SRW_App/develop" + + location="" + case ${external_model} in + + "GSMGFS") + location="${staged_data_dir}/input_model_data/GFS" + ;; + "FV3GFS") + location="${staged_data_dir}/input_model_data/FV3GFS" + ;; + "HRRR") + location="${staged_data_dir}/input_model_data/HRRR" + ;; + "RAP") + location="${staged_data_dir}/input_model_data/RAP" + ;; + "NAM") + location="${staged_data_dir}/input_model_data/NAM" + ;; + esac + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=() +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE=${NCORES_PER_NODE:-24} +SCHED=${SCHED:-"slurm"} +PARTITION_DEFAULT=${PARTITION_DEFAULT:-"workq"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"workq"} +PARTITION_HPSS=${PARTITION_HPSS:-"workq"} +QUEUE_HPSS=${QUEUE_HPSS:-"workq"} +PARTITION_FCST=${PARTITION_FCST:-"workq"} +QUEUE_FCST=${QUEUE_FCST:-"workq"} + +# UFS SRW App specific paths +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"${staged_data_dir}/FV3LAM_pregen"} + +# Run commands for executables +RUN_CMD_SERIAL="srun -n 1" +RUN_CMD_UTILS='srun -n $nprocs' +RUN_CMD_FCST='srun -n ${PE_MEMBER01}' +RUN_CMD_POST="srun -n 1" + +# Test Data Locations +TEST_PREGEN_BASEDIR="${staged_data_dir}/FV3LAM_pregen" +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" diff --git a/ush/machine/orion.sh b/ush/machine/orion.sh new file mode 100644 index 0000000000..fe01323b75 --- /dev/null +++ b/ush/machine/orion.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + # Orion does not currently have any files staged on disk. + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + location="" + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +EXTRN_MDL_DATA_STORES=${EXTRN_MDL_DATA_STORES:-"aws nomads"} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/etc/profile" ) +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE=${NCORES_PER_NODE:-40} +SCHED=${SCHED:-"slurm"} +PARTITION_DEFAULT=${PARTITION_DEFAULT:-"orion"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"batch"} +PARTITION_HPSS=${PARTITION_HPSS:-"service"} +QUEUE_HPSS=${QUEUE_HPSS:-"batch"} +PARTITION_FCST=${PARTITION_FCST:-"orion"} +QUEUE_FCST=${QUEUE_FCST:-"batch"} + +# UFS SRW App specific paths +staged_data_dir="/work/noaa/fv3-cam/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"${staged_data_dir}/FV3LAM_pregen"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +RUN_CMD_UTILS="srun" +RUN_CMD_FCST='srun -n ${PE_MEMBER01}' +RUN_CMD_POST="srun" + +# MET/METplus-Related Paths +MET_INSTALL_DIR=${MET_INSTALL_DIR:-"/apps/contrib/MET/10.1.1"} +METPLUS_PATH=${METPLUS_PATH:-"/apps/contrib/MET/METplus/METplus-4.1.1"} +CCPA_OBS_DIR=${CCPA_OBS_DIR:-"${staged_data_dir}/obs_data/ccpa/proc"} +MRMS_OBS_DIR=${MRMS_OBS_DIR:-"${staged_data_dir}/obs_data/mrms/proc"} +NDAS_OBS_DIR=${NDAS_OBS_DIR:-"${staged_data_dir}/obs_data/ndas/proc"} +MET_BIN_EXEC=${MET_BIN_EXEC:-"bin"} + +# Test Data Locations +TEST_COMIN="${staged_data_dir}/COMGFS" +TEST_PREGEN_BASEDIR="${staged_data_dir}/FV3LAM_pregen" +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" + diff --git a/ush/machine/singularity.sh b/ush/machine/singularity.sh new file mode 100644 index 0000000000..14f840800b --- /dev/null +++ b/ush/machine/singularity.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + location="" + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +EXTRN_MDL_DATA_STORES=${EXTRN_MDL_DATA_STORES:-"aws nomads"} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=( "/usr/share/lmod/6.6/init/profile" ) +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE=${NCORES_PER_NODE:-40} +SCHED=${SCHED:-"slurm"} +PARTITION_DEFAULT=${PARTITION_DEFAULT:-""} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"batch"} +PARTITION_HPSS=${PARTITION_HPSS:-"service"} +QUEUE_HPSS=${QUEUE_HPSS:-"batch"} +PARTITION_FCST=${PARTITION_FCST:-""} +QUEUE_FCST=${QUEUE_FCST:-"batch"} + +# UFS SRW App specific paths +FIXgsm=${FIXgsm:-"/contrib/global/glopara/fix/fix_am"} +FIXaer=${FIXaer:-"/contrib/global/glopara/fix/fix_aer"} +FIXlut=${FIXlut:-"/contrib/global/glopara/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"/contrib/global/glopara/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"/contrib/global/glopara/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"/needs/to/be/specified"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +RUN_CMD_UTILS='mpirun -np $nprocs --oversubscribe' +RUN_CMD_FCST='mpirun -n ${PE_MEMBER01} --oversubscribe' +RUN_CMD_POST='mpirun -np $nprocs --oversubscribe' diff --git a/ush/machine/stampede.sh b/ush/machine/stampede.sh new file mode 100644 index 0000000000..3f879ea22f --- /dev/null +++ b/ush/machine/stampede.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +function file_location() { + + # Return the default location of external model files on disk + + local external_file_fmt external_model location + + external_model=${1} + external_file_fmt=${2} + + staged_data_dir="/work2/00315/tg455890/stampede2/UFS_SRW_App/develop" + + location="" + case ${external_model} in + + "GSMGFS") + location="${staged_data_dir}/input_model_data/GFS" + ;; + "FV3GFS") + location="${staged_data_dir}/input_model_data/FV3GFS" + ;; + "HRRR") + location="${staged_data_dir}/input_model_data/HRRR" + ;; + "RAP") + location="${staged_data_dir}/input_model_data/RAP" + ;; + "NAM") + location="${staged_data_dir}/input_model_data/NAM" + ;; + esac + echo ${location:-} + +} + +EXTRN_MDL_SYSBASEDIR_ICS=${EXTRN_MDL_SYSBASEDIR_ICS:-$(file_location \ + ${EXTRN_MDL_NAME_ICS} \ + ${FV3GFS_FILE_FMT_ICS})} +EXTRN_MDL_SYSBASEDIR_LBCS=${EXTRN_MDL_SYSBASEDIR_LBCS:-$(file_location \ + ${EXTRN_MDL_NAME_LBCS} \ + ${FV3GFS_FILE_FMT_LBCS})} + +# System scripts to source to initialize various commands within workflow +# scripts (e.g. "module"). +if [ -z ${ENV_INIT_SCRIPTS_FPS:-""} ]; then + ENV_INIT_SCRIPTS_FPS=() +fi + +# Commands to run at the start of each workflow task. +PRE_TASK_CMDS='{ ulimit -s unlimited; ulimit -a; }' + +# Architecture information +WORKFLOW_MANAGER="rocoto" +NCORES_PER_NODE="${NCORES_PER_NODE:-68}" +SCHED=${SCHED:-"slurm"} +PARTITION_DEFAULT=${PARTITION_DEFAULT:-"normal"} +QUEUE_DEFAULT=${QUEUE_DEFAULT:-"normal"} +PARTITION_HPSS=${PARTITION_HPSS:-"normal"} +QUEUE_HPSS=${QUEUE_HPSS:-"normal"} +PARTITION_FCST=${PARTITION_FCST:-"normal"} +QUEUE_FCST=${QUEUE_FCST:-"normal"} + +# UFS SRW App specific paths +staged_data_dir="/work2/00315/tg455890/stampede2/UFS_SRW_App/develop" +FIXgsm=${FIXgsm:-"${staged_data_dir}/fix/fix_am"} +FIXaer=${FIXaer:-"${staged_data_dir}/fix/fix_aer"} +FIXlut=${FIXlut:-"${staged_data_dir}/fix/fix_lut"} +TOPO_DIR=${TOPO_DIR:-"${staged_data_dir}/fix/fix_orog"} +SFC_CLIMO_INPUT_DIR=${SFC_CLIMO_INPUT_DIR:-"${staged_data_dir}/fix/fix_sfc_climo"} +DOMAIN_PREGEN_BASEDIR=${DOMAIN_PREGEN_BASEDIR:-"${staged_data_dir}/FV3LAM_pregen"} + +# Run commands for executables +RUN_CMD_SERIAL="time" +RUN_CMD_UTILS='ibrun -np $nprocs' +RUN_CMD_FCST='ibrun -np $nprocs' +RUN_CMD_POST='ibrun -np $nprocs' + +# Test Data Locations +TEST_PREGEN_BASEDIR="${staged_data_dir}/FV3LAM_pregen" +TEST_EXTRN_MDL_SOURCE_BASEDIR="${staged_data_dir}/input_model_data" diff --git a/ush/make_grid_mosaic_file.sh b/ush/make_grid_mosaic_file.sh new file mode 100644 index 0000000000..8abba8c334 --- /dev/null +++ b/ush/make_grid_mosaic_file.sh @@ -0,0 +1,189 @@ +#!/bin/bash + +# +#----------------------------------------------------------------------- +# +# This file defines a function that creates a grid mosaic file from the +# specified grid file. +# +#----------------------------------------------------------------------- +# +function make_grid_mosaic_file() { +# +#----------------------------------------------------------------------- +# +# Save current shell options (in a global array). Then set new options +# for this script/function. +# +#----------------------------------------------------------------------- +# + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + local scrfunc_fp=$( $READLINK -f "${BASH_SOURCE[0]}" ) + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Specify the set of valid argument names that this script/function can +# accept. Then process the arguments provided to it (which should con- +# sist of a set of name-value pairs of the form arg1="value1", etc). +# +#----------------------------------------------------------------------- +# + local valid_args=( \ +"grid_dir" \ +"grid_fn" \ +"mosaic_fn" \ +"run_cmd" \ + ) + process_args valid_args "$@" +# +#----------------------------------------------------------------------- +# +# For debugging purposes, print out values of arguments passed to this +# script. Note that these will be printed out only if VERBOSE is set to +# TRUE. +# +#----------------------------------------------------------------------- +# + print_input_args valid_args +# +#----------------------------------------------------------------------- +# +# Declare local variables. +# +#----------------------------------------------------------------------- +# + local exec_fn \ + exec_fp \ + grid_fp \ + mosaic_fp \ + mosaic_fp_prefix +# +#----------------------------------------------------------------------- +# +# Set the name and path to the executable that creates a grid mosaic file +# and make sure that it exists. +# +#----------------------------------------------------------------------- +# + exec_fn="make_solo_mosaic" + exec_fp="$EXECDIR/${exec_fn}" + if [ ! -f "${exec_fp}" ]; then + print_err_msg_exit "\ +The executable (exec_fp) for generating the grid mosaic file does not +exist: + exec_fp = \"${exec_fp}\" +Please ensure that you've built this executable." + fi +# +#----------------------------------------------------------------------- +# +# Create the grid mosaic file for the grid with a NH4-cell-wide halo. +# +#----------------------------------------------------------------------- +# + grid_fp="${grid_dir}/${grid_fn}" + mosaic_fp="${grid_dir}/${mosaic_fn}" + mosaic_fp_prefix="${mosaic_fp%.*}" +# +# Call the make_solo_mosaic executable/code to generate a mosaic file. +# Note the following about this code: +# +# 1) The code attempts to open the grid file specified by the argument +# of --tile_file in the directory specified by the argument of --dir. +# If it cannot find this file, it will fail. +# +# Note that: +# +# a) The argument of --grid may or may not contain a "/" at the end. +# The code will add a "/" if necessary when appending the argument +# of --tile_file to that of --grid to form the full path to the +# grid file. +# +# b) The code creates a string variable named "gridlocation" in the +# mosaic file that contains the argument of --dir followed if +# necessary by a "/". +# +# c) The code creates a string array variable named "gridfiles" in the +# mosaic file that has only a single element (for the case of a +# global or nested grid, it would contain more elements). This +# element contains the argument of --grid, i.e. the name of the +# grid file. +# +# 2) The argument of --mosaic must be the absolute or relative path to +# the netcdf mosaic file that is to be created but without the ".nc" +# file extension. For example, if we want the mosaic file to be in +# the directory /abc/def and be called ghi.nc, then we would specify +# +# --mosaic "/abc/def/ghi" +# +# Note that: +# +# a) All parts of the specified path except the last one (i.e. the +# substring after the last "/", which is the name of the mosaic +# file without the ".nc" extension) must exist. If they don't, +# the code will fail. +# +# b) If the argument of --mosaic is a relative path, then the code +# assumes that this path is relative to the current working directory, +# i.e. the directory from which the make_solo_mosaic executable is +# called. +# +# c) If the argument of --mosaic ends with a "/", then it is the path +# to a directory, not to a file. In this case, a mosaic file named +# ".nc" will be created in this absolute or relative directory. +# For example, if the argument of --mosaic is "/abc/def/", then a +# file named ".nc" will be created in the directory /abc/def +# (assuming the directory /abc/def exists). This is generally not +# what we want, so the argument to --mosaic should not end with a +# "/" +# +# 3) The code creates a string variable named "mosaic" in the mosaic file. +# This gets set exactly to the argument of --mosaic without any +# modifications. Thus, if this argument is a relative path, "mosaic" +# will be set to that relative path without the current working directory +# prepended to it. Similarly, "mosaic" will normally not contain at +# its end the ".nc" extension of the mosaic file (unless the argument +# to --mosaic itself contains that extension, e.g. if the argument is +# "/abc/def/ghi.nc", but in that case the mosaic file will be in the +# directory /abc/def and named ghi.nc.nc -- note the double ".nc" +# extensions). +# + ${run_cmd} "${exec_fp}" \ + --num_tiles 1 \ + --dir "${grid_dir}" \ + --tile_file "${grid_fn}" \ + --mosaic "${mosaic_fp_prefix}" || \ + print_err_msg_exit "\ +Call to executable (exec_fp) that generates a grid mosaic file for a +regional grid returned with nonzero exit code: + exec_fp = \"${exec_fp}\"" +# +#----------------------------------------------------------------------- +# +# Restore the shell options saved at the start of this script/function. +# +#----------------------------------------------------------------------- +# + { restore_shell_opts; } > /dev/null 2>&1 + +} + diff --git a/ush/mrms_pull_topofhour.py b/ush/mrms_pull_topofhour.py new file mode 100644 index 0000000000..3744242019 --- /dev/null +++ b/ush/mrms_pull_topofhour.py @@ -0,0 +1,88 @@ +import sys, os, shutil, subprocess +import datetime +import re, csv, glob +import bisect +import numpy as np +import unittest + +if __name__ == '__main__': + # Copy and unzip MRMS files that are closest to top of hour + # Done every hour on a 20-minute lag + + # Include option to define valid time on command line + # Used to backfill verification + #try: + valid_time = str(sys.argv[1]) + + YYYY = int(valid_time[0:4]) + MM = int(valid_time[4:6]) + DD = int(valid_time[6:8]) + HH = int(valid_time[8:19]) + + valid = datetime.datetime(YYYY,MM,DD,HH,0,0) + + #except IndexError: + # valid_time = None + + # Default to current hour if not defined on command line + #if valid_time is None: + # now = datetime.datetime.utcnow() + # YYYY = int(now.strftime('%Y')) + # MM = int(now.strftime('%m')) + # DD = int(now.strftime('%d')) + # HH = int(now.strftime('%H')) + + # valid = datetime.datetime(YYYY,MM,DD,HH,0,0) + # valid_time = valid.strftime('%Y%m%d%H') + + print('Pulling '+valid_time+' MRMS data') + + # Set up working directory + DATA_HEAD = str(sys.argv[2]) + MRMS_PROD_DIR = str(sys.argv[3]) + MRMS_PRODUCT = str(sys.argv[4]) + level = str(sys.argv[5]) + + VALID_DIR = os.path.join(DATA_HEAD,valid.strftime('%Y%m%d')) + if not os.path.exists(VALID_DIR): + os.makedirs(VALID_DIR) + os.chdir(DATA_HEAD) + + # Sort list of files for each MRMS product + print(valid.strftime('%Y%m%d')) + if valid.strftime('%Y%m%d') < '20200303': + search_path = MRMS_PROD_DIR+'/'+valid.strftime('%Y%m%d')+'/dcom/us007003/ldmdata/obs/upperair/mrms/conus/'+MRMS_PRODUCT+'/'+MRMS_PRODUCT+'*.gz' + elif valid.strftime('%Y%m%d') >= '20200303': + search_path = MRMS_PROD_DIR+'/'+valid.strftime('%Y%m%d')+'/upperair/mrms/conus/'+MRMS_PRODUCT+'/'+MRMS_PRODUCT+'*.gz' + file_list = [f for f in glob.glob(search_path)] + time_list = [file_list[x][-24:-9] for x in range(len(file_list))] + int_list = [int(time_list[x][0:8]+time_list[x][9:15]) for x in range(len(time_list))] + int_list.sort() + datetime_list = [datetime.datetime.strptime(str(x),"%Y%m%d%H%M%S") for x in int_list] + + # Find the MRMS file closest to the valid time + i = bisect.bisect_left(datetime_list,valid) + closest_timestamp = min(datetime_list[max(0, i-1): i+2], key=lambda date: abs(valid - date)) + + # Check to make sure closest file is within +/- 15 mins of top of the hour + # Copy and rename the file for future ease + difference = abs(closest_timestamp - valid) + if difference.total_seconds() <= 900: + filename1 = MRMS_PRODUCT+level+closest_timestamp.strftime('%Y%m%d-%H%M%S')+'.grib2.gz' + filename2 = MRMS_PRODUCT+level+valid.strftime('%Y%m%d-%H')+'0000.grib2.gz' + + if valid.strftime('%Y%m%d') < '20200303': + print('cp '+MRMS_PROD_DIR+'/'+valid.strftime('%Y%m%d')+'/dcom/us007003/ldmdata/obs/upperair/mrms/conus/'+MRMS_PRODUCT+'/'+filename1+' '+VALID_DIR+'/'+filename2) + + os.system('cp '+MRMS_PROD_DIR+'/'+valid.strftime('%Y%m%d')+'/dcom/us007003/ldmdata/obs/upperair/mrms/conus/'+MRMS_PRODUCT+'/'+filename1+' '+VALID_DIR+'/'+filename2) + os.system('gunzip '+VALID_DIR+'/'+filename2) + elif valid.strftime('%Y%m%d') >= '20200303': + print('cp '+MRMS_PROD_DIR+'/'+valid.strftime('%Y%m%d')+'/upperair/mrms/conus/'+MRMS_PRODUCT+'/'+filename1+' '+VALID_DIR+'/'+filename2) + + os.system('cp '+MRMS_PROD_DIR+'/'+valid.strftime('%Y%m%d')+'/upperair/mrms/conus/'+MRMS_PRODUCT+'/'+filename1+' '+VALID_DIR+'/'+filename2) + os.system('gunzip '+VALID_DIR+'/'+filename2) + +#dummy unittest +class Testing(unittest.TestCase): + def test_mrms_pull_topfhour(self): + pass diff --git a/ush/predef_grid_params.yaml b/ush/predef_grid_params.yaml new file mode 100644 index 0000000000..5b3849fdd0 --- /dev/null +++ b/ush/predef_grid_params.yaml @@ -0,0 +1,874 @@ +# +#----------------------------------------------------------------------- +# +# Set grid and other parameters according to the value of the predefined +# domain (PREDEF_GRID_NAME). Note that the code will enter this script +# only if PREDEF_GRID_NAME has a valid (and non-empty) value. +# +#################### +# The following comments need to be updated: +#################### +# +# 1) Reset the experiment title (expt_title). +# 2) Reset the grid parameters. +# 3) If the write component is to be used (i.e. QUILTING is set to +# "TRUE") and the variable WRTCMP_PARAMS_TMPL_FN containing the name +# of the write-component template file is unset or empty, set that +# filename variable to the appropriate preexisting template file. +# +# For the predefined domains, we determine the starting and ending indi- +# ces of the regional grid within tile 6 by specifying margins (in units +# of number of cells on tile 6) between the boundary of tile 6 and that +# of the regional grid (tile 7) along the left, right, bottom, and top +# portions of these boundaries. Note that we do not use "west", "east", +# "south", and "north" here because the tiles aren't necessarily orient- +# ed such that the left boundary segment corresponds to the west edge, +# etc. The widths of these margins (in units of number of cells on tile +# 6) are specified via the parameters +# +# num_margin_cells_T6_left +# num_margin_cells_T6_right +# num_margin_cells_T6_bottom +# num_margin_cells_T6_top +# +# where the "_T6" in these names is used to indicate that the cell count +# is on tile 6, not tile 7. +# +# Note that we must make the margins wide enough (by making the above +# four parameters large enough) such that a region of halo cells around +# the boundary of the regional grid fits into the margins, i.e. such +# that the halo does not overrun the boundary of tile 6. (The halo is +# added later in another script; its function is to feed in boundary +# conditions to the regional grid.) Currently, a halo of 5 regional +# grid cells is used around the regional grid. Setting num_margin_- +# cells_T6_... to at least 10 leaves enough room for this halo. +# +#----------------------------------------------------------------------- +# +#----------------------------------------------------------------------- +# +# The RRFS CONUS domain with ~25km cells. +# +#----------------------------------------------------------------------- +# +"RRFS_CONUS_25km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 25000.0 + ESGgrid_DELY: 25000.0 + ESGgrid_NX: 219 + ESGgrid_NY: 131 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 40 + LAYOUT_X: 5 + LAYOUT_Y: 2 + BLOCKSIZE: 40 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 2 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 217 + WRTCMP_ny: 128 + WRTCMP_lon_lwr_left: -122.719528 + WRTCMP_lat_lwr_left: 21.138123 + WRTCMP_dx: 25000.0 + WRTCMP_dy: 25000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS CONUS domain with ~25km cells that can be initialized from the HRRR. +# +#----------------------------------------------------------------------- +# +"RRFS_CONUScompact_25km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 25000.0 + ESGgrid_DELY: 25000.0 + ESGgrid_NX: 202 + ESGgrid_NY: 116 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 40 + LAYOUT_X: 5 + LAYOUT_Y: 2 + BLOCKSIZE: 40 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 2 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 199 + WRTCMP_ny: 111 + WRTCMP_lon_lwr_left: -121.23349066 + WRTCMP_lat_lwr_left: 23.41731593 + WRTCMP_dx: 25000.0 + WRTCMP_dy: 25000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS CONUS domain with ~13km cells. +# +#----------------------------------------------------------------------- +# +"RRFS_CONUS_13km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 13000.0 + ESGgrid_DELY: 13000.0 + ESGgrid_NX: 420 + ESGgrid_NY: 252 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 45 + LAYOUT_X: 16 + LAYOUT_Y: 10 + BLOCKSIZE: 32 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 10 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 416 + WRTCMP_ny: 245 + WRTCMP_lon_lwr_left: -122.719528 + WRTCMP_lat_lwr_left: 21.138123 + WRTCMP_dx: 13000.0 + WRTCMP_dy: 13000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS CONUS domain with ~13km cells that can be initialized from the HRRR. +# +#----------------------------------------------------------------------- +# +"RRFS_CONUScompact_13km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 13000.0 + ESGgrid_DELY: 13000.0 + ESGgrid_NX: 396 + ESGgrid_NY: 232 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 45 + LAYOUT_X: 16 + LAYOUT_Y: 10 + BLOCKSIZE: 32 + # if QUILTING = TRUE + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 16 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 393 + WRTCMP_ny: 225 + WRTCMP_lon_lwr_left: -121.70231097 + WRTCMP_lat_lwr_left: 22.57417972 + WRTCMP_dx: 13000.0 + WRTCMP_dy: 13000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS CONUS domain with ~3km cells. +# +#----------------------------------------------------------------------- +# +"RRFS_CONUS_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 1820 + ESGgrid_NY: 1092 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 36 + LAYOUT_X: 28 + LAYOUT_Y: 28 + BLOCKSIZE: 29 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 28 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 1799 + WRTCMP_ny: 1059 + WRTCMP_lon_lwr_left: -122.719528 + WRTCMP_lat_lwr_left: 21.138123 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS CONUS domain with ~3km cells that can be initialized from the HRRR. +# +#----------------------------------------------------------------------- +# +"RRFS_CONUScompact_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 1748 + ESGgrid_NY: 1038 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 40 + LAYOUT_X: 30 + LAYOUT_Y: 16 + BLOCKSIZE: 32 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 16 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 1746 + WRTCMP_ny: 1014 + WRTCMP_lon_lwr_left: -122.17364391 + WRTCMP_lat_lwr_left: 21.88588562 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS SUBCONUS domain with ~3km cells. +# +#----------------------------------------------------------------------- +# +"RRFS_SUBCONUS_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 35.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 840 + ESGgrid_NY: 600 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 40 + LAYOUT_X: 30 + LAYOUT_Y: 24 + BLOCKSIZE: 35 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 24 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 35.0 + WRTCMP_stdlat1: 35.0 + WRTCMP_stdlat2: 35.0 + WRTCMP_nx: 837 + WRTCMP_ny: 595 + WRTCMP_lon_lwr_left: -109.97410429 + WRTCMP_lat_lwr_left: 26.31459843 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# A subconus domain over Indianapolis, Indiana with ~3km cells. This is +# mostly for testing on a 3km grid with a much small number of cells than +# on the full CONUS. +# +#----------------------------------------------------------------------- +# +"SUBCONUS_Ind_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -86.16 + ESGgrid_LAT_CTR: 39.77 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 200 + ESGgrid_NY: 200 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 40 + LAYOUT_X: 5 + LAYOUT_Y: 5 + BLOCKSIZE: 40 + #if QUILTING : True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 5 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -86.16 + WRTCMP_cen_lat: 39.77 + WRTCMP_stdlat1: 39.77 + WRTCMP_stdlat2: 39.77 + WRTCMP_nx: 197 + WRTCMP_ny: 197 + WRTCMP_lon_lwr_left: -89.47120417 + WRTCMP_lat_lwr_left: 37.07809642 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS Alaska domain with ~13km cells. +# +# Note: +# This grid has not been thoroughly tested (as of 20201027). +# +#----------------------------------------------------------------------- +# +"RRFS_AK_13km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -161.5 + ESGgrid_LAT_CTR: 63.0 + ESGgrid_DELX: 13000.0 + ESGgrid_DELY: 13000.0 + ESGgrid_NX: 320 + ESGgrid_NY: 240 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 10 + LAYOUT_X: 16 + LAYOUT_Y: 12 + BLOCKSIZE: 40 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 12 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -161.5 + WRTCMP_cen_lat: 63.0 + WRTCMP_stdlat1: 63.0 + WRTCMP_stdlat2: 63.0 + WRTCMP_nx: 318 + WRTCMP_ny: 234 + WRTCMP_lon_lwr_left: 172.23339164 + WRTCMP_lat_lwr_left: 45.77691870 + WRTCMP_dx: 13000.0 + WRTCMP_dy: 13000.0 +# +#----------------------------------------------------------------------- +# +# The RRFS Alaska domain with ~3km cells. +# +# Note: +# This grid has not been thoroughly tested (as of 20201027). +# +#----------------------------------------------------------------------- +# +"RRFS_AK_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -161.5 + ESGgrid_LAT_CTR: 63.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 1380 + ESGgrid_NY: 1020 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 10 + LAYOUT_X: 30 + LAYOUT_Y: 17 + BLOCKSIZE: 40 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 17 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -161.5 + WRTCMP_cen_lat: 63.0 + WRTCMP_stdlat1: 63.0 + WRTCMP_stdlat2: 63.0 + WRTCMP_nx: 1379 + WRTCMP_ny: 1003 + WRTCMP_lon_lwr_left: -187.89737923 + WRTCMP_lat_lwr_left: 45.84576053 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# The WoFS domain with ~3km cells. +# +# Note: +# The WoFS domain will generate a 301 x 301 output grid (WRITE COMPONENT) and +# will eventually be movable (ESGgrid_LON_CTR/ESGgrid_LAT_CTR). A python script +# python_utils/fv3write_parms_lambert will be useful to determine +# WRTCMP_lon_lwr_left and WRTCMP_lat_lwr_left locations (only for Lambert map +# projection currently) of the quilting output when the domain location is +# moved. Later, it should be integrated into the workflow. +# +#----------------------------------------------------------------------- +# +"WoFS_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -97.5 + ESGgrid_LAT_CTR: 38.5 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 361 + ESGgrid_NY: 361 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 20 + LAYOUT_X: 18 + LAYOUT_Y: 12 + BLOCKSIZE: 30 + # if QUILTING = True + WRTCMP_write_groups: "1" + WRTCMP_write_tasks_per_group: 12 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_stdlat1: 38.5 + WRTCMP_stdlat2: 38.5 + WRTCMP_nx: 301 + WRTCMP_ny: 301 + WRTCMP_lon_lwr_left: -102.3802487 + WRTCMP_lat_lwr_left: 34.3407918 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# A CONUS domain of GFDLgrid type with ~25km cells. +# +# Note: +# This grid is larger than the HRRRX domain and thus cannot be initialized +# using the HRRRX. +# +#----------------------------------------------------------------------- +# +"CONUS_25km_GFDLgrid": + GRID_GEN_METHOD: "GFDLgrid" + GFDLgrid_LON_T6_CTR: -97.5 + GFDLgrid_LAT_T6_CTR: 38.5 + GFDLgrid_STRETCH_FAC: 1.4 + GFDLgrid_NUM_CELLS: 96 + GFDLgrid_REFINE_RATIO: 3 + num_margin_cells_T6_left: 12 + GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G: 13 + num_margin_cells_T6_right: 12 + GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G: 84 + num_margin_cells_T6_bottom: 16 + GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G: 17 + num_margin_cells_T6_top: 16 + GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G: 80 + GFDLgrid_USE_NUM_CELLS_IN_FILENAMES: True + DT_ATMOS: 225 + LAYOUT_X: 6 + LAYOUT_Y: 4 + BLOCKSIZE: 36 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 4 + WRTCMP_output_grid: "rotated_latlon" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_lon_lwr_left: -24.40085141 + WRTCMP_lat_lwr_left: -19.65624142 + WRTCMP_lon_upr_rght: 24.40085141 + WRTCMP_lat_upr_rght: 19.65624142 + WRTCMP_dlon: 0.22593381 + WRTCMP_dlat: 0.22593381 +# +#----------------------------------------------------------------------- +# +# A CONUS domain of GFDLgrid type with ~3km cells. +# +# Note: +# This grid is larger than the HRRRX domain and thus cannot be initialized +# using the HRRRX. +# +#----------------------------------------------------------------------- +# +"CONUS_3km_GFDLgrid": + GRID_GEN_METHOD: "GFDLgrid" + GFDLgrid_LON_T6_CTR: -97.5 + GFDLgrid_LAT_T6_CTR: 38.5 + GFDLgrid_STRETCH_FAC: 1.5 + GFDLgrid_NUM_CELLS: 768 + GFDLgrid_REFINE_RATIO: 3 + num_margin_cells_T6_left: 69 + GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G: 70 + num_margin_cells_T6_right: 69 + GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G: 699 + num_margin_cells_T6_bottom: 164 + GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G: 165 + num_margin_cells_T6_top: 164 + GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G: 604 + GFDLgrid_USE_NUM_CELLS_IN_FILENAMES: True + DT_ATMOS: 18 + LAYOUT_X: 30 + LAYOUT_Y: 22 + BLOCKSIZE: 35 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 22 + WRTCMP_output_grid: "rotated_latlon" + WRTCMP_cen_lon: -97.5 + WRTCMP_cen_lat: 38.5 + WRTCMP_lon_lwr_left: -25.23144805 + WRTCMP_lat_lwr_left: -15.82130419 + WRTCMP_lon_upr_rght: 25.23144805 + WRTCMP_lat_upr_rght: 15.82130419 + WRTCMP_dlon: 0.02665763 + WRTCMP_dlat: 0.02665763 +# +#----------------------------------------------------------------------- +# +# EMC's Alaska grid. +# +#----------------------------------------------------------------------- +# +"EMC_AK": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -153.0 + ESGgrid_LAT_CTR: 61.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 1344 # Supergrid value 2704 + ESGgrid_NY: 1152 # Supergrid value 2320 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 18 + LAYOUT_X: 28 + LAYOUT_Y: 16 + BLOCKSIZE: 24 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 24 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -153.0 + WRTCMP_cen_lat: 61.0 + WRTCMP_stdlat1: 61.0 + WRTCMP_stdlat2: 61.0 + WRTCMP_nx: 1344 + WRTCMP_ny: 1152 + WRTCMP_lon_lwr_left: -177.0 + WRTCMP_lat_lwr_left: 42.5 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# EMC's Hawaii grid. +# +#----------------------------------------------------------------------- +# +"EMC_HI": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -157.0 + ESGgrid_LAT_CTR: 20.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 432 # Supergrid value 880 + ESGgrid_NY: 360 # Supergrid value 736 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 18 + LAYOUT_X: 8 + LAYOUT_Y: 8 + BLOCKSIZE: 27 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 8 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -157.0 + WRTCMP_cen_lat: 20.0 + WRTCMP_stdlat1: 20.0 + WRTCMP_stdlat2: 20.0 + WRTCMP_nx: 420 + WRTCMP_ny: 348 + WRTCMP_lon_lwr_left: -162.8 + WRTCMP_lat_lwr_left: 15.2 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# EMC's Puerto Rico grid. +# +#----------------------------------------------------------------------- +# +"EMC_PR": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -69.0 + ESGgrid_LAT_CTR: 18.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 576 # Supergrid value 1168 + ESGgrid_NY: 432 # Supergrid value 880 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 18 + LAYOUT_X: 16 + LAYOUT_Y: 8 + BLOCKSIZE: 24 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 24 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -69.0 + WRTCMP_cen_lat: 18.0 + WRTCMP_stdlat1: 18.0 + WRTCMP_stdlat2: 18.0 + WRTCMP_nx: 576 + WRTCMP_ny: 432 + WRTCMP_lon_lwr_left: -77 + WRTCMP_lat_lwr_left: 12 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# EMC's Guam grid. +# +#----------------------------------------------------------------------- +# +"EMC_GU": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: 146.0 + ESGgrid_LAT_CTR: 15.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 432 # Supergrid value 880 + ESGgrid_NY: 360 # Supergrid value 736 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 18 + LAYOUT_X: 16 + LAYOUT_Y: 12 + BLOCKSIZE: 27 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 24 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: 146.0 + WRTCMP_cen_lat: 15.0 + WRTCMP_stdlat1: 15.0 + WRTCMP_stdlat2: 15.0 + WRTCMP_nx: 420 + WRTCMP_ny: 348 + WRTCMP_lon_lwr_left: 140 + WRTCMP_lat_lwr_left: 10 + WRTCMP_dx: 3000.0 + WRTCMP_dy: 3000.0 +# +#----------------------------------------------------------------------- +# +# Emulation of the HAFS v0.A grid at 25 km. +# +#----------------------------------------------------------------------- +# +"GSL_HAFSV0.A_25km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -62.0 + ESGgrid_LAT_CTR: 22.0 + ESGgrid_DELX: 25000.0 + ESGgrid_DELY: 25000.0 + ESGgrid_NX: 345 + ESGgrid_NY: 230 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 300 + LAYOUT_X: 5 + LAYOUT_Y: 5 + BLOCKSIZE: 6 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 32 + WRTCMP_output_grid: "regional_latlon" + WRTCMP_cen_lon: -62.0 + WRTCMP_cen_lat: 25.0 + WRTCMP_lon_lwr_left: -114.5 + WRTCMP_lat_lwr_left: -5.0 + WRTCMP_lon_upr_rght: -9.5 + WRTCMP_lat_upr_rght: 55.0 + WRTCMP_dlon: 0.25 + WRTCMP_dlat: 0.25 +# +#----------------------------------------------------------------------- +# +# Emulation of the HAFS v0.A grid at 13 km. +# +#----------------------------------------------------------------------- +# +"GSL_HAFSV0.A_13km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -62.0 + ESGgrid_LAT_CTR: 22.0 + ESGgrid_DELX: 13000.0 + ESGgrid_DELY: 13000.0 + ESGgrid_NX: 665 + ESGgrid_NY: 444 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 180 + LAYOUT_X: 19 + LAYOUT_Y: 12 + BLOCKSIZE: 35 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 32 + WRTCMP_output_grid: "regional_latlon" + WRTCMP_cen_lon: -62.0 + WRTCMP_cen_lat: 25.0 + WRTCMP_lon_lwr_left: -114.5 + WRTCMP_lat_lwr_left: -5.0 + WRTCMP_lon_upr_rght: -9.5 + WRTCMP_lat_upr_rght: 55.0 + WRTCMP_dlon: 0.13 + WRTCMP_dlat: 0.13 +# +#----------------------------------------------------------------------- +# +# Emulation of the HAFS v0.A grid at 3 km. +# +#----------------------------------------------------------------------- +# +"GSL_HAFSV0.A_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -62.0 + ESGgrid_LAT_CTR: 22.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 2880 + ESGgrid_NY: 1920 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 40 + LAYOUT_X: 32 + LAYOUT_Y: 24 + BLOCKSIZE: 32 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 32 + WRTCMP_output_grid: "regional_latlon" + WRTCMP_cen_lon: -62.0 + WRTCMP_cen_lat: 25.0 + WRTCMP_lon_lwr_left: -114.5 + WRTCMP_lat_lwr_left: -5.0 + WRTCMP_lon_upr_rght: -9.5 + WRTCMP_lat_upr_rght: 55.0 + WRTCMP_dlon: 0.03 + WRTCMP_dlat: 0.03 +# +#----------------------------------------------------------------------- +# +# 50-km HRRR Alaska grid. +# +#----------------------------------------------------------------------- +# +"GSD_HRRR_AK_50km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -163.5 + ESGgrid_LAT_CTR: 62.8 + ESGgrid_DELX: 50000.0 + ESGgrid_DELY: 50000.0 + ESGgrid_NX: 74 + ESGgrid_NY: 51 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 600 + LAYOUT_X: 2 + LAYOUT_Y: 3 + BLOCKSIZE: 37 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 1 + WRTCMP_output_grid: "lambert_conformal" + WRTCMP_cen_lon: -163.5 + WRTCMP_cen_lat: 62.8 + WRTCMP_stdlat1: 62.8 + WRTCMP_stdlat2: 62.8 + WRTCMP_nx: 70 + WRTCMP_ny: 45 + WRTCMP_lon_lwr_left: 172.0 + WRTCMP_lat_lwr_left: 49.0 + WRTCMP_dx: 50000.0 + WRTCMP_dy: 50000.0 +# +#----------------------------------------------------------------------- +# +# Emulation of GSD's RAP domain with ~13km cell size. +# +#----------------------------------------------------------------------- +# +"RRFS_NA_13km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -112.5 + ESGgrid_LAT_CTR: 55.0 + ESGgrid_DELX: 13000.0 + ESGgrid_DELY: 13000.0 + ESGgrid_NX: 912 + ESGgrid_NY: 623 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 50 + LAYOUT_X: 16 + LAYOUT_Y: 16 + BLOCKSIZE: 30 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 16 + WRTCMP_output_grid: "rotated_latlon" + WRTCMP_cen_lon: -113.0 + WRTCMP_cen_lat: 55.0 + WRTCMP_lon_lwr_left: -61.0 + WRTCMP_lat_lwr_left: -37.0 + WRTCMP_lon_upr_rght: 61.0 + WRTCMP_lat_upr_rght: 37.0 + WRTCMP_dlon: 0.1169081 + WRTCMP_dlat: 0.1169081 +# +#----------------------------------------------------------------------- +# +# Future operational RRFS domain with ~3km cell size. +# +#----------------------------------------------------------------------- +# +"RRFS_NA_3km": + GRID_GEN_METHOD: "ESGgrid" + ESGgrid_LON_CTR: -112.5 + ESGgrid_LAT_CTR: 55.0 + ESGgrid_DELX: 3000.0 + ESGgrid_DELY: 3000.0 + ESGgrid_NX: 3950 + ESGgrid_NY: 2700 + ESGgrid_PAZI: 0.0 + ESGgrid_WIDE_HALO_WIDTH: 6 + DT_ATMOS: 36 + LAYOUT_X: 20 # 40 - EMC operational configuration + LAYOUT_Y: 35 # 45 - EMC operational configuration + BLOCKSIZE: 28 + #if QUILTING = True + WRTCMP_write_groups: 1 + WRTCMP_write_tasks_per_group: 144 + WRTCMP_output_grid: "rotated_latlon" + WRTCMP_cen_lon: -113.0 + WRTCMP_cen_lat: 55.0 + WRTCMP_lon_lwr_left: -61.0 + WRTCMP_lat_lwr_left: -37.0 + WRTCMP_lon_upr_rght: 61.0 + WRTCMP_lat_upr_rght: 37.0 + WRTCMP_dlon: 0.025 + WRTCMP_dlat: 0.025 + diff --git a/ush/python_utils/__init__.py b/ush/python_utils/__init__.py new file mode 100644 index 0000000000..3aa90e1549 --- /dev/null +++ b/ush/python_utils/__init__.py @@ -0,0 +1,25 @@ +try: + from .misc import uppercase, lowercase, find_pattern_in_str, find_pattern_in_file, flatten_dict + from .check_for_preexist_dir_file import check_for_preexist_dir_file + from .check_var_valid_value import check_var_valid_value + from .count_files import count_files + from .create_symlink_to_file import create_symlink_to_file + from .define_macos_utilities import define_macos_utilities + from .environment import str_to_date, date_to_str, str_to_type, type_to_str, list_to_str, \ + str_to_list, set_env_var, get_env_var, import_vars, export_vars + from .filesys_cmds_vrfy import cmd_vrfy, cp_vrfy, mv_vrfy, rm_vrfy, ln_vrfy, mkdir_vrfy, cd_vrfy + from .get_elem_inds import get_elem_inds + from .interpol_to_arbit_CRES import interpol_to_arbit_CRES + from .print_input_args import print_input_args + from .print_msg import print_info_msg, print_err_msg_exit + from .process_args import process_args + from .run_command import run_command + from .get_charvar_from_netcdf import get_charvar_from_netcdf + from .xml_parser import load_xml_file, has_tag_with_value + from .config_parser import load_shell_config, cfg_to_shell_str, \ + load_json_config, cfg_to_json_str, \ + load_ini_config, cfg_to_ini_str, \ + get_ini_value, load_config_file, \ + load_yaml_config, cfg_to_yaml_str +except: + pass diff --git a/ush/python_utils/check_for_preexist_dir_file.py b/ush/python_utils/check_for_preexist_dir_file.py new file mode 100644 index 0000000000..97c709cf0f --- /dev/null +++ b/ush/python_utils/check_for_preexist_dir_file.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import os +from datetime import datetime +from .print_msg import print_info_msg, print_err_msg_exit +from .check_var_valid_value import check_var_valid_value +from .filesys_cmds_vrfy import rm_vrfy, mv_vrfy + +def check_for_preexist_dir_file(path, method): + """ Check for a preexisting directory or file and, if present, deal with it + according to the specified method + + Args: + path: path to directory + method: could be any of [ 'delete', 'rename', 'quit' ] + Returns: + None + """ + + check_var_valid_value(method, ['delete', 'rename', 'quit']) + + if os.path.exists(path): + if method == 'delete': + rm_vrfy(' -rf ', path) + elif method == 'rename': + now = datetime.now() + d = now.strftime("_old_%Y%m%d_%H%M%S") + new_path = path + d + print_info_msg(f''' + Specified directory or file already exists: + {path} + Moving (renaming) preexisting directory or file to: + {new_path}''') + mv_vrfy(path, new_path) + else: + print_err_msg_exit(f''' + Specified directory or file already exists + {path}''') + diff --git a/ush/python_utils/check_var_valid_value.py b/ush/python_utils/check_var_valid_value.py new file mode 100644 index 0000000000..0a033b7249 --- /dev/null +++ b/ush/python_utils/check_var_valid_value.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +from .print_msg import print_err_msg_exit + +def check_var_valid_value(var, values, err_msg=None): + """ Check if specified variable has a valid value + + Args: + var: the variable + values: list of valid values + err_msg: additional error message to print + Returns: + True: if var has valid value, exit(1) otherwise + """ + + if var not in values: + if err_msg is not None: + err_msg = f'The value specified in var = {var} is not supported.' + print_err_msg_exit(err_msg + f'{var} must be set to one of the following:\n {values}') + return True + diff --git a/ush/python_utils/config_parser.py b/ush/python_utils/config_parser.py new file mode 100644 index 0000000000..b343551bfd --- /dev/null +++ b/ush/python_utils/config_parser.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 + + +""" +This file provides utilities for processing different configuration file formats. +Supported formats include: + a) YAML + b) JSON + c) SHELL + d) INI + +Typical usage involves first loading the config file, then using the dictionary +returnded by load_config to make queries. +""" + +import argparse +try: + import yaml +except: + pass +import json +import sys +import os +from textwrap import dedent +import configparser + +from .environment import list_to_str, str_to_list +from .print_msg import print_err_msg_exit +from .run_command import run_command + +########## +# YAML +########## +def load_yaml_config(config_file): + """ Safe load a yaml file """ + + try: + with open(config_file,'r') as f: + cfg = yaml.safe_load(f) + except yaml.YAMLError as e: + print_err_msg_exit(e) + + return cfg + +def cfg_to_yaml_str(cfg): + """ Get contents of config file as a yaml string """ + + return yaml.dump(cfg, sort_keys=False, default_flow_style=False) + +def join_str(loader, node): + """ Custom tag hangler to join strings """ + seq = loader.construct_sequence(node) + return ''.join([str(i) for i in seq]) + +try: + yaml.add_constructor('!join_str', join_str, Loader=yaml.SafeLoader) +except: + pass + +########## +# JSON +########## +def load_json_config(config_file): + """ Load json config file """ + + try: + with open(config_file,'r') as f: + cfg = json.load(f) + except: + print_err_msg_exit(e) + + return cfg + +def cfg_to_json_str(cfg): + """ Get contents of config file as a json string """ + + return json.dumps(cfg, sort_keys=False, indent=4) + +########## +# SHELL +########## +def load_shell_config(config_file): + """ Loads old style shell config files. + We source the config script in a subshell and gets the variables it sets + + Args: + config_file: path to config file script + Returns: + dictionary that should be equivalent to one obtained from parsing a yaml file. + """ + + # Save env vars before and after sourcing the scipt and then + # do a diff to get variables specifically defined/updated in the script + # Method sounds brittle but seems to work ok so far + pid = os.getpid() + code = dedent(f''' #!/bin/bash + t1="./t1.{pid}" + t2="./t2.{pid}" + (set -o posix; set) > $t1 + {{ . {config_file}; set +x; }} &>/dev/null + (set -o posix; set) > $t2 + diff $t1 $t2 | grep "> " | cut -c 3- + rm -rf $t1 $t2 + ''') + (_,config_str,_) = run_command(code) + lines = config_str.splitlines() + + #build the dictionary + cfg = {} + for l in lines: + idx = l.find("=") + k = l[:idx] + v = str_to_list(l[idx+1:]) + cfg[k] = v + return cfg + +def cfg_to_shell_str(cfg): + """ Get contents of config file as shell script string""" + + shell_str = '' + for k,v in cfg.items(): + if isinstance(v,dict): + shell_str += f"# [{k}]\n" + shell_str += cfg_to_shell_str(v) + shell_str += "\n" + continue + v1 = list_to_str(v) + if isinstance(v,list): + shell_str += f'{k}={v1}\n' + else: + shell_str += f"{k}='{v1}'\n" + return shell_str + +########## +# INI +########## +def load_ini_config(config_file): + """ Load a config file with a format similar to Microsoft's INI files""" + + if not os.path.exists(config_file): + print_err_msg_exit(f''' + The specified configuration file does not exist: + \"{config_file}\"''') + + config = configparser.ConfigParser() + config.read(config_file) + config_dict = {s:dict(config.items(s)) for s in config.sections()} + return config_dict + +def get_ini_value(config, section, key): + """ Finds the value of a property in a given section""" + + if not section in config: + print_err_msg_exit(f''' + Section not found: + section = \"{section}\" + valid sections = \"{config.keys()}\"''') + else: + return config[section][key] + + return None + +def cfg_to_ini_str(cfg): + """ Get contents of config file as ini string""" + + ini_str = '' + for k,v in cfg.items(): + if isinstance(v,dict): + ini_str += f"[{k}]\n" + ini_str += cfg_to_ini_str(v) + ini_str += "\n" + continue + v1 = list_to_str(v) + if isinstance(v,list): + ini_str += f'{k}={v1}\n' + else: + ini_str += f"{k}='{v1}'\n" + return ini_str + +################## +# CONFIG loader +################## +def load_config_file(file_name): + """ Load config file based on file name extension """ + + ext = os.path.splitext(file_name)[1][1:] + if ext == "sh": + return load_shell_config(file_name) + elif ext == "cfg": + return load_ini_config(file_name) + elif ext == "json": + return load_json_config(file_name) + else: + return load_yaml_config(file_name) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description=\ + 'Prints contents of config file.') + parser.add_argument('--cfg','-c',dest='cfg',required=True, + help='config file to parse') + parser.add_argument('--output-type','-o',dest='out_type',required=False, + help='output format: can be any of ["shell", "yaml", "ini", "json"]') + + args = parser.parse_args() + cfg = load_config_file(args.cfg) + + if args.out_type == 'shell': + print( cfg_to_shell_str(cfg) ) + elif args.out_type == 'ini': + print( cfg_to_ini_str(cfg) ) + elif args.out_type == 'json': + print( cfg_to_json_str(cfg) ) + else: + print( cfg_to_yaml_str(cfg) ) + diff --git a/ush/python_utils/count_files.py b/ush/python_utils/count_files.py new file mode 100644 index 0000000000..2239bf7eab --- /dev/null +++ b/ush/python_utils/count_files.py @@ -0,0 +1,16 @@ +import glob + +def count_files(ext,dirct='.'): + """ Function that returns the number of files in the specified directory + ending with the specified file extension + + Args: + ext: File extension string + dir: Directory to parse (default is current directory) + Returns: + int: Number of files + """ + + files = glob.glob(dirct + '/*.' + ext) + return len(files) + diff --git a/ush/python_utils/create_symlink_to_file.py b/ush/python_utils/create_symlink_to_file.py new file mode 100644 index 0000000000..1d078c9a8b --- /dev/null +++ b/ush/python_utils/create_symlink_to_file.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + +import os + +from .process_args import process_args +from .print_input_args import print_input_args +from .print_msg import print_err_msg_exit +from .check_var_valid_value import check_var_valid_value +from .filesys_cmds_vrfy import ln_vrfy + +def create_symlink_to_file(target,symlink,relative=True): + """ Create a symbolic link to the specified target file. + + Args: + target: target file + symlink: symbolic link to target file + relative: optional argument to specify relative symoblic link creation + Returns: + None + """ + + print_input_args(locals()) + + if target is None: + print_err_msg_exit(f''' + The argument \"target\" specifying the target of the symbolic link that + this function will create was not specified in the call to this function: + target = \"{target}\"''') + + if symlink is None: + print_err_msg_exit(f''' + The argument \"symlink\" specifying the target of the symbolic link that + this function will create was not specified in the call to this function: + symlink = \"{symlink}\"''') + + if not os.path.exists(target): + print_err_msg_exit(f''' + Cannot create symlink to specified target file because the latter does + not exist or is not a file: + target = \"{target}\"''') + + relative_flag="" + if relative: + RELATIVE_LINK_FLAG = os.getenv('RELATIVE_LINK_FLAG') + if RELATIVE_LINK_FLAG is not None: + relative_flag=f'{RELATIVE_LINK_FLAG}' + + ln_vrfy(f'-sf {relative_flag} {target} {symlink}') + diff --git a/ush/python_utils/define_macos_utilities.py b/ush/python_utils/define_macos_utilities.py new file mode 100644 index 0000000000..2bf996b996 --- /dev/null +++ b/ush/python_utils/define_macos_utilities.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import os + +from .print_msg import print_err_msg_exit +from .run_command import run_command +from .environment import set_env_var + +def check_darwin(cmd): + """ Check if darwin command exists """ + + (err,_,_) = run_command(f'command -v {cmd}') + if err != 0: + print_err_msg_exit(f''' + For Darwin-based operating systems (MacOS), the '{cmd}' utility is required to run the UFS SRW Application. + Reference the User's Guide for more information about platform requirements. + Aborting.''') + return True + +def define_macos_utilities(): + """ Set some environment variables for Darwin systems differently + The variables are: READLINK, SED, DATE_UTIL and LN_UTIL + """ + + if os.uname()[0] == 'Darwin': + if check_darwin('greadlink'): + set_env_var('READLINK','greadlink') + if check_darwin('gsed'): + set_env_var('SED','gsed') + if check_darwin('gdate'): + set_env_var('DATE_UTIL','gdate') + if check_darwin('gln'): + set_env_var('LN_UTIL','gln') + else: + set_env_var('READLINK','readlink') + set_env_var('SED','sed') + set_env_var('DATE_UTIL','date') + set_env_var('LN_UTIL','ln') + diff --git a/ush/python_utils/environment.py b/ush/python_utils/environment.py new file mode 100644 index 0000000000..2dc6bfbd7c --- /dev/null +++ b/ush/python_utils/environment.py @@ -0,0 +1,250 @@ +#!/usr/bin/env python3 + +import os +import inspect +import shlex +from datetime import datetime, date +from types import ModuleType + +def str_to_date(s): + """ Get python datetime object from string. + + Args: + s: a string + Returns: + datetime object or None + """ + v = None + try: + l = len(s) + if l == 8: + v = datetime.strptime(s, "%Y%m%d") + if l == 10: + v = datetime.strptime(s, "%Y%m%d%H") + elif l == 12: + v = datetime.strptime(s, "%Y%m%d%H%M") + elif l == 14: + v = datetime.strptime(s, "%Y%m%d%H%M%S") + except: + v = None + return v + +def date_to_str(d, format="%Y%m%d%H%M"): + """ Get string from python datetime object. + By default it converts to YYYYMMDDHHMM format unless + told otherwise by passing a different format + + Args: + d: datetime object + Returns: + string in YYYYMMDDHHMM or shorter version of it + """ + v = d.strftime(format) + return v + +def str_to_type(s, just_get_me_the_string = False): + """ Check if the string contains a float, int, boolean, or just regular string. + This will be used to automatically convert environment variables to data types + that are more convenient to work with. If you don't want this functionality, + pass just_get_me_the_string = True + + Args: + s: a string + just_get_me_the_string: Set to True to return the string itself + Returns: + a float, int, boolean, date, or the string itself when all else fails + """ + s = s.strip('"\'') + if not just_get_me_the_string: + if s.lower() in ['true','yes','yeah']: + return True + elif s.lower() in ['false','no','nope']: + return False + v = str_to_date(s) + if v is not None: + return v + if s.isnumeric(): + return int(s) + try: + v = float(s) + return v + except: + pass + return s + +def type_to_str(v): + """ Given a float/int/boolean/date or list of these types, gets a string + representing their values + + Args: + v: a variable of the above types + Returns: + a string + """ + if isinstance(v,bool): + return ("TRUE" if v else "FALSE") + elif isinstance(v,int) or isinstance(v,float): + pass + elif isinstance(v,date): + return date_to_str(v) + elif v is None: + return '' + return str(v) + +def list_to_str(v, oneline=False): + """ Given a string or list of string, construct a string + to be used on right hand side of shell environement variables + + Args: + v: a string/number, list of strings/numbers, or null string('') + Returns: + A string + """ + if isinstance(v,str): + return v + if isinstance(v, list): + v = [type_to_str(i) for i in v] + if oneline or len(v) <= 4: + shell_str = f'( "' + '" "'.join(v) + '" )' + else: + shell_str = f'( \\\n"' + '" \\\n"'.join(v) + '" \\\n)' + else: + shell_str = f'{type_to_str(v)}' + + return shell_str + +def str_to_list(v): + """ Given a string, construct a string or list of strings. + Basically does the reverse operation of `list_to_string`. + + Args: + v: a string + Returns: + a string, list of strings or null string('') + """ + + if not isinstance(v,str): + return v + v = v.strip() + if not v: + return None + if v[0] == '(' and v[-1] == ')': + v = v[1:-1] + tokens = shlex.split(v) + lst = [] + for itm in tokens: + itm = itm.strip() + if itm == '': + continue + # bash arrays could be stored with indices ([0]=hello ...) + if "=" in itm: + idx = itm.find("=") + itm = itm[idx+1:] + lst.append(str_to_type(itm)) + return lst + else: + return str_to_type(v) + +def set_env_var(param,value): + """ Set an environment variable + + Args: + param: the variable to set + value: either a string, list of strings or None + Returns: + None + """ + + os.environ[param] = list_to_str(value) + +def get_env_var(param): + """ Get the value of an environement variable + + Args: + param: the environement variable + Returns: + Returns either a string, list of strings or None + """ + + if not param in os.environ: + return None + else: + value = os.environ[param] + return str_to_list(value) + +def import_vars(dictionary=None, target_dict=None, env_vars=None): + """ Import all (or select few) environment/dictionary variables as python global + variables of the caller module. Call this function at the beginning of a function + that uses environment variables. + + Note that for read-only environmental variables, calling this function once at the + beginning should be enough. However, if the variable is modified in the module it is + called from, the variable should be explicitly tagged as `global`, and then its value + should be exported back to the environment with a call to export_vars() + + import_vars() # import all environment variables + global MY_VAR, MY_LIST_VAR + MY_PATH = "/path/to/somewhere" + MY_LIST_VAR.append("Hello") + export_vars() # these exports all global variables + + There doesn't seem to an easier way of imitating the shell script doing way of things, which + assumes that everything is global unless specifically tagged local, while the opposite is true + for python. + + Args: + dictionary: source dictionary (default=os.environ) + target_dict: target dictionary (default=caller module's globals()) + env_vars: list of selected environement/dictionary variables to import, or None, + in which case all environment/dictionary variables are imported + Returns: + None + """ + if dictionary is None: + dictionary = os.environ + + if target_dict is None: + target_dict = inspect.stack()[1][0].f_globals + + if env_vars is None: + env_vars = dictionary + else: + env_vars = { k: dictionary[k] if k in dictionary else None for k in env_vars } + + for k,v in env_vars.items(): + target_dict[k] = str_to_list(v) + +def export_vars(dictionary=None, source_dict=None, env_vars=None): + """ Export all (or select few) global variables of the caller module's + to either the environement/dictionary. Call this function at the end of + a function that updates environment variables. + + Args: + dictionary: target dictionary to set (default=os.environ) + source_dict: source dictionary (default=caller modules globals()) + env_vars: list of selected environement/dictionary variables to export, or None, + in which case all environment/dictionary variables are exported + Returns: + None + """ + if dictionary is None: + dictionary = os.environ + + if source_dict is None: + source_dict = inspect.stack()[1][0].f_globals + + if env_vars is None: + env_vars = source_dict + else: + env_vars = { k: source_dict[k] if k in source_dict else None for k in env_vars } + + for k,v in env_vars.items(): + # skip functions and other unlikely variable names + if callable(v): + continue + if isinstance(v,ModuleType): + continue + if not k or k[0] == '_': + continue + dictionary[k] = list_to_str(v) + diff --git a/ush/python_utils/filesys_cmds_vrfy.py b/ush/python_utils/filesys_cmds_vrfy.py new file mode 100644 index 0000000000..67f1f45f9c --- /dev/null +++ b/ush/python_utils/filesys_cmds_vrfy.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +import os +from .print_msg import print_err_msg_exit + +def cmd_vrfy(cmd, *args): + """ Execute system command + + Args: + cmd: the command + *args: its arguments + Returns: + Exit code + """ + + for a in args: + cmd += ' ' + str(a) + ret = os.system(cmd) + if ret != 0: + print_err_msg_exit(f'System call "{cmd}" failed.') + return ret + +def cp_vrfy(*args): + return cmd_vrfy('cp', *args) +def mv_vrfy(*args): + return cmd_vrfy('mv', *args) +def rm_vrfy(*args): + return cmd_vrfy('rm', *args) +def ln_vrfy(*args): + return cmd_vrfy('ln', *args) +def mkdir_vrfy(*args): + return cmd_vrfy('mkdir', *args) +def cd_vrfy(*args): + return os.chdir(*args) + diff --git a/ush/python_utils/fv3write_parms_lambert.py b/ush/python_utils/fv3write_parms_lambert.py new file mode 100755 index 0000000000..18b4a8f359 --- /dev/null +++ b/ush/python_utils/fv3write_parms_lambert.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# To use this tool, you should source the regional workflow environment +# $> source env/wflow_xxx.env +# and activate pygraf (or any one with cartopy installation) +# $> conda activate pygraf +# + +import argparse + +import cartopy.crs as ccrs + +#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +# +# Main function to return parameters for the FV3 write component. +# + +if __name__ == "__main__": + + parser = argparse.ArgumentParser(description='Determine FV3 write component lat1/lon1 for Lamert Conformal map projection', + epilog=''' ---- Yunheng Wang (2021-07-15). + ''') + #formatter_class=CustomFormatter) + parser.add_argument('-v','--verbose', help='Verbose output', action="store_true") + parser.add_argument('-ca','--ctrlat', help='Lambert Conformal central latitude', type=float, default=38.5 ) + parser.add_argument('-co','--ctrlon', help='Lambert Conformal central longitude', type=float, default=-97.5 ) + parser.add_argument('-s1','--stdlat1',help='Lambert Conformal standard latitude1', type=float, default=38.5 ) + parser.add_argument('-s2','--stdlat2',help='Lambert Conformal standard latitude2', type=float, default=38.5 ) + parser.add_argument('-nx', help='number of grid in X direction', type=int, default=301 ) + parser.add_argument('-ny' ,help='number of grid in Y direction', type=int, default=301 ) + parser.add_argument('-dx' ,help='grid resolution in X direction (meter)',type=float, default=3000.0) + parser.add_argument('-dy' ,help='grid resolution in Y direction (meter)',type=float, default=3000.0) + + args = parser.parse_args() + + if args.verbose: + print("Write component Lambert Conformal Parameters:") + print(f" cen_lat = {args.ctrlat}, cen_lon = {args.ctrlon}, stdlat1 = {args.stdlat1}, stdlat2 = {args.stdlat2}") + print(f" nx = {args.nx}, ny = {args.ny}, dx = {args.dx}, dy = {args.dy}") + + #----------------------------------------------------------------------- + # + # Lambert grid + # + #----------------------------------------------------------------------- + + nx1 = args.nx + ny1 = args.ny + dx1 = args.dx + dy1 = args.dy + + ctrlat = args.ctrlat + ctrlon = args.ctrlon + + xctr = (nx1-1)/2*dx1 + yctr = (ny1-1)/2*dy1 + + carr= ccrs.PlateCarree() + + proj1=ccrs.LambertConformal(central_longitude=ctrlon, central_latitude=ctrlat, + false_easting=xctr, false_northing= yctr, secant_latitudes=None, + standard_parallels=(args.stdlat1, args.stdlat2), globe=None) + + lonlat1 = carr.transform_point(0.0,0.0,proj1) + + if args.verbose: + print() + print(f' lat1 = {lonlat1[1]}, lon1 = {lonlat1[0]}') + print('\n') + + #----------------------------------------------------------------------- + # + # Output write component parameters + # + #----------------------------------------------------------------------- + + print() + print("output_grid: 'lambert_conformal'") + print(f"cen_lat: {args.ctrlat}") + print(f"cen_lon: {args.ctrlon}") + print(f"stdlat1: {args.stdlat1}") + print(f"stdlat2: {args.stdlat2}") + print(f"nx: {args.nx}") + print(f"ny: {args.ny}") + print(f"dx: {args.dx}") + print(f"dy: {args.dy}") + print(f"lat1: {lonlat1[1]}") + print(f"lon1: {lonlat1[0]}") + print() + + # End of program diff --git a/ush/python_utils/get_charvar_from_netcdf.py b/ush/python_utils/get_charvar_from_netcdf.py new file mode 100644 index 0000000000..c85e42e358 --- /dev/null +++ b/ush/python_utils/get_charvar_from_netcdf.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 + +import os +from .print_msg import print_err_msg_exit +from .run_command import run_command + +def get_charvar_from_netcdf(nc_file, nc_var_name): + """ Searches NetCDF file and extract a scalar variable + + Args: + nc_file: Path to netCDF file + nc_var_name: name of the scalar variable + Returns: + value of the variable + """ + + SED = os.getenv('SED') + + cmd = f"ncdump -v {nc_var_name} {nc_file} | \ + {SED} -r -e '1,/data:/d' \ + -e '/^[ ]*'{nc_var_name}'/d' \ + -e '/^}}$/d' \ + -e 's/.*\"(.*)\".*/\\1/' \ + -e '/^$/d' \ + " + (ret,nc_var_value,_) = run_command(cmd) + + if ret != 0: + print_err_msg_exit(f''' + Attempt to extract the value of the NetCDF variable spcecified by nc_var_name + from the file specified by nc_file failed: + nc_file = \"{nc_file}\" + nc_var_name = \"{nc_var_name}\"''') + + if nc_var_value is None: + print_err_msg_exit(f''' + In the specified NetCDF file (nc_file), the specified variable (nc_var_name) + was not found: + nc_file = \"{nc_file}\" + nc_var_name = \"{nc_var_name}\" + nc_var_value = \"{nc_var_value}\"''') + + return nc_var_value + diff --git a/ush/python_utils/get_elem_inds.py b/ush/python_utils/get_elem_inds.py new file mode 100644 index 0000000000..08cbfbff70 --- /dev/null +++ b/ush/python_utils/get_elem_inds.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +from .misc import lowercase +from .check_var_valid_value import check_var_valid_value + +def get_elem_inds(arr, match, ret_type): + """ Function that returns indices of elements of array + that match a given string + + Args: + arr: the list + match: element to match (case insenensitive) + ret_type: the return type can be any of [ 'first', 'last', 'all' ] + Returns: + A list of indices + """ + ret_type = lowercase(ret_type) + check_var_valid_value(ret_type, ['first', 'last', 'all']) + + if ret_type == 'first': + for i,e in enumerate(arr): + if e == match: + return i + elif ret_type == 'last': + for i in range(len(arr)-1, -1, -1): + if arr[i] == match: + return i + else: + return [i for i,e in enumerate(arr) if e == match] + diff --git a/ush/python_utils/interpol_to_arbit_CRES.py b/ush/python_utils/interpol_to_arbit_CRES.py new file mode 100644 index 0000000000..f6ec889b24 --- /dev/null +++ b/ush/python_utils/interpol_to_arbit_CRES.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 + +def interpol_to_arbit_CRES(RES, RES_array, prop_array): + """ Function to interpolate (or extrapolate) a grid cell size-dependent property + to an arbitrary cubed-sphere resolution using arrays that specify a set of property + values for a corresponding set of resolutions + + Args: + RES: The cubed-sphere resolution at which to find the value of a property. + This is in units of number of cells (in either of the two horizontal + directions) on any one of the tiles of a cubed-sphere grid. + + RES_array: The name of the array containing the cubed-sphere resolutions for + which corresponding property values are given (in prop_array). These + are assumed to be given from smallest to largest. + + prop_array: The name of the array containing the values of the property corres- + ponding to the cubed-sphere resolutions in RES_array. + Returns: + Interpolated (extrapolated) property value + """ + + num_valid_RESes = len(RES_array) + i_min = 0 + i_max = num_valid_RESes - 1 + + if RES <= RES_array[i_min]: + prop = prop_array[i_min] + elif RES > RES_array[i_max]: + prop = prop_array[i_max] + else: + for i in range(0,num_valid_RESes-1): + if RES > RES_array[i] and RES <= RES_array[i+1]: + RES1 = RES_array[i] + RES2 = RES_array[i+1] + prop1 = prop_array[i] + prop2 = prop_array[i+1] + m_slope = (prop2 - prop1) / (RES2 - RES1) + y_intcpt = (RES2 * prop1 - RES1 * prop2) / (RES2 - RES1) + prop = m_slope * RES + y_intcpt + + return prop + diff --git a/ush/python_utils/misc.py b/ush/python_utils/misc.py new file mode 100644 index 0000000000..c299e02735 --- /dev/null +++ b/ush/python_utils/misc.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import re + +def uppercase(str): + """ Function to convert a given string to uppercase + + Args: + str: the string + Return: + Uppercased str + """ + + return str.upper() + + +def lowercase(str): + """ Function to convert a given string to lowercase + + Args: + str: the string + Return: + Lowercase str + """ + + return str.lower() + +def find_pattern_in_str(pattern, source): + """ Find regex pattern in a string + + Args: + pattern: regex expression + source: string + Return: + A tuple of matched groups or None + """ + pattern = re.compile(pattern) + for match in re.finditer(pattern,source): + return match.groups() + return None + +def find_pattern_in_file(pattern, file_name): + """ Find regex pattern in a file + + Args: + pattern: regex expression + file_name: name of text file + Return: + A tuple of matched groups or None + """ + pattern = re.compile(pattern) + with open(file_name) as f: + for line in f: + for match in re.finditer(pattern,line): + return match.groups() + return None + +def flatten_dict(dictionary,keys=None): + """ Faltten a recursive dictionary (e.g.yaml/json) to be one level deep + Args: + dictionary: the source dictionary + keys: list of keys on top level whose contents to flatten, if None all of them + Returns: + A one-level deep dictionary for the selected set of keys + """ + flat_dict = {} + for k,v in dictionary.items(): + if not keys or k in keys: + if isinstance(v,dict): + r = flatten_dict(v) + flat_dict.update(r) + else: + flat_dict[k] = v + return flat_dict + diff --git a/ush/python_utils/print_input_args.py b/ush/python_utils/print_input_args.py new file mode 100644 index 0000000000..25d979eae9 --- /dev/null +++ b/ush/python_utils/print_input_args.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 + +import os +import inspect +from textwrap import dedent + +from .misc import lowercase +from .print_msg import print_info_msg +from .environment import import_vars + +def print_input_args(valid_args): + """ Prints function arguments for debugging purposes + + Args: + valid_args: dictionary of arg-value pairs + Returns: + Number of printed arguments + """ + + # get verbosity from environment + IMPORTS = ["DEBUG"] + import_vars(env_vars=IMPORTS) + + if list(valid_args.keys())[0] == '__unset__': + valid_arg_names = {} + else: + valid_arg_names = valid_args + num_valid_args = len(valid_arg_names) + + filename = inspect.stack()[1].filename + function = inspect.stack()[1].function + filename_base = os.path.basename(filename) + + if num_valid_args == 0: + msg = dedent(f''' + No arguments have been passed to function {function} in script {filename_base} located + + \"{filename}\"''') + else: + msg = dedent(f''' + The arguments to function {function} in script {filename_base} located + + \"{filename}\" + + have been set as follows:\n\n''') + + for k,v in valid_arg_names.items(): + msg = msg + f' {k}="{v}"\n' + + print_info_msg(msg,verbose=DEBUG) + return num_valid_args + diff --git a/ush/python_utils/print_msg.py b/ush/python_utils/print_msg.py new file mode 100644 index 0000000000..75858e5613 --- /dev/null +++ b/ush/python_utils/print_msg.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 + +import traceback +import sys +from textwrap import dedent + +def print_err_msg_exit(error_msg="",stack_trace=True): + """Function to print out an error message to stderr and exit. + It can optionally print the stack trace as well. + + Args: + error_msg : error message to print + stack_trace : set to True to print stack trace + Returns: + None + """ + if stack_trace: + traceback.print_stack(file=sys.stderr) + + msg_footer='\nExiting with nonzero status.' + print(dedent(error_msg) + msg_footer, file=sys.stderr) + sys.exit(1) + +def print_info_msg(info_msg,verbose=True): + """ Function to print information message to stdout, when verbose + is set to True. It does proper "dedentation" that is needed for readability + of python code. + + Args: + info_msg : info message to print + verbose : set to False to silence printing + Returns: + True: if message is successfully printed + """ + + if verbose == True: + print(dedent(info_msg)) + return True + return False + diff --git a/ush/python_utils/process_args.py b/ush/python_utils/process_args.py new file mode 100644 index 0000000000..0baf0d4f9b --- /dev/null +++ b/ush/python_utils/process_args.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +from textwrap import dedent +from .check_var_valid_value import check_var_valid_value + +def process_args(valid_args, **kwargs): + """ Function to process a list of variable name-value pairs. + It checks whether each argument is a valid argument or not. + + Args: + valid_args: List of valid arguments + **kwargs: keyword arguments + Returns: + A dictionary of all valid (arg,value) pairs + """ + + if valid_args[0] == '__unset__': + valid_arg_names = [] + else: + valid_arg_names = valid_args + num_valid_args = len(valid_arg_names) + num_arg_val_pairs = len(kwargs) + + if num_arg_val_pairs > num_valid_args: + print_err_msg_exit(f''' + The number of argument-value pairs specified on the command line (num_- + arg_val_pairs) must be less than or equal to the number of valid argu- + ments (num_valid_args) specified in the array valid_arg_names: + num_arg_val_pairs = {num_arg_val_pairs} + num_valid_args = {num_valid_args} + valid_arg_names = ( {valid_arg_names_str})''') + + if num_valid_args == 0: + return None + + values_args = [None] * num_valid_args + + for i,a in enumerate(valid_args): + if a is None: + print_err_msg_exit(f''' + The list of valid arguments (valid_arg_names) cannot contain empty elements, + but the element with index i={i} is empty: + valid_arg_names = ( {valid_arg_names}) + valid_arg_names[{i}] = \"{valid_arg_names[i]}\"''') + + for arg_name,arg_value in kwargs.items(): + err_msg=dedent(f''' + The specified argument name (arg_name) in the current argument-value + pair (arg_val_pair) is not valid: + arg_name = \"{arg_name}\" + arg_val = \"{arg_value}\"\n''') + check_var_valid_value(arg_name, valid_arg_names, err_msg) + + idx = valid_arg_names.index(arg_name) + if values_args[idx] is not None: + print_err_msg_exit(f''' + The current argument has already been assigned a value: + arg_name = \"{arg_name}\" + key_value_pair = {kwargs} + Please assign values to arguments only once on the command line.''') + values_args[idx] = arg_value + + return dict(zip(valid_args,values_args)) + diff --git a/ush/python_utils/run_command.py b/ush/python_utils/run_command.py new file mode 100644 index 0000000000..70978bd789 --- /dev/null +++ b/ush/python_utils/run_command.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import subprocess + +def run_command(cmd): + """ Run system command in a subprocess + + Args: + cmd: command to execute + Returns: + Tuple of (exit code, std_out, std_err) + """ + proc = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + shell=True, + universal_newlines=True) + + std_out, std_err = proc.communicate() + + # strip trailing newline character + return (proc.returncode, + std_out.rstrip('\n'), + std_err.rstrip('\n')) + diff --git a/ush/python_utils/test_data/Externals.cfg b/ush/python_utils/test_data/Externals.cfg new file mode 100644 index 0000000000..43e6e7b9b4 --- /dev/null +++ b/ush/python_utils/test_data/Externals.cfg @@ -0,0 +1,38 @@ +[regional_workflow] +protocol = git +repo_url = https://github.com/ufs-community/regional_workflow +# Specify either a branch name or a hash but not both. +#branch = develop +hash = 20a149d +local_path = regional_workflow +required = True + +[ufs_utils] +protocol = git +repo_url = https://github.com/ufs-community/UFS_UTILS +# Specify either a branch name or a hash but not both. +#branch = develop +hash = f30740e +local_path = src/UFS_UTILS +required = True + +[ufs-weather-model] +protocol = git +repo_url = https://github.com/ufs-community/ufs-weather-model +# Specify either a branch name or a hash but not both. +#branch = develop +hash = 805421d +local_path = src/ufs-weather-model +required = True + +[UPP] +protocol = git +repo_url = https://github.com/NOAA-EMC/UPP +# Specify either a branch name or a hash but not both. +#branch = develop +hash = a49af05 +local_path = src/UPP +required = True + +[externals_description] +schema_version = 1.0.0 diff --git a/ush/python_utils/test_data/sample.nc b/ush/python_utils/test_data/sample.nc new file mode 100644 index 0000000000..9e31e16a3d Binary files /dev/null and b/ush/python_utils/test_data/sample.nc differ diff --git a/ush/python_utils/test_data/var_defns.sh b/ush/python_utils/test_data/var_defns.sh new file mode 100644 index 0000000000..c2937c56b9 --- /dev/null +++ b/ush/python_utils/test_data/var_defns.sh @@ -0,0 +1,6 @@ +RUN_ENVIR="nco" +MACHINE="hera" +DATE_FIRST_CYCL="20210210" +DATE_LAST_CYCL="20210210" +CYCL_HRS="12" +FCST_LEN_HRS="12" diff --git a/ush/python_utils/test_python_utils.py b/ush/python_utils/test_python_utils.py new file mode 100644 index 0000000000..52defb1c6c --- /dev/null +++ b/ush/python_utils/test_python_utils.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 + +""" +Unit tests for python utilities. + +To run them, issue the following command from the ush directory: + python3 -m unittest -b python_utils/test_python_utils.py + +All modules needed to build and run the regional_workflow need to be +loaded first before executing unit tests. + +""" + +import unittest +import glob +import os + +from python_utils import * + +class Testing(unittest.TestCase): + def test_misc(self): + self.assertEqual( uppercase('upper'), 'UPPER' ) + self.assertEqual( lowercase('LOWER'), 'lower' ) + # regex in file + pattern = f'^[ ]*(lsm_ruc)<\/scheme>[ ]*$' + FILE=f"{self.PATH}/../test_data/suite_FV3_GSD_SAR.xml" + match = find_pattern_in_file(pattern, FILE) + self.assertEqual( ("lsm_ruc",), match) + # regex in string + with open(FILE) as f: + content = f.read() + find_pattern_in_str(pattern, content) + self.assertEqual( ("lsm_ruc",), match) + def test_xml_parser(self): + FILE=f"{self.PATH}/../test_data/suite_FV3_GSD_SAR.xml" + tree = load_xml_file(FILE) + self.assertTrue(has_tag_with_value(tree,"scheme","lsm_ruc")) + def test_check_for_preexist_dir_file(self): + cmd_vrfy('mkdir -p test_data/dir') + self.assertTrue( os.path.exists('test_data/dir') ) + check_for_preexist_dir_file('test_data/dir', 'rename') + dirs = glob.glob('test_data/dir_*') + self.assertEqual( len(dirs), 1) + rm_vrfy('-rf test_data/dir*') + def test_check_var_valid_value(self): + self.assertTrue( check_var_valid_value('rice', [ 'egg', 'spam', 'rice' ]) ) + def test_count_files(self): + (_,target_cnt,_) = run_command('ls -l *.py | wc -l') + cnt = count_files('py') + self.assertEqual(cnt, int(target_cnt)) + def test_filesys_cmds(self): + dPATH=f'{self.PATH}/test_data/dir' + mkdir_vrfy(dPATH) + self.assertTrue( os.path.exists(dPATH) ) + cp_vrfy(f'{self.PATH}/misc.py', f'{dPATH}/miscs.py') + self.assertTrue( os.path.exists(f'{dPATH}/miscs.py') ) + cmd_vrfy(f'rm -rf {dPATH}') + self.assertFalse( os.path.exists('tt.py') ) + def test_get_charvar_from_netcdf(self): + FILE=f'{self.PATH}/test_data/sample.nc' + val = get_charvar_from_netcdf(FILE, 'pressure') + self.assertTrue( val and (val.split()[0], '955.5,')) + def test_run_command(self): + self.assertEqual( run_command('echo hello'), (0, 'hello', '') ) + def test_get_elem_inds(self): + arr = [ 'egg', 'spam', 'egg', 'rice', 'egg'] + self.assertEqual( get_elem_inds(arr, 'egg', 'first' ) , 0 ) + self.assertEqual( get_elem_inds(arr, 'egg', 'last' ) , 4 ) + self.assertEqual( get_elem_inds(arr, 'egg', 'all' ) , [0, 2, 4] ) + def test_interpol_to_arbit_CRES(self): + RES = 800 + RES_array = [ 5, 25, 40, 60, 80, 100, 400, 700, 1000, 1500, 2800, 3000 ] + prop_array = [ 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.65, 0.7, 1.0, 1.1, 1.2, 1.3 ] + prop = interpol_to_arbit_CRES(RES, RES_array, prop_array) + self.assertAlmostEqual(prop, 0.8) + def test_create_symlink_to_file(self): + TARGET = f'{self.PATH}/test_python_utils.py' + SYMLINK = f'{self.PATH}/test_data/test_python_utils.py' + create_symlink_to_file(TARGET,SYMLINK) + def test_define_macos_utilities(self): + set_env_var('MYVAR','MYVAL') + val = os.getenv('MYVAR') + self.assertEqual(val,'MYVAL') + self.assertEqual(os.getenv('SED'), + 'gsed' if os.uname() == 'Darwin' else 'sed') + def test_process_args(self): + valid_args = [ "arg1", "arg2", "arg3", "arg4" ] + values = process_args( valid_args, + arg2 = "bye", arg3 = "hello", + arg4 = ["this", "is", "an", "array"] ) + self.assertEqual(values, + {'arg1': None, + 'arg2': 'bye', + 'arg3': 'hello', + 'arg4': ['this', 'is', 'an', 'array']} ) + def test_print_input_args(self): + valid_args = { "arg1":1, "arg2":2, "arg3":3, "arg4":4 } + self.assertEqual( print_input_args(valid_args), 4 ) + def test_import_vars(self): + #test import + global MYVAR + set_env_var("MYVAR","MYVAL") + env_vars = ["PWD", "MYVAR"] + import_vars(env_vars=env_vars) + self.assertEqual( os.path.realpath(PWD), os.path.realpath(os.getcwd()) ) + self.assertEqual(MYVAR,"MYVAL") + #test export + MYVAR="MYNEWVAL" + self.assertEqual(os.environ['MYVAR'],'MYVAL') + export_vars(env_vars=env_vars) + self.assertEqual(os.environ['MYVAR'],'MYNEWVAL') + #test custom dictionary + dictionary = { "Hello": "World!" } + import_vars(dictionary=dictionary) + self.assertEqual( Hello, "World!" ) + #test array + shell_str='("1" "2") \n' + v = str_to_list(shell_str) + self.assertTrue( isinstance(v,list) ) + self.assertEqual(v, [1, 2]) + shell_str = '( "1" "2" \n' + v = str_to_list(shell_str) + self.assertFalse( isinstance(v,list) ) + def test_config_parser(self): + cfg = { "HRS": [ "1", "2" ] } + shell_str = cfg_to_shell_str(cfg) + self.assertEqual( shell_str, 'HRS=( "1" "2" )\n') + # ini file + cfg = load_ini_config(f'{self.PATH}/test_data/Externals.cfg') + self.assertIn( \ + 'regional_workflow', + get_ini_value( \ + cfg, + 'regional_workflow', + 'repo_url')) + def test_print_msg(self): + self.assertEqual( print_info_msg("Hello World!", verbose=False), False) + def setUp(self): + """ setUp is where we do preparation for running the unittests. + If you need to download files for running test cases, prepare common stuff + for all test cases etc, this is the best place to do it """ + define_macos_utilities(); + set_env_var('DEBUG','FALSE') + self.PATH = os.path.dirname(__file__) + +if __name__ == '__main__': + unittest.main() + diff --git a/ush/python_utils/xml_parser.py b/ush/python_utils/xml_parser.py new file mode 100644 index 0000000000..0428259c6d --- /dev/null +++ b/ush/python_utils/xml_parser.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import xml.etree.ElementTree as ET + +def load_xml_file(xml_file): + """ Loads xml file + + Args: + xml_file: path to xml file + Returns: + root of the xml tree + """ + tree = ET.parse(xml_file) + return tree + +def has_tag_with_value(tree, tag, value): + """ Check if xml tree has a node with tag and value + + Args: + tree: the xml tree + tag: the tag + value: text of tag + Returns: + Boolean + """ + for node in tree.iter(): + if node.tag == tag and node.text == value: + return True + return False + diff --git a/ush/retrieve_data.py b/ush/retrieve_data.py new file mode 100755 index 0000000000..1257048e42 --- /dev/null +++ b/ush/retrieve_data.py @@ -0,0 +1,963 @@ +#!/usr/bin/env python3 +# pylint: disable=logging-fstring-interpolation +''' +This script helps users pull data from known data streams, including +URLS and HPSS (only on supported NOAA platforms), or from user-supplied +data locations on disk. + +Several supported data streams are included in +ush/templates/data_locations.yml, which provides locations and naming +conventions for files commonly used with the SRW App. Provide the file +to this tool via the --config flag. Users are welcome to provide their +own file with alternative locations and naming conventions. + +When using this script to pull from disk, the user is required to +provide the path to the data location, which can include Python +templates. The file names follow those included in the --config file by +default, or can be user-supplied via the --file_name flag. That flag +takes a YAML-formatted string that follows the same conventions outlined +in the ush/templates/data_locations.yml file for naming files. + +To see usage for this script: + + python retrieve_data.py -h + +Also see the parse_args function below. +''' + +import argparse +import datetime as dt +import logging +import os +import shutil +import subprocess +import sys +from textwrap import dedent +import time + +import yaml + +def clean_up_output_dir(expected_subdir, local_archive, output_path, source_paths): + + ''' Remove expected sub-directories and existing_archive files on + disk once all files have been extracted and put into the specified + output location. ''' + + unavailable = {} + # Check to make sure the files exist on disk + for file_path in source_paths: + local_file_path = os.path.join(output_path, file_path.lstrip("/")) + if not os.path.exists(local_file_path): + logging.info(f'File does not exist: {local_file_path}') + unavailable['hpss'] = source_paths + else: + file_name = os.path.basename(file_path) + expected_output_loc = os.path.join(output_path, file_name) + if not local_file_path == expected_output_loc: + logging.info(f'Moving {local_file_path} to ' \ + f'{expected_output_loc}') + shutil.move(local_file_path, expected_output_loc) + + # Clean up directories from inside archive, if they exist + if os.path.exists(expected_subdir) and expected_subdir != './': + logging.info(f'Removing {expected_subdir}') + os.removedirs(expected_subdir) + + # If an archive exists on disk, remove it + if os.path.exists(local_archive): + os.remove(local_archive) + + return unavailable + +def copy_file(source, destination): + + ''' + Copy a file from a source and place it in the destination location. + Return a boolean value reflecting the state of the copy. + + Assumes destination exists. + ''' + + if not os.path.exists(source): + logging.info(f'File does not exist on disk \n {source}') + return False + + # Using subprocess here because system copy is much faster than + # python copy options. + cmd = f'cp {source} {destination}' + logging.info(f'Running command: \n {cmd}') + try: + subprocess.run(cmd, + check=True, + shell=True, + ) + except subprocess.CalledProcessError as err: + logging.info(err) + return False + return True + +def download_file(url): + + ''' + Download a file from a url source, and place it in a target location + on disk. + + Arguments: + url url to file to be downloaded + + Return: + boolean value reflecting state of download. + ''' + + # wget flags: + # -c continue previous attempt + # -T timeout seconds + # -t number of tries + cmd = f'wget -q -c -T 30 -t 3 {url}' + logging.info(f'Running command: \n {cmd}') + try: + subprocess.run(cmd, + check=True, + shell=True, + ) + except subprocess.CalledProcessError as err: + logging.info(err) + return False + except: + logging.error('Command failed!') + raise + + return True + +def arg_list_to_range(args): + + ''' + Given an argparse list argument, return the sequence to process. + + The length of the list will determine what sequence items are returned: + + Length = 1: A single item is to be processed + Length = 2: A sequence of start, stop with increment 1 + Length = 3: A sequence of start, stop, increment + Length > 3: List as is + + argparse should provide a list of at least one item (nargs='+'). + + Must ensure that the list contains integers. + ''' + + args = args if isinstance(args, list) else list(args) + arg_len = len(args) + if arg_len in (2, 3): + args[1] += 1 + return list(range(*args)) + + return args + +def fill_template(template_str, cycle_date, templates_only=False, **kwargs): + + ''' Fill in the provided template string with date time information, + and return the resulting string. + + Arguments: + template_str a string containing Python templates + cycle_date a datetime object that will be used to fill in + date and time information + templates_only boolean value. When True, this function will only + return the templates available. + + Keyword Args: + ens_group a number associated with a bin where ensemble + members are stored in archive files + fcst_hr an integer forecast hour. string formatting should + be included in the template_str + mem a single ensemble member. should be a positive integer value + + Return: + filled template string + ''' + + # Parse keyword args + ens_group = kwargs.get('ens_group') + fcst_hr = kwargs.get('fcst_hr', 0) + mem = kwargs.get('mem', '') + # ----- + + cycle_hour = cycle_date.strftime('%H') + # One strategy for binning data files at NCEP is to put them into 6 + # cycle bins. The archive file names include the low and high end of the + # range. Set the range as would be indicated in the archive file + # here. Integer division is intentional here. + low_end = int(cycle_hour) // 6 * 6 + bin6 = f'{low_end:02d}-{low_end+5:02d}' + + # Another strategy is to bundle odd cycle hours with their next + # lowest even cycle hour. Files are named only with the even hour. + # Integer division is intentional here. + hh_even = f'{int(cycle_hour) // 2 * 2:02d}' + + format_values = dict( + bin6=bin6, + ens_group=ens_group, + fcst_hr=fcst_hr, + dd=cycle_date.strftime('%d'), + hh=cycle_hour, + hh_even=hh_even, + jjj=cycle_date.strftime('%j'), + mem=mem, + mm=cycle_date.strftime('%m'), + yy=cycle_date.strftime('%y'), + yyyy=cycle_date.strftime('%Y'), + yyyymm=cycle_date.strftime('%Y%m'), + yyyymmdd=cycle_date.strftime('%Y%m%d'), + yyyymmddhh=cycle_date.strftime('%Y%m%d%H'), + ) + if templates_only: + return f'{",".join((format_values.keys()))}' + return template_str.format(**format_values) + +def create_target_path(target_path): + + ''' + Append target path and create directory for ensemble members + ''' + if not os.path.exists(target_path): + os.makedirs(target_path) + return target_path + +def find_archive_files(paths, file_names, cycle_date, ens_group): + + ''' Given an equal-length set of archive paths and archive file + names, and a cycle date, check HPSS via hsi to make sure at least + one set exists. Return a dict of the paths of the existing archive, along with + the item in set of paths that was found.''' + + zipped_archive_file_paths = zip(paths, file_names) + + + # Narrow down which HPSS files are available for this date + for list_item, (archive_path, archive_file_names) in \ + enumerate(zipped_archive_file_paths): + + existing_archives = {} + if not isinstance(archive_file_names, list): + archive_file_names = [archive_file_names] + + for n_fp, archive_file_name in enumerate(archive_file_names): + # Only test the first item in the list, it will tell us if this + # set exists at this date. + file_path = os.path.join(archive_path, archive_file_name) + file_path = fill_template(file_path, cycle_date, ens_group=ens_group) + file_path = hsi_single_file(file_path) + + if file_path: + existing_archives[n_fp] = file_path + + if existing_archives: + for existing_archive in existing_archives.values(): + logging.info(f'Found HPSS file: {existing_archive}') + return existing_archives, list_item + + return '', 0 + +def get_file_templates(cla, known_data_info, data_store, use_cla_tmpl=False): + + ''' Returns the file templates requested by user input, either from + the command line, or from the known data information dict. + + Arguments: + + cla command line arguments Namespace object + known_data_info dict from data_locations yaml file + data_store string corresponding to a key in the + known_data_info dict + use_cla_tmpl boolean on whether to check cla for templates + + Returns: + file_templates a list of file templates + ''' + + file_templates = known_data_info.get(data_store, {}).get('file_names') + if use_cla_tmpl: + file_templates = cla.file_templates if cla.file_templates else \ + file_templates + + if isinstance(file_templates, dict): + if cla.file_type is not None: + file_templates = file_templates[cla.file_type] + file_templates = file_templates[cla.anl_or_fcst] + if not file_templates: + msg = ('No file naming convention found. They must be provided \ + either on the command line or on in a config file.') + raise argparse.ArgumentTypeError(msg) + return file_templates + +def get_requested_files(cla, file_templates, input_locs, method='disk', + **kwargs): + + # pylint: disable=too-many-locals + + ''' This function copies files from disk locations + or downloads files from a url, depending on the option specified for + user. + + This function expects that the output directory exists and is + writeable. + + Arguments: + + cla Namespace object containing command line arguments + file_templates a list of file templates + input_locs A string containing a single data location, either a url + or disk path, or a list of paths/urls. + method Choice of disk or download to indicate protocol for + retrieval + + Keyword args: + members a list integers corresponding to the ensemble members + check_all boolean flag that indicates all urls should be + checked for all files + + Returns: + unavailable a list of locations/files that were unretrievable + ''' + + members = kwargs.get('members', '') + members = members if isinstance(members, list) else [members] + + + + check_all = kwargs.get('check_all', False) + + logging.info(f'Getting files named like {file_templates}') + + # Make sure we're dealing with lists for input locations and file + # templates. Makes it easier to loop and zip. + file_templates = file_templates if isinstance(file_templates, list) else \ + [file_templates] + + input_locs = input_locs if isinstance(input_locs, list) else \ + [input_locs] + + orig_path = os.path.dirname(__file__) + unavailable = [] + + locs_files = pair_locs_with_files(input_locs, file_templates, check_all) + for mem in members: + target_path = fill_template(cla.output_path, + cla.cycle_date, + mem=mem) + target_path = create_target_path(target_path) + + logging.info(f'Retrieved files will be placed here: \n {target_path}') + os.chdir(target_path) + + for fcst_hr in cla.fcst_hrs: + logging.debug(f'Looking for fhr = {fcst_hr}') + for loc, templates in locs_files: + + templates = templates if isinstance(templates, list) \ + else [templates] + + + logging.debug(f'Looking for files like {templates}') + logging.debug(f'They should be here: {loc}') + + template_loc = loc + for tmpl_num, template in enumerate(templates): + if isinstance(loc, list) and len(loc) == len(templates): + template_loc = loc[tmpl_num] + input_loc = os.path.join(template_loc, template) + input_loc = fill_template(input_loc, + cla.cycle_date, + fcst_hr=fcst_hr, + mem=mem, + ) + logging.debug(f'Full file path: {input_loc}') + + if method == 'disk': + retrieved = copy_file(input_loc, target_path) + + if method == 'download': + retrieved = download_file(input_loc) + # Wait a bit before trying the next download. + # Seems to reduce the occurrence of timeouts + # when downloading from AWS + time.sleep(15) + + logging.debug(f'Retrieved status: {retrieved}') + if not retrieved: + unavailable.append(input_loc) + # Go on to the next location if the first file + # isn't found here. + break + + # If retrieved, reset unavailable + unavailable = [] + if not unavailable: + # Start on the next fcst hour if all files were + # found from a loc/template combo + break + + os.chdir(orig_path) + return unavailable + +def hsi_single_file(file_path, mode='ls'): + + ''' Call hsi as a subprocess for Python and return information about + whether the file_path was found. + + Arguments: + file_path path on HPSS + mode the hsi command to run. ls is default. may also + pass "get" to retrieve the file path + + ''' + cmd = f'hsi {mode} {file_path}' + + logging.info(f'Running command \n {cmd}') + try: + subprocess.run(cmd, + check=True, + shell=True, + ) + except subprocess.CalledProcessError: + logging.warning(f'{file_path} is not available!') + return '' + + return file_path + +def hpss_requested_files(cla, file_names, store_specs, members=-1, + ens_group=-1): + + # pylint: disable=too-many-locals + + ''' This function interacts with the "hpss" protocol in a provided + data store specs file to download a set of files requested by the + user. Depending on the type of archive file (zip or tar), it will + either pull the entire file and unzip it, or attempt to pull + individual files from a tar file. + + It cleans up local disk after files are deemed available to remove + any empty subdirectories that may still be present. + + This function exepcts that the output directory exists and is + writable. + ''' + members = [-1] if members == -1 else members + + archive_paths = store_specs['archive_path'] + archive_paths = archive_paths if isinstance(archive_paths, list) \ + else [archive_paths] + + # Could be a list of lists + archive_file_names = store_specs.get('archive_file_names', {}) + if cla.file_type is not None: + archive_file_names = archive_file_names[cla.file_type] + + if isinstance(archive_file_names, dict): + archive_file_names = archive_file_names[cla.anl_or_fcst] + + unavailable = {} + existing_archives = {} + + logging.debug(f'Will try to look for: '\ + f' {list(zip(archive_paths, archive_file_names))}') + + existing_archives, which_archive = find_archive_files(archive_paths, + archive_file_names, + cla.cycle_date, + ens_group=ens_group, + ) + + logging.debug(f'Found existing archives: {existing_archives}') + + if not existing_archives: + logging.warning('No archive files were found!') + unavailable['archive'] = list(zip(archive_paths, archive_file_names)) + return unavailable + + logging.info(f'Files in archive are named: {file_names}') + + archive_internal_dirs = store_specs.get('archive_internal_dir', ['']) + if isinstance(archive_internal_dirs, dict): + archive_internal_dirs = archive_internal_dirs.get(cla.anl_or_fcst, ['']) + + + # which_archive matters for choosing the correct file names within, + # but we can safely just try all options for the + # archive_internal_dir + logging.debug(f'Checking archive number {which_archive} in list.') + + for archive_internal_dir_tmpl in archive_internal_dirs: + for mem in members: + archive_internal_dir = fill_template( + archive_internal_dir_tmpl, + cla.cycle_date, + mem=mem, + ) + + output_path = fill_template(cla.output_path, + cla.cycle_date, mem=mem) + logging.info(f'Will place files in {os.path.abspath(output_path)}') + orig_path = os.path.dirname(__file__) + logging.debug(f'CWD: {os.getcwd()}') + os.chdir(orig_path) + + if mem != -1: + archive_internal_dir = fill_template(archive_internal_dir_tmpl, + cla.cycle_date, + mem=mem, + ) + output_path = create_target_path(output_path) + logging.info(f'Will place files in {os.path.abspath(output_path)}') + + os.chdir(output_path) + + source_paths = [] + for fcst_hr in cla.fcst_hrs: + for file_name in file_names: + source_paths.append(fill_template( + os.path.join(archive_internal_dir, file_name), + cla.cycle_date, + fcst_hr=fcst_hr, + mem=mem, + ens_group=ens_group, + )) + + expected = set(source_paths) + unavailable = {} + for existing_archive in existing_archives.values(): + if store_specs.get('archive_format', 'tar') == 'zip': + + # Get the entire file from HPSS + existing_archive = hsi_single_file(existing_archive, mode='get') + + # Grab only the necessary files from the archive + cmd = f'unzip -o {os.path.basename(existing_archive)} {" ".join(source_paths)}' + + else: + cmd = f'htar -xvf {existing_archive} {" ".join(source_paths)}' + + logging.info(f'Running command \n {cmd}') + subprocess.run(cmd, + check=True, + shell=True, + ) + + # Check that files exist and Remove any data transfer artifacts. + # Returns {'hpss': []}, turn that into a new dict of + # sets. + unavailable[existing_archive] = set(clean_up_output_dir( + expected_subdir=archive_internal_dir, + local_archive=os.path.basename(existing_archive), + output_path=output_path, + source_paths=source_paths, + ).get('hpss', [])) + + # Once we go through all the archives, the union of all + # "unavailable" files should equal the "expected" list of + # files since clean_up_output_dir only reports on those that + # are missing from one of the files attempted. If any + # additional files are reported as unavailable, then + # something has gone wrong. + unavailable = set.union(*unavailable.values()) + + + # Report only the files that are truly unavailable + if not expected == unavailable: + return unavailable - expected + + os.chdir(orig_path) + + return {} + +def load_str(arg): + + ''' Load a dict string safely using YAML. Return the resulting dict. ''' + return yaml.load(arg, Loader=yaml.SafeLoader) + +def config_exists(arg): + + ''' + Check to ensure that the provided config file exists. If it does, + load it with YAML's safe loader and return the resulting dict. + ''' + + # Check for existence of file + if not os.path.exists(arg): + msg = f'{arg} does not exist!' + raise argparse.ArgumentTypeError(msg) + + with open(arg, 'r') as config_path: + cfg = yaml.load(config_path, Loader=yaml.SafeLoader) + return cfg + +def pair_locs_with_files(input_locs, file_templates, check_all): + + ''' + Given a list of input locations and files, return an iterable that + contains the multiple locations and file templates for files that + should be searched in those locations. + + check_all indicates that all locations should be paired with all + avaiable file templates. + + The different possibilities: + 1. Get one or more files from a single path/url + 2. Get multiple files from multiple corresponding + paths/urls + 3. Check all paths for all file templates until files are + found + + The default will be to handle #1 and #2. #3 will be + indicated by a flag in the yaml: "check_all: True" + + ''' + + if not check_all: + + # Make sure the length of both input_locs and + # file_templates is consistent + + # Case 2 above + if len(file_templates) == len(input_locs): + locs_files = list(zip(input_locs, file_templates)) + + # Case 1 above + elif len(file_templates) > len(input_locs) and \ + len(input_locs) == 1: + + locs_files = list(zip(input_locs, [file_templates])) + else: + msg = "Please check your input locations and templates." + raise KeyError(msg) + else: + # Case 3 above + locs_files = [(loc, file_templates) for loc in input_locs] + + return locs_files + + +def path_exists(arg): + + ''' Check whether the supplied path exists and is writeable ''' + + if not os.path.exists(arg): + msg = f'{arg} does not exist!' + raise argparse.ArgumentTypeError(msg) + + if not os.access(arg, os.X_OK|os.W_OK): + logging.error(f'{arg} is not writeable!') + raise argparse.ArgumentTypeError(msg) + + return arg + + +def setup_logging(debug=False): + + ''' Calls initialization functions for logging package, and sets the + user-defined level for logging in the script.''' + + level = logging.WARNING + if debug: + level = logging.DEBUG + + logging.basicConfig(format='%(levelname)s: %(message)s \n ', level=level) + if debug: + logging.info('Logging level set to DEBUG') + + + +def write_summary_file(cla, data_store, file_templates): + + ''' Given the command line arguments and the data store from which + the data was retrieved, write a bash summary file that is needed by + the workflow elements downstream. ''' + + files = [] + for tmpl in file_templates: + files.extend([fill_template(tmpl, cla.cycle_date, fcst_hr=fh) for fh in cla.fcst_hrs]) + + summary_fp = os.path.join(cla.output_path, cla.summary_file) + logging.info(f'Writing a summary file to {summary_fp}') + file_contents = dedent(f''' + DATA_SRC={data_store} + EXTRN_MDL_CDATE={cla.cycle_date.strftime('%Y%m%d%H')} + EXTRN_MDL_STAGING_DIR={cla.output_path} + EXTRN_MDL_FNS=( {' '.join(files)} ) + EXTRN_MDL_FHRS=( {' '.join([str(i) for i in cla.fcst_hrs])} ) + ''') + logging.info(f'Contents: {file_contents}') + with open(summary_fp, "w") as summary: + summary.write(file_contents) + + +def to_datetime(arg): + ''' Return a datetime object give a string like YYYYMMDDHH. + ''' + return dt.datetime.strptime(arg, '%Y%m%d%H') + + +def to_lower(arg): + ''' Return a string provided by arg into all lower case. ''' + return arg.lower() + + +def main(argv): + # pylint: disable=too-many-branches, too-many-statements + ''' + Uses known location information to try the known locations and file + paths in priority order. + ''' + + cla = parse_args(argv) + cla.fcst_hrs = arg_list_to_range(cla.fcst_hrs) + + if cla.members: + cla.members = arg_list_to_range(cla.members) + + setup_logging(cla.debug) + print("Running script retrieve_data.py with args:\n", + f"{('-' * 80)}\n{('-' * 80)}") + for name, val in cla.__dict__.items(): + if name not in ['config']: + print(f"{name:>15s}: {val}") + print(f"{('-' * 80)}\n{('-' * 80)}") + + if 'disk' in cla.data_stores: + # Make sure a path was provided. + if not cla.input_file_path: + raise argparse.ArgumentTypeError( + ('You must provide an input_file_path when choosing ' \ + ' disk as a data store!')) + + if 'hpss' in cla.data_stores: + # Make sure hpss module is loaded + try: + subprocess.run('which hsi', + check=True, + shell=True, + ) + except subprocess.CalledProcessError: + logging.error('You requested the hpss data store, but ' \ + 'the HPSS module isn\'t loaded. This data store ' \ + 'is only available on NOAA compute platforms.') + sys.exit(1) + + + known_data_info = cla.config.get(cla.external_model, {}) + if not known_data_info: + msg = dedent(f'''No data stores have been defined for + {cla.external_model}! Only checking provided disk + location''') + if cla.input_file_path is None: + cla.data_stores = ['disk'] + raise KeyError(msg) + logging.info(msg) + + unavailable = {} + for data_store in cla.data_stores: + logging.info(f'Checking {data_store} for {cla.external_model}') + store_specs = known_data_info.get(data_store, {}) + + if data_store == 'disk': + file_templates = get_file_templates( + cla, + known_data_info, + data_store='hpss', + use_cla_tmpl=True, + ) + + logging.debug(f'User supplied file names are: {file_templates}') + unavailable = get_requested_files(cla, + check_all=known_data_info.get('check_all', + False), + file_templates=file_templates, + input_locs=cla.input_file_path, + method='disk', + ) + + elif not store_specs: + msg = (f'No information is available for {data_store}.') + raise KeyError(msg) + + else: + + file_templates = get_file_templates( + cla, + known_data_info, + data_store=data_store, + ) + + if store_specs.get('protocol') == 'download': + unavailable = get_requested_files( + cla, + check_all=known_data_info.get('check_all', False), + file_templates=file_templates, + input_locs=store_specs['url'], + method='download', + members=cla.members, + ) + + if store_specs.get('protocol') == 'htar': + ens_groups = get_ens_groups(cla.members) + for ens_group, members in ens_groups.items(): + unavailable = hpss_requested_files( + cla, + file_templates, + store_specs, + members=members, + ens_group=ens_group, + ) + + if not unavailable: + # All files are found. Stop looking! + # Write a variable definitions file for the data, if requested + if cla.summary_file: + write_summary_file(cla, data_store, file_templates) + break + + logging.debug(f'Some unavailable files: {unavailable}') + logging.warning(f'Requested files are unavailable from {data_store}') + + if unavailable: + logging.error('Could not find any of the requested files.') + sys.exit(1) + +def get_ens_groups(members): + + ''' Given a list of ensemble members, return a dict with keys for + the ensemble group, and values are lists of ensemble members + requested in that group. ''' + + + if members is None: + return {-1: [-1]} + + ens_groups = {} + for mem in members: + ens_group = (mem - 1) // 10 + 1 + if ens_groups.get(ens_group) is None: + ens_groups[ens_group] = [mem] + else: + ens_groups[ens_group].append(mem) + return ens_groups + +def parse_args(argv): + + ''' + Function maintains the arguments accepted by this script. Please see + Python's argparse documenation for more information about settings of each + argument. + ''' + + description=( + 'Allowable Python templates for paths, urls, and file names are '\ + ' defined in the fill_template function and include:\n' \ + f'{"-"*120}\n' \ + f'{fill_template("null", dt.datetime.now(), templates_only=True)}') + parser = argparse.ArgumentParser( + description=description, + ) + + # Required + parser.add_argument( + '--anl_or_fcst', + choices=('anl', 'fcst'), + help='Flag for whether analysis or forecast \ + files should be gathered', + required=True, + ) + parser.add_argument( + '--config', + help='Full path to a configuration file containing paths and \ + naming conventions for known data streams. The default included \ + in this repository is in ush/templates/data_locations.yml', + type=config_exists, + ) + parser.add_argument( + '--cycle_date', + help='Cycle date of the data to be retrieved in YYYYMMDDHH \ + format.', + required=True, + type=to_datetime, + ) + parser.add_argument( + '--data_stores', + help='List of priority data_stores. Tries first list item \ + first. Choices: hpss, nomads, aws, disk', + nargs='*', + required=True, + type=to_lower, + ) + parser.add_argument( + '--external_model', + choices=('FV3GFS','GDAS', 'GEFS', 'GSMGFS', 'HRRR', 'NAM', 'RAP', 'RAPx', + 'HRRRx'), + help='External model label. This input is case-sensitive', + required=True, + ) + parser.add_argument( + '--fcst_hrs', + help='A list describing forecast hours. If one argument, \ + one fhr will be processed. If 2 or 3 arguments, a sequence \ + of forecast hours [start, stop, [increment]] will be \ + processed. If more than 3 arguments, the list is processed \ + as-is.', + nargs='+', + required=True, + type=int, + ) + parser.add_argument( + '--output_path', + help='Path to a location on disk. Path is expected to exist.', + required=True, + type=os.path.abspath, + ) + + # Optional + parser.add_argument( + '--debug', + action='store_true', + help='Print debug messages', + ) + parser.add_argument( + '--file_templates', + help='One or more file template strings defining the naming \ + convention the be used for the files retrieved from disk. If \ + not provided, the default names from hpss are used.', + nargs='*', + ) + parser.add_argument( + '--file_type', + choices=('grib2', 'nemsio', 'netcdf'), + help='External model file format', + ) + parser.add_argument( + '--input_file_path', + help='A path to data stored on disk. The path may contain \ + Python templates. File names may be supplied using the \ + --file_templates flag, or the default naming convention will be \ + taken from the --config file.', + ) + parser.add_argument( + '--members', + help='A list describing ensemble members. If one argument, \ + one member will be processed. If 2 or 3 arguments, a sequence \ + of members [start, stop, [increment]] will be \ + processed. If more than 3 arguments, the list is processed \ + as-is.', + nargs='*', + type=int, + ) + parser.add_argument( + '--summary_file', + help='Name of the summary file to be written to the output \ + directory', + ) + return parser.parse_args(argv) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/ush/set_FV3nml_ens_stoch_seeds.py b/ush/set_FV3nml_ens_stoch_seeds.py new file mode 100644 index 0000000000..76f30b39b0 --- /dev/null +++ b/ush/set_FV3nml_ens_stoch_seeds.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse +import unittest +from textwrap import dedent +from datetime import datetime + +from python_utils import print_input_args, print_info_msg, print_err_msg_exit,\ + date_to_str, mkdir_vrfy, cp_vrfy, str_to_type, \ + import_vars,set_env_var, \ + define_macos_utilities, cfg_to_yaml_str, \ + load_shell_config + +from set_namelist import set_namelist + +def set_FV3nml_ens_stoch_seeds(cdate): + """ + This function, for an ensemble-enabled experiment + (i.e. for an experiment for which the workflow configuration variable + DO_ENSEMBLE has been set to "TRUE"), creates new namelist files with + unique stochastic "seed" parameters, using a base namelist file in the + ${EXPTDIR} directory as a template. These new namelist files are stored + within each member directory housed within each cycle directory. Files + of any two ensemble members differ only in their stochastic "seed" + parameter values. These namelist files are generated when this file is + called as part of the RUN_FCST_TN task. + + Args: + cdate + Returns: + None + """ + + print_input_args(locals()) + + # import all environment variables + import_vars() + + # + #----------------------------------------------------------------------- + # + # For a given cycle and member, generate a namelist file with unique + # seed values. + # + #----------------------------------------------------------------------- + # + ensmem_name=f"mem{ENSMEM_INDX}" + + fv3_nml_ensmem_fp=os.path.join(CYCLE_BASEDIR, f'{date_to_str(cdate,format="%Y%m%d%H")}{os.sep}{ensmem_name}{os.sep}{FV3_NML_FN}') + + ensmem_num=ENSMEM_INDX + + cdate_i = int(cdate.strftime('%Y%m%d%H')) + + settings = {} + nam_stochy_dict = {} + + if DO_SPPT: + iseed_sppt=cdate_i*1000 + ensmem_num*10 + 1 + nam_stochy_dict.update({ + 'iseed_sppt': iseed_sppt + }) + + if DO_SHUM: + iseed_shum=cdate_i*1000 + ensmem_num*10 + 2 + nam_stochy_dict.update({ + 'iseed_shum': iseed_shum + }) + + if DO_SKEB: + iseed_skeb=cdate_i*1000 + ensmem_num*10 + 3 + nam_stochy_dict.update({ + 'iseed_skeb': iseed_skeb + }) + + settings['nam_stochy'] = nam_stochy_dict + + if DO_SPP: + num_iseed_spp=len(ISEED_SPP) + iseed_spp = [None]*num_iseed_spp + for i in range(num_iseed_spp): + iseed_spp[i]=cdate_i*1000 + ensmem_num*10 + ISEED_SPP[i] + + settings['nam_sppperts'] = { + 'iseed_spp': iseed_spp + } + else: + settings['nam_sppperts'] = {} + + if DO_LSM_SPP: + iseed_lsm_spp=cdate_i*1000 + ensmem_num*10 + 9 + + settings['nam_sppperts'] = { + 'iseed_lndp': [iseed_lsm_spp] + } + + settings_str = cfg_to_yaml_str(settings) + + print_info_msg(dedent(f''' + The variable \"settings\" specifying seeds in \"{FV3_NML_FP}\" + has been set as follows: + + settings =\n\n''') + settings_str,verbose=VERBOSE) + + try: + set_namelist(["-q", "-n", FV3_NML_FP, "-u", settings_str, "-o", fv3_nml_ensmem_fp]) + except: + print_err_msg_exit(dedent(f''' + Call to python script set_namelist.py to set the variables in the FV3 + namelist file that specify the paths to the surface climatology files + failed. Parameters passed to this script are: + Full path to base namelist file: + FV3_NML_FP = \"{FV3_NML_FP}\" + Full path to output namelist file: + fv3_nml_ensmem_fp = \"{fv3_nml_ensmem_fp}\" + Namelist settings specified on command line (these have highest precedence):\n + settings =\n\n''') + settings_str) + +def parse_args(argv): + """ Parse command line arguments""" + parser = argparse.ArgumentParser( + description='Creates stochastic seeds for an ensemble experiment.' + ) + + parser.add_argument('-c', '--cdate', + dest='cdate', + required=True, + help='Date.') + + parser.add_argument('-p', '--path-to-defns', + dest='path_to_defns', + required=True, + help='Path to var_defns file.') + + return parser.parse_args(argv) + +if __name__ == '__main__': + args = parse_args(sys.argv[1:]) + cfg = load_shell_config(args.path_to_defns) + import_vars(dictionary=cfg) + set_FV3nml_ens_stoch_seeds(str_to_type(args.cdate)) + +class Testing(unittest.TestCase): + def test_set_FV3nml_ens_stoch_seeds(self): + set_FV3nml_ens_stoch_seeds(cdate=self.cdate) + def setUp(self): + define_macos_utilities(); + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + self.cdate=datetime(2021, 1, 1) + USHDIR = os.path.dirname(os.path.abspath(__file__)) + EXPTDIR = os.path.join(USHDIR,"test_data","expt"); + cp_vrfy(os.path.join(USHDIR,f'templates{os.sep}input.nml.FV3'), \ + os.path.join(EXPTDIR,'input.nml')) + for i in range(2): + mkdir_vrfy("-p", os.path.join(EXPTDIR,f'{date_to_str(self.cdate,format="%Y%m%d%H")}{os.sep}mem{i+1}')) + + set_env_var("USHDIR",USHDIR) + set_env_var("CYCLE_BASEDIR",EXPTDIR) + set_env_var("ENSMEM_INDX",2) + set_env_var("FV3_NML_FN","input.nml") + set_env_var("FV3_NML_FP",os.path.join(EXPTDIR,"input.nml")) + set_env_var("DO_SPPT",True) + set_env_var("DO_SHUM",True) + set_env_var("DO_SKEB",True) + set_env_var("DO_SPP",True) + set_env_var("DO_LSM_SPP",True) + ISEED_SPP = [ 4, 5, 6, 7, 8] + set_env_var("ISEED_SPP",ISEED_SPP) + diff --git a/ush/set_FV3nml_sfc_climo_filenames.py b/ush/set_FV3nml_sfc_climo_filenames.py new file mode 100644 index 0000000000..d351d33d04 --- /dev/null +++ b/ush/set_FV3nml_sfc_climo_filenames.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 + +import unittest +import os +import sys +import argparse +from textwrap import dedent + +from python_utils import print_input_args, print_info_msg, print_err_msg_exit,\ + check_var_valid_value,mv_vrfy,mkdir_vrfy,cp_vrfy,\ + rm_vrfy,import_vars,set_env_var,load_shell_config,\ + define_macos_utilities,find_pattern_in_str,cfg_to_yaml_str + +from set_namelist import set_namelist + +def set_FV3nml_sfc_climo_filenames(): + """ + This function sets the values of the variables in + the forecast model's namelist file that specify the paths to the surface + climatology files on the FV3LAM native grid (which are either pregenerated + or created by the MAKE_SFC_CLIMO_TN task). Note that the workflow + generation scripts create symlinks to these surface climatology files + in the FIXLAM directory, and the values in the namelist file that get + set by this function are relative or full paths to these links. + + Args: + None + Returns: + None + """ + + # import all environment variables + import_vars() + + # The regular expression regex_search set below will be used to extract + # from the elements of the array FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING + # the name of the namelist variable to set and the corresponding surface + # climatology field from which to form the name of the surface climatology file + regex_search = "^[ ]*([^| ]+)[ ]*[|][ ]*([^| ]+)[ ]*$" + + # Set the suffix of the surface climatology files. + suffix = "tileX.nc" + + # create yaml-complaint string + settings = {} + + dummy_run_dir = os.path.join(EXPTDIR, "any_cyc") + if DO_ENSEMBLE == "TRUE": + dummy_run_dir += os.sep + "any_ensmem" + + namsfc_dict = {} + for mapping in FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING: + tup = find_pattern_in_str(regex_search, mapping) + nml_var_name = tup[0] + sfc_climo_field_name = tup[1] + + check_var_valid_value(sfc_climo_field_name, SFC_CLIMO_FIELDS) + + fp = os.path.join(FIXLAM, f'{CRES}.{sfc_climo_field_name}.{suffix}') + if RUN_ENVIR != "nco": + fp = os.path.relpath(os.path.realpath(fp), start=dummy_run_dir) + + namsfc_dict[nml_var_name] = fp + + settings['namsfc_dict'] = namsfc_dict + settings_str = cfg_to_yaml_str(settings) + + + print_info_msg(dedent(f''' + The variable \"settings\" specifying values of the namelist variables + has been set as follows: + + settings =\n\n''') + settings_str, verbose=VERBOSE) + + # Rename the FV3 namelist and call set_namelist + fv3_nml_base_fp = f'{FV3_NML_FP}.base' + mv_vrfy(f'{FV3_NML_FP} {fv3_nml_base_fp}') + + try: + set_namelist(["-q", "-n", fv3_nml_base_fp, "-u", settings_str, "-o", FV3_NML_FP]) + except: + print_err_msg_exit(dedent(f''' + Call to python script set_namelist.py to set the variables in the FV3 + namelist file that specify the paths to the surface climatology files + failed. Parameters passed to this script are: + Full path to base namelist file: + fv3_nml_base_fp = \"{fv3_nml_base_fp}\" + Full path to output namelist file: + FV3_NML_FP = \"{FV3_NML_FP}\" + Namelist settings specified on command line (these have highest precedence):\n + settings =\n\n''') + settings_str) + + rm_vrfy(f'{fv3_nml_base_fp}') + +def parse_args(argv): + """ Parse command line arguments""" + parser = argparse.ArgumentParser( + description='Set surface climatology fields.' + ) + + parser.add_argument('-p', '--path-to-defns', + dest='path_to_defns', + required=True, + help='Path to var_defns file.') + + return parser.parse_args(argv) + +if __name__ == '__main__': + args = parse_args(sys.argv[1:]) + cfg = load_shell_config(args.path_to_defns) + import_vars(dictionary=cfg) + set_FV3nml_sfc_climo_filenames() + +class Testing(unittest.TestCase): + def test_set_FV3nml_sfc_climo_filenames(self): + set_FV3nml_sfc_climo_filenames() + def setUp(self): + define_macos_utilities(); + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + USHDIR = os.path.dirname(os.path.abspath(__file__)) + EXPTDIR = os.path.join(USHDIR, "test_data", "expt"); + FIXLAM = os.path.join(EXPTDIR, "fix_lam") + mkdir_vrfy("-p",FIXLAM) + cp_vrfy(os.path.join(USHDIR,f'templates{os.sep}input.nml.FV3'), \ + os.path.join(EXPTDIR,'input.nml')) + set_env_var("USHDIR",USHDIR) + set_env_var("EXPTDIR",EXPTDIR) + set_env_var("FIXLAM",FIXLAM) + set_env_var("DO_ENSEMBLE",False) + set_env_var("CRES","C3357") + set_env_var("RUN_ENVIR","nco") + set_env_var("FV3_NML_FP",os.path.join(EXPTDIR,"input.nml")) + + FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING=[ + "FNALBC | snowfree_albedo", + "FNALBC2 | facsf", + "FNTG3C | substrate_temperature", + "FNVEGC | vegetation_greenness", + "FNVETC | vegetation_type", + "FNSOTC | soil_type", + "FNVMNC | vegetation_greenness", + "FNVMXC | vegetation_greenness", + "FNSLPC | slope_type", + "FNABSC | maximum_snow_albedo" + ] + SFC_CLIMO_FIELDS=[ + "facsf", + "maximum_snow_albedo", + "slope_type", + "snowfree_albedo", + "soil_type", + "substrate_temperature", + "vegetation_greenness", + "vegetation_type" + ] + set_env_var("FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING", + FV3_NML_VARNAME_TO_SFC_CLIMO_FIELD_MAPPING) + set_env_var("SFC_CLIMO_FIELDS",SFC_CLIMO_FIELDS) + diff --git a/ush/set_cycle_dates.py b/ush/set_cycle_dates.py new file mode 100644 index 0000000000..69a707b972 --- /dev/null +++ b/ush/set_cycle_dates.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import unittest +from datetime import datetime,timedelta,date + +from python_utils import print_input_args, print_err_msg_exit + +def set_cycle_dates(date_start, date_end, cycle_hrs, incr_cycl_freq): + """ This file defines a function that, given the starting date (date_start, + in the form YYYYMMDD), the ending date (date_end, in the form YYYYMMDD), + and an array containing the cycle hours for each day (whose elements + have the form HH), returns an array of cycle date-hours whose elements + have the form YYYYMMDD. Here, YYYY is a four-digit year, MM is a two- + digit month, DD is a two-digit day of the month, and HH is a two-digit + hour of the day. + + Args: + date_start: start date + date_end: end date + cycle_hrs: [ HH0, HH1, ...] + incr_cycl_freq: cycle frequency increment in hours + Returns: + A list of dates in a format YYYYMMDDHH + """ + + print_input_args(locals()) + + #calculate date increment + if incr_cycl_freq <= 24: + incr_days = 1 + else: + incr_days = incr_cycl_freq // 24 + if incr_cycl_freq % 24 != 0: + print_err_msg_exit(f''' + INCR_CYCL_FREQ is not divided by 24: + INCR_CYCL_FREQ = \"{incr_cycl_freq}\"''') + + #iterate over days and cycles + all_cdates = [] + d = date_start + while d <= date_end: + for c in cycle_hrs: + dc = d + timedelta(hours=c) + v = datetime.strftime(dc,'%Y%m%d%H') + all_cdates.append(v) + d += timedelta(days=incr_days) + + return all_cdates + +class Testing(unittest.TestCase): + def test_set_cycle_dates(self): + cdates = set_cycle_dates(date_start=datetime(2022,1,1), date_end=datetime(2022,1,4), + cycle_hrs=[6,12], incr_cycl_freq=48) + self.assertEqual(cdates, ['2022010106', '2022010112','2022010306', '2022010312']) diff --git a/ush/set_extrn_mdl_params.py b/ush/set_extrn_mdl_params.py new file mode 100644 index 0000000000..f4fffc5907 --- /dev/null +++ b/ush/set_extrn_mdl_params.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +import unittest + +from python_utils import import_vars, export_vars, set_env_var, get_env_var + +def set_extrn_mdl_params(): + """ Sets parameters associated with the external model used for initial + conditions (ICs) and lateral boundary conditions (LBCs). + Args: + None + Returns: + None + """ + + #import all env variables + import_vars() + + global EXTRN_MDL_LBCS_OFFSET_HRS + + # + #----------------------------------------------------------------------- + # + # Set EXTRN_MDL_LBCS_OFFSET_HRS, which is the number of hours to shift + # the starting time of the external model that provides lateral boundary + # conditions. + # + #----------------------------------------------------------------------- + # + if EXTRN_MDL_NAME_LBCS == "RAP": + EXTRN_MDL_LBCS_OFFSET_HRS=EXTRN_MDL_LBCS_OFFSET_HRS or "3" + else: + EXTRN_MDL_LBCS_OFFSET_HRS=EXTRN_MDL_LBCS_OFFSET_HRS or "0" + + # export values we set above + env_vars = ["EXTRN_MDL_LBCS_OFFSET_HRS"] + export_vars(env_vars=env_vars) +# +#----------------------------------------------------------------------- +# +# Call the function defined above. +# +#----------------------------------------------------------------------- +# +if __name__ == "__main__": + set_extrn_mdl_params() + +class Testing(unittest.TestCase): + def test_extrn_mdl_params(self): + set_extrn_mdl_params() + EXTRN_MDL_LBCS_OFFSET_HRS = get_env_var("EXTRN_MDL_LBCS_OFFSET_HRS") + self.assertEqual(EXTRN_MDL_LBCS_OFFSET_HRS,3) + + def setUp(self): + set_env_var("EXTRN_MDL_NAME_LBCS","RAP") + set_env_var("EXTRN_MDL_LBCS_OFFSET_HRS",None) diff --git a/ush/set_gridparams_ESGgrid.py b/ush/set_gridparams_ESGgrid.py new file mode 100644 index 0000000000..722c2f27e2 --- /dev/null +++ b/ush/set_gridparams_ESGgrid.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python3 + +import unittest +from datetime import datetime,timedelta + +from python_utils import import_vars, set_env_var, print_input_args + +def set_gridparams_ESGgrid(lon_ctr,lat_ctr,nx,ny,halo_width,delx,dely,pazi): + """ Sets the parameters for a grid that is to be generated using the "ESGgrid" + grid generation method (i.e. GRID_GEN_METHOD set to "ESGgrid"). + + Args: + lon_ctr + lat_ctr + nx + ny + halo_width + delx + dely + pazi + Returns: + Tuple of inputs, and 4 outputs (see return statement) + """ + + print_input_args(locals()) + + # get needed environment variables + IMPORTS = ['RADIUS_EARTH', 'DEGS_PER_RADIAN'] + import_vars(env_vars=IMPORTS) + # + #----------------------------------------------------------------------- + # + # For a ESGgrid-type grid, the orography filtering is performed by pass- + # ing to the orography filtering the parameters for an "equivalent" glo- + # bal uniform cubed-sphere grid. These are the parameters that a global + # uniform cubed-sphere grid needs to have in order to have a nominal + # grid cell size equal to that of the (average) cell size on the region- + # al grid. These globally-equivalent parameters include a resolution + # (in units of number of cells in each of the two horizontal directions) + # and a stretch factor. The equivalent resolution is calculated in the + # script that generates the grid, and the stretch factor needs to be set + # to 1 because we are considering an equivalent globally UNIFORM grid. + # However, it turns out that with a non-symmetric regional grid (one in + # which nx is not equal to ny), setting stretch_factor to 1 fails be- + # cause the orography filtering program is designed for a global cubed- + # sphere grid and thus assumes that nx and ny for a given tile are equal + # when stretch_factor is exactly equal to 1. + # ^^-- Why is this? Seems like symmetry btwn x and y should still hold when the stretch factor is not equal to 1. + # It turns out that the program will work if we set stretch_factor to a + # value that is not exactly 1. This is what we do below. + # + #----------------------------------------------------------------------- + # + stretch_factor=0.999 # Check whether the orography program has been fixed so that we can set this to 1... + # + #----------------------------------------------------------------------- + # + # Set parameters needed as inputs to the regional_grid grid generation + # code. + # + #----------------------------------------------------------------------- + # + del_angle_x_sg = (delx / (2.0 * RADIUS_EARTH)) * DEGS_PER_RADIAN + del_angle_y_sg = (dely / (2.0 * RADIUS_EARTH)) * DEGS_PER_RADIAN + neg_nx_of_dom_with_wide_halo = -(nx + 2 * halo_width) + neg_ny_of_dom_with_wide_halo = -(ny + 2 * halo_width) + # + #----------------------------------------------------------------------- + # + # return output variables. + # + #----------------------------------------------------------------------- + # + return (lon_ctr,lat_ctr,nx,ny,pazi,halo_width,stretch_factor, + del_angle_x_sg, + del_angle_y_sg, + int(neg_nx_of_dom_with_wide_halo), + int(neg_ny_of_dom_with_wide_halo)) + +class Testing(unittest.TestCase): + def test_set_gridparams_ESGgrid(self): + + (LON_CTR,LAT_CTR,NX,NY,PAZI,NHW,STRETCH_FAC, + DEL_ANGLE_X_SG, + DEL_ANGLE_Y_SG, + NEG_NX_OF_DOM_WITH_WIDE_HALO, + NEG_NY_OF_DOM_WITH_WIDE_HALO) = set_gridparams_ESGgrid( \ + lon_ctr=-97.5, + lat_ctr=38.5, + nx=1748, + ny=1038, + pazi=0.0, + halo_width=6, + delx=3000.0, + dely=3000.0) + + self.assertEqual(\ + (LON_CTR,LAT_CTR,NX,NY,PAZI,NHW,STRETCH_FAC, + round(DEL_ANGLE_X_SG,10), + round(DEL_ANGLE_Y_SG,10), + NEG_NX_OF_DOM_WITH_WIDE_HALO, + NEG_NY_OF_DOM_WITH_WIDE_HALO), + (-97.5, 38.5, 1748, 1038, 0.0, 6,0.999, + 0.0134894006, + 0.0134894006, + -1760, + -1050) + ) + + def setUp(self): + set_env_var('RADIUS_EARTH',6371200.0) + set_env_var('DEGS_PER_RADIAN',57.2957795131) + diff --git a/ush/set_gridparams_GFDLgrid.py b/ush/set_gridparams_GFDLgrid.py new file mode 100644 index 0000000000..40a74d8105 --- /dev/null +++ b/ush/set_gridparams_GFDLgrid.py @@ -0,0 +1,465 @@ +#!/usr/bin/env python3 + +import unittest + +from python_utils import import_vars, set_env_var, print_input_args, \ + print_info_msg, print_err_msg_exit + +def prime_factors(n): + i = 2 + factors = [] + while i * i <= n: + if n % i: + i += 1 + else: + n //= i + factors.append(i) + if n > 1: + factors.append(n) + return factors + +def set_gridparams_GFDLgrid(lon_of_t6_ctr, lat_of_t6_ctr, res_of_t6g, stretch_factor, + refine_ratio_t6g_to_t7g, + istart_of_t7_on_t6g, iend_of_t7_on_t6g, + jstart_of_t7_on_t6g, jend_of_t7_on_t6g): + """ Sets the parameters for a grid that is to be generated using the "GFDLgrid" + grid generation method (i.e. GRID_GEN_METHOD set to "ESGgrid"). + + Args: + lon_of_t6_ctr + lat_of_t6_ctr + res_of_t6g + stretch_factor + refine_ratio_t6g_to_t7g + istart_of_t7_on_t6g + iend_of_t7_on_t6g + jstart_of_t7_on_t6g + jend_of_t7_on_t6g): + Returns: + Tuple of inputs and outputs (see return statement) + """ + + print_input_args(locals()) + + # get needed environment variables + IMPORTS = ['VERBOSE', 'RUN_ENVIR', 'NH4'] + import_vars(env_vars=IMPORTS) + + # + #----------------------------------------------------------------------- + # + # To simplify the grid setup, we require that tile 7 be centered on tile + # 6. Note that this is not really a restriction because tile 6 can al- + # ways be moved so that it is centered on tile 7 [the location of tile 6 + # doesn't really matter because for a regional setup, the forecast model + # will only run on tile 7 (not on tiles 1-6)]. + # + # We now check that tile 7 is centered on tile 6 by checking (1) that + # the number of cells (on tile 6) between the left boundaries of these + # two tiles is equal to that between their right boundaries and (2) that + # the number of cells (on tile 6) between the bottom boundaries of these + # two tiles is equal to that between their top boundaries. If not, we + # print out an error message and exit. If so, we set the longitude and + # latitude of the center of tile 7 to those of tile 6 and continue. + # + #----------------------------------------------------------------------- + # + + nx_of_t6_on_t6g = res_of_t6g + ny_of_t6_on_t6g = res_of_t6g + + num_left_margin_cells_on_t6g = istart_of_t7_on_t6g - 1 + num_right_margin_cells_on_t6g = nx_of_t6_on_t6g - iend_of_t7_on_t6g + + # This if-statement can hopefully be removed once EMC agrees to make their + # GFDLgrid type grids (tile 7) symmetric about tile 6. + if RUN_ENVIR != "nco": + if num_left_margin_cells_on_t6g != num_right_margin_cells_on_t6g: + print_err_msg_exit(f''' + In order for tile 7 to be centered in the x direction on tile 6, the x- + direction tile 6 cell indices at which tile 7 starts and ends (given by + istart_of_t7_on_t6g and iend_of_t7_on_t6g, respectively) must be set + such that the number of tile 6 cells in the margin between the left + boundaries of tiles 6 and 7 (given by num_left_margin_cells_on_t6g) is + equal to that in the margin between their right boundaries (given by + num_right_margin_cells_on_t6g): + istart_of_t7_on_t6g = {istart_of_t7_on_t6g} + iend_of_t7_on_t6g = {iend_of_t7_on_t6g} + num_left_margin_cells_on_t6g = {num_left_margin_cells_on_t6g} + num_right_margin_cells_on_t6g = {num_right_margin_cells_on_t6g} + Note that the total number of cells in the x-direction on tile 6 is gi- + ven by: + nx_of_t6_on_t6g = {nx_of_t6_on_t6g} + Please reset istart_of_t7_on_t6g and iend_of_t7_on_t6g and rerun.''') + + num_bot_margin_cells_on_t6g = jstart_of_t7_on_t6g - 1 + num_top_margin_cells_on_t6g = ny_of_t6_on_t6g - jend_of_t7_on_t6g + + # This if-statement can hopefully be removed once EMC agrees to make their + # GFDLgrid type grids (tile 7) symmetric about tile 6. + if RUN_ENVIR != "nco": + if num_bot_margin_cells_on_t6g != num_top_margin_cells_on_t6g: + print_err_msg_exit(f''' + In order for tile 7 to be centered in the y direction on tile 6, the y- + direction tile 6 cell indices at which tile 7 starts and ends (given by + jstart_of_t7_on_t6g and jend_of_t7_on_t6g, respectively) must be set + such that the number of tile 6 cells in the margin between the left + boundaries of tiles 6 and 7 (given by num_left_margin_cells_on_t6g) is + equal to that in the margin between their right boundaries (given by + num_right_margin_cells_on_t6g): + jstart_of_t7_on_t6g = {jstart_of_t7_on_t6g} + jend_of_t7_on_t6g = {jend_of_t7_on_t6g} + num_bot_margin_cells_on_t6g = {num_bot_margin_cells_on_t6g} + num_top_margin_cells_on_t6g = {num_top_margin_cells_on_t6g} + Note that the total number of cells in the y-direction on tile 6 is gi- + ven by: + ny_of_t6_on_t6g = {ny_of_t6_on_t6g} + Please reset jstart_of_t7_on_t6g and jend_of_t7_on_t6g and rerun.''') + + lon_of_t7_ctr = lon_of_t6_ctr + lat_of_t7_ctr = lat_of_t6_ctr + # + #----------------------------------------------------------------------- + # + # The grid generation script grid_gen_scr called below in turn calls the + # make_hgrid utility/executable to construct the regional grid. make_- + # hgrid accepts as arguments the index limits (i.e. starting and ending + # indices) of the regional grid on the supergrid of the regional grid's + # parent tile. The regional grid's parent tile is tile 6, and the su- + # pergrid of any given tile is defined as the grid obtained by doubling + # the number of cells in each direction on that tile's grid. We will + # denote these index limits by + # + # istart_of_t7_on_t6sg + # iend_of_t7_on_t6sg + # jstart_of_t7_on_t6sg + # jend_of_t7_on_t6sg + # + # The "_T6SG" suffix in these names is used to indicate that the indices + # are on the supergrid of tile 6. Recall, however, that we have as in- + # puts the index limits of the regional grid on the tile 6 grid, not its + # supergrid. These are given by + # + # istart_of_t7_on_t6g + # iend_of_t7_on_t6g + # jstart_of_t7_on_t6g + # jend_of_t7_on_t6g + # + # We can obtain the former from the latter by recalling that the super- + # grid has twice the resolution of the original grid. Thus, + # + # istart_of_t7_on_t6sg = 2*istart_of_t7_on_t6g - 1 + # iend_of_t7_on_t6sg = 2*iend_of_t7_on_t6g + # jstart_of_t7_on_t6sg = 2*jstart_of_t7_on_t6g - 1 + # jend_of_t7_on_t6sg = 2*jend_of_t7_on_t6g + # + # These are obtained assuming that grid cells on tile 6 must either be + # completely within the regional domain or completely outside of it, + # i.e. the boundary of the regional grid must coincide with gridlines + # on the tile 6 grid; it cannot cut through tile 6 cells. (Note that + # this implies that the starting indices on the tile 6 supergrid must be + # odd while the ending indices must be even; the above expressions sa- + # tisfy this requirement.) We perfrom these calculations next. + # + #----------------------------------------------------------------------- + # + istart_of_t7_on_t6sg = 2*istart_of_t7_on_t6g - 1 + iend_of_t7_on_t6sg = 2*iend_of_t7_on_t6g + jstart_of_t7_on_t6sg = 2*jstart_of_t7_on_t6g - 1 + jend_of_t7_on_t6sg = 2*jend_of_t7_on_t6g + # + #----------------------------------------------------------------------- + # + # If we simply pass to make_hgrid the index limits of the regional grid + # on the tile 6 supergrid calculated above, make_hgrid will generate a + # regional grid without a halo. To obtain a regional grid with a halo, + # we must pass to make_hgrid the index limits (on the tile 6 supergrid) + # of the regional grid including a halo. We will let the variables + # + # istart_of_t7_with_halo_on_t6sg + # iend_of_t7_with_halo_on_t6sg + # jstart_of_t7_with_halo_on_t6sg + # jend_of_t7_with_halo_on_t6sg + # + # denote these limits. The reason we include "_wide_halo" in these va- + # riable names is that the halo of the grid that we will first generate + # will be wider than the halos that are actually needed as inputs to the + # FV3LAM model (i.e. the 0-cell-wide, 3-cell-wide, and 4-cell-wide halos + # described above). We will generate the grids with narrower halos that + # the model needs later on by "shaving" layers of cells from this wide- + # halo grid. Next, we describe how to calculate the above indices. + # + # Let halo_width_on_t7g denote the width of the "wide" halo in units of number of + # grid cells on the regional grid (i.e. tile 7) that we'd like to have + # along all four edges of the regional domain (left, right, bottom, and + # top). To obtain the corresponding halo width in units of number of + # cells on the tile 6 grid -- which we denote by halo_width_on_t6g -- we simply di- + # vide halo_width_on_t7g by the refinement ratio, i.e. + # + # halo_width_on_t6g = halo_width_on_t7g/refine_ratio_t6g_to_t7g + # + # The corresponding halo width on the tile 6 supergrid is then given by + # + # halo_width_on_t6sg = 2*halo_width_on_t6g + # = 2*halo_width_on_t7g/refine_ratio_t6g_to_t7g + # + # Note that halo_width_on_t6sg must be an integer, but the expression for it de- + # rived above may not yield an integer. To ensure that the halo has a + # width of at least halo_width_on_t7g cells on the regional grid, we round up the + # result of the expression above for halo_width_on_t6sg, i.e. we redefine halo_width_on_t6sg + # to be + # + # halo_width_on_t6sg = ceil(2*halo_width_on_t7g/refine_ratio_t6g_to_t7g) + # + # where ceil(...) is the ceiling function, i.e. it rounds its floating + # point argument up to the next larger integer. Since in bash division + # of two integers returns a truncated integer and since bash has no + # built-in ceil(...) function, we perform the rounding-up operation by + # adding the denominator (of the argument of ceil(...) above) minus 1 to + # the original numerator, i.e. by redefining halo_width_on_t6sg to be + # + # halo_width_on_t6sg = (2*halo_width_on_t7g + refine_ratio_t6g_to_t7g - 1)/refine_ratio_t6g_to_t7g + # + # This trick works when dividing one positive integer by another. + # + # In order to calculate halo_width_on_t6g using the above expression, we must + # first specify halo_width_on_t7g. Next, we specify an initial value for it by + # setting it to one more than the largest-width halo that the model ac- + # tually needs, which is NH4. We then calculate halo_width_on_t6sg using the + # above expression. Note that these values of halo_width_on_t7g and halo_width_on_t6sg will + # likely not be their final values; their final values will be calcula- + # ted later below after calculating the starting and ending indices of + # the regional grid with wide halo on the tile 6 supergrid and then ad- + # justing the latter to satisfy certain conditions. + # + #----------------------------------------------------------------------- + # + halo_width_on_t7g = NH4 + 1 + halo_width_on_t6sg = (2*halo_width_on_t7g + refine_ratio_t6g_to_t7g - 1)/refine_ratio_t6g_to_t7g + # + #----------------------------------------------------------------------- + # + # With an initial value of halo_width_on_t6sg now available, we can obtain the + # tile 6 supergrid index limits of the regional domain (including the + # wide halo) from the index limits for the regional domain without a ha- + # lo by simply subtracting halo_width_on_t6sg from the lower index limits and add- + # ing halo_width_on_t6sg to the upper index limits, i.e. + # + # istart_of_t7_with_halo_on_t6sg = istart_of_t7_on_t6sg - halo_width_on_t6sg + # iend_of_t7_with_halo_on_t6sg = iend_of_t7_on_t6sg + halo_width_on_t6sg + # jstart_of_t7_with_halo_on_t6sg = jstart_of_t7_on_t6sg - halo_width_on_t6sg + # jend_of_t7_with_halo_on_t6sg = jend_of_t7_on_t6sg + halo_width_on_t6sg + # + # We calculate these next. + # + #----------------------------------------------------------------------- + # + istart_of_t7_with_halo_on_t6sg = int(istart_of_t7_on_t6sg - halo_width_on_t6sg) + iend_of_t7_with_halo_on_t6sg = int(iend_of_t7_on_t6sg + halo_width_on_t6sg) + jstart_of_t7_with_halo_on_t6sg = int(jstart_of_t7_on_t6sg - halo_width_on_t6sg) + jend_of_t7_with_halo_on_t6sg = int(jend_of_t7_on_t6sg + halo_width_on_t6sg) + # + #----------------------------------------------------------------------- + # + # As for the regional grid without a halo, the regional grid with a wide + # halo that make_hgrid will generate must be such that grid cells on + # tile 6 either lie completely within this grid or outside of it, i.e. + # they cannot lie partially within/outside of it. This implies that the + # starting indices on the tile 6 supergrid of the grid with wide halo + # must be odd while the ending indices must be even. Thus, below, we + # subtract 1 from the starting indices if they are even (which ensures + # that there will be at least halo_width_on_t7g halo cells along the left and bot- + # tom boundaries), and we add 1 to the ending indices if they are odd + # (which ensures that there will be at least halo_width_on_t7g halo cells along the + # right and top boundaries). + # + #----------------------------------------------------------------------- + # + if istart_of_t7_with_halo_on_t6sg % 2 == 0: + istart_of_t7_with_halo_on_t6sg = istart_of_t7_with_halo_on_t6sg - 1 + + if iend_of_t7_with_halo_on_t6sg % 2 == 1: + iend_of_t7_with_halo_on_t6sg = iend_of_t7_with_halo_on_t6sg + 1 + + if jstart_of_t7_with_halo_on_t6sg % 2 == 0: + jstart_of_t7_with_halo_on_t6sg = jstart_of_t7_with_halo_on_t6sg - 1 + + if jend_of_t7_with_halo_on_t6sg % 2 == 1: + jend_of_t7_with_halo_on_t6sg = jend_of_t7_with_halo_on_t6sg + 1 + # + #----------------------------------------------------------------------- + # + # Now that the starting and ending tile 6 supergrid indices of the re- + # gional grid with the wide halo have been calculated (and adjusted), we + # recalculate the width of the wide halo on: + # + # 1) the tile 6 supergrid; + # 2) the tile 6 grid; and + # 3) the tile 7 grid. + # + # These are the final values of these quantities that are guaranteed to + # correspond to the starting and ending indices on the tile 6 supergrid. + # + #----------------------------------------------------------------------- + # + print_info_msg(f''' + Original values of the halo width on the tile 6 supergrid and on the + tile 7 grid are: + halo_width_on_t6sg = {halo_width_on_t6sg} + halo_width_on_t7g = {halo_width_on_t7g}''', verbose=VERBOSE) + + halo_width_on_t6sg = istart_of_t7_on_t6sg - istart_of_t7_with_halo_on_t6sg + halo_width_on_t6g = halo_width_on_t6sg//2 + halo_width_on_t7g = int(halo_width_on_t6g*refine_ratio_t6g_to_t7g) + + print_info_msg(f''' + Values of the halo width on the tile 6 supergrid and on the tile 7 grid + AFTER adjustments are: + halo_width_on_t6sg = {halo_width_on_t6sg} + halo_width_on_t7g = {halo_width_on_t7g}''', verbose=VERBOSE) + # + #----------------------------------------------------------------------- + # + # Calculate the number of cells that the regional domain (without halo) + # has in each of the two horizontal directions (say x and y). We denote + # these by nx_of_t7_on_t7g and ny_of_t7_on_t7g, respectively. These + # will be needed in the "shave" steps in the grid generation task of the + # workflow. + # + #----------------------------------------------------------------------- + # + nx_of_t7_on_t6sg = iend_of_t7_on_t6sg - istart_of_t7_on_t6sg + 1 + nx_of_t7_on_t6g = nx_of_t7_on_t6sg/2 + nx_of_t7_on_t7g = int(nx_of_t7_on_t6g*refine_ratio_t6g_to_t7g) + + ny_of_t7_on_t6sg = jend_of_t7_on_t6sg - jstart_of_t7_on_t6sg + 1 + ny_of_t7_on_t6g = ny_of_t7_on_t6sg/2 + ny_of_t7_on_t7g = int(ny_of_t7_on_t6g*refine_ratio_t6g_to_t7g) + # + # The following are set only for informational purposes. + # + nx_of_t6_on_t6sg = 2*nx_of_t6_on_t6g + ny_of_t6_on_t6sg = 2*ny_of_t6_on_t6g + + prime_factors_nx_of_t7_on_t7g = prime_factors(nx_of_t7_on_t7g) + prime_factors_ny_of_t7_on_t7g = prime_factors(ny_of_t7_on_t7g) + + print_info_msg(f''' + The number of cells in the two horizontal directions (x and y) on the + parent tile's (tile 6) grid and supergrid are: + nx_of_t6_on_t6g = {nx_of_t6_on_t6g} + ny_of_t6_on_t6g = {ny_of_t6_on_t6g} + nx_of_t6_on_t6sg = {nx_of_t6_on_t6sg} + ny_of_t6_on_t6sg = {ny_of_t6_on_t6sg} + + The number of cells in the two horizontal directions on the tile 6 grid + and supergrid that the regional domain (tile 7) WITHOUT A HALO encompas- + ses are: + nx_of_t7_on_t6g = {nx_of_t7_on_t6g} + ny_of_t7_on_t6g = {ny_of_t7_on_t6g} + nx_of_t7_on_t6sg = {nx_of_t7_on_t6sg} + ny_of_t7_on_t6sg = {ny_of_t7_on_t6sg} + + The starting and ending i and j indices on the tile 6 grid used to gene- + rate this regional grid are: + istart_of_t7_on_t6g = {istart_of_t7_on_t6g} + iend_of_t7_on_t6g = {iend_of_t7_on_t6g} + jstart_of_t7_on_t6g = {jstart_of_t7_on_t6g} + jend_of_t7_on_t6g = {jend_of_t7_on_t6g} + + The corresponding starting and ending i and j indices on the tile 6 su- + pergrid are: + istart_of_t7_on_t6sg = {istart_of_t7_on_t6sg} + iend_of_t7_on_t6sg = {iend_of_t7_on_t6sg} + jstart_of_t7_on_t6sg = {jstart_of_t7_on_t6sg} + jend_of_t7_on_t6sg = {jend_of_t7_on_t6sg} + + The refinement ratio (ratio of the number of cells in tile 7 that abut + a single cell in tile 6) is: + refine_ratio_t6g_to_t7g = {refine_ratio_t6g_to_t7g} + + The number of cells in the two horizontal directions on the regional do- + main's (i.e. tile 7's) grid WITHOUT A HALO are: + nx_of_t7_on_t7g = {nx_of_t7_on_t7g} + ny_of_t7_on_t7g = {ny_of_t7_on_t7g} + + The prime factors of nx_of_t7_on_t7g and ny_of_t7_on_t7g are (useful for + determining an MPI task layout): + prime_factors_nx_of_t7_on_t7g: {prime_factors_nx_of_t7_on_t7g} + prime_factors_ny_of_t7_on_t7g: {prime_factors_ny_of_t7_on_t7g}''', verbose=VERBOSE) + # + #----------------------------------------------------------------------- + # + # For informational purposes, calculate the number of cells in each di- + # rection on the regional grid including the wide halo (of width halo_- + # width_on_t7g cells). We denote these by nx_of_t7_with_halo_on_t7g and + # ny_of_t7_with_halo_on_t7g, respectively. + # + #----------------------------------------------------------------------- + # + nx_of_t7_with_halo_on_t6sg = iend_of_t7_with_halo_on_t6sg - istart_of_t7_with_halo_on_t6sg + 1 + nx_of_t7_with_halo_on_t6g = nx_of_t7_with_halo_on_t6sg/2 + nx_of_t7_with_halo_on_t7g = nx_of_t7_with_halo_on_t6g*refine_ratio_t6g_to_t7g + + ny_of_t7_with_halo_on_t6sg = jend_of_t7_with_halo_on_t6sg - jstart_of_t7_with_halo_on_t6sg + 1 + ny_of_t7_with_halo_on_t6g = ny_of_t7_with_halo_on_t6sg/2 + ny_of_t7_with_halo_on_t7g = ny_of_t7_with_halo_on_t6g*refine_ratio_t6g_to_t7g + + print_info_msg(f''' + nx_of_t7_with_halo_on_t7g = {nx_of_t7_with_halo_on_t7g} + (istart_of_t7_with_halo_on_t6sg = {istart_of_t7_with_halo_on_t6sg}, + iend_of_t7_with_halo_on_t6sg = {iend_of_t7_with_halo_on_t6sg})''', verbose=VERBOSE) + + print_info_msg(f''' + ny_of_t7_with_halo_on_t7g = {ny_of_t7_with_halo_on_t7g} + (jstart_of_t7_with_halo_on_t6sg = {jstart_of_t7_with_halo_on_t6sg}, + jend_of_t7_with_halo_on_t6sg = {jend_of_t7_with_halo_on_t6sg})''', verbose=VERBOSE) + # + #----------------------------------------------------------------------- + # + # Return output variables. + # + #----------------------------------------------------------------------- + # + return (lon_of_t7_ctr, lat_of_t7_ctr, nx_of_t7_on_t7g, ny_of_t7_on_t7g, + halo_width_on_t7g, stretch_factor, + istart_of_t7_with_halo_on_t6sg, + iend_of_t7_with_halo_on_t6sg, + jstart_of_t7_with_halo_on_t6sg, + jend_of_t7_with_halo_on_t6sg) + +class Testing(unittest.TestCase): + def test_set_gridparams_GFDLgrid(self): + (LON_CTR,LAT_CTR,NX,NY,NHW,STRETCH_FAC, + ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG) = set_gridparams_GFDLgrid( \ + lon_of_t6_ctr=-97.5, \ + lat_of_t6_ctr=38.5, \ + res_of_t6g=96, \ + stretch_factor=1.4, \ + refine_ratio_t6g_to_t7g=3, \ + istart_of_t7_on_t6g=13, \ + iend_of_t7_on_t6g=84, \ + jstart_of_t7_on_t6g=17, \ + jend_of_t7_on_t6g=80) + + self.assertEqual(\ + (LON_CTR,LAT_CTR,NX,NY,NHW,STRETCH_FAC, + ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG), + (-97.5,38.5,216,192,6,1.4, + 21, + 172, + 29, + 164) + ) + + def setUp(self): + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + set_env_var('NH4', 4) + diff --git a/ush/set_namelist.py b/ush/set_namelist.py new file mode 100755 index 0000000000..84c61975ec --- /dev/null +++ b/ush/set_namelist.py @@ -0,0 +1,333 @@ +#!/usr/bin/env python3 + +''' +This utility updates a Fortran namelist file using the f90nml package. The +settings that are modified are supplied via command line YAML-formatted string +and/or YAML configuration files. + +Additionally, the tool can be used to create a YAML file from an input namelist, +or the difference between two namelists. + +The user configuration file should contain a heirarchy that follows the +heirarchy for the Fortran namelist. An example of modifying an FV3 namelist: + + Configuration file contains: + + fv_core_nml: + k_split: 4 + n_split: 5 + + gfs_physics_nml: + do_sppt: True + +The output namelist will differ from the input namelist by only these three +settings. If one of these sections and/or variables did not previously exist, it +will be automatically created. It is up to the user to ensure that configuration +settings are provided under the correct sections and variable names. + +The optional base configuration file (provided via the -c command line argument) +contains the known set of configurations used and supported by the community, if +using the one provided in ush/templates/FV3.input.yml. If maintaining this file +for a different set of configurations, ensure that the heirarchy is such that it +names the configuration at the top level (section), and the subsequent sections +match those in the F90 namelist that will be updated. + +Examples + + To show help options: + + set_namelist.py -h + + To produce a namelist (fv3_expt.nml) by specifying a physics package: + + set_namelist.py -n templates/input.nml.FV3 -c templates/FV3.input.yml FV3_HRRR + -o fv3_expt.nml + + To produce a YAML file (fv3_namelist.yml) from a user namelist: + + set_namelist.py -i my_namelist.nml -o fv3_namelist.nml -t yaml + + To produce a YAML file (fv3_my_namelist.yml) with differences from base nml: + + set_namelist.py -n templates/input.nml.FV3 -i my_namelist.nml -t yaml + -o fv3_my_namelist.nml + +Expected behavior: + + - A Fortran namelist that contains only user-defined settings will be + generated if no input namelist is provided. + - An unmodified copy of an input namelist will be generated in the + designated output location if no user-settings are provided. + - Command-line-entered settings over-ride settings in YAML configuration + file. + - Given a user namelist, the script can dump a YAML file. + - Given a user namelist and a base namelist, the script can dump the + difference in the two to a YAML file that can be included as a section + in the supported configs. +''' + +import argparse +import collections +import os +import sys + +import f90nml +import yaml + + +def config_exists(arg): + + ''' + Checks whether the config file exists and if it contains the input + section. Returns the arg as provided if checks are passed. + ''' + + # Agument is expected to be a 2-item list of file name and internal section + # name. + file_name = arg[0] + section_name = arg[1] + + file_exists(file_name) + + # Load the YAML file into a dictionary + with open(file_name, 'r') as fn: + cfg = yaml.load(fn, Loader=yaml.Loader) + + # Grab only the section that is specified by the user + try: + cfg = cfg[section_name] + except KeyError: + msg = f'Section {section_name} does not exist in top level of {file_name}' + raise argparse.ArgumentTypeError(msg) + + return [cfg, section_name] + +def file_exists(arg): + + ''' Check for existence of file ''' + + if not os.path.exists(arg): + msg = f'{arg} does not exist!' + raise argparse.ArgumentTypeError(msg) + + return arg + +def load_config(arg): + + ''' + Check to ensure that the provided config file exists. If it does, load it + with YAML's safe loader and return the resulting dict. + ''' + + return yaml.safe_load(arg) + +def path_ok(arg): + + ''' + Check whether the path to the file exists, and is writeable. Return the path + if it passes all checks, otherwise raise an error. + ''' + + # Get the absolute path provided by arg + dir_name = os.path.abspath(os.path.dirname(arg)) + + # Ensure the arg path exists, and is writable. Raise error if not. + if os.path.lexists(dir_name) and os.access(dir_name, os.W_OK): + return arg + + msg = f'{arg} is not a writable path!' + raise argparse.ArgumentTypeError(msg) + +def parse_args(argv): + + ''' + Function maintains the arguments accepted by this script. Please see + Python's argparse documenation for more information about settings of each + argument. + ''' + + parser = argparse.ArgumentParser( + description='Update a Fortran namelist with user-defined settings.' + ) + + # Required + parser.add_argument('-o', '--outfile', + help='Required: Full path to output file. This is a \ + namelist by default.', + required=True, + type=path_ok, + ) + + # Optional + parser.add_argument('-c', '--config', + help='Full path to a YAML config file containing multiple \ + configurations, and the top-level section to use. Optional.', + metavar=('[FILE,', 'SECTION]'), + nargs=2, + ) + parser.add_argument('-i', '--input_nml', + help='Path to a user namelist. Use with -n and \ + -t yaml to get a YAML file to use with workflow.', + type=file_exists, + ) + parser.add_argument('-n', '--basenml', + dest='nml', + help='Full path to the input Fortran namelist. Optional.', + type=file_exists, + ) + parser.add_argument('-t', '--type', + choices=['nml', 'yaml'], + default='nml', + help='Output file type.', + ) + parser.add_argument('-u', '--user_config', + help='Command-line user config options in YAML-formatted \ + string. These options will override any provided in an \ + input file. Optional.', + metavar='YAML STRING', + type=load_config, + ) + + # Flags + parser.add_argument('-q', '--quiet', + action='store_true', + help='If provided, suppress all output.', + ) + return parser.parse_args(argv) + +def dict_diff(dict1, dict2): + + ''' + Produces a dictionary of how dict2 differs from dict1 + ''' + + diffs = {} + + # Loop through dict1 sections and key/value pairs + for sect, items in dict1.items(): + for key, val in items.items(): + + # If dict 2 has a different value, record the dict2 value + if val != dict2.get(sect, {}).get(key, ''): + if not diffs.get(sect): + diffs[sect] = {} + diffs[sect][key] = dict2.get(sect, {}).get(key) + + # Loop through dict2 sections and key/value pairs to catch any settings that + # may be present in the 2nd dict that weren't in the first. + for sect, items in dict2.items(): + for key, val in items.items(): + + # If dict1 has a diffent value than dict2, record the dict2 value + if val != dict1.get(sect, {}).get(key, ''): + + # Check to make sure it hasn't already been recorded + if diffs.get(sect, {}).get(key, 'DNE') == 'DNE': + if not diffs.get(sect): + diffs[sect] = {} + diffs[sect][key] = val + return diffs + +def to_dict(odict): + + ''' Recursively convert OrderedDict to Python dict. ''' + + if not isinstance(odict, collections.OrderedDict): + return odict + + ret = dict(odict) + for key, value in ret.items(): + if isinstance(value, collections.OrderedDict): + ret[key] = to_dict(value) + return ret + +def update_dict(dest, newdict, quiet=False): + + ''' + Overwrites all values in dest dictionary with values from newdict. Turn off + print statements with queit=True. + + Input: + + dest A dict that is to be updated. + newdict A dict containing sections and keys corresponding to + those in dest and potentially additional ones, that will be used to + update the dest dict. + quiet An optional boolean flag to turn off output. + + Output: + + None + + Result: + + The dest dict is updated in place. + ''' + + for sect, values in newdict: + # If section is set to None, remove all contents from namelist + if values is None: + dest[sect] = {} + else: + for key, value in values.items(): + if not quiet: + print(f'Setting {sect}.{key} = {value}') + + # Remove key from dict if config is set to None + if value is None: + _ = dest[sect].pop(key, None) + else: + + try: + dest[sect][key] = value + except KeyError: + # Namelist section did not exist. Create it and update the value. + dest[sect] = {} + dest[sect][key] = value + +def set_namelist(argv): + + ''' Using input command line arguments (cla), update a Fortran namelist file. ''' + + # parse argumetns + cla = parse_args(argv) + if cla.config: + cla.config, _ = config_exists(cla.config) + + # Load base namelist into dict + nml = f90nml.Namelist() + if cla.nml is not None: + nml = f90nml.read(cla.nml) + + # Update namelist settings (nml) with config file settings (cfg) + cfg = {} + if cla.config is not None: + cfg = cla.config + update_dict(nml, cfg.items(), quiet=cla.quiet) + + # Update nml, overriding YAML if needed, with any command-line entries + if cla.user_config: + update_dict(nml, cla.user_config.items(), quiet=cla.quiet) + + # Write the resulting file + with open(cla.outfile, 'w') as fn: + if cla.type == 'nml': + nml.write(fn, sort=True) + + if cla.type == 'yaml': + if cla.input_nml: + input_nml = f90nml.read(cla.input_nml) + + # Determine how input_nml differs from the configured namelist + diff = dict_diff(nml, input_nml) + + # Write diffs to YAML file + yaml.dump(diff, fn) + + else: + # Write the namelist to YAML file + yaml.dump(to_dict(nml.todict()), fn) + + +if __name__ == '__main__': + set_namelist(sys.argv[1:]) diff --git a/ush/set_ozone_param.py b/ush/set_ozone_param.py new file mode 100644 index 0000000000..4c9998c3ca --- /dev/null +++ b/ush/set_ozone_param.py @@ -0,0 +1,231 @@ +#!/usr/bin/env python3 + +import os +import unittest +from textwrap import dedent + +from python_utils import import_vars,export_vars,set_env_var,list_to_str,\ + print_input_args, print_info_msg, print_err_msg_exit,\ + define_macos_utilities,load_xml_file,has_tag_with_value,find_pattern_in_str + +def set_ozone_param(ccpp_phys_suite_fp): + """ Function that does the following: + (1) Determines the ozone parameterization being used by checking in the + CCPP physics suite XML. + + (2) Sets the name of the global ozone production/loss file in the FIXgsm + FIXgsm system directory to copy to the experiment's FIXam directory. + + (3) Resets the last element of the workflow array variable + FIXgsm_FILES_TO_COPY_TO_FIXam that contains the files to copy from + FIXgsm to FIXam (this last element is initially set to a dummy + value) to the name of the ozone production/loss file set in the + previous step. + + (4) Resets the element of the workflow array variable + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING (this array contains the + mapping between the symlinks to create in any cycle directory and + the files in the FIXam directory that are their targets) that + specifies the mapping for the ozone symlink/file such that the + target FIXam file name is set to the name of the ozone production/ + loss file set above. + + Args: + ccpp_phys_suite_fp: full path to CCPP physics suite + Returns: + ozone_param: a string + """ + + print_input_args(locals()) + + # import all environment variables + import_vars() + + # + #----------------------------------------------------------------------- + # + # Get the name of the ozone parameterization being used. There are two + # possible ozone parameterizations: + # + # (1) A parameterization developed/published in 2015. Here, we refer to + # this as the 2015 parameterization. If this is being used, then we + # set the variable ozone_param to the string "ozphys_2015". + # + # (2) A parameterization developed/published sometime after 2015. Here, + # we refer to this as the after-2015 parameterization. If this is + # being used, then we set the variable ozone_param to the string + # "ozphys". + # + # We check the CCPP physics suite definition file (SDF) to determine the + # parameterization being used. If this file contains the line + # + # ozphys_2015 + # + # then the 2015 parameterization is being used. If it instead contains + # the line + # + # ozphys + # + # then the after-2015 parameterization is being used. (The SDF should + # contain exactly one of these lines; not both nor neither; we check for + # this.) + # + #----------------------------------------------------------------------- + # + tree = load_xml_file(ccpp_phys_suite_fp) + ozone_param = "" + if has_tag_with_value(tree, "scheme", "ozphys_2015"): + fixgsm_ozone_fn="ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77" + ozone_param = "ozphys_2015" + elif has_tag_with_value(tree, "scheme", "ozphys"): + fixgsm_ozone_fn="global_o3prdlos.f77" + ozone_param = "ozphys" + else: + print_err_msg_exit(f''' + Unknown or no ozone parameterization + specified in the CCPP physics suite file (ccpp_phys_suite_fp): + ccpp_phys_suite_fp = \"{ccpp_phys_suite_fp}\" + ozone_param = \"{ozone_param}\"''') + # + #----------------------------------------------------------------------- + # + # Set the last element of the array FIXgsm_FILES_TO_COPY_TO_FIXam to the + # name of the ozone production/loss file to copy from the FIXgsm to the + # FIXam directory. + # + #----------------------------------------------------------------------- + # + i=len(FIXgsm_FILES_TO_COPY_TO_FIXam) - 1 + FIXgsm_FILES_TO_COPY_TO_FIXam[i]=f"{fixgsm_ozone_fn}" + # + #----------------------------------------------------------------------- + # + # Set the element in the array CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING that + # specifies the mapping between the symlink for the ozone production/loss + # file that must be created in each cycle directory and its target in the + # FIXam directory. The name of the symlink is alrady in the array, but + # the target is not because it depends on the ozone parameterization that + # the physics suite uses. Since we determined the ozone parameterization + # above, we now set the target of the symlink accordingly. + # + #----------------------------------------------------------------------- + # + ozone_symlink="global_o3prdlos.f77" + fixgsm_ozone_fn_is_set=False + regex_search="^[ ]*([^| ]*)[ ]*[|][ ]*([^| ]*)[ ]*$" + num_symlinks=len(CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING) + + for i in range(num_symlinks): + mapping=CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING[i] + symlink = find_pattern_in_str(regex_search, mapping) + if symlink is not None: + symlink = symlink[0] + if symlink == ozone_symlink: + regex_search="^[ ]*([^| ]+[ ]*)[|][ ]*([^| ]*)[ ]*$" + mapping_ozone = find_pattern_in_str(regex_search, mapping)[0] + mapping_ozone=f"{mapping_ozone}| {fixgsm_ozone_fn}" + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING[i]=f"{mapping_ozone}" + fixgsm_ozone_fn_is_set=True + break + # + #----------------------------------------------------------------------- + # + # If fixgsm_ozone_fn_is_set is set to True, then the appropriate element + # of the array CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING was set successfully. + # In this case, print out the new version of this array. Otherwise, print + # out an error message and exit. + # + #----------------------------------------------------------------------- + # + if fixgsm_ozone_fn_is_set: + + msg=dedent(f''' + After setting the file name of the ozone production/loss file in the + FIXgsm directory (based on the ozone parameterization specified in the + CCPP suite definition file), the array specifying the mapping between + the symlinks that need to be created in the cycle directories and the + files in the FIXam directory is: + + ''') + msg+=dedent(f''' + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING = {list_to_str(CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING)} + ''') + print_info_msg(msg,verbose=VERBOSE) + + else: + + print_err_msg_exit(f''' + Unable to set name of the ozone production/loss file in the FIXgsm directory + in the array that specifies the mapping between the symlinks that need to + be created in the cycle directories and the files in the FIXgsm directory: + fixgsm_ozone_fn_is_set = \"{fixgsm_ozone_fn_is_set}\"''') + + EXPORTS = ["CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING", "FIXgsm_FILES_TO_COPY_TO_FIXam"] + export_vars(env_vars=EXPORTS) + + return ozone_param + +class Testing(unittest.TestCase): + def test_set_ozone_param(self): + self.assertEqual( "ozphys_2015", + set_ozone_param(ccpp_phys_suite_fp=f"test_data{os.sep}suite_FV3_GSD_SAR.xml") ) + def setUp(self): + define_macos_utilities(); + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING = [ + "aerosol.dat | global_climaeropac_global.txt", + "co2historicaldata_2010.txt | fix_co2_proj/global_co2historicaldata_2010.txt", + "co2historicaldata_2011.txt | fix_co2_proj/global_co2historicaldata_2011.txt", + "co2historicaldata_2012.txt | fix_co2_proj/global_co2historicaldata_2012.txt", + "co2historicaldata_2013.txt | fix_co2_proj/global_co2historicaldata_2013.txt", + "co2historicaldata_2014.txt | fix_co2_proj/global_co2historicaldata_2014.txt", + "co2historicaldata_2015.txt | fix_co2_proj/global_co2historicaldata_2015.txt", + "co2historicaldata_2016.txt | fix_co2_proj/global_co2historicaldata_2016.txt", + "co2historicaldata_2017.txt | fix_co2_proj/global_co2historicaldata_2017.txt", + "co2historicaldata_2018.txt | fix_co2_proj/global_co2historicaldata_2018.txt", + "co2historicaldata_2019.txt | fix_co2_proj/global_co2historicaldata_2019.txt", + "co2historicaldata_2020.txt | fix_co2_proj/global_co2historicaldata_2020.txt", + "co2historicaldata_2021.txt | fix_co2_proj/global_co2historicaldata_2021.txt", + "co2historicaldata_glob.txt | global_co2historicaldata_glob.txt", + "co2monthlycyc.txt | co2monthlycyc.txt", + "global_h2oprdlos.f77 | global_h2o_pltc.f77", + "global_zorclim.1x1.grb | global_zorclim.1x1.grb", + "sfc_emissivity_idx.txt | global_sfc_emissivity_idx.txt", + "solarconstant_noaa_an.txt | global_solarconstant_noaa_an.txt", + "global_o3prdlos.f77 | ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77"] + FIXgsm_FILES_TO_COPY_TO_FIXam = [ + "global_glacier.2x2.grb", + "global_maxice.2x2.grb", + "RTGSST.1982.2012.monthly.clim.grb", + "global_snoclim.1.875.grb", + "CFSR.SEAICE.1982.2012.monthly.clim.grb", + "global_soilmgldas.t126.384.190.grb", + "seaice_newland.grb", + "global_climaeropac_global.txt", + "fix_co2_proj/global_co2historicaldata_2010.txt", + "fix_co2_proj/global_co2historicaldata_2011.txt", + "fix_co2_proj/global_co2historicaldata_2012.txt", + "fix_co2_proj/global_co2historicaldata_2013.txt", + "fix_co2_proj/global_co2historicaldata_2014.txt", + "fix_co2_proj/global_co2historicaldata_2015.txt", + "fix_co2_proj/global_co2historicaldata_2016.txt", + "fix_co2_proj/global_co2historicaldata_2017.txt", + "fix_co2_proj/global_co2historicaldata_2018.txt", + "fix_co2_proj/global_co2historicaldata_2019.txt", + "fix_co2_proj/global_co2historicaldata_2020.txt", + "fix_co2_proj/global_co2historicaldata_2021.txt", + "global_co2historicaldata_glob.txt", + "co2monthlycyc.txt", + "global_h2o_pltc.f77", + "global_hyblev.l65.txt", + "global_zorclim.1x1.grb", + "global_sfc_emissivity_idx.txt", + "global_solarconstant_noaa_an.txt", + "geo_em.d01.lat-lon.2.5m.HGT_M.nc", + "HGT.Beljaars_filtered.lat-lon.30s_res.nc", + "ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77"] + + set_env_var('CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING', CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING) + set_env_var('FIXgsm_FILES_TO_COPY_TO_FIXam', FIXgsm_FILES_TO_COPY_TO_FIXam) diff --git a/ush/set_predef_grid_params.py b/ush/set_predef_grid_params.py new file mode 100644 index 0000000000..970187e1de --- /dev/null +++ b/ush/set_predef_grid_params.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import unittest +import os + +from python_utils import process_args,import_vars,export_vars,set_env_var,get_env_var,\ + print_input_args,define_macos_utilities, load_config_file, \ + cfg_to_yaml_str + +def set_predef_grid_params(): + """ Sets grid parameters for the specified predfined grid + + Args: + None + Returns: + None + """ + # import all environement variables + IMPORTS = ['PREDEF_GRID_NAME', 'QUILTING', 'DT_ATMOS', 'LAYOUT_X', 'LAYOUT_Y', 'BLOCKSIZE'] + import_vars(env_vars=IMPORTS) + + USHDIR = os.path.dirname(os.path.abspath(__file__)) + params_dict = load_config_file(os.path.join(USHDIR,"predef_grid_params.yaml")) + params_dict = params_dict[PREDEF_GRID_NAME] + + # if QUILTING = False, skip variables that start with "WRTCMP_" + if not QUILTING: + params_dict = {k: v for k,v in params_dict.items() \ + if not k.startswith("WRTCMP_") } + + # take care of special vars + special_vars = ['DT_ATMOS', 'LAYOUT_X', 'LAYOUT_Y', 'BLOCKSIZE'] + for var in special_vars: + if globals()[var] is not None: + params_dict[var] = globals()[var] + + # export variables to environment + export_vars(source_dict=params_dict) + + return params_dict + +if __name__ == "__main__": + params_dict = set_predef_grid_params() + print( cfg_to_shell_str(params_dict), end='' ) + +class Testing(unittest.TestCase): + def test_set_predef_grid_params(self): + set_predef_grid_params() + self.assertEqual(get_env_var('GRID_GEN_METHOD'),"ESGgrid") + self.assertEqual(get_env_var('ESGgrid_LON_CTR'),-97.5) + + def setUp(self): + define_macos_utilities(); + set_env_var('DEBUG',False) + set_env_var('PREDEF_GRID_NAME',"RRFS_CONUS_3km") + set_env_var('DT_ATMOS',36) + set_env_var('LAYOUT_X',18) + set_env_var('LAYOUT_Y',36) + set_env_var('BLOCKSIZE',28) + set_env_var('QUILTING',False) + diff --git a/ush/set_thompson_mp_fix_files.py b/ush/set_thompson_mp_fix_files.py new file mode 100644 index 0000000000..9a1703e098 --- /dev/null +++ b/ush/set_thompson_mp_fix_files.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python3 + +import os +import unittest +from textwrap import dedent + +from python_utils import import_vars,export_vars,set_env_var,list_to_str,\ + print_input_args,print_info_msg, print_err_msg_exit,\ + define_macos_utilities,load_xml_file,has_tag_with_value + +def set_thompson_mp_fix_files(ccpp_phys_suite_fp, thompson_mp_climo_fn): + """ Function that first checks whether the Thompson + microphysics parameterization is being called by the selected physics + suite. If not, it sets the output variable whose name is specified by + output_varname_sdf_uses_thompson_mp to "FALSE" and exits. If so, it + sets this variable to "TRUE" and modifies the workflow arrays + FIXgsm_FILES_TO_COPY_TO_FIXam and CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING + to ensure that fixed files needed by the Thompson microphysics + parameterization are copied to the FIXam directory and that appropriate + symlinks to these files are created in the run directories. + + Args: + ccpp_phys_suite_fp: full path to CCPP physics suite + thompson_mp_climo_fn: netcdf file for thompson microphysics + Returns: + boolean: sdf_uses_thompson_mp + """ + + print_input_args(locals()) + + # import all environment variables + import_vars() + + # + #----------------------------------------------------------------------- + # + # Check the suite definition file to see whether the Thompson microphysics + # parameterization is being used. + # + #----------------------------------------------------------------------- + # + tree = load_xml_file(ccpp_phys_suite_fp) + sdf_uses_thompson_mp = has_tag_with_value(tree, "scheme", "mp_thompson") + # + #----------------------------------------------------------------------- + # + # If the Thompson microphysics parameterization is being used, then... + # + #----------------------------------------------------------------------- + # + if sdf_uses_thompson_mp: + # + #----------------------------------------------------------------------- + # + # Append the names of the fixed files needed by the Thompson microphysics + # parameterization to the workflow array FIXgsm_FILES_TO_COPY_TO_FIXam, + # and append to the workflow array CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING + # the mappings between these files and the names of the corresponding + # symlinks that need to be created in the run directories. + # + #----------------------------------------------------------------------- + # + thompson_mp_fix_files=[ + "CCN_ACTIVATE.BIN", + "freezeH2O.dat", + "qr_acr_qg.dat", + "qr_acr_qs.dat", + "qr_acr_qgV2.dat", + "qr_acr_qsV2.dat" + ] + + if (EXTRN_MDL_NAME_ICS != "HRRR" and EXTRN_MDL_NAME_ICS != "RAP") or \ + (EXTRN_MDL_NAME_LBCS != "HRRR" and EXTRN_MDL_NAME_LBCS != "RAP"): + thompson_mp_fix_files.append(thompson_mp_climo_fn) + + FIXgsm_FILES_TO_COPY_TO_FIXam.extend(thompson_mp_fix_files) + + for fix_file in thompson_mp_fix_files: + mapping=f"{fix_file} | {fix_file}" + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING.append(mapping) + + msg=dedent(f''' + Since the Thompson microphysics parameterization is being used by this + physics suite (CCPP_PHYS_SUITE), the names of the fixed files needed by + this scheme have been appended to the array FIXgsm_FILES_TO_COPY_TO_FIXam, + and the mappings between these files and the symlinks that need to be + created in the cycle directories have been appended to the array + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING. After these modifications, the + values of these parameters are as follows: + + ''') + msg+=dedent(f''' + CCPP_PHYS_SUITE = \"{CCPP_PHYS_SUITE}\" + + FIXgsm_FILES_TO_COPY_TO_FIXam = {list_to_str(FIXgsm_FILES_TO_COPY_TO_FIXam)} + ''') + msg+=dedent(f''' + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING = {list_to_str(CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING)} + ''') + print_info_msg(msg) + + EXPORTS = [ "CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING", "FIXgsm_FILES_TO_COPY_TO_FIXam" ] + export_vars(env_vars=EXPORTS) + + return sdf_uses_thompson_mp + +class Testing(unittest.TestCase): + def test_set_thompson_mp_fix_files(self): + self.assertEqual( True, + set_thompson_mp_fix_files(ccpp_phys_suite_fp=f"test_data{os.sep}suite_FV3_GSD_SAR.xml", + thompson_mp_climo_fn="Thompson_MP_MONTHLY_CLIMO.nc") ) + def setUp(self): + define_macos_utilities(); + set_env_var('DEBUG',True) + set_env_var('VERBOSE',True) + set_env_var('EXTRN_MDL_NAME_ICS',"FV3GFS") + set_env_var('EXTRN_MDL_NAME_LBCS',"FV3GFS") + set_env_var('CCPP_PHYS_SUITE',"FV3_GSD_SAR") + + CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING = [ + "aerosol.dat | global_climaeropac_global.txt", + "co2historicaldata_2010.txt | fix_co2_proj/global_co2historicaldata_2010.txt", + "co2historicaldata_2011.txt | fix_co2_proj/global_co2historicaldata_2011.txt", + "co2historicaldata_2012.txt | fix_co2_proj/global_co2historicaldata_2012.txt", + "co2historicaldata_2013.txt | fix_co2_proj/global_co2historicaldata_2013.txt", + "co2historicaldata_2014.txt | fix_co2_proj/global_co2historicaldata_2014.txt", + "co2historicaldata_2015.txt | fix_co2_proj/global_co2historicaldata_2015.txt", + "co2historicaldata_2016.txt | fix_co2_proj/global_co2historicaldata_2016.txt", + "co2historicaldata_2017.txt | fix_co2_proj/global_co2historicaldata_2017.txt", + "co2historicaldata_2018.txt | fix_co2_proj/global_co2historicaldata_2018.txt", + "co2historicaldata_2019.txt | fix_co2_proj/global_co2historicaldata_2019.txt", + "co2historicaldata_2020.txt | fix_co2_proj/global_co2historicaldata_2020.txt", + "co2historicaldata_2021.txt | fix_co2_proj/global_co2historicaldata_2021.txt", + "co2historicaldata_glob.txt | global_co2historicaldata_glob.txt", + "co2monthlycyc.txt | co2monthlycyc.txt", + "global_h2oprdlos.f77 | global_h2o_pltc.f77", + "global_zorclim.1x1.grb | global_zorclim.1x1.grb", + "sfc_emissivity_idx.txt | global_sfc_emissivity_idx.txt", + "solarconstant_noaa_an.txt | global_solarconstant_noaa_an.txt", + "global_o3prdlos.f77 | ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77"] + + FIXgsm_FILES_TO_COPY_TO_FIXam = [ + "global_glacier.2x2.grb", + "global_maxice.2x2.grb", + "RTGSST.1982.2012.monthly.clim.grb", + "global_snoclim.1.875.grb", + "CFSR.SEAICE.1982.2012.monthly.clim.grb", + "global_soilmgldas.t126.384.190.grb", + "seaice_newland.grb", + "global_climaeropac_global.txt", + "fix_co2_proj/global_co2historicaldata_2010.txt", + "fix_co2_proj/global_co2historicaldata_2011.txt", + "fix_co2_proj/global_co2historicaldata_2012.txt", + "fix_co2_proj/global_co2historicaldata_2013.txt", + "fix_co2_proj/global_co2historicaldata_2014.txt", + "fix_co2_proj/global_co2historicaldata_2015.txt", + "fix_co2_proj/global_co2historicaldata_2016.txt", + "fix_co2_proj/global_co2historicaldata_2017.txt", + "fix_co2_proj/global_co2historicaldata_2018.txt", + "fix_co2_proj/global_co2historicaldata_2019.txt", + "fix_co2_proj/global_co2historicaldata_2020.txt", + "fix_co2_proj/global_co2historicaldata_2021.txt", + "global_co2historicaldata_glob.txt", + "co2monthlycyc.txt", + "global_h2o_pltc.f77", + "global_hyblev.l65.txt", + "global_zorclim.1x1.grb", + "global_sfc_emissivity_idx.txt", + "global_solarconstant_noaa_an.txt", + "geo_em.d01.lat-lon.2.5m.HGT_M.nc", + "HGT.Beljaars_filtered.lat-lon.30s_res.nc", + "ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77"] + + set_env_var('CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING', CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING) + set_env_var('FIXgsm_FILES_TO_COPY_TO_FIXam', FIXgsm_FILES_TO_COPY_TO_FIXam) + diff --git a/ush/setup.py b/ush/setup.py new file mode 100644 index 0000000000..570dc674ba --- /dev/null +++ b/ush/setup.py @@ -0,0 +1,2185 @@ +#!/usr/bin/env python3 + +import os +import sys +import datetime +from textwrap import dedent + +from python_utils import cd_vrfy, mkdir_vrfy, rm_vrfy, check_var_valid_value,\ + lowercase,uppercase,check_for_preexist_dir_file,\ + import_vars, export_vars, get_env_var, print_info_msg,\ + print_err_msg_exit, load_config_file, cfg_to_shell_str,\ + load_shell_config, load_ini_config, get_ini_value + +from set_cycle_dates import set_cycle_dates +from set_predef_grid_params import set_predef_grid_params +from set_ozone_param import set_ozone_param +from set_extrn_mdl_params import set_extrn_mdl_params +from set_gridparams_ESGgrid import set_gridparams_ESGgrid +from set_gridparams_GFDLgrid import set_gridparams_GFDLgrid +from link_fix import link_fix +from check_ruc_lsm import check_ruc_lsm +from set_thompson_mp_fix_files import set_thompson_mp_fix_files + +def setup(): + """ Function that sets a secondary set + of parameters needed by the various scripts that are called by the + FV3-LAM rocoto community workflow. This secondary set of parameters is + calculated using the primary set of user-defined parameters in the de- + fault and custom experiment/workflow configuration scripts (whose file + names are defined below). This script then saves both sets of parame- + ters in a global variable definitions file (really a bash script) in + the experiment directory. This file then gets sourced by the various + scripts called by the tasks in the workflow. + + Args: + None + Returns: + None + """ + + ushdir=os.path.dirname(os.path.abspath(__file__)) + cd_vrfy(ushdir) + + # import all environment variables + import_vars() + + # print message + print_info_msg(f''' + ======================================================================== + Starting function setup() in \"{os.path.basename(__file__)}\"... + ========================================================================''') + # + #----------------------------------------------------------------------- + # + # Set the name of the configuration file containing default values for + # the experiment/workflow variables. Then source the file. + # + #----------------------------------------------------------------------- + # + EXPT_DEFAULT_CONFIG_FN="config_defaults.sh" + cfg_d = load_config_file(os.path.join(ushdir,EXPT_DEFAULT_CONFIG_FN)) + import_vars(dictionary=cfg_d) + # + #----------------------------------------------------------------------- + # + # If a user-specified configuration file exists, source it. This file + # contains user-specified values for a subset of the experiment/workflow + # variables that override their default values. Note that the user- + # specified configuration file is not tracked by the repository, whereas + # the default configuration file is tracked. + # + #----------------------------------------------------------------------- + # + if os.path.exists(EXPT_CONFIG_FN): + # + # We require that the variables being set in the user-specified configu- + # ration file have counterparts in the default configuration file. This + # is so that we do not introduce new variables in the user-specified + # configuration file without also officially introducing them in the de- + # fault configuration file. Thus, before sourcing the user-specified + # configuration file, we check that all variables in the user-specified + # configuration file are also assigned default values in the default + # configuration file. + # + cfg_u = load_config_file(os.path.join(ushdir,EXPT_CONFIG_FN)) + cfg_d.update(cfg_u) + if cfg_u.items() > cfg_d.items(): + print_err_msg_exit(f''' + User specified config file {EXPT_CONGIG_FN} has variables that are + not defined in the default configuration file {EXPT_DEFAULT_CONFIG_FN}''') + import_vars(dictionary=cfg_u) + + # + #----------------------------------------------------------------------- + # Source constants.sh and save its contents to a variable for later + #----------------------------------------------------------------------- + # + cfg_c=load_config_file(os.path.join(ushdir,CONSTANTS_FN)) + const_lines=cfg_to_shell_str(cfg_c) + import_vars(dictionary=cfg_c) + # + #----------------------------------------------------------------------- + # + # If PREDEF_GRID_NAME is set to a non-empty string, set or reset parameters + # according to the predefined domain specified. + # + #----------------------------------------------------------------------- + # + # export env vars before calling another module + export_vars() + + if PREDEF_GRID_NAME: + set_predef_grid_params() + + import_vars() + + # + #----------------------------------------------------------------------- + # + # Make sure different variables are set to their corresponding valid value + # + #----------------------------------------------------------------------- + # + global VERBOSE + if DEBUG and not VERBOSE: + print_info_msg(''' + Resetting VERBOSE to \"TRUE\" because DEBUG has been set to \"TRUE\"...''') + VERBOSE=True + + # + #----------------------------------------------------------------------- + # + # Set magnitude of stochastic ad-hoc schemes to -999.0 if they are not + # being used. This is required at the moment, since "do_shum/sppt/skeb" + # does not override the use of the scheme unless the magnitude is also + # specifically set to -999.0. If all "do_shum/sppt/skeb" are set to + # "false," then none will run, regardless of the magnitude values. + # + #----------------------------------------------------------------------- + # + global SHUM_MAG, SKEB_MAG, SPPT_MAG + if not DO_SHUM: + SHUM_MAG=-999.0 + if not DO_SKEB: + SKEB_MAG=-999.0 + if not DO_SPPT: + SPPT_MAG=-999.0 + # + #----------------------------------------------------------------------- + # + # If running with SPP in MYNN PBL, MYNN SFC, GSL GWD, Thompson MP, or + # RRTMG, count the number of entries in SPP_VAR_LIST to correctly set + # N_VAR_SPP, otherwise set it to zero. + # + #----------------------------------------------------------------------- + # + global N_VAR_SPP + N_VAR_SPP=0 + if DO_SPP: + N_VAR_SPP = len(SPP_VAR_LIST) + # + #----------------------------------------------------------------------- + # + # If running with Noah or RUC-LSM SPP, count the number of entries in + # LSM_SPP_VAR_LIST to correctly set N_VAR_LNDP, otherwise set it to zero. + # Also set LNDP_TYPE to 2 for LSM SPP, otherwise set it to zero. Finally, + # initialize an "FHCYC_LSM_SPP" variable to 0 and set it to 999 if LSM SPP + # is turned on. This requirement is necessary since LSM SPP cannot run with + # FHCYC=0 at the moment, but FHCYC cannot be set to anything less than the + # length of the forecast either. A bug fix will be submitted to + # ufs-weather-model soon, at which point, this requirement can be removed + # from regional_workflow. + # + #----------------------------------------------------------------------- + # + global N_VAR_LNDP, LNDP_TYPE, LNDP_MODEL_TYPE, FHCYC_LSM_SPP_OR_NOT + N_VAR_LNDP=0 + LNDP_TYPE=0 + LNDP_MODEL_TYPE=0 + FHCYC_LSM_SPP_OR_NOT=0 + if DO_LSM_SPP: + N_VAR_LNDP=len(LSM_SPP_VAR_LIST) + LNDP_TYPE=2 + LNDP_MODEL_TYPE=2 + FHCYC_LSM_SPP_OR_NOT=999 + # + #----------------------------------------------------------------------- + # + # If running with SPP, confirm that each SPP-related namelist value + # contains the same number of entries as N_VAR_SPP (set above to be equal + # to the number of entries in SPP_VAR_LIST). + # + #----------------------------------------------------------------------- + # + if DO_SPP: + if ( len(SPP_MAG_LIST) != N_VAR_SPP ) or \ + ( len(SPP_LSCALE) != N_VAR_SPP) or \ + ( len(SPP_TSCALE) != N_VAR_SPP) or \ + ( len(SPP_SIGTOP1) != N_VAR_SPP) or \ + ( len(SPP_SIGTOP2) != N_VAR_SPP) or \ + ( len(SPP_STDDEV_CUTOFF) != N_VAR_SPP) or \ + ( len(ISEED_SPP) != N_VAR_SPP): + print_err_msg_exit(f''' + All MYNN PBL, MYNN SFC, GSL GWD, Thompson MP, or RRTMG SPP-related namelist + variables set in {CONFIG_FN} must be equal in number of entries to what is + found in SPP_VAR_LIST: + Number of entries in SPP_VAR_LIST = \"{len(SPP_VAR_LIST)}\"''') + # + #----------------------------------------------------------------------- + # + # If running with LSM SPP, confirm that each LSM SPP-related namelist + # value contains the same number of entries as N_VAR_LNDP (set above to + # be equal to the number of entries in LSM_SPP_VAR_LIST). + # + #----------------------------------------------------------------------- + # + if DO_LSM_SPP: + if ( len(LSM_SPP_MAG_LIST) != N_VAR_LNDP) or \ + ( len(LSM_SPP_LSCALE) != N_VAR_LNDP) or \ + ( len(LSM_SPP_TSCALE) != N_VAR_LNDP): + print_err_msg_exit(f''' + All Noah or RUC-LSM SPP-related namelist variables (except ISEED_LSM_SPP) + set in {CONFIG_FN} must be equal in number of entries to what is found in + SPP_VAR_LIST: + Number of entries in SPP_VAR_LIST = \"{len(LSM_SPP_VAR_LIST)}\"''') + # + # The current script should be located in the ush subdirectory of the + # workflow directory. Thus, the workflow directory is the one above the + # directory of the current script. + # + SR_WX_APP_TOP_DIR=os.path.abspath( os.path.dirname(__file__) + \ + os.sep + os.pardir) + + # + #----------------------------------------------------------------------- + # + # Set the base directories in which codes obtained from external reposi- + # tories (using the manage_externals tool) are placed. Obtain the rela- + # tive paths to these directories by reading them in from the manage_ex- + # ternals configuration file. (Note that these are relative to the lo- + # cation of the configuration file.) Then form the full paths to these + # directories. Finally, make sure that each of these directories actu- + # ally exists. + # + #----------------------------------------------------------------------- + # + mng_extrns_cfg_fn = os.path.join(SR_WX_APP_TOP_DIR, "Externals.cfg") + try: + mng_extrns_cfg_fn = os.readlink(mng_extrns_cfg_fn) + except: + pass + property_name="local_path" + cfg = load_ini_config(mng_extrns_cfg_fn) + # + # Get the base directory of the FV3 forecast model code. + # + external_name=FCST_MODEL + UFS_WTHR_MDL_DIR = get_ini_value(cfg, external_name,property_name) + + if not UFS_WTHR_MDL_DIR: + print_err_msg_exit(f''' + Externals.cfg does not contain "{external_name}".''') + + UFS_WTHR_MDL_DIR=os.path.join(SR_WX_APP_TOP_DIR, UFS_WTHR_MDL_DIR) + if not os.path.exists(UFS_WTHR_MDL_DIR): + print_err_msg_exit(f''' + The base directory in which the FV3 source code should be located + (UFS_WTHR_MDL_DIR) does not exist: + UFS_WTHR_MDL_DIR = \"{UFS_WTHR_MDL_DIR}\" + Please clone the external repository containing the code in this directory, + build the executable, and then rerun the workflow.''') + # + # Get the base directory of the UFS_UTILS codes. + # + external_name="ufs_utils" + UFS_UTILS_DIR=get_ini_value(cfg, external_name, property_name) + + if not UFS_UTILS_DIR: + print_err_msg_exit(f''' + Externals.cfg does not contain "{external_name}".''') + + UFS_UTILS_DIR=os.path.join(SR_WX_APP_TOP_DIR, UFS_UTILS_DIR) + if not os.path.exists(UFS_UTILS_DIR): + print_err_msg_exit(f''' + The base directory in which the UFS utilities source codes should be lo- + cated (UFS_UTILS_DIR) does not exist: + UFS_UTILS_DIR = \"{UFS_UTILS_DIR}\" + Please clone the external repository containing the code in this direct- + ory, build the executables, and then rerun the workflow.''') + # + # Get the base directory of the UPP code. + # + external_name="UPP" + UPP_DIR=get_ini_value(cfg,external_name,property_name ) + if not UPP_DIR: + print_err_msg_exit(f''' + Externals.cfg does not contain "{external_name}".''') + + UPP_DIR=os.path.join(SR_WX_APP_TOP_DIR, UPP_DIR) + if not os.path.exists(UPP_DIR): + print_err_msg_exit(f''' + The base directory in which the UPP source code should be located + (UPP_DIR) does not exist: + UPP_DIR = \"{UPP_DIR}\" + Please clone the external repository containing the code in this directory, + build the executable, and then rerun the workflow.''') + + # + # Define some other useful paths + # + global USHDIR, SCRIPTSDIR, JOBSDIR,SORCDIR, SRC_DIR, PARMDIR, MODULES_DIR, EXECDIR, TEMPLATE_DIR, \ + VX_CONFIG_DIR, METPLUS_CONF, MET_CONFIG + + USHDIR = os.path.join(SR_WX_APP_TOP_DIR,"ush") + SCRIPTSDIR = os.path.join(SR_WX_APP_TOP_DIR,"scripts") + JOBSDIR = os.path.join(SR_WX_APP_TOP_DIR,"jobs") + SORCDIR = os.path.join(SR_WX_APP_TOP_DIR,"sorc") + SRC_DIR = os.path.join(SR_WX_APP_TOP_DIR,"src") + PARMDIR = os.path.join(SR_WX_APP_TOP_DIR,"parm") + MODULES_DIR = os.path.join(SR_WX_APP_TOP_DIR,"modulefiles") + EXECDIR = os.path.join(SR_WX_APP_TOP_DIR,EXEC_SUBDIR) + TEMPLATE_DIR = os.path.join(USHDIR,"templates") + VX_CONFIG_DIR = os.path.join(TEMPLATE_DIR,"parm") + METPLUS_CONF = os.path.join(TEMPLATE_DIR,"parm","metplus") + MET_CONFIG = os.path.join(TEMPLATE_DIR,"parm","met") + + # + #----------------------------------------------------------------------- + # + # Source the machine config file containing architechture information, + # queue names, and supported input file paths. + # + #----------------------------------------------------------------------- + # + global MACHINE + global MACHINE_FILE + global FIXgsm, FIXaer, FIXlut, TOPO_DIR, SFC_CLIMO_INPUT_DIR, DOMAIN_PREGEN_BASEDIR, \ + RELATIVE_LINK_FLAG, WORKFLOW_MANAGER, NCORES_PER_NODE, SCHED, \ + QUEUE_DEFAULT, QUEUE_HPSS, QUEUE_FCST, \ + PARTITION_DEFAULT, PARTITION_HPSS, PARTITION_FCST + + MACHINE = uppercase(MACHINE) + RELATIVE_LINK_FLAG="--relative" + MACHINE_FILE=MACHINE_FILE or os.path.join(USHDIR,"machine",f"{lowercase(MACHINE)}.sh") + machine_cfg = load_shell_config(MACHINE_FILE) + import_vars(dictionary=machine_cfg) + + if not NCORES_PER_NODE: + print_err_msg_exit(f""" + NCORES_PER_NODE has not been specified in the file {MACHINE_FILE} + Please ensure this value has been set for your desired platform. """) + + if not (FIXgsm and FIXaer and FIXlut and TOPO_DIR and SFC_CLIMO_INPUT_DIR): + print_err_msg_exit(f''' + One or more fix file directories have not been specified for this machine: + MACHINE = \"{MACHINE}\" + FIXgsm = \"{FIXgsm or ""} + FIXaer = \"{FIXaer or ""} + FIXlut = \"{FIXlut or ""} + TOPO_DIR = \"{TOPO_DIR or ""} + SFC_CLIMO_INPUT_DIR = \"{SFC_CLIMO_INPUT_DIR or ""} + DOMAIN_PREGEN_BASEDIR = \"{DOMAIN_PREGEN_BASEDIR or ""} + You can specify the missing location(s) in config.sh''') + + # + #----------------------------------------------------------------------- + # + # Set the names of the build and workflow module files (if not + # already specified by the user). These are the files that need to be + # sourced before building the component SRW App codes and running various + # workflow scripts, respectively. + # + #----------------------------------------------------------------------- + # + global WFLOW_MOD_FN, BUILD_MOD_FN + machine=lowercase(MACHINE) + WFLOW_MOD_FN=WFLOW_MOD_FN or f"wflow_{machine}" + BUILD_MOD_FN=BUILD_MOD_FN or f"build_{machine}_{COMPILER}" + # + #----------------------------------------------------------------------- + # + # Calculate a default value for the number of processes per node for the + # RUN_FCST_TN task. Then set PPN_RUN_FCST to this default value if + # PPN_RUN_FCST is not already specified by the user. + # + #----------------------------------------------------------------------- + # + global PPN_RUN_FCST + ppn_run_fcst_default = NCORES_PER_NODE // OMP_NUM_THREADS_RUN_FCST + PPN_RUN_FCST=PPN_RUN_FCST or ppn_run_fcst_default + # + #----------------------------------------------------------------------- + # + # If we are using a workflow manager check that the ACCOUNT variable is + # not empty. + # + #----------------------------------------------------------------------- + # + if WORKFLOW_MANAGER != "none": + if not ACCOUNT: + print_err_msg_exit(f''' + The variable ACCOUNT cannot be empty if you are using a workflow manager: + ACCOUNT = \"ACCOUNT\" + WORKFLOW_MANAGER = \"WORKFLOW_MANAGER\"''') + # + #----------------------------------------------------------------------- + # + # Set the grid type (GTYPE). In general, in the FV3 code, this can take + # on one of the following values: "global", "stretch", "nest", and "re- + # gional". The first three values are for various configurations of a + # global grid, while the last one is for a regional grid. Since here we + # are only interested in a regional grid, GTYPE must be set to "region- + # al". + # + #----------------------------------------------------------------------- + # + global TILE_RGNL, GTYPE + GTYPE="regional" + TILE_RGNL="7" + + #----------------------------------------------------------------------- + # + # Set USE_MERRA_CLIMO to either "TRUE" or "FALSE" so we don't + # have to consider other valid values later on. + # + #----------------------------------------------------------------------- + global USE_MERRA_CLIMO + if CCPP_PHYS_SUITE == "FV3_GFS_v15_thompson_mynn_lam3km": + USE_MERRA_CLIMO=True + # + #----------------------------------------------------------------------- + # + # Set CPL to TRUE/FALSE based on FCST_MODEL. + # + #----------------------------------------------------------------------- + # + global CPL + if FCST_MODEL == "ufs-weather-model": + CPL=False + elif FCST_MODEL == "fv3gfs_aqm": + CPL=True + else: + print_err_msg_exit(f''' + The coupling flag CPL has not been specified for this value of FCST_MODEL: + FCST_MODEL = \"{FCST_MODEL}\"''') + # + #----------------------------------------------------------------------- + # + # Make sure RESTART_INTERVAL is set to an integer value if present + # + #----------------------------------------------------------------------- + # + if not isinstance(RESTART_INTERVAL,int): + print_err_msg_exit(f''' + RESTART_INTERVAL must be set to an integer number of hours. + RESTART_INTERVAL = \"{RESTART_INTERVAL}\"''') + # + #----------------------------------------------------------------------- + # + # Check that DATE_FIRST_CYCL and DATE_LAST_CYCL are strings consisting + # of exactly 8 digits. + # + #----------------------------------------------------------------------- + # + if not isinstance(DATE_FIRST_CYCL,datetime.date): + print_err_msg_exit(f''' + DATE_FIRST_CYCL must be a string consisting of exactly 8 digits of the + form \"YYYYMMDD\", where YYYY is the 4-digit year, MM is the 2-digit + month, and DD is the 2-digit day-of-month. + DATE_FIRST_CYCL = \"{DATE_FIRST_CYCL}\"''') + + if not isinstance(DATE_LAST_CYCL,datetime.date): + print_err_msg_exit(f''' + DATE_LAST_CYCL must be a string consisting of exactly 8 digits of the + form \"YYYYMMDD\", where YYYY is the 4-digit year, MM is the 2-digit + month, and DD is the 2-digit day-of-month. + DATE_LAST_CYCL = \"{DATE_LAST_CYCL}\"''') + # + #----------------------------------------------------------------------- + # + # Check that all elements of CYCL_HRS are strings consisting of exactly + # 2 digits that are between "00" and "23", inclusive. + # + #----------------------------------------------------------------------- + # + i=0 + for CYCL in CYCL_HRS: + if CYCL < 0 or CYCL > 23: + print_err_msg_exit(f''' + Each element of CYCL_HRS must be an integer between \"00\" and \"23\", in- + clusive (including a leading \"0\", if necessary), specifying an hour-of- + day. Element #{i} of CYCL_HRS (where the index of the first element is 0) + does not have this form: + CYCL_HRS = {CYCL_HRS} + CYCL_HRS[{i}] = \"{CYCL_HRS[i]}\"''') + + i=i+1 + # + #----------------------------------------------------------------------- + # Check cycle increment for cycle frequency (cycl_freq). + # only if INCR_CYCL_FREQ < 24. + #----------------------------------------------------------------------- + # + if INCR_CYCL_FREQ < 24 and i > 1: + cycl_intv=(24//i) + if cycl_intv != INCR_CYCL_FREQ: + print_err_msg_exit(f''' + The number of CYCL_HRS does not match with that expected by INCR_CYCL_FREQ: + INCR_CYCL_FREQ = {INCR_CYCL_FREQ} + cycle interval by the number of CYCL_HRS = {cycl_intv} + CYCL_HRS = {CYCL_HRS} ''') + + for itmp in range(1,i): + itm1=itmp-1 + cycl_next_itmp=CYCL_HRS[itm1] + INCR_CYCL_FREQ + if cycl_next_itmp != CYCL_HRS[itmp]: + print_err_msg_exit(f''' + Element {itmp} of CYCL_HRS does not match with the increment of cycle + frequency INCR_CYCL_FREQ: + CYCL_HRS = {CYCL_HRS} + INCR_CYCL_FREQ = {INCR_CYCL_FREQ} + CYCL_HRS[{itmp}] = \"{CYCL_HRS[itmp]}\"''') + # + #----------------------------------------------------------------------- + # + # Call a function to generate the array ALL_CDATES containing the cycle + # dates/hours for which to run forecasts. The elements of this array + # will have the form YYYYMMDDHH. They are the starting dates/times of + # the forecasts that will be run in the experiment. Then set NUM_CYCLES + # to the number of elements in this array. + # + #----------------------------------------------------------------------- + # + + ALL_CDATES = set_cycle_dates( \ + date_start=DATE_FIRST_CYCL, + date_end=DATE_LAST_CYCL, + cycle_hrs=CYCL_HRS, + incr_cycl_freq=INCR_CYCL_FREQ) + + NUM_CYCLES=len(ALL_CDATES) + + if NUM_CYCLES > 90: + ALL_CDATES=None + print_info_msg(f''' + Too many cycles in ALL_CDATES to list, redefining in abbreviated form." + ALL_CDATES="{DATE_FIRST_CYCL}{CYCL_HRS[0]}...{DATE_LAST_CYCL}{CYCL_HRS[-1]}''') + # + #----------------------------------------------------------------------- + # + # If using a custom post configuration file, make sure that it exists. + # + #----------------------------------------------------------------------- + # + if USE_CUSTOM_POST_CONFIG_FILE: + if not os.path.exists(CUSTOM_POST_CONFIG_FP): + print_err_msg_exit(f''' + The custom post configuration specified by CUSTOM_POST_CONFIG_FP does not + exist: + CUSTOM_POST_CONFIG_FP = \"{CUSTOM_POST_CONFIG_FP}\"''') + # + #----------------------------------------------------------------------- + # + # If using external CRTM fix files to allow post-processing of synthetic + # satellite products from the UPP, then make sure the fix file directory + # exists. + # + #----------------------------------------------------------------------- + # + if USE_CRTM: + if not os.path.exists(CRTM_DIR): + print_err_msg_exit(f''' + The external CRTM fix file directory specified by CRTM_DIR does not exist: + CRTM_DIR = \"{CRTM_DIR}\"''') + # + #----------------------------------------------------------------------- + # + # The forecast length (in integer hours) cannot contain more than 3 cha- + # racters. Thus, its maximum value is 999. Check whether the specified + # forecast length exceeds this maximum value. If so, print out a warn- + # ing and exit this script. + # + #----------------------------------------------------------------------- + # + fcst_len_hrs_max=999 + if FCST_LEN_HRS > fcst_len_hrs_max: + print_err_msg_exit(f''' + Forecast length is greater than maximum allowed length: + FCST_LEN_HRS = {FCST_LEN_HRS} + fcst_len_hrs_max = {fcst_len_hrs_max}''') + # + #----------------------------------------------------------------------- + # + # Check whether the forecast length (FCST_LEN_HRS) is evenly divisible + # by the BC update interval (LBC_SPEC_INTVL_HRS). If not, print out a + # warning and exit this script. If so, generate an array of forecast + # hours at which the boundary values will be updated. + # + #----------------------------------------------------------------------- + # + rem=FCST_LEN_HRS%LBC_SPEC_INTVL_HRS + + if rem != 0: + print_err_msg_exit(f''' + The forecast length (FCST_LEN_HRS) is not evenly divisible by the lateral + boundary conditions update interval (LBC_SPEC_INTVL_HRS): + FCST_LEN_HRS = {FCST_LEN_HRS} + LBC_SPEC_INTVL_HRS = {LBC_SPEC_INTVL_HRS} + rem = FCST_LEN_HRS%%LBC_SPEC_INTVL_HRS = {rem}''') + # + #----------------------------------------------------------------------- + # + # Set the array containing the forecast hours at which the lateral + # boundary conditions (LBCs) need to be updated. Note that this array + # does not include the 0-th hour (initial time). + # + #----------------------------------------------------------------------- + # + LBC_SPEC_FCST_HRS=[ i for i in range(LBC_SPEC_INTVL_HRS, \ + LBC_SPEC_INTVL_HRS + FCST_LEN_HRS, \ + LBC_SPEC_INTVL_HRS ) ] + # + #----------------------------------------------------------------------- + # + # Check to make sure that various computational parameters needed by the + # forecast model are set to non-empty values. At this point in the + # experiment generation, all of these should be set to valid (non-empty) + # values. + # + #----------------------------------------------------------------------- + # + if not DT_ATMOS: + print_err_msg_exit(f''' + The forecast model main time step (DT_ATMOS) is set to a null string: + DT_ATMOS = {DT_ATMOS} + Please set this to a valid numerical value in the user-specified experiment + configuration file (EXPT_CONFIG_FP) and rerun: + EXPT_CONFIG_FP = \"{EXPT_CONFIG_FP}\"''') + + if not LAYOUT_X: + print_err_msg_exit(f''' + The number of MPI processes to be used in the x direction (LAYOUT_X) by + the forecast job is set to a null string: + LAYOUT_X = {LAYOUT_X} + Please set this to a valid numerical value in the user-specified experiment + configuration file (EXPT_CONFIG_FP) and rerun: + EXPT_CONFIG_FP = \"{EXPT_CONFIG_FP}\"''') + + if not LAYOUT_Y: + print_err_msg_exit(f''' + The number of MPI processes to be used in the y direction (LAYOUT_Y) by + the forecast job is set to a null string: + LAYOUT_Y = {LAYOUT_Y} + Please set this to a valid numerical value in the user-specified experiment + configuration file (EXPT_CONFIG_FP) and rerun: + EXPT_CONFIG_FP = \"{EXPT_CONFIG_FP}\"''') + + if not BLOCKSIZE: + print_err_msg_exit(f''' + The cache size to use for each MPI task of the forecast (BLOCKSIZE) is + set to a null string: + BLOCKSIZE = {BLOCKSIZE} + Please set this to a valid numerical value in the user-specified experiment + configuration file (EXPT_CONFIG_FP) and rerun: + EXPT_CONFIG_FP = \"{EXPT_CONFIG_FP}\"''') + # + #----------------------------------------------------------------------- + # + # If performing sub-hourly model output and post-processing, check that + # the output interval DT_SUBHOURLY_POST_MNTS (in minutes) is specified + # correctly. + # + #----------------------------------------------------------------------- + # + global SUB_HOURLY_POST + + if SUB_HOURLY_POST: + # + # Check that DT_SUBHOURLY_POST_MNTS is between 0 and 59, inclusive. + # + if DT_SUBHOURLY_POST_MNTS < 0 or DT_SUBHOURLY_POST_MNTS > 59: + print_err_msg_exit(f''' + When performing sub-hourly post (i.e. SUB_HOURLY_POST set to \"TRUE\"), + DT_SUBHOURLY_POST_MNTS must be set to an integer between 0 and 59, + inclusive but in this case is not: + SUB_HOURLY_POST = \"{SUB_HOURLY_POST}\" + DT_SUBHOURLY_POST_MNTS = \"{DT_SUBHOURLY_POST_MNTS}\"''') + # + # Check that DT_SUBHOURLY_POST_MNTS (after converting to seconds) is + # evenly divisible by the forecast model's main time step DT_ATMOS. + # + rem=( DT_SUBHOURLY_POST_MNTS*60 % DT_ATMOS ) + if rem != 0: + print_err_msg_exit(f''' + When performing sub-hourly post (i.e. SUB_HOURLY_POST set to \"TRUE\"), + the time interval specified by DT_SUBHOURLY_POST_MNTS (after converting + to seconds) must be evenly divisible by the time step DT_ATMOS used in + the forecast model, i.e. the remainder (rem) must be zero. In this case, + it is not: + SUB_HOURLY_POST = \"{SUB_HOURLY_POST}\" + DT_SUBHOURLY_POST_MNTS = \"{DT_SUBHOURLY_POST_MNTS}\" + DT_ATMOS = \"{DT_ATMOS}\" + rem = (DT_SUBHOURLY_POST_MNTS*60) %% DT_ATMOS = {rem} + Please reset DT_SUBHOURLY_POST_MNTS and/or DT_ATMOS so that this remainder + is zero.''') + # + # If DT_SUBHOURLY_POST_MNTS is set to 0 (with SUB_HOURLY_POST set to + # True), then we're not really performing subhourly post-processing. + # In this case, reset SUB_HOURLY_POST to False and print out an + # informational message that such a change was made. + # + if DT_SUBHOURLY_POST_MNTS == 0: + print_info_msg(f''' + When performing sub-hourly post (i.e. SUB_HOURLY_POST set to \"TRUE\"), + DT_SUBHOURLY_POST_MNTS must be set to a value greater than 0; otherwise, + sub-hourly output is not really being performed: + SUB_HOURLY_POST = \"{SUB_HOURLY_POST}\" + DT_SUBHOURLY_POST_MNTS = \"{DT_SUBHOURLY_POST_MNTS}\" + Resetting SUB_HOURLY_POST to \"FALSE\". If you do not want this, you + must set DT_SUBHOURLY_POST_MNTS to something other than zero.''') + SUB_HOURLY_POST=False + # + #----------------------------------------------------------------------- + # + # If the base directory (EXPT_BASEDIR) in which the experiment subdirectory + # (EXPT_SUBDIR) will be located does not start with a "/", then it is + # either set to a null string or contains a relative directory. In both + # cases, prepend to it the absolute path of the default directory under + # which the experiment directories are placed. If EXPT_BASEDIR was set + # to a null string, it will get reset to this default experiment directory, + # and if it was set to a relative directory, it will get reset to an + # absolute directory that points to the relative directory under the + # default experiment directory. Then create EXPT_BASEDIR if it doesn't + # already exist. + # + #----------------------------------------------------------------------- + # + global EXPT_BASEDIR + if (not EXPT_BASEDIR) or (EXPT_BASEDIR[0] != "/"): + if not EXPT_BASEDIR: + EXPT_BASEDIR = "" + EXPT_BASEDIR = os.path.join(SR_WX_APP_TOP_DIR,"..","expt_dirs",EXPT_BASEDIR) + try: + EXPT_BASEDIR = os.path.realpath(EXPT_BASEDIR) + except: + pass + EXPT_BASEDIR = os.path.abspath(EXPT_BASEDIR) + + mkdir_vrfy(f' -p "{EXPT_BASEDIR}"') + # + #----------------------------------------------------------------------- + # + # If the experiment subdirectory name (EXPT_SUBDIR) is set to an empty + # string, print out an error message and exit. + # + #----------------------------------------------------------------------- + # + if not EXPT_SUBDIR: + print_err_msg_exit(f''' + The name of the experiment subdirectory (EXPT_SUBDIR) cannot be empty: + EXPT_SUBDIR = \"{EXPT_SUBDIR}\"''') + # + #----------------------------------------------------------------------- + # + # Set the full path to the experiment directory. Then check if it already + # exists and if so, deal with it as specified by PREEXISTING_DIR_METHOD. + # + #----------------------------------------------------------------------- + # + global EXPTDIR + EXPTDIR = os.path.join(EXPT_BASEDIR, EXPT_SUBDIR) + check_for_preexist_dir_file(EXPTDIR,PREEXISTING_DIR_METHOD) + # + #----------------------------------------------------------------------- + # + # Set other directories, some of which may depend on EXPTDIR (depending + # on whether we're running in NCO or community mode, i.e. whether RUN_ENVIR + # is set to "nco" or "community"). Definitions: + # + # LOGDIR: + # Directory in which the log files from the workflow tasks will be placed. + # + # FIXam: + # This is the directory that will contain the fixed files or symlinks to + # the fixed files containing various fields on global grids (which are + # usually much coarser than the native FV3-LAM grid). + # + # FIXclim: + # This is the directory that will contain the MERRA2 aerosol climatology + # data file and lookup tables for optics properties + # + # FIXLAM: + # This is the directory that will contain the fixed files or symlinks to + # the fixed files containing the grid, orography, and surface climatology + # on the native FV3-LAM grid. + # + # CYCLE_BASEDIR: + # The base directory in which the directories for the various cycles will + # be placed. + # + # COMROOT: + # In NCO mode, this is the full path to the "com" directory under which + # output from the RUN_POST_TN task will be placed. Note that this output + # is not placed directly under COMROOT but several directories further + # down. More specifically, for a cycle starting at yyyymmddhh, it is at + # + # $COMROOT/$NET/$envir/$RUN.$yyyymmdd/$hh + # + # Below, we set COMROOT in terms of PTMP as COMROOT="$PTMP/com". COMOROOT + # is not used by the workflow in community mode. + # + # COMOUT_BASEDIR: + # In NCO mode, this is the base directory directly under which the output + # from the RUN_POST_TN task will be placed, i.e. it is the cycle-independent + # portion of the RUN_POST_TN task's output directory. It is given by + # + # $COMROOT/$NET/$model_ver + # + # COMOUT_BASEDIR is not used by the workflow in community mode. + # + # POST_OUTPUT_DOMAIN_NAME: + # The PREDEF_GRID_NAME is set by default. + # + #----------------------------------------------------------------------- + # + global LOGDIR, FIXam, FIXclim, FIXLAM, CYCLE_BASEDIR, \ + COMROOT, COMOUT_BASEDIR, POST_OUTPUT_DOMAIN_NAME + + LOGDIR = os.path.join(EXPTDIR, "log") + + FIXam = os.path.join(EXPTDIR, "fix_am") + FIXclim = os.path.join(EXPTDIR, "fix_clim") + FIXLAM = os.path.join(EXPTDIR, "fix_lam") + + if RUN_ENVIR == "nco": + + CYCLE_BASEDIR = os.path.join(STMP, "tmpnwprd", RUN) + check_for_preexist_dir_file(CYCLE_BASEDIR,PREEXISTING_DIR_METHOD) + COMROOT = os.path.join(PTMP, "com") + COMOUT_BASEDIR = os.path.join(COMROOT, NET, model_ver) + check_for_preexist_dir_file(COMOUT_BASEDIR,PREEXISTING_DIR_METHOD) + + else: + + CYCLE_BASEDIR=EXPTDIR + COMROOT="" + COMOUT_BASEDIR="" + + if POST_OUTPUT_DOMAIN_NAME is None: + if PREDEF_GRID_NAME is None: + print_err_msg_exit(f''' + The domain name used in naming the run_post output files + (POST_OUTPUT_DOMAIN_NAME) has not been set: + POST_OUTPUT_DOMAIN_NAME = \"{POST_OUTPUT_DOMAIN_NAME}\" + If this experiment is not using a predefined grid (i.e. if + PREDEF_GRID_NAME is set to a null string), POST_OUTPUT_DOMAIN_NAME + must be set in the configuration file (\"{EXPT_CONFIG_FN}\"). ''') + + POST_OUTPUT_DOMAIN_NAME = PREDEF_GRID_NAME + + POST_OUTPUT_DOMAIN_NAME = lowercase(POST_OUTPUT_DOMAIN_NAME) + # + #----------------------------------------------------------------------- + # + # The FV3 forecast model needs the following input files in the run di- + # rectory to start a forecast: + # + # (1) The data table file + # (2) The diagnostics table file + # (3) The field table file + # (4) The FV3 namelist file + # (5) The model configuration file + # (6) The NEMS configuration file + # + # If using CCPP, it also needs: + # + # (7) The CCPP physics suite definition file + # + # The workflow contains templates for the first six of these files. + # Template files are versions of these files that contain placeholder + # (i.e. dummy) values for various parameters. The experiment/workflow + # generation scripts copy these templates to appropriate locations in + # the experiment directory (either the top of the experiment directory + # or one of the cycle subdirectories) and replace the placeholders in + # these copies by actual values specified in the experiment/workflow + # configuration file (or derived from such values). The scripts then + # use the resulting "actual" files as inputs to the forecast model. + # + # Note that the CCPP physics suite defintion file does not have a cor- + # responding template file because it does not contain any values that + # need to be replaced according to the experiment/workflow configura- + # tion. If using CCPP, this file simply needs to be copied over from + # its location in the forecast model's directory structure to the ex- + # periment directory. + # + # Below, we first set the names of the templates for the first six files + # listed above. We then set the full paths to these template files. + # Note that some of these file names depend on the physics suite while + # others do not. + # + #----------------------------------------------------------------------- + # + global DATA_TABLE_TMPL_FN, DIAG_TABLE_TMPL_FN, FIELD_TABLE_TMPL_FN, \ + MODEL_CONFIG_TMPL_FN, NEMS_CONFIG_TMPL_FN + global DATA_TABLE_TMPL_FP, DIAG_TABLE_TMPL_FP, FIELD_TABLE_TMPL_FP, \ + MODEL_CONFIG_TMPL_FP, NEMS_CONFIG_TMPL_FP + global FV3_NML_BASE_SUITE_FP, FV3_NML_YAML_CONFIG_FP,FV3_NML_BASE_ENS_FP + + dot_ccpp_phys_suite_or_null=f".{CCPP_PHYS_SUITE}" + + # Names of input files that the forecast model (ufs-weather-model) expects + # to read in. These should only be changed if the input file names in the + # forecast model code are changed. + #---------------------------------- + DATA_TABLE_FN = "data_table" + DIAG_TABLE_FN = "diag_table" + FIELD_TABLE_FN = "field_table" + MODEL_CONFIG_FN = "model_configure" + NEMS_CONFIG_FN = "nems.configure" + #---------------------------------- + + DATA_TABLE_TMPL_FN = DATA_TABLE_TMPL_FN or DATA_TABLE_FN + DIAG_TABLE_TMPL_FN = f"{DIAG_TABLE_TMPL_FN or DIAG_TABLE_FN}{dot_ccpp_phys_suite_or_null}" + FIELD_TABLE_TMPL_FN = f"{FIELD_TABLE_TMPL_FN or FIELD_TABLE_FN}{dot_ccpp_phys_suite_or_null}" + MODEL_CONFIG_TMPL_FN = MODEL_CONFIG_TMPL_FN or MODEL_CONFIG_FN + NEMS_CONFIG_TMPL_FN = NEMS_CONFIG_TMPL_FN or NEMS_CONFIG_FN + + DATA_TABLE_TMPL_FP = os.path.join(TEMPLATE_DIR,DATA_TABLE_TMPL_FN) + DIAG_TABLE_TMPL_FP = os.path.join(TEMPLATE_DIR,DIAG_TABLE_TMPL_FN) + FIELD_TABLE_TMPL_FP = os.path.join(TEMPLATE_DIR,FIELD_TABLE_TMPL_FN) + FV3_NML_BASE_SUITE_FP = os.path.join(TEMPLATE_DIR,FV3_NML_BASE_SUITE_FN) + FV3_NML_YAML_CONFIG_FP = os.path.join(TEMPLATE_DIR,FV3_NML_YAML_CONFIG_FN) + FV3_NML_BASE_ENS_FP = os.path.join(EXPTDIR,FV3_NML_BASE_ENS_FN) + MODEL_CONFIG_TMPL_FP = os.path.join(TEMPLATE_DIR,MODEL_CONFIG_TMPL_FN) + NEMS_CONFIG_TMPL_FP = os.path.join(TEMPLATE_DIR,NEMS_CONFIG_TMPL_FN) + # + #----------------------------------------------------------------------- + # + # Set: + # + # 1) the variable CCPP_PHYS_SUITE_FN to the name of the CCPP physics + # suite definition file. + # 2) the variable CCPP_PHYS_SUITE_IN_CCPP_FP to the full path of this + # file in the forecast model's directory structure. + # 3) the variable CCPP_PHYS_SUITE_FP to the full path of this file in + # the experiment directory. + # + # Note that the experiment/workflow generation scripts will copy this + # file from CCPP_PHYS_SUITE_IN_CCPP_FP to CCPP_PHYS_SUITE_FP. Then, for + # each cycle, the forecast launch script will create a link in the cycle + # run directory to the copy of this file at CCPP_PHYS_SUITE_FP. + # + #----------------------------------------------------------------------- + # + global CCPP_PHYS_SUITE_FN, CCPP_PHYS_SUITE_IN_CCPP_FP, CCPP_PHYS_SUITE_FP + CCPP_PHYS_SUITE_FN=f"suite_{CCPP_PHYS_SUITE}.xml" + CCPP_PHYS_SUITE_IN_CCPP_FP=os.path.join(UFS_WTHR_MDL_DIR, "FV3","ccpp","suites",CCPP_PHYS_SUITE_FN) + CCPP_PHYS_SUITE_FP=os.path.join(EXPTDIR, CCPP_PHYS_SUITE_FN) + if not os.path.exists(CCPP_PHYS_SUITE_IN_CCPP_FP): + print_err_msg_exit(f''' + The CCPP suite definition file (CCPP_PHYS_SUITE_IN_CCPP_FP) does not exist + in the local clone of the ufs-weather-model: + CCPP_PHYS_SUITE_IN_CCPP_FP = \"{CCPP_PHYS_SUITE_IN_CCPP_FP}\"''') + # + #----------------------------------------------------------------------- + # + # Set: + # + # 1) the variable FIELD_DICT_FN to the name of the field dictionary + # file. + # 2) the variable FIELD_DICT_IN_UWM_FP to the full path of this + # file in the forecast model's directory structure. + # 3) the variable FIELD_DICT_FP to the full path of this file in + # the experiment directory. + # + #----------------------------------------------------------------------- + # + global FIELD_DICT_FN, FIELD_DICT_IN_UWM_FP, FIELD_DICT_FP + FIELD_DICT_FN = "fd_nems.yaml" + FIELD_DICT_IN_UWM_FP = os.path.join(UFS_WTHR_MDL_DIR, "tests", "parm", FIELD_DICT_FN) + FIELD_DICT_FP = os.path.join(EXPTDIR, FIELD_DICT_FN) + if not os.path.exists(FIELD_DICT_IN_UWM_FP): + print_err_msg_exit(f''' + The field dictionary file (FIELD_DICT_IN_UWM_FP) does not exist + in the local clone of the ufs-weather-model: + FIELD_DICT_IN_UWM_FP = \"{FIELD_DICT_IN_UWM_FP}\"''') + # + #----------------------------------------------------------------------- + # + # Call the function that sets the ozone parameterization being used and + # modifies associated parameters accordingly. + # + #----------------------------------------------------------------------- + # + + # export env vars before calling another module + export_vars() + + OZONE_PARAM = set_ozone_param( \ + ccpp_phys_suite_fp=CCPP_PHYS_SUITE_IN_CCPP_FP) + + IMPORTS = ["CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING", "FIXgsm_FILES_TO_COPY_TO_FIXam"] + import_vars(env_vars=IMPORTS) + # + #----------------------------------------------------------------------- + # + # Set the full paths to those forecast model input files that are cycle- + # independent, i.e. they don't include information about the cycle's + # starting day/time. These are: + # + # * The data table file [(1) in the list above)] + # * The field table file [(3) in the list above)] + # * The FV3 namelist file [(4) in the list above)] + # * The NEMS configuration file [(6) in the list above)] + # + # Since they are cycle-independent, the experiment/workflow generation + # scripts will place them in the main experiment directory (EXPTDIR). + # The script that runs each cycle will then create links to these files + # in the run directories of the individual cycles (which are subdirecto- + # ries under EXPTDIR). + # + # The remaining two input files to the forecast model, i.e. + # + # * The diagnostics table file [(2) in the list above)] + # * The model configuration file [(5) in the list above)] + # + # contain parameters that depend on the cycle start date. Thus, custom + # versions of these two files must be generated for each cycle and then + # placed directly in the run directories of the cycles (not EXPTDIR). + # For this reason, the full paths to their locations vary by cycle and + # cannot be set here (i.e. they can only be set in the loop over the + # cycles in the rocoto workflow XML file). + # + #----------------------------------------------------------------------- + # + global DATA_TABLE_FP, FIELD_TABLE_FP, FV3_NML_FN, FV3_NML_FP, NEMS_CONFIG_FP + DATA_TABLE_FP = os.path.join(EXPTDIR, DATA_TABLE_FN) + FIELD_TABLE_FP = os.path.join(EXPTDIR, FIELD_TABLE_FN) + FV3_NML_FN = os.path.splitext(FV3_NML_BASE_SUITE_FN)[0] + FV3_NML_FP = os.path.join(EXPTDIR, FV3_NML_FN) + NEMS_CONFIG_FP = os.path.join(EXPTDIR, NEMS_CONFIG_FN) + # + #----------------------------------------------------------------------- + # + # If USE_USER_STAGED_EXTRN_FILES is set to TRUE, make sure that the user- + # specified directories under which the external model files should be + # located actually exist. + # + #----------------------------------------------------------------------- + # + if USE_USER_STAGED_EXTRN_FILES: + # Check for the base directory up to the first templated field. + idx = EXTRN_MDL_SOURCE_BASEDIR_ICS.find("$") + if idx == -1: + idx=len(EXTRN_MDL_SOURCE_BASEDIR_ICS) + + if not os.path.exists(EXTRN_MDL_SOURCE_BASEDIR_ICS[:idx]): + print_err_msg_exit(f''' + The directory (EXTRN_MDL_SOURCE_BASEDIR_ICS) in which the user-staged + external model files for generating ICs should be located does not exist: + EXTRN_MDL_SOURCE_BASEDIR_ICS = \"{EXTRN_MDL_SOURCE_BASEDIR_ICS}\"''') + + idx = EXTRN_MDL_SOURCE_BASEDIR_LBCS.find("$") + if idx == -1: + idx=len(EXTRN_MDL_SOURCE_BASEDIR_LBCS) + + if not os.path.exists(EXTRN_MDL_SOURCE_BASEDIR_LBCS[:idx]): + print_err_msg_exit(f''' + The directory (EXTRN_MDL_SOURCE_BASEDIR_LBCS) in which the user-staged + external model files for generating LBCs should be located does not exist: + EXTRN_MDL_SOURCE_BASEDIR_LBCS = \"{EXTRN_MDL_SOURCE_BASEDIR_LBCS}\"''') + # + #----------------------------------------------------------------------- + # + # Make sure that DO_ENSEMBLE is set to a valid value. Then set the names + # of the ensemble members. These will be used to set the ensemble member + # directories. Also, set the full path to the FV3 namelist file corresponding + # to each ensemble member. + # + #----------------------------------------------------------------------- + # + global NDIGITS_ENSMEM_NAMES,ENSMEM_NAMES,FV3_NML_ENSMEM_FPS,NUM_ENS_MEMBERS + NDIGITS_ENSMEM_NAMES=0 + ENSMEM_NAMES=[] + FV3_NML_ENSMEM_FPS=[] + if DO_ENSEMBLE: + NDIGITS_ENSMEM_NAMES=len(str(NUM_ENS_MEMBERS)) + fmt=f"0{NDIGITS_ENSMEM_NAMES}d" + for i in range(NUM_ENS_MEMBERS): + ENSMEM_NAMES.append(f"mem{fmt}".format(i+1)) + FV3_NML_ENSMEM_FPS.append(os.path.join(EXPTDIR, f"{FV3_NML_FN}_{ENSMEM_NAMES[i]}")) + # + #----------------------------------------------------------------------- + # + # Set the full path to the forecast model executable. + # + #----------------------------------------------------------------------- + # + global FV3_EXEC_FP + FV3_EXEC_FP = os.path.join(EXECDIR, FV3_EXEC_FN) + # + #----------------------------------------------------------------------- + # + # Set the full path to the script that can be used to (re)launch the + # workflow. Also, if USE_CRON_TO_RELAUNCH is set to TRUE, set the line + # to add to the cron table to automatically relaunch the workflow every + # CRON_RELAUNCH_INTVL_MNTS minutes. Otherwise, set the variable con- + # taining this line to a null string. + # + #----------------------------------------------------------------------- + # + global WFLOW_LAUNCH_SCRIPT_FP, WFLOW_LAUNCH_LOG_FP, CRONTAB_LINE + WFLOW_LAUNCH_SCRIPT_FP = os.path.join(USHDIR, WFLOW_LAUNCH_SCRIPT_FN) + WFLOW_LAUNCH_LOG_FP = os.path.join(EXPTDIR, WFLOW_LAUNCH_LOG_FN) + if USE_CRON_TO_RELAUNCH: + CRONTAB_LINE=f'''*/{CRON_RELAUNCH_INTVL_MNTS} * * * * cd {EXPTDIR} && ./{WFLOW_LAUNCH_SCRIPT_FN} called_from_cron="TRUE" >> ./{WFLOW_LAUNCH_LOG_FN} 2>&1''' + else: + CRONTAB_LINE="" + # + #----------------------------------------------------------------------- + # + # Set the full path to the script that, for a given task, loads the + # necessary module files and runs the tasks. + # + #----------------------------------------------------------------------- + # + global LOAD_MODULES_RUN_TASK_FP + LOAD_MODULES_RUN_TASK_FP = os.path.join(USHDIR, "load_modules_run_task.sh") + # + #----------------------------------------------------------------------- + # + # Define the various work subdirectories under the main work directory. + # Each of these corresponds to a different step/substep/task in the pre- + # processing, as follows: + # + # GRID_DIR: + # Directory in which the grid files will be placed (if RUN_TASK_MAKE_GRID + # is set to True) or searched for (if RUN_TASK_MAKE_GRID is set to + # False). + # + # OROG_DIR: + # Directory in which the orography files will be placed (if RUN_TASK_MAKE_OROG + # is set to True) or searched for (if RUN_TASK_MAKE_OROG is set to + # False). + # + # SFC_CLIMO_DIR: + # Directory in which the surface climatology files will be placed (if + # RUN_TASK_MAKE_SFC_CLIMO is set to True) or searched for (if + # RUN_TASK_MAKE_SFC_CLIMO is set to False). + # + #---------------------------------------------------------------------- + # + global RUN_TASK_MAKE_GRID, RUN_TASK_MAKE_OROG, RUN_TASK_MAKE_SFC_CLIMO + global GRID_DIR, OROG_DIR, SFC_CLIMO_DIR + global RUN_TASK_VX_GRIDSTAT, RUN_TASK_VX_POINTSTAT, RUN_TASK_VX_ENSGRID + + # + #----------------------------------------------------------------------- + # + # Make sure that DO_ENSEMBLE is set to TRUE when running ensemble vx. + # + #----------------------------------------------------------------------- + # + if (not DO_ENSEMBLE) and (RUN_TASK_VX_ENSGRID or RUN_TASK_VX_ENSPOINT): + print_err_msg_exit(f''' + Ensemble verification can not be run unless running in ensemble mode: + DO_ENSEMBLE = \"{DO_ENSEMBLE}\" + RUN_TASK_VX_ENSGRID = \"{RUN_TASK_VX_ENSGRID}\" + RUN_TASK_VX_ENSPOINT = \"{RUN_TASK_VX_ENSPOINT}\"''') + + if RUN_ENVIR == "nco": + + nco_fix_dir = os.path.join(DOMAIN_PREGEN_BASEDIR, PREDEF_GRID_NAME) + if not os.path.exists(nco_fix_dir): + print_err_msg_exit(f''' + The directory (nco_fix_dir) that should contain the pregenerated grid, + orography, and surface climatology files does not exist: + nco_fix_dir = \"{nco_fix_dir}\"''') + + if RUN_TASK_MAKE_GRID or \ + ( not RUN_TASK_MAKE_GRID and \ + GRID_DIR != nco_fix_dir ): + + msg=f''' + When RUN_ENVIR is set to \"nco\", the workflow assumes that pregenerated + grid files already exist in the directory + + {DOMAIN_PREGEN_BASEDIR}/{PREDEF_GRID_NAME} + + where + + DOMAIN_PREGEN_BASEDIR = \"{DOMAIN_PREGEN_BASEDIR}\" + PREDEF_GRID_NAME = \"{PREDEF_GRID_NAME}\" + + Thus, the MAKE_GRID_TN task must not be run (i.e. RUN_TASK_MAKE_GRID must + be set to \"FALSE\"), and the directory in which to look for the grid + files (i.e. GRID_DIR) must be set to the one above. Current values for + these quantities are: + + RUN_TASK_MAKE_GRID = \"{RUN_TASK_MAKE_GRID}\" + GRID_DIR = \"{GRID_DIR}\" + + Resetting RUN_TASK_MAKE_GRID to \"FALSE\" and GRID_DIR to the one above. + Reset values are: + ''' + + RUN_TASK_MAKE_GRID=False + GRID_DIR=nco_fix_dir + + msg+=f''' + RUN_TASK_MAKE_GRID = \"{RUN_TASK_MAKE_GRID}\" + GRID_DIR = \"{GRID_DIR}\" + ''' + + print_info_msg(msg) + + + if RUN_TASK_MAKE_OROG or \ + ( not RUN_TASK_MAKE_OROG and \ + OROG_DIR != nco_fix_dir ): + + msg=f''' + When RUN_ENVIR is set to \"nco\", the workflow assumes that pregenerated + orography files already exist in the directory + {DOMAIN_PREGEN_BASEDIR}/{PREDEF_GRID_NAME} + + where + + DOMAIN_PREGEN_BASEDIR = \"{DOMAIN_PREGEN_BASEDIR}\" + PREDEF_GRID_NAME = \"{PREDEF_GRID_NAME}\" + + Thus, the MAKE_OROG_TN task must not be run (i.e. RUN_TASK_MAKE_OROG must + be set to \"FALSE\"), and the directory in which to look for the orography + files (i.e. OROG_DIR) must be set to the one above. Current values for + these quantities are: + + RUN_TASK_MAKE_OROG = \"{RUN_TASK_MAKE_OROG}\" + OROG_DIR = \"{OROG_DIR}\" + + Resetting RUN_TASK_MAKE_OROG to \"FALSE\" and OROG_DIR to the one above. + Reset values are: + ''' + + RUN_TASK_MAKE_OROG=False + OROG_DIR=nco_fix_dir + + msg+=f''' + RUN_TASK_MAKE_OROG = \"{RUN_TASK_MAKE_OROG}\" + OROG_DIR = \"{OROG_DIR}\" + ''' + + print_info_msg(msg) + + + if RUN_TASK_MAKE_SFC_CLIMO or \ + ( not RUN_TASK_MAKE_SFC_CLIMO and \ + SFC_CLIMO_DIR != nco_fix_dir ): + + msg=f''' + When RUN_ENVIR is set to \"nco\", the workflow assumes that pregenerated + surface climatology files already exist in the directory + + {DOMAIN_PREGEN_BASEDIR}/{PREDEF_GRID_NAME} + + where + + DOMAIN_PREGEN_BASEDIR = \"{DOMAIN_PREGEN_BASEDIR}\" + PREDEF_GRID_NAME = \"{PREDEF_GRID_NAME}\" + + Thus, the MAKE_SFC_CLIMO_TN task must not be run (i.e. RUN_TASK_MAKE_SFC_CLIMO + must be set to \"FALSE\"), and the directory in which to look for the + surface climatology files (i.e. SFC_CLIMO_DIR) must be set to the one + above. Current values for these quantities are: + + RUN_TASK_MAKE_SFC_CLIMO = \"{RUN_TASK_MAKE_SFC_CLIMO}\" + SFC_CLIMO_DIR = \"{SFC_CLIMO_DIR}\" + + Resetting RUN_TASK_MAKE_SFC_CLIMO to \"FALSE\" and SFC_CLIMO_DIR to the + one above. Reset values are: + ''' + + RUN_TASK_MAKE_SFC_CLIMO=False + SFC_CLIMO_DIR=nco_fix_dir + + msg+=f''' + RUN_TASK_MAKE_SFC_CLIMO = \"{RUN_TASK_MAKE_SFC_CLIMO}\" + SFC_CLIMO_DIR = \"{SFC_CLIMO_DIR}\" + ''' + + print_info_msg(msg) + + if RUN_TASK_VX_GRIDSTAT: + + msg=f''' + When RUN_ENVIR is set to \"nco\", it is assumed that the verification + will not be run. + RUN_TASK_VX_GRIDSTAT = \"{RUN_TASK_VX_GRIDSTAT}\" + Resetting RUN_TASK_VX_GRIDSTAT to \"FALSE\" + Reset value is:''' + + RUN_TASK_VX_GRIDSTAT=False + + msg+=f''' + RUN_TASK_VX_GRIDSTAT = \"{RUN_TASK_VX_GRIDSTAT}\" + ''' + + print_info_msg(msg) + + if RUN_TASK_VX_POINTSTAT: + + msg=f''' + When RUN_ENVIR is set to \"nco\", it is assumed that the verification + will not be run. + RUN_TASK_VX_POINTSTAT = \"{RUN_TASK_VX_POINTSTAT}\" + Resetting RUN_TASK_VX_POINTSTAT to \"FALSE\" + Reset value is:''' + + RUN_TASK_VX_POINTSTAT=False + + msg=f''' + RUN_TASK_VX_POINTSTAT = \"{RUN_TASK_VX_POINTSTAT}\" + ''' + + print_info_msg(msg) + + if RUN_TASK_VX_ENSGRID: + + msg=f''' + When RUN_ENVIR is set to \"nco\", it is assumed that the verification + will not be run. + RUN_TASK_VX_ENSGRID = \"{RUN_TASK_VX_ENSGRID}\" + Resetting RUN_TASK_VX_ENSGRID to \"FALSE\" + Reset value is:''' + + RUN_TASK_VX_ENSGRID=False + + msg+=f''' + RUN_TASK_VX_ENSGRID = \"{RUN_TASK_VX_ENSGRID}\" + ''' + + print_info_msg(msg) + + # + #----------------------------------------------------------------------- + # + # Now consider community mode. + # + #----------------------------------------------------------------------- + # + else: + # + # If RUN_TASK_MAKE_GRID is set to False, the workflow will look for + # the pregenerated grid files in GRID_DIR. In this case, make sure that + # GRID_DIR exists. Otherwise, set it to a predefined location under the + # experiment directory (EXPTDIR). + # + if not RUN_TASK_MAKE_GRID: + if not os.path.exists(GRID_DIR): + print_err_msg_exit(f''' + The directory (GRID_DIR) that should contain the pregenerated grid files + does not exist: + GRID_DIR = \"{GRID_DIR}\"''') + else: + GRID_DIR=os.path.join(EXPTDIR,"grid") + # + # If RUN_TASK_MAKE_OROG is set to False, the workflow will look for + # the pregenerated orography files in OROG_DIR. In this case, make sure + # that OROG_DIR exists. Otherwise, set it to a predefined location under + # the experiment directory (EXPTDIR). + # + if not RUN_TASK_MAKE_OROG: + if not os.path.exists(OROG_DIR): + print_err_msg_exit(f''' + The directory (OROG_DIR) that should contain the pregenerated orography + files does not exist: + OROG_DIR = \"{OROG_DIR}\"''') + else: + OROG_DIR=os.path.join(EXPTDIR,"orog") + # + # If RUN_TASK_MAKE_SFC_CLIMO is set to False, the workflow will look + # for the pregenerated surface climatology files in SFC_CLIMO_DIR. In + # this case, make sure that SFC_CLIMO_DIR exists. Otherwise, set it to + # a predefined location under the experiment directory (EXPTDIR). + # + if not RUN_TASK_MAKE_SFC_CLIMO: + if not os.path.exists(SFC_CLIMO_DIR): + print_err_msg_exit(f''' + The directory (SFC_CLIMO_DIR) that should contain the pregenerated surface + climatology files does not exist: + SFC_CLIMO_DIR = \"{SFC_CLIMO_DIR}\"''') + else: + SFC_CLIMO_DIR=os.path.join(EXPTDIR,"sfc_climo") + + #----------------------------------------------------------------------- + # + # Set cycle-independent parameters associated with the external models + # from which we will obtain the ICs and LBCs. + # + #----------------------------------------------------------------------- + # + + # export env vars before calling another module + export_vars() + + set_extrn_mdl_params() + + IMPORTS = ["EXTRN_MDL_LBCS_OFFSET_HRS"] + import_vars(env_vars=IMPORTS) + # + #----------------------------------------------------------------------- + # + # Set parameters according to the type of horizontal grid generation + # method specified. First consider GFDL's global-parent-grid based + # method. + # + #----------------------------------------------------------------------- + # + global LON_CTR,LAT_CTR,NX,NY,NHW,STRETCH_FAC,\ + ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG,\ + IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG,\ + JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG,\ + JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG + global PAZI,DEL_ANGLE_X_SG,DEL_ANGLE_Y_SG,\ + NEG_NX_OF_DOM_WITH_WIDE_HALO,\ + NEG_NY_OF_DOM_WITH_WIDE_HALO + + if GRID_GEN_METHOD == "GFDLgrid": + + (\ + LON_CTR,LAT_CTR,NX,NY,NHW,STRETCH_FAC, + ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG \ + ) = \ + set_gridparams_GFDLgrid( \ + lon_of_t6_ctr=GFDLgrid_LON_T6_CTR, \ + lat_of_t6_ctr=GFDLgrid_LAT_T6_CTR, \ + res_of_t6g=GFDLgrid_NUM_CELLS, \ + stretch_factor=GFDLgrid_STRETCH_FAC, \ + refine_ratio_t6g_to_t7g=GFDLgrid_REFINE_RATIO, \ + istart_of_t7_on_t6g=GFDLgrid_ISTART_OF_RGNL_DOM_ON_T6G, \ + iend_of_t7_on_t6g=GFDLgrid_IEND_OF_RGNL_DOM_ON_T6G, \ + jstart_of_t7_on_t6g=GFDLgrid_JSTART_OF_RGNL_DOM_ON_T6G, \ + jend_of_t7_on_t6g=GFDLgrid_JEND_OF_RGNL_DOM_ON_T6G) + # + #----------------------------------------------------------------------- + # + # Now consider Jim Purser's map projection/grid generation method. + # + #----------------------------------------------------------------------- + # + elif GRID_GEN_METHOD == "ESGgrid": + + (\ + LON_CTR,LAT_CTR,NX,NY,PAZI, + NHW,STRETCH_FAC,DEL_ANGLE_X_SG,DEL_ANGLE_Y_SG, + NEG_NX_OF_DOM_WITH_WIDE_HALO, + NEG_NY_OF_DOM_WITH_WIDE_HALO \ + ) = \ + set_gridparams_ESGgrid( \ + lon_ctr=ESGgrid_LON_CTR, \ + lat_ctr=ESGgrid_LAT_CTR, \ + nx=ESGgrid_NX, \ + ny=ESGgrid_NY, \ + pazi=ESGgrid_PAZI, \ + halo_width=ESGgrid_WIDE_HALO_WIDTH, \ + delx=ESGgrid_DELX, \ + dely=ESGgrid_DELY) + + # + #----------------------------------------------------------------------- + # + # Create a new experiment directory. Note that at this point we are + # guaranteed that there is no preexisting experiment directory. For + # platforms with no workflow manager, we need to create LOGDIR as well, + # since it won't be created later at runtime. + # + #----------------------------------------------------------------------- + # + mkdir_vrfy(f' -p "{EXPTDIR}"') + mkdir_vrfy(f' -p "{LOGDIR}"') + # + #----------------------------------------------------------------------- + # + # If not running the MAKE_GRID_TN, MAKE_OROG_TN, and/or MAKE_SFC_CLIMO + # tasks, create symlinks under the FIXLAM directory to pregenerated grid, + # orography, and surface climatology files. In the process, also set + # RES_IN_FIXLAM_FILENAMES, which is the resolution of the grid (in units + # of number of grid points on an equivalent global uniform cubed-sphere + # grid) used in the names of the fixed files in the FIXLAM directory. + # + #----------------------------------------------------------------------- + # + mkdir_vrfy(f' -p "{FIXLAM}"') + RES_IN_FIXLAM_FILENAMES="" + # + #----------------------------------------------------------------------- + # + # If the grid file generation task in the workflow is going to be skipped + # (because pregenerated files are available), create links in the FIXLAM + # directory to the pregenerated grid files. + # + #----------------------------------------------------------------------- + # + + # export env vars + export_vars() + + # link fix files + res_in_grid_fns="" + if not RUN_TASK_MAKE_GRID: + + res_in_grid_fns = link_fix( \ + verbose=VERBOSE, \ + file_group="grid") + + RES_IN_FIXLAM_FILENAMES=res_in_grid_fns + # + #----------------------------------------------------------------------- + # + # If the orography file generation task in the workflow is going to be + # skipped (because pregenerated files are available), create links in + # the FIXLAM directory to the pregenerated orography files. + # + #----------------------------------------------------------------------- + # + res_in_orog_fns="" + if not RUN_TASK_MAKE_OROG: + + res_in_orog_fns = link_fix( \ + verbose=VERBOSE, \ + file_group="orog") + + if not RES_IN_FIXLAM_FILENAMES and \ + ( res_in_orog_fns != RES_IN_FIXLAM_FILENAMES): + print_err_msg_exit(f''' + The resolution extracted from the orography file names (res_in_orog_fns) + does not match the resolution in other groups of files already consi- + dered (RES_IN_FIXLAM_FILENAMES): + res_in_orog_fns = {res_in_orog_fns} + RES_IN_FIXLAM_FILENAMES = {RES_IN_FIXLAM_FILENAMES}''') + else: + RES_IN_FIXLAM_FILENAMES=res_in_orog_fns + # + #----------------------------------------------------------------------- + # + # If the surface climatology file generation task in the workflow is + # going to be skipped (because pregenerated files are available), create + # links in the FIXLAM directory to the pregenerated surface climatology + # files. + # + #----------------------------------------------------------------------- + # + res_in_sfc_climo_fns="" + if not RUN_TASK_MAKE_SFC_CLIMO: + + res_in_sfc_climo_fns = link_fix( \ + verbose=VERBOSE, \ + file_group="sfc_climo") + + if RES_IN_FIXLAM_FILENAMES and \ + res_in_sfc_climo_fns != RES_IN_FIXLAM_FILENAMES: + print_err_msg_exit(f''' + The resolution extracted from the surface climatology file names (res_- + in_sfc_climo_fns) does not match the resolution in other groups of files + already considered (RES_IN_FIXLAM_FILENAMES): + res_in_sfc_climo_fns = {res_in_sfc_climo_fns} + RES_IN_FIXLAM_FILENAMES = {RES_IN_FIXLAM_FILENAMES}''') + else: + RES_IN_FIXLAM_FILENAMES=res_in_sfc_climo_fns + # + #----------------------------------------------------------------------- + # + # The variable CRES is needed in constructing various file names. If + # not running the make_grid task, we can set it here. Otherwise, it + # will get set to a valid value by that task. + # + #----------------------------------------------------------------------- + # + global CRES + CRES="" + if not RUN_TASK_MAKE_GRID: + CRES=f"C{RES_IN_FIXLAM_FILENAMES}" + # + #----------------------------------------------------------------------- + # + # Make sure that WRITE_DOPOST is set to a valid value. + # + #----------------------------------------------------------------------- + # + global RUN_TASK_RUN_POST + if WRITE_DOPOST: + # Turn off run_post + RUN_TASK_RUN_POST=False + + # Check if SUB_HOURLY_POST is on + if SUB_HOURLY_POST: + print_err_msg_exit(f''' + SUB_HOURLY_POST is NOT available with Inline Post yet.''') + # + #----------------------------------------------------------------------- + # + # Calculate PE_MEMBER01. This is the number of MPI tasks used for the + # forecast, including those for the write component if QUILTING is set + # to True. + # + #----------------------------------------------------------------------- + # + global PE_MEMBER01 + PE_MEMBER01=LAYOUT_X*LAYOUT_Y + if QUILTING: + PE_MEMBER01 = PE_MEMBER01 + WRTCMP_write_groups*WRTCMP_write_tasks_per_group + + print_info_msg(f''' + The number of MPI tasks for the forecast (including those for the write + component if it is being used) are: + PE_MEMBER01 = {PE_MEMBER01}''', verbose=VERBOSE) + # + #----------------------------------------------------------------------- + # + # Calculate the number of nodes (NNODES_RUN_FCST) to request from the job + # scheduler for the forecast task (RUN_FCST_TN). This is just PE_MEMBER01 + # dividied by the number of processes per node we want to request for this + # task (PPN_RUN_FCST), then rounded up to the nearest integer, i.e. + # + # NNODES_RUN_FCST = ceil(PE_MEMBER01/PPN_RUN_FCST) + # + # where ceil(...) is the ceiling function, i.e. it rounds its floating + # point argument up to the next larger integer. Since in bash, division + # of two integers returns a truncated integer, and since bash has no + # built-in ceil(...) function, we perform the rounding-up operation by + # adding the denominator (of the argument of ceil(...) above) minus 1 to + # the original numerator, i.e. by redefining NNODES_RUN_FCST to be + # + # NNODES_RUN_FCST = (PE_MEMBER01 + PPN_RUN_FCST - 1)/PPN_RUN_FCST + # + #----------------------------------------------------------------------- + # + global NNODES_RUN_FCST + NNODES_RUN_FCST= (PE_MEMBER01 + PPN_RUN_FCST - 1)//PPN_RUN_FCST + + # + #----------------------------------------------------------------------- + # + # Call the function that checks whether the RUC land surface model (LSM) + # is being called by the physics suite and sets the workflow variable + # SDF_USES_RUC_LSM to True or False accordingly. + # + #----------------------------------------------------------------------- + # + global SDF_USES_RUC_LSM + SDF_USES_RUC_LSM = check_ruc_lsm( \ + ccpp_phys_suite_fp=CCPP_PHYS_SUITE_IN_CCPP_FP) + # + #----------------------------------------------------------------------- + # + # Set the name of the file containing aerosol climatology data that, if + # necessary, can be used to generate approximate versions of the aerosol + # fields needed by Thompson microphysics. This file will be used to + # generate such approximate aerosol fields in the ICs and LBCs if Thompson + # MP is included in the physics suite and if the exteranl model for ICs + # or LBCs does not already provide these fields. Also, set the full path + # to this file. + # + #----------------------------------------------------------------------- + # + THOMPSON_MP_CLIMO_FN="Thompson_MP_MONTHLY_CLIMO.nc" + THOMPSON_MP_CLIMO_FP=os.path.join(FIXam,THOMPSON_MP_CLIMO_FN) + # + #----------------------------------------------------------------------- + # + # Call the function that, if the Thompson microphysics parameterization + # is being called by the physics suite, modifies certain workflow arrays + # to ensure that fixed files needed by this parameterization are copied + # to the FIXam directory and appropriate symlinks to them are created in + # the run directories. This function also sets the workflow variable + # SDF_USES_THOMPSON_MP that indicates whether Thompson MP is called by + # the physics suite. + # + #----------------------------------------------------------------------- + # + SDF_USES_THOMPSON_MP = set_thompson_mp_fix_files( \ + ccpp_phys_suite_fp=CCPP_PHYS_SUITE_IN_CCPP_FP, \ + thompson_mp_climo_fn=THOMPSON_MP_CLIMO_FN) + + IMPORTS = [ "CYCLEDIR_LINKS_TO_FIXam_FILES_MAPPING", "FIXgsm_FILES_TO_COPY_TO_FIXam" ] + import_vars(env_vars=IMPORTS) + # + #----------------------------------------------------------------------- + # + # Generate the shell script that will appear in the experiment directory + # (EXPTDIR) and will contain definitions of variables needed by the va- + # rious scripts in the workflow. We refer to this as the experiment/ + # workflow global variable definitions file. We will create this file + # by: + # + # 1) Copying the default workflow/experiment configuration file (speci- + # fied by EXPT_DEFAULT_CONFIG_FN and located in the shell script di- + # rectory specified by USHDIR) to the experiment directory and rena- + # ming it to the name specified by GLOBAL_VAR_DEFNS_FN. + # + # 2) Resetting the default variable values in this file to their current + # values. This is necessary because these variables may have been + # reset by the user-specified configuration file (if one exists in + # USHDIR) and/or by this setup script, e.g. because predef_domain is + # set to a valid non-empty value. + # + # 3) Appending to the variable definitions file any new variables intro- + # duced in this setup script that may be needed by the scripts that + # perform the various tasks in the workflow (and which source the va- + # riable defintions file). + # + # First, set the full path to the variable definitions file and copy the + # default configuration script into it. + # + #----------------------------------------------------------------------- + # + + # update dictionary with globals() values + update_dict = {k: globals()[k] for k in cfg_d.keys() if k in globals() } + cfg_d.update(update_dict) + + # write the updated default dictionary + global GLOBAL_VAR_DEFNS_FP + GLOBAL_VAR_DEFNS_FP=os.path.join(EXPTDIR,GLOBAL_VAR_DEFNS_FN) + all_lines=cfg_to_shell_str(cfg_d) + + with open(GLOBAL_VAR_DEFNS_FP,'w') as f: + msg = f""" # + # + #----------------------------------------------------------------------- + #----------------------------------------------------------------------- + # Section 1: + # This section contains definitions of the various constants defined in + # the file {CONSTANTS_FN}. + #----------------------------------------------------------------------- + #----------------------------------------------------------------------- + # + """ + f.write(dedent(msg)) + f.write(const_lines) + + msg = f""" # + #----------------------------------------------------------------------- + #----------------------------------------------------------------------- + # Section 2: + # This section contains (most of) the primary experiment variables, i.e. + # those variables that are defined in the default configuration file + # (config_defaults.sh) and that can be reset via the user-specified + # experiment configuration file (config.sh). + #----------------------------------------------------------------------- + #----------------------------------------------------------------------- + # + """ + f.write(dedent(msg)) + f.write(all_lines) + + # print info message + msg=dedent(f''' + Before updating default values of experiment variables to user-specified + values, the variable \"line_list\" contains: + + ''') + + msg +=dedent(f''' + {all_lines}''') + + print_info_msg(msg,verbose=DEBUG) + # + # print info message + # + print_info_msg(f''' + Generating the global experiment variable definitions file specified by + GLOBAL_VAR_DEFNS_FN: + GLOBAL_VAR_DEFNS_FN = \"{GLOBAL_VAR_DEFNS_FN}\" + Full path to this file is: + GLOBAL_VAR_DEFNS_FP = \"{GLOBAL_VAR_DEFNS_FP}\" + For more detailed information, set DEBUG to \"TRUE\" in the experiment + configuration file (\"{EXPT_CONFIG_FN}\").''') + + # + #----------------------------------------------------------------------- + # + # Append additional variable definitions (and comments) to the variable + # definitions file. These variables have been set above using the vari- + # ables in the default and local configuration scripts. These variables + # are needed by various tasks/scripts in the workflow. + # + #----------------------------------------------------------------------- + # + msg = f""" + # + #----------------------------------------------------------------------- + #----------------------------------------------------------------------- + # Section 2: + # This section defines variables that have been derived from the primary + # set of experiment variables above (we refer to these as \"derived\" or + # \"secondary\" variables). + #----------------------------------------------------------------------- + #----------------------------------------------------------------------- + # + """ + with open(GLOBAL_VAR_DEFNS_FP,'a') as f: + f.write(dedent(msg)) + + settings = { + # + #----------------------------------------------------------------------- + # + # Full path to workflow (re)launch script, its log file, and the line + # that gets added to the cron table to launch this script if the flag + # USE_CRON_TO_RELAUNCH is set to \"TRUE\". + # + #----------------------------------------------------------------------- + # + 'WFLOW_LAUNCH_SCRIPT_FP': WFLOW_LAUNCH_SCRIPT_FP, + 'WFLOW_LAUNCH_LOG_FP': WFLOW_LAUNCH_LOG_FP, + 'CRONTAB_LINE': CRONTAB_LINE, + # + #----------------------------------------------------------------------- + # + # Directories. + # + #----------------------------------------------------------------------- + # + 'SR_WX_APP_TOP_DIR': SR_WX_APP_TOP_DIR, + 'USHDIR': USHDIR, + 'SCRIPTSDIR': SCRIPTSDIR, + 'JOBSDIR': JOBSDIR, + 'SORCDIR': SORCDIR, + 'SRC_DIR': SRC_DIR, + 'PARMDIR': PARMDIR, + 'MODULES_DIR': MODULES_DIR, + 'EXECDIR': EXECDIR, + 'FIXam': FIXam, + 'FIXclim': FIXclim, + 'FIXLAM': FIXLAM, + 'FIXgsm': FIXgsm, + 'FIXaer': FIXaer, + 'FIXlut': FIXlut, + 'COMROOT': COMROOT, + 'COMOUT_BASEDIR': COMOUT_BASEDIR, + 'TEMPLATE_DIR': TEMPLATE_DIR, + 'VX_CONFIG_DIR': VX_CONFIG_DIR, + 'METPLUS_CONF': METPLUS_CONF, + 'MET_CONFIG': MET_CONFIG, + 'UFS_WTHR_MDL_DIR': UFS_WTHR_MDL_DIR, + 'UFS_UTILS_DIR': UFS_UTILS_DIR, + 'SFC_CLIMO_INPUT_DIR': SFC_CLIMO_INPUT_DIR, + 'TOPO_DIR': TOPO_DIR, + 'UPP_DIR': UPP_DIR, + + 'EXPTDIR': EXPTDIR, + 'LOGDIR': LOGDIR, + 'CYCLE_BASEDIR': CYCLE_BASEDIR, + 'GRID_DIR': GRID_DIR, + 'OROG_DIR': OROG_DIR, + 'SFC_CLIMO_DIR': SFC_CLIMO_DIR, + + 'NDIGITS_ENSMEM_NAMES': NDIGITS_ENSMEM_NAMES, + 'ENSMEM_NAMES': ENSMEM_NAMES, + 'FV3_NML_ENSMEM_FPS': FV3_NML_ENSMEM_FPS, + # + #----------------------------------------------------------------------- + # + # Files. + # + #----------------------------------------------------------------------- + # + 'GLOBAL_VAR_DEFNS_FP': GLOBAL_VAR_DEFNS_FP, + + 'DATA_TABLE_FN': DATA_TABLE_FN, + 'DIAG_TABLE_FN': DIAG_TABLE_FN, + 'FIELD_TABLE_FN': FIELD_TABLE_FN, + 'MODEL_CONFIG_FN': MODEL_CONFIG_FN, + 'NEMS_CONFIG_FN': NEMS_CONFIG_FN, + + 'DATA_TABLE_TMPL_FN': DATA_TABLE_TMPL_FN, + 'DIAG_TABLE_TMPL_FN': DIAG_TABLE_TMPL_FN, + 'FIELD_TABLE_TMPL_FN': FIELD_TABLE_TMPL_FN, + 'MODEL_CONFIG_TMPL_FN': MODEL_CONFIG_TMPL_FN, + 'NEMS_CONFIG_TMPL_FN': NEMS_CONFIG_TMPL_FN, + + 'DATA_TABLE_TMPL_FP': DATA_TABLE_TMPL_FP, + 'DIAG_TABLE_TMPL_FP': DIAG_TABLE_TMPL_FP, + 'FIELD_TABLE_TMPL_FP': FIELD_TABLE_TMPL_FP, + 'FV3_NML_BASE_SUITE_FP': FV3_NML_BASE_SUITE_FP, + 'FV3_NML_YAML_CONFIG_FP': FV3_NML_YAML_CONFIG_FP, + 'FV3_NML_BASE_ENS_FP': FV3_NML_BASE_ENS_FP, + 'MODEL_CONFIG_TMPL_FP': MODEL_CONFIG_TMPL_FP, + 'NEMS_CONFIG_TMPL_FP': NEMS_CONFIG_TMPL_FP, + + 'CCPP_PHYS_SUITE_FN': CCPP_PHYS_SUITE_FN, + 'CCPP_PHYS_SUITE_IN_CCPP_FP': CCPP_PHYS_SUITE_IN_CCPP_FP, + 'CCPP_PHYS_SUITE_FP': CCPP_PHYS_SUITE_FP, + + 'FIELD_DICT_FN': FIELD_DICT_FN, + 'FIELD_DICT_IN_UWM_FP': FIELD_DICT_IN_UWM_FP, + 'FIELD_DICT_FP': FIELD_DICT_FP, + + 'DATA_TABLE_FP': DATA_TABLE_FP, + 'FIELD_TABLE_FP': FIELD_TABLE_FP, + 'FV3_NML_FN': FV3_NML_FN, # This may not be necessary... + 'FV3_NML_FP': FV3_NML_FP, + 'NEMS_CONFIG_FP': NEMS_CONFIG_FP, + + 'FV3_EXEC_FP': FV3_EXEC_FP, + + 'LOAD_MODULES_RUN_TASK_FP': LOAD_MODULES_RUN_TASK_FP, + + 'THOMPSON_MP_CLIMO_FN': THOMPSON_MP_CLIMO_FN, + 'THOMPSON_MP_CLIMO_FP': THOMPSON_MP_CLIMO_FP, + # + #----------------------------------------------------------------------- + # + # Flag for creating relative symlinks (as opposed to absolute ones). + # + #----------------------------------------------------------------------- + # + 'RELATIVE_LINK_FLAG': RELATIVE_LINK_FLAG, + # + #----------------------------------------------------------------------- + # + # Parameters that indicate whether or not various parameterizations are + # included in and called by the physics suite. + # + #----------------------------------------------------------------------- + # + 'SDF_USES_RUC_LSM': SDF_USES_RUC_LSM, + 'SDF_USES_THOMPSON_MP': SDF_USES_THOMPSON_MP, + # + #----------------------------------------------------------------------- + # + # Grid configuration parameters needed regardless of grid generation + # method used. + # + #----------------------------------------------------------------------- + # + 'GTYPE': GTYPE, + 'TILE_RGNL': TILE_RGNL, + + 'LON_CTR': LON_CTR, + 'LAT_CTR': LAT_CTR, + 'NX': NX, + 'NY': NY, + 'NHW': NHW, + 'STRETCH_FAC': STRETCH_FAC, + + 'RES_IN_FIXLAM_FILENAMES': RES_IN_FIXLAM_FILENAMES, + # + # If running the make_grid task, CRES will be set to a null string during + # the grid generation step. It will later be set to an actual value after + # the make_grid task is complete. + # + 'CRES': CRES + } + # + #----------------------------------------------------------------------- + # + # Append to the variable definitions file the defintions of grid parame- + # ters that are specific to the grid generation method used. + # + #----------------------------------------------------------------------- + # + if GRID_GEN_METHOD == "GFDLgrid": + # + #----------------------------------------------------------------------- + # + # Grid configuration parameters for a regional grid generated from a + # global parent cubed-sphere grid. This is the method originally + # suggested by GFDL since it allows GFDL's nested grid generator to be + # used to generate a regional grid. However, for large regional domains, + # it results in grids that have an unacceptably large range of cell sizes + # (i.e. ratio of maximum to minimum cell size is not sufficiently close + # to 1). + # + #----------------------------------------------------------------------- + # + settings.update({ + 'ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG': ISTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + 'IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG': IEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + 'JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG': JSTART_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG, + 'JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG': JEND_OF_RGNL_DOM_WITH_WIDE_HALO_ON_T6SG + }) + elif GRID_GEN_METHOD == "ESGgrid": + # + #----------------------------------------------------------------------- + # + # Grid configuration parameters for a regional grid generated independently + # of a global parent grid. This method was developed by Jim Purser of + # EMC and results in very uniform grids (i.e. ratio of maximum to minimum + # cell size is very close to 1). + # + #----------------------------------------------------------------------- + # + settings.update({ + 'DEL_ANGLE_X_SG': DEL_ANGLE_X_SG, + 'DEL_ANGLE_Y_SG': DEL_ANGLE_Y_SG, + 'NEG_NX_OF_DOM_WITH_WIDE_HALO': NEG_NX_OF_DOM_WITH_WIDE_HALO, + 'NEG_NY_OF_DOM_WITH_WIDE_HALO': NEG_NY_OF_DOM_WITH_WIDE_HALO, + 'PAZI': PAZI or '' + }) + # + #----------------------------------------------------------------------- + # + # Continue appending variable definitions to the variable definitions + # file. + # + #----------------------------------------------------------------------- + # + settings.update({ + # + #----------------------------------------------------------------------- + # + # Flag in the \"{MODEL_CONFIG_FN}\" file for coupling the ocean model to + # the weather model. + # + #----------------------------------------------------------------------- + # + 'CPL': CPL, + # + #----------------------------------------------------------------------- + # + # Name of the ozone parameterization. The value this gets set to depends + # on the CCPP physics suite being used. + # + #----------------------------------------------------------------------- + # + 'OZONE_PARAM': OZONE_PARAM, + # + #----------------------------------------------------------------------- + # + # If USE_USER_STAGED_EXTRN_FILES is set to \"FALSE\", this is the system + # directory in which the workflow scripts will look for the files generated + # by the external model specified in EXTRN_MDL_NAME_ICS. These files will + # be used to generate the input initial condition and surface files for + # the FV3-LAM. + # + #----------------------------------------------------------------------- + # + 'EXTRN_MDL_SYSBASEDIR_ICS': EXTRN_MDL_SYSBASEDIR_ICS, + # + #----------------------------------------------------------------------- + # + # If USE_USER_STAGED_EXTRN_FILES is set to \"FALSE\", this is the system + # directory in which the workflow scripts will look for the files generated + # by the external model specified in EXTRN_MDL_NAME_LBCS. These files + # will be used to generate the input lateral boundary condition files for + # the FV3-LAM. + # + #----------------------------------------------------------------------- + # + 'EXTRN_MDL_SYSBASEDIR_LBCS': EXTRN_MDL_SYSBASEDIR_LBCS, + # + #----------------------------------------------------------------------- + # + # Shift back in time (in units of hours) of the starting time of the ex- + # ternal model specified in EXTRN_MDL_NAME_LBCS. + # + #----------------------------------------------------------------------- + # + 'EXTRN_MDL_LBCS_OFFSET_HRS': EXTRN_MDL_LBCS_OFFSET_HRS, + # + #----------------------------------------------------------------------- + # + # Boundary condition update times (in units of forecast hours). Note that + # LBC_SPEC_FCST_HRS is an array, even if it has only one element. + # + #----------------------------------------------------------------------- + # + 'LBC_SPEC_FCST_HRS': LBC_SPEC_FCST_HRS, + # + #----------------------------------------------------------------------- + # + # The number of cycles for which to make forecasts and the list of + # starting dates/hours of these cycles. + # + #----------------------------------------------------------------------- + # + 'NUM_CYCLES': NUM_CYCLES, + 'ALL_CDATES': ALL_CDATES, + # + #----------------------------------------------------------------------- + # + # Parameters that determine whether FVCOM data will be used, and if so, + # their location. + # + # If USE_FVCOM is set to \"TRUE\", then FVCOM data (in the file FVCOM_FILE + # located in the directory FVCOM_DIR) will be used to update the surface + # boundary conditions during the initial conditions generation task + # (MAKE_ICS_TN). + # + #----------------------------------------------------------------------- + # + 'USE_FVCOM': USE_FVCOM, + 'FVCOM_DIR': FVCOM_DIR, + 'FVCOM_FILE': FVCOM_FILE, + # + #----------------------------------------------------------------------- + # + # Computational parameters. + # + #----------------------------------------------------------------------- + # + 'NCORES_PER_NODE': NCORES_PER_NODE, + 'PE_MEMBER01': PE_MEMBER01, + # + #----------------------------------------------------------------------- + # + # IF DO_SPP is set to "TRUE", N_VAR_SPP specifies the number of physics + # parameterizations that are perturbed with SPP. If DO_LSM_SPP is set to + # "TRUE", N_VAR_LNDP specifies the number of LSM parameters that are + # perturbed. LNDP_TYPE determines the way LSM perturbations are employed + # and FHCYC_LSM_SPP_OR_NOT sets FHCYC based on whether LSM perturbations + # are turned on or not. + # + #----------------------------------------------------------------------- + # + 'N_VAR_SPP': N_VAR_SPP, + 'N_VAR_LNDP': N_VAR_LNDP, + 'LNDP_TYPE': LNDP_TYPE, + 'LNDP_MODEL_TYPE': LNDP_MODEL_TYPE, + 'FHCYC_LSM_SPP_OR_NOT': FHCYC_LSM_SPP_OR_NOT + }) + + # + #----------------------------------------------------------------------- + # + # Now write all settings we collacted so far to var_defns file + # + #----------------------------------------------------------------------- + # + with open(GLOBAL_VAR_DEFNS_FP,'a') as f: + f.write(cfg_to_shell_str(settings)) + + # export all global variables back to the environment + export_vars() + + # + #----------------------------------------------------------------------- + # + # Check validity of parameters in one place, here in the end. + # + #----------------------------------------------------------------------- + # + + # update dictionary with globals() values + update_dict = {k: globals()[k] for k in cfg_d.keys() if k in globals() } + cfg_d.update(update_dict) + + # loop through cfg_d and check validity of params + cfg_v = load_config_file("valid_param_vals.yaml") + for k,v in cfg_d.items(): + if v == None: + continue + vkey = 'valid_vals_' + k + if (vkey in cfg_v) and not (v in cfg_v[vkey]): + print_err_msg_exit(f''' + The variable {k}={v} in {EXPT_DEFAULT_CONFIG_FN} or {EXPT_CONFIG_FN} does not have + a valid value. Possible values are: + {k} = {cfg_v[vkey]}''') + + # + #----------------------------------------------------------------------- + # + # Print message indicating successful completion of script. + # + #----------------------------------------------------------------------- + # + print_info_msg(f''' + ======================================================================== + Function setup() in \"{os.path.basename(__file__)}\" completed successfully!!! + ========================================================================''') + +# +#----------------------------------------------------------------------- +# +# Call the function defined above. +# +#----------------------------------------------------------------------- +# +if __name__ == "__main__": + setup() + diff --git a/ush/source_machine_file.sh b/ush/source_machine_file.sh new file mode 100644 index 0000000000..532335962b --- /dev/null +++ b/ush/source_machine_file.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# +# This script is a wrapper that sources the machine file but also allows +# for certain pre- and post-source commands to be executed (e.g. setting +# of "set -x" shell option depending on the DEBUG variable). +# + +if [ -z ${DEBUG+x} ] || [ "$DEBUG" != "TRUE" ]; then + { save_shell_opts; set -u +x; } > /dev/null 2>&1 +else + { save_shell_opts; set -u -x; } > /dev/null 2>&1 +fi + +source ${MACHINE_FILE} + +{ restore_shell_opts; } > /dev/null 2>&1 diff --git a/ush/source_util_funcs.sh b/ush/source_util_funcs.sh new file mode 100644 index 0000000000..fd03d9cad5 --- /dev/null +++ b/ush/source_util_funcs.sh @@ -0,0 +1,236 @@ +function source_util_funcs() { +# +#----------------------------------------------------------------------- +# +# Get the full path to the file in which this script/function is located +# (scrfunc_fp), the name of that file (scrfunc_fn), and the directory in +# which the file is located (scrfunc_dir). +# +#----------------------------------------------------------------------- +# + if [[ $(uname -s) == Darwin ]]; then + local scrfunc_fp=$( greadlink -f "${BASH_SOURCE[0]}" ) + else + local scrfunc_fp=$( readlink -f "${BASH_SOURCE[0]}" ) + fi + local scrfunc_fn=$( basename "${scrfunc_fp}" ) + local scrfunc_dir=$( dirname "${scrfunc_fp}" ) +# +#----------------------------------------------------------------------- +# +# Get the name of this function. +# +#----------------------------------------------------------------------- +# + local func_name="${FUNCNAME[0]}" +# +#----------------------------------------------------------------------- +# +# Set necessary directory variables. +# +#----------------------------------------------------------------------- +# + local ushdir="${scrfunc_dir}" + local bashutils_dir="${ushdir}/bash_utils" +# +#----------------------------------------------------------------------- +# +# Source the file containing workflow constants. +# +#----------------------------------------------------------------------- +# + . ${ushdir}/constants.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing functions to save and restore shell op- +# tions. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/save_restore_shell_opts.sh +# +#----------------------------------------------------------------------- +# +# Source the file that defines MacOS-specific UNIX command-line +# utilities, that mimic the functionality of the GNU equivalents +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/define_macos_utilities.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the functions that print out messages. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/print_msg.sh +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/set_bash_param.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that replaces variable values +# (or value placeholders) in several types of files (e.g. Fortran name- +# list files) with actual values. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/set_file_param.sh +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/count_files.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that changes all boolean +# options to TRUE or FALSE +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/boolify.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the functions that will echo given strings +# as uppercase or lowercase +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/change_case.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that checks for preexisting +# directories or files and handles them according to a specified method +# (which can be one of "delete", "rename", and "quit"). +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/check_for_preexist_dir_file.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing functions that execute filesystem commands +# (e.g. "cp", "mv") with verification (i.e. verifying that the commands +# completed successfully). +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/filesys_cmds_vrfy.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that searches an array for a +# specified string. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/is_element_of.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that gets the indices of those +# elements of an array that match a given string. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/get_elem_inds.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that determines whether or not +# a specified variable is an array. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/is_array.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that interpolates (or extrapo- +# lates) a grid cell size-dependent property to an arbitrary global +# cubed-sphere resolution. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/interpol_to_arbit_CRES.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that checks the validity of a +# variable's value (given a set of valid values). +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/check_var_valid_value.sh +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/print_input_args.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that processes a list of argu- +# ments to a script or function, where the list is comprised of a set of +# argument name-value pairs, e.g. arg1="value1", ... +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/process_args.sh +# +#----------------------------------------------------------------------- +# +# +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/get_manage_externals_config_property.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that returns to stdout the +# contents of a character (i.e. string) variable in a netcdf file. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/get_charvar_from_netcdf.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that creates a symlink to a +# file (including performing checks). +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/create_symlink_to_file.sh +# +#----------------------------------------------------------------------- +# +# Source the file containing the function that gets the stripped contents +# of a bash script or function. +# +#----------------------------------------------------------------------- +# + . ${bashutils_dir}/get_bash_file_contents.sh + +} +source_util_funcs + + diff --git a/ush/templates/FV3.input.yml b/ush/templates/FV3.input.yml new file mode 100644 index 0000000000..0e9276de25 --- /dev/null +++ b/ush/templates/FV3.input.yml @@ -0,0 +1,385 @@ +# This configuration file maintains the modifications that need to be +# made to the base FV3 namelist specified in +# +# ush/templates/input.nml.FV3 +# +# to obtain the namelist for each physics suite that the SRW App can +# run with. To build a namelist for one of these configurations, use +# the Python helper script +# +# ush/set_namelist.py +# +# and provide this file and the desired section via the -c option. + + +FV3_RRFS_v1beta: + gfs_physics_nml: &RRFS_v1beta_phys + do_deep: False + do_mynnsfclay: True + imfdeepcnv: -1 + imfshalcnv: -1 + iopt_alb: 2 + iopt_btr: 1 + iopt_crs: 1 + iopt_dveg: 2 + iopt_frz: 1 + iopt_inf: 1 + iopt_rad: 1 + iopt_run: 1 + iopt_sfc: 1 + iopt_snf: 4 + iopt_stc: 1 + iopt_tbot: 2 + iopt_trs: 2 + lsm: 2 + lsoil_lsm: 4 + +FV3_HRRR: + fv_core_nml: + hord_dp: -5 + hord_mt: 5 + hord_tm: 5 + hord_vt: 5 + kord_mt: 9 + kord_tm: -9 + kord_tr: 9 + kord_wz: 9 + nord_tr: 2 + nrows_blend: 10 + gfs_physics_nml: + <<: *RRFS_v1beta_phys + cdmbgwd: [3.5, 1.0] + do_mynnsfclay: True + do_sfcperts: !!python/none + gwd_opt: 3 + do_gsl_drag_ss: True + do_gsl_drag_tofd: True + do_gsl_drag_ls_bl: True + iaer: 5111 + icliq_sw: 2 + iovr: 3 + lsm: 3 + lsoil_lsm: 9 + sfclay_compute_flux: True + +FV3_GFS_2017_gfdlmp: + atmos_model_nml: + avg_max_length: 3600.0 + fv_core_nml: &gfs_2017_gfdlmp_fv_core + agrid_vel_rst: False + d4_bg: 0.15 + delt_max: 0.008 + dnats: 1 + do_sat_adj: True + fv_debug: False + k_split: 6 + n_split: 6 + nord: 2 + nord_zs_filter: !!python/none + range_warn: False + vtdm4: 0.075 + gfs_physics_nml: &gfs_2017_gfdlmp_phys + avg_max_length: 3600.0 + bl_mynn_tkeadvect: !!python/none + bl_mynn_edmf: !!python/none + bl_mynn_edmf_mom: !!python/none + cdmbgwd: [3.5, 0.01] + cplflx: !!python/none + do_deep: False + do_mynnedmf: !!python/none + do_mynnsfclay: !!python/none + fhcyc: 0.0 + fhlwr: 3600.0 + fhswr: 3600.0 + hybedmf: True + icloud_bl: !!python/none + imfdeepcnv: 2 + imfshalcnv: 2 + imp_physics: 11 + lgfdlmprad: True + lheatstrg: !!python/none + lndp_type: !!python/none + lsm: !!python/none + lsoil: !!python/none + lsoil_lsm: !!python/none + ltaerosol: !!python/none + n_var_lndp: !!python/none + oz_phys: True + oz_phys_2015: False + satmedmf: !!python/none + shal_cnv: True + ttendlim: !!python/none + gfdl_cloud_microphysics_nml: &gfs_gfdl_cloud_mp + c_cracw: 0.8 + c_paut: 0.5 + c_pgacs: 0.01 + c_psaci: 0.05 + ccn_l: 300.0 + ccn_o: 100.0 + const_vg: False + const_vi: False + const_vr: False + const_vs: False + de_ice: False + do_qa: True + do_sedi_heat: False + dw_land: 0.16 + dw_ocean: 0.1 + fast_sat_adj: True + fix_negative: True + icloud_f: 1 + mono_prof: True + mp_time: 90.0 + prog_ccn: False + qi0_crt: 8.0e-05 + qi_lim: 1.0 + ql_gen: 0.001 + ql_mlt: 0.001 + qs0_crt: 0.001 + rad_graupel: True + rad_rain: True + rad_snow: True + rh_inc: 0.3 + rh_inr: 0.3 + rh_ins: 0.3 + rthresh: 1.0e-05 + sedi_transport: False + tau_g2v: 900.0 + tau_i2s: 1000.0 + tau_l2v: 180.0 + tau_v2l: 90.0 + use_ccn: True + use_ppm: False + vg_max: 12.0 + vi_max: 1.0 + vr_max: 12.0 + vs_max: 2.0 + z_slope_ice: True + z_slope_liq: True + +FV3_GFS_2017_gfdlmp_regional: + atmos_model_nml: + avg_max_length: 3600.0 + fv_core_nml: + <<: *gfs_2017_gfdlmp_fv_core + k_split: 2 + gfs_physics_nml: + <<: *gfs_2017_gfdlmp_phys + cplflx: False + effr_in: False + iopt_alb: 2 + iopt_btr: 1 + iopt_crs: 1 + iopt_dveg: 2 + iopt_frz: 1 + iopt_inf: 1 + iopt_rad: 1 + iopt_run: 1 + iopt_sfc: 1 + iopt_snf: 4 + iopt_stc: 1 + iopt_tbot: 2 + iopt_trs: 2 + lgfdlmprad: True + lheatstrg: False + lndp_type: 0 + lsm: 1 + n_var_lndp: 0 + nstf_name: [2, 0, 0, 0, 0] + oz_phys: False + oz_phys_2015: True + satmedmf: False + gfdl_cloud_microphysics_nml: + <<: *gfs_gfdl_cloud_mp + +FV3_GFS_v15p2: + fv_core_nml: &gfs_v15_fv_core + agrid_vel_rst: False + d2_bg_k1: 0.15 + d2_bg_k2: 0.02 + dnats: 1 + do_sat_adj: True + fv_debug: False + fv_sg_adj: 600 + k_split: 1 + kord_mt: 9 + kord_tm: -9 + kord_tr: 9 + kord_wz: 9 + n_split: 8 + n_sponge: 30 + nord_zs_filter: !!python/none + nudge_qv: True + range_warn: False + rf_cutoff: 750.0 + rf_fast: False + gfdl_cloud_microphysics_nml: + <<: *gfs_gfdl_cloud_mp + sedi_transport: True + tau_l2v: 225.0 + tau_v2l: 150.0 + gfs_physics_nml: &gfs_v15_gfs_physics + bl_mynn_edmf: !!python/none + bl_mynn_edmf_mom: !!python/none + bl_mynn_tkeadvect: !!python/none + cnvcld: True + cnvgwd: True + cplflx: !!python/none + do_myjpbl: False + do_myjsfc: False + do_mynnedmf: !!python/none + do_mynnsfclay: !!python/none + do_tofd: False + do_ugwp: False + do_ysu: False + fhcyc: 0.0 + fhlwr: 3600.0 + fhswr: 3600.0 + hybedmf: True + iau_delthrs: !!python/none + iaufhrs: !!python/none + imfdeepcnv: 2 + imfshalcnv: 2 + imp_physics: 11 + icloud_bl: !!python/none + iopt_alb: 2 + iopt_btr: 1 + iopt_crs: 1 + iopt_dveg: 2 + iopt_frz: 1 + iopt_inf: 1 + iopt_rad: 1 + iopt_run: 1 + iopt_sfc: 1 + iopt_snf: 4 + iopt_stc: 1 + iopt_tbot: 2 + iopt_trs: 2 + ldiag_ugwp: False + lgfdlmprad: True + lradar: !!python/none + lsm: 1 + lsoil: !!python/none + lsoil_lsm: !!python/none + ltaerosol: !!python/none + shal_cnv: True + shinhong: False + ttendlim: !!python/none + xkzm_h: 1.0 + xkzm_m: 1.0 + xkzminv: 0.3 + namsfc: + landice: True + ldebug: False + surf_map_nml: + +FV3_GFS_v15_thompson_mynn_lam3km: + atmos_model_nml: + avg_max_length: 3600.0 + fv_core_nml: + agrid_vel_rst: True + full_zs_filter: !!python/none + n_sponge: 9 + npz_type: '' + rf_fast: False + sg_cutoff: 10000.0 + vtdm4: 0.02 + gfs_physics_nml: + avg_max_length: 3600.0 + cdmbgwd: [0.88, 0.04] + do_deep: False + do_mynnsfclay: True + do_ugwp: False + fhswr: 900.0 + fhlwr: 900.0 + iaer: 1011 + iccn: 2 + icliq_sw: 2 + imfdeepcnv: 2 + imfshalcnv: 2 + iopt_alb: 2 + iopt_btr: 1 + iopt_crs: 1 + iopt_dveg: 2 + iopt_frz: 1 + iopt_inf: 1 + iopt_rad: 1 + iopt_run: 1 + iopt_sfc: 1 + iopt_snf: 4 + iopt_stc: 1 + iopt_tbot: 2 + iopt_trs: 2 + iovr: 3 + ldiag_ugwp: False + lgfdlmprad: False + lsm: 1 + lsoil_lsm: !!python/none + ltaerosol: False + xkzminv: 0.3 + xkzm_m: 1.0 + xkzm_h: 1.0 + +FV3_GFS_v16: + cires_ugwp_nml: + launch_level: 27 + fv_core_nml: + <<: *gfs_v15_fv_core + agrid_vel_rst: False + d2_bg_k1: 0.2 + d2_bg_k2: 0.0 + fv_sg_adj: 450 + hord_dp: -5 + hord_mt: 5 + hord_tm: 5 + hord_vt: 5 + k_split: 6 + make_nh: False + n_split: 6 + n_sponge: 10 + na_init: 0 + nudge_dz: False + res_latlon_dynamics: '' + rf_fast: !!python/none + tau: 10.0 + gfdl_cloud_microphysics_nml: + <<: *gfs_gfdl_cloud_mp + mp_time: 150.0 + reiflag: 2 + sedi_transport: True + tau_l2v: 225.0 + tau_v2l: 150.0 + gfs_physics_nml: + <<: *gfs_v15_gfs_physics + cdmbgwd: [4.0, 0.15, 1.0, 1.0] + do_myjpbl: !!python/none + do_myjsfc: !!python/none + do_tofd: True + do_ysu: !!python/none + hybedmf: False + iaer: 5111 + icliq_sw: 2 + iopt_dveg: 1 + iovr: 3 + isatmedmf: 1 + lgfdlmprad: True + lheatstrg: True + lndp_type: !!python/none + lsoil: 4 + n_var_lndp: !!python/none + nstf_name: [2, 1, 0, 0, 0] + prautco: [0.00015, 0.00015] + psautco: [0.0008, 0.0005] + satmedmf: True + shinhong: !!python/none + xkzminv: !!python/none + xkzm_m: !!python/none + xkzm_h: !!python/none + mpp_io_nml: + deflate_level: 1 + shuffle: 1 + namsfc: + landice: True + ldebug: False + surf_map_nml: !!python/none + diff --git a/ush/templates/FV3LAM_wflow.xml b/ush/templates/FV3LAM_wflow.xml new file mode 100644 index 0000000000..219798afb1 --- /dev/null +++ b/ush/templates/FV3LAM_wflow.xml @@ -0,0 +1,1764 @@ +{# + +This is a Jinja-enabled Rocoto XML template. It is filled in using the +fill_template.py script, and is done automatically by the +generate_workflow.sh step of preparing a regional workflow configured +experiment. + +See README.xml_templating.md for information on using the Templating mechanisms. +-#} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +{%- if partition_default is not none %} +&ACCOUNT;&QUEUE_DEFAULT;{{ partition_default }}"> +{%- else %} +&ACCOUNT;&QUEUE_DEFAULT;"> +{%- endif %} +{%- if partition_hpss is not none %} +&ACCOUNT;&QUEUE_HPSS;{{ partition_hpss }}"> +{%- else %} +&ACCOUNT;&QUEUE_HPSS;"> +{%- endif %} +{%- if partition_fcst is not none %} +&ACCOUNT;&QUEUE_FCST;{{ partition_fcst }}"> +{%- else %} +&ACCOUNT;&QUEUE_FCST;"> +{%- endif %} + +]> + + +{# Double quotes are required inside the strftime! Expect an error from reading the template if using single quotes. #} + {{ cdate_first_cycl.strftime("%M %H %d %m %Y *") }} +{% for c in cycl_hrs %} + + {%- set cdate_first=date_first_cycl ~ c ~ "00" -%} + {%- set cdate_last=date_last_cycl ~ c ~ "00" -%} + {{- cdate_first ~ " " ~ cdate_last ~ " " ~ cycl_freq -}} + +{%- endfor %} + + + &LOGDIR;/FV3LAM_wflow.log + + + + + + +{%- if run_task_make_grid %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&MAKE_GRID_TN;" "&JOBSDIR;/JREGIONAL_MAKE_GRID" + {{ nnodes_make_grid }}:ppn={{ ppn_make_grid }} + {{ wtime_make_grid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &MAKE_GRID_TN; + &LOGDIR;/&MAKE_GRID_TN;.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + + +{%- endif %} +{%- if run_task_make_orog %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&MAKE_OROG_TN;" "&JOBSDIR;/JREGIONAL_MAKE_OROG" + {{ nnodes_make_orog }}:ppn={{ ppn_make_orog }} + {{ wtime_make_orog }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &MAKE_OROG_TN; + &LOGDIR;/&MAKE_OROG_TN;.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + + + + + &LOGDIR;/&MAKE_GRID_TN;_task_complete.txt + &RUN_TASK_MAKE_GRID;FALSE + + + + +{%- endif %} +{%- if run_task_make_sfc_climo %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&MAKE_SFC_CLIMO_TN;" "&JOBSDIR;/JREGIONAL_MAKE_SFC_CLIMO" + {{ nnodes_make_sfc_climo }}:ppn={{ ppn_make_sfc_climo }} + {{ wtime_make_sfc_climo }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &MAKE_SFC_CLIMO_TN; + &LOGDIR;/&MAKE_SFC_CLIMO_TN;.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + + + + + + &LOGDIR;/&MAKE_GRID_TN;_task_complete.txt + &RUN_TASK_MAKE_GRID;FALSE + + + + &LOGDIR;/&MAKE_OROG_TN;_task_complete.txt + &RUN_TASK_MAKE_OROG;FALSE + + + + + +{%- endif %} +{%- if run_task_get_extrn_ics %} + + + + &RSRV_HPSS; + &LOAD_MODULES_RUN_TASK_FP; "&GET_EXTRN_ICS_TN;" "&JOBSDIR;/JREGIONAL_GET_EXTRN_MDL_FILES" + {{ nnodes_get_extrn_ics }}:ppn={{ ppn_get_extrn_ics }} + {{ wtime_get_extrn_ics }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &GET_EXTRN_ICS_TN; + &LOGDIR;/&GET_EXTRN_ICS_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + ICS_OR_LBCSICS + + +{%- endif %} +{%- if run_task_get_extrn_lbcs %} + + + + &RSRV_HPSS; + &LOAD_MODULES_RUN_TASK_FP; "&GET_EXTRN_LBCS_TN;" "&JOBSDIR;/JREGIONAL_GET_EXTRN_MDL_FILES" + {{ nnodes_get_extrn_lbcs }}:ppn={{ ppn_get_extrn_lbcs }} + {{ wtime_get_extrn_lbcs }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &GET_EXTRN_LBCS_TN; + &LOGDIR;/&GET_EXTRN_LBCS_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + ICS_OR_LBCSLBCS + + +{%- endif %} + +{%- if do_ensemble %} + + + +{%- for m in range(1, num_ens_members+1) -%} + {%- set fmtstr=" %0"~ndigits_ensmem_names~"d" -%} + {{- fmtstr%m -}} +{%- endfor %} +{%- endif %} + +{%- if run_task_make_ics %} + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&MAKE_ICS_TN;" "&JOBSDIR;/JREGIONAL_MAKE_ICS" + {{ nnodes_make_ics }}:ppn={{ ppn_make_ics }} + {{ wtime_make_ics }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &MAKE_ICS_TN;{{ uscore_ensmem_name }} + &LOGDIR;/&MAKE_ICS_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + + + + + + + &LOGDIR;/&MAKE_GRID_TN;_task_complete.txt + &RUN_TASK_MAKE_GRID;FALSE + + + + &LOGDIR;/&MAKE_OROG_TN;_task_complete.txt + &RUN_TASK_MAKE_OROG;FALSE + + + + &LOGDIR;/&MAKE_SFC_CLIMO_TN;_task_complete.txt + &RUN_TASK_MAKE_SFC_CLIMO;FALSE + + + + + +{%- endif %} +{%- if run_task_make_lbcs %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&MAKE_LBCS_TN;" "&JOBSDIR;/JREGIONAL_MAKE_LBCS" + {{ nnodes_make_lbcs }}:ppn={{ ppn_make_lbcs }} + {{ wtime_make_lbcs }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &MAKE_LBCS_TN;{{ uscore_ensmem_name }} + &LOGDIR;/&MAKE_LBCS_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + + + + + + + &LOGDIR;/&MAKE_GRID_TN;_task_complete.txt + &RUN_TASK_MAKE_GRID;FALSE + + + + &LOGDIR;/&MAKE_OROG_TN;_task_complete.txt + &RUN_TASK_MAKE_OROG;FALSE + + + + &LOGDIR;/&MAKE_SFC_CLIMO_TN;_task_complete.txt + &RUN_TASK_MAKE_SFC_CLIMO;FALSE + + + + + +{%- endif %} +{%- if run_task_run_fcst %} + + + + &RSRV_FCST; + &LOAD_MODULES_RUN_TASK_FP; "&RUN_FCST_TN;" "&JOBSDIR;/JREGIONAL_RUN_FCST" + {%- if machine in ["JET", "HERA", "LINUX"] %} + {{ ncores_run_fcst }} + {{ native_run_fcst }} + {%- else %} + {{ nnodes_run_fcst }}:ppn={{ ppn_run_fcst }} + &NCORES_PER_NODE; + {%- endif %} + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + {{ wtime_run_fcst }} + &RUN_FCST_TN;{{ uscore_ensmem_name }} + &LOGDIR;/&RUN_FCST_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + ENSMEM_INDX#{{ ensmem_indx_name }}# + + + + + + + + + +{%- endif %} + +{%- if run_task_run_post %} + {%- if sub_hourly_post %} + + + + 000 + 00 + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&RUN_POST_TN;" "&JOBSDIR;/JREGIONAL_RUN_POST" + {{ nnodes_run_post }}:ppn={{ ppn_run_post }} + {{ wtime_run_post }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn# + &LOGDIR;/&RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn#_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + cyc@H + fhr#fhr# + fmn#fmn# + + + + + + + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/dynf{{ first_fv3_file_tstr }}.nc + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/phyf{{ first_fv3_file_tstr }}.nc + + + + + + + + + + + + 000 + + + {% for min in range(delta_min, 60, delta_min) %}{{ " %02d" % min }}{% endfor %} + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&RUN_POST_TN;" "&JOBSDIR;/JREGIONAL_RUN_POST" + {{ nnodes_run_post }}:ppn={{ ppn_run_post }} + {{ wtime_run_post }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn# + &LOGDIR;/&RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn#_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + cyc@H + fhr#fhr# + fmn#fmn# + + + + + + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/dynf#fhr#:#fmn#:00.nc + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/phyf#fhr#:#fmn#:00.nc + + + + + + + + + + {%- endif %} + + + {%- if sub_hourly_post %} + + {% for h in range(1, fcst_len_hrs) %}{{ " %03d" % h }}{% endfor %} + + {% for min in range(0, 60, delta_min) %}{{ " %02d" % min }}{% endfor %} + + {%- else %} + + {% for h in range(0, fcst_len_hrs+1) %}{{ " %03d" % h }}{% endfor %} + + {%- endif %} + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&RUN_POST_TN;" "&JOBSDIR;/JREGIONAL_RUN_POST" + {{ nnodes_run_post }}:ppn={{ ppn_run_post }} + {{ wtime_run_post }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + {%- if sub_hourly_post %} + &RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn# + &LOGDIR;/&RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn#_@Y@m@d@H.log + {%- else %} + &RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr# + &LOGDIR;/&RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr#_@Y@m@d@H.log + {%- endif %} + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + cyc@H + {%- if sub_hourly_post %} + fhr#fhr# + fmn#fmn# + {%- else %} + fhr#fhr# + {%- endif %} + + + + + + {%- if sub_hourly_post %} + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/dynf#fhr#:#fmn#:00.nc + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/phyf#fhr#:#fmn#:00.nc + {%- else %} + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/dynf#fhr#.nc + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/phyf#fhr#.nc + {%- endif %} + + + + + + + {%- if sub_hourly_post %} + + {%- else %} + {%- endif %} + + + {%- if sub_hourly_post %} + + + + {{ "%03d" % fcst_len_hrs }} + 00 + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&RUN_POST_TN;" "&JOBSDIR;/JREGIONAL_RUN_POST" + {{ nnodes_run_post }}:ppn={{ ppn_run_post }} + {{ wtime_run_post }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn# + &LOGDIR;/&RUN_POST_TN;{{ uscore_ensmem_name }}_f#fhr##fmn#_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + PDY@Y@m@d + CDATE@Y@m@d@H + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + cyc@H + fhr#fhr# + fmn#fmn# + + + + + + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/dynf#fhr#:#fmn#:00.nc + &CYCLE_BASEDIR;/@Y@m@d@H{{ slash_ensmem_subdir }}/phyf#fhr#:#fmn#:00.nc + + + + + + + + {%- endif %} +{%- endif %} + +{%- if run_task_get_obs_ccpa %} + + + + &RSRV_HPSS; + &LOAD_MODULES_RUN_TASK_FP; "&GET_OBS;" "&JOBSDIR;/JREGIONAL_GET_OBS_CCPA" + {{ nnodes_get_obs_ccpa }}:ppn={{ ppn_get_obs_ccpa }} + {{ wtime_get_obs_ccpa }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &GET_OBS_CCPA_TN; + &LOGDIR;/&GET_OBS_CCPA_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + ACCUM01 + + +{%- endif %} + +{%- if run_task_get_obs_mrms %} + + + + &RSRV_HPSS; + &LOAD_MODULES_RUN_TASK_FP; "&GET_OBS;" "&JOBSDIR;/JREGIONAL_GET_OBS_MRMS" + {{ nnodes_get_obs_mrms }}:ppn={{ ppn_get_obs_mrms }} + {{ wtime_get_obs_mrms }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &GET_OBS_MRMS_TN; + &LOGDIR;/&GET_OBS_MRMS_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + SCRIPTSDIR&SCRIPTSDIR; + VARREFC RETOP + + +{%- endif %} + +{%- if run_task_get_obs_ndas %} + + + + &RSRV_HPSS; + &LOAD_MODULES_RUN_TASK_FP; "&GET_OBS;" "&JOBSDIR;/JREGIONAL_GET_OBS_NDAS" + {{ nnodes_get_obs_ndas }}:ppn={{ ppn_get_obs_ndas }} + {{ wtime_get_obs_ndas }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &GET_OBS_NDAS_TN; + &LOGDIR;/&GET_OBS_NDAS_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&NDAS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + + +{%- endif %} + +{%- if run_task_vx_gridstat %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_GRIDSTAT" + {{ nnodes_vx_gridstat }}:ppn={{ ppn_vx_gridstat }} + {{ wtime_vx_gridstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_GRIDSTAT_TN; + &LOGDIR;/&VX_GRIDSTAT_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM01 + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + {%- if run_task_get_obs_ccpa %} + + + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + + {%- else %} + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + {%- endif %} + + + +{%- endif %} + +{%- if run_task_vx_gridstat %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_GRIDSTAT" + {{ nnodes_vx_gridstat }}:ppn={{ ppn_vx_gridstat }} + {{ wtime_vx_gridstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_GRIDSTAT_REFC_TN; + &LOGDIR;/&VX_GRIDSTAT_REFC_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARREFC + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + {%- if run_task_get_obs_mrms %} + + + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + + {%- else %} + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + {%- endif %} + + + +{%- endif %} + +{%- if run_task_vx_gridstat %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_GRIDSTAT" + {{ nnodes_vx_gridstat }}:ppn={{ ppn_vx_gridstat }} + {{ wtime_vx_gridstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_GRIDSTAT_RETOP_TN; + &LOGDIR;/&VX_GRIDSTAT_RETOP_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARRETOP + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + {%- if run_task_get_obs_mrms %} + + + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + + {%- else %} + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + {%- endif %} + + + +{%- endif %} + +{%- if run_task_vx_gridstat and fcst_len_hrs >= 3 %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_GRIDSTAT" + {{ nnodes_vx_gridstat }}:ppn={{ ppn_vx_gridstat }} + {{ wtime_vx_gridstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_GRIDSTAT_03h_TN; + &LOGDIR;/&VX_GRIDSTAT_03h_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(3, fcst_len_hrs+1, 3) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM03 + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + + + + +{%- endif %} + +{%- if run_task_vx_gridstat and fcst_len_hrs >= 6 %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_GRIDSTAT" + {{ nnodes_vx_gridstat }}:ppn={{ ppn_vx_gridstat }} + {{ wtime_vx_gridstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_GRIDSTAT_06h_TN; + &LOGDIR;/&VX_GRIDSTAT_06h_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(6, fcst_len_hrs+1, 6) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM06 + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + + + + +{%- endif %} + +{%- if run_task_vx_gridstat and fcst_len_hrs >= 24 %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_GRIDSTAT" + {{ nnodes_vx_gridstat }}:ppn={{ ppn_vx_gridstat }} + {{ wtime_vx_gridstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_GRIDSTAT_24h_TN; + &LOGDIR;/&VX_GRIDSTAT_24h_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(24, fcst_len_hrs+1, 24) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM24 + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + + + + +{%- endif %} + +{%- if run_task_vx_pointstat %} + + + &RSRV_DEFAULT; + + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_POINTSTAT" + {{ nnodes_vx_pointstat }}:ppn={{ ppn_vx_pointstat }} + {{ wtime_vx_pointstat }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_POINTSTAT_TN; + &LOGDIR;/&VX_POINTSTAT_TN;{{ uscore_ensmem_name }}_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&NDAS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + {%- if do_ensemble %} + SLASH_ENSMEM_SUBDIR{{ slash_ensmem_subdir }} + {%- endif %} + + + {%- if run_task_get_obs_ndas %} + + + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + + {%- else %} + {%- if write_dopost %} + + {%- else %} + + {%- endif %} + {%- endif %} + + + +{%- endif %} + +{%- if do_ensemble %} + +{%- endif %} + +{%- if run_task_vx_ensgrid %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID" + {{ nnodes_vx_ensgrid }}:ppn={{ ppn_vx_ensgrid }} + {{ wtime_vx_ensgrid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_TN; + &LOGDIR;/&VX_ENSGRID_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM01 + + + + + + + +{%- if fcst_len_hrs >= 3 %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID" + {{ nnodes_vx_ensgrid }}:ppn={{ ppn_vx_ensgrid }} + {{ wtime_vx_ensgrid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_03h_TN; + &LOGDIR;/&VX_ENSGRID_03h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(3, fcst_len_hrs+1, 3) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM03 + + + + + + +{%- endif %} +{%- if fcst_len_hrs >= 6 %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID" + {{ nnodes_vx_ensgrid }}:ppn={{ ppn_vx_ensgrid }} + {{ wtime_vx_ensgrid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_06h_TN; + &LOGDIR;/&VX_ENSGRID_06h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(6, fcst_len_hrs+1, 6) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM06 + + + + + + +{%- endif %} +{%- if fcst_len_hrs >= 24 %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID" + {{ nnodes_vx_ensgrid }}:ppn={{ ppn_vx_ensgrid }} + {{ wtime_vx_ensgrid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_24h_TN; + &LOGDIR;/&VX_ENSGRID_24h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(24, fcst_len_hrs+1, 24) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM24 + + + + + + +{%- endif %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID" + {{ nnodes_vx_ensgrid }}:ppn={{ ppn_vx_ensgrid }} + {{ wtime_vx_ensgrid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_REFC_TN; + &LOGDIR;/&VX_ENSGRID_REFC_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARREFC + + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID" + {{ nnodes_vx_ensgrid }}:ppn={{ ppn_vx_ensgrid }} + {{ wtime_vx_ensgrid }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_RETOP_TN; + &LOGDIR;/&VX_ENSGRID_RETOP_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARRETOP + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_MEAN" + {{ nnodes_vx_ensgrid_mean }}:ppn={{ ppn_vx_ensgrid_mean }} + {{ wtime_vx_ensgrid_mean }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_MEAN_TN; + &LOGDIR;/&VX_ENSGRID_MEAN_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM01 + + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_PROB" + {{ nnodes_vx_ensgrid_prob }}:ppn={{ ppn_vx_ensgrid_prob }} + {{ wtime_vx_ensgrid_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_PROB_TN; + &LOGDIR;/&VX_ENSGRID_PROB_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM01 + + + + + + +{%- if fcst_len_hrs >= 3 %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_MEAN" + {{ nnodes_vx_ensgrid_mean }}:ppn={{ ppn_vx_ensgrid_mean }} + {{ wtime_vx_ensgrid_mean }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_MEAN_03h_TN; + &LOGDIR;/&VX_ENSGRID_MEAN_03h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(3, fcst_len_hrs+1, 3) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM03 + + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_PROB" + {{ nnodes_vx_ensgrid_prob }}:ppn={{ ppn_vx_ensgrid_prob }} + {{ wtime_vx_ensgrid_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_PROB_03h_TN; + &LOGDIR;/&VX_ENSGRID_PROB_03h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(3, fcst_len_hrs+1, 3) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM03 + + + + + + +{%- endif %} +{%- if fcst_len_hrs >= 6 %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_MEAN" + {{ nnodes_vx_ensgrid_mean }}:ppn={{ ppn_vx_ensgrid_mean }} + {{ wtime_vx_ensgrid_mean }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_MEAN_06h_TN; + &LOGDIR;/&VX_ENSGRID_MEAN_06h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(6, fcst_len_hrs+1, 6) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM06 + + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_PROB" + {{ nnodes_vx_ensgrid_prob }}:ppn={{ ppn_vx_ensgrid_prob }} + {{ wtime_vx_ensgrid_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_PROB_06h_TN; + &LOGDIR;/&VX_ENSGRID_PROB_06h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(6, fcst_len_hrs+1, 6) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM06 + + + + + + +{%- endif %} +{%- if fcst_len_hrs >= 24 %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_MEAN" + {{ nnodes_vx_ensgrid_mean }}:ppn={{ ppn_vx_ensgrid_mean }} + {{ wtime_vx_ensgrid_mean }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_MEAN_24h_TN; + &LOGDIR;/&VX_ENSGRID_MEAN_24h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(24, fcst_len_hrs+1, 24) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM24 + + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_PROB" + {{ nnodes_vx_ensgrid_prob }}:ppn={{ ppn_vx_ensgrid_prob }} + {{ wtime_vx_ensgrid_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_PROB_24h_TN; + &LOGDIR;/&VX_ENSGRID_PROB_24h_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&CCPA_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(24, fcst_len_hrs+1, 24) %}{{ " %02d" % h }}{% endfor %} + VARAPCP + ACCUM24 + + + + + + +{%- endif %} + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_PROB" + {{ nnodes_vx_ensgrid_prob }}:ppn={{ ppn_vx_ensgrid_prob }} + {{ wtime_vx_ensgrid_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_PROB_REFC_TN; + &LOGDIR;/&VX_ENSGRID_PROB_REFC_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARREFC + + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSGRID_PROB" + {{ nnodes_vx_ensgrid_prob }}:ppn={{ ppn_vx_ensgrid_prob }} + {{ wtime_vx_ensgrid_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSGRID_PROB_RETOP_TN; + &LOGDIR;/&VX_ENSGRID_PROB_RETOP_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&MRMS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(1, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + VARRETOP + + + + + + +{%- endif %} + +{%- if run_task_vx_enspoint %} + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSPOINT" + {{ nnodes_vx_enspoint }}:ppn={{ ppn_vx_enspoint }} + {{ wtime_vx_enspoint }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSPOINT_TN; + &LOGDIR;/&VX_ENSPOINT_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&NDAS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSPOINT_MEAN" + {{ nnodes_vx_enspoint_mean }}:ppn={{ ppn_vx_enspoint_mean }} + {{ wtime_vx_enspoint_mean }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSPOINT_MEAN_TN; + &LOGDIR;/&VX_ENSPOINT_MEAN_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&NDAS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + + + + + + + + + + + &RSRV_DEFAULT; + &LOAD_MODULES_RUN_TASK_FP; "&VX_TN;" "&JOBSDIR;/JREGIONAL_RUN_VX_ENSPOINT_PROB" + {{ nnodes_vx_enspoint_prob }}:ppn={{ ppn_vx_enspoint_prob }} + {{ wtime_vx_enspoint_prob }} + &NCORES_PER_NODE; + {%- if machine in ["GAEA"] %} + &SLURM_NATIVE_CMD; + {%- endif %} + &VX_ENSPOINT_PROB_TN; + &LOGDIR;/&VX_ENSPOINT_PROB_TN;_@Y@m@d@H.log + + GLOBAL_VAR_DEFNS_FP&GLOBAL_VAR_DEFNS_FP; + OBS_DIR&NDAS_OBS_DIR; + CYCLE_DIR&CYCLE_BASEDIR;/@Y@m@d@H + CDATE@Y@m@d@H + PDY@Y@m@d + cyc@H + FHR {% for h in range(0, fcst_len_hrs+1) %}{{ " %02d" % h }}{% endfor %} + + + + + + + +{%- endif %} + diff --git a/ush/templates/README.xml_templating.md b/ush/templates/README.xml_templating.md new file mode 100644 index 0000000000..0d2c58cf1b --- /dev/null +++ b/ush/templates/README.xml_templating.md @@ -0,0 +1,164 @@ +# Rocoto XML templating + +## Jinja Templating + +Jinja2 is a fast, widely used, secure templating language for Python. +Documentation is here: [Jinja2 +Docs](https://jinja.palletsprojects.com/en/2.11.x?target=_blank) + +### Brief overview + +A Python script parses a Jinja template, looks for standard template +fields containing variables known to Python. Finding all the template +variables, it renders the desired output, which can then be saved as +output. + +Inside a Jinja Template file, you will see several place holders: + +- `{% ... %}` for Statements + - In our context, the are mainly control structures like if and for + loops + +- `{{ ... }}` for Expressions to print to the template output + - Used mainly by `regional_workflow` templates to fill in variables + +- `{# ... #}` for Comments not included in the template output + +- `# ... ##` for Line Statements + - Not used for `regional_workflow` templates + +--- + +## Templates for Rocoto XML + +The `regional_workflow` repository uses `ush/fill_template.py` to do +this work. And Jinja templates are used for the Rocoto XML, and with the +FV3 diag tables. + + +### Entities - XML variables with template Expressions + +--- + +**Example:** `` + +- Add ENTITIES in XML using `{{ ... }}` fields for the values. + - Any variable inside the curly braces will need to be supplied by the + Python script filling the template. Add the value to the settings + variable in `ush/generate_workflow.sh`. +- Setting proper XML ENTITIES should be limited to variables that are only +needed for setting cycle-specific values, i.e., submitting the job, passing +in a date, tracking locations of files for dependencies, etc. +- Static settings not used directly by the XML (only used by J-Jobs +or ex-scripts) should be set in `ush/setup.sh` or +`ush/default_configs.sh` so that it ends up in an experiment's +`var_defns.sh` file +- Static settings included in the XML only serve to make the submit +process cumbersome for users who wish to submit jobs manually (without +Rocoto). + +### In-line template Expressions -- Python variables + +--- + +**Example:** `{{ nnodes_make_grid }}:ppn={{ ppn_make_grid }}` + +- Values can be filled "in-place" without setting an XML ENTITY. This +means that you won't be able to reference this value anywhere else in +the XML file once the template has been rendered. +- Reducing indirection for variables that are used sparingly can be +easier to understand and manage once the template is filled. + +### ENTITY vs In-Line Expression?? + +--- + +**Example:** Are you asking yourself THIS: + +`` \ +`` + +... + +`&NNODES_MAKE_GRID;:ppn=&PPN_MAKE_GRID;` + + -- OR THIS -- + +`{{ nnodes_make_grid }}:ppn={{ ppn_make_grid }}` + +??? + + +- Identical values set for the same purpose in many places (~3+) should +probably be an ENTITY. Otherwise, apply the KISS Method. +- Entities can help with the search process as XML files grow +ever-longer. If you envision needing to search on a particular ENTITY +throughout, set it up top to help end-user (YOU!) find all occurrences +later. +- Use of Jinja Statements like loops and if statements should always be +done in-line for the sake of clarity. + + +### Handling Optional Tasks + +--- + +There are few things to consider when adding optional tasks to the +XML. + +- When a task is turned off, but does not run, Rocoto can't easily mark +a cycle as "complete". Instead, consider leaving the task out of the XML +altogether with a Jinja control structure. +- When the task is NOT included in an XML (flag is turned off), a +subsequent task dependency must be treated with care. You probably want +to add an ENTITY to be treated as an "ON/OFF" flag so that task +dependencies are never evaluated if they aren't included. +- Add a Jinja "if statement" along with your boolean flag to remove the +whole task from the final template. + +These all work together like this: + +In `ush/generate_workflow.sh`, the `run_task_make_grid` flag is set to "False" to +turn off running verification. + +In `ush/templates/FV3LAM_wflow.xml`: + +1. Set an entity for use in dependencies. +2. Add a Jinja if statement around the optional task. +3. Treat subsequent dependencies carefully. + +Altogether it looks like this: + + + + + ... + + + {% if run_task_make_grid %} + + + + {% endif %} + + + + + + + + + + &RUN_TASK_MAKE_GRID;TRUE + + + + + &LOGDIR;/make_grid_task_complete.txt + + + + + diff --git a/ush/templates/data_locations.yml b/ush/templates/data_locations.yml new file mode 100644 index 0000000000..067708f99f --- /dev/null +++ b/ush/templates/data_locations.yml @@ -0,0 +1,261 @@ +# This file tracks known data store locations for data used as input to +# the SRW App configuations. +# +# The contents should be organized as follows: +# +# Top level: A key corresponding to an external model file or +# observation dataset accepted by the SRW App. +# +# 2nd level: A key corressponding to a named datastore for a given data +# set. This could be nomads, aws, hpss, etc. +# +# 3rd level required: +# +# protocol: +# indication of how a set of files will be retrieved. Options: +# download or htar. The requirements for each protocol are described +# below +# +# file_names: +# Each data store will require an entry that describes the names of +# files to be extracted from the data store. These entries are +# expected as lists to indicate when multiple files should be +# retrieved. anl and fcst subsections indicate the naming convention +# for that type of file. Both are required for external models ICS and +# LBCS. Each file name may (and likely should) include templates. +# +# If the SRW App accepts different file formats, as it does for +# FV3GFS, an intermediary level indicating the value associate with a +# FV3GFS_FILE_FMT_* variable. +# +# 3rd level optional: +# +# for download protocol: +# url: required. the URL to the location of the data file. May include +# templates. +# +# for htar protocol: +# archive_path: a list of paths to the potential location of the +# archive file on HPSS. since there may be multiple +# options for a given external model file, the list +# will be searched in order listed below. +# archive_file_names: the name of the archive file. this could +# differ for each archive_path option, so one entry is +# needed (even if it's identical) for each entry of +# archive_path provided +# archive_internal_dir: (optional) a path to data files stored +# inside a given archive file +# +# +# +FV3GFS: + nomads: + protocol: download + url: https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/gfs.{yyyymmdd}/{hh}/atmos + file_names: &gfs_file_names + grib2: + anl: + - gfs.t{hh}z.pgrb2.0p25.f000 + fcst: + - gfs.t{hh}z.pgrb2.0p25.f{fcst_hr:03d} + nemsio: + anl: + - gfs.t{hh}z.atmanl.nemsio + - gfs.t{hh}z.sfcanl.nemsio + fcst: + - gfs.t{hh}z.atmf{fcst_hr:03d}.nemsio + netcdf: + anl: + - gfs.t{hh}z.atmanl.nc + - gfs.t{hh}z.sfcanl.nc + fcst: + - gfs.t{hh}z.atmf{fcst_hr:03d}.nc + hpss: + protocol: htar + archive_path: + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + archive_internal_dir: + - ./gfs.{yyyymmdd}/{hh} + - ./gfs.{yyyymmdd}/{hh}/atmos + archive_file_names: + grib2: + anl: + - gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_pgrb2.tar + - com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_pgrb2.tar + fcst: + - gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_pgrb2.tar + - com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_pgrb2.tar + nemsio: + anl: + - gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nemsioa.tar + - com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nemsioa.tar + fcst: + - ['gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nemsioa.tar', 'gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nemsiob.tar'] + - ['com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nemsioa.tar', 'com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nemsiob.tar'] + netcdf: + anl: + - gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nca.tar + - com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nca.tar + fcst: + - ['gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nca.tar', 'gpfs_dell1_nco_ops_com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_ncb.tar'] + - ['com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_nca.tar', 'com_gfs_prod_gfs.{yyyymmdd}_{hh}.gfs_ncb.tar'] + file_names: + <<: *gfs_file_names + aws: + protocol: download + url: https://noaa-gfs-bdp-pds.s3.amazonaws.com/gfs.{yyyymmdd}/{hh}/atmos + file_names: + <<: *gfs_file_names + +GDAS: + hpss: + protocol: htar + archive_path: + - /NCEPPROD/5year/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + - /NCEPPROD/5year/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + archive_internal_dir: + - ./enkfgdas.{yyyymmdd}/{hh}/atmos/mem{mem:03d} + archive_file_names: + nemsio: + anl: + - com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + - gpfs_dell1_nco_ops_com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + fcst: + - com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + - gpfs_dell1_nco_ops_com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + netcdf: + anl: + - com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + - gpfs_dell1_nco_ops_com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + fcst: + - com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + - gpfs_dell1_nco_ops_com_gfs_prod_enkfgdas.{yyyymmdd}_{hh}.enkfgdas_grp{ens_group}.tar + file_names: + nemsio: + anl: + - gdas.t{hh}z.atmf{fcst_hr:03d}.nemsio + fcst: + - gdas.t{hh}.sfcf{fcst_hr:03d}.nemsio + netcdf: + anl: + - gdas.t{hh}z.atmf{fcst_hr:03d}.nc + - gdas.t{hh}z.sfcf{fcst_hr:03d}.nc + fcst: + - gdas.t{hh}z.atmf{fcst_hr:03d}.nc + nomads: + protocol: download + url: https://nomads.ncep.noaa.gov/pub/data/nccf/com/gfs/prod/enkfgdas.{yyyymmdd}/{hh}/atmos/mem{mem:03d} + file_names: + netcdf: + fcst: + - gdas.t{hh}z.sfcf{fcst_hr:03d}.nc + aws: + protocol: download + url: https://noaa-gfs-bdp-pds.s3.amazonaws.com/enkfgdas.{yyyymmdd}/{hh}/atmos/mem{mem:03d} + file_names: + netcdf: + anl: + - gdas.t{hh}z.sfcf{fcst_hr:03d}.nc + +GEFS: + aws: + protocol: download + url: + - ['https://noaa-gefs-pds.s3.amazonaws.com/gefs.{yyyymmdd}/{hh}/atmos/pgrb2ap5', 'https://noaa-gefs-pds.s3.amazonaws.com/gefs.{yyyymmdd}/{hh}/atmos/pgrb2bp5'] + - ['https://noaa-gefs-pds.s3.amazonaws.com/gefs.{yyyymmdd}/{hh}/pgrb2a', 'https://noaa-gefs-pds.s3.amazonaws.com/gefs.{yyyymmdd}/{hh}/pgrb2b'] + - ['https://noaa-gefs-pds.s3.amazonaws.com/gefs.{yyyymmdd}/{hh}', 'https://noaa-gefs-pds.s3.amazonaws.com/gefs.{yyyymmdd}/{hh}'] + file_names: + - ['gep{mem:02d}.t{hh}z.pgrb2a.0p50.f{fcst_hr:03d}', 'gep{mem:02d}.t{hh}z.pgrb2b.0p50.f{fcst_hr:03d}'] + - ['gep{mem:02d}.t{hh}z.pgrb2af{fcst_hr:02d}', 'gep{mem:02d}.t{hh}z.pgrb2bf{fcst_hr:02d}'] + - ['gep{mem:02d}.t{hh}z.pgrb2af{fcst_hr:03d}', 'gep{mem:02d}.t{hh}z.pgrb2bf{fcst_hr:03d}' ] + +GSMGFS: + hpss: + protocol: htar + archive_path: + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + archive_internal_dir: + anl: + - ./ + fcst: + - /gpfs/hps/nco/ops/com/gfs/prod/gfs.{yyyymmdd} + archive_file_names: + anl: + - gpfs_hps_nco_ops_com_gfs_prod_gfs.{yyyymmddhh}.anl.tar + fcst: + - gpfs_hps_nco_ops_com_gfs_prod_gfs.{yyyymmddhh}.sigma.tar + file_names: + anl: + - gfs.t{hh}z.atmanl.nemsio + - gfs.t{hh}z.sfcanl.nemsio + fcst: + - gfs.t{hh}z.atmf{fcst_hr:03d}.nemsio + +RAP: + hpss: + protocol: htar + archive_format: tar + archive_path: + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + archive_internal_dir: + - ./ + - ./ + archive_file_names: + # RAP forecasts are binned into 6 hour tar files. + - gpfs_hps_nco_ops_com_rap_prod_rap.{yyyymmdd}{bin6}.wrf.tar + - com_rap_prod_rap.{yyyymmdd}{bin6}.wrf.tar + file_names: &rap_file_names + anl: + - rap.t{hh}z.wrfnatf{fcst_hr:02d}.grib2 + fcst: + - rap.t{hh}z.wrfnatf{fcst_hr:02d}.grib2 + aws: + protocol: download + url: https://noaa-rap-pds.s3.amazonaws.com/rap.{yyyymmdd} + file_names: + <<: *rap_file_names + +HRRR: + hpss: + protocol: htar + archive_format: tar + archive_path: + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + archive_internal_dir: + - ./ + - ./ + archive_file_names: + # HRRR forecasts are binned into 6 hour tar files. + - gpfs_hps_nco_ops_com_hrrr_prod_hrrr.{yyyymmdd}_conus{bin6}.wrf.tar + - com_hrrr_prod_hrrr.{yyyymmdd}_conus{bin6}.wrf.tar + file_names: &hrrr_file_names + anl: + - hrrr.t{hh}z.wrfprsf{fcst_hr:02d}.grib2 + fcst: + - hrrr.t{hh}z.wrfprsf{fcst_hr:02d}.grib2 + aws: + protocol: download + url: https://noaa-hrrr-bdp-pds.s3.amazonaws.com/hrrr.{yyyymmdd}/conus/ + file_names: + <<: *hrrr_file_names + +NAM: + hpss: + protocol: htar + archive_format: tar + archive_path: + - /NCEPPROD/hpssprod/runhistory/rh{yyyy}/{yyyymm}/{yyyymmdd} + archive_internal_dir: + - ./ + archive_file_names: + - com_nam_prod_nam.{yyyymmddhh}.awphys.tar + - com_nam_prod_nam.{yyyymmddhh}.awphys{fcst_hr:02d}.tar + file_names: + anl: + - nam.t{hh}z.awphys{fcst_hr:02d}.tm00.grib2 + fcst: + - nam.t{hh}z.awphys{fcst_hr:02d}.tm00.grib2 + diff --git a/ush/templates/data_table b/ush/templates/data_table new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/templates/diag_table.FV3_GFS_2017_gfdlmp b/ush/templates/diag_table.FV3_GFS_2017_gfdlmp new file mode 100755 index 0000000000..8b64d1ee91 --- /dev/null +++ b/ush/templates/diag_table.FV3_GFS_2017_gfdlmp @@ -0,0 +1,310 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +"grid_spec", -1, "months", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +"atmos_4xdaily", 1, "hours", 1, "days", "time" +"fv3_history", 1, "years", 1, "hours", "time" +"fv3_history2d", 1, "years", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### +# "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "z1000", "z1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z850", "z850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z700", "z700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z500", "z500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z200", "z200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z100", "z100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z50", "z50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z10", "z10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Stochastic physics +"gfs_phys", "sppt_wts", "sppt_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebu_wts", "skebu_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebv_wts", "skebv_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "shum_wts", "shum_wts", "fv3_history", "all", .false., "none", 2 +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_GFS_2017_gfdlmp_regional b/ush/templates/diag_table.FV3_GFS_2017_gfdlmp_regional new file mode 100644 index 0000000000..dbcfbb1f65 --- /dev/null +++ b/ush/templates/diag_table.FV3_GFS_2017_gfdlmp_regional @@ -0,0 +1,352 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +#output files +"grid_spec", -1, "months", 1, "days", "time" +#"atmos_4xdaily", 1, "hours", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +"fv3_history", 0, "hours", 1, "hours", "time" +"fv3_history2d", 0, "hours", 1, "hours", "time" +#"ref3D", 0, "hours", 1, "hours", "time" +#"maxmin2D", 1, "hours", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### +# "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort500", "vort500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "z1000", "z1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z850", "z850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z700", "z700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z500", "z500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z200", "z200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z100", "z100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z50", "z50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z10", "z10", "atmos_4xdaily", "all", .false., "none", 2 +#### +#"dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "cape", "sbcape", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "cin", "sbcin", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "cld_amt", "cld_amt", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +### +# Max hourly fields +### +"gfs_dyn", "wmaxup", "upvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "wmaxdn", "dnvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax03", "uhmax03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax25", "uhmax25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin03", "uhmin03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin25", "uhmin25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort01", "maxvort01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort02", "maxvort02", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvorthy1", "maxvorthy1", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ustm", "ustm", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vstm", "vstm", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "srh01", "srh01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "srh03", "srh03", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "u10max", "u10max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10max", "v10max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spd10max", "spd10max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "refdmax", "refdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "refdmax263k", "refdmax263k", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "t02max", "t02max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "t02min", "t02min", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "rh02max", "rh02max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "rh02min", "rh02min", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 + +# Reflectivity from GFDL microphysics +"gfs_phys", "refl_10cm", "refl_10cm", "fv3_history2d", "all", .false., "none", 2 + +#Cloud fraction +"gfs_phys", "cldfra", "cldfra", "fv3_history", "all", .false., "none", 2 + +#Max/Min must be kept in separate files. Time is controlled by diag_table +# "dynamics", "uh25", "MXUPHL2_5km", "maxmin2D", "all", max, "none", 2 +# "dynamics", "uh25", "MNUPHL2_5km", "maxmin2D", "all", min, "none", 2 +# "dynamics", "max_reflectivity", "MAXREFC", "maxmin2D", "all", max, "none", 2 +# "dynamics", "base_reflectivity", "MAXREF_1km", "maxmin2D", "all", max, "none", 2 +# +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_GFS_v15_thompson_mynn_lam3km b/ush/templates/diag_table.FV3_GFS_v15_thompson_mynn_lam3km new file mode 100644 index 0000000000..6f32189582 --- /dev/null +++ b/ush/templates/diag_table.FV3_GFS_v15_thompson_mynn_lam3km @@ -0,0 +1,340 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +#output files +"grid_spec", -1, "months", 1, "days", "time" +#"atmos_4xdaily", 6, "hours", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +"fv3_history", 3, "hours", 1, "hours", "time" +"fv3_history2d", 3, "hours", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### +# "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "z1000", "z1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z850", "z850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z700", "z700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z500", "z500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z200", "z200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z100", "z100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z50", "z50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z10", "z10", "atmos_4xdaily", "all", .false., "none", 2 +#### +#"dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "q_rimef", "q_rimef", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "pfnh", "pfnh", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "cld_amt", "cld_amt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "wmaxup", "upvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "wmaxdn", "dnvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax03", "uhmax03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax25", "uhmax25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin03", "uhmin03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin25", "uhmin25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort01", "maxvort01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort02", "maxvort02", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvorthy1", "maxvorthy1", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ustm", "ustm", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vstm", "vstm", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "srh01", "srh01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "srh03", "srh03", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "u10max", "u10max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10max", "v10max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spd10max", "spd10max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "refdmax", "refdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "refdmax263k","refdmax263k","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "t02max", "t02max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "t02min", "t02min", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "rh02max", "rh02max", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "rh02min", "rh02min", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "refl_10cm", "refl_10cm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cldfra", "cldfra", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pratemax", "pratemax", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Aerosols (CCN, IN) from Thompson microphysics +#"gfs_phys", "nwfa", "nwfa", "fv3_history", "all", .false., "none", 2 +#"gfs_phys", "nifa", "nifa", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "nwfa2d", "nwfa2d", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "nifa2d", "nifa2d", "fv3_history2d", "all", .false., "none", 2 + +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_GFS_v15p2 b/ush/templates/diag_table.FV3_GFS_v15p2 new file mode 100755 index 0000000000..129061171f --- /dev/null +++ b/ush/templates/diag_table.FV3_GFS_v15p2 @@ -0,0 +1,311 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +"grid_spec", -1, "months", 1, "days", "time" +"atmos_4xdaily", 6, "hours", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +"fv3_history", 1, "years", 1, "hours", "time" +"fv3_history2d", 1, "years", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### + "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "h1000", "h1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h850", "h850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h700", "h700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h500", "h500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h200", "h200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h100", "h100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h50", "h50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h10", "h10", "atmos_4xdaily", "all", .false., "none", 2 +#### +#"dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Stochastic physics +"gfs_phys", "sppt_wts", "sppt_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebu_wts", "skebu_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebv_wts", "skebv_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "shum_wts", "shum_wts", "fv3_history", "all", .false., "none", 2 + +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_GFS_v16 b/ush/templates/diag_table.FV3_GFS_v16 new file mode 100755 index 0000000000..129061171f --- /dev/null +++ b/ush/templates/diag_table.FV3_GFS_v16 @@ -0,0 +1,311 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +"grid_spec", -1, "months", 1, "days", "time" +"atmos_4xdaily", 6, "hours", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +"fv3_history", 1, "years", 1, "hours", "time" +"fv3_history2d", 1, "years", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### + "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "h1000", "h1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h850", "h850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h700", "h700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h500", "h500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h200", "h200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h100", "h100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h50", "h50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "h10", "h10", "atmos_4xdaily", "all", .false., "none", 2 +#### +#"dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### + "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 + "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Stochastic physics +"gfs_phys", "sppt_wts", "sppt_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebu_wts", "skebu_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebv_wts", "skebv_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "shum_wts", "shum_wts", "fv3_history", "all", .false., "none", 2 + +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_HRRR b/ush/templates/diag_table.FV3_HRRR new file mode 100755 index 0000000000..45d5c87d19 --- /dev/null +++ b/ush/templates/diag_table.FV3_HRRR @@ -0,0 +1,366 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +"grid_spec", -1, "months", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +#"atmos_4xdaily", 1, "hours", 1, "days", "time" +"fv3_history", 1, "years", 1, "hours", "time" +"fv3_history2d", 1, "years", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### +# "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "z1000", "z1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z850", "z850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z700", "z700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z500", "z500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z200", "z200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z100", "z100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z50", "z50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z10", "z10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "refl_10cm" "refl_10cm" "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cldfra", "cldfra", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +"gfs_dyn", "wmaxup", "upvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "wmaxdn", "dnvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax03", "uhmax03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax25", "uhmax25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin03", "uhmin03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin25", "uhmin25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort01", "maxvort01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort02", "maxvort02", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvorthy1", "maxvorthy1", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt5", "soilt5" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt6", "soilt6" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt7", "soilt7" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt8", "soilt8" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt9", "soilt9" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw5", "soilw5" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw6", "soilw6" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw7", "soilw7" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw8", "soilw8" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw9", "soilw9" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_5", "soill5", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_6", "soill6", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_7", "soill7", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_8", "soill8", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_9", "soill9", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Aerosols (CCN, IN) from Thompson microphysics +"gfs_phys", "nwfa", "nwfa", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "nifa", "nifa", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "nwfa2d", "nwfa2d", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "nifa2d", "nifa2d", "fv3_history2d", "all", .false., "none", 2 +# Cloud effective radii from Thompson and WSM6 microphysics +"gfs_phys", "cleffr", "cleffr", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cieffr", "cieffr", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cseffr", "cseffr", "fv3_history", "all", .false., "none", 2 +# Prognostic/diagnostic variables from MYNN +"gfs_phys", "QC_BL", "qc_bl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "CLDFRA_BL", "cldfra_bl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "EL_PBL", "el_pbl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "QKE", "qke", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "maxmf", "maxmf", "fv3_history2d", "all", .false., "none", 2 +#"gfs_sfc", "nupdraft", "nupdrafts", "fv3_history2d", "all", .false., "none", 2 +#"gfs_sfc", "ktop_shallow", "ktop_shallow", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zol", "zol", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "flhc", "flhc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "flqc", "flqc", "fv3_history2d", "all", .false., "none", 2 +# Prognostic/diagnostic variables from RUC LSM +"gfs_sfc", "snowfall_acc", "snowfall_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "swe_snowfall_acc", "swe_snowfall_acc", "fv3_history2d", "all", .false., "none", 2 +# Stochastic physics +"gfs_phys", "sppt_wts", "sppt_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebu_wts", "skebu_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebv_wts", "skebv_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "shum_wts", "shum_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_pbl", "spp_wts_pbl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_sfc", "spp_wts_sfc", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_mp", "spp_wts_mp", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_rad", "spp_wts_rad", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_gwd", "spp_wts_gwd", "fv3_history", "all", .false., "none", 2 + +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_RRFS_v0 b/ush/templates/diag_table.FV3_RRFS_v0 new file mode 100644 index 0000000000..a3cb733d5c --- /dev/null +++ b/ush/templates/diag_table.FV3_RRFS_v0 @@ -0,0 +1,341 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +"grid_spec", -1, "months", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +#"atmos_4xdaily", 1, "hours", 1, "days", "time" +"fv3_history", 1, "years", 1, "hours", "time" +"fv3_history2d", 1, "years", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### +# "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "z1000", "z1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z850", "z850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z700", "z700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z500", "z500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z200", "z200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z100", "z100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z50", "z50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z10", "z10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "refl_10cm" "refl_10cm" "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cldfra", "cldfra", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +"gfs_dyn", "wmaxup", "upvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "wmaxdn", "dnvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax03", "uhmax03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax25", "uhmax25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin03", "uhmin03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin25", "uhmin25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort01", "maxvort01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort02", "maxvort02", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvorthy1", "maxvorthy1", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Aerosols (CCN, IN) from Thompson microphysics +"gfs_phys", "nwfa", "nwfa", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "nifa", "nifa", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "nwfa2d", "nwfa2d", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "nifa2d", "nifa2d", "fv3_history2d", "all", .false., "none", 2 +# Cloud effective radii from Thompson and WSM6 microphysics +"gfs_phys", "cleffr", "cleffr", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cieffr", "cieffr", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cseffr", "cseffr", "fv3_history", "all", .false., "none", 2 +# Prognostic/diagnostic variables from MYNN +"gfs_phys", "QC_BL", "qc_bl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "CLDFRA_BL", "cldfra_bl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "EL_PBL", "el_pbl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "QKE", "qke", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "maxmf", "maxmf", "fv3_history2d", "all", .false., "none", 2 +#"gfs_sfc", "nupdraft", "nupdrafts", "fv3_history2d", "all", .false., "none", 2 +#"gfs_sfc", "ktop_shallow", "ktop_shallow", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zol", "zol", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "flhc", "flhc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "flqc", "flqc", "fv3_history2d", "all", .false., "none", 2 +# Prognostic/diagnostic variables from RUC LSM +"gfs_sfc", "snowfall_acc", "snowfall_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "swe_snowfall_acc", "swe_snowfall_acc", "fv3_history2d", "all", .false., "none", 2 + +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/diag_table.FV3_RRFS_v1beta b/ush/templates/diag_table.FV3_RRFS_v1beta new file mode 100755 index 0000000000..00690a5498 --- /dev/null +++ b/ush/templates/diag_table.FV3_RRFS_v1beta @@ -0,0 +1,350 @@ +{{ starttime.strftime("%Y%m%d.%H") }}Z.{{ cres }}.32bit.non-hydro.regional +{{ starttime.strftime("%Y %m %d %H %M %S") }} + +"grid_spec", -1, "months", 1, "days", "time" +"atmos_static", -1, "hours", 1, "hours", "time" +#"atmos_4xdaily", 1, "hours", 1, "days", "time" +"fv3_history", 1, "years", 1, "hours", "time" +"fv3_history2d", 1, "years", 1, "hours", "time" + +# +#======================= +# ATMOSPHERE DIAGNOSTICS +#======================= +### +# grid_spec +### + "dynamics", "grid_lon", "grid_lon", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lat", "grid_lat", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_lont", "grid_lont", "grid_spec", "all", .false., "none", 2, + "dynamics", "grid_latt", "grid_latt", "grid_spec", "all", .false., "none", 2, + "dynamics", "area", "area", "grid_spec", "all", .false., "none", 2, +### +# 4x daily output +### +# "dynamics", "slp", "slp", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort850", "vort850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vort200", "vort200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "us", "us", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u1000", "u1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u850", "u850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u700", "u700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u500", "u500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u200", "u200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u100", "u100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u50", "u50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "u10", "u10", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "vs", "vs", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v1000", "v1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v850", "v850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v700", "v700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v500", "v500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v200", "v200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v100", "v100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v50", "v50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "v10", "v10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "tm", "tm", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t1000", "t1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t850", "t850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t700", "t700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t500", "t500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t200", "t200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t100", "t100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t50", "t50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "t10", "t10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "z1000", "z1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z850", "z850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z700", "z700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z500", "z500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z200", "z200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z100", "z100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z50", "z50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "z10", "z10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "w1000", "w1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w850", "w850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w700", "w700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w500", "w500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "w200", "w200", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "q1000", "q1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q850", "q850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q700", "q700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q500", "q500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q200", "q200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q100", "q100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q50", "q50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "q10", "q10", "atmos_4xdaily", "all", .false., "none", 2 +#### +# "dynamics", "rh1000", "rh1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh850", "rh850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh700", "rh700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh500", "rh500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "rh200", "rh200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg1000", "omg1000", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg850", "omg850", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg700", "omg700", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg500", "omg500", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg200", "omg200", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg100", "omg100", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg50", "omg50", "atmos_4xdaily", "all", .false., "none", 2 +# "dynamics", "omg10", "omg10", "atmos_4xdaily", "all", .false., "none", 2 +### +# gfs static data +### + "dynamics", "pk", "pk", "atmos_static", "all", .false., "none", 2 + "dynamics", "bk", "bk", "atmos_static", "all", .false., "none", 2 + "dynamics", "hyam", "hyam", "atmos_static", "all", .false., "none", 2 + "dynamics", "hybm", "hybm", "atmos_static", "all", .false., "none", 2 + "dynamics", "zsurf", "zsurf", "atmos_static", "all", .false., "none", 2 +### +# FV3 variabls needed for NGGPS evaluation +### +"gfs_dyn", "ucomp", "ugrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "vcomp", "vgrd", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "sphum", "spfh", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "temp", "tmp", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "liq_wat", "clwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "o3mr", "o3mr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delp", "dpres", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "delz", "delz", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "w", "dzdt", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ice_wat", "icmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "rainwat", "rwmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "snowwat", "snmr", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "graupel", "grle", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "ps", "pressfc", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "hs", "hgtsfc", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "refl_10cm" "refl_10cm" "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cldfra", "cldfra", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "ice_nc", "nicp", "fv3_history", "all", .false., "none", 2 +#"gfs_dyn", "rain_nc", "ntrnc", "fv3_history", "all", .false., "none", 2 + +"gfs_dyn", "wmaxup", "upvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "wmaxdn", "dnvvelmax", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax03", "uhmax03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmax25", "uhmax25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin03", "uhmin03", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "uhmin25", "uhmin25", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort01", "maxvort01", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvort02", "maxvort02", "fv3_history", "all", .false., "none", 2 +"gfs_dyn", "maxvorthy1", "maxvorthy1", "fv3_history", "all", .false., "none", 2 + +"gfs_phys", "ALBDO_ave", "albdo_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcp_ave", "cprat_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cnvprcpb_ave", "cpratb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcp_ave", "prate_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "totprcpb_ave", "prateb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRF", "dlwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DLWRFI", "dlwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRF", "ulwrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFI", "ulwrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRF", "dswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFI", "dswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRF", "uswrf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFI", "uswrf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "DSWRFtoa", "dswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "USWRFtoa", "uswrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ULWRFtoa", "ulwrf_avetoa","fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gflux_ave", "gflux_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hpbl", "hpbl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl_ave", "lhtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl_ave", "shtfl_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pwat", "pwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "soilm", "soilm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_aveclm", "tcdc_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avebndcl", "tcdc_avebndcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avehcl", "tcdc_avehcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avelcl", "tcdc_avelcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDC_avemcl", "tcdc_avemcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TCDCcnvcl", "tcdccnvcl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclt", "prescnvclt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PREScnvclb", "prescnvclb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehct", "pres_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avehcb", "pres_avehcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avehct", "tmp_avehct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemct", "pres_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avemcb", "pres_avemcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avemct", "tmp_avemct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelct", "pres_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "PRES_avelcb", "pres_avelcb", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "TEMP_avelct", "tmp_avelct", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u-gwd_ave", "u-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v-gwd_ave", "v-gwd_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dusfc", "uflx_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "dvsfc", "vflx_ave", "fv3_history2d", "all", .false., "none", 2 +#"gfs_phys", "cnvw", "cnvcldwat", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "psurf", "pressfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "u10m", "ugrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "v10m", "vgrd10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "crain", "crain", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tprcp", "tprcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hgtsfc", "orog", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "weasd", "weasd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "f10m", "f10m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "q2m", "spfh2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "t2m", "tmp2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tsfc", "tmpsfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vtype", "vtype", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "stype", "sotyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slmsksfc", "land", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "vfracsfc", "veg", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zorlsfc", "sfcr", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "uustar", "fricv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt1", "soilt1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt2", "soilt2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt3", "soilt3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilt4", "soilt4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw1", "soilw1" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw2", "soilw2" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw3", "soilw3" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "soilw4", "soilw4" "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_1", "soill1", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_2", "soill2", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_3", "soill3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slc_4", "soill4", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "slope", "sltyp", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnsf", "alnsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alnwf", "alnwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvsf", "alvsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "alvwf", "alvwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "canopy", "cnwat", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facsf", "facsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "facwf", "facwf", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffhh", "ffhh", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "ffmm", "ffmm", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "fice", "icec", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "hice", "icetk", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snoalb", "snoalb", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmax", "shdmax", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "shdmin", "shdmin", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "snowd", "snod", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tg3", "tg3", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tisfc", "tisfc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "tref", "tref", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "z_c", "zc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_0", "c0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "c_d", "cd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_0", "w0", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "w_d", "wd", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xt", "xt", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xz", "xz", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "dt_cool", "dtcool", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xs", "xs", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xu", "xu", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xv", "xv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xtts", "xtts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "xzts", "xzts", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "d_conv", "dconv", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "qrain", "qrain", "fv3_history2d", "all", .false., "none", 2 + +"gfs_phys", "acond", "acond", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cduvb_ave", "cduvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cpofp", "cpofp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "duvb_ave", "duvb_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdlf_ave", "csdlf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_ave", "csusf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csusf_avetoa", "csusftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csdsf_ave", "csdsf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_ave", "csulf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "csulf_avetoa", "csulftoa", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "cwork_ave", "cwork_aveclm", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evbs_ave", "evbs_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "evcw_ave", "evcw_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "fldcp", "fldcp", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "hgt_hyblev1", "hgt_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfh_hyblev1", "spfh_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ugrd_hyblev1", "ugrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vgrd_hyblev1", "vgrd_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmp_hyblev1", "tmp_hyblev1", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "gfluxi", "gflux", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "lhtfl", "lhtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "shtfl", "shtfl", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr", "pevpr", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "pevpr_ave", "pevpr_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sbsno_ave", "sbsno_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sfexc", "sfexc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snohf", "snohf", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "snowc_ave", "snowc_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmax2m", "spfhmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "spfhmin2m", "spfhmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmax2m", "tmax_max2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "tmpmin2m", "tmin_min2m", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "ssrun_acc", "ssrun_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "sunsd_acc", "sunsd_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "watr_acc", "watr_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "wilt", "wilt", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vbdsf_ave", "vbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "vddsf_ave", "vddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nbdsf_ave", "nbdsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "nddsf_ave", "nddsf_ave", "fv3_history2d", "all", .false., "none", 2 +"gfs_phys", "trans_ave", "trans_ave", "fv3_history2d", "all", .false., "none", 2 +# Aerosols (CCN, IN) from Thompson microphysics +"gfs_phys", "nwfa", "nwfa", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "nifa", "nifa", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "nwfa2d", "nwfa2d", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "nifa2d", "nifa2d", "fv3_history2d", "all", .false., "none", 2 +# Cloud effective radii from Thompson and WSM6 microphysics +"gfs_phys", "cleffr", "cleffr", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cieffr", "cieffr", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "cseffr", "cseffr", "fv3_history", "all", .false., "none", 2 +# Prognostic/diagnostic variables from MYNN +"gfs_phys", "QC_BL", "qc_bl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "CLDFRA_BL", "cldfra_bl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "EL_PBL", "el_pbl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "QKE", "qke", "fv3_history", "all", .false., "none", 2 +"gfs_sfc", "maxmf", "maxmf", "fv3_history2d", "all", .false., "none", 2 +#"gfs_sfc", "nupdraft", "nupdrafts", "fv3_history2d", "all", .false., "none", 2 +#"gfs_sfc", "ktop_shallow", "ktop_shallow", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "zol", "zol", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "flhc", "flhc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "flqc", "flqc", "fv3_history2d", "all", .false., "none", 2 +# Prognostic/diagnostic variables from RUC LSM +"gfs_sfc", "snowfall_acc", "snowfall_acc", "fv3_history2d", "all", .false., "none", 2 +"gfs_sfc", "swe_snowfall_acc", "swe_snowfall_acc", "fv3_history2d", "all", .false., "none", 2 +# Stochastic physics +"gfs_phys", "sppt_wts", "sppt_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebu_wts", "skebu_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "skebv_wts", "skebv_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "shum_wts", "shum_wts", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_pbl", "spp_wts_pbl", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_sfc", "spp_wts_sfc", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_mp", "spp_wts_mp", "fv3_history", "all", .false., "none", 2 +"gfs_phys", "spp_wts_rad", "spp_wts_rad", "fv3_history", "all", .false., "none", 2 + +#============================================================================================= +# +#====> This file can be used with diag_manager/v2.0a (or higher) <==== +# +# +# FORMATS FOR FILE ENTRIES (not all input values are used) +# ------------------------ +# +#"file_name", output_freq, "output_units", format, "time_units", "long_name", +# +# +#output_freq: > 0 output frequency in "output_units" +# = 0 output frequency every time step +# =-1 output frequency at end of run +# +#output_units = units used for output frequency +# (years, months, days, minutes, hours, seconds) +# +#time_units = units used to label the time axis +# (days, minutes, hours, seconds) +# +# +# FORMAT FOR FIELD ENTRIES (not all input values are used) +# ------------------------ +# +#"module_name", "field_name", "output_name", "file_name" "time_sampling", time_avg, "other_opts", packing +# +#time_avg = .true. or .false. +# +#packing = 1 double precision +# = 2 float +# = 4 packed 16-bit integers +# = 8 packed 1-byte (not tested?) diff --git a/ush/templates/field_table.FV3_GFS_2017_gfdlmp b/ush/templates/field_table.FV3_GFS_2017_gfdlmp new file mode 100644 index 0000000000..77ccbf9a79 --- /dev/null +++ b/ush/templates/field_table.FV3_GFS_2017_gfdlmp @@ -0,0 +1,38 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=3.e-6" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "ice_wat" + "longname", "ice water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=3.e-6" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "rainwat" + "longname", "rain water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "snowwat" + "longname", "snow water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# non-prognostic cloud amount + "TRACER", "atmos_mod", "cld_amt" + "longname", "cloud amount" + "units", "1" + "profile_type", "fixed", "surface_value=1.e30" / diff --git a/ush/templates/field_table.FV3_GFS_2017_gfdlmp_regional b/ush/templates/field_table.FV3_GFS_2017_gfdlmp_regional new file mode 100644 index 0000000000..7719eb2e09 --- /dev/null +++ b/ush/templates/field_table.FV3_GFS_2017_gfdlmp_regional @@ -0,0 +1,38 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "rainwat" + "longname", "rain mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "snowwat" + "longname", "snow mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# non-prognostic cloud amount + "TRACER", "atmos_mod", "cld_amt" + "longname", "cloud amount" + "units", "1" + "profile_type", "fixed", "surface_value=1.e30" / + diff --git a/ush/templates/field_table.FV3_GFS_v15_thompson_mynn_lam3km b/ush/templates/field_table.FV3_GFS_v15_thompson_mynn_lam3km new file mode 100644 index 0000000000..6fea174372 --- /dev/null +++ b/ush/templates/field_table.FV3_GFS_v15_thompson_mynn_lam3km @@ -0,0 +1,51 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=3.e-6" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ice water mixing ratio + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic rain water mixing ratio + "TRACER", "atmos_mod", "rainwat" + "longname", "rain water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic snow water mixing ratio + "TRACER", "atmos_mod", "snowwat" + "longname", "snow water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic Grau water mixing ratio + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud ice number concentration + "TRACER", "atmos_mod", "ice_nc" + "longname", "cloud ice water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic rain number concentration + "TRACER", "atmos_mod", "rain_nc" + "longname", "rain number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic subgrid scale turbulent kinetic energy + "TRACER", "atmos_mod", "sgs_tke" + "longname", "subgrid scale turbulent kinetic energy" + "units", "m2/s2" + "profile_type", "fixed", "surface_value=0.0" / diff --git a/ush/templates/field_table.FV3_GFS_v15p2 b/ush/templates/field_table.FV3_GFS_v15p2 new file mode 100644 index 0000000000..06adb66d72 --- /dev/null +++ b/ush/templates/field_table.FV3_GFS_v15p2 @@ -0,0 +1,42 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "rainwat" + "longname", "rain mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "snowwat" + "longname", "snow mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic subgrid scale turbulent kinetic energy + "TRACER", "atmos_mod", "sgs_tke" + "longname", "subgrid scale turbulent kinetic energy" + "units", "m2/s2" + "profile_type", "fixed", "surface_value=0.0" / +# non-prognostic cloud amount + "TRACER", "atmos_mod", "cld_amt" + "longname", "cloud amount" + "units", "1" + "profile_type", "fixed", "surface_value=1.e30" / diff --git a/ush/templates/field_table.FV3_GFS_v16 b/ush/templates/field_table.FV3_GFS_v16 new file mode 100644 index 0000000000..06adb66d72 --- /dev/null +++ b/ush/templates/field_table.FV3_GFS_v16 @@ -0,0 +1,42 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "rainwat" + "longname", "rain mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "snowwat" + "longname", "snow mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic subgrid scale turbulent kinetic energy + "TRACER", "atmos_mod", "sgs_tke" + "longname", "subgrid scale turbulent kinetic energy" + "units", "m2/s2" + "profile_type", "fixed", "surface_value=0.0" / +# non-prognostic cloud amount + "TRACER", "atmos_mod", "cld_amt" + "longname", "cloud amount" + "units", "1" + "profile_type", "fixed", "surface_value=1.e30" / diff --git a/ush/templates/field_table.FV3_HRRR b/ush/templates/field_table.FV3_HRRR new file mode 100644 index 0000000000..fbfb0c3399 --- /dev/null +++ b/ush/templates/field_table.FV3_HRRR @@ -0,0 +1,65 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ice water mixing ratio + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic rain water mixing ratio + "TRACER", "atmos_mod", "rainwat" + "longname", "rain water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic snow water mixing ratio + "TRACER", "atmos_mod", "snowwat" + "longname", "snow water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic graupel mixing ratio + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water number concentration + "TRACER", "atmos_mod", "water_nc" + "longname", "cloud liquid water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic cloud ice number concentration + "TRACER", "atmos_mod", "ice_nc" + "longname", "cloud ice water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic rain number concentration + "TRACER", "atmos_mod", "rain_nc" + "longname", "rain number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# water- and ice-friendly aerosols (Thompson) + "TRACER", "atmos_mod", "liq_aero" + "longname", "water-friendly aerosol number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / + "TRACER", "atmos_mod", "ice_aero" + "longname", "ice-friendly aerosol number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic subgrid scale turbulent kinetic energy + "TRACER", "atmos_mod", "sgs_tke" + "longname", "subgrid scale turbulent kinetic energy" + "units", "m2/s2" + "profile_type", "fixed", "surface_value=0.0" / diff --git a/ush/templates/field_table.FV3_RRFS_v0 b/ush/templates/field_table.FV3_RRFS_v0 new file mode 100644 index 0000000000..fe96567e5f --- /dev/null +++ b/ush/templates/field_table.FV3_RRFS_v0 @@ -0,0 +1,65 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ice water mixing ratio + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic rain water mixing ratio + "TRACER", "atmos_mod", "rainwat" + "longname", "rain water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic snow water mixing ratio + "TRACER", "atmos_mod", "snowwat" + "longname", "snow water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic graupel mixing ratio + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water number concentration + "TRACER", "atmos_mod", "water_nc" + "longname", "cloud liquid water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud ice number concentration + "TRACER", "atmos_mod", "ice_nc" + "longname", "cloud ice water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic rain number concentration + "TRACER", "atmos_mod", "rain_nc" + "longname", "rain number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# water- and ice-friendly aerosols (Thompson) + "TRACER", "atmos_mod", "liq_aero" + "longname", "water-friendly aerosol number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / + "TRACER", "atmos_mod", "ice_aero" + "longname", "ice-friendly aerosol number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic subgrid scale turbulent kinetic energy + "TRACER", "atmos_mod", "sgs_tke" + "longname", "subgrid scale turbulent kinetic energy" + "units", "m2/s2" + "profile_type", "fixed", "surface_value=0.0" / diff --git a/ush/templates/field_table.FV3_RRFS_v1beta b/ush/templates/field_table.FV3_RRFS_v1beta new file mode 100644 index 0000000000..fe96567e5f --- /dev/null +++ b/ush/templates/field_table.FV3_RRFS_v1beta @@ -0,0 +1,65 @@ +# added by FRE: sphum must be present in atmos +# specific humidity for moist runs + "TRACER", "atmos_mod", "sphum" + "longname", "specific humidity" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water mixing ratio + "TRACER", "atmos_mod", "liq_wat" + "longname", "cloud water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic ice water mixing ratio + "TRACER", "atmos_mod", "ice_wat" + "longname", "cloud ice mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic rain water mixing ratio + "TRACER", "atmos_mod", "rainwat" + "longname", "rain water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic snow water mixing ratio + "TRACER", "atmos_mod", "snowwat" + "longname", "snow water mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic graupel mixing ratio + "TRACER", "atmos_mod", "graupel" + "longname", "graupel mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud water number concentration + "TRACER", "atmos_mod", "water_nc" + "longname", "cloud liquid water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# prognostic cloud ice number concentration + "TRACER", "atmos_mod", "ice_nc" + "longname", "cloud ice water number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic rain number concentration + "TRACER", "atmos_mod", "rain_nc" + "longname", "rain number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic ozone mixing ratio tracer + "TRACER", "atmos_mod", "o3mr" + "longname", "ozone mixing ratio" + "units", "kg/kg" + "profile_type", "fixed", "surface_value=1.e30" / +# water- and ice-friendly aerosols (Thompson) + "TRACER", "atmos_mod", "liq_aero" + "longname", "water-friendly aerosol number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / + "TRACER", "atmos_mod", "ice_aero" + "longname", "ice-friendly aerosol number concentration" + "units", "/kg" + "profile_type", "fixed", "surface_value=0.0" / +# prognostic subgrid scale turbulent kinetic energy + "TRACER", "atmos_mod", "sgs_tke" + "longname", "subgrid scale turbulent kinetic energy" + "units", "m2/s2" + "profile_type", "fixed", "surface_value=0.0" / diff --git a/ush/templates/input.nml.FV3 b/ush/templates/input.nml.FV3 new file mode 100644 index 0000000000..e33c09522c --- /dev/null +++ b/ush/templates/input.nml.FV3 @@ -0,0 +1,242 @@ +&amip_interp_nml + data_set = 'reynolds_oi' + date_out_of_range = 'climo' + interp_oi_sst = .true. + no_anom_sst = .false. + use_ncep_ice = .false. + use_ncep_sst = .true. +/ + +&atmos_model_nml + chksum_debug = .false. + dycore_only = .false. +/ + +&cires_ugwp_nml + knob_ugwp_azdir = 2,4,4,4 + knob_ugwp_doaxyz = 1 + knob_ugwp_doheat = 1 + knob_ugwp_dokdis = 1 + knob_ugwp_effac = 1,1,1,1 + knob_ugwp_ndx4lh = 1 + knob_ugwp_solver = 2 + knob_ugwp_source = 1,1,0,0 + knob_ugwp_stoch = 0,0,0,0 + knob_ugwp_version = 0 + knob_ugwp_wvspec = 1,25,25,25 + launch_level = 25 +/ + +&diag_manager_nml + prepend_date = .false. +/ + +&external_ic_nml + checker_tr = .false. + filtered_terrain = .true. + gfs_dwinds = .true. + levp = 65 + nt_checker = 0 +/ + +&fms_io_nml + checksum_required = .false. + max_files_r = 100 + max_files_w = 100 +/ + +&fms_nml + clock_grain = 'ROUTINE' + domains_stack_size = 5000000 + print_memory_usage = .false. +/ + +&fv_core_nml + a_imp = 1.0 + adjust_dry_mass = .false. + beta = 0.0 + consv_am = .false. + consv_te = 0.0 + d2_bg = 0.0 + d2_bg_k1 = 0.20 + d2_bg_k2 = 0.04 + d4_bg = 0.12 + d_con = 1.0 + d_ext = 0.0 + dddmp = 0.1 + delt_max = 0.008 + dnats = 0 + do_sat_adj = .false. + do_schmidt = .true. + do_vort_damp = .true. + dwind_2d = .false. + dz_min = 2 + external_eta = .true. + external_ic = .true. + fill = .true. + full_zs_filter = .false. + fv_debug = .false. + fv_sg_adj = 300 + gfs_phil = .false. + hord_dp = 6 + hord_mt = 6 + hord_tm = 6 + hord_tr = 10 + hord_vt = 6 + hydrostatic = .false. + io_layout = 1,1 + k_split = 2 + ke_bg = 0.0 + kord_mt = 9 + kord_tm = -9 + kord_tr = 9 + kord_wz = 9 + make_nh = .true. + mountain = .false. + n_split = 5 + n_sponge = 24 + n_zs_filter = 0 + na_init = 1 + ncep_ic = .false. + nggps_ic = .true. + no_dycore = .false. + nord = 3 + npz = 64 + nrows_blend = 10 + ntiles = 1 + nudge_qv = .false. + nwat = 6 + p_fac = 0.1 + phys_hydrostatic = .false. + print_freq = 6 + psm_bc = 1 + range_warn = .true. + read_increment = .false. + regional = .true. + regional_bcs_from_gsi = .false. + res_latlon_dynamics = 'fv3_increment.nc' + reset_eta = .false. + rf_cutoff = 20.e2 + tau = 5.0 + use_hydro_pressure = .false. + vtdm4 = 0.02 + warm_start = .false. + write_restart_with_bcs = .false. + z_tracer = .true. +/ + +&fv_grid_nml + grid_file = 'INPUT/grid_spec.nc' +/ + +&gfs_physics_nml + bl_mynn_edmf = 1 + bl_mynn_edmf_mom = 1 + bl_mynn_tkeadvect = .true. + cal_pre = .false. + cdmbgwd = 3.5,0.25 + cnvcld = .false. + cnvgwd = .false. + cplflx = .false. + debug = .false. + do_mynnedmf = .true. + do_mynnsfclay = .false. + dspheat = .true. + effr_in = .true. + fhcyc = 0.0 + fhlwr = 1200.0 + fhswr = 1200.0 + fhzero = 1.0 + h2o_phys = .true. + hybedmf = .false. + iaer = 111 + ialb = 1 + iau_delthrs = 6 + iau_inc_files = '' + iaufhrs = 30 + icloud_bl = 1 + ico2 = 2 + iems = 1 + imfdeepcnv = 3 + imfshalcnv = 3 + imp_physics = 8 + isol = 2 + isot = 1 + isubc_lw = 2 + isubc_sw = 2 + ivegsrc = 1 + ldiag3d = .false. + lheatstrg = .false. + lradar = .true. + lsm = 3 + lsoil_lsm = 9 + ltaerosol = .true. + lwhtr = .true. + nsradar_reset = 3600 + nst_anl = .true. + nstf_name = 2,1,0,0,0 + oz_phys = .false. + oz_phys_2015 = .true. + pdfcld = .false. + pre_rad = .false. + print_diff_pgr = .false. + prslrd0 = 0.0 + random_clds = .false. + redrag = .true. + satmedmf = .false. + sfclay_compute_flux = .false. + shal_cnv = .false. + swhtr = .true. + trans_trac = .true. + ttendlim = -999 + use_ufo = .true. +/ + +&interpolator_nml + interp_method = 'conserve_great_circle' +/ + +&nam_sfcperts +/ + +&nam_sppperts +/ + +&nam_stochy +/ + +&namsfc + fabsl = 99999 + faisl = 99999 + faiss = 99999 + fnacna = '' + fnsnoa = '' + fntsfa = '' + fnzorc = 'igbp' + fsicl = 99999 + fsics = 99999 + fslpl = 99999 + fsmcl(2) = 99999 + fsmcl(3) = 99999 + fsmcl(4) = 99999 + fsnol = 99999 + fsnos = 99999 + fsotl = 99999 + ftsfl = 99999 + ftsfs = 90 + fvetl = 99999 + fvmnl = 99999 + fvmxl = 99999 + ldebug = .true. +/ + +&surf_map_nml + cd2 = -1 + cd4 = 0.12 + max_slope = 0.4 + n_del2_strong = 0 + n_del2_weak = 2 + n_del4 = 1 + peak_fac = 1.0 + zero_ocean = .false. +/ diff --git a/ush/templates/model_configure b/ush/templates/model_configure new file mode 100644 index 0000000000..fa2472e336 --- /dev/null +++ b/ush/templates/model_configure @@ -0,0 +1,115 @@ +total_member: 1 +PE_MEMBER01: {{ PE_MEMBER01 }} +print_esmf: {{ print_esmf }} +start_year: {{ start_year }} +start_month: {{ start_month }} +start_day: {{ start_day }} +start_hour: {{ start_hour }} +start_minute: 0 +start_second: 0 +nhours_fcst: {{ nhours_fcst }} +RUN_CONTINUE: .false. +ENS_SPS: .false. +dt_atmos: {{ dt_atmos }} +cpl: {{ cpl }} +calendar: 'julian' +memuse_verbose: .false. +atmos_nthreads: {{ atmos_nthreads }} +restart_interval: {{ restart_interval }} -1 +output_1st_tstep_rst: .false. +write_dopost: {{ write_dopost }} +ideflate: 0 +nbits: 0 +quilting: {{ quilting }} +{% if quilting %} +# +# Write-component (quilting) computational parameters. +# +write_groups: {{ write_groups }} +write_tasks_per_group: {{ write_tasks_per_group }} +num_files: 2 +filename_base: 'dyn' 'phy' +output_file: 'netcdf' 'netcdf' +# +# Write-component output frequency parameter definitions: +# +# output_fh: Output frequency in hours. +# nsout: Output frequency in time steps (positive values override "output_fh"). +# +output_fh: {{ output_fh }} -1 +nsout: {{ nsout }} +# +# Coordinate system used by the output grid. +# +output_grid: '{{ output_grid }}' +# +# Parameter definitions for an output grid of type "{{ output_grid }}": +# + {%- if output_grid == "lambert_conformal" %} +# cen_lon: Longitude of center of grid (degrees). +# cen_lat: Latitude of center of grid (degrees). +# stdlat1: Latitude of first standard parallel (degrees). +# stdlat2: Latitude of second standard parallel (degrees). +# nx: Number of grid cells along x-axis in Lambert conformal (x,y) plane. +# ny: Number of grid cells along y-axis in Lambert conformal (x,y) plane. +# lon1: Longitude of center of grid cell at bottom-left corner of grid (degrees). +# lat1: Latitude of center of grid cell at bottom-left corner of grid (degrees). +# dx: Grid cell size in x direction (meters). +# dy: Grid cell size in y direction (meters). +# + {%- elif output_grid == "regional_latlon" %} +# cen_lon: Longitude of center of grid (degrees). +# cen_lat: Latitude of center of grid (degrees). +# lon1: Longitude of center of lower-left (southwest) grid cell (degrees). +# lat1: Latitude of center of lower-left (southwest) grid cell (degrees). +# lon2: Longitude of center of upper-right (northeast) grid cell (degrees). +# lat2: Latitude of center of upper-right (northeast) grid cell (degrees). +# dlon: Longitudinal grid size (degrees). +# dlat: Latitudinal grid size (degrees). +# + {%- elif output_grid == "rotated_latlon" %} +# cen_lon: Longitude of center of grid, expressed in the NON-ROTATED latlon coordinate +# system (degrees). This is also the longitude of the point at which the +# equator and prime meridian of the ROTATED coordinate system intersect (i.e. +# the point at which the longitude and latitude in the ROTATED latlon +# coordinate system are both 0). +# cen_lat: Latitude of center of grid, expressed in the NON-ROTATED latlon coordinate +# system (degrees). This is also the latitude of the point at which the +# equator and prime meridian of the ROTATED coordinate system intersect (i.e. +# the point at which the longitude and latitude in the ROTATED latlon +# coordinate system are both 0). +# lon1: Longitude of center of lower-left grid cell, expressed in the ROTATED latlon +# coordinate system (degrees). +# lat1: Latitude of center of lower-left grid cell, expressed in the ROTATED latlon +# coordinate system (degrees). +# lon2: Longitude of center of upper-right grid cell, expressed in the ROTATED latlon +# coordinate system (degrees). +# lat2: Latitude of center of upper-right grid cell, expressed in the ROTATED latlon +# coordinate system (degrees). +# dlon: Longitudinal grid size in the ROTATED latlon coordinate system (degrees). +# dlat: Latitudinal grid size in the ROTATED latlon coordinate system (degrees). +# + {%- endif %} + {%- if output_grid == "lambert_conformal" %} +cen_lon: {{ cen_lon }} +cen_lat: {{ cen_lat }} +stdlat1: {{ stdlat1 }} +stdlat2: {{ stdlat2 }} +nx: {{ nx }} +ny: {{ ny }} +lon1: {{ lon1 }} +lat1: {{ lat1 }} +dx: {{ dx }} +dy: {{ dy }} + {%- elif (output_grid == "regional_latlon") or (output_grid == "rotated_latlon") %} +cen_lon: {{ cen_lon }} +cen_lat: {{ cen_lat }} +lon1: {{ lon1 }} +lat1: {{ lat1 }} +lon2: {{ lon2 }} +lat2: {{ lat2 }} +dlon: {{ dlon }} +dlat: {{ dlat }} + {%- endif %} +{%- endif %} + diff --git a/ush/templates/nems.configure b/ush/templates/nems.configure new file mode 100644 index 0000000000..86b095464b --- /dev/null +++ b/ush/templates/nems.configure @@ -0,0 +1,6 @@ +EARTH_component_list: ATM + ATM_model: fv3 + runSeq:: + ATM + :: +logKindFlag: ESMF_LOGKIND_MULTI_ON_ERROR diff --git a/ush/templates/parm/metplus/EnsembleStat_APCP01h.conf b/ush/templates/parm/metplus/EnsembleStat_APCP01h.conf new file mode 100644 index 0000000000..33599d9f79 --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_APCP01h.conf @@ -0,0 +1,251 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} + +ENSEMBLE_STAT_DESC = NA ;; not in other file + +# Name to identify observation data in output +OBTYPE = CCPA + +#ENSEMBLE_STAT_DESC = # not in other file + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +#LOG_ENSEMBLE_STAT_VERBOSITY = 2 + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = 0 +OBS_ENSEMBLE_STAT_WINDOW_END = 0 + +OBS_FILE_WINDOW_BEGIN = 0 +OBS_FILE_WINDOW_END = 0 + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_APCP_01h_{OBTYPE} + +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = {MET_BASE}/table_files/obs_error_table.txt + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = FCST +ENSEMBLE_STAT_REGRID_METHOD = BUDGET +ENSEMBLE_STAT_REGRID_WIDTH = 2 +ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = + +ENSEMBLE_STAT_DUPLICATE_FLAG = UNIQUE +ENSEMBLE_STAT_SKIP_CONST = TRUE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = TRUE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = APCP +ENS_VAR1_LEVELS = A01 +ENS_VAR1_THRESH = gt0.0,ge0.254,ge0.508,ge2.54 + +# Forecast Variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION +FCST_VAR1_NAME = APCP +FCST_VAR1_LEVELS = A01 + +FCST_VAR1_OPTIONS = ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + +# Observation Variables and levels as specified in the obs field dictionary +# of the MET configuration file. Specify as OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION +OBS_VAR1_NAME = {FCST_VAR1_NAME} +OBS_VAR1_LEVELS = {FCST_VAR1_LEVELS} + +OBS_VAR1_OPTIONS = {FCST_VAR1_OPTIONS} + + +[dir] +# Input and output data directories +INPUT_BASE = {ENV[EXPTDIR]}/{ENV[CDATE]} +OUTPUT_BASE = {ENV[EXPTDIR]} + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {INPUT_BASE} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {OUTPUT_BASE}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_01 + + +[filename_templates] + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = mem*/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.ensgrid_APCP_01h.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_APCP03h.conf b/ush/templates/parm/metplus/EnsembleStat_APCP03h.conf new file mode 100644 index 0000000000..2691dc2dca --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_APCP03h.conf @@ -0,0 +1,296 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = PcpCombine, EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# Loop through ensmeble members for making precip buckets +PCP_COMBINE_CUSTOM_LOOP_LIST = membegin_end_incr(1,{ENV[NUM_ENS_MEMBERS]},1,{ENV[NUM_PAD]}) + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB + +ENSEMBLE_STAT_DESC = NA ;; not in other file + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = True +OBS_PCP_COMBINE_RUN = True + +# Mode of pcp_combine to use (SUM, ADD, SUBTRACT) +FCST_PCP_COMBINE_METHOD = ADD +OBS_PCP_COMBINE_METHOD = ADD + +FCST_PCP_COMBINE_CONSTANT_INIT = True + +# Accumulation interval available in forecast data +FCST_PCP_COMBINE_INPUT_ACCUMS = 01 +FCST_PCP_COMBINE_OUTPUT_ACCUM = 03 + +# Accumulation interval available in observation data +OBS_PCP_COMBINE_INPUT_ACCUMS = 01 +OBS_PCP_COMBINE_OUTPUT_ACCUM = 03 + +# If 'bucket' output already exists, skip the PcpCombine step for the data +PCP_COMBINE_SKIP_IF_OUTPUT_EXISTS = True + +# Forecast data description variables +FCST_PCP_COMBINE_INPUT_DATATYPE = GRIB +FCST_IS_PROB = false + +#ENSEMBLE_STAT_DESC = # not in other file + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +#LOG_ENSEMBLE_STAT_VERBOSITY = 2 + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = 0 +OBS_ENSEMBLE_STAT_WINDOW_END = 0 + +OBS_FILE_WINDOW_BEGIN = 0 +OBS_FILE_WINDOW_END = 0 + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_APCP_03h_{OBTYPE} + +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = {MET_BASE}/table_files/obs_error_table.txt + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = FCST +ENSEMBLE_STAT_REGRID_METHOD = BUDGET +ENSEMBLE_STAT_REGRID_WIDTH = 2 +ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = + +ENSEMBLE_STAT_DUPLICATE_FLAG = UNIQUE +ENSEMBLE_STAT_SKIP_CONST = TRUE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = TRUE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = APCP +ENS_VAR1_LEVELS = A03 +ENS_VAR1_THRESH = gt0.0,ge0.508,ge2.54,ge6.350 + +# Forecast Variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION +FCST_VAR1_NAME = APCP +FCST_VAR1_LEVELS = A03 + +FCST_VAR1_OPTIONS = ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + +# Observation Variables and levels as specified in the obs field dictionary +# of the MET configuration file. Specify as OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION +OBS_VAR1_NAME = {FCST_VAR1_NAME} +OBS_VAR1_LEVELS = {FCST_VAR1_LEVELS} + +OBS_VAR1_OPTIONS = {FCST_VAR1_OPTIONS} + + +[dir] +# Input and output data directories +INPUT_BASE = {ENV[EXPTDIR]}/{ENV[CDATE]} +OUTPUT_BASE = {ENV[EXPTDIR]} + +# Input and output fcst data directories for pcp-combine +FCST_PCP_COMBINE_INPUT_DIR = {INPUT_BASE} +FCST_PCP_COMBINE_OUTPUT_DIR = {INPUT_BASE} + +# Input and output obs data directories for pcp-combine +OBS_PCP_COMBINE_INPUT_DIR = {ENV[OBS_DIR]} +OBS_PCP_COMBINE_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {FCST_PCP_COMBINE_OUTPUT_DIR} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = {OBS_PCP_COMBINE_OUTPUT_DIR} + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {OUTPUT_BASE}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_03 + + +[filename_templates] +# Need to have PCPCombine output data to individual member directories. +FCST_PCP_COMBINE_INPUT_TEMPLATE = {custom?fmt=%s}/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = {custom?fmt=%s}/metprd/pcp_combine/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a03h + +# Input and output template for obs pcp-combine files +OBS_PCP_COMBINE_INPUT_TEMPLATE = {OBS_PCP_COMBINE_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a03h + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = membegin_end_incr(1,{ENV[NUM_ENS_MEMBERS]},1,{ENV[NUM_PAD]})/metprd/pcp_combine/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a03h + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_TEMPLATE} + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.ensgrid_APCP_03h.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_APCP06h.conf b/ush/templates/parm/metplus/EnsembleStat_APCP06h.conf new file mode 100644 index 0000000000..8527e23635 --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_APCP06h.conf @@ -0,0 +1,297 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = PcpCombine, EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# Loop through ensmeble members for making precip buckets +PCP_COMBINE_CUSTOM_LOOP_LIST = membegin_end_incr(1,{ENV[NUM_ENS_MEMBERS]},1,{ENV[NUM_PAD]}) + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB + +ENSEMBLE_STAT_DESC = NA ;; not in other file + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = True +OBS_PCP_COMBINE_RUN = True + +# Mode of pcp_combine to use (SUM, ADD, SUBTRACT) +FCST_PCP_COMBINE_METHOD = ADD +OBS_PCP_COMBINE_METHOD = ADD + +FCST_PCP_COMBINE_CONSTANT_INIT = True + +# Accumulation interval available in forecast data +FCST_PCP_COMBINE_INPUT_ACCUMS = 01 +FCST_PCP_COMBINE_OUTPUT_ACCUM = 06 + +# Accumulation interval available in observation data +OBS_PCP_COMBINE_INPUT_ACCUMS = 01 +OBS_PCP_COMBINE_OUTPUT_ACCUM = 06 + +# If 'bucket' output already exists, skip the PcpCombine step for the data +PCP_COMBINE_SKIP_IF_OUTPUT_EXISTS = True + +# Forecast data description variables +FCST_PCP_COMBINE_INPUT_DATATYPE = GRIB +FCST_IS_PROB = false + +#ENSEMBLE_STAT_DESC = # not in other file + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +#LOG_ENSEMBLE_STAT_VERBOSITY = 2 + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = 0 +OBS_ENSEMBLE_STAT_WINDOW_END = 0 + +OBS_FILE_WINDOW_BEGIN = 0 +OBS_FILE_WINDOW_END = 0 + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_APCP_06h_{OBTYPE} + +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = {MET_BASE}/table_files/obs_error_table.txt + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = FCST +ENSEMBLE_STAT_REGRID_METHOD = BUDGET +ENSEMBLE_STAT_REGRID_WIDTH = 2 +ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = + +ENSEMBLE_STAT_DUPLICATE_FLAG = UNIQUE +ENSEMBLE_STAT_SKIP_CONST = TRUE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = TRUE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = APCP +ENS_VAR1_LEVELS = A06 +ENS_VAR1_THRESH = gt0.0,ge2.54,ge6.350,ge12.700 + +# Forecast Variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION +FCST_VAR1_NAME = APCP +FCST_VAR1_LEVELS = A06 + +# FIGURE OUT WHAT BIN SIZE SHOULD BE +FCST_VAR1_OPTIONS = ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + + +# Observation Variables and levels as specified in the obs field dictionary +# of the MET configuration file. Specify as OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION +OBS_VAR1_NAME = {FCST_VAR1_NAME} +OBS_VAR1_LEVELS = {FCST_VAR1_LEVELS} + +OBS_VAR1_OPTIONS = {FCST_VAR1_OPTIONS} + +[dir] +# Input and output data directories +INPUT_BASE = {ENV[EXPTDIR]}/{ENV[CDATE]} +OUTPUT_BASE = {ENV[EXPTDIR]} + +# Input and output fcst data directories for pcp-combine +FCST_PCP_COMBINE_INPUT_DIR = {INPUT_BASE} +FCST_PCP_COMBINE_OUTPUT_DIR = {INPUT_BASE} + +# Input and output obs data directories for pcp-combine +OBS_PCP_COMBINE_INPUT_DIR = {ENV[OBS_DIR]} +OBS_PCP_COMBINE_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {FCST_PCP_COMBINE_OUTPUT_DIR} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = {OBS_PCP_COMBINE_OUTPUT_DIR} + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {OUTPUT_BASE}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_01 + + +[filename_templates] +# Need to have PCPCombine output data to individual member directories. +FCST_PCP_COMBINE_INPUT_TEMPLATE = {custom?fmt=%s}/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = {custom?fmt=%s}/metprd/pcp_combine/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a06h + +# Input and output template for obs pcp-combine files +OBS_PCP_COMBINE_INPUT_TEMPLATE = {OBS_PCP_COMBINE_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a06h + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = membegin_end_incr(1,{ENV[NUM_ENS_MEMBERS]},1,{ENV[NUM_PAD]})/metprd/pcp_combine/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a06h + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_TEMPLATE} + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.ensgrid_APCP_06h.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_APCP24h.conf b/ush/templates/parm/metplus/EnsembleStat_APCP24h.conf new file mode 100644 index 0000000000..c3ed6a3a99 --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_APCP24h.conf @@ -0,0 +1,297 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = PcpCombine, EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# Loop through ensmeble members for making precip buckets +PCP_COMBINE_CUSTOM_LOOP_LIST = membegin_end_incr(1,{ENV[NUM_ENS_MEMBERS]},1,{ENV[NUM_PAD]}) + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB + +ENSEMBLE_STAT_DESC = NA ;; not in other file + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = True +OBS_PCP_COMBINE_RUN = True + +# Mode of pcp_combine to use (SUM, ADD, SUBTRACT) +FCST_PCP_COMBINE_METHOD = ADD +OBS_PCP_COMBINE_METHOD = ADD + +FCST_PCP_COMBINE_CONSTANT_INIT = True + +# Accumulation interval available in forecast data +FCST_PCP_COMBINE_INPUT_ACCUMS = 01 +FCST_PCP_COMBINE_OUTPUT_ACCUM = 24 + +# Accumulation interval available in observation data +OBS_PCP_COMBINE_INPUT_ACCUMS = 01 +OBS_PCP_COMBINE_OUTPUT_ACCUM = 24 + +# If 'bucket' output already exists, skip the PcpCombine step for the data +PCP_COMBINE_SKIP_IF_OUTPUT_EXISTS = True + +# Forecast data description variables +FCST_PCP_COMBINE_INPUT_DATATYPE = GRIB +FCST_IS_PROB = false + +#ENSEMBLE_STAT_DESC = # not in other file + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +#LOG_ENSEMBLE_STAT_VERBOSITY = 2 + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = 0 +OBS_ENSEMBLE_STAT_WINDOW_END = 0 + +OBS_FILE_WINDOW_BEGIN = 0 +OBS_FILE_WINDOW_END = 0 + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_APCP_24h_{OBTYPE} + +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = {MET_BASE}/table_files/obs_error_table.txt + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = FCST +ENSEMBLE_STAT_REGRID_METHOD = BUDGET +ENSEMBLE_STAT_REGRID_WIDTH = 2 +ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = + +ENSEMBLE_STAT_DUPLICATE_FLAG = UNIQUE +ENSEMBLE_STAT_SKIP_CONST = TRUE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = TRUE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = APCP +ENS_VAR1_LEVELS = A24 +ENS_VAR1_THRESH = gt0.0,ge6.350,ge12.700,ge25.400 + +# Forecast Variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION +FCST_VAR1_NAME = APCP +FCST_VAR1_LEVELS = A24 + +# FIGURE OUT WHAT BIN SIZE SHOULD BE +FCST_VAR1_OPTIONS = ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + + +# Observation Variables and levels as specified in the obs field dictionary +# of the MET configuration file. Specify as OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION +OBS_VAR1_NAME = {FCST_VAR1_NAME} +OBS_VAR1_LEVELS = {FCST_VAR1_LEVELS} + +OBS_VAR1_OPTIONS = {FCST_VAR1_OPTIONS} + +[dir] +# Input and output data directories +INPUT_BASE = {ENV[EXPTDIR]}/{ENV[CDATE]} +OUTPUT_BASE = {ENV[EXPTDIR]} + +# Input and output fcst data directories for pcp-combine +FCST_PCP_COMBINE_INPUT_DIR = {INPUT_BASE} +FCST_PCP_COMBINE_OUTPUT_DIR = {INPUT_BASE} + +# Input and output obs data directories for pcp-combine +OBS_PCP_COMBINE_INPUT_DIR = {ENV[OBS_DIR]} +OBS_PCP_COMBINE_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {FCST_PCP_COMBINE_OUTPUT_DIR} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = {OBS_PCP_COMBINE_OUTPUT_DIR} + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {OUTPUT_BASE}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_01 + + +[filename_templates] +# Need to have PCPCombine output data to individual member directories. +FCST_PCP_COMBINE_INPUT_TEMPLATE = {custom?fmt=%s}/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = {custom?fmt=%s}/metprd/pcp_combine/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a24h + +# Input and output template for obs pcp-combine files +OBS_PCP_COMBINE_INPUT_TEMPLATE = {OBS_PCP_COMBINE_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a24h + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = membegin_end_incr(1,{ENV[NUM_ENS_MEMBERS]},1,{ENV[NUM_PAD]})/metprd/pcp_combine/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a24h + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_TEMPLATE} + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.ensgrid_APCP_24h.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_REFC.conf b/ush/templates/parm/metplus/EnsembleStat_REFC.conf new file mode 100644 index 0000000000..123af0f0a2 --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_REFC.conf @@ -0,0 +1,250 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} + +ENSEMBLE_STAT_DESC = NA ;; not in other file + +# Name to identify observation data in output +OBTYPE = MRMS + +#ENSEMBLE_STAT_DESC = # not in other file + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +#LOG_ENSEMBLE_STAT_VERBOSITY = 2 + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = 0 +OBS_ENSEMBLE_STAT_WINDOW_END = 0 + +OBS_FILE_WINDOW_BEGIN = -300 +OBS_FILE_WINDOW_END = 300 + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_REFC_{OBTYPE} + +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = FCST +ENSEMBLE_STAT_REGRID_METHOD = BUDGET +ENSEMBLE_STAT_REGRID_WIDTH = 2 +ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = ADPSFC + +ENSEMBLE_STAT_DUPLICATE_FLAG = NONE +ENSEMBLE_STAT_SKIP_CONST = TRUE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = FALSE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = FULL + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = REFC +ENS_VAR1_LEVELS = L0 +ENS_VAR1_THRESH = ge20, ge30, ge40, ge50 + +# Forecast Variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION +FCST_VAR1_NAME = REFC +FCST_VAR1_LEVELS = L0 + +FCST_VAR1_OPTIONS = ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + +# Observation Variables and levels as specified in the obs field dictionary +# of the MET configuration file. Specify as OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION +OBS_VAR1_NAME = MergedReflectivityQCComposite +OBS_VAR1_LEVELS = Z500 + +OBS_VAR1_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + +[dir] +# Input and output data directories +INPUT_BASE = {ENV[EXPTDIR]}/{ENV[CDATE]} +OUTPUT_BASE = {ENV[EXPTDIR]} + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {INPUT_BASE} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {OUTPUT_BASE}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/REFC + + +[filename_templates] + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = mem*/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/MergedReflectivityQCComposite_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.ensgrid_REFC.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_RETOP.conf b/ush/templates/parm/metplus/EnsembleStat_RETOP.conf new file mode 100644 index 0000000000..4fcbc9bcf2 --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_RETOP.conf @@ -0,0 +1,253 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} + +ENSEMBLE_STAT_DESC = NA ;; not in other file + +# Name to identify observation data in output +OBTYPE = MRMS + +#ENSEMBLE_STAT_DESC = # not in other file + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +#LOG_ENSEMBLE_STAT_VERBOSITY = 2 + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = 0 +OBS_ENSEMBLE_STAT_WINDOW_END = 0 + +OBS_FILE_WINDOW_BEGIN = -300 +OBS_FILE_WINDOW_END = 300 + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_RETOP_{OBTYPE} + +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = FCST +ENSEMBLE_STAT_REGRID_METHOD = BUDGET +ENSEMBLE_STAT_REGRID_WIDTH = 2 +ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = ADPSFC + +ENSEMBLE_STAT_DUPLICATE_FLAG = NONE +ENSEMBLE_STAT_SKIP_CONST = TRUE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = FALSE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = FULL + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = RETOP +ENS_VAR1_LEVELS = L0 +ENS_VAR1_THRESH = ge20, ge30, ge40, ge50 +# convert from meters to kilofeet: M_to_KFT(x) = x * 3.28084 * 0.001; +ENS_VAR1_OPTIONS = convert(x) = x * 3.28084 * 0.001; + +# Forecast Variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION +FCST_VAR1_NAME = RETOP +FCST_VAR1_LEVELS = L0 +# convert from meters to kilofeet: M_to_KFT(x) = x * 3.28084 * 0.001; +FCST_VAR1_OPTIONS = convert(x) = x * 3.28084 * 0.001; ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + +# Observation Variables and levels as specified in the obs field dictionary +# of the MET configuration file. Specify as OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION + +OBS_VAR1_NAME = EchoTop18 +OBS_VAR1_LEVELS = Z500 +# convert from kilometers to kilofeet: KM_to_KFT(x) = x * 3280.84 * 0.001; +OBS_VAR1_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; convert(x) = x * 3280.84 * 0.001; ens_ssvar_bin_size = 50.0; ens_phist_bin_size = 0.05; + +[dir] +# Input and output data directories +INPUT_BASE = {ENV[EXPTDIR]}/{ENV[CDATE]} +OUTPUT_BASE = {ENV[EXPTDIR]} + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {INPUT_BASE} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {OUTPUT_BASE}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/RETOP + + +[filename_templates] + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = mem*/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/EchoTop_18_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.ensgrid_RETOP.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_conus_sfc.conf b/ush/templates/parm/metplus/EnsembleStat_conus_sfc.conf new file mode 100644 index 0000000000..9f93af38f6 --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_conus_sfc.conf @@ -0,0 +1,354 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = PB2NC, EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = {ENV[fhr_list]} + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} + +ENSEMBLE_STAT_DESC = NA + +# Name to identify observation data in output +OBTYPE = NDAS + +#ENSEMBLE_STAT_DESC = + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +LOG_ENSEMBLE_STAT_VERBOSITY = 3 + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# False for no time summary, True otherwise +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 ;; start time of time summary in HHMMSS format +PB2NC_TIME_SUMMARY_END = 235959 ;; end time of time summary in HHMMSS format +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 ;; a list of the statistics to summarize + +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_ENSEMBLE_STAT_WINDOW_END = {OBS_WINDOW_END} + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_ADPSFC_{OBTYPE} + +# MET Configuration files for pb2nc and ensemble_stat +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +ENSEMBLE_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#ENSEMBLE_STAT_OBS_QUALITY_EXC = + +# if True, pb2nc will skip processing a file if the output already exists +# used to speed up runs and reduce redundancy +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = {MET_BASE}/table_files/obs_error_table.txt + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = NONE +#ENSEMBLE_STAT_REGRID_METHOD = BILIN +#ENSEMBLE_STAT_REGRID_WIDTH = 2 +#ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +#ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = ADPSFC + +ENSEMBLE_STAT_DUPLICATE_FLAG = NONE +ENSEMBLE_STAT_SKIP_CONST = FALSE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = FALSE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +#ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +#ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +#ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = TMP +ENS_VAR1_LEVELS = Z02 +ENS_VAR1_THRESH = >=268, >=273, >=278, >=293, >=298, >=303 + +ENS_VAR2_NAME = DPT +ENS_VAR2_LEVELS = Z2 +ENS_VAR2_THRESH = >=263, >=268, >=273, >=288, >=293, >=298 + +ENS_VAR3_NAME = WIND +ENS_VAR3_LEVELS = Z10 +ENS_VAR3_THRESH = >=5, >=10, >=15 +ENS_VAR3_OPTIONS = GRIB2_pdt = 0; ;; derive instantaneous 10-m wind from U/V components, overriding max 10-m wind + +ENS_VAR4_NAME = TCDC +ENS_VAR4_LEVELS = L0 +ENS_VAR4_THRESH = <25, >75 +ENS_VAR4_OPTIONS = GRIB_lvl_typ = 200; GRIB2_ipdtmpl_index=[27]; GRIB2_ipdtmpl_val=[255]; interp = { type = [ { method = NEAREST; width = 1; } ]; } + +ENS_VAR5_NAME = VIS +ENS_VAR5_LEVELS = L0 +ENS_VAR5_THRESH = <1609, <8045, >=8045 +ENS_VAR5_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +ENS_VAR6_NAME = HGT +ENS_VAR6_LEVELS = L0 +ENS_VAR6_THRESH = <152, <1520, >=914 +ENS_VAR6_OPTIONS = GRIB_lvl_typ = 215; desc = "CEILING"; + + +# Forecast and observation variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION and OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION + +FCST_VAR1_NAME = TMP +FCST_VAR1_LEVELS = Z2 +FCST_VAR1_THRESH = >=268, >=273, >=278, >=293, >=298, >=303 +OBS_VAR1_NAME = TMP +OBS_VAR1_LEVELS = Z2 +OBS_VAR1_THRESH = >=268, >=273, >=278, >=293, >=298, >=303 +OBS_VAR1_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR2_NAME = DPT +FCST_VAR2_LEVELS = Z2 +FCST_VAR2_THRESH = >=263, >=268, >=273, >=288, >=293, >=298 +OBS_VAR2_NAME = DPT +OBS_VAR2_LEVELS = Z2 +OBS_VAR2_THRESH = >=263, >=268, >=273, >=288, >=293, >=298 +OBS_VAR2_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR3_NAME = WIND +FCST_VAR3_LEVELS = Z10 +FCST_VAR3_THRESH = >=5, >=10, >=15 +FCST_VAR3_OPTIONS = GRIB2_pdt = 0; ;; derive instantaneous 10-m wind from U/V components, overriding max 10-m wind +OBS_VAR3_NAME = WIND +OBS_VAR3_LEVELS = Z10 +OBS_VAR3_THRESH = >=5, >=10, >=15 +OBS_VAR3_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR4_NAME = TCDC +FCST_VAR4_LEVELS = L0 +FCST_VAR4_THRESH = <25, >75 +FCST_VAR4_OPTIONS = GRIB_lvl_typ = 200; GRIB2_ipdtmpl_index=[27]; GRIB2_ipdtmpl_val=[255]; interp = { type = [ { method = NEAREST; width = 1; } ]; } +OBS_VAR4_NAME = TCDC +OBS_VAR4_LEVELS = L0 +OBS_VAR4_THRESH = <25, >75 + +BOTH_VAR5_NAME = VIS +BOTH_VAR5_LEVELS = L0 +BOTH_VAR5_THRESH = <1609, <8045, >=8045 +BOTH_VAR5_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +FCST_VAR6_NAME = HGT +FCST_VAR6_LEVELS = L0 +FCST_VAR6_THRESH = <152, <1520, >=914 +FCST_VAR6_OPTIONS = GRIB_lvl_typ = 215; desc = "CEILING"; +OBS_VAR6_NAME = CEILING +OBS_VAR6_LEVELS = L0 +OBS_VAR6_OPTIONS = GRIB_lvl_typ = 215; interp = { type = [ { method = NEAREST; width = 1; } ]; } +OBS_VAR6_THRESH = <152, <305, >=914 + +[dir] +# Input and output directories for pb2nc +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {ENV[EXPTDIR]}/{ENV[CDATE]} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +OUTPUT_BASE = {ENV[EXPTDIR]} +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {ENV[EXPTDIR]}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/conus_sfc + + +[filename_templates] + +# Input and output templates for pb2nc +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = + mem*/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = {PB2NC_OUTPUT_TEMPLATE} + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Template for where ensemble-stat output is written +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_sfc + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.conus_surface.conf + diff --git a/ush/templates/parm/metplus/EnsembleStat_upper_air.conf b/ush/templates/parm/metplus/EnsembleStat_upper_air.conf new file mode 100644 index 0000000000..c3e24b259d --- /dev/null +++ b/ush/templates/parm/metplus/EnsembleStat_upper_air.conf @@ -0,0 +1,424 @@ +# Ensemble-Stat METplus Configuration + +[config] + +## Configuration-related settings such as the process list, begin and end times, etc. +PROCESS_LIST = PB2NC, EnsembleStat + +# Looping by times: steps through each 'task' in the PROCESS_LIST for each +# defined time, and repeats until all times have been evaluated. +LOOP_ORDER = times + +# LOOP_BY: Set to INIT to loop over initialization times +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +INIT_BEG={ENV[CDATE]} + +# End time for METplus run +INIT_END={ENV[CDATE]} + +# Increment between METplus runs in seconds. Must be >= 60 +INIT_INCREMENT=3600 + +# List of forecast leads to process +LEAD_SEQ = begin_end_incr(0,{ENV[fhr_last]},6) + +# Used in the MET config file for: model, output_prefix +MODEL = {ENV[MODEL]} + +ENSEMBLE_STAT_DESC = NA + +# Name to identify observation data in output +OBTYPE = NDAS + +#ENSEMBLE_STAT_DESC = + +# The MET ensemble_stat logging level +# 0 quiet to 5 loud, Verbosity setting for MET ensemble_stat output, 2 is default. +# This takes precendence over the general LOG_MET_VERBOSITY set in metplus_logging.conf +LOG_ENSEMBLE_STAT_VERBOSITY = 3 + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# False for no time summary, True otherwise +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 ;; start time of time summary in HHMMSS format +PB2NC_TIME_SUMMARY_END = 235959 ;; end time of time summary in HHMMSS format +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 ;; a list of the statistics to summarize + +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +OBS_ENSEMBLE_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_ENSEMBLE_STAT_WINDOW_END = {OBS_WINDOW_END} + +# number of expected members for ensemble. Should correspond with the +# number of items in the list for FCST_ENSEMBLE_STAT_INPUT_TEMPLATE +ENSEMBLE_STAT_N_MEMBERS = {ENV[NUM_ENS_MEMBERS]} + +# ens.ens_thresh value in the MET config file +# threshold for ratio of valid files to expected files to allow app to run +ENSEMBLE_STAT_ENS_THRESH = 0.05 + +# ens.vld_thresh value in the MET config file +ENSEMBLE_STAT_ENS_VLD_THRESH = 1.0 + +ENSEMBLE_STAT_OUTPUT_PREFIX = {MODEL}_ADPUPA_{OBTYPE} + +# MET Configuration files for pb2nc and ensemble_stat +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped +ENSEMBLE_STAT_CONFIG_FILE = {PARM_BASE}/met_config/EnsembleStatConfig_wrapped + +ENSEMBLE_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#ENSEMBLE_STAT_OBS_QUALITY_EXC = + +# if True, pb2nc will skip processing a file if the output already exists +# used to speed up runs and reduce redundancy +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# ENSEMBLE_STAT_MET_OBS_ERR_TABLE is not required. +# If the variable is not defined, or the value is not set +# than the MET default is used. +ENSEMBLE_STAT_MET_OBS_ERR_TABLE = {MET_BASE}/table_files/obs_error_table.txt + + +# Used in the MET config file for: regrid to_grid field +ENSEMBLE_STAT_REGRID_TO_GRID = NONE +#ENSEMBLE_STAT_REGRID_METHOD = BILIN +#ENSEMBLE_STAT_REGRID_WIDTH = 2 +#ENSEMBLE_STAT_REGRID_VLD_THRESH = 0.5 +#ENSEMBLE_STAT_REGRID_SHAPE = SQUARE + +ENSEMBLE_STAT_CENSOR_THRESH = +ENSEMBLE_STAT_CENSOR_VAL = + +#ENSEMBLE_STAT_NBRHD_PROB_WIDTH = 5 +#ENSEMBLE_STAT_NBRHD_PROB_SHAPE = CIRCLE +#ENSEMBLE_STAT_NBRHD_PROB_VLD_THRESH = 0.0 + +#ENSEMBLE_STAT_NMEP_SMOOTH_VLD_THRESH = 0.0 +#ENSEMBLE_STAT_NMEP_SMOOTH_SHAPE = CIRCLE +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_DX = 81.27 +#ENSEMBLE_STAT_NMEP_SMOOTH_GAUSSIAN_RADIUS = 120 +#ENSEMBLE_STAT_NMEP_SMOOTH_METHOD = GAUSSIAN +#ENSEMBLE_STAT_NMEP_SMOOTH_WIDTH = 1 + +ENSEMBLE_STAT_MESSAGE_TYPE = ADPUPA + +ENSEMBLE_STAT_DUPLICATE_FLAG = NONE +ENSEMBLE_STAT_SKIP_CONST = FALSE + +ENSEMBLE_STAT_OBS_ERROR_FLAG = FALSE + +ENSEMBLE_STAT_ENS_SSVAR_BIN_SIZE = 1.0 +ENSEMBLE_STAT_ENS_PHIST_BIN_SIZE = 0.05 + +#ENSEMBLE_STAT_CLIMO_MEAN_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_MEAN_FIELD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_MEAN_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_MEAN_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_MEAN_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_MEAN_HOUR_INTERVAL = 6 + +#ENSEMBLE_STAT_CLIMO_STDEV_FILE_NAME = +#ENSEMBLE_STAT_CLIMO_STDEV_FIELD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_WIDTH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#ENSEMBLE_STAT_CLIMO_STDEV_REGRID_SHAPE = +#ENSEMBLE_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#ENSEMBLE_STAT_CLIMO_STDEV_MATCH_MONTH = +#ENSEMBLE_STAT_CLIMO_STDEV_DAY_INTERVAL = 31 +#ENSEMBLE_STAT_CLIMO_STDEV_HOUR_INTERVAL = 6 + + +#ENSEMBLE_STAT_CLIMO_CDF_BINS = 1 +#ENSEMBLE_STAT_CLIMO_CDF_CENTER_BINS = False +#ENSEMBLE_STAT_CLIMO_CDF_WRITE_BINS = True + +ENSEMBLE_STAT_MASK_GRID = + +ENSEMBLE_STAT_CI_ALPHA = 0.05 + +ENSEMBLE_STAT_INTERP_FIELD = BOTH +ENSEMBLE_STAT_INTERP_VLD_THRESH = 1.0 +ENSEMBLE_STAT_INTERP_SHAPE = SQUARE +ENSEMBLE_STAT_INTERP_METHOD = NEAREST +ENSEMBLE_STAT_INTERP_WIDTH = 1 + +ENSEMBLE_STAT_OUTPUT_FLAG_ECNT = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RPS = NONE +ENSEMBLE_STAT_OUTPUT_FLAG_RHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_PHIST = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_ORANK = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_SSVAR = STAT +ENSEMBLE_STAT_OUTPUT_FLAG_RELP = STAT + +ENSEMBLE_STAT_ENSEMBLE_FLAG_LATLON = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MEAN = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_STDEV = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MINUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_PLUS = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MIN = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_MAX = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANGE = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_VLD_COUNT = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_FREQUENCY = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_NMEP = FALSE +ENSEMBLE_STAT_ENSEMBLE_FLAG_RANK = TRUE +ENSEMBLE_STAT_ENSEMBLE_FLAG_WEIGHT = FALSE + +# Ensemble Variables and levels as specified in the ens field dictionary +# of the MET configuration file. Specify as ENS_VARn_NAME, ENS_VARn_LEVELS, +# (optional) ENS_VARn_OPTION +ENS_VAR1_NAME = TMP +ENS_VAR1_LEVELS = P850 +ENS_VAR1_THRESH = >=288, >=293, >=298 + +ENS_VAR2_NAME = TMP +ENS_VAR2_LEVELS = P700 +ENS_VAR2_THRESH = >=273, >=278, >=283 + +ENS_VAR3_NAME = TMP +ENS_VAR3_LEVELS = P500 +ENS_VAR3_THRESH = >=258, >=263, >=268 + +ENS_VAR4_NAME = DPT +ENS_VAR4_LEVELS = P850 +ENS_VAR4_THRESH = >=273, >=278, >=283 + +ENS_VAR5_NAME = DPT +ENS_VAR5_LEVELS = P700 +ENS_VAR5_THRESH = >=263, >=268, >=273 + +ENS_VAR6_NAME = WIND +ENS_VAR6_LEVELS = P850 +ENS_VAR6_THRESH = >=5, >=10, >=15 + +ENS_VAR7_NAME = WIND +ENS_VAR7_LEVELS = P700 +ENS_VAR7_THRESH = >=10, >=15, >=20 + +ENS_VAR8_NAME = WIND +ENS_VAR8_LEVELS = P500 +ENS_VAR8_THRESH = >=15, >=21, >=26 + +ENS_VAR9_NAME = WIND +ENS_VAR9_LEVELS = P250 +ENS_VAR9_THRESH = >=26, >=31, >=36, >=46, >=62 + +ENS_VAR10_NAME = HGT +ENS_VAR10_LEVELS = P500 +ENS_VAR10_THRESH = >=5400, >=5600, >=5880 + +ENS_VAR11_NAME = CAPE +ENS_VAR11_LEVELS = L0 +ENS_VAR11_OPTIONS = cnt_thresh = [ >0 ]; +ENS_VAR11_THRESH = <=1000, >1000&&<2500, >2500&&<4000, >2500 + +ENS_VAR12_NAME = HPBL +ENS_VAR12_LEVELS = Z0 +ENS_VAR12_THRESH = <500, <1500, >1500 + +# Forecast and observation variables and levels as specified in the fcst field dictionary +# of the MET configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION and OBS_VARn_NAME, OBS_VARn_LEVELS, +# (optional) OBS_VARn_OPTION + +FCST_VAR1_NAME = TMP +FCST_VAR1_LEVELS = P850 +FCST_VAR1_THRESH = >=288, >=293, >=298 +OBS_VAR1_NAME = TMP +OBS_VAR1_LEVELS = P850 +OBS_VAR1_THRESH = >=288, >=293, >=298 +OBS_VAR1_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR2_NAME = TMP +FCST_VAR2_LEVELS = P700 +FCST_VAR2_THRESH = >=273, >=278, >=283 +OBS_VAR2_NAME = TMP +OBS_VAR2_LEVELS = P700 +OBS_VAR2_THRESH = >=273, >=278, >=283 +OBS_VAR2_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR3_NAME = TMP +FCST_VAR3_LEVELS = P500 +FCST_VAR3_THRESH = >=258, >=263, >=268 +OBS_VAR3_NAME = TMP +OBS_VAR3_LEVELS = P500 +OBS_VAR3_THRESH = >=258, >=263, >=268 +OBS_VAR3_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR4_NAME = DPT +FCST_VAR4_LEVELS = P850 +FCST_VAR4_THRESH = >=273, >=278, >=283 +OBS_VAR4_NAME = DPT +OBS_VAR4_LEVELS = P850 +OBS_VAR4_THRESH = >=273, >=278, >=283 +OBS_VAR4_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR5_NAME = DPT +FCST_VAR5_LEVELS = P700 +FCST_VAR5_THRESH = >=263, >=286, >=273 +OBS_VAR5_NAME = DPT +OBS_VAR5_LEVELS = P700 +OBS_VAR5_THRESH = >=263, >=286, >=273 +OBS_VAR5_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR6_NAME = WIND +FCST_VAR6_LEVELS = P850 +FCST_VAR6_THRESH = >=5, >=10, >=15 +OBS_VAR6_NAME = WIND +OBS_VAR6_LEVELS = P850 +OBS_VAR6_THRESH = >=5, >=10, >=15 +OBS_VAR6_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR7_NAME = WIND +FCST_VAR7_LEVELS = P700 +FCST_VAR7_THRESH = >=10, >=15, >=20 +OBS_VAR7_NAME = WIND +OBS_VAR7_LEVELS = P700 +OBSVAR7_THRESH = >=10, >=15, >=20 +OBS_VAR7_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR8_NAME = WIND +FCST_VAR8_LEVELS = P500 +FCST_VAR8_THRESH = >=15, >=21, >=26 +OBS_VAR8_NAME = WIND +OBS_VAR8_LEVELS = P500 +OBS_VAR8_THRESH = >=15, >=21, >=26 +OBS_VAR8_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR9_NAME = WIND +FCST_VAR9_LEVELS = P250 +FCST_VAR9_THRESH = >=26, >=31, >=36, >=46, >=62 +OBS_VAR9_NAME = WIND +OBS_VAR9_LEVELS = P250 +OBS_VAR9_THRESH = >=26, >=31, >=36, >=46, >=62 +OBS_VAR9_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR10_NAME = HGT +FCST_VAR10_LEVELS = P500 +FCST_VAR10_THRESH = >=5400, >=5600, >=5880 +OBS_VAR10_NAME = HGT +OBS_VAR10_LEVELS = P500 +OBS_VAR10_THRESH = >=5400, >=5600, >=5880 +OBS_VAR10_OPTIONS = obs_error = { flag = TRUE; dist_type = NONE; dist_parm = []; inst_bias_scale = 1.0; inst_bias_offset = 0.0; min = NA; max = NA; } + +FCST_VAR11_NAME = CAPE +FCST_VAR11_LEVELS = L0 +FCST_VAR11_OPTIONS = cnt_thresh = [ >0 ]; +FCST_VAR11_THRESH = <=1000, >1000&&<2500, >=2500&&<4000, >=2500 +OBS_VAR11_NAME = CAPE +OBS_VAR11_LEVELS = L0-100000 +OBS_VAR11_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR11_THRESH = <=1000, >1000&&<2500, >=2500&&<4000, >=2500 + +FCST_VAR12_NAME = HPBL +FCST_VAR12_LEVELS = Z0 +FCST_VAR12_THRESH = <500, <1500, >1500 +OBS_VAR12_NAME = PBL +OBS_VAR12_LEVELS = L0 +OBS_VAR12_OPTIONS = desc = "TKE"; +OBS_VAR12_THRESH = <500, <1500, >1500 + +[dir] +# Input and output directories for pb2nc +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +# Forecast model input directory for ensemble_stat +FCST_ENSEMBLE_STAT_INPUT_DIR = {ENV[EXPTDIR]}/{ENV[CDATE]} + +# Point observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_POINT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# Grid observation input dir for ensemble_stat +OBS_ENSEMBLE_STAT_GRID_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to EnsembleStat +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR = + +# output directory for ensemble_stat +OUTPUT_BASE = {ENV[EXPTDIR]} +ENSEMBLE_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +# directory containing log files +LOG_DIR = {ENV[EXPTDIR]}/log + +# directory for staging data +STAGING_DIR = {OUTPUT_BASE}/stage/upper_air + + +[filename_templates] + +# Input and output templates for pb2nc +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# FCST_ENSEMBLE_STAT_INPUT_TEMPLATE - comma separated list of ensemble members +# or a single line, - filename wildcard characters may be used, ? or *. + +FCST_ENSEMBLE_STAT_INPUT_TEMPLATE = + mem*/postprd/{ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for point observations. +# Example precip24_2010010112.nc +OBS_ENSEMBLE_STAT_POINT_INPUT_TEMPLATE = {PB2NC_OUTPUT_TEMPLATE} + +# Template to look for gridded observations. +# Example ST4.2010010112.24h +OBS_ENSEMBLE_STAT_GRID_INPUT_TEMPLATE = + +ENSEMBLE_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to EnsembleStat relative to ENSEMBLE_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +ENSEMBLE_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Template for where ensemble-stat output is written +ENSEMBLE_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_upa + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat/metplus_final.upper_air.conf + diff --git a/ush/templates/parm/metplus/GridStat_APCP01h.conf b/ush/templates/parm/metplus/GridStat_APCP01h.conf new file mode 100644 index 0000000000..2c6aac65aa --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP01h.conf @@ -0,0 +1,274 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {ENV[EXPTDIR]}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/grid_stat/metplus_final.APCP_01h.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A01 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge0.254,ge0.508,ge1.27,ge2.54 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A01 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {MODEL}_{CURRENT_FCST_NAME}_{ENV[acc]}_{OBTYPE} + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_01h + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = metprd/grid_stat + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP01h_mean.conf b/ush/templates/parm/metplus/GridStat_APCP01h_mean.conf new file mode 100644 index 0000000000..26740647e6 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP01h_mean.conf @@ -0,0 +1,274 @@ +# Ensemble Mean GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.APCP01.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_mean +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP_01_A01_ENS_MEAN + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A01 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge0.254,ge0.508,ge2.54 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A01 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_mean + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_01h_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP01h_prob.conf b/ush/templates/parm/metplus/GridStat_APCP01h_prob.conf new file mode 100644 index 0000000000..d507983f2c --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP01h_prob.conf @@ -0,0 +1,285 @@ +# Ensemble Prob GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.APCP01.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_prob +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variables +# thresholds in mm, equal to >0, .01",.05",.10" +FCST_VAR1_NAME = APCP_01_A01_ENS_FREQ_gt0.0 +FCST_VAR1_LEVELS = A01 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = APCP +OBS_VAR1_LEVELS = A01 +OBS_VAR1_THRESH = >0.0 + +FCST_VAR2_NAME = APCP_01_A01_ENS_FREQ_ge0.254 +FCST_VAR2_LEVELS = A01 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = APCP +OBS_VAR2_LEVELS = A01 +OBS_VAR2_THRESH = >=0.254 + +FCST_VAR3_NAME = APCP_01_A01_ENS_FREQ_ge0.508 +FCST_VAR3_LEVELS = A01 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = APCP +OBS_VAR3_LEVELS = A01 +OBS_VAR3_THRESH = >=0.508 + +FCST_VAR4_NAME = APCP_01_A01_ENS_FREQ_ge2.54 +FCST_VAR4_LEVELS = A01 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = APCP +OBS_VAR4_LEVELS = A01 +OBS_VAR4_THRESH = >=2.54 + +#FCST_GRID_STAT_FILE_TYPE = + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_prob + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = NONE +GRID_STAT_OUTPUT_FLAG_CTC = NONE +GRID_STAT_OUTPUT_FLAG_CTS = NONE +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = NONE +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +GRID_STAT_OUTPUT_FLAG_PCT = STAT +GRID_STAT_OUTPUT_FLAG_PSTD = STAT +GRID_STAT_OUTPUT_FLAG_PJC = STAT +GRID_STAT_OUTPUT_FLAG_PRC = STAT +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTS = NONE +GRID_STAT_OUTPUT_FLAG_NBRCNT = NONE +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_01h_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP03h.conf b/ush/templates/parm/metplus/GridStat_APCP03h.conf new file mode 100644 index 0000000000..c017806171 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP03h.conf @@ -0,0 +1,308 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = PcpCombine, GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +# # If True, run PCPCombine on forecast data +# observation equivalent OBS_PCP_COMBINE_RUN also exists +FCST_PCP_COMBINE_RUN = True +OBS_PCP_COMBINE_RUN = True + +# mode of PCPCombine to use (SUM, ADD, SUBTRACT, DERIVE, or CUSTOM) +FCST_PCP_COMBINE_METHOD = ADD +OBS_PCP_COMBINE_METHOD = ADD + +# Accumulation interval available in forecast data +FCST_PCP_COMBINE_INPUT_ACCUMS = 01 +FCST_PCP_COMBINE_OUTPUT_ACCUM = 03 + +# Accumulation interval available in obs data +OBS_PCP_COMBINE_INPUT_ACCUMS = 01 +OBS_PCP_COMBINE_OUTPUT_ACCUM = 03 + +# If 'bucket' output already exists, skip the PcpCombine step for the data +PCP_COMBINE_SKIP_IF_OUTPUT_EXISTS = True + +# maximum forecast lead to allow when searching for model data to use in PCPCombine +# Default is a very large time (4000 years) so setting this to a valid maximum value can +# speed up execution time of numerous runs +FCST_PCP_COMBINE_MAX_FORECAST = 2d + +# keep initialization time constant +FCST_PCP_COMBINE_CONSTANT_INIT = True + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {ENV[EXPTDIR]}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/grid_stat/metplus_final.APCP_03h.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB +FCST_PCP_COMBINE_INPUT_DATATYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A03 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge0.254,ge0.508,ge1.27,ge2.54,ge3.810,ge6.350 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A03 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {MODEL}_{CURRENT_FCST_NAME}_{ENV[acc]}_{OBTYPE} + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to PCPCombine and GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_PCP_COMBINE_INPUT_DIR = {INPUT_BASE} +FCST_GRID_STAT_INPUT_DIR = {FCST_PCP_COMBINE_OUTPUT_DIR} + +# directory containing observation input to PCPCombine and GridStat +OBS_PCP_COMBINE_INPUT_DIR = {ENV[OBS_DIR]} +OBS_GRID_STAT_INPUT_DIR = {OBS_PCP_COMBINE_OUTPUT_DIR} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from PCPCombine and GridStat +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +FCST_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/metprd/pcp_combine +OBS_PCP_COMBINE_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_03h + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to PCPCombine and GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_PCP_COMBINE_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 +FCST_GRID_STAT_INPUT_TEMPLATE = {FCST_PCP_COMBINE_OUTPUT_TEMPLATE} + +# Template to look for observation input to PCPCombine and GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_PCP_COMBINE_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_TEMPLATE} + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from PCPCombine and GridStat +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a{level?fmt=%HH}h +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a{level?fmt=%HH}h +GRID_STAT_OUTPUT_TEMPLATE = metprd/grid_stat + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP03h_mean.conf b/ush/templates/parm/metplus/GridStat_APCP03h_mean.conf new file mode 100644 index 0000000000..d912c7f8d9 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP03h_mean.conf @@ -0,0 +1,274 @@ +# Ensemble Mean GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.APCP03.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_mean +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP_A3_ENS_MEAN + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A3 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge0.508,ge2.54,ge6.350 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A3 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_mean + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_03h_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_GRID_STAT_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a03h + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP03h_prob.conf b/ush/templates/parm/metplus/GridStat_APCP03h_prob.conf new file mode 100644 index 0000000000..30cd5ad102 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP03h_prob.conf @@ -0,0 +1,284 @@ +# Ensemble Prob GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.APCP03.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_prob +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variables +FCST_VAR1_NAME = APCP_A3_ENS_FREQ_gt0.0 +FCST_VAR1_LEVELS = A03 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = APCP +OBS_VAR1_LEVELS = A03 +OBS_VAR1_THRESH = >0.0 + +FCST_VAR2_NAME = APCP_A3_ENS_FREQ_ge0.508 +FCST_VAR2_LEVELS = A03 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = APCP +OBS_VAR2_LEVELS = A03 +OBS_VAR2_THRESH = >=0.508 + +FCST_VAR3_NAME = APCP_A3_ENS_FREQ_ge2.54 +FCST_VAR3_LEVELS = A03 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = APCP +OBS_VAR3_LEVELS = A03 +OBS_VAR3_THRESH = >=2.54 + +FCST_VAR4_NAME = APCP_A3_ENS_FREQ_ge6.350 +FCST_VAR4_LEVELS = A03 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = APCP +OBS_VAR4_LEVELS = A03 +OBS_VAR4_THRESH = >=6.350 + +#FCST_GRID_STAT_FILE_TYPE = + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_prob + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = NONE +GRID_STAT_OUTPUT_FLAG_CTC = NONE +GRID_STAT_OUTPUT_FLAG_CTS = NONE +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = NONE +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +GRID_STAT_OUTPUT_FLAG_PCT = STAT +GRID_STAT_OUTPUT_FLAG_PSTD = STAT +GRID_STAT_OUTPUT_FLAG_PJC = STAT +GRID_STAT_OUTPUT_FLAG_PRC = STAT +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTS = NONE +GRID_STAT_OUTPUT_FLAG_NBRCNT = NONE +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_03h_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_GRID_STAT_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a03h + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP06h.conf b/ush/templates/parm/metplus/GridStat_APCP06h.conf new file mode 100644 index 0000000000..0e4d66531e --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP06h.conf @@ -0,0 +1,308 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = PcpCombine, GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +# # If True, run PCPCombine on forecast data +# observation equivalent OBS_PCP_COMBINE_RUN also exists +FCST_PCP_COMBINE_RUN = True +OBS_PCP_COMBINE_RUN = True + +# mode of PCPCombine to use (SUM, ADD, SUBTRACT, DERIVE, or CUSTOM) +FCST_PCP_COMBINE_METHOD = ADD +OBS_PCP_COMBINE_METHOD = ADD + +# Accumulation interval available in forecast data +FCST_PCP_COMBINE_INPUT_ACCUMS = 01 +FCST_PCP_COMBINE_OUTPUT_ACCUM = 06 + +# Accumulation interval available in obs data +OBS_PCP_COMBINE_INPUT_ACCUMS = 01 +OBS_PCP_COMBINE_OUTPUT_ACCUM = 06 + +# If 'bucket' output already exists, skip the PcpCombine step for the data +PCP_COMBINE_SKIP_IF_OUTPUT_EXISTS = True + +# maximum forecast lead to allow when searching for model data to use in PCPCombine +# Default is a very large time (4000 years) so setting this to a valid maximum value can +# speed up execution time of numerous runs +FCST_PCP_COMBINE_MAX_FORECAST = 2d + +# keep initialization time constant +FCST_PCP_COMBINE_CONSTANT_INIT = True + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {ENV[EXPTDIR]}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/grid_stat/metplus_final.APCP_06h.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB +FCST_PCP_COMBINE_INPUT_DATATYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP + +# List of levels to evaluate for forecast variable 1 +# A06 = 6 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A06 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge0.254,ge0.508,ge1.27,ge2.54,ge3.810,ge6.350,ge8.890,ge12.700 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A06 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {MODEL}_{CURRENT_FCST_NAME}_{ENV[acc]}_{OBTYPE} + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to PCPCombine and GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_PCP_COMBINE_INPUT_DIR = {INPUT_BASE} +FCST_GRID_STAT_INPUT_DIR = {FCST_PCP_COMBINE_OUTPUT_DIR} + +# directory containing observation input to PCPCombine and GridStat +OBS_PCP_COMBINE_INPUT_DIR = {ENV[OBS_DIR]} +OBS_GRID_STAT_INPUT_DIR = {OBS_PCP_COMBINE_OUTPUT_DIR} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from PCPCombine and GridStat +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +FCST_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/metprd/pcp_combine +OBS_PCP_COMBINE_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_06h + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to PCPCombine and GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_PCP_COMBINE_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 +FCST_GRID_STAT_INPUT_TEMPLATE = {FCST_PCP_COMBINE_OUTPUT_TEMPLATE} + +# Template to look for observation input to PCPCombine and GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_PCP_COMBINE_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_TEMPLATE} + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from PCPCombine and GridStat +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a{level?fmt=%HH}h +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a{level?fmt=%HH}h +GRID_STAT_OUTPUT_TEMPLATE = metprd/grid_stat + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP06h_mean.conf b/ush/templates/parm/metplus/GridStat_APCP06h_mean.conf new file mode 100644 index 0000000000..264321eef3 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP06h_mean.conf @@ -0,0 +1,274 @@ +# Ensemble Mean GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.APCP06.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_mean +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP_A6_ENS_MEAN + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A06 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge2.54,ge6.350,ge12.700 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A06 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_mean + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_06h_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_GRID_STAT_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a06h + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP06h_prob.conf b/ush/templates/parm/metplus/GridStat_APCP06h_prob.conf new file mode 100644 index 0000000000..0bfdf4eaa9 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP06h_prob.conf @@ -0,0 +1,284 @@ +# Ensemble Prob GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.APCP06.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_prob +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variables +FCST_VAR1_NAME = APCP_A6_ENS_FREQ_gt0.0 +FCST_VAR1_LEVELS = A06 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = APCP +OBS_VAR1_LEVELS = A06 +OBS_VAR1_THRESH = >0.0 + +FCST_VAR2_NAME = APCP_A6_ENS_FREQ_ge2.54 +FCST_VAR2_LEVELS = A06 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = APCP +OBS_VAR2_LEVELS = A06 +OBS_VAR2_THRESH = >=2.54 + +FCST_VAR3_NAME = APCP_A6_ENS_FREQ_ge6.350 +FCST_VAR3_LEVELS = A06 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = APCP +OBS_VAR3_LEVELS = A06 +OBS_VAR3_THRESH = >=6.350 + +FCST_VAR4_NAME = APCP_A6_ENS_FREQ_ge12.700 +FCST_VAR4_LEVELS = A06 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = APCP +OBS_VAR4_LEVELS = A06 +OBS_VAR4_THRESH = >=12.700 + +#FCST_GRID_STAT_FILE_TYPE = + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_prob + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = NONE +GRID_STAT_OUTPUT_FLAG_CTC = NONE +GRID_STAT_OUTPUT_FLAG_CTS = NONE +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = NONE +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +GRID_STAT_OUTPUT_FLAG_PCT = STAT +GRID_STAT_OUTPUT_FLAG_PSTD = STAT +GRID_STAT_OUTPUT_FLAG_PJC = STAT +GRID_STAT_OUTPUT_FLAG_PRC = STAT +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTS = NONE +GRID_STAT_OUTPUT_FLAG_NBRCNT = NONE +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_06h_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_GRID_STAT_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a06h + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP24h.conf b/ush/templates/parm/metplus/GridStat_APCP24h.conf new file mode 100644 index 0000000000..7ae700cf31 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP24h.conf @@ -0,0 +1,308 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = PcpCombine, GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +# # If True, run PCPCombine on forecast data +# observation equivalent OBS_PCP_COMBINE_RUN also exists +FCST_PCP_COMBINE_RUN = True +OBS_PCP_COMBINE_RUN = True + +# mode of PCPCombine to use (SUM, ADD, SUBTRACT, DERIVE, or CUSTOM) +FCST_PCP_COMBINE_METHOD = ADD +OBS_PCP_COMBINE_METHOD = ADD + +# Accumulation interval available in forecast data +FCST_PCP_COMBINE_INPUT_ACCUMS = 01 +FCST_PCP_COMBINE_OUTPUT_ACCUM = 24 + +# Accumulation interval available in obs data +OBS_PCP_COMBINE_INPUT_ACCUMS = 01 +OBS_PCP_COMBINE_OUTPUT_ACCUM = 24 + +# If 'bucket' output already exists, skip the PcpCombine step for the data +PCP_COMBINE_SKIP_IF_OUTPUT_EXISTS = True + +# maximum forecast lead to allow when searching for model data to use in PCPCombine +# Default is a very large time (4000 years) so setting this to a valid maximum value can +# speed up execution time of numerous runs +FCST_PCP_COMBINE_MAX_FORECAST = 2d + +# keep initialization time constant +FCST_PCP_COMBINE_CONSTANT_INIT = True + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {ENV[EXPTDIR]}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/grid_stat/metplus_final.APCP_24h.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB +FCST_PCP_COMBINE_INPUT_DATATYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP + +# List of levels to evaluate for forecast variable 1 +# A24 = 24 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A24 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge0.254,ge0.508,ge1.27,ge2.54,ge3.810,ge6.350,ge8.890,ge12.700,ge25.400 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A24 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {MODEL}_{CURRENT_FCST_NAME}_{ENV[acc]}_{OBTYPE} + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to PCPCombine and GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_PCP_COMBINE_INPUT_DIR = {INPUT_BASE} +FCST_GRID_STAT_INPUT_DIR = {FCST_PCP_COMBINE_OUTPUT_DIR} + +# directory containing observation input to PCPCombine and GridStat +OBS_PCP_COMBINE_INPUT_DIR = {ENV[OBS_DIR]} +OBS_GRID_STAT_INPUT_DIR = {OBS_PCP_COMBINE_OUTPUT_DIR} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from PCPCombine and GridStat +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +FCST_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/metprd/pcp_combine +OBS_PCP_COMBINE_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_24h + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to PCPCombine and GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_PCP_COMBINE_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 +FCST_GRID_STAT_INPUT_TEMPLATE = {FCST_PCP_COMBINE_OUTPUT_TEMPLATE} + +# Template to look for observation input to PCPCombine and GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_PCP_COMBINE_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.01h.hrap.conus.gb2 +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_PCP_COMBINE_OUTPUT_TEMPLATE} + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from PCPCombine and GridStat +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}_a{level?fmt=%HH}h +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = {valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a{level?fmt=%HH}h +GRID_STAT_OUTPUT_TEMPLATE = metprd/grid_stat + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP24h_mean.conf b/ush/templates/parm/metplus/GridStat_APCP24h_mean.conf new file mode 100644 index 0000000000..eaf9d5fb30 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP24h_mean.conf @@ -0,0 +1,274 @@ +# Ensemble Mean GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.APCP24.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_mean +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = APCP_A24_ENS_MEAN + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = A24 + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +#FCST_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 +BOTH_VAR1_THRESH = gt0.0,ge6.350,ge12.700,ge25.400 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = APCP + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = A24 + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_mean + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_24h_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_GRID_STAT_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a24h + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_APCP24h_prob.conf b/ush/templates/parm/metplus/GridStat_APCP24h_prob.conf new file mode 100644 index 0000000000..397abdc42e --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_APCP24h_prob.conf @@ -0,0 +1,284 @@ +# Ensemble Prob GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.APCP24.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +#GRID_STAT_INTERP_FIELD = BOTH +#GRID_STAT_INTERP_VLD_THRESH = 1.0 +#GRID_STAT_INTERP_SHAPE = SQUARE +#GRID_STAT_INTERP_TYPE_METHOD = NEAREST +#GRID_STAT_INTERP_TYPE_WIDTH = 1 + +#GRID_STAT_GRID_WEIGHT_FLAG = + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_prob +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = CCPA +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = [NA]; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variables +FCST_VAR1_NAME = APCP_A24_ENS_FREQ_gt0.0 +FCST_VAR1_LEVELS = A24 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = APCP +OBS_VAR1_LEVELS = A24 +OBS_VAR1_THRESH = >0.0 + +FCST_VAR2_NAME = APCP_A24_ENS_FREQ_ge6.350 +FCST_VAR2_LEVELS = A24 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = APCP +OBS_VAR2_LEVELS = A24 +OBS_VAR2_THRESH = >=6.350 + +FCST_VAR3_NAME = APCP_A24_ENS_FREQ_ge12.700 +FCST_VAR3_LEVELS = A24 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = APCP +OBS_VAR3_LEVELS = A24 +OBS_VAR3_THRESH = >=12.700 + +FCST_VAR4_NAME = APCP_A24_ENS_FREQ_ge25.400 +FCST_VAR4_LEVELS = A24 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = APCP +OBS_VAR4_LEVELS = A24 +OBS_VAR4_THRESH = >=25.400 + +#FCST_GRID_STAT_FILE_TYPE = + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = 0 +OBS_GRID_STAT_FILE_WINDOW_END = 0 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3,5,7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_prob + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = NONE +GRID_STAT_OUTPUT_FLAG_CTC = NONE +GRID_STAT_OUTPUT_FLAG_CTS = NONE +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = NONE +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +GRID_STAT_OUTPUT_FLAG_PCT = STAT +GRID_STAT_OUTPUT_FLAG_PSTD = STAT +GRID_STAT_OUTPUT_FLAG_PJC = STAT +GRID_STAT_OUTPUT_FLAG_PRC = STAT +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTS = NONE +GRID_STAT_OUTPUT_FLAG_NBRCNT = NONE +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[EXPTDIR]}/metprd/pcp_combine + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/APCP_24h_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_APCP_{ENV[acc]}_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {OBS_GRID_STAT_INPUT_DIR}/{valid?fmt=%Y%m%d}/ccpa.t{valid?fmt=%H}z.hrap.conus.gb2_a24h + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_REFC.conf b/ush/templates/parm/metplus/GridStat_REFC.conf new file mode 100644 index 0000000000..027723470e --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_REFC.conf @@ -0,0 +1,284 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {ENV[EXPTDIR]}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/grid_stat/metplus_final.REFC.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +GRID_STAT_INTERP_FIELD = NONE +GRID_STAT_INTERP_VLD_THRESH = 1.0 +GRID_STAT_INTERP_SHAPE = SQUARE +GRID_STAT_INTERP_TYPE_METHOD = NEAREST +GRID_STAT_INTERP_TYPE_WIDTH = 1 + +GRID_STAT_GRID_WEIGHT_FLAG = NONE + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = MRMS +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = []; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = REFC + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = L0 + +FCST_VAR1_OPTIONS = cnt_thresh = [ >15 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +BOTH_VAR1_THRESH = ge20, ge30, ge40, ge50 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = MergedReflectivityQCComposite + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = Z500 + +OBS_VAR1_OPTIONS = censor_thresh = [eq-999, <-20]; censor_val = [-9999, -20]; cnt_thresh = [ >15 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +#FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +#FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = -300 +OBS_GRID_STAT_FILE_WINDOW_END = 300 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 1, 3, 5, 7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +# Set to true if observation data is probabilistic +# Only used if configuring forecast data as the 'OBS' input +OBS_IS_PROB = false + +# Only used if OBS_IS_PROB is true - sets probabilistic threshold +OBS_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {MODEL}_{CURRENT_FCST_NAME}_{OBTYPE} + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/REFC + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/MergedReflectivityQCComposite_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = metprd/grid_stat + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_REFC_mean.conf b/ush/templates/parm/metplus/GridStat_REFC_mean.conf new file mode 100644 index 0000000000..6fad42b133 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_REFC_mean.conf @@ -0,0 +1,284 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.REFC.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +GRID_STAT_INTERP_FIELD = NONE +GRID_STAT_INTERP_VLD_THRESH = 1.0 +GRID_STAT_INTERP_SHAPE = SQUARE +GRID_STAT_INTERP_TYPE_METHOD = NEAREST +GRID_STAT_INTERP_TYPE_WIDTH = 1 + +GRID_STAT_GRID_WEIGHT_FLAG = NONE + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_mean +#FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = MRMS +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = []; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = REFC_L0_ENS_MEAN + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = L0 + +#FCST_VAR1_OPTIONS = cnt_thresh = [ >15 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +BOTH_VAR1_THRESH = ge20, ge30, ge40, ge50 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = MergedReflectivityQCComposite + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = Z500 + +OBS_VAR1_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +#FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +#FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = -300 +OBS_GRID_STAT_FILE_WINDOW_END = 300 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3, 5, 7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +# Set to true if observation data is probabilistic +# Only used if configuring forecast data as the 'OBS' input +OBS_IS_PROB = false + +# Only used if OBS_IS_PROB is true - sets probabilistic threshold +OBS_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_REFC_{OBTYPE}_mean + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/REFC_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_REFC_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/MergedReflectivityQCComposite_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_REFC_prob.conf b/ush/templates/parm/metplus/GridStat_REFC_prob.conf new file mode 100644 index 0000000000..997fe1274a --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_REFC_prob.conf @@ -0,0 +1,309 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.REFC.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +GRID_STAT_INTERP_FIELD = NONE +GRID_STAT_INTERP_VLD_THRESH = 1.0 +GRID_STAT_INTERP_SHAPE = SQUARE +GRID_STAT_INTERP_TYPE_METHOD = NEAREST +GRID_STAT_INTERP_TYPE_WIDTH = 1 + +GRID_STAT_GRID_WEIGHT_FLAG = NONE + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_prob +#FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = MRMS +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = []; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = REFC_L0_ENS_FREQ_ge20 + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = L0 + +#FCST_VAR1_OPTIONS = cnt_thresh = [ >15 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +FCST_VAR1_THRESH = ==0.1 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = MergedReflectivityQCComposite + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = Z500 +OBS_VAR1_THRESH = >=20.0 +OBS_VAR1_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 + +FCST_VAR2_NAME = REFC_L0_ENS_FREQ_ge30 +FCST_VAR2_LEVELS = L0 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = MergedReflectivityQCComposite +OBS_VAR2_LEVELS = Z500 +OBS_VAR2_THRESH = >=30.0 +OBS_VAR2_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; + +FCST_VAR3_NAME = REFC_L0_ENS_FREQ_ge40 +FCST_VAR3_LEVELS = L0 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = MergedReflectivityQCComposite +OBS_VAR3_LEVELS = Z500 +OBS_VAR3_THRESH = >=40.0 +OBS_VAR3_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; + +FCST_VAR4_NAME = REFC_L0_ENS_FREQ_ge50 +FCST_VAR4_LEVELS = L0 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = MergedReflectivityQCComposite +OBS_VAR4_LEVELS = Z500 +OBS_VAR4_THRESH = >=50.0 +OBS_VAR4_OPTIONS = censor_thresh = lt-20; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +#FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +#FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = -300 +OBS_GRID_STAT_FILE_WINDOW_END = 300 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3, 5, 7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +# Set to true if observation data is probabilistic +# Only used if configuring forecast data as the 'OBS' input +OBS_IS_PROB = false + +# Only used if OBS_IS_PROB is true - sets probabilistic threshold +OBS_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_REFC_{OBTYPE}_prob + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = NONE +GRID_STAT_OUTPUT_FLAG_CTC = NONE +GRID_STAT_OUTPUT_FLAG_CTS = NONE +GRID_STAT_OUTPUT_FLAG_MCTC = NONE +GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = NONE +GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_VCNT = NONE +GRID_STAT_OUTPUT_FLAG_PCT = STAT +GRID_STAT_OUTPUT_FLAG_PSTD = STAT +GRID_STAT_OUTPUT_FLAG_PJC = STAT +GRID_STAT_OUTPUT_FLAG_PRC = STAT +GRID_STAT_OUTPUT_FLAG_ECLV = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTC = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTS = NONE +GRID_STAT_OUTPUT_FLAG_NBRCNT = NONE +GRID_STAT_OUTPUT_FLAG_GRAD = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/REFC_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_REFC_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/MergedReflectivityQCComposite_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_RETOP.conf b/ush/templates/parm/metplus/GridStat_RETOP.conf new file mode 100644 index 0000000000..0b00292112 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_RETOP.conf @@ -0,0 +1,284 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {ENV[EXPTDIR]}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/grid_stat/metplus_final.RETOP.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +GRID_STAT_INTERP_FIELD = NONE +GRID_STAT_INTERP_VLD_THRESH = 1.0 +GRID_STAT_INTERP_SHAPE = SQUARE +GRID_STAT_INTERP_TYPE_METHOD = NEAREST +GRID_STAT_INTERP_TYPE_WIDTH = 1 + +GRID_STAT_GRID_WEIGHT_FLAG = NONE + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]} +FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = MRMS +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = []; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = RETOP + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = L0 + +FCST_VAR1_OPTIONS = convert(x) = x * 3.28084 * 0.001; cnt_thresh = [ >0 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +BOTH_VAR1_THRESH = ge20, ge30, ge40, ge50 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = EchoTop18 + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = Z500 + +OBS_VAR1_OPTIONS = convert(x) = x * 3280.84 * 0.001; censor_thresh = [<=-9.84252,eq-3.28084]; censor_val = [-9999,-16.4042]; cnt_thresh = [ >0 ]; cnt_logic = UNION; + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +#FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +#FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = -300 +OBS_GRID_STAT_FILE_WINDOW_END = 300 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 1, 3, 5, 7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +# Set to true if observation data is probabilistic +# Only used if configuring forecast data as the 'OBS' input +OBS_IS_PROB = false + +# Only used if OBS_IS_PROB is true - sets probabilistic threshold +OBS_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {MODEL}_{CURRENT_FCST_NAME}_{OBTYPE} + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/RETOP + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/EchoTop_18_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H%M%S}.grib2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = metprd/grid_stat + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_RETOP_mean.conf b/ush/templates/parm/metplus/GridStat_RETOP_mean.conf new file mode 100644 index 0000000000..b0b17dbbd0 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_RETOP_mean.conf @@ -0,0 +1,284 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.RETOP.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +GRID_STAT_INTERP_FIELD = NONE +GRID_STAT_INTERP_VLD_THRESH = 1.0 +GRID_STAT_INTERP_SHAPE = SQUARE +GRID_STAT_INTERP_TYPE_METHOD = NEAREST +GRID_STAT_INTERP_TYPE_WIDTH = 1 + +GRID_STAT_GRID_WEIGHT_FLAG = NONE + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_mean +#FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = MRMS +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = []; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = RETOP_L0_ENS_MEAN + +# List of levels to evaluate for forecast variable 1 +# A03 = 3 hour accumulation in GRIB file +FCST_VAR1_LEVELS = L0 + +FCST_VAR1_OPTIONS = convert(x) = x * 3.28084 * 0.001; + +# List of thresholds to evaluate for each name/level combination for +# forecast variable 1 +BOTH_VAR1_THRESH = ge20, ge30, ge40, ge50 + +#FCST_GRID_STAT_FILE_TYPE = + +# Name of observation variable 1 +OBS_VAR1_NAME = EchoTop18 + +# List of levels to evaluate for observation variable 1 +# (*,*) is NetCDF notation - must include quotes around these values! +# must be the same length as FCST_VAR1_LEVELS +OBS_VAR1_LEVELS = Z500 + +OBS_VAR1_OPTIONS = censor_thresh = lt-20.0; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; convert(x) = x * 3280.84 * 0.001; + +# List of thresholds to evaluate for each name/level combination for +# observation variable 1 +#OBS_VAR1_THRESH = gt12.7, gt25.4, gt50.8, gt76.2 + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +#FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +#FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = -300 +OBS_GRID_STAT_FILE_WINDOW_END = 300 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3, 5, 7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +# Set to true if observation data is probabilistic +# Only used if configuring forecast data as the 'OBS' input +OBS_IS_PROB = false + +# Only used if OBS_IS_PROB is true - sets probabilistic threshold +OBS_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_RETOP_{OBTYPE}_mean + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = STAT +GRID_STAT_OUTPUT_FLAG_CTC = STAT +GRID_STAT_OUTPUT_FLAG_CTS = STAT +#GRID_STAT_OUTPUT_FLAG_MCTC = NONE +#GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = STAT +#GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +#GRID_STAT_OUTPUT_FLAG_VCNT = NONE +#GRID_STAT_OUTPUT_FLAG_PCT = NONE +#GRID_STAT_OUTPUT_FLAG_PSTD = NONE +#GRID_STAT_OUTPUT_FLAG_PJC = NONE +#GRID_STAT_OUTPUT_FLAG_PRC = NONE +#GRID_STAT_OUTPUT_FLAG_ECLV = BOTH +GRID_STAT_OUTPUT_FLAG_NBRCTC = STAT +GRID_STAT_OUTPUT_FLAG_NBRCTS = STAT +GRID_STAT_OUTPUT_FLAG_NBRCNT = STAT +#GRID_STAT_OUTPUT_FLAG_GRAD = BOTH +#GRID_STAT_OUTPUT_FLAG_DMAP = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +#GRID_STAT_NC_PAIRS_FLAG_CLIMO_CDP = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +#GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +#GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +#GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/RETOP_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_RETOP_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/EchoTop_18_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/GridStat_RETOP_prob.conf b/ush/templates/parm/metplus/GridStat_RETOP_prob.conf new file mode 100644 index 0000000000..27142979c0 --- /dev/null +++ b/ush/templates/parm/metplus/GridStat_RETOP_prob.conf @@ -0,0 +1,292 @@ +# GridStat METplus Configuration + +# section heading for [config] variables - all items below this line and +# before the next section heading correspond to the [config] section +[config] + +# List of applications to run - only GridStat for this case +PROCESS_LIST = GridStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Run pcp_combine on forecast/obs data? +FCST_PCP_COMBINE_RUN = False +OBS_PCP_COMBINE_RUN = False + +# Verbosity of MET output - overrides LOG_VERBOSITY for GridStat only +#LOG_GRID_STAT_VERBOSITY = 2 + +LOG_DIR = {OUTPUT_BASE}/log + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]} + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.RETOP.conf + +# Location of MET config file to pass to GridStat +GRID_STAT_CONFIG_FILE = {PARM_BASE}/met_config/GridStatConfig_wrapped + +# grid to remap data. Value is set as the 'to_grid' variable in the 'regrid' dictionary +# See MET User's Guide for more information +GRID_STAT_REGRID_TO_GRID = FCST +GRID_STAT_REGRID_VLD_THRESH = 0.5 +GRID_STAT_REGRID_METHOD = BUDGET +GRID_STAT_REGRID_WIDTH = 2 +GRID_STAT_REGRID_SHAPE = SQUARE + +GRID_STAT_INTERP_FIELD = NONE +GRID_STAT_INTERP_VLD_THRESH = 1.0 +GRID_STAT_INTERP_SHAPE = SQUARE +GRID_STAT_INTERP_TYPE_METHOD = NEAREST +GRID_STAT_INTERP_TYPE_WIDTH = 1 + +GRID_STAT_GRID_WEIGHT_FLAG = NONE + +# Name to identify model (forecast) data in output +MODEL = {ENV[MODEL]}_prob +#FCST_NATIVE_DATA_TYPE = GRIB + +# Name to identify observation data in output +OBTYPE = MRMS +OBS_NATIVE_DATA_TYPE = GRIB + +# set the desc value in the GridStat MET config file +GRID_STAT_DESC = NA + +# List of variables to compare in GridStat - FCST_VAR1 variables correspond +# to OBS_VAR1 variables +# Note [FCST/OBS/BOTH]_GRID_STAT_VAR_NAME can be used instead if different evaluations +# are needed for different tools + +GRID_STAT_MET_CONFIG_OVERRIDES = cat_thresh = []; cnt_thresh = [NA]; cnt_logic = UNION; wind_thresh = [NA]; wind_logic = UNION; ci_alpha = [0.05]; rank_corr_flag = FALSE; + +# Name of forecast variable 1 +FCST_VAR1_NAME = RETOP_L0_ENS_FREQ_ge20 +FCST_VAR1_LEVELS = L0 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = EchoTop18 +OBS_VAR1_LEVELS = Z500 +OBS_VAR1_THRESH = >=20.0 +OBS_VAR1_OPTIONS = censor_thresh = lt-20.0; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; convert(x) = x * 3280.84 * 0.001; + +FCST_VAR2_NAME = RETOP_L0_ENS_FREQ_ge30 +FCST_VAR2_LEVELS = L0 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = EchoTop18 +OBS_VAR2_LEVELS = Z500 +OBS_VAR2_THRESH = >=30.0 +OBS_VAR2_OPTIONS = censor_thresh = lt-20.0; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; convert(x) = x * 3280.84 * 0.001; + +FCST_VAR3_NAME = RETOP_L0_ENS_FREQ_ge40 +FCST_VAR3_LEVELS = L0 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = EchoTop18 +OBS_VAR3_LEVELS = Z500 +OBS_VAR3_THRESH = >=40.0 +OBS_VAR3_OPTIONS = censor_thresh = lt-20.0; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; convert(x) = x * 3280.84 * 0.001; + +FCST_VAR4_NAME = RETOP_L0_ENS_FREQ_ge50 +FCST_VAR4_LEVELS = L0 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = EchoTop18 +OBS_VAR4_LEVELS = Z500 +OBS_VAR4_THRESH = >=50.0 +OBS_VAR4_OPTIONS = censor_thresh = lt-20.0; censor_val = -20.0; cnt_thresh = [ >15 ]; cnt_logic = UNION; convert(x) = x * 3280.84 * 0.001; + + +#OBS_GRID_STAT_FILE_TYPE = + +# Time relative to valid time (in seconds) to allow files to be considered +# valid. Set both BEGIN and END to 0 to require the exact time in the filename +# Not used in this example. +#FCST_GRID_STAT_FILE_WINDOW_BEGIN = 0 +#FCST_GRID_STAT_FILE_WINDOW_END = 0 +OBS_GRID_STAT_FILE_WINDOW_BEGIN = -300 +OBS_GRID_STAT_FILE_WINDOW_END = 300 + +# MET GridStat neighborhood values +# See the MET User's Guide GridStat section for more information +GRID_STAT_NEIGHBORHOOD_FIELD = BOTH + +# width value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_WIDTH = 3, 5, 7 + +# shape value passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_SHAPE = SQUARE + +# cov thresh list passed to nbrhd dictionary in the MET config file +GRID_STAT_NEIGHBORHOOD_COV_THRESH = >=0.5 + +# Set to true to run GridStat separately for each field specified +# Set to false to create one run of GridStat per run time that +# includes all fields specified. +GRID_STAT_ONCE_PER_FIELD = False + +# Set to true if forecast data is probabilistic +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# Only used if FCST_IS_PROB is true - sets probabilistic threshold +FCST_GRID_STAT_PROB_THRESH = ==0.1 + +# Set to true if observation data is probabilistic +# Only used if configuring forecast data as the 'OBS' input +OBS_IS_PROB = false + +# Only used if OBS_IS_PROB is true - sets probabilistic threshold +OBS_GRID_STAT_PROB_THRESH = ==0.1 + +GRID_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_RETOP_{OBTYPE}_prob + +# Climatology data +#GRID_STAT_CLIMO_MEAN_FILE_NAME = +#GRID_STAT_CLIMO_MEAN_FIELD = +#GRID_STAT_CLIMO_MEAN_REGRID_METHOD = +#GRID_STAT_CLIMO_MEAN_REGRID_WIDTH = +#GRID_STAT_CLIMO_MEAN_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_MEAN_REGRID_SHAPE = +#GRID_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_MEAN_MATCH_MONTH = +#GRID_STAT_CLIMO_MEAN_DAY_INTERVAL = +#GRID_STAT_CLIMO_MEAN_HOUR_INTERVAL = + +#GRID_STAT_CLIMO_STDEV_FILE_NAME = +#GRID_STAT_CLIMO_STDEV_FIELD = +#GRID_STAT_CLIMO_STDEV_REGRID_METHOD = +#GRID_STAT_CLIMO_STDEV_REGRID_WIDTH = +#GRID_STAT_CLIMO_STDEV_REGRID_VLD_THRESH = +#GRID_STAT_CLIMO_STDEV_REGRID_SHAPE = +#GRID_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = +#GRID_STAT_CLIMO_STDEV_MATCH_MONTH = +#GRID_STAT_CLIMO_STDEV_DAY_INTERVAL = +#GRID_STAT_CLIMO_STDEV_HOUR_INTERVAL = + +GRID_STAT_CLIMO_CDF_BINS = 1 +#GRID_STAT_CLIMO_CDF_CENTER_BINS = False +#GRID_STAT_CLIMO_CDF_WRITE_BINS = True + +GRID_STAT_MASK_GRID = + +# Statistical output types +GRID_STAT_OUTPUT_FLAG_FHO = NONE +GRID_STAT_OUTPUT_FLAG_CTC = NONE +GRID_STAT_OUTPUT_FLAG_CTS = NONE +GRID_STAT_OUTPUT_FLAG_MCTC = NONE +GRID_STAT_OUTPUT_FLAG_MCTS = NONE +GRID_STAT_OUTPUT_FLAG_CNT = NONE +GRID_STAT_OUTPUT_FLAG_SL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_SAL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_VL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_VAL1L2 = NONE +GRID_STAT_OUTPUT_FLAG_VCNT = NONE +GRID_STAT_OUTPUT_FLAG_PCT = STAT +GRID_STAT_OUTPUT_FLAG_PSTD = STAT +GRID_STAT_OUTPUT_FLAG_PJC = STAT +GRID_STAT_OUTPUT_FLAG_PRC = STAT +GRID_STAT_OUTPUT_FLAG_ECLV = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTC = NONE +GRID_STAT_OUTPUT_FLAG_NBRCTS = NONE +GRID_STAT_OUTPUT_FLAG_NBRCNT = NONE +GRID_STAT_OUTPUT_FLAG_GRAD = NONE + +# NetCDF matched pairs output file +#GRID_STAT_NC_PAIRS_VAR_NAME = +GRID_STAT_NC_PAIRS_FLAG_LATLON = FALSE +GRID_STAT_NC_PAIRS_FLAG_RAW = FALSE +GRID_STAT_NC_PAIRS_FLAG_DIFF = FALSE +GRID_STAT_NC_PAIRS_FLAG_CLIMO = FALSE +GRID_STAT_NC_PAIRS_FLAG_WEIGHT = FALSE +GRID_STAT_NC_PAIRS_FLAG_NBRHD = FALSE +GRID_STAT_NC_PAIRS_FLAG_FOURIER = FALSE +GRID_STAT_NC_PAIRS_FLAG_GRADIENT = FALSE +GRID_STAT_NC_PAIRS_FLAG_DISTANCE_MAP = FALSE +GRID_STAT_NC_PAIRS_FLAG_APPLY_MASK = FALSE + +# End of [config] section and start of [dir] section +[dir] + +# directory containing forecast input to GridStat +INPUT_BASE = {ENV[INPUT_BASE]} +FCST_GRID_STAT_INPUT_DIR = {INPUT_BASE} + +# directory containing observation input to GridStat +OBS_GRID_STAT_INPUT_DIR = {ENV[OBS_DIR]} + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to GridStat +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_DIR = + +# directory to write output from GridStat +OUTPUT_BASE = {ENV[EXPTDIR]} +GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +STAGING_DIR = {OUTPUT_BASE}/stage/RETOP_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for forecast input to GridStat relative to FCST_GRID_STAT_INPUT_DIR +FCST_GRID_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_RETOP_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to GridStat relative to OBS_GRID_STAT_INPUT_DIR +OBS_GRID_STAT_INPUT_TEMPLATE = {valid?fmt=%Y%m%d}/EchoTop_18_00.50_{valid?fmt=%Y%m%d}-{valid?fmt=%H}0000.grib2 + +# Optional subdirectories relative to GRID_STAT_OUTPUT_DIR to write output from GridStat +GRID_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to GridStat relative to GRID_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +GRID_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +# Used to specify one or more verification mask files for GridStat +# Not used for this example +GRID_STAT_VERIFICATION_MASK_TEMPLATE = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly diff --git a/ush/templates/parm/metplus/PointStat_conus_sfc.conf b/ush/templates/parm/metplus/PointStat_conus_sfc.conf new file mode 100644 index 0000000000..a0994f222e --- /dev/null +++ b/ush/templates/parm/metplus/PointStat_conus_sfc.conf @@ -0,0 +1,294 @@ +[config] + +# List of applications to run - only PointStat for this case +PROCESS_LIST = PB2NC, PointStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INIT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Verbosity of MET output - overrides LOG_VERBOSITY for PointStat only +LOG_POINT_STAT_VERBOSITY = 2 + +# Location of MET config file to pass to PB2NC +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped + +# For both PB2NC and point_stat +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +# If set to True, skip run if the output file determined by the output directory and +# filename template already exists +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# For defining the time periods for summarization +# False for no time summary, True otherwise +# The rest of the PB2NC_TIME_SUMMARY variables are ignored if set to False +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 +PB2NC_TIME_SUMMARY_END = 235959 +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 + +# Location of MET config file to pass to GridStat +# References PARM_BASE which is the location of the parm directory corresponding +# to the ush directory of the run_metplus.py script that is called +# or the value of the environment variable METPLUS_PARM_BASE if set +POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped + +POINT_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#POINT_STAT_OBS_QUALITY_EXC = + +POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST +#POINT_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = + +#POINT_STAT_INTERP_VLD_THRESH = +#POINT_STAT_INTERP_SHAPE = +POINT_STAT_INTERP_TYPE_METHOD = BILIN +POINT_STAT_INTERP_TYPE_WIDTH = 2 + +POINT_STAT_OUTPUT_FLAG_FHO = STAT +POINT_STAT_OUTPUT_FLAG_CTC = STAT +POINT_STAT_OUTPUT_FLAG_CTS = STAT +#POINT_STAT_OUTPUT_FLAG_MCTC = +#POINT_STAT_OUTPUT_FLAG_MCTS = +POINT_STAT_OUTPUT_FLAG_CNT = STAT +POINT_STAT_OUTPUT_FLAG_SL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_SAL1L2 = +POINT_STAT_OUTPUT_FLAG_VL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_VAL1L2 = +POINT_STAT_OUTPUT_FLAG_VCNT = STAT +#POINT_STAT_OUTPUT_FLAG_PCT = +#POINT_STAT_OUTPUT_FLAG_PSTD = +#POINT_STAT_OUTPUT_FLAG_PJC = +#POINT_STAT_OUTPUT_FLAG_PRC = +#POINT_STAT_OUTPUT_FLAG_ECNT = +#POINT_STAT_OUTPUT_FLAG_RPS = +#POINT_STAT_OUTPUT_FLAG_ECLV = +#POINT_STAT_OUTPUT_FLAG_MPR = +#POINT_STAT_OUTPUT_FLAG_ORANK = + +POINT_STAT_CLIMO_CDF_BINS = 1 +#POINT_STAT_CLIMO_CDF_CENTER_BINS = False +#POINT_STAT_CLIMO_CDF_WRITE_BINS = True + +#POINT_STAT_HSS_EC_VALUE = + +# Time relative to each input file's valid time (in seconds if no units are specified) for data within the file to be +# considered valid. Values are set in the 'obs_window' dictionary in the PointStat config file +OBS_POINT_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_POINT_STAT_WINDOW_END = {OBS_WINDOW_END} + +# Optional list of offsets to look for point observation data +POINT_STAT_OFFSETS = 0 + +# Model/fcst and obs name, e.g. GFS, NAM, GDAS, etc. +MODEL = {ENV[MODEL]} + +POINT_STAT_DESC = NA +OBTYPE = NDAS + +# Regrid to specified grid. Indicate NONE if no regridding, or the grid id +# (e.g. G212) +POINT_STAT_REGRID_TO_GRID = NONE +POINT_STAT_REGRID_METHOD = BILIN +POINT_STAT_REGRID_WIDTH = 2 + +POINT_STAT_OUTPUT_PREFIX = {MODEL}_{OBTYPE}_ADPSFC + +# sets the -obs_valid_beg command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_BEG = {valid?fmt=%Y%m%d_%H} + +# sets the -obs_valid_end command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_END = {valid?fmt=%Y%m%d_%H} + +# Verification Masking regions +# Indicate which grid and polygon masking region, if applicable +POINT_STAT_GRID = + +# List of full path to poly masking files. NOTE: Only short lists of poly +# files work (those that fit on one line), a long list will result in an +# environment variable that is too long, resulting in an error. For long +# lists of poly masking files (i.e. all the mask files in the NCEP_mask +# directory), define these in the MET point_stat configuration file. +POINT_STAT_POLY = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly +POINT_STAT_STATION_ID = + +# Message types, if all message types are to be returned, leave this empty, +# otherwise indicate the message types of interest. +POINT_STAT_MESSAGE_TYPE = ADPSFC +# Variables and levels as specified in the field dictionary of the MET +# point_stat configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION + +# set to True to run PointStat once for each name/level combination +# set to False to run PointStat once per run time including all fields +POINT_STAT_ONCE_PER_FIELD = False + +# fields to compare +# Note: If FCST_VAR_* is set, then a corresponding OBS_VAR_* variable must be set +# To use one variables for both forecast and observation data, set BOTH_VAR_* instead + +BOTH_VAR1_NAME = TMP +BOTH_VAR1_LEVELS = Z2 + +BOTH_VAR2_NAME = DPT +BOTH_VAR2_LEVELS = Z2 + +BOTH_VAR3_NAME = RH +BOTH_VAR3_LEVELS = Z2 + +BOTH_VAR4_NAME = UGRD +BOTH_VAR4_LEVELS = Z10 +BOTH_VAR4_THRESH = >=2.572 ;; m/s or 5kts + +BOTH_VAR5_NAME = VGRD +BOTH_VAR5_LEVELS = Z10 +BOTH_VAR5_THRESH = >=2.572 ;; m/s or 5kts + +BOTH_VAR6_NAME = WIND +BOTH_VAR6_LEVELS = Z10 +BOTH_VAR6_THRESH = >=2.572, >=2.572&&<5.144, >=5.144, >=10.288, >=15.433 ;; m/s or 5, 10, 20, 30kts +BOTH_VAR6_OPTIONS = GRIB2_pdt = 0; ;; derive instantaneous 10-m wind from U/V components, overriding max 10-m wind + +BOTH_VAR7_NAME = PRMSL +BOTH_VAR7_LEVELS = Z0 + +FCST_VAR8_NAME = TCDC +FCST_VAR8_LEVELS = L0 +FCST_VAR8_OPTIONS = GRIB_lvl_typ = 200; GRIB2_ipdtmpl_index=[27]; GRIB2_ipdtmpl_val=[255]; interp = { type = [ { method = NEAREST; width = 1; } ]; } +OBS_VAR8_NAME = TCDC +OBS_VAR8_LEVELS = L0 + +BOTH_VAR9_NAME = VIS +BOTH_VAR9_LEVELS = L0 +BOTH_VAR9_THRESH = <805, <1609, <4828, <8045 ,>=8045, <16090 +BOTH_VAR9_OPTIONS = censor_thresh = [>16090]; censor_val = [16090]; interp = { type = [ { method = NEAREST; width = 1; } ]; } + +BOTH_VAR10_NAME = GUST +BOTH_VAR10_LEVELS = Z0 + +FCST_VAR11_NAME = HGT +FCST_VAR11_LEVELS = L0 +FCST_VAR11_OPTIONS = GRIB_lvl_typ = 215; desc = "CEILING"; +FCST_VAR11_THRESH = <152, <305, <914, <1520, <3040, >=914 +OBS_VAR11_NAME = CEILING +OBS_VAR11_LEVELS = L0 +OBS_VAR11_OPTIONS = GRIB_lvl_typ = 215; interp = { type = [ { method = NEAREST; width = 1; } ]; } +OBS_VAR11_THRESH = <152, <305, <914, <1520, <3040, >=914 + +# End of [config] section and start of [dir] section +[dir] + +# directory containing input to PB2NC +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} + +# directory to write output from +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +INPUT_BASE = {ENV[INPUT_BASE]} + +FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE} +OBS_POINT_STAT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_DIR = + +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +LOG_DIR = {ENV[EXPTDIR]}/log + +STAGING_DIR = {OUTPUT_BASE}/stage/conus_sfc + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for prepbvur input to PB2NC relative to PB2NC_INPUT_DIR +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} +# Template to use to write output from PB2NC +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for forecast input to PointStat relative to FCST_POINT_STAT_INPUT_DIR +FCST_POINT_STAT_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for observation input to PointStat relative to OBS_POINT_STAT_INPUT_DIR +OBS_POINT_STAT_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +#Template for where point-stat output is written +POINT_STAT_OUTPUT_TEMPLATE = metprd/point_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_sfc + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/point_stat/metplus_final.conus_surface.conf diff --git a/ush/templates/parm/metplus/PointStat_conus_sfc_mean.conf b/ush/templates/parm/metplus/PointStat_conus_sfc_mean.conf new file mode 100644 index 0000000000..98c23a30d2 --- /dev/null +++ b/ush/templates/parm/metplus/PointStat_conus_sfc_mean.conf @@ -0,0 +1,269 @@ +[config] + +# List of applications to run - only PointStat for this case +PROCESS_LIST = PB2NC, PointStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INIT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Verbosity of MET output - overrides LOG_VERBOSITY for PointStat only +LOG_POINT_STAT_VERBOSITY = 2 + +# Location of MET config file to pass to PB2NC +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped + +# For both PB2NC and point_stat +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +# If set to True, skip run if the output file determined by the output directory and +# filename template already exists +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# For defining the time periods for summarization +# False for no time summary, True otherwise +# The rest of the PB2NC_TIME_SUMMARY variables are ignored if set to False +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 +PB2NC_TIME_SUMMARY_END = 235959 +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 + +# Location of MET config file to pass to GridStat +# References PARM_BASE which is the location of the parm directory corresponding +# to the ush directory of the run_metplus.py script that is called +# or the value of the environment variable METPLUS_PARM_BASE if set +POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped + +POINT_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#POINT_STAT_OBS_QUALITY_EXC = + +POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST +#POINT_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = + +#POINT_STAT_INTERP_VLD_THRESH = +#POINT_STAT_INTERP_SHAPE = +POINT_STAT_INTERP_TYPE_METHOD = BILIN +POINT_STAT_INTERP_TYPE_WIDTH = 2 + +#POINT_STAT_OUTPUT_FLAG_FHO = +#POINT_STAT_OUTPUT_FLAG_CTC = +#POINT_STAT_OUTPUT_FLAG_CTS = +#POINT_STAT_OUTPUT_FLAG_MCTC = +#POINT_STAT_OUTPUT_FLAG_MCTS = +POINT_STAT_OUTPUT_FLAG_CNT = STAT +POINT_STAT_OUTPUT_FLAG_SL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_SAL1L2 = +POINT_STAT_OUTPUT_FLAG_VL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_VAL1L2 = +POINT_STAT_OUTPUT_FLAG_VCNT = STAT +#POINT_STAT_OUTPUT_FLAG_PCT = +#POINT_STAT_OUTPUT_FLAG_PSTD = +#POINT_STAT_OUTPUT_FLAG_PJC = +#POINT_STAT_OUTPUT_FLAG_PRC = +#POINT_STAT_OUTPUT_FLAG_ECNT = +#POINT_STAT_OUTPUT_FLAG_RPS = +#POINT_STAT_OUTPUT_FLAG_ECLV = +#POINT_STAT_OUTPUT_FLAG_MPR = +#POINT_STAT_OUTPUT_FLAG_ORANK = + +POINT_STAT_CLIMO_CDF_BINS = 1 +#POINT_STAT_CLIMO_CDF_CENTER_BINS = False +#POINT_STAT_CLIMO_CDF_WRITE_BINS = True + +#POINT_STAT_HSS_EC_VALUE = + +# Time relative to each input file's valid time (in seconds if no units are specified) for data within the file to be +# considered valid. Values are set in the 'obs_window' dictionary in the PointStat config file +OBS_POINT_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_POINT_STAT_WINDOW_END = {OBS_WINDOW_END} + +# Optional list of offsets to look for point observation data +POINT_STAT_OFFSETS = 0 + +# Model/fcst and obs name, e.g. GFS, NAM, GDAS, etc. +MODEL = {ENV[MODEL]}_mean + +POINT_STAT_DESC = NA +OBTYPE = NDAS + +# Regrid to specified grid. Indicate NONE if no regridding, or the grid id +# (e.g. G212) +POINT_STAT_REGRID_TO_GRID = NONE +POINT_STAT_REGRID_METHOD = BILIN +POINT_STAT_REGRID_WIDTH = 2 + +POINT_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_ADPSFC_{OBTYPE}_mean + +# sets the -obs_valid_beg command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_BEG = {valid?fmt=%Y%m%d_%H} + +# sets the -obs_valid_end command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_END = {valid?fmt=%Y%m%d_%H} + +# Verification Masking regions +# Indicate which grid and polygon masking region, if applicable +POINT_STAT_GRID = + +# List of full path to poly masking files. NOTE: Only short lists of poly +# files work (those that fit on one line), a long list will result in an +# environment variable that is too long, resulting in an error. For long +# lists of poly masking files (i.e. all the mask files in the NCEP_mask +# directory), define these in the MET point_stat configuration file. +POINT_STAT_POLY = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly +POINT_STAT_STATION_ID = + +# Message types, if all message types are to be returned, leave this empty, +# otherwise indicate the message types of interest. +POINT_STAT_MESSAGE_TYPE = ADPSFC +# Variables and levels as specified in the field dictionary of the MET +# point_stat configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION + +# set to True to run PointStat once for each name/level combination +# set to False to run PointStat once per run time including all fields +POINT_STAT_ONCE_PER_FIELD = False + +# fields to compare +# Note: If FCST_VAR_* is set, then a corresponding OBS_VAR_* variable must be set +# To use one variables for both forecast and observation data, set BOTH_VAR_* instead +FCST_VAR1_NAME = TMP_Z2_ENS_MEAN +FCST_VAR1_LEVELS = Z2 +FCST_VAR1_THRESH = >=268, >=273, >=278, >=293, >=298, >=303 + +OBS_VAR1_NAME = TMP +OBS_VAR1_LEVELS = Z2 +OBS_VAR1_THRESH = >=268, >=273, >=278, >=293, >=298, >=303 + +FCST_VAR2_NAME = DPT_Z2_ENS_MEAN +FCST_VAR2_LEVELS = Z2 +FCST_VAR2_THRESH = >=263, >=268, >=273, >=288, >=293, >=298 + +OBS_VAR2_NAME = DPT +OBS_VAR2_LEVELS = Z2 +OBS_VAR2_THRESH = >=263, >=268, >=273, >=288, >=293, >=298 + +FCST_VAR3_NAME = WIND_Z10_ENS_MEAN +FCST_VAR3_LEVELS = Z10 +FCST_VAR3_THRESH = >=5, >=10, >=15 + +OBS_VAR3_NAME = WIND +OBS_VAR3_LEVELS = Z10 +OBS_VAR3_THRESH = >=5, >=10, >=15 + +# End of [config] section and start of [dir] section +[dir] + +# directory containing input to PB2NC_INPUT_DIR = {ENV[OBS_DIR]} +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} + +# directory to write output from +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +INPUT_BASE = {ENV[INPUT_BASE]} + +FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE} +OBS_POINT_STAT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_DIR = + +OUTPUT_BASE = {ENV[EXPTDIR]} +POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +LOG_DIR = {ENV[EXPTDIR]}/log + +STAGING_DIR = {OUTPUT_BASE}/stage/conus_sfc_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for prepbvur input to PB2NC relative to PB2NC_INPUT_DIR +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} +# Template to use to write output from PB2NC +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for forecast input to PointStat relative to FCST_POINT_STAT_INPUT_DIR +FCST_POINT_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_ADPSFC_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to PointStat relative to OBS_POINT_STAT_INPUT_DIR +OBS_POINT_STAT_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +#Template for where point-stat output is written +POINT_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_sfc + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.conus_surface.conf diff --git a/ush/templates/parm/metplus/PointStat_conus_sfc_prob.conf b/ush/templates/parm/metplus/PointStat_conus_sfc_prob.conf new file mode 100644 index 0000000000..66bbc06020 --- /dev/null +++ b/ush/templates/parm/metplus/PointStat_conus_sfc_prob.conf @@ -0,0 +1,445 @@ +[config] + +# List of applications to run - only PointStat for this case +PROCESS_LIST = PB2NC, PointStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INIT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = {ENV[fhr_list]} + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Verbosity of MET output - overrides LOG_VERBOSITY for PointStat only +LOG_POINT_STAT_VERBOSITY = 2 + +# Location of MET config file to pass to PB2NC +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped + +# For both PB2NC and point_stat +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +# If set to True, skip run if the output file determined by the output directory and +# filename template already exists +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# For defining the time periods for summarization +# False for no time summary, True otherwise +# The rest of the PB2NC_TIME_SUMMARY variables are ignored if set to False +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 +PB2NC_TIME_SUMMARY_END = 235959 +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 + +# Location of MET config file to pass to GridStat +# References PARM_BASE which is the location of the parm directory corresponding +# to the ush directory of the run_metplus.py script that is called +# or the value of the environment variable METPLUS_PARM_BASE if set +POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped + +POINT_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#POINT_STAT_OBS_QUALITY_EXC = + +POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST +#POINT_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = + +#POINT_STAT_INTERP_VLD_THRESH = +#POINT_STAT_INTERP_SHAPE = +POINT_STAT_INTERP_TYPE_METHOD = BILIN +POINT_STAT_INTERP_TYPE_WIDTH = 2 + +#POINT_STAT_OUTPUT_FLAG_FHO = +#POINT_STAT_OUTPUT_FLAG_CTC = +#POINT_STAT_OUTPUT_FLAG_CTS = +#POINT_STAT_OUTPUT_FLAG_MCTC = +#POINT_STAT_OUTPUT_FLAG_MCTS = +#POINT_STAT_OUTPUT_FLAG_CNT = +#POINT_STAT_OUTPUT_FLAG_SL1L2 = +#POINT_STAT_OUTPUT_FLAG_SAL1L2 = +#POINT_STAT_OUTPUT_FLAG_VL1L2 = +#POINT_STAT_OUTPUT_FLAG_VAL1L2 = +#POINT_STAT_OUTPUT_FLAG_VCNT = +POINT_STAT_OUTPUT_FLAG_PCT = STAT +POINT_STAT_OUTPUT_FLAG_PSTD = STAT +POINT_STAT_OUTPUT_FLAG_PJC = STAT +POINT_STAT_OUTPUT_FLAG_PRC = STAT +#POINT_STAT_OUTPUT_FLAG_ECNT = +#POINT_STAT_OUTPUT_FLAG_RPS = +#POINT_STAT_OUTPUT_FLAG_ECLV = +#POINT_STAT_OUTPUT_FLAG_MPR = +#POINT_STAT_OUTPUT_FLAG_ORANK = + +POINT_STAT_CLIMO_CDF_BINS = 1 +#POINT_STAT_CLIMO_CDF_CENTER_BINS = False +#POINT_STAT_CLIMO_CDF_WRITE_BINS = True + +#POINT_STAT_HSS_EC_VALUE = + +# Time relative to each input file's valid time (in seconds if no units are specified) for data within the file to be +# considered valid. Values are set in the 'obs_window' dictionary in the PointStat config file +OBS_POINT_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_POINT_STAT_WINDOW_END = {OBS_WINDOW_END} + +# Optional list of offsets to look for point observation data +POINT_STAT_OFFSETS = 0 + +# Model/fcst and obs name, e.g. GFS, NAM, GDAS, etc. +MODEL = {ENV[MODEL]}_prob + +POINT_STAT_DESC = NA +OBTYPE = NDAS + +# Regrid to specified grid. Indicate NONE if no regridding, or the grid id +# (e.g. G212) +POINT_STAT_REGRID_TO_GRID = NONE +POINT_STAT_REGRID_METHOD = BILIN +POINT_STAT_REGRID_WIDTH = 2 + +POINT_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_ADPSFC_{OBTYPE}_prob + +# sets the -obs_valid_beg command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_BEG = {valid?fmt=%Y%m%d_%H} + +# sets the -obs_valid_end command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_END = {valid?fmt=%Y%m%d_%H} + +# Verification Masking regions +# Indicate which grid and polygon masking region, if applicable +POINT_STAT_GRID = + +# List of full path to poly masking files. NOTE: Only short lists of poly +# files work (those that fit on one line), a long list will result in an +# environment variable that is too long, resulting in an error. For long +# lists of poly masking files (i.e. all the mask files in the NCEP_mask +# directory), define these in the MET point_stat configuration file. +POINT_STAT_POLY = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly +POINT_STAT_STATION_ID = + +# Message types, if all message types are to be returned, leave this empty, +# otherwise indicate the message types of interest. +POINT_STAT_MESSAGE_TYPE = ADPSFC +# Variables and levels as specified in the field dictionary of the MET +# point_stat configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION + +# set to True to run PointStat once for each name/level combination +# set to False to run PointStat once per run time including all fields +POINT_STAT_ONCE_PER_FIELD = False + +# fields to compare +# Note: If FCST_VAR_* is set, then a corresponding OBS_VAR_* variable must be set +# To use one variables for both forecast and observation data, set BOTH_VAR_* instead +FCST_VAR1_NAME = TMP_Z2_ENS_FREQ_ge268 +FCST_VAR1_LEVELS = Z2 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = TMP +OBS_VAR1_LEVELS = Z2 +OBS_VAR1_THRESH = >=268 + +FCST_VAR2_NAME = TMP_Z2_ENS_FREQ_ge273 +FCST_VAR2_LEVELS = Z2 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = TMP +OBS_VAR2_LEVELS = Z2 +OBS_VAR2_THRESH = >=273 + +FCST_VAR3_NAME = TMP_Z2_ENS_FREQ_ge278 +FCST_VAR3_LEVELS = Z2 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = TMP +OBS_VAR3_LEVELS = Z2 +OBS_VAR3_THRESH = >=278 + +FCST_VAR4_NAME = TMP_Z2_ENS_FREQ_ge293 +FCST_VAR4_LEVELS = Z2 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = TMP +OBS_VAR4_LEVELS = Z2 +OBS_VAR4_THRESH = >=293 + +FCST_VAR5_NAME = TMP_Z2_ENS_FREQ_ge298 +FCST_VAR5_LEVELS = Z2 +FCST_VAR5_THRESH = ==0.1 + +OBS_VAR5_NAME = TMP +OBS_VAR5_LEVELS = Z2 +OBS_VAR5_THRESH = >=298 + +FCST_VAR6_NAME = TMP_Z2_ENS_FREQ_ge303 +FCST_VAR6_LEVELS = Z2 +FCST_VAR6_THRESH = ==0.1 + +OBS_VAR6_NAME = TMP +OBS_VAR6_LEVELS = Z2 +OBS_VAR6_THRESH = >=303 + +FCST_VAR7_NAME = DPT_Z2_ENS_FREQ_ge263 +FCST_VAR7_LEVELS = Z2 +FCST_VAR7_THRESH = ==0.1 + +OBS_VAR7_NAME = DPT +OBS_VAR7_LEVELS = Z2 +OBS_VAR7_THRESH = >=263 + +FCST_VAR8_NAME = DPT_Z2_ENS_FREQ_ge268 +FCST_VAR8_LEVELS = Z2 +FCST_VAR8_THRESH = ==0.1 + +OBS_VAR8_NAME = DPT +OBS_VAR8_LEVELS = Z2 +OBS_VAR8_THRESH = >=268 + +FCST_VAR9_NAME = DPT_Z2_ENS_FREQ_ge273 +FCST_VAR9_LEVELS = Z2 +FCST_VAR9_THRESH = ==0.1 + +OBS_VAR9_NAME = DPT +OBS_VAR9_LEVELS = Z2 +OBS_VAR9_THRESH = >=273 + +FCST_VAR10_NAME = DPT_Z2_ENS_FREQ_ge288 +FCST_VAR10_LEVELS = Z2 +FCST_VAR10_THRESH = ==0.1 + +OBS_VAR10_NAME = DPT +OBS_VAR10_LEVELS = Z2 +OBS_VAR10_THRESH = >=288 + +FCST_VAR11_NAME = DPT_Z2_ENS_FREQ_ge293 +FCST_VAR11_LEVELS = Z2 +FCST_VAR11_THRESH = ==0.1 + +OBS_VAR11_NAME = DPT +OBS_VAR11_LEVELS = Z2 +OBS_VAR11_THRESH = >=293 + +FCST_VAR12_NAME = DPT_Z2_ENS_FREQ_ge298 +FCST_VAR12_LEVELS = Z2 +FCST_VAR12_THRESH = ==0.1 + +OBS_VAR12_NAME = DPT +OBS_VAR12_LEVELS = Z2 +OBS_VAR12_THRESH = >=298 + +FCST_VAR13_NAME = WIND_Z10_ENS_FREQ_ge5 +FCST_VAR13_LEVELS = Z10 +FCST_VAR13_THRESH = ==0.1 + +OBS_VAR13_NAME = WIND +OBS_VAR13_LEVELS = Z10 +OBS_VAR13_THRESH = >=5 + +FCST_VAR14_NAME = WIND_Z10_ENS_FREQ_ge10 +FCST_VAR14_LEVELS = Z10 +FCST_VAR14_THRESH = ==0.1 + +OBS_VAR14_NAME = WIND +OBS_VAR14_LEVELS = Z10 +OBS_VAR14_THRESH = >=10 + +FCST_VAR15_NAME = WIND_Z10_ENS_FREQ_ge15 +FCST_VAR15_LEVELS = Z10 +FCST_VAR15_THRESH = ==0.1 + +OBS_VAR15_NAME = WIND +OBS_VAR15_LEVELS = Z10 +OBS_VAR15_THRESH = >=15 + +FCST_VAR16_NAME = TCDC_L0_ENS_FREQ_lt25 +FCST_VAR16_LEVELS = L0 +FCST_VAR16_THRESH = ==0.1 + +OBS_VAR16_NAME = TCDC +OBS_VAR16_LEVELS = L0 +OBS_VAR16_THRESH = <25 + +FCST_VAR17_NAME = TCDC_L0_ENS_FREQ_gt75 +FCST_VAR17_LEVELS = L0 +FCST_VAR17_THRESH = ==0.1 + +OBS_VAR17_NAME = TCDC +OBS_VAR17_LEVELS = L0 +OBS_VAR17_THRESH = >75 + +FCST_VAR18_NAME = VIS_L0_ENS_FREQ_lt1609 +FCST_VAR18_LEVELS = L0 +FCST_VAR18_THRESH = ==0.1 +FCST_VAR18_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +OBS_VAR18_NAME = VIS +OBS_VAR18_LEVELS = L0 +OBS_VAR18_THRESH = <1609 +OBS_VAR18_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +FCST_VAR19_NAME = VIS_L0_ENS_FREQ_lt8045 +FCST_VAR19_LEVELS = L0 +FCST_VAR19_THRESH = ==0.1 +FCST_VAR19_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +OBS_VAR19_NAME = VIS +OBS_VAR19_LEVELS = L0 +OBS_VAR19_THRESH = <8045 +OBS_VAR19_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +FCST_VAR20_NAME = VIS_L0_ENS_FREQ_ge8045 +FCST_VAR20_LEVELS = L0 +FCST_VAR20_THRESH = ==0.1 +FCST_VAR20_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +OBS_VAR20_NAME = VIS +OBS_VAR20_LEVELS = L0 +OBS_VAR20_THRESH = >=8045 +OBS_VAR20_OPTIONS = interp = { type = [ { method = NEAREST; width = 1; } ]; } + +FCST_VAR21_NAME = HGT_L0_ENS_FREQ_lt152 +FCST_VAR21_LEVELS = L0 +FCST_VAR21_THRESH = ==0.1 +FCST_VAR21_OPTIONS = desc = "CEILING"; + +OBS_VAR21_NAME = CEILING +OBS_VAR21_LEVELS = L0 +OBS_VAR21_THRESH = <152 +OBS_VAR21_OPTIONS = GRIB_lvl_typ = 215; interp = { type = [ { method = NEAREST; width = 1; } ]; } + +FCST_VAR22_NAME = HGT_L0_ENS_FREQ_lt1520 +FCST_VAR22_LEVELS = L0 +FCST_VAR22_THRESH = ==0.1 +FCST_VAR22_OPTIONS = desc = "CEILING"; + +OBS_VAR22_NAME = CEILING +OBS_VAR22_LEVELS = L0 +OBS_VAR22_THRESH = <1520 +OBS_VAR22_OPTIONS = GRIB_lvl_typ = 215; interp = { type = [ { method = NEAREST; width = 1; } ]; } + +FCST_VAR23_NAME = HGT_L0_ENS_FREQ_ge914 +FCST_VAR23_LEVELS = L0 +FCST_VAR23_THRESH = ==0.1 +FCST_VAR23_OPTIONS = desc = "CEILING"; + +OBS_VAR23_NAME = CEILING +OBS_VAR23_LEVELS = L0 +OBS_VAR23_THRESH = >=914 +OBS_VAR23_OPTIONS = GRIB_lvl_typ = 215; interp = { type = [ { method = NEAREST; width = 1; } ]; } + +# Forecast data description variables +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# End of [config] section and start of [dir] section +[dir] + +# directory containing input to PB2NC_INPUT_DIR = {ENV[OBS_DIR]} +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} + +# directory to write output from +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +INPUT_BASE = {ENV[INPUT_BASE]} + +FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE} +OBS_POINT_STAT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_DIR = + +OUTPUT_BASE = {ENV[EXPTDIR]} +POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +LOG_DIR = {ENV[EXPTDIR]}/log + +STAGING_DIR = {OUTPUT_BASE}/stage/conus_sfc_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for prepbvur input to PB2NC relative to PB2NC_INPUT_DIR +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} +# Template to use to write output from PB2NC +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for forecast input to PointStat relative to FCST_POINT_STAT_INPUT_DIR +FCST_POINT_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_ADPSFC_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to PointStat relative to OBS_POINT_STAT_INPUT_DIR +OBS_POINT_STAT_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +#Template for where point-stat output is written +POINT_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_sfc + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.conus_surface.conf diff --git a/ush/templates/parm/metplus/PointStat_upper_air.conf b/ush/templates/parm/metplus/PointStat_upper_air.conf new file mode 100644 index 0000000000..23591bec11 --- /dev/null +++ b/ush/templates/parm/metplus/PointStat_upper_air.conf @@ -0,0 +1,295 @@ +[config] + +# List of applications to run - only PointStat for this case +PROCESS_LIST = PB2NC, PointStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INIT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = begin_end_incr(0,{ENV[fhr_last]},6) + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Verbosity of MET output - overrides LOG_VERBOSITY for PointStat only +LOG_POINT_STAT_VERBOSITY = 2 + +# Location of MET config file to pass to PB2NC +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped + +# For both PB2NC and point_stat +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +# If set to True, skip run if the output file determined by the output directory and +# filename template already exists +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# For defining the time periods for summarization +# False for no time summary, True otherwise +# The rest of the PB2NC_TIME_SUMMARY variables are ignored if set to False +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 +PB2NC_TIME_SUMMARY_END = 235959 +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 + +# Location of MET config file to pass to GridStat +# References PARM_BASE which is the location of the parm directory corresponding +# to the ush directory of the run_metplus.py script that is called +# or the value of the environment variable METPLUS_PARM_BASE if set +POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped + +POINT_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#POINT_STAT_OBS_QUALITY_EXC = + +POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST +#POINT_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = + +#POINT_STAT_INTERP_VLD_THRESH = +#POINT_STAT_INTERP_SHAPE = +POINT_STAT_INTERP_TYPE_METHOD = BILIN +POINT_STAT_INTERP_TYPE_WIDTH = 2 + +POINT_STAT_OUTPUT_FLAG_FHO = STAT +POINT_STAT_OUTPUT_FLAG_CTC = STAT +POINT_STAT_OUTPUT_FLAG_CTS = STAT +#POINT_STAT_OUTPUT_FLAG_MCTC = +#POINT_STAT_OUTPUT_FLAG_MCTS = +POINT_STAT_OUTPUT_FLAG_CNT = STAT +POINT_STAT_OUTPUT_FLAG_SL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_SAL1L2 = +POINT_STAT_OUTPUT_FLAG_VL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_VAL1L2 = +POINT_STAT_OUTPUT_FLAG_VCNT = STAT +#POINT_STAT_OUTPUT_FLAG_PCT = +#POINT_STAT_OUTPUT_FLAG_PSTD = +#POINT_STAT_OUTPUT_FLAG_PJC = +#POINT_STAT_OUTPUT_FLAG_PRC = +#POINT_STAT_OUTPUT_FLAG_ECNT = +#POINT_STAT_OUTPUT_FLAG_RPS = +#POINT_STAT_OUTPUT_FLAG_ECLV = +#POINT_STAT_OUTPUT_FLAG_MPR = +#POINT_STAT_OUTPUT_FLAG_ORANK = + +POINT_STAT_CLIMO_CDF_BINS = 1 +#POINT_STAT_CLIMO_CDF_CENTER_BINS = False +#POINT_STAT_CLIMO_CDF_WRITE_BINS = True + +#POINT_STAT_HSS_EC_VALUE = + +# Time relative to each input file's valid time (in seconds if no units are specified) for data within the file to be +# considered valid. Values are set in the 'obs_window' dictionary in the PointStat config file +OBS_POINT_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_POINT_STAT_WINDOW_END = {OBS_WINDOW_END} + +# Optional list of offsets to look for point observation data +POINT_STAT_OFFSETS = 0 + +# Model/fcst and obs name, e.g. GFS, NAM, GDAS, etc. +MODEL = {ENV[MODEL]} + +POINT_STAT_DESC = NA +OBTYPE = NDAS + +# Regrid to specified grid. Indicate NONE if no regridding, or the grid id +# (e.g. G212) +POINT_STAT_REGRID_TO_GRID = NONE +POINT_STAT_REGRID_METHOD = BILIN +POINT_STAT_REGRID_WIDTH = 2 + +POINT_STAT_OUTPUT_PREFIX = {MODEL}_{OBTYPE}_ADPUPA + +# sets the -obs_valid_beg command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_BEG = {valid?fmt=%Y%m%d_%H} + +# sets the -obs_valid_end command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_END = {valid?fmt=%Y%m%d_%H} + +# Verification Masking regions +# Indicate which grid and polygon masking region, if applicable +POINT_STAT_GRID = + +# List of full path to poly masking files. NOTE: Only short lists of poly +# files work (those that fit on one line), a long list will result in an +# environment variable that is too long, resulting in an error. For long +# lists of poly masking files (i.e. all the mask files in the NCEP_mask +# directory), define these in the MET point_stat configuration file. +POINT_STAT_POLY = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly +POINT_STAT_STATION_ID = + +# Message types, if all message types are to be returned, leave this empty, +# otherwise indicate the message types of interest. +POINT_STAT_MESSAGE_TYPE = ADPUPA +# Variables and levels as specified in the field dictionary of the MET +# point_stat configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION + +# set to True to run PointStat once for each name/level combination +# set to False to run PointStat once per run time including all fields +POINT_STAT_ONCE_PER_FIELD = False + +# fields to compare +# Note: If FCST_VAR_* is set, then a corresponding OBS_VAR_* variable must be set +# To use one variables for both forecast and observation data, set BOTH_VAR_* instead +BOTH_VAR1_NAME = TMP +BOTH_VAR1_LEVELS = P1000, P925, P850, P700, P500, P400, P300, P250, P200, P150, P100, P50, P20, P10 + +BOTH_VAR2_NAME = RH +BOTH_VAR2_LEVELS = P1000, P925, P850, P700, P500, P400, P300, P250 + +BOTH_VAR3_NAME = DPT +BOTH_VAR3_LEVELS = P1000, P925, P850, P700, P500, P400, P300 + +BOTH_VAR4_NAME = UGRD +BOTH_VAR4_LEVELS = P1000, P925, P850, P700, P500, P400, P300, P250, P200, P150, P100, P50, P20, P10 +BOTH_VAR4_THRESH = >=2.572 ;; m/s or 5kts + +BOTH_VAR5_NAME = VGRD +BOTH_VAR5_LEVELS = P1000, P925, P850, P700, P500, P400, P300, P250, P200, P150, P100, P50, P20, P10 +BOTH_VAR5_THRESH = >=2.572 ;; m/s or 5kts + +BOTH_VAR6_NAME = WIND +BOTH_VAR6_LEVELS = P1000, P925, P850, P700, P500, P400, P300, P250, P200, P150, P100, P50, P20, P10 +BOTH_VAR6_THRESH = >=2.572, >=2.572&&<5.144, >=5.144, >=10.288, >=15.433, >=20.577, >=25.722 ;; m/s or 5, 10, 20, 30, 40, 50kts + +BOTH_VAR7_NAME = HGT +BOTH_VAR7_LEVELS = P1000, P950, P925, P850, P700, P500, P400, P300, P250, P200, P150, P100, P50, P20, P10 + +BOTH_VAR8_NAME = SPFH +BOTH_VAR8_LEVELS = P1000, P850, P700, P500, P400, P300 + +FCST_VAR9_NAME = CAPE +FCST_VAR9_LEVELS = L0 +FCST_VAR9_OPTIONS = cnt_thresh = [ >0 ]; +FCST_VAR9_THRESH = >500, >1000, >1500, >2000, >3000, >4000 +OBS_VAR9_NAME = CAPE +OBS_VAR9_LEVELS = L0-100000 +OBS_VAR9_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR9_THRESH = >500, >1000, >1500, >2000, >3000, >4000 + +FCST_VAR10_NAME = HPBL +FCST_VAR10_LEVELS = Z0 +OBS_VAR10_NAME = PBL +OBS_VAR10_LEVELS = L0 +OBS_VAR10_OPTIONS = desc = "TKE"; + +FCST_VAR11_NAME = HGT +FCST_VAR11_LEVELS = L0 +FCST_VAR11_OPTIONS = GRIB_lvl_typ = 220; +OBS_VAR11_NAME = PBL +OBS_VAR11_LEVELS = L0 +OBS_VAR11_OPTIONS = desc = "RI"; + +# End of [config] section and start of [dir] section +[dir] + +# directory containing input to PB2NC +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} + +# directory to write output from +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +INPUT_BASE = {ENV[INPUT_BASE]} + +FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE} +OBS_POINT_STAT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_DIR = + +OUTPUT_BASE = {ENV[OUTPUT_BASE]} +POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +LOG_DIR = {ENV[EXPTDIR]}/log + +STAGING_DIR = {OUTPUT_BASE}/stage/upper_air + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for prepbvur input to PB2NC relative to PB2NC_INPUT_DIR +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} + +# Template to use to write output from PB2NC +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for forecast input to PointStat relative to FCST_POINT_STAT_INPUT_DIR +FCST_POINT_STAT_INPUT_TEMPLATE = {ENV[NET]}.t{init?fmt=%H}z.prslev.f{lead?fmt=%HHH}.{ENV[POST_OUTPUT_DOMAIN_NAME]}.grib2 + +# Template to look for observation input to PointStat relative to OBS_POINT_STAT_INPUT_DIR +OBS_POINT_STAT_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +#Template for where point-stat output is written +POINT_STAT_OUTPUT_TEMPLATE = metprd/point_stat + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_upa + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/metprd/point_stat/metplus_final.upper_air.conf diff --git a/ush/templates/parm/metplus/PointStat_upper_air_mean.conf b/ush/templates/parm/metplus/PointStat_upper_air_mean.conf new file mode 100644 index 0000000000..4b5e917100 --- /dev/null +++ b/ush/templates/parm/metplus/PointStat_upper_air_mean.conf @@ -0,0 +1,345 @@ +[config] + +# List of applications to run - only PointStat for this case +PROCESS_LIST = PB2NC, PointStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INIT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = begin_end_incr(0,{ENV[fhr_last]},6) + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Verbosity of MET output - overrides LOG_VERBOSITY for PointStat only +LOG_POINT_STAT_VERBOSITY = 2 + +# Location of MET config file to pass to PB2NC +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped + +# For both PB2NC and point_stat +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +# If set to True, skip run if the output file determined by the output directory and +# filename template already exists +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# For defining the time periods for summarization +# False for no time summary, True otherwise +# The rest of the PB2NC_TIME_SUMMARY variables are ignored if set to False +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 +PB2NC_TIME_SUMMARY_END = 235959 +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 + +# Location of MET config file to pass to GridStat +# References PARM_BASE which is the location of the parm directory corresponding +# to the ush directory of the run_metplus.py script that is called +# or the value of the environment variable METPLUS_PARM_BASE if set +POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped + +POINT_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#POINT_STAT_OBS_QUALITY_EXC = + +POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST +#POINT_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = + +#POINT_STAT_INTERP_VLD_THRESH = +#POINT_STAT_INTERP_SHAPE = +POINT_STAT_INTERP_TYPE_METHOD = BILIN +POINT_STAT_INTERP_TYPE_WIDTH = 2 + +#POINT_STAT_OUTPUT_FLAG_FHO = +#POINT_STAT_OUTPUT_FLAG_CTC = +#POINT_STAT_OUTPUT_FLAG_CTS = +#POINT_STAT_OUTPUT_FLAG_MCTC = +#POINT_STAT_OUTPUT_FLAG_MCTS = +POINT_STAT_OUTPUT_FLAG_CNT = STAT +POINT_STAT_OUTPUT_FLAG_SL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_SAL1L2 = +POINT_STAT_OUTPUT_FLAG_VL1L2 = STAT +#POINT_STAT_OUTPUT_FLAG_VAL1L2 = +POINT_STAT_OUTPUT_FLAG_VCNT = STAT +#POINT_STAT_OUTPUT_FLAG_PCT = +#POINT_STAT_OUTPUT_FLAG_PSTD = +#POINT_STAT_OUTPUT_FLAG_PJC = +#POINT_STAT_OUTPUT_FLAG_PRC = +#POINT_STAT_OUTPUT_FLAG_ECNT = +#POINT_STAT_OUTPUT_FLAG_RPS = +#POINT_STAT_OUTPUT_FLAG_ECLV = +#POINT_STAT_OUTPUT_FLAG_MPR = +#POINT_STAT_OUTPUT_FLAG_ORANK = + +POINT_STAT_CLIMO_CDF_BINS = 1 +#POINT_STAT_CLIMO_CDF_CENTER_BINS = False +#POINT_STAT_CLIMO_CDF_WRITE_BINS = True + +#POINT_STAT_HSS_EC_VALUE = + +# Time relative to each input file's valid time (in seconds if no units are specified) for data within the file to be +# considered valid. Values are set in the 'obs_window' dictionary in the PointStat config file +OBS_POINT_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_POINT_STAT_WINDOW_END = {OBS_WINDOW_END} + +# Optional list of offsets to look for point observation data +POINT_STAT_OFFSETS = 0 + +# Model/fcst and obs name, e.g. GFS, NAM, GDAS, etc. +MODEL = {ENV[MODEL]}_mean + +POINT_STAT_DESC = NA +OBTYPE = NDAS + +# Regrid to specified grid. Indicate NONE if no regridding, or the grid id +# (e.g. G212) +POINT_STAT_REGRID_TO_GRID = NONE +POINT_STAT_REGRID_METHOD = BILIN +POINT_STAT_REGRID_WIDTH = 2 + +POINT_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_ADPUPA_{OBTYPE}_mean + +# sets the -obs_valid_beg command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_BEG = {valid?fmt=%Y%m%d_%H} + +# sets the -obs_valid_end command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_END = {valid?fmt=%Y%m%d_%H} + +# Verification Masking regions +# Indicate which grid and polygon masking region, if applicable +POINT_STAT_GRID = + +# List of full path to poly masking files. NOTE: Only short lists of poly +# files work (those that fit on one line), a long list will result in an +# environment variable that is too long, resulting in an error. For long +# lists of poly masking files (i.e. all the mask files in the NCEP_mask +# directory), define these in the MET point_stat configuration file. +POINT_STAT_POLY = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly +POINT_STAT_STATION_ID = + +# Message types, if all message types are to be returned, leave this empty, +# otherwise indicate the message types of interest. +POINT_STAT_MESSAGE_TYPE = ADPUPA +# Variables and levels as specified in the field dictionary of the MET +# point_stat configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION + +# set to True to run PointStat once for each name/level combination +# set to False to run PointStat once per run time including all fields +POINT_STAT_ONCE_PER_FIELD = False + +# fields to compare +# Note: If FCST_VAR_* is set, then a corresponding OBS_VAR_* variable must be set +# To use one variables for both forecast and observation data, set BOTH_VAR_* instead +FCST_VAR1_NAME = TMP_P850_ENS_MEAN +FCST_VAR1_LEVELS = P850 +FCST_VAR1_THRESH = >=288, >=293, >=298 + +OBS_VAR1_NAME = TMP +OBS_VAR1_LEVELS = P850 +OBS_VAR1_THRESH = >=288, >=293, >=298 + +FCST_VAR2_NAME = TMP_P700_ENS_MEAN +FCST_VAR2_LEVELS = P700 +FCST_VAR2_THRESH = >=273, >=278, >=283 + +OBS_VAR2_NAME = TMP +OBS_VAR2_LEVELS = P700 +OBS_VAR2_THRESH = >=273, >=278, >=283 + +FCST_VAR3_NAME = TMP_P500_ENS_MEAN +FCST_VAR3_LEVELS = P500 +FCST_VAR3_THRESH = >=258, >=263, >=268 + +OBS_VAR3_NAME = TMP +OBS_VAR3_LEVELS = P500 +OBS_VAR3_THRESH = >=258, >=263, >=268 + +FCST_VAR4_NAME = DPT_P850_ENS_MEAN +FCST_VAR4_LEVELS = P850 +FCST_VAR4_THRESH = >=273, >=278, >=283 + +OBS_VAR4_NAME = DPT +OBS_VAR4_LEVELS = P850 +OBS_VAR4_THRESH = >=273, >=278, >=283 + +FCST_VAR5_NAME = DPT_P700_ENS_MEAN +FCST_VAR5_LEVELS = P700 +FCST_VAR5_THRESH = >=263, >=286, >=273 + +OBS_VAR5_NAME = DPT +OBS_VAR5_LEVELS = P700 +OBS_VAR5_THRESH = >=263, >=286, >=273 + +FCST_VAR6_NAME = WIND_P850_ENS_MEAN +FCST_VAR6_LEVELS = P850 +FCST_VAR6_THRESH = >=5, >=10, >=15 + +OBS_VAR6_NAME = WIND +OBS_VAR6_LEVELS = P850 +OBS_VAR6_THRESH = >=5, >=10, >=15 + +FCST_VAR7_NAME = WIND_P700_ENS_MEAN +FCST_VAR7_LEVELS = P700 +FCST_VAR7_THRESH = >=10, >=15, >=20 + +OBS_VAR7_NAME = WIND +OBS_VAR7_LEVELS = P700 +OBS_VAR7_THRESH = >=10, >=15, >=20 + +FCST_VAR8_NAME = WIND_P500_ENS_MEAN +FCST_VAR8_LEVELS = P500 +FCST_VAR8_THRESH = >=15, >=21, >=26 + +OBS_VAR8_NAME = WIND +OBS_VAR8_LEVELS = P500 +OBS_VAR8_THRESH = >=15, >=21, >=26 + +FCST_VAR9_NAME = WIND_P250_ENS_MEAN +FCST_VAR9_LEVELS = P250 +FCST_VAR9_THRESH = >=26, >=31, >=46, >=62 + +OBS_VAR9_NAME = WIND +OBS_VAR9_LEVELS = P250 +OBS_VAR9_THRESH = >=26, >=31, >=46, >=62 + +FCST_VAR10_NAME = HGT_P500_ENS_MEAN +FCST_VAR10_LEVELS = P500 +FCST_VAR10_THRESH = >=5400, >=5600, >=5880 + +OBS_VAR10_NAME = HGT +OBS_VAR10_LEVELS = P500 +OBS_VAR10_THRESH = >=5400, >=5600, >=5880 + +FCST_VAR11_NAME = CAPE_L0_ENS_MEAN +FCST_VAR11_LEVELS = L0 +FCST_VAR11_OPTIONS = cnt_thresh = [ >0 ]; +FCST_VAR11_THRESH = <=1000, >1000&&<2500, >2500&&<4000, >2500 + +OBS_VAR11_NAME = CAPE +OBS_VAR11_LEVELS = L0-100000 +OBS_VAR11_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR11_THRESH = <=1000, >1000&&<2500, >2500&&<4000, >2500 + +FCST_VAR12_NAME = HPBL_Z0_ENS_MEAN +FCST_VAR12_LEVELS = Z0 +FCST_VAR12_THRESH = <500, <1500, >1500 + +OBS_VAR12_NAME = PBL +OBS_VAR12_LEVELS = L0 +OBS_VAR12_OPTIONS = desc = "TKE"; +OBS_VAR12_THRESH = <500, <1500, >1500 + +# End of [config] section and start of [dir] section +[dir] + +# directory containing input to PB2NC +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} + +# directory to write output from +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +INPUT_BASE = {ENV[INPUT_BASE]} + +FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE} +OBS_POINT_STAT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_DIR = + +OUTPUT_BASE = {ENV[EXPTDIR]} +POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +LOG_DIR = {ENV[EXPTDIR]}/log + +STAGING_DIR = {OUTPUT_BASE}/stage/upper_air_mean + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for prepbvur input to PB2NC relative to PB2NC_INPUT_DIR +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} + +# Template to use to write output from PB2NC +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for forecast input to PointStat relative to FCST_POINT_STAT_INPUT_DIR +FCST_POINT_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_ADPUPA_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to PointStat relative to OBS_POINT_STAT_INPUT_DIR +OBS_POINT_STAT_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +#Template for where point-stat output is written +POINT_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_mean + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_upa + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_mean/metplus_final.upper_air.conf diff --git a/ush/templates/parm/metplus/PointStat_upper_air_prob.conf b/ush/templates/parm/metplus/PointStat_upper_air_prob.conf new file mode 100644 index 0000000000..213e1f04f5 --- /dev/null +++ b/ush/templates/parm/metplus/PointStat_upper_air_prob.conf @@ -0,0 +1,569 @@ +[config] + +# List of applications to run - only PointStat for this case +PROCESS_LIST = PB2NC, PointStat + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = INIT + +# Format of INIT_BEG and INIT_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +INIT_TIME_FMT = %Y%m%d%H + +# Start time for METplus run - must match INIT_TIME_FMT +INIT_BEG = {ENV[CDATE]} + +# End time for METplus run - must match INIT_TIME_FMT +INIT_END = {ENV[CDATE]} + +# Increment between METplus runs (in seconds if no units are specified) +# Must be >= 60 seconds +INIT_INCREMENT = 3600 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = begin_end_incr(0,{ENV[fhr_last]},6) + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = times + +# Verbosity of MET output - overrides LOG_VERBOSITY for PointStat only +LOG_POINT_STAT_VERBOSITY = 2 + +# Location of MET config file to pass to PB2NC +PB2NC_CONFIG_FILE = {PARM_BASE}/met_config/PB2NCConfig_wrapped + +# For both PB2NC and point_stat +OBS_WINDOW_BEGIN = -1799 +OBS_WINDOW_END = 1800 + +PB2NC_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +PB2NC_WINDOW_END = {OBS_WINDOW_END} + +# If set to True, skip run if the output file determined by the output directory and +# filename template already exists +PB2NC_SKIP_IF_OUTPUT_EXISTS = True + +# Values to pass to pb2nc config file using environment variables of the same name. +PB2NC_GRID = +PB2NC_POLY = +PB2NC_STATION_ID = +PB2NC_MESSAGE_TYPE = ADPSFC, ADPUPA +PB2NC_LEVEL_CATEGORY = 0, 1, 4, 5, 6 +PB2NC_QUALITY_MARK_THRESH = 9 + +PB2NC_PB_REPORT_TYPE = 120, 220, 221, 122, 222, 223, 224, 131, 133, 233, 153, 156, 157, 188, 288, 180, 280, 181, 182, 281, 282, 183, 284, 187, 287 + +# Leave empty to process all +PB2NC_OBS_BUFR_VAR_LIST = PMO, ZOB, TOB, D_DPT, QOB, UOB, VOB, PWO, TOCC, D_RH, HOVI, CEILING, D_PBL, D_CAPE, MXGS, D_WIND, D_PRMSL + +# Mapping of input BUFR variable names to output variables names. +# The default PREPBUFR map, obs_prepbufr_map, is appended to this map. +PB2NC_OBS_BUFR_MAP = [{ key = "PWO"; val = "PWAT"; },{ key = "MXGS"; val = "GUST"; }, { key = "CEILING"; val = "CEILING"; }] + +# For defining the time periods for summarization +# False for no time summary, True otherwise +# The rest of the PB2NC_TIME_SUMMARY variables are ignored if set to False +PB2NC_TIME_SUMMARY_FLAG = False +PB2NC_TIME_SUMMARY_BEG = 000000 +PB2NC_TIME_SUMMARY_END = 235959 +PB2NC_TIME_SUMMARY_VAR_NAMES = PMO,TOB,TDO,UOB,VOB,PWO,TOCC +PB2NC_TIME_SUMMARY_TYPES = min, max, range, mean, stdev, median, p80 + +# Location of MET config file to pass to GridStat +# References PARM_BASE which is the location of the parm directory corresponding +# to the ush directory of the run_metplus.py script that is called +# or the value of the environment variable METPLUS_PARM_BASE if set +POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped + +POINT_STAT_OBS_QUALITY_INC = 0, 1, 2, 3, 9, NA +#POINT_STAT_OBS_QUALITY_EXC = + +POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST +#POINT_STAT_CLIMO_STDEV_TIME_INTERP_METHOD = + +#POINT_STAT_INTERP_VLD_THRESH = +#POINT_STAT_INTERP_SHAPE = +POINT_STAT_INTERP_TYPE_METHOD = BILIN +POINT_STAT_INTERP_TYPE_WIDTH = 2 + +#POINT_STAT_OUTPUT_FLAG_FHO = +#POINT_STAT_OUTPUT_FLAG_CTC = +#POINT_STAT_OUTPUT_FLAG_CTS = +#POINT_STAT_OUTPUT_FLAG_MCTC = +#POINT_STAT_OUTPUT_FLAG_MCTS = +#POINT_STAT_OUTPUT_FLAG_CNT = +#POINT_STAT_OUTPUT_FLAG_SL1L2 = +#POINT_STAT_OUTPUT_FLAG_SAL1L2 = +#POINT_STAT_OUTPUT_FLAG_VL1L2 = +#POINT_STAT_OUTPUT_FLAG_VAL1L2 = +#POINT_STAT_OUTPUT_FLAG_VCNT = +POINT_STAT_OUTPUT_FLAG_PCT = STAT +POINT_STAT_OUTPUT_FLAG_PSTD = STAT +POINT_STAT_OUTPUT_FLAG_PJC = STAT +POINT_STAT_OUTPUT_FLAG_PRC = STAT +#POINT_STAT_OUTPUT_FLAG_ECNT = +#POINT_STAT_OUTPUT_FLAG_RPS = +#POINT_STAT_OUTPUT_FLAG_ECLV = +#POINT_STAT_OUTPUT_FLAG_MPR = +#POINT_STAT_OUTPUT_FLAG_ORANK = + +POINT_STAT_CLIMO_CDF_BINS = 1 +#POINT_STAT_CLIMO_CDF_CENTER_BINS = False +#POINT_STAT_CLIMO_CDF_WRITE_BINS = True + +#POINT_STAT_HSS_EC_VALUE = + +# Time relative to each input file's valid time (in seconds if no units are specified) for data within the file to be +# considered valid. Values are set in the 'obs_window' dictionary in the PointStat config file +OBS_POINT_STAT_WINDOW_BEGIN = {OBS_WINDOW_BEGIN} +OBS_POINT_STAT_WINDOW_END = {OBS_WINDOW_END} + +# Optional list of offsets to look for point observation data +POINT_STAT_OFFSETS = 0 + +# Model/fcst and obs name, e.g. GFS, NAM, GDAS, etc. +MODEL = {ENV[MODEL]}_prob + +POINT_STAT_DESC = NA +OBTYPE = NDAS + +# Regrid to specified grid. Indicate NONE if no regridding, or the grid id +# (e.g. G212) +POINT_STAT_REGRID_TO_GRID = NONE +POINT_STAT_REGRID_METHOD = BILIN +POINT_STAT_REGRID_WIDTH = 2 + +POINT_STAT_OUTPUT_PREFIX = {ENV[MODEL]}_ADPUPA_{OBTYPE}_prob + +# sets the -obs_valid_beg command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_BEG = {valid?fmt=%Y%m%d_%H} + +# sets the -obs_valid_end command line argument (optional) +# not used for this example +#POINT_STAT_OBS_VALID_END = {valid?fmt=%Y%m%d_%H} + +# Verification Masking regions +# Indicate which grid and polygon masking region, if applicable +POINT_STAT_GRID = + +# List of full path to poly masking files. NOTE: Only short lists of poly +# files work (those that fit on one line), a long list will result in an +# environment variable that is too long, resulting in an error. For long +# lists of poly masking files (i.e. all the mask files in the NCEP_mask +# directory), define these in the MET point_stat configuration file. +POINT_STAT_POLY = {MET_INSTALL_DIR}/share/met/poly/CONUS.poly +POINT_STAT_STATION_ID = + +# Message types, if all message types are to be returned, leave this empty, +# otherwise indicate the message types of interest. +POINT_STAT_MESSAGE_TYPE = ADPUPA +# Variables and levels as specified in the field dictionary of the MET +# point_stat configuration file. Specify as FCST_VARn_NAME, FCST_VARn_LEVELS, +# (optional) FCST_VARn_OPTION + +# set to True to run PointStat once for each name/level combination +# set to False to run PointStat once per run time including all fields +POINT_STAT_ONCE_PER_FIELD = False + +# fields to compare +# Note: If FCST_VAR_* is set, then a corresponding OBS_VAR_* variable must be set +# To use one variables for both forecast and observation data, set BOTH_VAR_* instead +FCST_VAR1_NAME = TMP_P850_ENS_FREQ_ge288 +FCST_VAR1_LEVELS = P850 +FCST_VAR1_THRESH = ==0.1 + +OBS_VAR1_NAME = TMP +OBS_VAR1_LEVELS = P850 +OBS_VAR1_THRESH = >=288 + +FCST_VAR2_NAME = TMP_P850_ENS_FREQ_ge293 +FCST_VAR2_LEVELS = P850 +FCST_VAR2_THRESH = ==0.1 + +OBS_VAR2_NAME = TMP +OBS_VAR2_LEVELS = P850 +OBS_VAR2_THRESH = >=293 + +FCST_VAR3_NAME = TMP_P850_ENS_FREQ_ge298 +FCST_VAR3_LEVELS = P850 +FCST_VAR3_THRESH = ==0.1 + +OBS_VAR3_NAME = TMP +OBS_VAR3_LEVELS = P850 +OBS_VAR3_THRESH = >=298 + +FCST_VAR4_NAME = TMP_P700_ENS_FREQ_ge273 +FCST_VAR4_LEVELS = P700 +FCST_VAR4_THRESH = ==0.1 + +OBS_VAR4_NAME = TMP +OBS_VAR4_LEVELS = P700 +OBS_VAR4_THRESH = >=273 + +FCST_VAR5_NAME = TMP_P700_ENS_FREQ_ge278 +FCST_VAR5_LEVELS = P700 +FCST_VAR5_THRESH = ==0.1 + +OBS_VAR5_NAME = TMP +OBS_VAR5_LEVELS = P700 +OBS_VAR5_THRESH = >=278 + +FCST_VAR6_NAME = TMP_P700_ENS_FREQ_ge283 +FCST_VAR6_LEVELS = P700 +FCST_VAR6_THRESH = ==0.1 + +OBS_VAR6_NAME = TMP +OBS_VAR6_LEVELS = P700 +OBS_VAR6_THRESH = >=283 + +FCST_VAR7_NAME = TMP_P500_ENS_FREQ_ge258 +FCST_VAR7_LEVELS = P500 +FCST_VAR7_THRESH = ==0.1 + +OBS_VAR7_NAME = TMP +OBS_VAR7_LEVELS = P500 +OBS_VAR7_THRESH = >=258 + +FCST_VAR8_NAME = TMP_P500_ENS_FREQ_ge263 +FCST_VAR8_LEVELS = P500 +FCST_VAR8_THRESH = ==0.1 + +OBS_VAR8_NAME = TMP +OBS_VAR8_LEVELS = P500 +OBS_VAR8_THRESH = >=263 + +FCST_VAR9_NAME = TMP_P500_ENS_FREQ_ge268 +FCST_VAR9_LEVELS = P500 +FCST_VAR9_THRESH = ==0.1 + +OBS_VAR9_NAME = TMP +OBS_VAR9_LEVELS = P500 +OBS_VAR9_THRESH = >=268 + +FCST_VAR10_NAME = DPT_P850_ENS_FREQ_ge273 +FCST_VAR10_LEVELS = P850 +FCST_VAR10_THRESH = ==0.1 + +OBS_VAR10_NAME = DPT +OBS_VAR10_LEVELS = P850 +OBS_VAR10_THRESH = >=273 + +FCST_VAR11_NAME = DPT_P850_ENS_FREQ_ge278 +FCST_VAR11_LEVELS = P850 +FCST_VAR11_THRESH = ==0.1 + +OBS_VAR11_NAME = DPT +OBS_VAR11_LEVELS = P850 +OBS_VAR11_THRESH = >=278 + +FCST_VAR12_NAME = DPT_P850_ENS_FREQ_ge283 +FCST_VAR12_LEVELS = P850 +FCST_VAR12_THRESH = ==0.1 + +OBS_VAR12_NAME = DPT +OBS_VAR12_LEVELS = P850 +OBS_VAR12_THRESH = >=283 + +FCST_VAR13_NAME = DPT_P700_ENS_FREQ_ge263 +FCST_VAR13_LEVELS = P700 +FCST_VAR13_THRESH = ==0.1 + +OBS_VAR13_NAME = DPT +OBS_VAR13_LEVELS = P700 +OBS_VAR13_THRESH = >=263 + +FCST_VAR14_NAME = DPT_P700_ENS_FREQ_ge268 +FCST_VAR14_LEVELS = P700 +FCST_VAR14_THRESH = ==0.1 + +OBS_VAR14_NAME = DPT +OBS_VAR14_LEVELS = P700 +OBS_VAR14_THRESH = >=268 + +FCST_VAR15_NAME = DPT_P700_ENS_FREQ_ge273 +FCST_VAR15_LEVELS = P700 +FCST_VAR15_THRESH = ==0.1 + +OBS_VAR15_NAME = DPT +OBS_VAR15_LEVELS = P700 +OBS_VAR15_THRESH = >=273 + +FCST_VAR16_NAME = WIND_P850_ENS_FREQ_ge5 +FCST_VAR16_LEVELS = P850 +FCST_VAR16_THRESH = ==0.1 + +OBS_VAR16_NAME = WIND +OBS_VAR16_LEVELS = P850 +OBS_VAR16_THRESH = >=5 + +FCST_VAR17_NAME = WIND_P850_ENS_FREQ_ge10 +FCST_VAR17_LEVELS = P850 +FCST_VAR17_THRESH = ==0.1 + +OBS_VAR17_NAME = WIND +OBS_VAR17_LEVELS = P850 +OBS_VAR17_THRESH = >=10 + +FCST_VAR18_NAME = WIND_P850_ENS_FREQ_ge15 +FCST_VAR18_LEVELS = P850 +FCST_VAR18_THRESH = ==0.1 + +OBS_VAR18_NAME = WIND +OBS_VAR18_LEVELS = P850 +OBS_VAR18_THRESH = >=15 + +FCST_VAR19_NAME = WIND_P700_ENS_FREQ_ge10 +FCST_VAR19_LEVELS = P700 +FCST_VAR19_THRESH = ==0.1 + +OBS_VAR19_NAME = WIND +OBS_VAR19_LEVELS = P700 +OBS_VAR19_THRESH = >=10 + +FCST_VAR20_NAME = WIND_P700_ENS_FREQ_ge15 +FCST_VAR20_LEVELS = P700 +FCST_VAR20_THRESH = ==0.1 + +OBS_VAR20_NAME = WIND +OBS_VAR20_LEVELS = P700 +OBS_VAR20_THRESH = >=15 + +FCST_VAR21_NAME = WIND_P700_ENS_FREQ_ge20 +FCST_VAR21_LEVELS = P700 +FCST_VAR21_THRESH = ==0.1 + +OBS_VAR21_NAME = WIND +OBS_VAR21_LEVELS = P700 +OBS_VAR21_THRESH = >=20 + +FCST_VAR22_NAME = WIND_P500_ENS_FREQ_ge15 +FCST_VAR22_LEVELS = P500 +FCST_VAR22_THRESH = ==0.1 + +OBS_VAR22_NAME = WIND +OBS_VAR22_LEVELS = P500 +OBS_VAR22_THRESH = >=15 + +FCST_VAR23_NAME = WIND_P500_ENS_FREQ_ge21 +FCST_VAR23_LEVELS = P500 +FCST_VAR23_THRESH = ==0.1 + +OBS_VAR23_NAME = WIND +OBS_VAR23_LEVELS = P500 +OBS_VAR23_THRESH = >=21 + +FCST_VAR24_NAME = WIND_P500_ENS_FREQ_ge26 +FCST_VAR24_LEVELS = P500 +FCST_VAR24_THRESH = ==0.1 + +OBS_VAR24_NAME = WIND +OBS_VAR24_LEVELS = P500 +OBS_VAR24_THRESH = >=26 + +FCST_VAR25_NAME = WIND_P250_ENS_FREQ_ge26 +FCST_VAR25_LEVELS = P250 +FCST_VAR25_THRESH = ==0.1 + +OBS_VAR25_NAME = WIND +OBS_VAR25_LEVELS = P250 +OBS_VAR25_THRESH = >=26 + +FCST_VAR26_NAME = WIND_P250_ENS_FREQ_ge31 +FCST_VAR26_LEVELS = P250 +FCST_VAR26_THRESH = ==0.1 + +OBS_VAR26_NAME = WIND +OBS_VAR26_LEVELS = P250 +OBS_VAR26_THRESH = >=31 + +FCST_VAR27_NAME = WIND_P250_ENS_FREQ_ge36 +FCST_VAR27_LEVELS = P250 +FCST_VAR27_THRESH = ==0.1 + +OBS_VAR27_NAME = WIND +OBS_VAR27_LEVELS = P250 +OBS_VAR27_THRESH = >=36 + +FCST_VAR28_NAME = WIND_P250_ENS_FREQ_ge46 +FCST_VAR28_LEVELS = P250 +FCST_VAR28_THRESH = ==0.1 + +OBS_VAR28_NAME = WIND +OBS_VAR28_LEVELS = P250 +OBS_VAR28_THRESH = >=46 + +FCST_VAR29_NAME = WIND_P250_ENS_FREQ_ge62 +FCST_VAR29_LEVELS = P250 +FCST_VAR29_THRESH = ==0.1 + +OBS_VAR29_NAME = WIND +OBS_VAR29_LEVELS = P250 +OBS_VAR29_THRESH = >=62 + +FCST_VAR30_NAME = HGT_P500_ENS_FREQ_ge5400 +FCST_VAR30_LEVELS = P500 +FCST_VAR30_THRESH = ==0.1 + +OBS_VAR30_NAME = HGT +OBS_VAR30_LEVELS = P500 +OBS_VAR30_THRESH = >=5400 + +FCST_VAR31_NAME = HGT_P500_ENS_FREQ_ge5600 +FCST_VAR31_LEVELS = P500 +FCST_VAR31_THRESH = ==0.1 + +OBS_VAR31_NAME = HGT +OBS_VAR31_LEVELS = P500 +OBS_VAR31_THRESH = >=5600 + +FCST_VAR32_NAME = HGT_P500_ENS_FREQ_ge5880 +FCST_VAR32_LEVELS = P500 +FCST_VAR32_THRESH = ==0.1 + +OBS_VAR32_NAME = HGT +OBS_VAR32_LEVELS = P500 +OBS_VAR32_THRESH = >=5880 + +FCST_VAR33_NAME = CAPE_L0_ENS_FREQ_le1000 +FCST_VAR33_LEVELS = L0 +FCST_VAR33_THRESH = ==0.1 + +OBS_VAR33_NAME = CAPE +OBS_VAR33_LEVELS = L0-100000 +OBS_VAR33_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR33_THRESH = <=1000 + +FCST_VAR34_NAME = CAPE_L0_ENS_FREQ_gt1000.and.lt2500 +FCST_VAR34_LEVELS = L0 +FCST_VAR34_THRESH = ==0.1 + +OBS_VAR34_NAME = CAPE +OBS_VAR34_LEVELS = L0-100000 +OBS_VAR34_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR34_THRESH = >1000&&<2500 + +FCST_VAR35_NAME = CAPE_L0_ENS_FREQ_gt2500.and.lt4000 +FCST_VAR35_LEVELS = L0 +FCST_VAR35_THRESH = ==0.1 + +OBS_VAR35_NAME = CAPE +OBS_VAR35_LEVELS = L0-100000 +OBS_VAR35_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR35_THRESH = >2500&&<4000 + +FCST_VAR36_NAME = CAPE_L0_ENS_FREQ_gt2500 +FCST_VAR36_LEVELS = L0 +FCST_VAR36_THRESH = ==0.1 + +OBS_VAR36_NAME = CAPE +OBS_VAR36_LEVELS = L0-100000 +OBS_VAR36_OPTIONS = cnt_thresh = [ >0 ]; cnt_logic = UNION; +OBS_VAR36_THRESH =>2500 + +FCST_VAR37_NAME = HPBL_Z0_ENS_FREQ_lt500 +FCST_VAR37_LEVELS = Z0 +FCST_VAR37_THRESH = ==0.1 + +OBS_VAR37_NAME = PBL +OBS_VAR37_LEVELS = L0 +OBS_VAR37_OPTIONS = desc = "TKE"; +OBS_VAR37_THRESH = <500 + +FCST_VAR38_NAME = HPBL_Z0_ENS_FREQ_lt1500 +FCST_VAR38_LEVELS = Z0 +FCST_VAR38_THRESH = ==0.1 + +OBS_VAR38_NAME = PBL +OBS_VAR38_LEVELS = L0 +OBS_VAR38_OPTIONS = desc = "TKE"; +OBS_VAR38_THRESH = <1500 + +FCST_VAR39_NAME = HPBL_Z0_ENS_FREQ_gt1500 +FCST_VAR39_LEVELS = Z0 +FCST_VAR39_THRESH = ==0.1 + +OBS_VAR39_NAME = PBL +OBS_VAR39_LEVELS = L0 +OBS_VAR39_OPTIONS = desc = "TKE"; +OBS_VAR39_THRESH = >1500 + +# Forecast data description variables +FCST_IS_PROB = True +FCST_PROB_IN_GRIB_PDS = False + +# End of [config] section and start of [dir] section +[dir] + +# directory containing input to PB2NC +PB2NC_INPUT_DIR = {ENV[OBS_DIR]} + +# directory to write output from +PB2NC_OUTPUT_DIR = {ENV[EXPTDIR]}/metprd/pb2nc + +INPUT_BASE = {ENV[INPUT_BASE]} + +FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE} +OBS_POINT_STAT_INPUT_DIR = {PB2NC_OUTPUT_DIR} + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_DIR = + +# directory containing climatology mean input to PointStat +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_DIR = + +OUTPUT_BASE = {ENV[EXPTDIR]} +POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE} + +LOG_DIR = {ENV[EXPTDIR]}/log + +STAGING_DIR = {OUTPUT_BASE}/stage/upper_air_prob + +# End of [dir] section and start of [filename_templates] section +[filename_templates] + +# Template to look for prepbvur input to PB2NC relative to PB2NC_INPUT_DIR +PB2NC_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H} + +# Template to use to write output from PB2NC +PB2NC_OUTPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for forecast input to PointStat relative to FCST_POINT_STAT_INPUT_DIR +FCST_POINT_STAT_INPUT_TEMPLATE = ensemble_stat_{ENV[MODEL]}_ADPUPA_{OBTYPE}_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V_ens.nc + +# Template to look for observation input to PointStat relative to OBS_POINT_STAT_INPUT_DIR +OBS_POINT_STAT_INPUT_TEMPLATE = prepbufr.ndas.{valid?fmt=%Y%m%d%H}.nc + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_MEAN_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE = + +# Template to look for climatology input to PointStat relative to POINT_STAT_CLIMO_STDEV_INPUT_DIR +# Not used in this example +POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE = + +#Template for where point-stat output is written +POINT_STAT_OUTPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/metprd/ensemble_stat_prob + +# Specify the name of the metplus.log file +LOG_METPLUS = {LOG_DIR}/metplus.log.{ENV[LOG_SUFFIX]}_upa + +# Specify where the location and name of the final metplus_final.conf +METPLUS_CONF={OUTPUT_BASE}/{ENV[CDATE]}/metprd/ensemble_stat_prob/metplus_final.upper_air.conf diff --git a/ush/templates/parm/metplus/common.conf b/ush/templates/parm/metplus/common.conf new file mode 100644 index 0000000000..01cc667460 --- /dev/null +++ b/ush/templates/parm/metplus/common.conf @@ -0,0 +1,23 @@ +[dir] +# Commonly used base METplus variables +# Location of METplus code +METPLUS_BASE = {ENV[METPLUS_PATH]} + +# Met install location +MET_INSTALL_DIR = {ENV[MET_INSTALL_DIR]} +MET_BASE = {MET_INSTALL_DIR}/share/met +MET_BIN_DIR = {MET_INSTALL_DIR}/{ENV[MET_BIN_EXEC]} + +# Location of METplus parm directory +METPLUS_PARM_BASE = {ENV[METPLUS_CONF]} + +# Location of configuration files used by MET applications +CONFIG_DIR = {METPLUS_BASE}/parm/met_config + +# Other directories +TMP_DIR = /tmp + +[config] +LOG_LEVEL = DEBUG +LOG_MET_VERBOSITY = 2 +LOG_MET_OUTPUT_TO_METPLUS = yes diff --git a/ush/templates/regional_grid.nml b/ush/templates/regional_grid.nml new file mode 100644 index 0000000000..fa175c6d57 --- /dev/null +++ b/ush/templates/regional_grid.nml @@ -0,0 +1,91 @@ +! +!*********************************************************************** +! +! Parameter descriptions: +! ====================== +! +! plon: +! ---- +! Longitude (in degrees) of the center of the regional domain. +! +! plat: +! ---- +! Latitude (in degrees) of the center of the regional domain. +! +! delx: +! ---- +! Grid spacing (in degrees) in the x direction ON THE SUPERGRID. Since +! the supergrid has twice the resolution of the actual grid, the grid +! spacing in the x direction on the actual grid will be twice this re- +! solution. +! +! The physical grid spacing del_dist_x in the x direction on the ACTUAL +! grid is related to delx by +! +! del_dist_x = 2*delx*(circumf_Earth/360 deg) +! +! where circumf_Earth is the Earth's circumference, and the factor of 2 +! appears due to delx being the grid angle in the x direction on the su- +! pergrid. Since circumf_Earth = 2*pi*radius_Earth, then solving the +! above for delx gives +! +! delx = (del_dist_x/(2*radius_Earth))*degs_per_radian +! +! where degs_per_radian = (360 deg/2*pi). For example, to obtain a grid +! with a del_dist_x = 3 km actual grid spacting, we must use +! +! delx = (3 km/(2*6371 km)*(360 deg/(2*pi)) +! = 0.0135 deg +! dely: +! ---- +! Grid spacing (in degrees) in the y direction ON THE SUPERGRID. Since +! the supergrid has twice the resolution of the actual grid, the grid +! spacing in the y direction on the actual grid will be twice this re- +! solution. +! +! lx: +! -- +! Negative of the number of cells in the x direction ON THE SUPERGRID +! from the lower-left corner of the regional domain to the grid center. +! Thus, if nx_SG is the number of cells on the supergrid in the x direc- +! tion, this is simply -nx_SG/2. Since the number of cells on the su- +! pergrid is twice the number of cells on the actual grid, i.e. nx_SG = +! 2*nx where nx is the number of points on the actual grid, then this +! becomes +! +! lx = -nx_SG/2 = -(2*nx)/2 = -nx +! +! To include a halo region of width nhalo cells (where the cells are +! counted on the actual grid), set this to +! +! lx = -(nx + 2*nhalo) +! +! and include nhalo in the calculation of ly, i.e. +! +! ly = -(ny + 2*nhalo) +! +! where ny is the number of cells in the y direction on the actual grid. +! The factor of 2 multiplying nhalo in the above two expressions appears +! because the halo is present on both sides of a given direction (e.g. +! both west and east, both south and north, etc). +! +! ly: +! -- +! Analogous to lx but in the y direction. +! +! pazi: +! ---- +! Rotation angle for the ESG grid in degrees. +! +!*********************************************************************** +! + +®ional_grid_nml + plon = + plat = + delx = + dely = + lx = + ly = + pazi = +/ diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.facsf.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.facsf.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.facsf.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.facsf.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.maximum_snow_albedo.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.maximum_snow_albedo.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.maximum_snow_albedo.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.maximum_snow_albedo.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.slope_type.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.slope_type.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.slope_type.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.slope_type.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.snowfree_albedo.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.snowfree_albedo.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.snowfree_albedo.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.snowfree_albedo.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.soil_type.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.soil_type.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.soil_type.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.soil_type.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.substrate_temperature.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.substrate_temperature.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.substrate_temperature.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.substrate_temperature.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_greenness.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_greenness.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_greenness.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_greenness.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_type.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_type.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_type.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357.vegetation_type.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_grid.tile7.halo3.nc b/ush/test_data/RRFS_CONUS_3km/C3357_grid.tile7.halo3.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_grid.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357_grid.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_grid.tile7.halo6.nc b/ush/test_data/RRFS_CONUS_3km/C3357_grid.tile7.halo6.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_mosaic.halo3.nc b/ush/test_data/RRFS_CONUS_3km/C3357_mosaic.halo3.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_mosaic.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357_mosaic.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_mosaic.halo6.nc b/ush/test_data/RRFS_CONUS_3km/C3357_mosaic.halo6.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_oro_data.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357_oro_data.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_oro_data.tile7.halo4.nc b/ush/test_data/RRFS_CONUS_3km/C3357_oro_data.tile7.halo4.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_oro_data_ls.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357_oro_data_ls.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/RRFS_CONUS_3km/C3357_oro_data_ss.tile7.halo0.nc b/ush/test_data/RRFS_CONUS_3km/C3357_oro_data_ss.tile7.halo0.nc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ush/test_data/suite_FV3_GSD_SAR.xml b/ush/test_data/suite_FV3_GSD_SAR.xml new file mode 100644 index 0000000000..f2b38d5773 --- /dev/null +++ b/ush/test_data/suite_FV3_GSD_SAR.xml @@ -0,0 +1,85 @@ + + + + + + + GFS_time_vary_pre + GFS_rrtmg_setup + GFS_rad_time_vary + GFS_phys_time_vary + + + + + GFS_suite_interstitial_rad_reset + sgscloud_radpre + GFS_rrtmg_pre + GFS_radiation_surface + rrtmg_sw_pre + rrtmg_sw + rrtmg_sw_post + rrtmg_lw_pre + rrtmg_lw + sgscloud_radpost + rrtmg_lw_post + GFS_rrtmg_post + + + + + GFS_suite_interstitial_phys_reset + GFS_suite_stateout_reset + get_prs_fv3 + GFS_suite_interstitial_1 + GFS_surface_generic_pre + GFS_surface_composites_pre + dcyc2t3 + GFS_surface_composites_inter + GFS_suite_interstitial_2 + + + + sfc_diff + GFS_surface_loop_control_part1 + sfc_nst_pre + sfc_nst + sfc_nst_post + lsm_ruc + GFS_surface_loop_control_part2 + + + + GFS_surface_composites_post + sfc_diag + sfc_diag_post + GFS_surface_generic_post + mynnedmf_wrapper + GFS_GWD_generic_pre + cires_ugwp + cires_ugwp_post + GFS_GWD_generic_post + GFS_suite_stateout_update + ozphys_2015 + h2ophys + get_phi_fv3 + + GFS_suite_interstitial_3 + GFS_suite_interstitial_4 + + GFS_MP_generic_pre + mp_thompson_pre + mp_thompson + mp_thompson_post + GFS_MP_generic_post + maximum_hourly_diagnostics + phys_tend + + + + + GFS_stochastics + + + + diff --git a/ush/test_retrieve_data.py b/ush/test_retrieve_data.py new file mode 100644 index 0000000000..78cc0e8cca --- /dev/null +++ b/ush/test_retrieve_data.py @@ -0,0 +1,319 @@ +''' +Functional test suite for gathering data using retreve_data.py. + +The tests reflect some use cases of gathering various model input data +from HPSS and AWS. Obviously, HPSS tests will only be runnable on +machines with access to NOAA's HPSS system. AWS tests will be runnable +on any platform with an internet connection. + +To run the full test suite: + + python -m unittest -b test_retrieve_data.py + + +To run a single test: + + python -m unittest -b test_retrieve_data.FunctionalTesting.test_rap_lbcs_from_aws +''' +import glob +import os +import tempfile +import unittest + +import retrieve_data + +class FunctionalTesting(unittest.TestCase): + + ''' Test class for retrieve data ''' + + def setUp(self): + self.path = os.path.dirname(__file__) + self.config = f'{self.path}/templates/data_locations.yml' + + @unittest.skipIf(os.environ.get('CI') == "true", "Skipping HPSS tests") + def test_fv3gfs_grib2_lbcs_from_hpss(self): + + ''' Get FV3GFS grib2 files from HPSS for LBCS, offset by 6 hours + + ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'fcst', + '--config', self.config, + '--cycle_date', '2022062512', + '--data_stores', 'hpss', + '--external_model', 'FV3GFS', + '--fcst_hrs', '6', '12', '3', + '--output_path', tmp_dir, + '--debug', + '--file_type', 'grib2', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 3) + + @unittest.skipIf(os.environ.get('CI') == "true", "Skipping HPSS tests") + def test_fv3gfs_netcdf_lbcs_from_hpss(self): + + ''' Get FV3GFS netcdf files from HPSS for LBCS. Tests fcst lead + times > 40 hours, since they come from a different archive file. + ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'fcst', + '--config', self.config, + '--cycle_date', '2022060112', + '--data_stores', 'hpss', + '--external_model', 'FV3GFS', + '--fcst_hrs', '24', '48', '24', + '--output_path', tmp_dir, + '--debug', + '--file_type', 'netcdf', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 2) + + # GDAS Tests + def test_gdas_ics_from_aws(self): + + ''' In real time, GDAS is used for LBCS with a 6 hour offset. + ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + out_path_tmpl = f'{tmp_dir}/mem{{mem:03d}}' + + args = [ + '--anl_or_fcst', 'anl', + '--config', self.config, + '--cycle_date', '2022052512', + '--data_stores', 'aws', + '--external_model', 'GDAS', + '--fcst_hrs', '6', '9', '3', + '--output_path', out_path_tmpl, + '--debug', + '--file_type', 'netcdf', + '--members', '9', '10', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + for mem in [9, 10]: + files_on_disk = glob.glob( + os.path.join(out_path_tmpl.format(mem=mem), '*') + ) + self.assertEqual(len(files_on_disk), 2) + + + # GEFS Tests + def test_gefs_grib2_ics_from_aws(self): + + ''' Get GEFS grib2 a & b files for ICS offset by 6 hours. + + ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + out_path_tmpl = f'{tmp_dir}/mem{{mem:03d}}' + + args = [ + '--anl_or_fcst', 'anl', + '--config', self.config, + '--cycle_date', '2022052512', + '--data_stores', 'aws', + '--external_model', 'GEFS', + '--fcst_hrs', '6', + '--output_path', out_path_tmpl, + '--debug', + '--file_type', 'netcdf', + '--members', '1', '2', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + for mem in [1, 2]: + files_on_disk = glob.glob( + os.path.join(out_path_tmpl.format(mem=mem), '*') + ) + self.assertEqual(len(files_on_disk), 2) + + + + # HRRR Tests + @unittest.skipIf(os.environ.get('CI') == "true", "Skipping HPSS tests") + def test_hrrr_ics_from_hpss(self): + + ''' Get HRRR ICS from hpss ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'anl', + '--config', self.config, + '--cycle_date', '2022062512', + '--data_stores', 'hpss', + '--external_model', 'HRRR', + '--fcst_hrs', '0', + '--output_path', tmp_dir, + '--debug', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 1) + + @unittest.skipIf(os.environ.get('CI') == "true", "Skipping HPSS tests") + def test_hrrr_lbcs_from_hpss(self): + + ''' Get HRRR LBCS from hpss for 3 hour boundary conditions ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'fcst', + '--config', self.config, + '--cycle_date', '2022062512', + '--data_stores', 'hpss', + '--external_model', 'HRRR', + '--fcst_hrs', '3', '24', '3', + '--output_path', tmp_dir, + '--debug', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 8) + + def test_hrrr_ics_from_aws(self): + + ''' Get HRRR ICS from aws ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'anl', + '--config', self.config, + '--cycle_date', '2022062512', + '--data_stores', 'aws', + '--external_model', 'HRRR', + '--fcst_hrs', '0', + '--output_path', tmp_dir, + '--debug', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 1) + + def test_hrrr_lbcs_from_aws(self): + + ''' Get HRRR LBCS from aws for 3 hour boundary conditions ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'fcst', + '--config', self.config, + '--cycle_date', '2022062512', + '--data_stores', 'aws', + '--external_model', 'HRRR', + '--fcst_hrs', '3', '24', '3', + '--output_path', tmp_dir, + '--debug', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 8) + + # RAP tests + def test_rap_ics_from_aws(self): + + ''' Get RAP ICS from aws offset by 3 hours ''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'anl', + '--config', self.config, + '--cycle_date', '2022062509', + '--data_stores', 'aws', + '--external_model', 'RAP', + '--fcst_hrs', '3', + '--output_path', tmp_dir, + '--debug', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 1) + + def test_rap_lbcs_from_aws(self): + + ''' Get RAP LBCS from aws for 6 hour boundary conditions offset + by 3 hours. Use 09Z start time for longer LBCS.''' + + with tempfile.TemporaryDirectory(dir='.') as tmp_dir: + + args = [ + '--anl_or_fcst', 'fcst', + '--config', self.config, + '--cycle_date', '2022062509', + '--data_stores', 'aws', + '--external_model', 'RAP', + '--fcst_hrs', '3', '30', '6', + '--output_path', tmp_dir, + '--debug', + ] + + retrieve_data.main(args) + + # Verify files exist in temp dir + + os.chdir(os.path.dirname(__file__)) + path = os.path.join(tmp_dir, '*') + files_on_disk = glob.glob(path) + self.assertEqual(len(files_on_disk), 5) diff --git a/ush/valid_param_vals.yaml b/ush/valid_param_vals.yaml new file mode 100644 index 0000000000..4d6b40278a --- /dev/null +++ b/ush/valid_param_vals.yaml @@ -0,0 +1,84 @@ +# +# Define valid values for various global experiment/workflow variables. +# +valid_vals_RUN_ENVIR: ["nco", "community"] +valid_vals_VERBOSE: [True, False] +valid_vals_DEBUG: [True, False] +valid_vals_MACHINE: ["HERA", "ORION", "JET", "ODIN", "CHEYENNE", "STAMPEDE", "LINUX", "MACOS", "NOAACLOUD", "SINGULARITY", "GAEA"] +valid_vals_SCHED: ["slurm", "pbspro", "lsf", "lsfcray", "none"] +valid_vals_FCST_MODEL: ["ufs-weather-model", "fv3gfs_aqm"] +valid_vals_WORKFLOW_MANAGER: ["rocoto", "none"] +valid_vals_PREDEF_GRID_NAME: [ +"RRFS_CONUS_25km", +"RRFS_CONUS_13km", +"RRFS_CONUS_3km", +"RRFS_CONUScompact_25km", +"RRFS_CONUScompact_13km", +"RRFS_CONUScompact_3km", +"RRFS_SUBCONUS_3km", +"RRFS_AK_13km", +"RRFS_AK_3km", +"CONUS_25km_GFDLgrid", +"CONUS_3km_GFDLgrid", +"EMC_AK", +"EMC_HI", +"EMC_PR", +"EMC_GU", +"GSL_HAFSV0.A_25km", +"GSL_HAFSV0.A_13km", +"GSL_HAFSV0.A_3km", +"GSD_HRRR_AK_50km", +"RRFS_NA_13km", +"RRFS_NA_3km", +"SUBCONUS_Ind_3km", +"WoFS_3km" +] +valid_vals_CCPP_PHYS_SUITE: [ +"FV3_GFS_2017_gfdlmp", +"FV3_GFS_2017_gfdlmp_regional", +"FV3_GFS_v15p2", +"FV3_GFS_v15_thompson_mynn_lam3km", +"FV3_GFS_v16", +"FV3_RRFS_v1beta", +"FV3_HRRR" +] +valid_vals_GFDLgrid_NUM_CELLS: [48, 96, 192, 384, 768, 1152, 3072] +valid_vals_EXTRN_MDL_NAME_ICS: ["GSMGFS", "FV3GFS", "RAP", "HRRR", "NAM"] +valid_vals_EXTRN_MDL_NAME_LBCS: ["GSMGFS", "FV3GFS", "RAP", "HRRR", "NAM"] +valid_vals_USE_USER_STAGED_EXTRN_FILES: [True, False] +valid_vals_FV3GFS_FILE_FMT_ICS: ["nemsio", "grib2", "netcdf"] +valid_vals_FV3GFS_FILE_FMT_LBCS: ["nemsio", "grib2", "netcdf"] +valid_vals_GRID_GEN_METHOD: ["GFDLgrid", "ESGgrid"] +valid_vals_PREEXISTING_DIR_METHOD: ["delete", "rename", "quit"] +valid_vals_GTYPE: ["regional"] +valid_vals_WRTCMP_output_grid: ["rotated_latlon", "lambert_conformal", "regional_latlon"] +valid_vals_RUN_TASK_MAKE_GRID: [True, False] +valid_vals_RUN_TASK_MAKE_OROG: [True, False] +valid_vals_RUN_TASK_MAKE_SFC_CLIMO: [True, False] +valid_vals_RUN_TASK_RUN_POST: [True, False] +valid_vals_WRITE_DOPOST: [True, False] +valid_vals_RUN_TASK_VX_GRIDSTAT: [True, False] +valid_vals_RUN_TASK_VX_POINTSTAT: [True, False] +valid_vals_RUN_TASK_VX_ENSGRID: [True, False] +valid_vals_RUN_TASK_VX_ENSPOINT: [True, False] +valid_vals_QUILTING: [True, False] +valid_vals_PRINT_ESMF: [True, False] +valid_vals_USE_CRON_TO_RELAUNCH: [True, False] +valid_vals_DOT_OR_USCORE: [".", "_"] +valid_vals_NOMADS: [True, False] +valid_vals_NOMADS_file_type: ["GRIB2", "grib2", "NEMSIO", "nemsio"] +valid_vals_DO_ENSEMBLE: [True, False] +valid_vals_USE_CUSTOM_POST_CONFIG_FILE: [True, False] +valid_vals_USE_CRTM: [True, False] +valid_vals_DO_SHUM: [True, False] +valid_vals_DO_SPPT: [True, False] +valid_vals_DO_SPP: [True, False] +valid_vals_DO_LSM_SPP: [True, False] +valid_vals_DO_SKEB: [True, False] +valid_vals_USE_ZMTNBLCK: [True, False] +valid_vals_USE_FVCOM: [True, False] +valid_vals_FVCOM_WCSTART: ["warm", "WARM", "cold", "COLD"] +valid_vals_COMPILER: ["intel", "gnu"] +valid_vals_SUB_HOURLY_POST: [True, False] +valid_vals_DT_SUBHOURLY_POST_MNTS: [0, 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30] +valid_vals_USE_MERRA_CLIMO: [True, False] diff --git a/ush/wrappers/README.md b/ush/wrappers/README.md new file mode 100644 index 0000000000..2775d0fba7 --- /dev/null +++ b/ush/wrappers/README.md @@ -0,0 +1,40 @@ +Each workflow task has a wrapper script to set environment variables and run the job script + +The experiment-generation step MUST be done FIRST! generate_FV3SAR_wflow.sh + +There is an example batch-submit script for hera (Slurm) and cheyenne (PBS). These examples set the build and run environment for hera or cheyenne, so that run-time libraries match the compiled libraries (i.e. netcdf, mpi). + +Users may either modify the one batch submit script as each task is submitted, or duplicate this batch wrapper for their system settings, for each task. Alternatively, some batch systems allow users to specify most of the settings on the command line (with the sbatch or qsub command, for example). This piece will be unique to your system - use the examples, but expect that you will need to change things! + +Tasks with the same Stage level may be run concurrently (no dependency). + +``` + +Stage/step Task Run Script #procs Wall clock time + (on cheyenne, hera) + ========= =============== ====== =============== + 1 run_get_ics.sh 1 0:20 - depends on HPSS vs FTP vs staged-on-disk + 1 run_get_lbcs.sh 1 0:20 - depends on HPSS vs FTP vs staged-on-disk + 1 run_make_grid.sh 24 0:20 + 2 run_make_orog.sh 24 0:20 + 3 run_make_sfc_climo.sh 48 0:20 + 4 run_make_ics.sh 48 0:30 + 4 run_make_lbcs.sh 48 0:30 + 5 run_fcst.sh 48 2:30 + 6 run_post.sh 48 0:25 - 2min per output forecast hour + +``` + +QuickStart: +1. clone, and build the ufs-srweather-app: https://github.com/ufs-community/ufs-srweather-app/wiki/Getting-Started +2. Generate an experiment configuration: https://github.com/ufs-community/ufs-srweather-app/wiki/Getting-Started +3. CD to the experiment directory +4. SET the environment variable EXPTDIR: setenv EXPTDIR `pwd` //or// export EXPTDIR=`pwd` +5. COPY the wrapper scripts from the workflow directory: cp ufs-srweather-app/regional-workflow/ush/wrappers/* . +6. Run each of the listed scripts, in the order given. Scripts with the same stage-# may be run simultaneously. + - On most HPC systems, you will need to submit a batch job to run the multi-processor jobs + - On some HPC systems, you can run the first two jobs (serial) on a login node/command-line + - Example scripts for Slurm (hera) and for PBS (cheyenne) are provided. These will need to be adapted to your system + - This batch-submit script is hard-coded per task, so will need to be modified or copied to run each task + + diff --git a/ush/wrappers/qsub_job.sh b/ush/wrappers/qsub_job.sh new file mode 100755 index 0000000000..8cd49aa57c --- /dev/null +++ b/ush/wrappers/qsub_job.sh @@ -0,0 +1,47 @@ +#!/bin/sh +#PBS -A XXXXXXXXX +#PBS -q regular +#PBS -l select=1:mpiprocs=24:ncpus=24 +##PBS -l select=1:mpiprocs=1:ncpus=1 # USE FOR MET VERIFICATION +#PBS -l walltime=02:30:00 +#PBS -N run_make_grid +#PBS -j oe -o /path/to/exptdir/log/run_make_grid.log # NEED TO SET +cd /path/to/exptdir # NEED TO SET +set -x +# +source /etc/profile.d/modules.sh +module load ncarenv/1.3 +module load intel/19.0.2 +module load mpt/2.19 +module load ncarcompilers/0.5.0 +module load netcdf/4.6.3 + +module use -a /glade/p/ral/jntp/GMTB/tools/modulefiles/intel-19.0.2/mpt-2.19 +module load esmf/8.0.0 +# +# Different modules are needed for the UFS_UTILS/mpi jobs... why are they using impi anyway??? +## make_sfc_climo make_ics make_lbcs +# +##module load ncarenv/1.3 +##module load intel/19.0.2 +##module load ncarcompilers/0.5.0 +##module load impi/2019.2.187 +##module load netcdf/4.6.3 +# +##module use -a /glade/p/ral/jntp/GMTB/tools/modulefiles/intel-19.0.2/impi-2019.2.187 +##module load esmf/8.0.0_bs50 +# +./run_make_grid.sh +# +# +# Additional modules are needed for MET verification jobs +# +#module use /glade/p/ral/jntp/MET/MET_releases/modulefiles +#module load met/10.0.0 +#module load conda/latest +#conda activate /glade/p/ral/jntp/UFS_SRW_app/conda/python_graphics + +#./run_pointvx.sh # Run grod-to-point deterministic vx +#./run_gridvx.sh # Run grid-stat deterministic vx +#./run_pointensvx.sh # Run grid-to-point ensemble/probabilsitic vx +#./rungridensvx.sh # Run grid-to-grid ensemble/probabilsitic vx diff --git a/ush/wrappers/run_fcst.sh b/ush/wrappers/run_fcst.sh new file mode 100755 index 0000000000..f5abf5e5d5 --- /dev/null +++ b/ush/wrappers/run_fcst.sh @@ -0,0 +1,11 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export SLASH_ENSMEM_SUBDIR="" +export ENSMEM_INDX="" + +${JOBSDIR}/JREGIONAL_RUN_FCST + diff --git a/ush/wrappers/run_get_ics.sh b/ush/wrappers/run_get_ics.sh new file mode 100755 index 0000000000..69b0a6bccf --- /dev/null +++ b/ush/wrappers/run_get_ics.sh @@ -0,0 +1,12 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} + +# get the ICS files +export ICS_OR_LBCS="ICS" +export EXTRN_MDL_NAME=${EXTRN_MDL_NAME_ICS} +${JOBSDIR}/JREGIONAL_GET_EXTRN_MDL_FILES + diff --git a/ush/wrappers/run_get_lbcs.sh b/ush/wrappers/run_get_lbcs.sh new file mode 100755 index 0000000000..07da389400 --- /dev/null +++ b/ush/wrappers/run_get_lbcs.sh @@ -0,0 +1,11 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} + +# get the LBCS files +export ICS_OR_LBCS="LBCS" +export EXTRN_MDL_NAME=${EXTRN_MDL_NAME_LBCS} +${JOBSDIR}/JREGIONAL_GET_EXTRN_MDL_FILES diff --git a/ush/wrappers/run_gridensvx.sh b/ush/wrappers/run_gridensvx.sh new file mode 100755 index 0000000000..d6a3c76aff --- /dev/null +++ b/ush/wrappers/run_gridensvx.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# Stand-alone script to run grid-to-grid ensemble verification +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export cyc=${CYCL_HRS} +export PDY=${DATE_FIRST_CYCL} +export OBS_DIR=${MRMS_OBS_DIR} # CCPA_OBS_DIR MRMS_OBS_DIR +export VAR="REFC" # APCP REFC RETOP +export ACCUM="" # 01 03 06 24 --> leave empty for REFC and RETOP + +export FHR=`echo $(seq 0 ${ACCUM} ${FCST_LEN_HRS}) | cut -d" " -f2-` + +${JOBSDIR}/JREGIONAL_RUN_VX_ENSGRID + +${JOBSDIR}/JREGIONAL_RUN_VX_ENSGRID_MEAN + +${JOBSDIR}/JREGIONAL_RUN_VX_ENSGRID_PROB + diff --git a/ush/wrappers/run_gridvx.sh b/ush/wrappers/run_gridvx.sh new file mode 100755 index 0000000000..a96383f6ed --- /dev/null +++ b/ush/wrappers/run_gridvx.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# Stand-alone script to run grid-to-grid verification +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export cyc=${CYCL_HRS} +export PDY=${DATE_FIRST_CYCL} +export SLASH_ENSMEM_SUBDIR="" # When running with do_ensemble = true, need to run for each member, e.g., "/mem1" +export OBS_DIR=${CCPA_OBS_DIR} # CCPA_OBS_DIR MRMS_OBS_DIR +export VAR="APCP" # APCP REFC RETOP +export ACCUM="06" # 01 03 06 24 --> leave empty for REFC and RETOP + +export FHR=`echo $(seq 0 ${ACCUM} ${FCST_LEN_HRS}) | cut -d" " -f2-` + +${JOBSDIR}/JREGIONAL_RUN_VX_GRIDSTAT + diff --git a/ush/wrappers/run_make_grid.sh b/ush/wrappers/run_make_grid.sh new file mode 100755 index 0000000000..96fd8a4ec4 --- /dev/null +++ b/ush/wrappers/run_make_grid.sh @@ -0,0 +1,8 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} + +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +${JOBSDIR}/JREGIONAL_MAKE_GRID diff --git a/ush/wrappers/run_make_ics.sh b/ush/wrappers/run_make_ics.sh new file mode 100755 index 0000000000..de3d3de6d2 --- /dev/null +++ b/ush/wrappers/run_make_ics.sh @@ -0,0 +1,10 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export SLASH_ENSMEM_SUBDIR="" + +${JOBSDIR}/JREGIONAL_MAKE_ICS + diff --git a/ush/wrappers/run_make_lbcs.sh b/ush/wrappers/run_make_lbcs.sh new file mode 100755 index 0000000000..adae78ea4a --- /dev/null +++ b/ush/wrappers/run_make_lbcs.sh @@ -0,0 +1,10 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export SLASH_ENSMEM_SUBDIR="" + +${JOBSDIR}/JREGIONAL_MAKE_LBCS + diff --git a/ush/wrappers/run_make_orog.sh b/ush/wrappers/run_make_orog.sh new file mode 100755 index 0000000000..cf1adab4c4 --- /dev/null +++ b/ush/wrappers/run_make_orog.sh @@ -0,0 +1,8 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} + +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +${JOBSDIR}/JREGIONAL_MAKE_OROG diff --git a/ush/wrappers/run_make_sfc_climo.sh b/ush/wrappers/run_make_sfc_climo.sh new file mode 100755 index 0000000000..06c9260793 --- /dev/null +++ b/ush/wrappers/run_make_sfc_climo.sh @@ -0,0 +1,8 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} + +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +${JOBSDIR}/JREGIONAL_MAKE_SFC_CLIMO diff --git a/ush/wrappers/run_pointensvx.sh b/ush/wrappers/run_pointensvx.sh new file mode 100755 index 0000000000..142d9ec833 --- /dev/null +++ b/ush/wrappers/run_pointensvx.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# Stand-alone script to run grid-to-point ensemble verification +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export cyc=${CYCL_HRS} +export PDY=${DATE_FIRST_CYCL} +export OBS_DIR=${NDAS_OBS_DIR} + +export FHR=`echo $(seq 0 1 ${FCST_LEN_HRS})` + +${JOBSDIR}/JREGIONAL_RUN_VX_ENSPOINT + +${JOBSDIR}/JREGIONAL_RUN_VX_ENSPOINT_MEAN + +${JOBSDIR}/JREGIONAL_RUN_VX_ENSPOINT_PROB + diff --git a/ush/wrappers/run_pointvx.sh b/ush/wrappers/run_pointvx.sh new file mode 100755 index 0000000000..527c16f37d --- /dev/null +++ b/ush/wrappers/run_pointvx.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +# Stand-alone script to run grid-to-point verification +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export cyc=${CYCL_HRS} +export PDY=${DATE_FIRST_CYCL} +export SLASH_ENSMEM_SUBDIR="" # When running with do_ensemble = true, need to run for each member, e.g., "/mem1" +export OBS_DIR=${NDAS_OBS_DIR} + +export FHR=`echo $(seq 0 1 ${FCST_LEN_HRS})` + +${JOBSDIR}/JREGIONAL_RUN_VX_POINTSTAT + diff --git a/ush/wrappers/run_post.sh b/ush/wrappers/run_post.sh new file mode 100755 index 0000000000..1c8f3d4dfb --- /dev/null +++ b/ush/wrappers/run_post.sh @@ -0,0 +1,15 @@ +#!/bin/sh +export GLOBAL_VAR_DEFNS_FP="${EXPTDIR}/var_defns.sh" +set -x +source ${GLOBAL_VAR_DEFNS_FP} +export CDATE=${DATE_FIRST_CYCL}${CYCL_HRS} +export CYCLE_DIR=${EXPTDIR}/${CDATE} +export cyc=${CYCL_HRS} +export SLASH_ENSMEM_SUBDIR="" +export ENSMEM_INDX="" + +num_fcst_hrs=${FCST_LEN_HRS} +for (( i=0; i<=$((num_fcst_hrs)); i++ )); do + export fhr=`printf "%03i" ${i}` + ${JOBSDIR}/JREGIONAL_RUN_POST +done diff --git a/ush/wrappers/sq_job.sh b/ush/wrappers/sq_job.sh new file mode 100755 index 0000000000..a9fa3c1805 --- /dev/null +++ b/ush/wrappers/sq_job.sh @@ -0,0 +1,58 @@ +#!/bin/sh +#SBATCH -e /path/to/exptdir/log/run_make_grid.log # NEED TO SET +#SBATCH --account=XXXXXXXXX +#SBATCH --qos=batch +#SBATCH --ntasks=48 +##SBATCH --ntasks=1 # USE FOR MET VERIFICATION +#SBATCH --time=20 +#SBATCH --job-name="run_make_grid" +cd /path/to/exptdir # NEED TO SET +set -x +. /apps/lmod/lmod/init/sh + +module purge +module load hpss + +module load intel/18.0.5.274 +module load impi/2018.0.4 +module load wgrib2 +############ +# use this netcdf for most of the tasks +module load netcdf/4.7.0 +############ + +############ +# use this version for make_sfc_climo, make_ics and make_lbcs +#module load netcdf/4.6.1 +############ + +module load hdf5/1.10.5 + +############ +# use this for the forecast model +#module use -a /scratch1/NCEPDEV/nems/emc.nemspara/soft/modulefiles +#module load hdf5_parallel/1.10.6 +#module load netcdf_parallel/4.7.4 +#module load esmf/8.0.0_ParallelNetCDF +############ + + +module use -a /contrib/miniconda3/modulefiles +module load miniconda3 +conda activate regional_workflow + +./run_make_grid.sh +# +# +# Additional modules are needed for MET verification jobs +# +#module use -a /contrib/anaconda/modulefiles +#module load intel/18.0.5.274 +#module load anaconda/latest +#module use -a /contrib/met/modulefiles/ +#module load met/10.0.0 + +#./run_pointvx.sh # Run grod-to-point deterministic vx +#./run_gridvx.sh # Run grid-stat deterministic vx +#./run_pointensvx.sh # Run grid-to-point ensemble/probabilsitic vx +#./run_gridensvx.sh # Run grid-to-grid ensemble/probabilsitic vx