GridStat: Verifying Soil moisture of SFS-GSL output against ERA5-Land, continuous and categorical statistics

model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture.conf

Scientific Objective

This use case verifies 30 years of Soil Moisture data from an ensemble for a given year and month (here June). The purpose is to evaluate the Soil Moisture ensemble mean at a 1 degree resolution against ERA5-Land data. The use case demonstrates how to compute categorical, continuous, and anomaly statistics over the globe and CONUS with Grid-Stat, and also select continuous statistics at each grid point over the globe statistics with Series-Analysis. It also illustrates how to read in NMME data and compute an emsemble mean from NMME data as input to Grid-Stat and Series-Analysis, and how to plot example statistics from the command line.

Version Added

METplus version 6.1

Datasets

Forecast: 30 SFS-GSL Ensemble files, 0-1m Soil Moisture fields in mm

Observation: ERA5-Land, Monthly 0-1m Soil Moisture field in mm

Climatology Forecast: SFS-GSL 30 year Enemble Mean Soil Moisture mean and standard deviation

Climatology Observation: ERA5-Land, 30 year Monthly 0-1m Soil Moisture mean and standard deviation

Location: All of the input data required for this use case can be found in a sample data tarball. Each use case category will have one or more sample data tarballs. It is only necessary to download the tarball with the use case’s dataset and not the entire collection of sample data. Click here to access the METplus releases page and download sample data for the appropriate release: https://github.com/dtcenter/METplus/releases This tarball should be unpacked into the directory that you will set the value of INPUT_BASE. See Running METplus section for more information.

METplus Components

This use case calls GridStat 30 times, once for each year of data of the SFS-GSL ensemble. It also calls Series-Analysis once and UserScript twice. METcalcpy, METplotpy, and METdataio are required to run the two UserScripts. These steps could be turned off if graphics are not desired. The METcalcpy scripts accessed include the following:

  • metcalcpy/util/read_env_vars_in_config.py

The METplopty scrips accessed include the following:

  • metplotpy/plots/line/line.py

The METdataio scripts accessed include the following:

  • METdbLoad/ush/read_data_files.py

  • METdbLoad/ush/read_load_xml.py

  • METreformat/write_stat_ascii.py

METplus Workflow

Beginning time (VALID_BEG): 1991-06-00

End time (VALID_END): 2020-06-00

Increment between beginning and end times (VALID_INCREMENT): 12 months

Sequence of forecast leads to process (LEAD_SEQ): None

This use case initially computes statistics with Grid-Stat using ensemble means from the SFS-GSL 5 member ensemble monthly forecast data. With an increment of 12 months, all Junes from 1991 to 2020 are processed for a total of 30 years over the globe and CONUS.

Then, Series-Analysis is run once to compute 2D statistics over the entire 30 year time period. Finally, the two UserScripts are each run once; one to reformat data and another to create a plot of ME and RMSE for June over the 30 year time period.

METplus Configuration

METplus first loads all of the configuration files found in parm/metplus_config, then it loads any configuration files passed to METplus via the command line, i.e. parm/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture.conf

[config]

# Documentation for this use case can be found at
# https://metplus.readthedocs.io/en/latest/generated/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture.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 = GridStat, SeriesAnalysis(sm_2d), UserScript(reformat_CNT), UserScript(plot_stats)


###
# 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
###

LOG_LEVEL = INFO

LOOP_BY = VALID
VALID_TIME_FMT = %Y%m%d%H
VALID_BEG = 1991060100
VALID_END = 2020060100
VALID_INCREMENT = 12m
LEAD_SEQ = 0


###
# GridStat File I/O
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#directory-and-filename-template-info
###

FCST_GRID_STAT_INPUT_TEMPLATE = PYTHON_NUMPY

OBS_GRID_STAT_INPUT_DIR = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/ERA5
OBS_GRID_STAT_INPUT_TEMPLATE = ERA5.soilm1m.1x1.1991-2020.mon.nc

GRID_STAT_FCST_CLIMO_MEAN_FILE_NAME = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/clim/SFS_GSL.soilm1m.30year_1991_2020.{valid?fmt=%m}_mean_stdev.nc
GRID_STAT_FCST_CLIMO_STDEV_FILE_NAME = {GRID_STAT_FCST_CLIMO_MEAN_FILE_NAME}

