diff --git a/.github/parm/use_case_groups.json b/.github/parm/use_case_groups.json index db716d52c5..5684f4f2cd 100644 --- a/.github/parm/use_case_groups.json +++ b/.github/parm/use_case_groups.json @@ -61,12 +61,12 @@ }, { "category": "marine_and_cryosphere", - "index_list": "0-1", + "index_list": "0-2", "run": false }, { "category": "marine_and_cryosphere", - "index_list": "2-5", + "index_list": "3-5", "run": false }, { @@ -264,6 +264,11 @@ "index_list": "13", "run": false }, + { + "category": "short_range", + "index_list": "14", + "run": false + }, { "category": "space_weather", "index_list": "0-1", diff --git a/docs/_static/short-range_UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.png b/docs/_static/short-range_UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.png new file mode 100644 index 0000000000..3dfa948d3c Binary files /dev/null and b/docs/_static/short-range_UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.png differ diff --git a/docs/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot_ecnt_spread_skill.py b/docs/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot_ecnt_spread_skill.py new file mode 100755 index 0000000000..c48e6c6cec --- /dev/null +++ b/docs/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot_ecnt_spread_skill.py @@ -0,0 +1,255 @@ +""" +UserScript: Reformat MET .stat ECNT data, calculate aggregation statistics, and generate a spread skill plot +====================================================================================================================== + +model_applications/ +short_range/ +UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot_ecnt_spread_skill.py + +""" + +################################################################################# +# Scientific Objective +# -------------------- +# +# This use case illustrates how to use MET .stat output (using the ECNT linetype data) to generate a +# spread skill plot using a subset of the METplus Analysis Tools (METdataio, METcalcpy, +# and METplotpy). The METdataio METreformat module extracts the ECNT linetype data and +# performs reformatting, the METcalcpy agg-stat module performs aggregation, and the +# METplotpy line plot is used to generate the spread skill plot. +# + +################################################################################# +# Datasets +# -------- +# +# * Forecast dataset: RRFS GEFS (Rapid Refresh Forecast System Global Ensemble Forecast System) +# * Observation dataset: None +# +# **Input**: MET .stat files from MET ensemble-stat tool for RRFS for 20220506 +# +# **Location**: All the input data required for this use case can be found in the met_test sample data tarball +# (**sample_data-short_range.tgz**). +# +# Click here to see the METplus releases page and download sample data for the appropriate +# release: https://github.com/dtcenter/METplus/releases +# +# See `Running METplus `_ +# section for more information. +# +# **This tarball should be unpacked into the directory corresponding to the value of INPUT_BASE** in the +# `User Configuration File `_ +# section. +# + +############################################################################# +# External Dependencies +# --------------------- +# You will need to use the version of Python that is required for the METplus version +# in use. Refer to the Installation section of the User's Guide for basic Python requirements: +# https://metplus.readthedocs.io/en/latest/Users_Guide/installation.html +# +# The METplus Analysis tools: METdataio, METcalcpy, and METplotpy have the additional third-party +# Python package requirements. The version numbers are found in the requirements.txt file found at the +# top-level directory of each repository. +# +# * lxml +# * pandas +# * pyyaml +# * numpy +# * netcdf4 +# * xarray +# * scipy +# * metpy +# * pint +# * python-dateutil +# * kaleido (python-kaleido) +# * plotly +# * matplotlib + + + +############################################################################## +# METplus Components +# ------------------ +# +# This use case runs the UserScript wrapper tool to run a user provided script, +# in this case, reformat_ecnt_linetype.py, agg_stat_ecnt.py and plot_spread_skill.py. +# It also requires the METdataio, METcalcpy and METplotpy source code to reformat the MET .stat output, +# perform aggregation, and generate the plot. Clone the METdataio repository +# (https://github.com/dtcenter/METdataio), +# METcalcpy repository (https://github.com/dtcenter/METcalcpy, and the METplotpy +# repository (https://github.com/dtcenter/METplotpy) under the same base directory as the +# METPLUS_BASE directory so that the METdataio, METcalcpy, and METplotpy directories are under the +# same base directory (i.e. if the METPLUS_BASE directory is /home/username/working/METplus, +# then clone the METdataio, METcalcpy and METplotpy source code into the /home/username/working directory) +# +# Clone the METdataio, METcalcpy, and METplotpy source code from their repositories under a base directory. The +# repositories are located: +# +# * https://github.com/dtcenter/METdataio +# * https://github.com/dtcenter/METcalcpy +# * https://github.com/dtcenter/METplotpy +# +# +# +# Define the OUTPUT_BASE, INPUT_BASE, and MET_INSTALL_DIR settings in the user +# configuration file. For instructions on how to set up the user configuration file, refer to the `User ConfigurationFile +# `_ section. +# + + +############################################################################## +# METplus Workflow +# ---------------- +# +# This use case reads in the MET .stat output that contains the ECNT linetype (from +# the MET ensemble-stat tool). The .stat output *MUST* reside under one directory. +# If .stat files are spread among multiple directories, these must be consolidated under a +# single directory. +# The use case loops over three processes: reformatting, aggregating, and plotting. +# + + +############################################################################## +# METplus Configuration +# --------------------- +# +# METplus first loads all the configuration files found in parm/metplus_config, +# then it loads any configuration files passed to METplus via the command line +# with the -c option, i.e. -c parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf +# +# .. highlight:: bash +# .. literalinclude:: ../../../../parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf +# + +############################################################################# +# MET Configuration +# --------------------- +# +# There are no MET tools used in this use case. The use case uses MET .stat +# output as input for the reformatting step. +# + +############################################################################## +# Python Embedding +# ---------------- +# +# There is no python embedding in this use case +# + +############################################################################## +# Python Scripts +# ---------------- +# This use case uses Python scripts to invoke the METdataio reformatter, the METcalcpy aggregator, and the METplotpy +# line plot. +# +# The following Python script (from METdataio) is used to reformat the MET .stat ECNT linetype data +# into a format that can be used by the aggregating script. +# +# .. highlight:: python +# .. literalinclude:: ../../../../parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt_linetype.py +# +# This Python script (from METcalcpy) is used to calculate aggregation statistics for the ECNT linetype. +# +# .. highlight:: python +# .. literalinclude:: ../../../../parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.py +# +# Finally,this Python script (from METplotpy) is used to generate a spread-skill plot using the METplotypy line plot code. +# +# .. highlight:: python +# .. literalinclude:: ../../../../parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.py +# + +############################################################################## +# Running METplus +# --------------- +# +# This use case can be run two ways: +# +# 1) Passing in UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf, +# then a user-specific system configuration file:: +# +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf -c /path/to/user_system.conf +# +# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf:: +# +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf +# +# The former method is recommended. Whether you add them to a user-specific configuration file or modify the metplus_config files, the following variables must be set correctly: +# +# * **INPUT_BASE** - Path to directory where sample data tarballs are unpacked (See Datasets section to obtain tarballs). This is not required to run METplus, but it is required to run the examples in parm/use_cases +# * **OUTPUT_BASE** - Path where METplus output will be written. This must be in a location where you have write permissions +# * **MET_INSTALL_DIR** - Path to location where MET is installed locally +# +# and for the [exe] section, you will need to define the location of NON-MET executables. +# If the executable is in the user's path, METplus will find it from the name. +# If the executable is not in the path, specify the full path to the executable here (i.e. RM = /bin/rm) +# The following executables are required for performing series analysis use cases: +# +# Example User Configuration File:: +# +# [config] +# INPUT_BASE = /path/to/sample/input/data +# OUTPUT_BASE = /path/to/output/dir +# MET_INSTALL_DIR = /path/to/met-X.Y +# +# +# [exe] +# RM = /path/to/rm +# CUT = /path/to/cut +# TR = /path/to/tr +# NCAP2 = /path/to/ncap2 +# CONVERT = /path/to/convert +# NCDUMP = /path/to/ncdump +# + +############################################################################## +# Expected Output +# ---------------- +# +# A successful run will output the following both to the screen and to the logfile, one for the +# reformat, aggregate, and plot steps of the use case:: +# +# INFO: METplus has successfully finished running. +# +# +# **Reformat Output** +# +# The reformatted ensemble-stat ECNT linetype data should exist in the location specified in the user +# configuration file (OUTPUT_BASE). Verify that the ensemble_stat_ecnt.data file exists. The file now has all +# the statistics under the stat_name and stat_value columns, all ECNT statistic columns labelled with their +# corresponding names (e.g. crps, crpss, rmse, etc.) and confidence level values under the +# following columns: stat_btcl and stat_btcu +# +# +# **Aggregation Output** +# +# The METcalcpy agg_stat module is used to calculate aggregated statistics and confidence intervals for each +# series (line) point. +# +# **Plot Output** +# +# A spread-skill plot of temperature for the RMSE, SPREAD_PLUS_OERR, and a ratio line of SPREAD_PLUS_OERR/RMSE is +# created and found in the output location specified in the user configuration file (OUTPUT_BASE). The plot is named +# short-range_UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.png +# +# + +############################################################################## +# Keywords +# -------- +# +# .. note:: +# +# * UserScriptUseCase +# * ShortRangeAppUseCase +# * METdataioUseCase +# * METcalcpyUseCase +# * METplotpyUseCase +# +# Navigate to the :ref:`quick-search` page to discover other similar use cases. +# +# +# +# sphinx_gallery_thumbnail_path = '_static/short-range_UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.png' diff --git a/internal/tests/use_cases/all_use_cases.txt b/internal/tests/use_cases/all_use_cases.txt index 6bb6af4eff..658f73d3dd 100644 --- a/internal/tests/use_cases/all_use_cases.txt +++ b/internal/tests/use_cases/all_use_cases.txt @@ -175,6 +175,7 @@ Category: short_range 11::UserScript_fcstFV3_fcstOnly_PhysicsTendency_VerticalProfile::model_applications/short_range/UserScript_fcstFV3_fcstOnly_PhysicsTendency_VerticalProfile.conf:: metplotpy_env 12::UserScript_fcstFV3_fcstOnly_PhysicsTendency_VerticalCrossSection::model_applications/short_range/UserScript_fcstFV3_fcstOnly_PhysicsTendency_VerticalCrossSection.conf:: metplotpy_env 13::MODEMultivar_fcstHRRR_obsMRMS_HRRRanl::model_applications/short_range/MODEMultivar_fcstHRRR_obsMRMS_HRRRanl.conf +14::UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot::model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf:: metdataio, metcalcpy, metplotpy,mp_analysis_env Category: space_weather diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf new file mode 100755 index 0000000000..6ee8473174 --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf @@ -0,0 +1,67 @@ +[config] + +# Documentation for this use case can be found at +# https://metplus.readthedocs.io/en/latest/generated/model_applications/short-range/UserScript_fcstRRFS_obsOnly_Reformat_Aggregate_Plot.html + +# For additional information, please see the METplus Users Guide. +# https://metplus.readthedocs.io/en/latest/Users_Guide + +### +# Processes to run +# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#process-list +### + +PROCESS_LIST = UserScript(reformatter), UserScript(aggregate), UserScript(plotting) + +### +# Time Info +# LOOP_BY 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 +# LEAD_SEQ is the list of forecast leads to process +# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#timing-control +### + +LOOP_BY = VALID +VALID_TIME_FMT = %Y%m%d_%H%M%S +VALID_BEG = 20220506_000000 + +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE +LOOP_ORDER = processes + +### +# UserScript Settings +# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#userscript +### + + +[user_env_vars] +REFORMAT_YAML_CONFIG_NAME = {PARM_BASE}/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt.yaml +AGGREGATE_YAML_CONFIG_NAME = {PARM_BASE}/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.yaml +PLOTTING_YAML_CONFIG_NAME = {PARM_BASE}/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.yaml +REFORMAT_INPUT_BASE = {INPUT_BASE}/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot +REFORMAT_OUTPUT_BASE = {OUTPUT_BASE}/reformatted +AGGREGATE_INPUT_BASE = {REFORMAT_OUTPUT_BASE} +AGGREGATE_OUTPUT_BASE = {OUTPUT_BASE}/aggregated +PLOT_INPUT_BASE = {AGGREGATE_OUTPUT_BASE} +PLOT_OUTPUT_BASE = {OUTPUT_BASE}/plot +METDATAIO_BASE = {METPLUS_BASE}/../METdataio +METCALCPY_BASE = {METPLUS_BASE}/../METcalcpy +METPLOTPY_BASE = {METPLUS_BASE}/../METplotpy +PYTHONPATH = {METDATAIO_BASE}:{METDATAIO_BASE}/METdbLoad:{METDATAIO_BASE}/METdbLoad/ush:{METDATAIO_BASE}/METreformat:{METCALCPY_BASE}:{METCALCPY_BASE}/metcalcpy:{METPLOTPY_BASE}:{METPLOTPY_BASE}/metplotpy/plots + + +[reformatter] +USER_SCRIPT_COMMAND = {PARM_BASE}/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt_linetype.py + +[aggregate] +USER_SCRIPT_COMMAND = {PARM_BASE}/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.py + +[plotting] +USER_SCRIPT_COMMAND = {PARM_BASE}/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.py + + + + diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.py b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.py new file mode 100755 index 0000000000..4766dd500e --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + + +import os +import time +import logging +import pandas as pd +import yaml +from metcalcpy.util import read_env_vars_in_config as readconfig +from metcalcpy.agg_stat import AggStat + +logger = logging.getLogger(__name__) + +def main(): + ''' + Read in the config file (with ENVIRONMENT variables defined in the + UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf). Invoke METcalcpy agg_stat module to + calculate the aggregation statistics, clean up the data so it is compatible for the METplotpy line plot + and write a tab-separated ASCII file. + + ''' + + start_agg_step = time.time() + + # Read in the YAML configuration file. Environment variables in + # the configuration file are supported. + try: + input_config_file = os.getenv("AGGREGATE_YAML_CONFIG_NAME", "aggregate_ecnt.yaml") + settings = readconfig.parse_config(input_config_file) + logger.info(settings) + except yaml.YAMLError as exc: + logger.error(exc) + + # Calculate the aggregation statistics using METcalcpy agg_stat + agg_begin = time.time() + try: + os.mkdir(os.getenv("AGGREGATE_OUTPUT_BASE")) + except OSError: + # Directory already exists, ignore error. + pass + + AGG_STAT = AggStat(settings) + AGG_STAT.calculate_stats_and_ci() + agg_finish = time.time() + time_for_aggregation = agg_finish - agg_begin + logger.info("Total time for calculating aggregation statistics (in seconds): {time_for_aggregation}") + + # Add a 'dummy' column (fcst_valid with the same values as fcst_lead) + # to the output data. The aggregation was based + # on the fcst_lead BUT the line plot requires a *second* time-related + # column (i.e. fcst_init_beg, fcst_valid, etc.) to identify unique + # points. In this case, the aggregated data already consists of + # unique points. If any other time column was used, this + # step would not be required. + output_file = settings['agg_stat_output'] + df = pd.read_csv(output_file, sep='\t') + df['fcst_valid'] = df['fcst_lead'] + df.to_csv(output_file, sep='\t') + + finish_agg = time.time() + total_agg_step = finish_agg - start_agg_step + logger.info("Total time for performing the aggregation step (in sec): {total_agg_step} ") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.yaml b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.yaml new file mode 100644 index 0000000000..4d94d41809 --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/aggregate_ecnt.yaml @@ -0,0 +1,41 @@ +agg_stat_input: !ENV '${AGGREGATE_INPUT_BASE}/ensemble_stat_ecnt.data' +agg_stat_output: !ENV '${AGGREGATE_OUTPUT_BASE}/ecnt_aggregated.data' +alpha: 0.05 +append_to_file: null +circular_block_bootstrap: True +derived_series_1: [] +derived_series_2: [] +event_equal: False +fcst_var_val_1: + TMP: + - ECNT_RMSE + - ECNT_SPREAD_PLUS_OERR +fcst_var_val_2: {} +indy_vals: +- '30000' +- '40000' +- '60000' +- '90000' +- '120000' +- '150000' +- '160000' +- '170000' +- '180000' +- '200000' +- '240000' +- '270000' + +indy_var: fcst_lead +line_type: ecnt +list_stat_1: + - ECNT_RMSE + - ECNT_SPREAD_PLUS_OERR +list_stat_2: [] +method: perc +num_iterations: 1 +num_threads: -1 +random_seed: null +series_val_1: + model: + - RRFS_GEFS_GF.SPP.SPPT +series_val_2: {} diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.py b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.py new file mode 100755 index 0000000000..d482ba5d4e --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + + +import os +from time import perf_counter +import logging +import yaml +import metcalcpy.util.read_env_vars_in_config as readconfig +from metplotpy.plots.line import line + +def main(): + + # Read in the YAML configuration file. Environment variables in + # the configuration file are supported. + try: + input_config_file = os.getenv("PLOTTING_YAML_CONFIG_NAME", "plot_spread_skill.yaml") + settings = readconfig.parse_config(input_config_file) + logging.info(settings) + except yaml.YAMLError as exc: + logging.error(exc) + + try: + start = perf_counter() + plot = line.Line(settings) + plot.save_to_file() + plot.write_html() + plot.write_output_file() + end = perf_counter() + execution_time = end - start + plot.line_logger.info(f"Finished creating line plot, execution time: {execution_time} seconds") + except ValueError as val_er: + print(val_er) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.yaml b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.yaml new file mode 100644 index 0000000000..2b1951bd82 --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/plot_spread_skill.yaml @@ -0,0 +1,281 @@ +alpha: 0.05 +box_avg: 'False' +box_boxwex: 0.2 +box_notch: 'False' +box_outline: 'True' +box_pts: 'False' +caption_align: 0.0 +caption_col: '#333333' +caption_offset: 3.0 +caption_size: 0.8 +caption_weight: 1 +cex: 1 + +colors: +# Colors for each line that will be generated. +# Accessible colors https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40 +- '#D41159' # reddish +- '#4B0092' # purple-ish +- '#1Aff1A' # lime green-ish + + +con_series: +- 1 +- 1 +- 1 + +create_html: 'False' + +# Two derived series (lines) are supported (i.e. difference or ratio lines: DIFF or RATIO). +derived_series_1: + # Generate the ratio line of the ECNT spread_plus_oerr/rmse for temperature and the + # The first line is the top portion (left side) of the ratio, the second is the bottom (right side), and the + # third line indicates the type of derived line (i.e. RATIO or DIFF). This is a list of lists, so remember + # to have two '-' at the start of the first line ( - - 'model var stat') + # + # RRFS_GEFS_GF.SPP.SPPT model for temperature and the SPREAD_PLUS_OERR and RMSE statistics. + # +- - RRFS_GEFS_GF.SPP.SPPT TMP ECNT_SPREAD_PLUS_OERR + - RRFS_GEFS_GF.SPP.SPPT TMP ECNT_RMSE + - RATIO + +derived_series_2: [] + +dump_points_1: 'False' +dump_points_2: 'False' +event_equal: 'False' +fcst_var_val_1: + # Specify the variable name and the statistic(s) of interest. + # This will generate the line for the spread_plus_oerr values for TMP and a + # line for rmse values for TMP. + TMP: + - ECNT_SPREAD_PLUS_OERR + - ECNT_RMSE + +fcst_var_val_2: {} + +fixed_vars_vals_input: {} +grid_col: '#cccccc' +grid_lty: 3 +grid_lwd: 1 +grid_on: 'True' +grid_x: listX + +# Labels for the x-axis +indy_label: +- '3' +- '4' +- '6' +- '9' +- '12' +- '15' +- '16' +- '17' +- '18' +- '20' +- '24' +- '27' +- '30' +- '32' +- '33' +- '34' +- '36' + +# Stagger the points so overlapping points don't obscure one another +indy_stagger_1: 'True' +indy_stagger_2: 'True' + +# Values for the x-axis +indy_vals: +- '30000' +- '40000' +- '60000' +- '90000' +- '120000' +- '150000' +- '160000' +- '170000' +- '180000' +- '200000' +- '240000' +- '270000' +- '300000' +- '320000' +- '330000' +- '340000' +- '360000' + +# Specify the variable corresponding to the x-axis +indy_var: fcst_lead + +legend_box: o +legend_inset: + x: 0.0 + y: -0.25 +legend_ncol: -1 +legend_size: 0.8 +line_type: None + +# Explicitly set only the statistics for the derived series line +# (without the accompanying variable name) +list_stat_1: + - ECNT_SPREAD_PLUS_OERR + - ECNT_RMSE +list_stat_2: [] + +mar: +- 8 +- 4 +- 5 +- 4 +method: bca +mgp: +- 1 +- 1 +- 0 +num_iterations: 1 +num_threads: -1 +plot_caption: Caption +plot_ci: +- std +- std +- std + +# Turn on/off displaying the lines +plot_disp: +- 'True' +- 'True' +- 'True' + + +plot_filename: !ENV '${PLOT_OUTPUT_BASE}/short-range_UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.png' +plot_height: 8.5 +plot_res: 72 +plot_stat: median +plot_type: png16m +plot_units: in +plot_width: 11.0 + +# Optional, uncomment and set to directory to store the .points1 file +# that is used by METviewer (created when dump_points_1 is set to True) +# if dump_points_1 is True and this is uncommented, the points1 file +# will be saved in the default location (i.e. where the input data file is stored). +#points_path: /path/to + +random_seed: null + +# Define the style of the line +series_line_style: +- '-' # solid +- '--' # dashes +- ':' # dots + + + +series_line_width: +- 1 +- 1 +- 1 + +series_order: +# The order in which to apply settings for line width, line style, colors, symbols, etc. +# A convenience for experimenting with which color/line style/symbol combination works best for +# a particular line. +- 1 +- 2 +- 3 + + +series_symbols: +- . # circle +- "s" # square +- ^ # triangle up + + +series_type: +# b=lines + markers, l=lines only p=markers only +- b +- b +- b + +series_val_1: + # value of interest, in this case, the model, RRFS_GEFS_GF.SPP.SPPT + model: + - 'RRFS_GEFS_GF.SPP.SPPT' +series_val_2: {} + +show_nstats: 'False' +show_signif: +- 'False' +- 'False' +- 'False' + + +stat_input: !ENV '${PLOT_INPUT_BASE}/ecnt_aggregated.data' +sync_yaxes: 'False' +title: Spread skill plot with ratio line from MET ensemble-stat data (aggregation statistics) +title_align: 0.5 +title_offset: -2 +title_size: 1.4 +title_weight: 2.0 +# Use empty list to use automatically generated legend labels +user_legend: [] +# comment above and uncomment below to use user-specified legend labels +#user_legend: ['ECNT SPREAD_PLUS_OERR for RRFS_GEFS_GF.SPP.SPPT TMP ', 'ECNT RMSE for for RRFS_GEFS_GF.SPP.SPPT TMP', 'RATIO(RRFS_GEFS_GF.SPP.SPPT TMP SPREAD_PLUS_OERR/RMSE)'] +variance_inflation_factor: 'False' +vert_plot: 'False' +x2lab_align: 0.5 +x2lab_offset: -0.5 +x2lab_size: 0.8 +x2lab_weight: 1 +x2tlab_horiz: 0.5 +x2tlab_orient: 1 +x2tlab_perp: 1 +x2tlab_size: 0.8 +xaxis: fcst lead (hr) +xaxis_reverse: 'False' +xlab_align: 0.5 +xlab_offset: 2 +xlab_size: 1 +xlab_weight: 1 +xlim: [] +xtlab_decim: 0 +xtlab_horiz: 0.5 +xtlab_orient: 1 +xtlab_perp: -0.75 +xtlab_size: 1 +y2lab_align: 0.5 +y2lab_offset: 1 +y2lab_size: 1 +y2lab_weight: 1 +y2lim: [] +y2tlab_horiz: 0.5 +y2tlab_orient: 1 +y2tlab_perp: 1 +y2tlab_size: 1.0 +yaxis_1: Statistic value (or ratio of statistic values) +yaxis_2: '' +ylab_align: 0.5 +ylab_offset: -2 +ylab_size: 1 +ylab_weight: 1 +ylim: [] +ytlab_horiz: 0.5 +ytlab_orient: 1 +ytlab_perp: 0.5 +ytlab_size: 1 + +show_legend: +# 0 for don't show, 1 to show + - 1 + - 1 + - 1 + + +# Default logging is ERROR and to stdout. Omit the log_filename and log_level setting name and value if +# to use default settings. +log_filename: !ENV '${PLOT_OUTPUT_BASE}/spread_skill_ecnt.log' +log_level: INFO + +# 0-value on the x-axis is to the far left. +start_from_zero: False diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt.yaml b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt.yaml new file mode 100755 index 0000000000..a60bbdac21 --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt.yaml @@ -0,0 +1,23 @@ +# The REFORMAT_OUTPUT_BASE and REFORMAT_INPUT_BASE are defined in the +# UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot.conf file +# + +# Indicates whether the .stat file input contains aggregated statistics (i.e. output from MET stat-analysis +# has been applied to MET .stat output from point-stat, grid-stat, or ensemble-stat, or previously aggregated +# via METcalcpy agg_stat). In this example, the input data is not aggregated. +# Set this to False, ensuring the appropriate format for METcalcpy agg_stat. +input_stats_aggregated: False +output_dir: !ENV '${REFORMAT_OUTPUT_BASE}' +output_filename: ensemble_stat_ecnt.data +line_type: ECNT +input_data_dir: !ENV '${REFORMAT_INPUT_BASE}' + +# !!! DO NOT modify the settings for the log_directory and log_filename.!!! +# The METdataio METreformat code is expecting values for these settings even though the log +# messages are in the METplus logfile. +log_directory: !ENV '${REFORMAT_OUTPUT_BASE}' +log_filename: 'ecnt_reformat.log' + +# Log levels are: INFO, DEBUG, WARNING, ERROR. +# Set to INFO for most verbose, ERROR for least verbose. +log_level: DEBUG diff --git a/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt_linetype.py b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt_linetype.py new file mode 100755 index 0000000000..239458c1f2 --- /dev/null +++ b/parm/use_cases/model_applications/short_range/UserScript_fcstRRFS_fcstOnly_Reformat_Aggregate_Plot/reformat_ecnt_linetype.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 + + +import os +import time +import logging + +from METdbLoad.ush.read_data_files import ReadDataFiles +from METdbLoad.ush.read_load_xml import XmlLoadFile +from METreformat.write_stat_ascii import WriteStatAscii +from metcalcpy.util import read_env_vars_in_config as readconfig + + +logger = logging.getLogger(__name__) + +def main(): + + # Read in the YAML configuration file. Environment variables in + # the configuration file are supported. + input_config_file = os.getenv("REFORMAT_YAML_CONFIG_NAME", "reformat_ecnt.yaml") + settings = readconfig.parse_config(input_config_file) + logging.info(settings) + + + # Replacing the need for an XML specification file, pass in the XMLLoadFile and + # ReadDataFile parameters + rdf_obj: ReadDataFiles = ReadDataFiles() + xml_loadfile_obj: XmlLoadFile = XmlLoadFile(None) + + # Retrieve all the filenames in the data_dir specified in the YAML config file + load_files = xml_loadfile_obj.filenames_from_template(settings['input_data_dir'], + {}) + + flags = xml_loadfile_obj.flags + line_types = xml_loadfile_obj.line_types + beg_read_data = time.perf_counter() + rdf_obj.read_data(flags, load_files, line_types) + end_read_data = time.perf_counter() + time_to_read = end_read_data - beg_read_data + logger.info("Time to read input .stat data files using METdbLoad: {time_to_read}") + file_df = rdf_obj.stat_data + + # Check if the output file already exists, if so, delete it to avoid + # appending output from subsequent runs into the same file. + existing_output_file = os.path.join(settings['output_dir'], settings['output_filename']) + logger.info("Checking if {existing_output_file} already exists") + if os.path.exists(existing_output_file): + logger.info("Removing existing output file {existing_output_file}") + os.remove(existing_output_file) + + # Write stat file in ASCII format + stat_lines_obj: WriteStatAscii = WriteStatAscii(settings) + # stat_lines_obj.write_stat_ascii(file_df, parms, logger) + stat_lines_obj.write_stat_ascii(file_df, settings) + + +if __name__ == "__main__": + main()