GRID_STAT_OBS_CLIMO_MEAN_FILE_NAME = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/clim/ERA5_soilm1m_1x1_30year_1991_2020_{valid?fmt=%m}_mean_stdev.nc
GRID_STAT_OBS_CLIMO_STDEV_FILE_NAME = {GRID_STAT_OBS_CLIMO_MEAN_FILE_NAME}

GRID_STAT_OUTPUT_DIR = {OUTPUT_BASE}/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/grid_stat
#GRID_STAT_OUTPUT_TEMPLATE = {valid?fmt=%Y%m%d%H}


###
# GridStat Field Info
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#field-info
###

MODEL = SFS-GSL
OBTYPE = ERA5

FCST_GRID_STAT_VAR1_NAME = {PARM_BASE}/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/sfs_gsl_model_wrapper.py {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/SFS_GSL/SFS_GSL.soilm1m.{valid?fmt=%Y%m}.fcst.nc {valid?fmt=%2m} {valid?fmt=%Y}
FCST_GRID_STAT_VAR1_THRESH = gt1.0, gt2.0, >SFP25, >SFP50, >SFP75 

OBS_GRID_STAT_VAR1_NAME = soilm1m
OBS_GRID_STAT_VAR1_LEVELS =  "({valid?fmt=%Y%m%d_%H%M%S},*,*)"
OBS_GRID_STAT_FILE_TYPE = NETCDF_NCCF

OBS_VAR1_THRESH = gt1.0, gt2.0, >SOP25, >SOP50, >SOP75 

GRID_STAT_FCST_CLIMO_MEAN_VAR1_NAME = soilm1m_mean
GRID_STAT_FCST_CLIMO_MEAN_VAR1_LEVELS = "(*,*)"
GRID_STAT_FCST_CLIMO_MEAN_HOUR_INTERVAL = NA

GRID_STAT_FCST_CLIMO_STDEV_VAR1_NAME = soilm1m_stdev
GRID_STAT_FCST_CLIMO_STDEV_VAR1_LEVELS = "(*,*)"
GRID_STAT_FCST_CLIMO_STDEV_HOUR_INTERVAL = NA

GRID_STAT_OBS_CLIMO_MEAN_VAR1_NAME = soilm1m_mean
GRID_STAT_OBS_CLIMO_MEAN_VAR1_LEVELS = "(*,*)"
GRID_STAT_OBS_CLIMO_MEAN_HOUR_INTERVAL = NA

GRID_STAT_OBS_CLIMO_STDEV_VAR1_NAME = soilm1m_stdev
GRID_STAT_OBS_CLIMO_STDEV_VAR1_LEVELS = "(*,*)"
GRID_STAT_OBS_CLIMO_STDEV_HOUR_INTERVAL = NA


###
# GridStat Settings
# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#gridstat
###

GRID_STAT_VERIFICATION_MASK_TEMPLATE =
  {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/masks/CONUS.nc

GRID_STAT_OUTPUT_FLAG_FHO = BOTH
GRID_STAT_OUTPUT_FLAG_CTC = STAT
GRID_STAT_OUTPUT_FLAG_CTS = STAT
GRID_STAT_OUTPUT_FLAG_CNT = STAT
GRID_STAT_OUTPUT_FLAG_SL1L2 = STAT
GRID_STAT_OUTPUT_FLAG_SAL1L2 = STAT

GRID_STAT_REGRID_TO_GRID = OBS
GRID_STAT_REGRID_METHOD = BILIN
GRID_STAT_REGRID_WIDTH = 2
GRID_STAT_REGRID_SHAPE = SQUARE

GRID_STAT_ONCE_PER_FIELD = False

GRID_STAT_OUTPUT_PREFIX = {MODEL}_vs_{OBTYPE}


[sm_2d]
###
# SeriesAnalysis File I/O
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#directory-and-filename-template-info
###

FCST_SERIES_ANALYSIS_INPUT_DIR = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/SFS_GSL
FCST_SERIES_ANALYSIS_INPUT_TEMPLATE = SFS_GSL.soilm1m.{init?fmt=%Y%m}.fcst.nc
FCST_SERIES_ANALYSIS_INPUT_DATATYPE = PYTHON_NUMPY

OBS_SERIES_ANALYSIS_INPUT_DIR = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/ERA5
OBS_SERIES_ANALYSIS_INPUT_TEMPLATE = ERA5.soilm1m.1x1.1991-2020.mon.nc
OBS_SERIES_ANALYSIS_INPUT_DATATYPE = NETCDF_NCCF

SERIES_ANALYSIS_FCST_CLIMO_MEAN_FILE_NAME = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/clim/SFS_GSL.soilm1m.30year_1991_2020.06_mean_stdev.nc
SERIES_ANALYSIS_FCST_CLIMO_STDEV_FILE_NAME = {SERIES_ANALYSIS_FCST_CLIMO_MEAN_FILE_NAME}

SERIES_ANALYSIS_OBS_CLIMO_MEAN_FILE_NAME = {INPUT_BASE}/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/clim/ERA5_soilm1m_1x1_30year_1991_2020_06_mean_stdev.nc
SERIES_ANALYSIS_OBS_CLIMO_STDEV_FILE_NAME = {SERIES_ANALYSIS_OBS_CLIMO_MEAN_FILE_NAME}

SERIES_ANALYSIS_OUTPUT_DIR = {OUTPUT_BASE}/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/series_analysis
SERIES_ANALYSIS_OUTPUT_TEMPLATE = {MODEL}_vs_{OBTYPE}_June.nc


###
# SeriesAnalysis Field Info
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#field-info
###

FCST_SERIES_ANALYSIS_VAR1_NAME = {PARM_BASE}/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/sfs_gsl_model_wrapper.py MET_PYTHON_INPUT_ARG {valid?fmt=%m} {valid?fmt=%Y}

OBS_SERIES_ANALYSIS_VAR1_NAME = soilm1m
OBS_SERIES_ANALYSIS_VAR1_LEVELS =  "({valid?fmt=%Y%m%d_%H%M%S},*,*)"

SERIES_ANALYSIS_FCST_CLIMO_MEAN_VAR1_NAME = soilm1m_mean
SERIES_ANALYSIS_FCST_CLIMO_MEAN_VAR1_LEVELS = "(*,*)"
SERIES_ANALYSIS_FCST_CLIMO_MEAN_HOUR_INTERVAL = NA

SERIES_ANALYSIS_FCST_CLIMO_STDEV_VAR1_NAME = soilm1m_stdev
SERIES_ANALYSIS_FCST_CLIMO_STDEV_VAR1_LEVELS = "(*,*)"
SERIES_ANALYSIS_FCST_CLIMO_STDEV_HOUR_INTERVAL = NA

SERIES_ANALYSIS_OBS_CLIMO_MEAN_VAR1_NAME = soilm1m_mean
SERIES_ANALYSIS_OBS_CLIMO_MEAN_VAR1_LEVELS = "(*,*)"
SERIES_ANALYSIS_OBS_CLIMO_MEAN_HOUR_INTERVAL = NA

SERIES_ANALYSIS_OBS_CLIMO_STDEV_VAR1_NAME = soilm1m_stdev
SERIES_ANALYSIS_OBS_CLIMO_STDEV_VAR1_LEVELS = "(*,*)"
SERIES_ANALYSIS_OBS_CLIMO_STDEV_HOUR_INTERVAL = NA


###
# Series Analysis Settings
# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#seriesanalysis
###
SERIES_ANALYSIS_RUNTIME_FREQ = RUN_ONCE

SERIES_ANALYSIS_DESC =

SERIES_ANALYSIS_CAT_THRESH =

SERIES_ANALYSIS_VLD_THRESH =

SERIES_ANALYSIS_BLOCK_SIZE = 0

SERIES_ANALYSIS_CTS_LIST =

SERIES_ANALYSIS_REGRID_TO_GRID = OBS
SERIES_ANALYSIS_REGRID_METHOD = BILIN
SERIES_ANALYSIS_REGRID_WIDTH = 2
SERIES_ANALYSIS_REGRID_VLD_THRESH = 0.0
SERIES_ANALYSIS_REGRID_SHAPE = SQUARE

SERIES_ANALYSIS_RUN_ONCE_PER_STORM_ID = False

SERIES_ANALYSIS_IS_PAIRED = False

SERIES_ANALYSIS_CONFIG_FILE = {PARM_BASE}/met_config/SeriesAnalysisConfig_wrapped

SERIES_ANALYSIS_OUTPUT_STATS_CNT = TOTAL, ME, RMSE, FBAR, OBAR, ANOM_CORR

MODEL = SFS-GSL-SA
OBTYPE = ERA5


[user_env_vars]
# This section contains some needed variables for the reformatting and plotting

# Paths to METdataio, METcalcpy, and METplotpy as needed for the use case
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

###
# Settings for the reformatting of the CTS linetype, to later be iused for plotting
### 
REFORMAT_YAML_CONFIG_NAME = {PARM_BASE}/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/reformat_CNT.yaml

# Input directory where the .stat files you need to reformat are located 
REFORMAT_INPUT_DIR = {OUTPUT_BASE}/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/grid_stat

# Output directory to store the reformatted data
REFORMAT_OUTPUT_DIR = {OUTPUT_BASE}/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/reformatted

# Name of the output file containing reformatted data
REFORMAT_OUTPUT_FILENAME = reformat_CNT.data

# Line type to reformat
# Currently support FHO, CTC, CTS, CNT, SL1L2, VL1L2, PCT, MCTC, VCNT, ECNT, RHIST, TCDiag, and MPR line types
REFORMAT_LINETYPE = CNT


###
# Settings for creating the plots of ME and RMSE
###
# Directory where the YAML configurations for plotting are located
PLOTTING_YAML_CONFIG_DIR = {PARM_BASE}/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture

# YAML Configuration file list
PLOTTING_YAML_CONFIG_FILE_LIST = custom_line_ME.yaml, custom_line_RMSE.yaml

#Input for plotting (this is the Reformatted data above 
PLOTTING_STAT_INPUT = {REFORMAT_OUTPUT_DIR}/{REFORMAT_OUTPUT_FILENAME}

# Output directory for plots
PLOTTING_OUTPUT_DIR = {OUTPUT_BASE}/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/plots

# List of the output filenames for plotting.  This should have the same number of files as 
# PLOTTING_YAML_CONFIG_FILE_LIST and they should be in the same order
PLOTTING_OUTPUT_FILENAME_LIST = SoilMoisture_ME.png, SoilMoisture_RMSE.png

# Log file for the plotting
PLOTTING_LOG_FILENAME = {LOG_DIR}/plotting.log


[reformat_CNT]
###
# UserScript Settings to reformat the CNT linetype
# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#userscript
###

USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE
USER_SCRIPT_COMMAND = {PARM_BASE}/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/reformat_CNT_linetype.py


[plot_stats]
###
# UserScript Settings to create the plots
# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#userscript
###

USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE
USER_SCRIPT_COMMAND = {PARM_BASE}/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture/plot_line_stats.py

MET Configuration

METplus sets environment variables based on user settings in the METplus configuration file. See How METplus controls MET config file settings for more details.

YOU SHOULD NOT SET ANY OF THESE ENVIRONMENT VARIABLES YOURSELF! THEY WILL BE OVERWRITTEN BY METPLUS WHEN IT CALLS THE MET TOOLS!

If there is a setting in the MET configuration file that is currently not supported by METplus you’d like to control, please refer to: Overriding Unsupported MET config file settings

GridStatConfig_wrapped
////////////////////////////////////////////////////////////////////////////////
//
// Grid-Stat configuration file.
//
// For additional information, see the MET_BASE/config/README file.
//
////////////////////////////////////////////////////////////////////////////////

//
// Output model name to be written
//
// model =
${METPLUS_MODEL}

//
// Output description to be written
// May be set separately in each "obs.field" entry
//
// desc =
${METPLUS_DESC}

//
// Output observation type to be written
//
// obtype =
${METPLUS_OBTYPE}

////////////////////////////////////////////////////////////////////////////////

//
// Verification grid
//
// regrid = {
${METPLUS_REGRID_DICT}

////////////////////////////////////////////////////////////////////////////////

//censor_thresh =
${METPLUS_CENSOR_THRESH}
//censor_val =
${METPLUS_CENSOR_VAL}
//cat_thresh =
${METPLUS_CAT_THRESH}
cnt_thresh  	 = [ NA ];
cnt_logic   	 = UNION;
wind_thresh 	 = [ NA ];
wind_logic  	 = UNION;
eclv_points      = 0.05;
//nc_pairs_var_name =
${METPLUS_NC_PAIRS_VAR_NAME}
nc_pairs_var_suffix = "";
//hss_ec_value =
${METPLUS_HSS_EC_VALUE}

rank_corr_flag   = FALSE;

//
// Forecast and observation fields to be verified
//
fcst = {
  ${METPLUS_FCST_FILE_TYPE}
  ${METPLUS_FCST_FIELD}
  ${METPLUS_FCST_CLIMO_MEAN_DICT}
  ${METPLUS_FCST_CLIMO_STDEV_DICT}
}
obs = {
  ${METPLUS_OBS_FILE_TYPE}
  ${METPLUS_OBS_FIELD}
  ${METPLUS_OBS_CLIMO_MEAN_DICT}
  ${METPLUS_OBS_CLIMO_STDEV_DICT}
}

////////////////////////////////////////////////////////////////////////////////

//
// Climatology mean data
//
//climo_mean = {
${METPLUS_CLIMO_MEAN_DICT}


//climo_stdev = {
${METPLUS_CLIMO_STDEV_DICT}

//
// May be set separately in each "obs.field" entry
//
//climo_cdf = {
${METPLUS_CLIMO_CDF_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Verification masking regions
//
// mask = {
${METPLUS_MASK_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Confidence interval settings
//
ci_alpha  = [ 0.05 ];

boot = {
   interval = PCTILE;
   rep_prop = 1.0;
   n_rep    = 0;
   rng      = "mt19937";
   seed     = "";
}

////////////////////////////////////////////////////////////////////////////////

//
// Data smoothing methods
//
//interp = {
${METPLUS_INTERP_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Neighborhood methods
//
nbrhd = {
   field      = BOTH;
   // shape =
   ${METPLUS_NBRHD_SHAPE}
   // width =
   ${METPLUS_NBRHD_WIDTH}
   // cov_thresh =
   ${METPLUS_NBRHD_COV_THRESH}
   vld_thresh = 1.0;
}

////////////////////////////////////////////////////////////////////////////////

//
// Fourier decomposition
// May be set separately in each "obs.field" entry
//
//fourier = {
${METPLUS_FOURIER_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Gradient statistics
// May be set separately in each "obs.field" entry
//
//gradient = {
${METPLUS_GRADIENT_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Distance Map statistics
// May be set separately in each "obs.field" entry
//
//distance_map = {
${METPLUS_DISTANCE_MAP_DICT}


////////////////////////////////////////////////////////////////////////////////
// Threshold for SEEPS p1 (Probability of being dry)

//seeps_p1_thresh =
${METPLUS_SEEPS_P1_THRESH}

////////////////////////////////////////////////////////////////////////////////

//
// Statistical output types
//
//output_flag = {
${METPLUS_OUTPUT_FLAG_DICT}

//
// NetCDF matched pairs output file
// May be set separately in each "obs.field" entry
//
// nc_pairs_flag = {
${METPLUS_NC_PAIRS_FLAG_DICT}

////////////////////////////////////////////////////////////////////////////////

//ugrid_dataset =
${METPLUS_UGRID_DATASET}

//ugrid_max_distance_km =
${METPLUS_UGRID_MAX_DISTANCE_KM}

//ugrid_coordinates_file =
${METPLUS_UGRID_COORDINATES_FILE}

////////////////////////////////////////////////////////////////////////////////

//grid_weight_flag =
${METPLUS_GRID_WEIGHT_FLAG}

tmp_dir = "${MET_TMP_DIR}";

// output_prefix =
${METPLUS_OUTPUT_PREFIX}

////////////////////////////////////////////////////////////////////////////////

${METPLUS_TIME_OFFSET_WARNING}
${METPLUS_MET_CONFIG_OVERRIDES}
SeriesAnalysisConfig_wrapped
////////////////////////////////////////////////////////////////////////////////
//
// Series-Analysis configuration file.
//
// For additional information, see the MET_BASE/config/README file.
//
////////////////////////////////////////////////////////////////////////////////

//
// Output model name to be written
//
//model =
${METPLUS_MODEL}

//
// Output description to be written
//
//desc =
${METPLUS_DESC}

//
// Output observation type to be written
//
//obtype =
${METPLUS_OBTYPE}

////////////////////////////////////////////////////////////////////////////////

//
// Verification grid
// May be set separately in each "field" entry
//
//regrid = {
${METPLUS_REGRID_DICT}

////////////////////////////////////////////////////////////////////////////////

censor_thresh = [];
censor_val    = [];
//cat_thresh =
${METPLUS_CAT_THRESH}
cnt_thresh    = [ NA ];
cnt_logic     = UNION;

//
// Forecast and observation fields to be verified
//
fcst = {
   ${METPLUS_FCST_FILE_TYPE}
   ${METPLUS_FCST_CAT_THRESH}
   //field = [
   ${METPLUS_FCST_FIELD}
   ${METPLUS_FCST_CLIMO_MEAN_DICT}
   ${METPLUS_FCST_CLIMO_STDEV_DICT}
}
obs = {
   ${METPLUS_OBS_FILE_TYPE}
   ${METPLUS_OBS_CAT_THRESH}
   //field = [
   ${METPLUS_OBS_FIELD}
   ${METPLUS_OBS_CLIMO_MEAN_DICT}
   ${METPLUS_OBS_CLIMO_STDEV_DICT}
}

////////////////////////////////////////////////////////////////////////////////

//
// Climatology data
//
//climo_mean = {
${METPLUS_CLIMO_MEAN_DICT}


//climo_stdev = {
${METPLUS_CLIMO_STDEV_DICT}

//climo_cdf = {
${METPLUS_CLIMO_CDF_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Confidence interval settings
//
ci_alpha  = [ 0.05 ];

boot = {
   interval = PCTILE;
   rep_prop = 1.0;
   n_rep    = 0;
   rng      = "mt19937";
   seed     = "";
}

////////////////////////////////////////////////////////////////////////////////

//
// Verification masking regions
//
//mask = {
${METPLUS_MASK_DICT}

////////////////////////////////////////////////////////////////////////////////

//
// Gradient statistics
// May be set separately in each "obs.field" entry
//
//gradient = {
${METPLUS_GRADIENT_DICT}

//
// Number of grid points to be processed concurrently.  Set smaller to use
// less memory but increase the number of passes through the data.
//
//block_size =
${METPLUS_BLOCK_SIZE}

//
// Ratio of valid matched pairs to compute statistics for a grid point
//
//vld_thresh =
${METPLUS_VLD_THRESH}

////////////////////////////////////////////////////////////////////////////////

//
// Statistical output types
//
//output_stats = {
${METPLUS_OUTPUT_STATS_DICT}

////////////////////////////////////////////////////////////////////////////////

//hss_ec_value =
${METPLUS_HSS_EC_VALUE}
rank_corr_flag = FALSE;

tmp_dir = "${MET_TMP_DIR}";

//version        = "V10.0";

////////////////////////////////////////////////////////////////////////////////

${METPLUS_TIME_OFFSET_WARNING}
${METPLUS_MET_CONFIG_OVERRIDES}

Python Embedding

This script reads output from the SFS-GSL model, which provides soil moisture forecasts in separate monthly NetCDF files. It accepts command-line arguments specifying the file path, a valid forecast month, and year. The script loads forecast data (fcst) along with associated latitude, longitude, and target time variables. It converts the model’s target time values—representing months since January 1960—into actual calendar dates, then filters the data to retain only forecasts matching the specified valid month. It computes the ensemble mean over the 5-member ensemble and prepares the resulting data in a format suitable for input into the MET (Model Evaluation Tools) verification system. The code is located in the following directory:

parm/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture
sfs_gsl_model_wrapper.py
# Script to read SFS-GSL model output. 
# Separate monthly files
# Data description
# 5 member ensemble, target: forecast target month
# Variable: fcst(ensmem, target, lat, lon)
 
import sys
import re
import numpy as np
import datetime as dt
from datetime import datetime
from netCDF4 import Dataset, chartostring
import pandas as pd

print('Usage')
print('/location/of/model/data valid_month valid_year')

# Define inputs
#print('arguments: '+str(arguments))

path = sys.argv[0]
print('path: ' + path)
mod_path = sys.argv[1]
print('mod_path: ' + mod_path)
valid_month = sys.argv[2]
print('Valid Month: ' + valid_month)
year = sys.argv[3]
print('Year: ' + str(year))

valid_time = year+valid_month
valid_time = dt.datetime.strptime(valid_time,"%Y%m")

print('Reading input file')

# Setup data to be read into MET

f = Dataset(mod_path, 'r')

lat    = f.variables['lat'][::-1]
lon    = f.variables['lon'][:]
fcst   = f.variables['fcst'][:]      
target = f.variables['target'][:] 

mon_since = datetime(1960, 1, 1)
target_dates = [mon_since + pd.DateOffset(months=int(months)) for months in target]

#Get valid month from arguments above
val_month = int(valid_month)
desired_dates = [i for i, date in enumerate(target_dates) if date.month == val_month]

if not desired_dates:
   print(f"No data available for the specified month: {desired_month}")
else:
   # Extract the forecast data for the specified month
   fcst_for_month = fcst[:, desired_dates, :, :]

   # Calculate the mean over the ensemble dimension (ensmem)
   var = np.mean(fcst_for_month, axis=0)

val_time = valid_time
print('Valid Time: ' + str(val_time))
print('Shape of variable to read into MET: ' + str(var.shape))

#squeeze out all 1d arrays, add fill value, convert to float64
var = np.float64(var)
var[var < 0] = np.nan

met_data = np.squeeze(var).copy()

#create a metadata dictionary

attrs = {

        'valid': str(val_time.strftime("%Y%m%d"))+'_'+str(val_time.strftime("%H%M%S")),
        'init': str(val_time.strftime("%Y%m%d"))+'_'+str(val_time.strftime("%H%M%S")),
        'name': 'Soil_moisture',
        'long_name': 'SFS_GSL 0-1m soilm1m ensemble mean',
        'lead': str(int(valid_month)),
        'accum': '00',
        'level': '0-1m',
        'units': 'mm',
        'grid': {
            'name': 'Global 1 degree',
            'type': 'LatLon',
            'lat_ll': -90.0,
            'lon_ll': 0.0,
            'delta_lat': 1.0,
            'delta_lon': 1.0,

            'Nlon': f.dimensions['lon'].size,
            'Nlat': f.dimensions['lat'].size,
            }
        }


print("valid time: " + repr(val_time.strftime("%Y%m%d%H%M")))
print("Attributes:\t" + repr(attrs))
f.close()

For more information on the basic requirements to utilize Python Embedding in METplus, please refer to the MET User’s Guide section on Python embedding

User Scripting

There are two Python scripts used in this use case, called using the “UserScript” keyword in the METplus wrappers PROCESS_LIST configuration item. These scripts provide an interface to the functions in the METdataio, METcalcpy, and METplotpy Python modules of METplus. The functions used in these scripts demonstrate reformatting of the GridStat output to meet the format required by METcalcpy and METplotpy, and then plotting that reformatted output using functions from METcalcpy and METplotpy.

The first Python script is called reformat_CNT_linetype.py. This script takes the output CNT linetype from Grid Stat and reformats it so that the data can be plotted. The script takes an input .yaml file, reformat_CNT.yaml. Environment variables in the yaml file are specified in the [user_env_vars] section of the GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture.conf METplus configuration file.

The second Python script is plot_line_stats.py. This script creates line plots for ME and RMSE over time, using the YAML files custom_line_ME.yaml, and custom_line_RMSE.yaml Input variables to both scripts are set in the [user_env_vars] section of the GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture.conf file.

For more information about YAML configuration options for the line plots shown here, see the METplotpy line plot documentation.

Both Python scripts are located in the following directory:

parm/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture
reformat_CNT_linetype.py
#!/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_cnt_config_file = os.getenv("REFORMAT_YAML_CONFIG_NAME", "reformat_CNT.yaml")
    settings = readconfig.parse_config(input_cnt_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
    print(flags)
    line_types = xml_loadfile_obj.line_types
    print(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: %f", 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, logger)
    stat_lines_obj.write_stat_ascii(file_df, settings)


if __name__ == "__main__":
    main()
plot_line_stats.py
#!/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 the input files
    yaml_files_str = os.environ['PLOTTING_YAML_CONFIG_FILE_LIST'].split(',')
    yaml_files = [yf.lstrip() for yf in yaml_files_str]
    yaml_file_dir = os.environ['PLOTTING_YAML_CONFIG_DIR']
    plot_output_file_list_str = os.environ['PLOTTING_OUTPUT_FILENAME_LIST'].split(',')
    plot_output_files = [po.lstrip() for po in plot_output_file_list_str]
    plot_output_dir = os.environ['PLOTTING_OUTPUT_DIR']

    # Check to see that the two lists have the same number of elements
    # If they dont', error out
    if len(yaml_files) != len(plot_output_files):
        raise RuntimeError('The number of files in PLOTTING_YAML_CONFIG_FILE_LIST must be equal to the number of files in PLOTTING_OUTPUT_FILENAME_LIST')


    # Loop through data
    for i,j in zip (yaml_files,plot_output_files):

        os.environ['PLOTTING_YAML_CONFIG_NAME'] = os.path.join(yaml_file_dir,i)
        os.environ['PLOTTING_OUTPUT_FILENAME'] = os.path.join(plot_output_dir,j)

        # Read in the YAML configuration file.  Environment variables in
        # the configuration file are supported.
        try:
            input_config_file = os.getenv("PLOTTING_YAML_CONFIG_NAME", "custom_line.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.logger.info(f"Finished creating line plot, execution time: {execution_time} seconds")
        except ValueError as val_er:
            print(val_er)

if __name__ == "__main__":
  main()

Running METplus

Pass the use case configuration file to the run_metplus.py script along with any user-specific system configuration files if desired:

run_metplus.py /path/to/METplus/parm/use_cases/model_applications/s2s_soil_moisture/GridStat_fcstSFSGSL_obsERA5Land_SoilMoisture.conf /path/to/user_system.conf

See Running METplus for more information.

Expected Output

A successful run will output the following both to the screen and to the logfile:

INFO: METplus has successfully finished running.

Refer to the value set for OUTPUT_BASE to find where the output data was generated. Output for the GridStat run will be found in the grid_stat directory (relative to OUTPUT_BASE) and will have the following files:

* grid_stat_SFS-GSL_vs_ERA5_060000L_YYYY0601_000000V_fho.txt
* grid_stat_SFS-GSL_vs_ERA5_060000L_YYYY0601_000000V_pairs.nc
* grid_stat_SFS-GSL_vs_ERA5_060000L_YYYY0601_000000V.stat

Each file should contain corresponding statistics for the line type(s) requested. For the netCDF file output from Grid Stat, 16 variable fields are present (not including the lat/lon fields). Those variables are:

* FCST_Soil_moisture_0-1m_FULL(lat, lon)
* FCST_Soil_moisture_0-1m_CONUS(lat, lon)
* OBS_soilm1m_20200601_000000_all_all_FULL(lat, lon)
* OBS_soilm1m_20200601_000000_all_all_CONUS(lat, lon)
* DIFF_Soil_moisture_0-1m_soilm1m_20200601_000000_all_all_FULL(lat, lon)
* DIFF_Soil_moisture_0-1m_soilm1m_20200601_000000_all_all_CONUS(lat, lon)
* FCST_CLIMO_MEAN_soilm1m_20190601_000000_all_all_FULL(lat, lon)
* FCST_CLIMO_MEAN_soilm1m_20190601_000000_all_all_CONUS(lat, lon)
* FCST_CLIMO_STDEV_soilm1m_20190601_000000_all_all_FULL(lat, lon)
* FCST_CLIMO_STDEV_soilm1m_20190601_000000_all_all_CONUS(lat, lon)
* OBS_CLIMO_MEAN_soilm1m_20190601_000000_all_all_FULL(lat, lon)
* OBS_CLIMO_MEAN_soilm1m_20190601_000000_all_all_CONUS(lat, lon)
* OBS_CLIMO_STDEV_soilm1m_20190601_000000_all_all_FULL(lat, lon)
* OBS_CLIMO_STDEV_soilm1m_20190601_000000_all_all_CONUS(lat, lon)
* OBS_CLIMO_CDF_soilm1m_20190601_000000_all_all_FULL(lat, lon)
* OBS_CLIMO_CDF_soilm1m_20190601_000000_all_all_CONUS(lat, lon)

The output from SeriesAnalysis will be in the series_analysis directory (relative to OUTPUT_BASE) and will contain 3 files:

* series_analysis_files_fcst_init_ALL_valid_ALL_lead_ALL.txt
* series_analysis_files_obs_init_ALL_valid_ALL_lead_ALL.txt
* SFS-GSL-SA_vs_ERA5_June.nc

The netCDF file from SeriesAnalysis contains 5 variable fields (not including the lat/lon fields). Those variables are:

* series_cnt_TOTAL(lat, lon)
* series_cnt_ME(lat, lon)
* series_cnt_RMSE(lat, lon)
* series_cnt_FBAR(lat, lon)
* series_cnt_OBAR(lat, lon)

The output from the first UserScript can be found in the reformatted directory (relative to OUTPUT_BASE) and will contain 1 file:

* reformat_CNT.data

The output from the second UserScript will be 2 plots found in the plots directory (relative to OUTPUT_BASE):

* SoilMoisture_ME.png
* SoilMoisture_RMSE.png

Keywords

Note

  • GridStatToolUseCase

  • SeriesAnalysisUseCase

  • UserScriptUseCase

  • PythonEmbeddingFileUseCase

  • S2SAppUseCase

  • S2SSoilMoistureAppUseCase

  • NetCDFFileUseCase

  • METdataioUseCase

  • METcalcpyUseCase

  • METplotpyUseCase

Navigate to the METplus Quick Search for Use Cases page to discover other similar use cases.

Gallery generated by Sphinx-Gallery