From c8b8c4148d2791e415658c01f1bce5fea506ffb2 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 16 Dec 2024 21:40:14 +0000 Subject: [PATCH 01/15] Per #3006, add fcst.pairs and obs.pairs config entries. --- src/basic/vx_config/config_constants.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index 9f1366a681..ee2b379274 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -717,6 +717,7 @@ static const char conf_key_ugrid_metadata_map[] = "ugrid_metadata_map"; // // Entries to override file metadata // + static const char conf_key_set_attr_name[] = "set_attr_name"; static const char conf_key_set_attr_units[] = "set_attr_units"; static const char conf_key_set_attr_level[] = "set_attr_level"; @@ -738,6 +739,7 @@ static const char conf_key_is_prob[] = "is_prob"; // // Climatology data parameter key names // + static const char conf_key_climo_mean[] = "climo_mean"; static const char conf_key_climo_mean_field[] = "climo_mean.field"; static const char conf_key_climo_stdev[] = "climo_stdev"; @@ -746,6 +748,7 @@ static const char conf_key_climo_stdev_field[] = "climo_stdev.field"; // // Climatology distribution parameter key names // + static const char conf_key_climo_cdf[] = "climo_cdf"; static const char conf_key_cdf_bins[] = "cdf_bins"; static const char conf_key_center_bins[] = "center_bins"; @@ -758,6 +761,7 @@ static const char conf_key_hour_interval[] = "hour_interval"; // // Point-Stat specific parameter key names // + static const char conf_key_hira[] = "hira"; static const char conf_key_land_mask[] = "land_mask"; static const char conf_key_land_mask_flag[] = "land_mask.flag"; @@ -767,9 +771,17 @@ static const char conf_key_use_obs_thresh[] = "use_obs_thresh"; static const char conf_key_interp_fcst_thresh[] = "interp_fcst_thresh"; static const char conf_key_point_weight_flag[] = "point_weight_flag"; +// +// Pair-Stat specific parameter key names +// + +static const char conf_key_fcst_pairs[] = "fcst.pairs"; +static const char conf_key_obs_pairs[] = "obs.pairs"; + // // Grid-Stat specific parameter key names // + static const char conf_key_nc_pairs_var_name[] = "nc_pairs_var_name"; static const char conf_key_nc_pairs_var_suffix[] = "nc_pairs_var_suffix"; // nc_pairs_var_str is deprecated and replaced by nc_pairs_var_suffix From 4a9c387845ebf5c19712d24df5064091c0121edf Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 26 Dec 2024 16:52:04 +0000 Subject: [PATCH 02/15] Per #3006, define new GrdFileType::FileType_Pairs enumerated value to be used in the pair_stat tool. --- src/basic/vx_config/data_file_type.h | 1 + src/basic/vx_config/grdfiletype_to_string.cc | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/basic/vx_config/data_file_type.h b/src/basic/vx_config/data_file_type.h index 9fbefee775..e40a9bcdb7 100644 --- a/src/basic/vx_config/data_file_type.h +++ b/src/basic/vx_config/data_file_type.h @@ -33,6 +33,7 @@ enum GrdFileType { FileType_Python_Numpy, // Python script using numpy array and attributes dictionary FileType_Python_Xarray, // Python script using xarray dataplane FileType_UGrid, // Unstructured grid + FileType_Pairs, // Paired data }; diff --git a/src/basic/vx_config/grdfiletype_to_string.cc b/src/basic/vx_config/grdfiletype_to_string.cc index c9e89451c3..39ac64b246 100644 --- a/src/basic/vx_config/grdfiletype_to_string.cc +++ b/src/basic/vx_config/grdfiletype_to_string.cc @@ -57,6 +57,7 @@ switch ( t ) { case FileType_Python_Numpy: s = "FileType_Python_Numpy"; break; case FileType_Python_Xarray: s = "FileType_Python_Xarray"; break; case FileType_UGrid: s = "FileType_UGrid"; break; + case FileType_Pairs: s = "FileType_Pairs"; break; default: s = "(bad value)"; @@ -92,6 +93,7 @@ else if ( strcmp(text, "FileType_Bufr" ) == 0 ) { t = FileType_Bufr; else if ( strcmp(text, "FileType_Python_Numpy" ) == 0 ) { t = FileType_Python_Numpy; return true; } else if ( strcmp(text, "FileType_Python_Xarray" ) == 0 ) { t = FileType_Python_Xarray; return true; } else if ( strcmp(text, "FileType_UGrid" ) == 0 ) { t = FileType_UGrid; return true; } +else if ( strcmp(text, "FileType_Pairs" ) == 0 ) { t = FileType_Pairs; return true; } // // nope // From 5325ee980a5213ba6f5b767580162fe88c5a3ccb Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 26 Dec 2024 16:55:31 +0000 Subject: [PATCH 03/15] Per #3006, update pair_stat to use the newly added GrdFileType::FileType_Pairs enumerated value. --- data/config/PairStatConfig_default | 14 ++++++++++++++ src/tools/core/pair_stat/pair_stat.cc | 16 ++++++++++++++-- src/tools/core/pair_stat/pair_stat_conf_info.cc | 16 ++++++++-------- src/tools/core/pair_stat/pair_stat_conf_info.h | 2 +- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/data/config/PairStatConfig_default b/data/config/PairStatConfig_default index 1f0a1ccedb..2e165335f0 100644 --- a/data/config/PairStatConfig_default +++ b/data/config/PairStatConfig_default @@ -44,6 +44,20 @@ obs = { //////////////////////////////////////////////////////////////////////////////// +// +// Mapping of message type group name to comma-separated list of values +// +message_type_group_map = [ + { key = "SURFACE"; val = "ADPSFC,SFCSHP,MSONET"; }, + { key = "ANYAIR"; val = "AIRCAR,AIRCFT"; }, + { key = "ANYSFC"; val = "ADPSFC,SFCSHP,ADPUPA,PROFLR,MSONET"; }, + { key = "ONLYSF"; val = "ADPSFC,SFCSHP"; }, + { key = "LANDSF"; val = "ADPSFC,MSONET"; }, + { key = "WATERSF"; val = "SFCSHP"; } +]; + +//////////////////////////////////////////////////////////////////////////////// + // // Forecast and observation data censoring, thresholding, and filtering options // May be set separately in each "fcst.pairs" or "obs.pairs" entry diff --git a/src/tools/core/pair_stat/pair_stat.cc b/src/tools/core/pair_stat/pair_stat.cc index 43a18179a3..9749aa6635 100644 --- a/src/tools/core/pair_stat/pair_stat.cc +++ b/src/tools/core/pair_stat/pair_stat.cc @@ -210,7 +210,12 @@ void process_command_line(int argc, char **argv) { << "Pairs File(s): " << write_css(pairs_files) << "\n"; // Set the model name - shc.set_model(conf_info.model.c_str()); + if(conf_info.model.empty()) { + shc.set_model(na_str); + } + else { + shc.set_model(conf_info.model.c_str()); + } // Use the first verification task to set the random number generator // and seed value for bootstrap confidence intervals @@ -869,7 +874,12 @@ void process_scores() { if(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa.n_planes() == 0) continue; // Store the description - shc.set_desc(conf_info.vx_opt[i_vx].vx_pd.desc.c_str()); + if(conf_info.vx_opt[i_vx].vx_pd.desc.empty()) { + shc.set_desc(na_str); + } + else { + shc.set_desc(conf_info.vx_opt[i_vx].vx_pd.desc.c_str()); + } // Store the forecast variable name shc.set_fcst_var(conf_info.vx_opt[i_vx].vx_pd.fcst_info->name_attr()); @@ -2149,6 +2159,8 @@ void usage() { << "\t[-log file]\n" << "\t[-v level]\n\n" + +// JHG change -pairs file to -pairs file_list to support a long list of inputs << "\twhere\t\"-pairs file\" is one or more files containing " << "forecast/observation pairs. May be used multiple times " << "(required).\n" diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.cc b/src/tools/core/pair_stat/pair_stat_conf_info.cc index afc9044232..957c526056 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.cc +++ b/src/tools/core/pair_stat/pair_stat_conf_info.cc @@ -142,7 +142,7 @@ void PairStatConfInfo::process_config(PairsFormat ftype) { version = parse_conf_version(&conf); // Conf: model - model = parse_conf_string(&conf, conf_key_model); + model = parse_conf_string(&conf, conf_key_model, false); // Conf: point_weight_flag point_weight_flag = parse_conf_point_weight_flag(&conf); @@ -156,9 +156,9 @@ void PairStatConfInfo::process_config(PairsFormat ftype) { // Conf: message_type_group_map msg_typ_group_map = parse_conf_message_type_group_map(&conf); - // Conf: fcst.field and obs.field - fdict = conf.lookup_array(conf_key_fcst_field); - odict = conf.lookup_array(conf_key_obs_field); + // Conf: fcst.pairs and obs.pairs + fdict = conf.lookup_array(conf_key_fcst_pairs); + odict = conf.lookup_array(conf_key_obs_pairs); // Determine the number of fields (name/level) to be verified n_fvx = parse_conf_n_vx(fdict); @@ -168,9 +168,9 @@ void PairStatConfInfo::process_config(PairsFormat ftype) { if(n_fvx == 0 || n_fvx != n_ovx) { mlog << Error << "\nPairStatConfInfo::process_config() -> " << "The number of verification tasks in \"" - << conf_key_obs_field << "\" (" << n_ovx + << conf_key_obs_pairs << "\" (" << n_ovx << ") must be non-zero and match the number in \"" - << conf_key_fcst_field << "\" (" << n_fvx << ").\n\n"; + << conf_key_fcst_pairs << "\" (" << n_fvx << ").\n\n"; exit(1); } @@ -800,8 +800,8 @@ void PairStatVxOpt::process_config(PairsFormat ftype, clear(); // Allocate new VarInfo objects - vx_pd.set_fcst_info(info_factory.new_var_info(FileType_None)); - vx_pd.set_obs_info(info_factory.new_var_info(FileType_None)); + vx_pd.set_fcst_info(info_factory.new_var_info(FileType_Pairs)); + vx_pd.set_obs_info(info_factory.new_var_info(FileType_Pairs)); // Set the VarInfo objects vx_pd.fcst_info->set_dict(fdict); diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.h b/src/tools/core/pair_stat/pair_stat_conf_info.h index 34dd66946b..1ebea15d53 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.h +++ b/src/tools/core/pair_stat/pair_stat_conf_info.h @@ -239,7 +239,7 @@ class PairStatConfInfo { // Pair-Stat configuration object MetConfig conf; - // Store data parsed from the Pair-Stat configuration object + // Model name from the Pair-Stat config file ConcatString model; // Model name std::vector vx_opt; // Vector of vx options [n_vx] From 7e2cad1aaf3b1fe1653c896152ecb86cca6a991d Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 26 Dec 2024 17:19:36 +0000 Subject: [PATCH 04/15] Per #3006, rerun bootstrap on seneca to incorporate the compilation of the vx_ioda library. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 565ad93737..19da79f5f4 100755 --- a/configure +++ b/configure @@ -10197,7 +10197,7 @@ fi # Create configured files -ac_config_files="$ac_config_files Makefile scripts/Rscripts/Makefile scripts/Rscripts/include/Makefile scripts/python/Makefile scripts/python/examples/Makefile scripts/python/met/Makefile scripts/python/pyembed/Makefile scripts/python/utility/Makefile scripts/python/tc_diag/Makefile scripts/python/tc_diag/atcf_tools/Makefile scripts/python/tc_diag/config/Makefile scripts/python/tc_diag/diag_lib/Makefile scripts/python/tc_diag/tc_diag_driver/Makefile data/Makefile data/climo/Makefile data/climo/seeps/Makefile data/colortables/Makefile data/colortables/NCL_colortables/Makefile data/config/Makefile data/map/Makefile data/map/admin_by_country/Makefile data/poly/Makefile data/poly/HMT_masks/Makefile data/poly/NCEP_masks/Makefile data/ps/Makefile data/table_files/Makefile data/tc_data/Makefile src/Makefile src/basic/Makefile src/basic/enum_to_string/Makefile src/basic/vx_cal/Makefile src/basic/vx_config/Makefile src/basic/vx_log/Makefile src/basic/vx_math/Makefile src/basic/vx_util/Makefile src/basic/vx_util_math/Makefile src/libcode/Makefile src/libcode/vx_afm/Makefile src/libcode/vx_analysis_util/Makefile src/libcode/vx_color/Makefile src/libcode/vx_data2d/Makefile src/libcode/vx_data2d_factory/Makefile src/libcode/vx_data2d_grib/Makefile src/libcode/vx_data2d_grib2/Makefile src/libcode/vx_data2d_nc_met/Makefile src/libcode/vx_data2d_nc_wrf/Makefile src/libcode/vx_data2d_nc_cf/Makefile src/libcode/vx_data2d_ugrid/Makefile src/libcode/vx_geodesy/Makefile src/libcode/vx_gis/Makefile src/libcode/vx_gnomon/Makefile src/libcode/vx_grid/Makefile src/libcode/vx_gsl_prob/Makefile src/libcode/vx_ioda/Makefile src/libcode/vx_nav/Makefile src/libcode/vx_solar/Makefile src/libcode/vx_nc_obs/Makefile src/libcode/vx_nc_util/Makefile src/libcode/vx_pb_util/Makefile src/libcode/vx_plot_util/Makefile src/libcode/vx_ps/Makefile src/libcode/vx_pxm/Makefile src/libcode/vx_render/Makefile src/libcode/vx_shapedata/Makefile src/libcode/vx_stat_out/Makefile src/libcode/vx_statistics/Makefile src/libcode/vx_time_series/Makefile src/libcode/vx_physics/Makefile src/libcode/vx_series_data/Makefile src/libcode/vx_regrid/Makefile src/libcode/vx_tc_util/Makefile src/libcode/vx_summary/Makefile src/libcode/vx_python3_utils/Makefile src/libcode/vx_data2d_python/Makefile src/libcode/vx_bool_calc/Makefile src/libcode/vx_pointdata_python/Makefile src/libcode/vx_seeps/Makefile src/tools/Makefile src/tools/core/Makefile src/tools/core/ensemble_stat/Makefile src/tools/core/grid_stat/Makefile src/tools/core/mode/Makefile src/tools/core/mode_analysis/Makefile src/tools/core/pcp_combine/Makefile src/tools/core/point_stat/Makefile src/tools/core/pair_stat/Makefile src/tools/core/series_analysis/Makefile src/tools/core/stat_analysis/Makefile src/tools/core/wavelet_stat/Makefile src/tools/other/Makefile src/tools/other/ascii2nc/Makefile src/tools/other/lidar2nc/Makefile src/tools/other/gen_ens_prod/Makefile src/tools/other/gen_vx_mask/Makefile src/tools/other/gis_utils/Makefile src/tools/other/ioda2nc/Makefile src/tools/other/madis2nc/Makefile src/tools/other/mode_graphics/Makefile src/tools/other/modis_regrid/Makefile src/tools/other/pb2nc/Makefile src/tools/other/plot_data_plane/Makefile src/tools/other/plot_point_obs/Makefile src/tools/other/wwmca_tool/Makefile src/tools/other/gsi_tools/Makefile src/tools/other/regrid_data_plane/Makefile src/tools/other/point2grid/Makefile src/tools/other/shift_data_plane/Makefile src/tools/other/mode_time_domain/Makefile src/tools/other/grid_diag/Makefile src/tools/tc_utils/Makefile src/tools/tc_utils/tc_dland/Makefile src/tools/tc_utils/tc_pairs/Makefile src/tools/tc_utils/tc_stat/Makefile src/tools/tc_utils/tc_gen/Makefile src/tools/tc_utils/rmw_analysis/Makefile src/tools/tc_utils/tc_rmw/Makefile src/tools/tc_utils/tc_diag/Makefile" +ac_config_files="$ac_config_files Makefile scripts/Rscripts/Makefile scripts/Rscripts/include/Makefile scripts/python/Makefile scripts/python/examples/Makefile scripts/python/met/Makefile scripts/python/pyembed/Makefile scripts/python/utility/Makefile scripts/python/tc_diag/Makefile scripts/python/tc_diag/atcf_tools/Makefile scripts/python/tc_diag/config/Makefile scripts/python/tc_diag/diag_lib/Makefile scripts/python/tc_diag/tc_diag_driver/Makefile data/Makefile data/climo/Makefile data/climo/seeps/Makefile data/colortables/Makefile data/colortables/NCL_colortables/Makefile data/config/Makefile data/map/Makefile data/map/admin_by_country/Makefile data/poly/Makefile data/poly/HMT_masks/Makefile data/poly/NCEP_masks/Makefile data/ps/Makefile data/table_files/Makefile data/tc_data/Makefile src/Makefile src/basic/Makefile src/basic/enum_to_string/Makefile src/basic/vx_cal/Makefile src/basic/vx_config/Makefile src/basic/vx_log/Makefile src/basic/vx_math/Makefile src/basic/vx_util/Makefile src/basic/vx_util_math/Makefile src/libcode/Makefile src/libcode/vx_afm/Makefile src/libcode/vx_analysis_util/Makefile src/libcode/vx_color/Makefile src/libcode/vx_data2d/Makefile src/libcode/vx_data2d_factory/Makefile src/libcode/vx_data2d_grib/Makefile src/libcode/vx_data2d_grib2/Makefile src/libcode/vx_data2d_nc_met/Makefile src/libcode/vx_data2d_nc_wrf/Makefile src/libcode/vx_data2d_nc_cf/Makefile src/libcode/vx_data2d_ugrid/Makefile src/libcode/vx_geodesy/Makefile src/libcode/vx_gis/Makefile src/libcode/vx_gnomon/Makefile src/libcode/vx_grid/Makefile src/libcode/vx_gsl_prob/Makefile src/libcode/vx_nav/Makefile src/libcode/vx_solar/Makefile src/libcode/vx_nc_obs/Makefile src/libcode/vx_nc_util/Makefile src/libcode/vx_pb_util/Makefile src/libcode/vx_plot_util/Makefile src/libcode/vx_ps/Makefile src/libcode/vx_pxm/Makefile src/libcode/vx_render/Makefile src/libcode/vx_shapedata/Makefile src/libcode/vx_stat_out/Makefile src/libcode/vx_statistics/Makefile src/libcode/vx_time_series/Makefile src/libcode/vx_physics/Makefile src/libcode/vx_series_data/Makefile src/libcode/vx_regrid/Makefile src/libcode/vx_tc_util/Makefile src/libcode/vx_summary/Makefile src/libcode/vx_python3_utils/Makefile src/libcode/vx_data2d_python/Makefile src/libcode/vx_bool_calc/Makefile src/libcode/vx_pointdata_python/Makefile src/libcode/vx_seeps/Makefile src/libcode/vx_ioda/Makefile src/tools/Makefile src/tools/core/Makefile src/tools/core/ensemble_stat/Makefile src/tools/core/grid_stat/Makefile src/tools/core/mode/Makefile src/tools/core/mode_analysis/Makefile src/tools/core/pcp_combine/Makefile src/tools/core/point_stat/Makefile src/tools/core/pair_stat/Makefile src/tools/core/series_analysis/Makefile src/tools/core/stat_analysis/Makefile src/tools/core/wavelet_stat/Makefile src/tools/other/Makefile src/tools/other/ascii2nc/Makefile src/tools/other/lidar2nc/Makefile src/tools/other/gen_ens_prod/Makefile src/tools/other/gen_vx_mask/Makefile src/tools/other/gis_utils/Makefile src/tools/other/ioda2nc/Makefile src/tools/other/madis2nc/Makefile src/tools/other/mode_graphics/Makefile src/tools/other/modis_regrid/Makefile src/tools/other/pb2nc/Makefile src/tools/other/plot_data_plane/Makefile src/tools/other/plot_point_obs/Makefile src/tools/other/wwmca_tool/Makefile src/tools/other/gsi_tools/Makefile src/tools/other/regrid_data_plane/Makefile src/tools/other/point2grid/Makefile src/tools/other/shift_data_plane/Makefile src/tools/other/mode_time_domain/Makefile src/tools/other/grid_diag/Makefile src/tools/tc_utils/Makefile src/tools/tc_utils/tc_dland/Makefile src/tools/tc_utils/tc_pairs/Makefile src/tools/tc_utils/tc_stat/Makefile src/tools/tc_utils/tc_gen/Makefile src/tools/tc_utils/rmw_analysis/Makefile src/tools/tc_utils/tc_rmw/Makefile src/tools/tc_utils/tc_diag/Makefile" if test -n "$MET_DEVELOPMENT"; then From 0b930096aa27d54b60060cd5bd178ecc5a5f8386 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 26 Dec 2024 11:23:37 -0700 Subject: [PATCH 05/15] Per #3006, make docs build without warning --- docs/Users_Guide/grid-stat.rst | 4 +- docs/Users_Guide/pair-stat.rst | 1607 +------------------------------ docs/Users_Guide/point-stat.rst | 4 +- 3 files changed, 38 insertions(+), 1577 deletions(-) diff --git a/docs/Users_Guide/grid-stat.rst b/docs/Users_Guide/grid-stat.rst index b45fbe9521..056135c07e 100644 --- a/docs/Users_Guide/grid-stat.rst +++ b/docs/Users_Guide/grid-stat.rst @@ -9,7 +9,7 @@ Introduction The Grid-Stat tool functions in much the same way as the Point-Stat tool, except that the verification statistics it calculates are for a matched forecast-observation grid (as opposed to a set of observation points). Neither the forecast nor the observation grid needs to be identical to the final matched grid. If the forecast grid is different from the final matched grid, then forecast values are regridded (interpolated) to the final matched grid. The same procedure is followed for observations. No regridding is necessary if the forecast and observation grids are identical but remains optional. A smoothing operation may be performed on the forecast and observation fields prior to verification. All the matched forecast-observation grid points are used to compute the verification statistics. In addition to traditional verification approaches, the Grid-Stat tool includes Fourier decompositions, gradient statistics, distance metrics, and neighborhood methods, designed to examine forecast performance as a function of spatial scale. -Scientific and statistical aspects of the Grid-Stat tool are briefly described in this section, followed by practical details regarding usage and output from the tool. +Scientific and statistical aspects of the Grid-Stat tool are briefly described in this section. Practical aspects of the Grid-Stat tool are described in :numref:`grid-stat_practical_info`. Scientific and Statistical Aspects ================================== @@ -156,6 +156,8 @@ In some cases, a user may be interested in a much higher threshold than :math:`2 Since :math:`G_\beta` is so sensitive to the choice of :math:`\beta`, which is defined relative to the number of points in the verification domain, :math:`G_\beta` is only computed for the full verification domain. :math:`G_\beta` is reported as a bad data value for any masking region subsets of the full verification domain. +.. _grid-stat_practical_info: + Practical Information ===================== diff --git a/docs/Users_Guide/pair-stat.rst b/docs/Users_Guide/pair-stat.rst index c470209c0c..573d5de8a0 100644 --- a/docs/Users_Guide/pair-stat.rst +++ b/docs/Users_Guide/pair-stat.rst @@ -7,257 +7,16 @@ Pair-Stat Tool Introduction ============ -The Pair-Stat tool provides verification statistics for forecasts at observation points (as opposed to over gridded analyses). The Pair-Stat tool matches gridded forecasts to point observation locations and supports several different interpolation options. The tool then computes continuous, categorical, spatial, and probabilistic verification statistics. The categorical and probabilistic statistics generally are derived by applying a threshold to the forecast and observation values. Confidence intervals - representing the uncertainty in the verification measures - are computed for the verification statistics. +The Pair-Stat tool provides verification statistics for forecast and observation data that has already been paired. While no smoothing, regridding, or interpolation methods apply, the Pair-Stat tool filters and groups the pairs temporally and spatially. It then computes continuous, categorical, and probabilistic verification statistics. The categorical and probabilistic statistics generally are derived by applying a threshold to the forecast and observation values. Confidence intervals - representing the uncertainty in the verification measures - are computed for the verification statistics. -Scientific and statistical aspects of the Pair-Stat tool are discussed in the following section. Practical aspects of the Pair-Stat tool are described in :numref:`tc-stat_practical-information`. +Scientific and statistical aspects of the Pair-Stat tool are discussed in the following section. Practical aspects of the Pair-Stat tool are described in :numref:`pair-stat_practical_info`. Scientific and Statistical Aspects ================================== The statistical methods and measures computed by the Pair-Stat tool are described briefly in this section. In addition, :numref:`matching-methods` discusses the various interpolation options available for matching the forecast grid point values to the observation points. The statistical measures computed by the Pair-Stat tool are described briefly in :numref:`PS_Statistical-measures` and in more detail in :numref:`Appendix C, Section %s `. :numref:`PS_Statistical-confidence-intervals` describes the methods for computing confidence intervals that are applied to some of the measures computed by the Pair-Stat tool; more detail on confidence intervals is provided in :numref:`Appendix D, Section %s `. -.. _matching-methods: - -Interpolation/Matching Methods ------------------------------- - -This section provides information about the various methods available in MET to match gridded model output to point observations. Matching in the vertical and horizontal are completed separately using different methods. - -In the vertical, if forecasts and observations are at the same vertical level, then they are paired as-is. If any discrepancy exists between the vertical levels, then the forecasts are interpolated to the level of the observation. The vertical interpolation is done in the natural log of pressure coordinates, except for specific humidity, which is interpolated using the natural log of specific humidity in the natural log of pressure coordinates. Vertical interpolation for heights above ground are done linear in height coordinates. When forecasts are for the surface, no interpolation is done. They are matched to observations with message types that are mapped to "SURFACE" in the **message_type_group_map** configuration option. By default, the surface message types include ADPSFC, SFCSHP, and MSONET. The regular expression is applied to the message type list at the message_type_group_map. The derived message types from the time summary ("ADPSFC_MIN_hhmmss" and "ADPSFC_MAX_hhmmss") are accepted as "ADPSFC". - -To match forecasts and observations in the horizontal plane, the user can select from a number of methods described below. Many of these methods require the user to define the width of the forecast grid W, around each observation point P, that should be considered. In addition, the user can select the interpolation shape, either a SQUARE or a CIRCLE. For example, a square of width 2 defines the 2 x 2 set of grid points enclosing P, or simply the 4 grid points closest to P. A square of width of 3 defines a 3 x 3 square consisting of 9 grid points centered on the grid point closest to P. :numref:`pair_stat_fig1` provides illustration. The point P denotes the observation location where the interpolated value is calculated. The interpolation width W, shown is five. - -This section describes the options for interpolation in the horizontal. - -.. _pair_stat_fig1: - -.. figure:: figure/pair_stat_fig1.png - - Diagram illustrating matching and interpolation methods used in MET. See text for explanation. - -.. _pair_stat_fig2: - -.. figure:: figure/pair_stat_fig2.jpg - - Illustration of some matching and interpolation methods used in MET. See text for explanation. - -____________________ - -**Nearest Neighbor** - -The forecast value at P is assigned the value at the nearest grid point. No interpolation is performed. Here, "nearest" means spatially closest in horizontal grid coordinates. This method is used by default when the interpolation width, W, is set to 1. - -_____________________ - -**Geography Match** - -The forecast value at P is assigned the value at the nearest grid point in the interpolation area where the land/sea mask and topography criteria are satisfied. - -_____________________ - -**Gaussian** - -The forecast value at P is a weighted sum of the values in the interpolation area. The weight given to each forecast point follows the Gaussian distribution with nearby points contributing more the far away points. The shape of the distribution is configured using sigma. - -When used for regridding, with the **regrid** configuration option, or smoothing, with the **interp** configuration option in grid-to-grid comparisons, the Gaussian method is named **MAXGAUSS** and is implemented as a 2-step process. First, the data is regridded or smoothed using the maximum value interpolation method described below, where the **width** and **shape** define the interpolation area. Second, the Gaussian smoother, defined by the **gaussian_dx** and **gaussian_radius** configuration options, is applied. - -_____________________ - -**Minimum value** - -The forecast value at P is the minimum of the values in the interpolation area. - -_____________________ - -**Maximum value** - -The forecast value at P is the maximum of the values in the interpolation area. - -______________________ - -**Distance-weighted mean** - -The forecast value at P is a weighted sum of the values in the interpolation area. The weight given to each forecast point is the reciprocal of the square of the distance (in grid coordinates) from P. The weighted sum of forecast values is normalized by dividing by the sum of the weights. - -_______________________ - -**Unweighted mean** - -This method is similar to the distance-weighted mean, except all the weights are equal to 1. The distance of any point from P is not considered. - -_____________________ - -**Median** - -The forecast value at P is the median of the forecast values in the interpolation area. - -_____________________ - -**Least-Squares Fit** - -To perform least squares interpolation of a gridded field at a location P, MET uses an **WxW** subgrid centered (as closely as possible) at P. :numref:`pair_stat_fig1` shows the case where W = 5. - -If we denote the horizontal coordinate in this subgrid by x, and vertical coordinate by y, then we can assign coordinates to the point P relative to this subgrid. These coordinates are chosen so that the center of the grid is. For example, in :numref:`pair_stat_fig1`, P has coordinates (-0.4, 0.2). Since the grid is centered near P, the coordinates of P should always be at most 0.5 in absolute value. At each of the vertices of the grid (indicated by black dots in the figure), we have data values. We would like to use these values to interpolate a value at P. We do this using least squares. If we denote the interpolated value by z, then we fit an expression of the form :math:`z=\alpha (x) + \beta (y) + \gamma` over the subgrid. The values of :math:`\alpha, \beta, \gamma` are calculated from the data values at the vertices. Finally, the coordinates (**x,y**) of P are substituted into this expression to give z, our least squares interpolated data value at P. - -_______________________ - -**Bilinear Interpolation** - -This method is performed using the four closest grid squares. The forecast values are interpolated linearly first in one dimension and then the other to the location of the observation. - -________________________ - -**Upper Left, Upper Right, Lower Left, Lower Right Interpolation** - -This method is performed using the four closest grid squares. The forecast values are interpolated to the specified grid point. - -_______________________ - -**Best Interpolation** - -The forecast value at P is chosen as the grid point inside the interpolation area whose value most closely matches the observation value. - -.. _PS_HiRA_framework: - -HiRA Framework --------------- - -The Pair-Stat tool has been enhanced to include the High Resolution Assessment (HiRA) verification logic (:ref:`Mittermaier, 2014 `). HiRA is analogous to neighborhood verification but for point observations. The HiRA logic interprets the forecast values surrounding each point observation as an ensemble forecast. These ensemble values are processed in three ways. First, the ensemble continuous statistics (ECNT), the observation rank statistics (ORANK) and the ranked probability score (RPS) line types are computed directly from the ensemble values. Second, for each categorical threshold specified, a fractional coverage value is computed as the ratio of the nearby forecast values that meet the threshold criteria. Pair-Stat evaluates those fractional coverage values as if they were a probability forecast. When applying HiRA, users should enable the matched pair (MPR), probabilistic (PCT, PSTD, PJC, or PRC), continuous ensemble statistics (ECNT), observation rank statistics (ORANK) or ranked probability score (RPS) line types in the **output_flag** dictionary. The number of probabilistic HiRA output lines is determined by the number of categorical forecast thresholds and HiRA neighborhood widths chosen. - -The HiRA framework provides a unique method for evaluating models in the neighborhood of point observations, allowing for some spatial and temporal uncertainty in the forecast and/or the observations. Additionally, the HiRA framework can be used to compare deterministic forecasts to ensemble forecasts. In MET, the neighborhood is a circle or square centered on the grid point closest to the observation location. An event is defined, then the proportion of points with events in the neighborhood is calculated. This proportion is treated as an ensemble probability, though it is likely to be uncalibrated. - -:numref:`pair_stat_fig3` shows a couple of examples of how the HiRA proportion is derived at a single model level using square neighborhoods. Events (in our case, model accretion values > 0) are separated from non-events (model accretion value = 0). Then, in each neighborhood, the total proportion of events is calculated. In the leftmost panel, four events exist in the 25 point neighborhood, making the HiRA proportion is 4/25 = 0.16. For the neighborhood of size 9 centered in that same panel, the HiRA proportion is 1/9. In the right panel, the size 25 neighborhood has HiRA proportion of 6/25, with the centered 9-point neighborhood having a HiRA value of 2/9. To extend this method into 3-dimensions, all layers within the user-defined layer are also included in the calculation of the proportion in the same manner. - -.. _pair_stat_fig3: - -.. figure:: figure/pair_stat_fig3.png - - Example showing how HiRA proportions are calculated. - -Often, the neighborhood size is chosen so that multiple models to be compared have approximately the same horizontal resolution. Then, standard metrics for probabilistic forecasts, such as Brier Score, can be used to compare those forecasts. HiRA was developed using surface observation stations so the neighborhood lies completely within the horizontal plane. With any type of upper air observation, the vertical neighborhood must also be defined. - -.. _PS_seeps: - -SEEPS Scores ------------- - -The Stable Equitable Error in Probability Space (SEEPS) was devised for monitoring global deterministic forecasts of precipitation against the WMO gauge network (:ref:`Rodwell et al., 2010 `; :ref:`Haiden et al., 2012 `) and is a multi-category score which uses a climatology to account for local variations in behavior. Since the score uses probability space to define categories using the climatology, it can be aggregated over heterogeneous climate regions. Even though it was developed for use with precipitation forecasts, in principle it could be applied to any forecast parameter for which a sufficiently long time period of observations exists to create a suitable climatology. The computation of SEEPS for precipitation is only supported for now. - -For use with precipitation, three categories are used, named ‘dry’, ‘light’ and ‘heavy’. The ‘dry’ category is defined (using the WMO observing guidelines) with any accumulation (rounded to the nearest 0.1 millimeter) that is less than or equal to 0.2 mm. The remaining precipitation is divided into ‘light’ and ‘heavy’ categories whose thresholds are with respect to a climatology and thus location specific. The light precipitation is defined to occur twice as often as heavy precipitation. - -When calculating a single SEEPS value over observing stations for a particular region, the scores should have a density weighting applied which accounts for uneven station distribution in the region of interest (see Section 9.1 in :ref:`Rodwell et al., 2010 `). This density weighting has not yet been implemented in MET. Global precipitation climatologies calculated from the WMO SYNOP records from 1980-2009 are supplied with the release. At the moment, a 24-hour climatology is available (valid at 00 UTC or 12 UTC), but in future a 6-hour climatology will become available. - -.. _PS_Statistical-measures: - -Statistical Measures --------------------- - -The Pair-Stat tool computes a wide variety of verification statistics. Broadly speaking, these statistics can be subdivided into statistics for categorical variables and statistics for continuous variables. The categories of measures are briefly described here; specific descriptions of the measures are provided in :numref:`Appendix C, Section %s `. Additional information can be found in :ref:`Wilks (2011) ` and :ref:`Jolliffe and Stephenson (2012) `, and at Collaboration for Australian Weather and Climate Research. Forecast Verification - `Issues, Methods and FAQ web page. `_ - -In addition to these verification measures, the Pair-Stat tool also computes partial sums and other FHO statistics that are produced by the NCEP verification system. These statistics are also described in :numref:`Appendix C, Section %s `. - -Measures for Categorical Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Categorical verification statistics are used to evaluate forecasts that are in the form of a discrete set of categories rather than on a continuous scale. If the original forecast is continuous, the user may specify one or more thresholds in the configuration file to divide the continuous measure into categories. Currently, Pair-Stat computes categorical statistics for variables in two or more categories. The special case of dichotomous (i.e., 2-category) variables has several types of statistics calculated from the resulting contingency table and are available in the CTS output line type. For multi-category variables, fewer statistics can be calculated so these are available separately, in line type MCTS. Categorical variables can be intrinsic (e.g., rain/no-rain) or they may be formed by applying one or more thresholds to a continuous variable (e.g., temperature < 273.15 K or cloud coverage percentages in 10% bins). See :numref:`Appendix C, Section %s ` for more information. - -Measures for Continuous Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For continuous variables, many verification measures are based on the forecast error (i.e., f - o). However, it also is of interest to investigate characteristics of the forecasts, and the observations, as well as their relationship. These concepts are consistent with the general framework for verification outlined by :ref:`Murphy and Winkler (1987) `. The statistics produced by MET for continuous forecasts represent this philosophy of verification, which focuses on a variety of aspects of performance rather than a single measure. See :numref:`Appendix C, Section %s ` for specific information. - -A user may wish to eliminate certain values of the forecasts from the calculation of statistics, a process referred to here as``'conditional verification''. For example, a user may eliminate all temperatures above freezing and then calculate the error statistics only for those forecasts of below freezing temperatures. Another common example involves verification of wind forecasts. Since wind direction is indeterminate at very low wind speeds, the user may wish to set a minimum wind speed threshold prior to calculating error statistics for wind direction. The user may specify these thresholds in the configuration file to specify the conditional verification. Thresholds can be specified using the usual Fortran conventions (<, <=, ==, !-, >=, or >) followed by a numeric value. The threshold type may also be specified using two letter abbreviations (lt, le, eq, ne, ge, gt). Further, more complex thresholds can be achieved by defining multiple thresholds and using && or || to string together event definition logic. The forecast and observation threshold can be used together according to user preference by specifying one of: UNION, INTERSECTION, or SYMDIFF (symmetric difference). - -Measures for Probabilistic Forecasts and Dichotomous Outcomes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For probabilistic forecasts, many verification measures are based on reliability, accuracy and bias. However, it also is of interest to investigate joint and conditional distributions of the forecasts and the observations, as in :ref:`Wilks (2011) `. See :numref:`Appendix C, Section %s ` for specific information. - -Probabilistic forecast values are assumed to have a range of either 0 to 1 or 0 to 100. If the max data value is > 1, we assume the data range is 0 to 100, and divide all the values by 100. If the max data value is <= 1, then we use the values as is. Further, thresholds are applied to the probabilities with equality on the lower end. For example, with a forecast probability p, and thresholds t1 and t2, the range is defined as: t1 <= p < t2. The exception is for the highest set of thresholds, when the range includes 1: t1 <= p <= 1. To make configuration easier, in METv6.0, these probabilities may be specified in the configuration file as a list (>=0.00,>=0.25,>=0.50,>=0.75,>=1.00) or using shorthand notation (==0.25) for bins of equal width. - -When the "prob" entry is set as a dictionary to define the field of interest, setting "prob_as_scalar = TRUE" indicates that this data should be processed as regular scalars rather than probabilities. For example, this option can be used to compute traditional 2x2 contingency tables and neighborhood verification statistics for probability data. It can also be used to compare two probability fields directly. - -.. _Climatology: - -Measures for Comparison Against Climatology -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For each of the types of statistics mentioned above (categorical, continuous, and probabilistic), it is possible to calculate measures of skill relative to climatology. MET will accept a climatology file provided by the user, and will evaluate it as a reference forecast. Further, anomalies, i.e. departures from average conditions, can be calculated. As with all other statistics, the available measures will depend on the nature of the forecast. Common statistics that use a climatological reference include: the mean squared error skill score (MSESS), the Anomaly Correlation (ANOM_CORR and ANOM_CORR_UNCNTR), scalar and vector anomalies (SAL1L2 and VAL1L2), continuous ranked probability skill score (CRPSS and CRPSS_EMP), Brier Skill Score (BSS) (:ref:`Wilks, 2011 `; :ref:`Mason, 2004 `). - -Often, the sample climatology is used as a reference by a skill score. The sample climatology is the average over all included observations and may be transparent to the user. This is the case in most categorical skill scores. The sample climatology will probably prove more difficult to improve upon than a long term climatology, since it will be from the same locations and time periods as the forecasts. This may mask legitimate forecast skill. However, a more general climatology, perhaps covering many years, is often easier to improve upon and is less likely to mask real forecast skill. - -.. _PS_Statistical-confidence-intervals: - -Statistical Confidence Intervals --------------------------------- - -A single summary score gives an indication of the forecast performance, but it is a single realization from a random process that neglects uncertainty in the score's estimate. That is, it is possible to obtain a good score, but it may be that the "good" score was achieved by chance and does not reflect the "true" score. Therefore, when interpreting results from a verification analysis, it is imperative to analyze the uncertainty in the realized scores. One good way to do this is to utilize confidence intervals. A confidence interval indicates that if the process were repeated many times, say 100, then the true score would fall within the interval :math:`100(1-\alpha)\%` of the time. Typical values of :math:`\alpha` are 0.01, 0.05, and 0.10. The Pair-Stat tool allows the user to select one or more specific :math:`\alpha`-values to use. - -For continuous fields (e.g., temperature), it is possible to estimate confidence intervals for some measures of forecast performance based on the assumption that the data, or their errors, are normally distributed. The Pair-Stat tool computes confidence intervals for the following summary measures: forecast mean and standard deviation, observation mean and standard deviation, correlation, mean error, and the standard deviation of the error. In the case of the respective means, the central limit theorem suggests that the means are normally distributed, and this assumption leads to the usual :math:`100(1-\alpha)\%` confidence intervals for the mean. For the standard deviations of each field, one must be careful to check that the field of interest is normally distributed, as this assumption is necessary for the interpretation of the resulting confidence intervals. - -For the measures relating the two fields (i.e., mean error, correlation and standard deviation of the errors), confidence intervals are based on either the joint distributions of the two fields (e.g., with correlation) or on a function of the two fields. For the correlation, the underlying assumption is that the two fields follow a bivariate normal distribution. In the case of the mean error and the standard deviation of the mean error, the assumption is that the errors are normally distributed, which for continuous variables, is usually a reasonable assumption, even for the standard deviation of the errors. - -Bootstrap confidence intervals for any verification statistic are available in MET. Bootstrapping is a nonparametric statistical method for estimating parameters and uncertainty information. The idea is to obtain a sample of the verification statistic(s) of interest (e.g., bias, ETS, etc.) so that inferences can be made from this sample. The assumption is that the original sample of matched forecast-observation pairs is representative of the population. Several replicated samples are taken with replacement from this set of forecast-observation pairs of variables (e.g., precipitation, temperature, etc.), and the statistic(s) are calculated for each replicate. That is, given a set of n forecast-observation pairs, we draw values at random from these pairs, allowing the same pair to be drawn more than once, and the statistic(s) is (are) calculated for each replicated sample. This yields a sample of the statistic(s) based solely on the data without making any assumptions about the underlying distribution of the sample. It should be noted, however, that if the observed sample of matched pairs is dependent, then this dependence should be taken into account somehow. Currently, the confidence interval methods in MET do not take into account dependence, but future releases will support a robust method allowing for dependence in the original sample. More detailed information about the bootstrap algorithm is found in the :numref:`Appendix D, Section %s `. Note that MET writes temporary files whenever bootstrap confidence intervals are computed, as described in :numref:`Contributor's Guide Section %s `. - -Confidence intervals can be calculated from the sample of verification statistics obtained through the bootstrap algorithm. The most intuitive method is to simply take the appropriate quantiles of the sample of statistic(s). For example, if one wants a 95% CI, then one would take the 2.5 and 97.5 percentiles of the resulting sample. This method is called the percentile method, and has some nice properties. However, if the original sample is biased and/or has non-constant variance, then it is well known that this interval is too optimistic. The most robust, accurate, and well-behaved way to obtain accurate CIs from bootstrapping is to use the bias corrected and adjusted percentile method (or BCa). If there is no bias, and the variance is constant, then this method will yield the usual percentile interval. The only drawback to the approach is that it is computationally intensive. Therefore, both the percentile and BCa methods are available in MET, with the considerably more efficient percentile method being the default. - -The only other option associated with bootstrapping currently available in MET is to obtain replicated samples smaller than the original sample (i.e., to sample *m` for more information and references about this topic. - -MET provides parametric confidence intervals based on assumptions of normality for the following categorical statistics: - -• Base Rate - -• Forecast Mean - -• Accuracy - -• Probability of Detection - -• Probability of Detection of the non-event - -• Probability of False Detection - -• False Alarm Ratio - -• Critical Success Index - -• Hanssen-Kuipers Discriminant - -• Odds Ratio - -• Log Odds Ratio - -• Odds Ratio Skill Score - -• Extreme Dependency Score - -• Symmetric Extreme Dependency Score - -• Extreme Dependency Index - -• Symmetric Extremal Dependency Index - -MET provides parametric confidence intervals based on assumptions of normality for the following continuous statistics: - -• Forecast and Observation Means - -• Forecast, Observation, and Error Standard Deviations - -• Pearson Correlation Coefficient - -• Mean Error - -MET provides parametric confidence intervals based on assumptions of normality for the following probabilistic statistics: - -• Brier Score - -• Base Rate - -MET provides non-parametric bootstrap confidence intervals for many categorical and continuous statistics. Kendall's Tau and Spearman's Rank correlation coefficients are the only exceptions. Computing bootstrap confidence intervals for these statistics would be computationally unrealistic. - -For more information on confidence intervals pertaining to verification measures, see :ref:`Wilks (2011) `, :ref:`Jolliffe and Stephenson (2012) `, and Bradley (2008). - -.. _tc-stat_practical-information: +.. _pair-stat_practical_info: Practical Information ===================== @@ -267,1368 +26,68 @@ The Pair-Stat tool is used to perform verification of a gridded model field usin If no matched pairs are found for a particular verification task, a report listing counts for reasons why the observations were not used is written to the log output at the default verbosity level of 2. If matched pairs are found, this report is written at verbosity level 3. Inspecting these rejection reason counts is the first step in determining why Pair-Stat found no matched pairs. The order of the log messages matches the order in which the processing logic is applied. Start from the last log message and work your way up, considering each of the non-zero rejection reason counts. Verbosity level 9 prints a very detailed explanation about why each observation is used or skipped for each verification task. pair_stat Usage ----------------- +--------------- The usage statement for the Pair-Stat tool is shown below: .. code-block:: none Usage: pair_stat - fcst_file - obs_file - config_file - [-ugrid_config config_file] - [-point_obs file] - [-obs_valid_beg time] - [-obs_valid_end time] + -pairs file_1 ... file_n | file_list + -format type + -config config_file [-outdir path] [-log file] [-v level] -pair_stat has three required arguments and can take many optional ones. +pair_stat has three required arguments and accepts optional ones. Required Arguments for pair_stat ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -1. The **fcst_file** argument names the gridded file in either GRIB or NetCDF containing the model data to be verified. +1. The **-pairs** argument defines one or more input files containing forecast/observation pairs. + May be set as a list of file names (**file_1 ... file_n**) or as an ASCII file containing + a list file names (**file_list**). May be used multiple times (required). -2. The **obs_file** argument indicates the MET NetCDF point observation file to be used for verifying the model. Python embedding for point observations is also supported, as described in :numref:`pyembed-point-obs-data`. +2. The **format type** argument defines the input pairs file format and may be set to + "mpr" or "ioda" (required). -3. The **config_file** argument indicates the name of the configuration file to be used. The contents of the configuration file are discussed below. +3. The **-config config_file** argument is a PairStatConfig file containing the desired + configuration settings (required). Optional Arguments for pair_stat ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -5. The **-ugrid_config** option provides a way for a user to provide a separate config file with metadata about their UGRID. - -5. The **-point_obs** file may be used to pass additional NetCDF point observation files to be used in the verification. Python embedding for point observations is also supported, as described in :numref:`pyembed-point-obs-data`. - -6. The **-obs_valid_beg** time option in YYYYMMDD[_HH[MMSS]] format sets the beginning of the observation matching time window, overriding the configuration file setting. +4. The **-outdir path** option overrides the output directory which defaults to the current + working directory (optional). -7. The **-obs_valid_end** time option in YYYYMMDD[_HH[MMSS]] format sets the end of the observation matching time window, overriding the configuration file setting. +5. The **-log file** option directs output and errors to the specified log file. + All messages will be written to that file as well as standard out and error. + Thus, users can save the messages without having to redirect the output on the command line. + The default behavior is no log file. -8. The **-outdir path** indicates the directory where output files should be written. - -9. The **-log file** option directs output and errors to the specified log file. All messages will be written to that file as well as standard out and error. Thus, users can save the messages without having to redirect the output on the command line. The default behavior is no log file. - -10. The **-v level** option indicates the desired level of verbosity. The value of "level" will override the default setting of 2. Setting the verbosity to 0 will make the tool run with no log messages, while increasing the verbosity will increase the amount of logging. +6. The **-v level** option indicates the desired level of verbosity. + The value of "level" will override the default setting of 2. + Setting the verbosity to 0 will make the tool run with no log messages, + while increasing the verbosity will increase the amount of logging. An example of the pair_stat calling sequence is shown below: .. code-block:: none - pair_stat sample_fcst.grb \ - sample_pb.nc \ - PointStatConfig + pair_stat \ + -pairs point_stat_mpr.txt \ + -format mpr \ + -config PairStatConfig -In this example, the Pair-Stat tool evaluates the model data in the sample_fcst.grb GRIB file using the observations in the NetCDF output of PB2NC, sample_pb.nc, applying the configuration options specified in the **PointStatConfig file**. +In this example, the Pair-Stat tool reads matched pair data (**-format mpr**) from **point_stat_mpr.txt** +and applies the configuration options specified in the **PairStatConfig** file. pair_stat Configuration File ----------------------------- -The default configuration file for the Pair-Stat tool named **PointStatConfig_default** can be found in the installed *share/met/config* directory. Another version is located in *scripts/config*. We encourage users to make a copy of these files prior to modifying their contents. The contents of the configuration file are described in the subsections below. +The default configuration file for the Pair-Stat tool named **PairStatConfig_default** can be found in the installed *share/met/config* directory. Users are encouraged to make a copy prior to modifying its contents. The configuration file options are described in the subsections below. Note that environment variables may be used when editing configuration files, as described in the :numref:`config_env_vars`. -________________________ - -.. code-block:: none - - model = "FCST"; - desc = "NA"; - regrid = { ... } - climo_mean = { ... } - climo_stdev = { ... } - climo_cdf = { ... } - obs_window = { beg = -5400; end = 5400; } - mask = { grid = [ "FULL" ]; poly = []; sid = []; } - ci_alpha = [ 0.05 ]; - boot = { interval = PCTILE; rep_prop = 1.0; n_rep = 1000; - rng = "mt19937"; seed = ""; } - interp = { vld_thresh = 1.0; shape = SQUARE; - type = [ { method = NEAREST; width = 1; } ]; } - censor_thresh = []; - censor_val = []; - mpr_column = []; - mpr_thresh = []; - eclv_points = 0.05; - hss_ec_value = NA; - rank_corr_flag = TRUE; - sid_inc = []; - sid_exc = []; - duplicate_flag = NONE; - obs_quality_inc = []; - obs_quality_exc = []; - obs_summary = NONE; - obs_perc_value = 50; - message_type_group_map = [...]; - obtype_as_group_val_flag = FALSE; - point_weight_flag = NONE; - tmp_dir = "/tmp"; - output_prefix = ""; - version = "VN.N"; - -The configuration options listed above are common to multiple MET tools and are described in :numref:`config_options`. - -_________________________ - -Setting up the **fcst** and **obs** dictionaries of the configuration file is described in :numref:`config_options`. The following are some special considerations for the Pair-Stat tool. - -The **obs** dictionary looks very similar to the **fcst** dictionary. When the forecast and observation variables follow the same naming convention, one can easily copy over the forecast settings to the observation dictionary using **obs = fcst;**. However when verifying forecast data in NetCDF format or verifying against not-standard observation variables, users will need to specify the **fcst** and **obs** dictionaries separately. The number of fields specified in the **fcst** and **obs** dictionaries must match. - -The **message_type** entry, defined in the **obs** dictionary, contains a comma-separated list of the message types to use for verification. At least one entry must be provided. The Pair-Stat tool performs verification using observations for one message type at a time. See `Table 1.a Current Table A Entries in PREPBUFR mnemonic table `_ for a list of the possible types. If using **obs = fcst;**, it can be defined in the forecast dictionary and the copied into the observation dictionary. - -______________________ - -.. code-block:: none - - land_mask = { - flag = FALSE; - file_name = []; - field = { name = "LAND"; level = "L0"; } - regrid = { method = NEAREST; width = 1; } - thresh = eq1; - } - -The **land_mask** dictionary defines the land/sea mask field which is used when verifying at the surface. For point observations whose message type appears in the **LANDSF** entry of the **message_type_group_map** setting, only use forecast grid points where land = TRUE. For point observations whose message type appears in the **WATERSF** entry of the **message_type_group_map** setting, only use forecast grid points where land = FALSE. The **flag** entry enables/disables this logic. If the **file_name** is left empty, then the land/sea is assumed to exist in the input forecast file. Otherwise, the specified file(s) are searched for the data specified in the **field** entry. The **regrid** settings specify how this field should be regridded to the verification domain. Lastly, the **thresh** entry is the threshold which defines land (threshold is true) and water (threshold is false). - -__________________________ - -.. code-block:: none - - topo_mask = { - flag = FALSE; - file_name = []; - field = { name = "TOPO"; level = "L0"; } - regrid = { method = BILIN; width = 2; } - use_obs_thresh = ge-100&&le100; - interp_fcst_thresh = ge-50&&le50; - } - -The **topo_mask** dictionary defines the model topography field which is used when verifying at the surface. This logic is applied to point observations whose message type appears in the **SURFACE** entry of the **message_type_group_map** setting. Only use point observations where the topo - station elevation difference meets the **use_obs_thresh** threshold entry. For the observations kept, when interpolating forecast data to the observation location, only use forecast grid points where the topo - station difference meets the **interp_fcst_thresh** threshold entry. The **flag** entry enables/disables this logic. If the **file_name** is left empty, then the topography data is assumed to exist in the input forecast file. Otherwise, the specified file(s) are searched for the data specified in the **field** entry. The **regrid** settings specify how this field should be regridded to the verification domain. - -____________________________ - -.. code-block:: none - - hira = { - flag = FALSE; - width = [ 2, 3, 4, 5 ] - vld_thresh = 1.0; - cov_thresh = [ ==0.25 ]; - shape = SQUARE; - prob_cat_thresh = []; - } - -The **hira** dictionary that is very similar to the **interp** and **nbrhd** entries. It specifies information for applying the High Resolution Assessment (HiRA) verification logic described in section :numref:`PS_HiRA_framework`. The **flag** entry is a boolean which toggles HiRA on (**TRUE**) and off (**FALSE**). The **width** and **shape** entries define the neighborhood size and shape, respectively. Since HiRA applies to point observations, the width may be even or odd. The **vld_thresh** entry is the required ratio of valid data within the neighborhood to compute an output value. The **cov_thresh** entry is an array of probabilistic thresholds used to populate the Nx2 probabilistic contingency table written to the PCT output line and used for computing probabilistic statistics. The **prob_cat_thresh** entry defines the thresholds to be used in computing the ranked probability score in the RPS output line type. If left empty but climatology data is provided, the **climo_cdf** thresholds will be used instead of **prob_cat_thresh**. - -________________________ - -.. code-block:: none - - output_flag = { - fho = BOTH; - ctc = BOTH; - cts = BOTH; - mctc = BOTH; - mcts = BOTH; - cnt = BOTH; - sl1l2 = BOTH; - sal1l2 = BOTH; - vl1l2 = BOTH; - vcnt = BOTH; - val1l2 = BOTH; - pct = BOTH; - pstd = BOTH; - pjc = BOTH; - prc = BOTH; - ecnt = BOTH; // Only for HiRA - orank = BOTH; // Only for HiRA - rps = BOTH; // Only for HiRA - eclv = BOTH; - mpr = BOTH; - seeps = NONE; - seeps_mpr = NONE; - } - -The **output_flag** array controls the type of output that the Pair-Stat tool generates. Each flag corresponds to an output line type in the STAT file. Setting the flag to NONE indicates that the line type should not be generated. Setting the flag to STAT indicates that the line type should be written to the STAT file only. Setting the flag to BOTH indicates that the line type should be written to the STAT file as well as a separate ASCII file where the data is grouped by line type. The output flags correspond to the following output line types: - -1. **FHO** for Forecast, Hit, Observation Rates - -2. **CTC** for Contingency Table Counts - -3. **CTS** for Contingency Table Statistics - -4. **MCTC** for Multi-category Contingency Table Counts - -5. **MCTS** for Multi-category Contingency Table Statistics - -6. **CNT** for Continuous Statistics - -7. **SL1L2** for Scalar L1L2 Partial Sums - -8. **SAL1L2** for Scalar Anomaly L1L2 Partial Sums when climatological data is supplied - -9. **VL1L2** for Vector L1L2 Partial Sums - -10. **VAL1L2** for Vector Anomaly L1L2 Partial Sums when climatological data is supplied - -11. **VCNT** for Vector Continuous Statistics - -12. **PCT** for Contingency Table counts for Probabilistic forecasts - -13. **PSTD** for contingency table Statistics for Probabilistic forecasts with Dichotomous outcomes - -14. **PJC** for Joint and Conditional factorization for Probabilistic forecasts - -15. **PRC** for Receiver Operating Characteristic for Probabilistic forecasts - -16. **ECNT** for Ensemble Continuous Statistics is only computed for the HiRA methodology - -17. **ORANK** for Ensemble Matched Pair Information when point observations are supplied for the HiRA methodology - -18. **RPS** for Ranked Probability Score is only computed for the HiRA methodology - -19. **ECLV** for Economic Cost/Loss Relative Value - -20. **MPR** for Matched Pair data - -21. **SEEPS** for averaged SEEPS (Stable Equitable Error in Probability Space) score - -22. **SEEPS_MPR** for SEEPS score of Matched Pair data - -Note that the FHO and CTC line types are easily derived from each other. Users are free to choose which measures are most desired. The output line types are described in more detail in :numref:`pair_stat-output`. - -Note that writing out matched pair data (MPR lines) for a large number of cases is generally not recommended. The MPR lines create very large output files and are only intended for use on a small set of cases. - -If all line types corresponding to a particular verification method are set to NONE, the computation of those statistics will be skipped in the code and thus make the Pair-Stat tool run more efficiently. For example, if FHO, CTC, and CTS are all set to NONE, the Pair-Stat tool will skip the categorical verification step. - -The default SEEPS climo file exists at MET_BASE/climo/seeps/PPT24_seepsweights.nc. It is configurable by using the configuration file (seeps_point_climo_name). It can be overridden by the environment variable, MET_SEEPS_POINT_CLIMO_NAME. - -.. _pair_stat-output: - -pair_stat Output ------------------ - -pair_stat produces output in STAT and, optionally, ASCII format. The ASCII output duplicates the STAT output but has the data organized by line type. The output files will be written to the default output directory or the directory specified using the "-outdir" command line option. - -The output STAT file will be named using the following naming convention: - -pair_stat_PREFIX_HHMMSSL_YYYYMMDD_HHMMSSV.stat where PREFIX indicates the user-defined output prefix, HHMMSSL indicates the forecast lead time and YYYYMMDD_HHMMSS indicates the forecast valid time. - -The output ASCII files are named similarly: - -pair_stat_PREFIX_HHMMSSL_YYYYMMDD_HHMMSSV_TYPE.txt where TYPE is one of mpr, fho, ctc, cts, cnt, mctc, mcts, pct, pstd, pjc, prc, ecnt, orank, rps, eclv, sl1l2, sal1l2, vl1l2, vcnt or val1l2 to indicate the line type it contains. - -The first set of header columns are common to all of the output files generated by the Pair-Stat tool. Tables describing the contents of the header columns and the contents of the additional columns for each line type are listed in the following tables. The ECNT line type is described in :numref:`table_ES_header_info_es_out_ECNT`. The ORANK line type is described in :numref:`table_ES_header_info_es_out_ORANK`. The RPS line type is described in :numref:`table_ES_header_info_es_out_RPS`. - -.. _table_PS_header_info_pair-stat_out: - -.. list-table:: Common STAT header columns. - :widths: auto - :header-rows: 2 - - * - HEADER - - - - - * - Column Number - - Header Column Name - - Description - * - 1 - - VERSION - - Version number - * - 2 - - MODEL - - User provided text string designating model name - * - 3 - - DESC - - User provided text string describing the verification task - * - 4 - - FCST_LEAD - - Forecast lead time in HHMMSS format - * - 5 - - FCST_VALID_BEG - - Forecast valid start time in YYYYMMDD_HHMMSS format - * - 6 - - FCST_VALID_END - - Forecast valid end time in YYYYMMDD_HHMMSS format - * - 7 - - OBS_LEAD - - Observation lead time in HHMMSS format - * - 8 - - OBS_VALID_BEG - - Observation valid start time in YYYYMMDD_HHMMSS format - * - 9 - - OBS_VALID_END - - Observation valid end time in YYYYMMDD_HHMMSS format - * - 10 - - FCST_VAR - - Model variable - * - 11 - - FCST_UNITS - - Units for model variable - * - 12 - - FCST_LEV - - Selected Vertical level for forecast - * - 13 - - OBS_VAR - - Observation variable - * - 14 - - OBS_UNITS - - Units for observation variable - * - 15 - - OBS_LEV - - Selected Vertical level for observations - * - 16 - - OBTYPE - - Observation message type selected - * - 17 - - VX_MASK - - Verifying masking region indicating the masking grid or polyline region applied - * - 18 - - INTERP_MTHD - - Interpolation method applied to forecasts - * - 19 - - INTERP_PNTS - - Number of points used in interpolation method - * - 20 - - FCST_THRESH - - The threshold applied to the forecast - * - 21 - - OBS_THRESH - - The threshold applied to the observations - * - 22 - - COV_THRESH - - NA in Pair-Stat - * - 23 - - ALPHA - - Error percent value used in confidence intervals - * - 24 - - LINE_TYPE - - Output line types are listed in tables :numref:`table_PS_format_info_FHO` through :numref:`table_PS_format_info_MPR`. - -.. _table_PS_format_info_FHO: - -.. list-table:: Format information for FHO (Forecast, Hit rate, Observation rate) output line type. - :widths: auto - :header-rows: 2 - - * - FHO OUTPUT FORMAT - - - - - * - Column Number - - FHO Column Name - - Description - * - 24 - - FHO - - Forecast, Hit, Observation line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - F_RATE - - Forecast rate - * - 27 - - H_RATE - - Hit rate - * - 28 - - O_RATE - - Observation rate - -.. _table_PS_format_info_CTC: - -.. list-table:: Format information for CTC (Contingency Table Counts) output line type. - :widths: auto - :header-rows: 2 - - * - CTC OUTPUT FORMAT - - - - - * - Column Number - - CTC Column Name - - Description - * - 24 - - CTC - - Contingency Table Counts line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - FY_OY - - Number of forecast yes and observation yes - * - 27 - - FY_ON - - Number of forecast yes and observation no - * - 28 - - FN_OY - - Number of forecast no and observation yes - * - 29 - - FN_ON - - Number of forecast no and observation no - * - 30 - - EC_VALUE - - Expected correct rate, used for CTS HSS_EC - -.. role:: raw-html(raw) - :format: html - -.. _table_PS_format_info_CTS: - -.. list-table:: Format information for CTS (Contingency Table Statistics) output line type. - :widths: auto - :header-rows: 2 - - * - CTS OUTPUT FORMAT - - - - - * - Column Number - - CTS Column Name - - Description - * - 24 - - CTS - - Contingency Table Statistics line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26-30 - - BASER, :raw-html:`
` BASER_NCL, :raw-html:`
` BASER_NCU, :raw-html:`
` BASER_BCL, :raw-html:`
` BASER_BCU - - Base rate including normal and bootstrap upper and lower confidence limits - * - 31-35 - - FMEAN, :raw-html:`
` FMEAN_NCL, :raw-html:`
` FMEAN_NCU, :raw-html:`
` FMEAN_BCL, :raw-html:`
` FMEAN_BCU - - Forecast mean including normal and bootstrap upper and lower confidence limits - * - 36-40 - - ACC, :raw-html:`
` ACC_NCL, :raw-html:`
` ACC_NCU, :raw-html:`
` ACC_BCL, :raw-html:`
` ACC_BCU - - Accuracy including normal and bootstrap upper and lower confidence limits - * - 41-43 - - FBIAS, :raw-html:`
` FBIAS_BCL, :raw-html:`
` FBIAS_BCU - - Frequency Bias including bootstrap upper and lower confidence limits - * - 44-48 - - PODY, :raw-html:`
` PODY_NCL, :raw-html:`
` PODY_NCU, :raw-html:`
` PODY_BCL, :raw-html:`
` PODY_BCU - - Probability of detecting yes including normal and bootstrap upper and lower confidence limits - * - 49-53 - - PODN, :raw-html:`
` PODN_NCL, :raw-html:`
` PODN_NCU, :raw-html:`
` PODN_BCL, :raw-html:`
` PODN_BCU - - Probability of detecting no including normal and bootstrap upper and lower confidence limits - * - 54-58 - - POFD, :raw-html:`
` POFD_NCL, :raw-html:`
` POFD_NCU, :raw-html:`
` POFD_BCL, :raw-html:`
` POFD_BCU - - Probability of false detection including normal and bootstrap upper and lower confidence limits - * - 59-63 - - FAR, :raw-html:`
` FAR_NCL, :raw-html:`
` FAR_NCU, :raw-html:`
` FAR_BCL, :raw-html:`
` FAR_BCU - - False alarm ratio including normal and bootstrap upper and lower confidence limits - * - 64-68 - - CSI, :raw-html:`
` CSI_NCL, :raw-html:`
` CSI_NCU, :raw-html:`
` CSI_BCL, :raw-html:`
` CSI_BCU - - Critical Success Index including normal and bootstrap upper and lower confidence limits - * - 69-71 - - GSS, :raw-html:`
` GSS_BCL, :raw-html:`
` GSS_BCU - - Gilbert Skill Score including bootstrap upper and lower confidence limits - -.. role:: raw-html(raw) - :format: html - -.. _table_PS_format_info_CTS_cont: - -.. list-table:: Format information for CTS (Contingency Table Statistics) output line type, continued from above - :widths: auto - :header-rows: 2 - - * - CTS OUTPUT FORMAT (continued) - - - - - * - Column Number - - CTS Column Name - - Description - * - 72-76 - - HK, :raw-html:`
` HK_NCL, :raw-html:`
` HK_NCU, :raw-html:`
` HK_BCL, :raw-html:`
` HK_BCU - - Hanssen-Kuipers Discriminant including normal and bootstrap upper and lower confidence limits - * - 77-79 - - HSS, :raw-html:`
` HSS_BCL, :raw-html:`
` HSS_BCU - - Heidke Skill Score including bootstrap upper and lower confidence limits - * - 80-84 - - ODDS, :raw-html:`
` ODDS_NCL, :raw-html:`
` ODDS_NCU, :raw-html:`
` ODDS_BCL, :raw-html:`
` ODDS_BCU - - Odds Ratio including normal and bootstrap upper and lower confidence limits - * - 85-89 - - LODDS, :raw-html:`
` LODDS_NCL, :raw-html:`
` LODDS_NCU, :raw-html:`
` LODDS_BCL, :raw-html:`
` LODDS_BCU - - Logarithm of the Odds Ratio including normal and bootstrap upper and lower confidence limits - * - 90-94 - - ORSS, :raw-html:`
` ORSS _NCL, :raw-html:`
` ORSS _NCU, :raw-html:`
` ORSS _BCL, :raw-html:`
` ORSS _BCU - - Odds Ratio Skill Score including normal and bootstrap upper and lower confidence limits - * - 95-99 - - EDS, :raw-html:`
` EDS _NCL, :raw-html:`
` EDS _NCU, :raw-html:`
` EDS _BCL, :raw-html:`
` EDS _BCU - - Extreme Dependency Score including normal and bootstrap upper and lower confidence limits - * - 100-104 - - SEDS, :raw-html:`
` SEDS _NCL, :raw-html:`
` SEDS _NCU, :raw-html:`
` SEDS _BCL, :raw-html:`
` SEDS _BCU - - Symmetric Extreme Dependency Score including normal and bootstrap upper and lower confidence limits - * - 105-109 - - EDI, :raw-html:`
` EDI _NCL, :raw-html:`
` EDI _NCU, :raw-html:`
` EDI _BCL, :raw-html:`
` EDI _BCU - - Extreme Dependency Index including normal and bootstrap upper and lower confidence limits - * - 111-113 - - SEDI, :raw-html:`
` SEDI _NCL, :raw-html:`
` SEDI _NCU, :raw-html:`
` SEDI _BCL, :raw-html:`
` SEDI _BCU - - Symmetric Extremal Dependency Index including normal and bootstrap upper and lower confidence limits - * - 115-117 - - BAGSS, :raw-html:`
` BAGSS_BCL, :raw-html:`
` BAGSS_BCU - - Bias-Adjusted Gilbert Skill Score including bootstrap upper and lower confidence limits - * - 118-120 - - HSS_EC, :raw-html:`
` HSS_EC_BCL, :raw-html:`
` HSS_EC_BCU - - Heidke Skill Score with user-specific expected correct and bootstrap confidence limits - * - 121 - - EC_VALUE - - Expected correct rate, used for CTS HSS_EC - - -.. role:: raw-html(raw) - :format: html - -.. _table_PS_format_info_CNT: - -.. list-table:: Format information for CNT (Continuous Statistics) output line type. - :widths: auto - :header-rows: 2 - - * - CNT OUTPUT FORMAT - - - - - * - Column Number - - CNT Column Name - - Description - * - 24 - - CNT - - Continuous statistics line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26-30 - - FBAR, :raw-html:`
` FBAR_NCL, :raw-html:`
` FBAR_NCU, :raw-html:`
` FBAR_BCL, :raw-html:`
` FBAR_BCU - - Forecast mean including normal and bootstrap upper and lower confidence limits - * - 31-35 - - FSTDEV, :raw-html:`
` FSTDEV_NCL, :raw-html:`
` FSTDEV_NCU, :raw-html:`
` FSTDEV_BCL, :raw-html:`
` FSTDEV_BCU - - Standard deviation of the forecasts including normal and bootstrap upper and lower confidence limits - * - 36-40 - - OBAR, :raw-html:`
` OBAR_NCL, :raw-html:`
` OBAR_NCU, :raw-html:`
` OBAR_BCL, :raw-html:`
` OBAR_BCU - - Observation mean including normal and bootstrap upper and lower confidence limits - * - 41-45 - - OSTDEV, :raw-html:`
` OSTDEV_NCL, :raw-html:`
` OSTDEV_NCU, :raw-html:`
` OSTDEV_BCL, :raw-html:`
` OSTDEV_BCU - - Standard deviation of the observations including normal and bootstrap upper and lower confidence limits - * - 46-50 - - PR_CORR, :raw-html:`
` PR_CORR_NCL, :raw-html:`
` PR_CORR_NCU, :raw-html:`
` PR_CORR_BCL, :raw-html:`
` PR_CORR_BCU - - Pearson correlation coefficient including normal and bootstrap upper and lower confidence limits - * - 51 - - SP_CORR - - Spearman's rank correlation coefficient - * - 52 - - KT_CORR - - Kendall's tau statistic - * - 53 - - RANKS - - Number of ranks used in computing Kendall's tau statistic - * - 54 - - FRANK_TIES - - Number of tied forecast ranks used in computing Kendall's tau statistic - * - 55 - - ORANK_TIES - - Number of tied observation ranks used in computing Kendall's tau statistic - * - 56-60 - - ME, :raw-html:`
` ME_NCL, :raw-html:`
` ME_NCU, :raw-html:`
` ME_BCL, :raw-html:`
` ME_BCU - - Mean error (F-O) including normal and bootstrap upper and lower confidence limits - * - 61-65 - - ESTDEV, :raw-html:`
` ESTDEV_NCL, :raw-html:`
` ESTDEV_NCU, :raw-html:`
` ESTDEV_BCL, :raw-html:`
` ESTDEV_BCU - - Standard deviation of the error including normal and bootstrap upper and lower confidence limits - - -.. role:: raw-html(raw) - :format: html - -.. _table_PS_format_info_CNT_cont: - -.. list-table:: Format information for CNT (Continuous Statistics) output line type continued from above table - :widths: auto - :header-rows: 2 - - * - CNT OUTPUT FORMAT (continued) - - - - - * - Column Number - - CNT Column Name - - Description - * - 66-68 - - MBIAS, :raw-html:`
` MBIAS_BCL, :raw-html:`
` MBIAS_BCU - - Multiplicative bias including bootstrap upper and lower confidence limits - * - 69-71 - - MAE, :raw-html:`
` MAE_BCL, :raw-html:`
` MAE_BCU - - Mean absolute error including bootstrap upper and lower confidence limits - * - 72-74 - - MSE, :raw-html:`
` MSE_BCL, :raw-html:`
` MSE_BCU - - Mean squared error including bootstrap upper and lower confidence limits - * - 75-77 - - BCMSE, :raw-html:`
` BCMSE_BCL, :raw-html:`
` BCMSE_BCU - - Bias-corrected mean squared error including bootstrap upper and lower confidence limits - * - 78-80 - - RMSE, :raw-html:`
` RMSE_BCL, :raw-html:`
` RMSE_BCU - - Root mean squared error including bootstrap upper and lower confidence limits - * - 81-95 - - E10, :raw-html:`
` E10_BCL, :raw-html:`
` E10_BCU, :raw-html:`
` E25, :raw-html:`
` E25_BCL, :raw-html:`
` E25_BCU, :raw-html:`
` E50, :raw-html:`
` E50_BCL, :raw-html:`
` E50_BCU, :raw-html:`
` E75, :raw-html:`
` E75_BCL, :raw-html:`
` E75_BCU, :raw-html:`
` E90, :raw-html:`
` E90_BCL, :raw-html:`
` E90_BCU - - 10th, 25th, 50th, 75th, and 90th percentiles of the error including bootstrap upper and lower confidence limits - * - 96-98 - - EIQR, :raw-html:`
` IQR _BCL, :raw-html:`
` IQR _BCU - - The Interquartile Range of the error including bootstrap upper and lower confidence limits - * - 99-101 - - MAD, :raw-html:`
` MAD_BCL, :raw-html:`
` MAD_BCU - - The Median Absolute Deviation including bootstrap upper and lower confidence limits - * - 102-106 - - ANOM_CORR, :raw-html:`
` ANOM_CORR_NCL, :raw-html:`
` ANOM_CORR_NCU, :raw-html:`
` ANOM_CORR_BCL, :raw-html:`
` ANOM_CORR_BCU - - The Anomaly Correlation including mean error with normal and bootstrap upper and lower confidence limits - * - 107-109 - - ME2, :raw-html:`
` ME2_BCL, :raw-html:`
` ME2_BCU - - The square of the mean error (bias) including bootstrap upper and lower confidence limits - * - 110-112 - - MSESS, :raw-html:`
` MSESS_BCL, :raw-html:`
` MSESS_BCU - - The mean squared error skill score including bootstrap upper and lower confidence limits - * - 113-115 - - RMSFA, :raw-html:`
` RMSFA_BCL, :raw-html:`
` RMSFA_BCU - - Root mean squared forecast anomaly (f-c) including bootstrap upper and lower confidence limits - * - 116-118 - - RMSOA, :raw-html:`
` RMSOA_BCL, :raw-html:`
` RMSOA_BCU - - Root mean squared observation anomaly (o-c) including bootstrap upper and lower confidence limits - * - 119-121 - - ANOM_CORR_UNCNTR, :raw-html:`
` ANOM_CORR_UNCNTR_BCL, :raw-html:`
` ANOM_CORR_UNCNTR_BCU - - The uncentered Anomaly Correlation excluding mean error including bootstrap upper and lower confidence limits - * - 122-124 - - SI, :raw-html:`
` SI_BCL, :raw-html:`
` SI_BCU - - Scatter Index including bootstrap upper and lower confidence limits - - -.. _table_PS_format_info_MCTC: - -.. list-table:: Format information for MCTC (Multi-category Contingency Table Count) output line type. - :widths: auto - :header-rows: 2 - - * - MCTC OUTPUT FORMAT - - - - - * - Column Number - - MCTC Column Name - - Description - * - 24 - - MCTC - - Multi-category Contingency Table Counts line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - N_CAT - - Dimension of the contingency table - * - 27 - - Fi_Oj - - Count of events in forecast category i and observation category j, with the observations incrementing first (repeated) - * - \* - - EC_VALUE - - Expected correct rate, used for MCTS HSS_EC - - -.. role:: raw-html(raw) - :format: html - -.. _table_PS_format_info_MCTS: - -.. list-table:: Format information for MCTS (Multi- category Contingency Table Statistics) output line type. - :widths: auto - :header-rows: 2 - - * - MCTS OUTPUT FORMAT - - - - - * - Column Number - - MCTS Column Name - - Description - * - 24 - - MCTS - - Multi-category Contingency Table Statistics line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - N_CAT - - The total number of categories in each dimension of the contingency table. So the total number of cells is N_CAT*N_CAT. - * - 27-31 - - ACC, :raw-html:`
` ACC_NCL, :raw-html:`
` ACC_NCU, :raw-html:`
` ACC_BCL, :raw-html:`
` ACC_BCU - - Accuracy, normal confidence limits and bootstrap confidence limits - * - 32-34 - - HK, :raw-html:`
` HK_BCL, :raw-html:`
` HK_BCU - - Hanssen and Kuipers Discriminant and bootstrap confidence limits - * - 35-37 - - HSS, :raw-html:`
` HSS_BCL, :raw-html:`
` HSS_BCU - - Heidke Skill Score and bootstrap confidence limits - * - 38-40 - - GER, :raw-html:`
` GER_BCL, :raw-html:`
` GER_BCU - - Gerrity Score and bootstrap confidence limits - * - 41-43 - - HSS_EC, :raw-html:`
` HSS_EC_BCL, :raw-html:`
` HSS_EC_BCU - - Heidke Skill Score with user-specific expected correct and bootstrap confidence limits - * - 44 - - EC_VALUE - - Expected correct rate, used for MCTS HSS_EC - -.. _table_PS_format_info_PCT: - -.. list-table:: Format information for PCT (Contingency Table Counts for Probabilistic forecasts) output line type. - :widths: auto - :header-rows: 2 - - * - PCT OUTPUT FORMAT - - - - - * - Column Number - - PCT Column Name - - Description - * - 24 - - PCT - - Probability contingency table count line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - N_THRESH - - Number of probability thresholds - * - 27 - - THRESH_i - - The ith probability threshold value (repeated) - * - 28 - - OY_i - - Number of observation yes when forecast is between the ith and i+1th probability thresholds (repeated) - * - 29 - - ON_i - - Number of observation no when forecast is between the ith and i+1th probability thresholds (repeated) - * - \* - - THRESH_n - - Last probability threshold value - - -.. role:: raw-html(raw) - :format: html - -.. _table_PS_format_info_PSTD: - -.. list-table:: Format information for PSTD (Contingency Table Statistics for Probabilistic forecasts) output line type - :widths: auto - :header-rows: 2 - - * - PSTD OUTPUT FORMAT - - - - - * - Column Number - - PSTD Column Name - - Description - * - 24 - - PSTD - - Probabilistic statistics for dichotomous outcome line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - N_THRESH - - Number of probability thresholds - * - 27-29 - - BASER, :raw-html:`
` BASER_NCL, :raw-html:`
` BASER_NCU - - The Base Rate, including normal upper and lower confidence limits - * - 30 - - RELIABILITY - - Reliability - * - 31 - - RESOLUTION - - Resolution - * - 32 - - UNCERTAINTY - - Uncertainty - * - 33 - - ROC_AUC - - Area under the receiver operating characteristic curve - * - 34-36 - - BRIER, :raw-html:`
` BRIER_NCL, :raw-html:`
` BRIER_NCU - - Brier Score including normal upper and lower confidence limits - * - 37-39 - - BRIERCL, :raw-html:`
` BRIERCL_NCL, :raw-html:`
` BRIERCL_NCU - - Climatological Brier Score including upper and lower normal confidence limits - * - 40 - - BSS - - Brier Skill Score relative to external climatology - * - 41 - - BSS_SMPL - - Brier Skill Score relative to sample climatology - * - 42 - - THRESH_i - - The ith probability threshold value (repeated) - -.. _table_PS_format_info_PJC: - -.. list-table:: Format information for PJC (Joint and Conditional factorization for Probabilistic forecasts) output line type. - :widths: auto - :header-rows: 2 - - * - PJC OUTPUT FORMAT - - - - - * - Column Number - - PJC Column Name - - Description - * - 24 - - PJC - - Probabilistic Joint/Continuous line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - N_THRESH - - Number of probability thresholds - * - 27 - - THRESH_i - - The ith probability threshold value (repeated) - * - 28 - - OY_TP_i - - Number of observation yes when forecast is between the ith and i+1th probability thresholds as a proportion of the total OY (repeated) - * - 29 - - ON_TP_i - - Number of observation no when forecast is between the ith and i+1th probability thresholds as a proportion of the total ON (repeated) - * - 30 - - CALIBRATION_i - - Calibration when forecast is between the ith and i+1th probability thresholds (repeated) - * - 31 - - REFINEMENT_i - - Refinement when forecast is between the ith and i+1th probability thresholds (repeated) - * - 32 - - LIKELIHOOD_i - - Likelihood when forecast is between the ith and i+1th probability thresholds (repeated - * - 33 - - BASER_i - - Base rate when forecast is between the ith and i+1th probability thresholds (repeated) - * - \* - - THRESH_n - - Last probability threshold value - -.. _table_PS_format_info_PRC: - -.. list-table:: Format information for PRC (PRC for Receiver Operating Characteristic for Probabilistic forecasts) output line type. - :widths: auto - :header-rows: 2 - - * - PRC OUTPUT FORMAT - - - - - * - Column Number - - PRC Column Name - - Description - * - 24 - - PRC - - Probability ROC points line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - N_THRESH - - Number of probability thresholds - * - 27 - - THRESH_i - - The ith probability threshold value (repeated) - * - 28 - - PODY_i - - Probability of detecting yes when forecast is greater than the ith probability thresholds (repeated) - * - 29 - - POFD_i - - Probability of false detection when forecast is greater than the ith probability thresholds (repeated) - * - \* - - THRESH_n - - Last probability threshold value - -.. _table_PS_format_info_ECLV: - -.. list-table:: Format information for ECLV (ECLV for Economic Cost/Loss Relative Value) output line type. - :widths: auto - :header-rows: 2 - - * - ECLV OUTPUT FORMAT - - - - - * - Column Number - - PRC Column Name - - Description - * - 24 - - ECLV - - Economic Cost/Loss Relative Value line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - BASER - - Base rate - * - 27 - - VALUE_BASER - - Economic value of the base rate - * - 28 - - N_PNT - - Number of Cost/Loss ratios - * - 29 - - CL_i - - ith Cost/Loss ratio evaluated - * - 30 - - VALUE_i - - Relative value for the ith Cost/Loss ratio - -.. _table_PS_format_info_SL1L2: - -.. list-table:: Format information for SL1L2 (Scalar Partial Sums) output line type. - :widths: auto - :header-rows: 2 - - * - SL1L2 OUTPUT FORMAT - - - - - * - Column Number - - SL1L2 Column Name - - Description - * - 24 - - SL1L2 - - Scalar L1L2 line type - * - 25 - - TOTAL - - Total number of matched pairs of forecast (f) and observation (o) - * - 26 - - FBAR - - Mean(f) - * - 27 - - OBAR - - Mean(o) - * - 28 - - FOBAR - - Mean(f*o) - * - 29 - - FFBAR - - Mean(f²) - * - 30 - - OOBAR - - Mean(o²) - * - 31 - - MAE - - Mean(\|f-o\|) - -.. _table_PS_format_info_SAL1L2: - -.. list-table:: Format information for SAL1L2 (Scalar Anomaly Partial Sums) output line type. - :widths: auto - :header-rows: 2 - - * - SAL1L2 OUTPUT FORMAT - - - - - * - Column Number - - SAL1L2 Column Name - - Description - * - 24 - - SAL1L2 - - Scalar Anomaly L1L2 line type - * - 25 - - TOTAL - - Total number of matched pairs of forecast (f), observation (o), forecast climatology (cf), and observation climatology (co) - * - 26 - - FABAR - - Mean(f-cf) - * - 27 - - OABAR - - Mean(o-co) - * - 28 - - FOABAR - - Mean((f-cf)*(o-co)) - * - 29 - - FFABAR - - Mean((f-cf)²) - * - 30 - - OOABAR - - Mean((o-co)²) - * - 31 - - MAE - - Mean(\|(f-cf)-(o-co)\|) - -.. _table_PS_format_info_VL1L2: - -.. list-table:: Format information for VL1L2 (Vector Partial Sums) output line type. - :widths: auto - :header-rows: 2 - - * - VL1L2 OUTPUT FORMAT - - - - - * - Column Number - - VL1L2 Column Name - - Description - * - 24 - - VL1L2 - - Vector L1L2 line type - * - 25 - - TOTAL - - Total number of matched pairs of forecast winds (uf, vf) and observation winds (uo, vo) - * - 26 - - UFBAR - - Mean(uf) - * - 27 - - VFBAR - - Mean(vf) - * - 28 - - UOBAR - - Mean(uo) - * - 29 - - VOBAR - - Mean(vo) - * - 30 - - UVFOBAR - - Mean(uf*uo+vf*vo) - * - 31 - - UVFFBAR - - Mean(uf²+vf²) - * - 32 - - UVOOBAR - - Mean(uo²+vo²) - * - 33 - - F_SPEED_BAR - - Mean forecast wind speed - * - 34 - - O_SPEED_BAR - - Mean observed wind speed - * - 35 - - TOTAL_DIR - - Total number of matched pairs for which both the forecast and observation wind directions are well-defined (i.e. non-zero vectors) - * - 36 - - DIR_ME - - Mean wind direction difference, from -180 to 180 degrees - * - 37 - - DIR_MAE - - Mean absolute wind direction difference - * - 38 - - DIR_MSE - - Mean squared wind direction difference - -.. _table_PS_format_info_VAL1L2: - -.. list-table:: Format information for VAL1L2 (Vector Anomaly Partial Sums) output line type. - :widths: auto - :header-rows: 2 - - * - VAL1L2 OUTPUT FORMAT - - - - - * - Column Number - - VAL1L2 Column Name - - Description - * - 24 - - VAL1L2 - - Vector Anomaly L1L2 line type - * - 25 - - TOTAL - - Total number of matched pairs of forecast winds (uf, vf), observation winds (uo, vo), forecast climatology winds (ucf, vcf), and observation climatology winds (uco, vco) - * - 26 - - UFABAR - - Mean(uf-ucf) - * - 27 - - VFABAR - - Mean(vf-vcf) - * - 28 - - UOABAR - - Mean(uo-uco) - * - 29 - - VOABAR - - Mean(vo-vco) - * - 30 - - UVFOABAR - - Mean((uf-ucf)*(uo-uco)+(vf-vcf)*(vo-vco)) - * - 31 - - UVFFABAR - - Mean((uf-ucf)²+(vf-vcf)²) - * - 32 - - UVOOABAR - - Mean((uo-uco)²+(vo-vco)²) - * - 33 - - FA_SPEED_BAR - - Mean forecast wind speed anomaly - * - 34 - - OA_SPEED_BAR - - Mean observed wind speed anomaly - * - 35 - - TOTAL_DIR - - Total number of matched pairs for which the forecast, observation, forecast climatology, and observation climatology wind directions are well-defined (i.e. non-zero vectors) - * - 36 - - DIRA_ME - - Mean wind direction anomaly difference, from -180 to 180 degrees - * - 37 - - DIRA_MAE - - Mean absolute wind direction anomaly difference - * - 38 - - DIRA_MSE - - Mean squared wind direction anomaly difference - -.. _table_PS_format_info_VCNT: - -.. list-table:: Format information for VCNT (Vector Continuous Statistics) output line type. Note that the bootstrap confidence intervals columns ending with BCL and BCU are not currently calculated for this release of MET, but will be in future releases. - :widths: auto - :header-rows: 2 - - * - VCNT OUTPUT FORMAT - - - - - * - Column Numbers - - VCNT Column Name - - Description - * - 24 - - VCNT - - Vector Continuous Statistics line type - * - 25 - - TOTAL - - Total number of data points - * - 26-28 - - FBAR, :raw-html:`
` FBAR_BCL, :raw-html:`
` FBAR_BCU - - Mean value of forecast wind speed including bootstrap upper and lower confidence limits - * - 29-31 - - OBAR, :raw-html:`
` OBAR_BCL, :raw-html:`
` OBAR_BCU - - Mean value of observed wind speed including bootstrap upper and lower confidence limits - * - 32-34 - - FS_RMS, :raw-html:`
` FS_RMS_BCL, :raw-html:`
` FS_RMS_BCU - - Root mean square forecast wind speed including bootstrap upper and lower confidence limits - * - 35-37 - - OS_RMS, :raw-html:`
` OS_RMS_BCL, :raw-html:`
` OS_RMS_BCU - - Root mean square observed wind speed including bootstrap upper and lower confidence limits - * - 38-40 - - MSVE, :raw-html:`
` MSVE_BCL, :raw-html:`
` MSVE_BCU - - Mean squared length of the vector difference between the forecast and observed winds including bootstrap upper and lower confidence limits - * - 41-43 - - RMSVE, :raw-html:`
` RMSVE_BCL, :raw-html:`
` RMSVE_BCU - - Square root of MSVE including bootstrap upper and lower confidence limits - * - 45-46 - - FSTDEV, :raw-html:`
` FSTDEV_BCL, :raw-html:`
` FSTDEV_BCU - - Standard deviation of the forecast wind speed including bootstrap upper and lower confidence limits - * - 47-49 - - OSTDEV, :raw-html:`
` OSTDEV_BCL, :raw-html:`
` OSTDEV_BCU - - Standard deviation of the observed wind field including bootstrap upper and lower confidence limits - * - 50-52 - - FDIR, :raw-html:`
` FDIR_BCL, :raw-html:`
` FDIR_BCU - - Direction of the average forecast wind vector including bootstrap upper and lower confidence limits - * - 53-55 - - ODIR, :raw-html:`
` ODIR_BCL, :raw-html:`
` ODIR_BCU - - Direction of the average observed wind vector including bootstrap upper and lower confidence limits - * - 56-58 - - FBAR_SPEED, :raw-html:`
` FBAR_SPEED_BCL, :raw-html:`
` FBAR_SPEED_BCU - - Length (speed) of the average forecast wind vector including bootstrap upper and lower confidence limits - * - 59-61 - - OBAR_SPEED, :raw-html:`
` OBAR_SPEED_BCL, :raw-html:`
` OBAR_SPEED_BCU - - Length (speed) of the average observed wind vector including bootstrap upper and lower confidence limits - * - 62-64 - - VDIFF_SPEED, :raw-html:`
` VDIFF_SPEED_BCL, :raw-html:`
` VDIFF_SPEED_BCU - - Length (speed) of the vector difference between the average forecast and average observed wind vectors including bootstrap upper and lower confidence limits - * - 65-67 - - VDIFF_DIR, :raw-html:`
` VDIFF_DIR_BCL, :raw-html:`
` VDIFF_DIR_BCU - - Direction of the vector difference between the average forecast and average wind vectors including bootstrap upper and lower confidence limits - * - 68-70 - - SPEED_ERR, :raw-html:`
` SPEED_ERR_BCL, :raw-html:`
` SPEED_ERR_BCU - - Difference between the length of the average forecast wind vector and the average observed wind vector (in the sense F - O) including bootstrap upper and lower confidence limits - * - 71-73 - - SPEED_ABSERR, :raw-html:`
` SPEED_ABSERR_BCL, :raw-html:`
` SPEED_ABSERR_BCU - - Absolute value of SPEED_ERR including bootstrap upper and lower confidence limits - * - 74-76 - - DIR_ERR, :raw-html:`
` DIR_ERR_BCL, :raw-html:`
` DIR_ERR_BCU - - Signed angle between the directions of the average forecast and observed wing vectors. Positive if the forecast wind vector is counterclockwise from the observed wind vector including bootstrap upper and lower confidence limits - * - 77-79 - - DIR_ABSERR, :raw-html:`
` DIR_ABSERR_BCL, :raw-html:`
` DIR_ABSERR_BCU - - Absolute value of DIR_ABSERR including bootstrap upper and lower confidence limits - * - 80-84 - - ANOM_CORR, :raw-html:`
` ANOM_CORR_NCL, :raw-html:`
` ANOM_CORR_NCU, :raw-html:`
` ANOM_CORR_BCL, :raw-html:`
` ANOM_CORR_BCU - - Vector Anomaly Correlation including mean error with normal and bootstrap upper and lower confidence limits - * - 85-87 - - ANOM_CORR_UNCNTR, :raw-html:`
` ANOM_CORR_UNCNTR_BCL, :raw-html:`
` ANOM_CORR_UNCNTR_BCU - - Uncentered vector Anomaly Correlation excluding mean error including bootstrap upper and lower confidence limits - * - 88 - - TOTAL_DIR - - Total number of matched pairs for which both the forecast and observation wind directions are well-defined (i.e. non-zero vectors) - * - 89-91 - - DIR_ME, :raw-html:`
` DIR_ME_BCL, :raw-html:`
` DIR_ME_BCU - - Mean direction difference, from -180 to 180 degrees, including bootstrap upper and lower confidence limits - * - 92-94 - - DIR_MAE, :raw-html:`
` DIR_MAE_BCL, :raw-html:`
` DIR_MAE_BCU - - Mean absolute direction difference including bootstrap upper and lower confidence limits - * - 95-97 - - DIR_MSE, :raw-html:`
` DIR_MSE_BCL, :raw-html:`
` DIR_MSE_BCU - - Mean squared direction difference including bootstrap upper and lower confidence limits - * - 98-100 - - DIR_RMSE, :raw-html:`
` DIR_RMSE_BCL, :raw-html:`
` DIR_RMSE_BCU - - Root mean squared direction difference including bootstrap upper and lower confidence limits - -.. _table_PS_format_info_MPR: - -.. list-table:: Format information for MPR (Matched Pair) output line type. - :widths: auto - :header-rows: 2 - - * - MPR OUTPUT FORMAT - - - - - * - Column Number - - MPR Column Name - - Description - * - 24 - - MPR - - Matched Pair line type - * - 25 - - TOTAL - - Total number of matched pairs - * - 26 - - INDEX - - Index for the current matched pair - * - 27 - - OBS_SID - - Station Identifier of observation - * - 28 - - OBS_LAT - - Latitude of the observation in degrees north - * - 29 - - OBS_LON - - Longitude of the observation in degrees east - * - 30 - - OBS_LVL - - Pressure level of the observation in hPa or accumulation interval in hours - * - 31 - - OBS_ELV - - Elevation of the observation in meters above sea level - * - 32 - - FCST - - Forecast value interpolated to the observation location - * - 33 - - OBS - - Observation value - * - 34 - - OBS_QC - - Quality control flag for observation - * - 35 - - OBS_CLIMO_MEAN - - Observation climatological mean value (named CLIMO_MEAN prior to met-12.0.0) - * - 36 - - OBS_CLIMO_STDEV - - Observation climatological standard deviation value (named CLIMO_STDEV prior to met-12.0.0) - * - 37 - - OBS_CLIMO_CDF - - Observation climatological cumulative distribution function value (named CLIMO_CDF prior to met-12.0.0) - * - 38 - - FCST_CLIMO_MEAN - - Forecast climatological mean value - * - 39 - - FCST_CLIMO_STDEV - - Forecast climatological standard deviation value - -.. _table_PS_format_info_SEEPS_MPR: - -.. list-table:: Format information for SEEPS (Stable Equitable Error in Probability Space) of MPR (Matched Pair) output line type. - :widths: auto - :header-rows: 2 - - * - SEEPS_MPR OUTPUT FORMAT - - - - - * - Column Number - - SEEPS_MPR Column Name - - Description - * - 24 - - SEEPS_MPR - - SEEPS Matched Pair line type - * - 25 - - OBS_SID - - Station Identifier of observation - * - 26 - - OBS_LAT - - Latitude of the observation in degrees north - * - 27 - - OBS_LON - - Longitude of the observation in degrees east - * - 28 - - FCST - - Forecast value interpolated to the observation location - * - 29 - - OBS - - Observation value - * - 30 - - OBS_QC - - Quality control flag for observation - * - 31 - - FCST_CAT - - Forecast category (dry, light, or heavy) - * - 32 - - OBS_CAT - - Observation category (dry, light, or heavy) - * - 33 - - P1 - - Climo-derived probability value for this station (dry) - * - 34 - - P2 - - Climo-derived probability value for this station (dry + light) - * - 35 - - T1 - - Threshold 1 for P1 (dry) - * - 36 - - T2 - - Threshold 2 for P2 (dry + light) - * - 37 - - SEEPS - - SEEPS (Stable Equitable Error in Probability Space) score - - -.. _table_PS_format_info_SEEPS: - -.. list-table:: Format information for SEEPS (Stable Equitable Error in Probability Space) output line type. - :widths: auto - :header-rows: 2 - - * - SEEPS OUTPUT FORMAT - - - - - * - Column Number - - SEEPS Column Name - - Description - * - 24 - - SEEPS - - SEEPS line type - * - 25 - - TOTAL - - Total number of SEEPS matched pairs - * - 26 - - ODFL - - Counts multiplied by the weights for the observation dry, forecast light category - * - 27 - - ODFH - - Counts multiplied by the weights for the observation dry, forecast heavy category - * - 28 - - OLFD - - Counts multiplied by the weights for the observation light, forecast dry category - * - 29 - - OLFH - - Counts multiplied by the weights for the observation light, forecast heavy category - * - 30 - - OHFD - - Counts multiplied by the weights for the observation heavy, forecast dry category - * - 31 - - OHFL - - Counts multiplied by the weights for the observation heavy, forecast light category - * - 32 - - PF1 - - Marginal probabilities of the forecast dry (FCST_CAT 0) - * - 33 - - PF2 - - Marginal probabilities of the forecast light (FCST_CAT 1) - * - 34 - - PF3 - - Marginal probabilities of the forecast heavy (FCST_CAT 2) - * - 35 - - PV1 - - Marginal probabilities of the observed dry (OBS_CAT 0) - * - 36 - - PV2 - - Marginal probabilities of the observed light (OBS_CAT 1) - * - 37 - - PV3 - - Marginal probabilities of the observed heavy (OBS_CAT 2) - * - 38 - - SEEPS - - Averaged SEEPS (Stable Equitable Error in Probability Space) score - - -The STAT output files described for pair_stat may be used as inputs to the Stat-Analysis tool. For more information on using the Stat-Analysis tool to create stratifications and aggregations of the STAT files produced by pair_stat, please see :numref:`stat-analysis`. +TODO: Complete documentation diff --git a/docs/Users_Guide/point-stat.rst b/docs/Users_Guide/point-stat.rst index 50fd7c3015..fc764c1962 100644 --- a/docs/Users_Guide/point-stat.rst +++ b/docs/Users_Guide/point-stat.rst @@ -9,7 +9,7 @@ Introduction The Point-Stat tool provides verification statistics for forecasts at observation points (as opposed to over gridded analyses). The Point-Stat tool matches gridded forecasts to point observation locations and supports several different interpolation options. The tool then computes continuous, categorical, spatial, and probabilistic verification statistics. The categorical and probabilistic statistics generally are derived by applying a threshold to the forecast and observation values. Confidence intervals - representing the uncertainty in the verification measures - are computed for the verification statistics. -Scientific and statistical aspects of the Point-Stat tool are discussed in the following section. Practical aspects of the Point-Stat tool are described in :numref:`tc-stat_practical-information`. +Scientific and statistical aspects of the Point-Stat tool are discussed in the following section. Practical aspects of the Point-Stat tool are described in :numref:`point-stat_practical_info`. Scientific and Statistical Aspects ================================== @@ -257,7 +257,7 @@ MET provides non-parametric bootstrap confidence intervals for many categorical For more information on confidence intervals pertaining to verification measures, see :ref:`Wilks (2011) `, :ref:`Jolliffe and Stephenson (2012) `, and Bradley (2008). -.. _tc-stat_practical-information: +.. _point-stat_practical_info: Practical Information ===================== From eda1b90339e4cfe7eb45c8ba73dd39c6e71d1c5c Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 27 Dec 2024 22:09:28 +0000 Subject: [PATCH 06/15] Per #3006, saving compiling state --- src/libcode/vx_data2d/Makefile.am | 1 + src/libcode/vx_data2d/Makefile.in | 22 +- src/libcode/vx_data2d/var_info_pairs.cc | 224 ++++ src/libcode/vx_data2d/var_info_pairs.h | 73 ++ .../vx_data2d_factory/var_info_factory.cc | 5 + src/libcode/vx_statistics/pair_base.cc | 41 +- src/libcode/vx_statistics/pair_base.h | 15 +- src/libcode/vx_statistics/pair_data_point.cc | 58 +- src/libcode/vx_statistics/pair_data_point.h | 4 +- src/tools/core/grid_stat/grid_stat.cc | 5 +- .../core/grid_stat/grid_stat_conf_info.cc | 27 +- .../core/grid_stat/grid_stat_conf_info.h | 4 +- src/tools/core/pair_stat/pair_stat.cc | 997 +++++------------- src/tools/core/pair_stat/pair_stat.h | 45 +- .../core/pair_stat/pair_stat_conf_info.cc | 234 +--- .../core/pair_stat/pair_stat_conf_info.h | 79 +- .../core/point_stat/point_stat_conf_info.cc | 27 +- .../core/point_stat/point_stat_conf_info.h | 4 +- 18 files changed, 814 insertions(+), 1051 deletions(-) create mode 100644 src/libcode/vx_data2d/var_info_pairs.cc create mode 100644 src/libcode/vx_data2d/var_info_pairs.h diff --git a/src/libcode/vx_data2d/Makefile.am b/src/libcode/vx_data2d/Makefile.am index c705ee2486..0203547703 100644 --- a/src/libcode/vx_data2d/Makefile.am +++ b/src/libcode/vx_data2d/Makefile.am @@ -15,6 +15,7 @@ libvx_data2d_a_SOURCES = \ leveltype_to_string.cc leveltype_to_string.h \ level_info.cc level_info.h \ var_info.cc var_info.h \ + var_info_pairs.cc var_info_pairs.h \ data_class.cc data_class.h \ data2d_utils.cc data2d_utils.h \ table_lookup.cc table_lookup.h \ diff --git a/src/libcode/vx_data2d/Makefile.in b/src/libcode/vx_data2d/Makefile.in index ead0ee6915..0129891261 100644 --- a/src/libcode/vx_data2d/Makefile.in +++ b/src/libcode/vx_data2d/Makefile.in @@ -111,6 +111,7 @@ am_libvx_data2d_a_OBJECTS = \ libvx_data2d_a-leveltype_to_string.$(OBJEXT) \ libvx_data2d_a-level_info.$(OBJEXT) \ libvx_data2d_a-var_info.$(OBJEXT) \ + libvx_data2d_a-var_info_pairs.$(OBJEXT) \ libvx_data2d_a-data_class.$(OBJEXT) \ libvx_data2d_a-data2d_utils.$(OBJEXT) \ libvx_data2d_a-table_lookup.$(OBJEXT) \ @@ -137,7 +138,8 @@ am__depfiles_remade = ./$(DEPDIR)/libvx_data2d_a-data2d_utils.Po \ ./$(DEPDIR)/libvx_data2d_a-leveltype_to_string.Po \ ./$(DEPDIR)/libvx_data2d_a-mask_filters.Po \ ./$(DEPDIR)/libvx_data2d_a-table_lookup.Po \ - ./$(DEPDIR)/libvx_data2d_a-var_info.Po + ./$(DEPDIR)/libvx_data2d_a-var_info.Po \ + ./$(DEPDIR)/libvx_data2d_a-var_info_pairs.Po am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -361,6 +363,7 @@ libvx_data2d_a_SOURCES = \ leveltype_to_string.cc leveltype_to_string.h \ level_info.cc level_info.h \ var_info.cc var_info.h \ + var_info_pairs.cc var_info_pairs.h \ data_class.cc data_class.h \ data2d_utils.cc data2d_utils.h \ table_lookup.cc table_lookup.h \ @@ -423,6 +426,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_data2d_a-mask_filters.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_data2d_a-table_lookup.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_data2d_a-var_info.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_data2d_a-var_info_pairs.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -486,6 +490,20 @@ libvx_data2d_a-var_info.obj: var_info.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_data2d_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libvx_data2d_a-var_info.obj `if test -f 'var_info.cc'; then $(CYGPATH_W) 'var_info.cc'; else $(CYGPATH_W) '$(srcdir)/var_info.cc'; fi` +libvx_data2d_a-var_info_pairs.o: var_info_pairs.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_data2d_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libvx_data2d_a-var_info_pairs.o -MD -MP -MF $(DEPDIR)/libvx_data2d_a-var_info_pairs.Tpo -c -o libvx_data2d_a-var_info_pairs.o `test -f 'var_info_pairs.cc' || echo '$(srcdir)/'`var_info_pairs.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvx_data2d_a-var_info_pairs.Tpo $(DEPDIR)/libvx_data2d_a-var_info_pairs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='var_info_pairs.cc' object='libvx_data2d_a-var_info_pairs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_data2d_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libvx_data2d_a-var_info_pairs.o `test -f 'var_info_pairs.cc' || echo '$(srcdir)/'`var_info_pairs.cc + +libvx_data2d_a-var_info_pairs.obj: var_info_pairs.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_data2d_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libvx_data2d_a-var_info_pairs.obj -MD -MP -MF $(DEPDIR)/libvx_data2d_a-var_info_pairs.Tpo -c -o libvx_data2d_a-var_info_pairs.obj `if test -f 'var_info_pairs.cc'; then $(CYGPATH_W) 'var_info_pairs.cc'; else $(CYGPATH_W) '$(srcdir)/var_info_pairs.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvx_data2d_a-var_info_pairs.Tpo $(DEPDIR)/libvx_data2d_a-var_info_pairs.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='var_info_pairs.cc' object='libvx_data2d_a-var_info_pairs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_data2d_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libvx_data2d_a-var_info_pairs.obj `if test -f 'var_info_pairs.cc'; then $(CYGPATH_W) 'var_info_pairs.cc'; else $(CYGPATH_W) '$(srcdir)/var_info_pairs.cc'; fi` + libvx_data2d_a-data_class.o: data_class.cc @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_data2d_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libvx_data2d_a-data_class.o -MD -MP -MF $(DEPDIR)/libvx_data2d_a-data_class.Tpo -c -o libvx_data2d_a-data_class.o `test -f 'data_class.cc' || echo '$(srcdir)/'`data_class.cc @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvx_data2d_a-data_class.Tpo $(DEPDIR)/libvx_data2d_a-data_class.Po @@ -673,6 +691,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libvx_data2d_a-mask_filters.Po -rm -f ./$(DEPDIR)/libvx_data2d_a-table_lookup.Po -rm -f ./$(DEPDIR)/libvx_data2d_a-var_info.Po + -rm -f ./$(DEPDIR)/libvx_data2d_a-var_info_pairs.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -725,6 +744,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libvx_data2d_a-mask_filters.Po -rm -f ./$(DEPDIR)/libvx_data2d_a-table_lookup.Po -rm -f ./$(DEPDIR)/libvx_data2d_a-var_info.Po + -rm -f ./$(DEPDIR)/libvx_data2d_a-var_info_pairs.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/libcode/vx_data2d/var_info_pairs.cc b/src/libcode/vx_data2d/var_info_pairs.cc new file mode 100644 index 0000000000..3cbf5dcddc --- /dev/null +++ b/src/libcode/vx_data2d/var_info_pairs.cc @@ -0,0 +1,224 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2024 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +/////////////////////////////////////////////////////////////////////////////// +// +// Filename: var_info_pairs.cc +// +// Description: +// +// Mod# Date Name Description +// ---- ---- ---- ----------- +// +/////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "var_info.h" +#include "var_info_pairs.h" + +#include "util_constants.h" + +#include "vx_math.h" +#include "vx_util.h" +#include "vx_log.h" +#include "vx_data2d.h" + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////// +// +// Code for class VarInfoPairs +// +/////////////////////////////////////////////////////////////////////////////// + +VarInfoPairs::VarInfoPairs() { + + init_from_scratch(); +} + +/////////////////////////////////////////////////////////////////////////////// + +VarInfoPairs::~VarInfoPairs() { + + clear(); +} + +/////////////////////////////////////////////////////////////////////////////// + +VarInfoPairs::VarInfoPairs(const VarInfoPairs &f) { + + init_from_scratch(); + + assign(f); +} + +/////////////////////////////////////////////////////////////////////////////// + +VarInfoPairs & VarInfoPairs::operator=(const VarInfoPairs &f) { + + if ( this == &f ) return *this; + + assign(f); + + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +VarInfo *VarInfoPairs::clone() const { + + VarInfoPairs *ret = new VarInfoPairs(*this); + + return (VarInfo *)ret; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoPairs::init_from_scratch() { + + // First call the parent's initialization + VarInfo::init_from_scratch(); + + clear(); + + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoPairs::assign(const VarInfoPairs &v) { + + // First call the parent's assign + VarInfo::assign(v); + + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoPairs::clear() { + + // First call the parent's clear + VarInfo::clear(); + + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoPairs::dump(ostream &out) const { + + // Dump out the contents + out << "VarInfoPairs::dump():\n"; + + VarInfo::dump(out); + + return; +} + +/////////////////////////////////////////////////////////////////////////////// + +void VarInfoPairs::set_dict(Dictionary & dict) { + VarInfo::set_dict(dict); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfoPairs::is_precipitation() const { + bool status = false; + + // + // Check set_attrs entry + // + if(!is_bad_data(SetAttrIsPrecipitation)) { + return(SetAttrIsPrecipitation != 0); + } + + return status; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfoPairs::is_specific_humidity() const { + bool status = false; + + // + // Check set_attrs entry + // + if(!is_bad_data(SetAttrIsSpecificHumidity)) { + return(SetAttrIsSpecificHumidity != 0); + } + + return status; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfoPairs::is_u_wind() const { + bool status = false; + + // + // Check set_attrs entry + // + if(!is_bad_data(SetAttrIsUWind)) { + return(SetAttrIsUWind != 0); + } + + return status; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfoPairs::is_v_wind() const { + bool status = false; + + // + // Check set_attrs entry + // + if(!is_bad_data(SetAttrIsVWind)) { + return(SetAttrIsVWind != 0); + } + + return status; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfoPairs::is_wind_speed() const { + bool status = false; + + // + // Check set_attrs entry + // + if(!is_bad_data(SetAttrIsWindSpeed)) { + return(SetAttrIsWindSpeed != 0); + } + + return status; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool VarInfoPairs::is_wind_direction() const { + bool status = false; + + // + // Check set_attrs entry + // + if(!is_bad_data(SetAttrIsWindDirection)) { + return(SetAttrIsWindDirection != 0); + } + + return status; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d/var_info_pairs.h b/src/libcode/vx_data2d/var_info_pairs.h new file mode 100644 index 0000000000..9d5644a6fc --- /dev/null +++ b/src/libcode/vx_data2d/var_info_pairs.h @@ -0,0 +1,73 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2024 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +/////////////////////////////////////////////////////////////////////////////// + +#ifndef __VAR_INFO_PAIRS_H__ +#define __VAR_INFO_PAIRS_H__ + +/////////////////////////////////////////////////////////////////////////////// + +#include "var_info.h" +#include "vx_config.h" + +#include "data_file_type.h" + +/////////////////////////////////////////////////////////////////////////////// + +class VarInfoPairs : public VarInfo { + + private: + + void init_from_scratch(); + void assign(const VarInfoPairs &); + + public: + VarInfoPairs(); + ~VarInfoPairs(); + VarInfoPairs(const VarInfoPairs &); + VarInfoPairs & operator=(const VarInfoPairs &); + VarInfo *clone() const; + + void dump(std::ostream &) const; + void clear(); + + // + // get stuff + // + + GrdFileType file_type() const; + + // + // set stuff + // + + void set_dict(Dictionary &); + + // + // do stuff + // + + bool is_precipitation() const; + bool is_specific_humidity() const; + bool is_u_wind() const; + bool is_v_wind() const; + bool is_wind_speed() const; + bool is_wind_direction() const; +}; + +/////////////////////////////////////////////////////////////////////////////// + +inline GrdFileType VarInfoPairs::file_type() const { return FileType_Pairs; } + +/////////////////////////////////////////////////////////////////////////////// + +#endif // __VAR_INFO_PAIRS_H__ + +/////////////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_data2d_factory/var_info_factory.cc b/src/libcode/vx_data2d_factory/var_info_factory.cc index 32a398fb39..968d68dfd4 100644 --- a/src/libcode/vx_data2d_factory/var_info_factory.cc +++ b/src/libcode/vx_data2d_factory/var_info_factory.cc @@ -27,6 +27,7 @@ #include "var_info_nc_cf.h" #include "var_info_nc_met.h" #include "var_info_nc_wrf.h" +#include "var_info_pairs.h" #include "var_info_ugrid.h" #ifdef WITH_PYTHON @@ -115,6 +116,10 @@ VarInfo * VarInfoFactory::new_var_info(GrdFileType type) ugrid_compile_error(method_name); #endif + case FileType_Pairs: + vi = new VarInfoPairs; + break; + case FileType_HdfEos: mlog << Error << "\n" << method_name << "Support for GrdFileType = " << grdfiletype_to_string(type) diff --git a/src/libcode/vx_statistics/pair_base.cc b/src/libcode/vx_statistics/pair_base.cc index 88fdca66bd..4f07b87362 100644 --- a/src/libcode/vx_statistics/pair_base.cc +++ b/src/libcode/vx_statistics/pair_base.cc @@ -989,8 +989,9 @@ void VxPairBase::clear() { obs_qty_inc_filt.clear(); obs_qty_exc_filt.clear(); - mpr_column.clear(); - mpr_thresh.clear(); + mpr_thr_inc_map.clear(); + mpr_str_inc_map.clear(); + mpr_str_exc_map.clear(); fcst_ut = (unixtime) 0; beg_ut = (unixtime) 0; @@ -1061,8 +1062,9 @@ void VxPairBase::assign(const VxPairBase &vx_pb) { obs_qty_inc_filt = vx_pb.obs_qty_inc_filt; obs_qty_exc_filt = vx_pb.obs_qty_exc_filt; - mpr_column = vx_pb.mpr_column; - mpr_thresh = vx_pb.mpr_thresh; + mpr_thr_inc_map = vx_pb.mpr_thr_inc_map; + mpr_str_inc_map = vx_pb.mpr_str_inc_map; + mpr_str_exc_map = vx_pb.mpr_str_exc_map; msg_typ_sfc = vx_pb.msg_typ_sfc; msg_typ_lnd = vx_pb.msg_typ_lnd; @@ -1434,20 +1436,27 @@ void VxPairBase::set_interp(int i_interp, //////////////////////////////////////////////////////////////////////// -void VxPairBase::set_mpr_thresh(const StringArray &sa, const ThreshArray &ta) { +void VxPairBase::set_mpr_thr_inc_map(const map &m) { - // Check for constant length - if(sa.n() != ta.n()) { - mlog << Error << "\nVxPairBase::set_mpr_thresh() -> " - << "the \"" << conf_key_mpr_column << "\" (" - << write_css(sa) << ") and \"" << conf_key_mpr_thresh - << "\" (" << write_css(ta) - << ") config file entries must have the same length!\n\n"; - exit(1); - } + mpr_thr_inc_map = m; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void VxPairBase::set_mpr_str_inc_map(const map &m) { + + mpr_str_inc_map = m; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void VxPairBase::set_mpr_str_exc_map(const map &m) { - mpr_column = sa; - mpr_thresh = ta; + mpr_str_exc_map = m; return; } diff --git a/src/libcode/vx_statistics/pair_base.h b/src/libcode/vx_statistics/pair_base.h index c829a8efe7..4da5c29a51 100644 --- a/src/libcode/vx_statistics/pair_base.h +++ b/src/libcode/vx_statistics/pair_base.h @@ -286,8 +286,15 @@ class VxPairBase { ////////////////////////////////////////////////////////////////// - StringArray mpr_column; // Names of MPR columns or diffs of columns - ThreshArray mpr_thresh; // Filtering thresholds for the MPR columns + // Mapping of numeric MPR columns or diffs of colums to + // inclusion thresholds + std::map mpr_thr_inc_map; + + // Mapping of string MPR columns to list of inclusion + // and exclusion strings + std::map mpr_str_inc_map; + std::map mpr_str_exc_map; + ////////////////////////////////////////////////////////////////// @@ -378,7 +385,9 @@ class VxPairBase { void set_interp(int i_interp, InterpMthd mthd, int width, GridTemplateFactory::GridTemplates shape); - void set_mpr_thresh(const StringArray &, const ThreshArray &); + void set_mpr_thr_inc_map(const std::map &); + void set_mpr_str_inc_map(const std::map &); + void set_mpr_str_exc_map(const std::map &); void set_climo_cdf_info_ptr(const ClimoCDFInfo *); diff --git a/src/libcode/vx_statistics/pair_data_point.cc b/src/libcode/vx_statistics/pair_data_point.cc index 85595d69d3..d34b65798f 100644 --- a/src/libcode/vx_statistics/pair_data_point.cc +++ b/src/libcode/vx_statistics/pair_data_point.cc @@ -606,7 +606,7 @@ void VxPairDataPoint::add_point_obs(float *hdr_arr, const char *hdr_typ_str, // Check matched pair filtering options ConcatString reason_cs; if(!check_mpr_thresh(fcst_v, obs_v, cpi, - mpr_column, mpr_thresh, &reason_cs)) { + mpr_thr_inc_map, &reason_cs)) { if(mlog.verbosity_level() >= REJECT_DEBUG_LEVEL) { mlog << Debug(REJECT_DEBUG_LEVEL) @@ -742,13 +742,13 @@ bool check_fo_thresh(double f, double o, const ClimoPntInfo &cpi, //////////////////////////////////////////////////////////////////////// bool check_mpr_thresh(double f, double o, const ClimoPntInfo &cpi, - const StringArray &col_sa, const ThreshArray &col_ta, + const map &m, ConcatString *reason_ptr) { // Initialize if(reason_ptr) reason_ptr->erase(); // Check arrays - if(col_sa.n() == 0 || col_ta.n() == 0) return true; + if(m.size() == 0) return true; bool keep = true; bool absv = false; @@ -756,18 +756,18 @@ bool check_mpr_thresh(double f, double o, const ClimoPntInfo &cpi, ConcatString cs; double v, v_cur; - // Loop over all the column filter names - for(int i=0; i &m) { // Check for no work to be done - if(col_sa.n() == 0 && col_ta.n() == 0) return; - - // Check for constant length - if(col_sa.n() != col_ta.n()) { - mlog << Error << "\napply_mpr_thresh_mask() -> " - << "the \"" << conf_key_mpr_column << "\" (" - << write_css(col_sa) << ") and \"" << conf_key_mpr_thresh - << "\" (" << write_css(col_ta) - << ") config file entries must have the same length!\n\n"; - exit(1); - } + if(m.size() == 0) return; int nxy = fcst_dp.nx() * fcst_dp.ny(); int n_skip = 0; @@ -884,8 +877,7 @@ void apply_mpr_thresh_mask(DataPlane &fcst_dp, DataPlane &obs_dp, (ocsd_flag && is_bad_data(cpi.ocsd))) continue; // Discard pairs which do not meet the threshold criteria - if(!check_mpr_thresh(fcst_dp.buf()[i], obs_dp.buf()[i], cpi, - col_sa, col_ta)) { + if(!check_mpr_thresh(fcst_dp.buf()[i], obs_dp.buf()[i], cpi, m)) { // Increment skip counter n_skip++; @@ -902,9 +894,7 @@ void apply_mpr_thresh_mask(DataPlane &fcst_dp, DataPlane &obs_dp, mlog << Debug(3) << "Discarded " << n_skip << " of " << nxy - << " pairs for matched pair filtering columns (" - << write_css(col_sa) << ") and thresholds (" - << col_ta.get_str() << ").\n"; + << " pairs when applying matched pair filtering thresholds.\n"; return; } diff --git a/src/libcode/vx_statistics/pair_data_point.h b/src/libcode/vx_statistics/pair_data_point.h index 5f43a5e185..57084675d1 100644 --- a/src/libcode/vx_statistics/pair_data_point.h +++ b/src/libcode/vx_statistics/pair_data_point.h @@ -141,7 +141,7 @@ extern bool check_fo_thresh(double, double, const ClimoPntInfo &, const SetLogic); extern bool check_mpr_thresh(double, double, const ClimoPntInfo &, - const StringArray &, const ThreshArray &, + const std::map &, ConcatString * = 0); extern double get_mpr_column_value(double, double, const ClimoPntInfo &, @@ -150,7 +150,7 @@ extern double get_mpr_column_value(double, double, const ClimoPntInfo &, extern void apply_mpr_thresh_mask(DataPlane &, DataPlane &, DataPlane &, DataPlane &, DataPlane &, DataPlane &, - const StringArray &, const ThreshArray &); + const std::map &); extern bool check_seeps_thresh(double, double, const StringArray &, const ThreshArray &, diff --git a/src/tools/core/grid_stat/grid_stat.cc b/src/tools/core/grid_stat/grid_stat.cc index a1c43f0824..acd788993a 100644 --- a/src/tools/core/grid_stat/grid_stat.cc +++ b/src/tools/core/grid_stat/grid_stat.cc @@ -823,12 +823,11 @@ void process_scores() { << (ocsd_dp.is_empty() ? 0 : 1) << " standard deviation field(s).\n"; // Apply MPR threshold filters - if(conf_info.vx_opt[i].mpr_sa.n() > 0) { + if(conf_info.vx_opt[i].mpr_thr_inc_map.size() > 0) { apply_mpr_thresh_mask(fcst_dp, obs_dp, fcmn_dp, fcsd_dp, ocmn_dp, ocsd_dp, - conf_info.vx_opt[i].mpr_sa, - conf_info.vx_opt[i].mpr_ta); + conf_info.vx_opt[i].mpr_thr_inc_map); } // Setup the first pass through the data diff --git a/src/tools/core/grid_stat/grid_stat_conf_info.cc b/src/tools/core/grid_stat/grid_stat_conf_info.cc index f9b704e455..a049ceeab2 100644 --- a/src/tools/core/grid_stat/grid_stat_conf_info.cc +++ b/src/tools/core/grid_stat/grid_stat_conf_info.cc @@ -599,8 +599,7 @@ void GridStatVxOpt::clear() { var_name.clear(); var_suffix.clear(); - mpr_sa.clear(); - mpr_ta.clear(); + mpr_thr_inc_map.clear(); fcat_ta.clear(); ocat_ta.clear(); @@ -734,8 +733,26 @@ void GridStatVxOpt::process_config( for(i=0; i " + << "The length of \"" << conf_key_mpr_column << "\" and \"" + << conf_key_mpr_thresh << "\" must match (" << mpr_sa.n() + << " != " << mpr_ta.n() << ")!\n\n"; + exit(1); + } + + // Store in map + for(int i=0; mpr_sa.n(); i++) { + if(mpr_thr_inc_map.count(mpr_sa[i]) == 0) { + ThreshArray ta; + mpr_thr_inc_map[(mpr_sa[i])] = ta; + } + mpr_thr_inc_map[(mpr_sa[i])].add(mpr_ta[i]); + } // Conf: cat_thresh fcat_ta = fdict.lookup_thresh_array(conf_key_cat_thresh); @@ -1016,7 +1033,7 @@ bool GridStatVxOpt::is_uv_match(const GridStatVxOpt &v) const { // // The following do not impact matched pairs: // desc, var_name, var_suffix, - // mpr_sa, mpr_ta, + // mpr_thr_inc_map, // fcat_ta, ocat_ta, // fcnt_ta, ocnt_ta, cnt_logic, // fwind_ta, owind_ta, wind_logic, diff --git a/src/tools/core/grid_stat/grid_stat_conf_info.h b/src/tools/core/grid_stat/grid_stat_conf_info.h index e24326c7cd..c46eef12a1 100644 --- a/src/tools/core/grid_stat/grid_stat_conf_info.h +++ b/src/tools/core/grid_stat/grid_stat_conf_info.h @@ -149,8 +149,8 @@ class GridStatVxOpt { ConcatString var_suffix; // nc_pairs_var_suffix string // nc_pairs_var_str is deprecated - StringArray mpr_sa; // MPR filtering columns - ThreshArray mpr_ta; // MPR filtering thresholds + // Matched pair inclusion thresholds + std::map mpr_thr_inc_map; ThreshArray fcat_ta; // fcst categorical thresholds ThreshArray ocat_ta; // obs categorical thresholds diff --git a/src/tools/core/pair_stat/pair_stat.cc b/src/tools/core/pair_stat/pair_stat.cc index 9749aa6635..508883ef14 100644 --- a/src/tools/core/pair_stat/pair_stat.cc +++ b/src/tools/core/pair_stat/pair_stat.cc @@ -75,8 +75,6 @@ static void do_mcts (MCTSInfo &, int, const PairDataPoint *); static void do_cnt_sl1l2 (const PairStatVxOpt &, const PairDataPoint *); static void do_vl1l2 (VL1L2Info *&, int, const PairDataPoint *, const PairDataPoint *); static void do_pct (const PairStatVxOpt &, const PairDataPoint *); -static void do_hira_ens ( int, const PairDataPoint *); -static void do_hira_prob ( int, const PairDataPoint *); static void finish_txt_files(); @@ -165,6 +163,20 @@ void process_command_line(int argc, char **argv) { // Check for error. There should be no arguments left if(cline.n() != 0) usage(); + // Expand the input pairs file lists + StringArray tmp_src(pairs_files); + pairs_files.clear(); + + for(int i=0; i 0) pairs_files.add(sa); + else pairs_files.add(tmp_src[i]); + } + // Check for required argruments if(pairs_files.n() == 0) { mlog << Error << "\n" << method_name @@ -205,9 +217,11 @@ void process_command_line(int argc, char **argv) { // Process the configuration conf_info.process_config(pairs_format); - // List the pairs files + // List the input pair files mlog << Debug(1) - << "Pairs File(s): " << write_css(pairs_files) << "\n"; + << "Reading " << pairs_files.n() << " " + << pairsformat_to_string(pairs_format) << " Pairs File(s): " + << write_css(pairs_files) << "\n"; // Set the model name if(conf_info.model.empty()) { @@ -257,7 +271,7 @@ void setup_first_pass(const DataPlane &dp, const Grid &data_grid) { void setup_txt_files() { int max_col, max_prob_col, max_mctc_col, max_orank_col; - int n_prob, n_cat, n_eclv, n_ens; + int n_prob, n_cat, n_eclv; ConcatString base_name; // Create output file names for the stat file and optional text files @@ -270,15 +284,12 @@ void setup_txt_files() { ///////////////////////////////////////////////////////////////////// // Get the maximum number of data columns - n_prob = max(conf_info.get_max_n_fprob_thresh(), - conf_info.get_max_n_hira_prob()); + n_prob = conf_info.get_max_n_fprob_thresh(); n_cat = conf_info.get_max_n_cat_thresh() + 1; n_eclv = conf_info.get_max_n_eclv_points(); - n_ens = conf_info.get_max_n_hira_ens(); max_prob_col = get_n_pjc_columns(n_prob); max_mctc_col = get_n_mctc_columns(n_cat); - max_orank_col = get_n_orank_columns(n_ens); // Determine the maximum number of data columns max_col = (max_prob_col > max_stat_col ? max_prob_col : max_stat_col); @@ -356,10 +367,6 @@ void setup_txt_files() { max_col = get_n_eclv_columns(n_eclv) + n_header_columns + 1; break; - case i_orank: - max_col = get_n_orank_columns(n_ens) + n_header_columns + 1; - break; - default: max_col = n_txt_columns[i] + n_header_columns + 1; break; @@ -396,10 +403,6 @@ void setup_txt_files() { write_eclv_header_row(1, n_eclv, txt_at[i], 0, 0); break; - case i_orank: - write_orank_header_row(1, n_ens, txt_at[i], 0, 0); - break; - default: write_header_row(txt_columns[i], n_txt_columns[i], 1, txt_at[i], 0, 0); @@ -848,7 +851,6 @@ void process_scores() { ConcatString cs; // Initialize pointers - PairDataPoint *pd_ptr = (PairDataPoint *) nullptr; CTSInfo *cts_info = (CTSInfo *) nullptr; MCTSInfo mcts_info; VL1L2Info *vl1l2_info = (VL1L2Info *) nullptr; @@ -870,389 +872,320 @@ void process_scores() { // Compute scores for each PairData object and write output for(int i_vx=0; i_vxvx_pd.fcst_dpa.n_planes() == 0) continue; // Store the description - if(conf_info.vx_opt[i_vx].vx_pd.desc.empty()) { + if(vx_ptr->vx_pd.desc.empty()) { shc.set_desc(na_str); } else { - shc.set_desc(conf_info.vx_opt[i_vx].vx_pd.desc.c_str()); + shc.set_desc(vx_ptr->vx_pd.desc.c_str()); } // Store the forecast variable name - shc.set_fcst_var(conf_info.vx_opt[i_vx].vx_pd.fcst_info->name_attr()); + shc.set_fcst_var(vx_ptr->vx_pd.fcst_info->name_attr()); // Store the forecast variable units - shc.set_fcst_units(conf_info.vx_opt[i_vx].vx_pd.fcst_info->units_attr()); + shc.set_fcst_units(vx_ptr->vx_pd.fcst_info->units_attr()); // Set the forecast level name - shc.set_fcst_lev(conf_info.vx_opt[i_vx].vx_pd.fcst_info->level_attr().c_str()); + shc.set_fcst_lev(vx_ptr->vx_pd.fcst_info->level_attr().c_str()); // Store the observation variable name - shc.set_obs_var(conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr()); + shc.set_obs_var(vx_ptr->vx_pd.obs_info->name_attr()); // Store the observation variable units - cs = conf_info.vx_opt[i_vx].vx_pd.obs_info->units_attr(); + cs = vx_ptr->vx_pd.obs_info->units_attr(); if(cs.empty()) cs = na_string; shc.set_obs_units(cs); // Set the observation level name - shc.set_obs_lev(conf_info.vx_opt[i_vx].vx_pd.obs_info->level_attr().c_str()); + shc.set_obs_lev(vx_ptr->vx_pd.obs_info->level_attr().c_str()); // Set the forecast lead time - shc.set_fcst_lead_sec(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa[0].lead()); + shc.set_fcst_lead_sec(vx_ptr->vx_pd.fcst_dpa[0].lead()); // Set the forecast valid time - shc.set_fcst_valid_beg(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa[0].valid()); - shc.set_fcst_valid_end(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa[0].valid()); + shc.set_fcst_valid_beg(vx_ptr->vx_pd.fcst_dpa[0].valid()); + shc.set_fcst_valid_end(vx_ptr->vx_pd.fcst_dpa[0].valid()); // Set the observation lead time shc.set_obs_lead_sec(0); // Set the observation valid time - shc.set_obs_valid_beg(conf_info.vx_opt[i_vx].vx_pd.beg_ut); - shc.set_obs_valid_end(conf_info.vx_opt[i_vx].vx_pd.end_ut); - - // Loop through the message types - for(int i_msg_typ=0; i_msg_typmagic_str() - << " versus " - << conf_info.vx_opt[i_vx].vx_pd.obs_info->magic_str() - << ", for observation type " << pd_ptr->msg_typ - << ", over region " << pd_ptr->mask_name - << ", for interpolation method " - << shc.get_interp_mthd() << "(" - << shc.get_interp_pnts_str() - << "), using " << pd_ptr->n_obs << " matched pairs.\n"; - - // List counts for reasons why observations were rejected - cs << cs_erase - << "Number of matched pairs = " << pd_ptr->n_obs << "\n" - << "Observations processed = " << conf_info.vx_opt[i_vx].vx_pd.n_try << "\n" - << "Rejected: station id = " << conf_info.vx_opt[i_vx].vx_pd.rej_sid << "\n" - << "Rejected: obs var name = " << conf_info.vx_opt[i_vx].vx_pd.rej_var << "\n" - << "Rejected: valid time = " << conf_info.vx_opt[i_vx].vx_pd.rej_vld << "\n" - << "Rejected: bad obs value = " << conf_info.vx_opt[i_vx].vx_pd.rej_obs << "\n" - << "Rejected: off the grid = " << conf_info.vx_opt[i_vx].vx_pd.rej_grd << "\n" - << "Rejected: topography = " << conf_info.vx_opt[i_vx].vx_pd.rej_topo << "\n" - << "Rejected: level mismatch = " << conf_info.vx_opt[i_vx].vx_pd.rej_lvl << "\n" - << "Rejected: quality marker = " << conf_info.vx_opt[i_vx].vx_pd.rej_qty << "\n" - << "Rejected: message type = " << conf_info.vx_opt[i_vx].vx_pd.rej_typ[n] << "\n" - << "Rejected: masking region = " << conf_info.vx_opt[i_vx].vx_pd.rej_mask[n] << "\n" - << "Rejected: bad fcst value = " << conf_info.vx_opt[i_vx].vx_pd.rej_fcst[n] << "\n" - << "Rejected: bad climo mean = " << conf_info.vx_opt[i_vx].vx_pd.rej_cmn[n] << "\n" - << "Rejected: bad climo stdev = " << conf_info.vx_opt[i_vx].vx_pd.rej_csd[n] << "\n" - << "Rejected: mpr filter = " << conf_info.vx_opt[i_vx].vx_pd.rej_mpr[n] << "\n" - << "Rejected: duplicates = " << conf_info.vx_opt[i_vx].vx_pd.rej_dup[n] << "\n"; - - // Print report based on the number of matched pairs - if(pd_ptr->n_obs > 0) { - mlog << Debug(3) << cs; - } - // Continue for zero matched pairs - else { - mlog << Debug(2) << cs; - continue; - } + shc.set_obs_valid_beg(vx_ptr->vx_pd.beg_ut); + shc.set_obs_valid_end(vx_ptr->vx_pd.end_ut); - // Process percentile thresholds - conf_info.vx_opt[i_vx].set_perc_thresh(pd_ptr); + // Store the message type in the obtype column + shc.set_obtype(na_str); - // Write out the MPR lines - if(conf_info.vx_opt[i_vx].output_flag[i_mpr] != STATOutputType::None) { - write_mpr_row(shc, pd_ptr, - conf_info.vx_opt[i_vx].output_flag[i_mpr], - stat_at, i_stat_row, - txt_at[i_mpr], i_txt_row[i_mpr], false); + // Loop through the verification masking regions + for(int i_mask=0; i_maskget_n_mask(); i_mask++) { - // Reset the obtype column - shc.set_obtype(conf_info.vx_opt[i_vx].msg_typ[i_msg_typ].c_str()); + // Store the verification masking region + shc.set_mask(vx_ptr->mask_name[i_mask].c_str()); - // Reset the observation valid time - shc.set_obs_valid_beg(conf_info.vx_opt[i_vx].vx_pd.beg_ut); - shc.set_obs_valid_end(conf_info.vx_opt[i_vx].vx_pd.end_ut); - } + // Store the interpolation method as nearest + shc.set_interp_mthd(InterpMthd::Nearest); + shc.set_interp_wdth(1); - // Write out the SEEPS MPR lines - if(conf_info.vx_opt[i_vx].output_flag[i_seeps_mpr] != STATOutputType::None) { - write_seeps_mpr_row(shc, pd_ptr, - conf_info.vx_opt[i_vx].output_flag[i_seeps_mpr], - stat_at, i_stat_row, - txt_at[i_seeps_mpr], i_txt_row[i_seeps_mpr], false); + PairDataPoint *pd_ptr = &vx_ptr->vx_pd.pd[i_mask]; + + mlog << Debug(2) + << "Processing " << vx_ptr->vx_pd.fcst_info->magic_str() + << " versus " << vx_ptr->vx_pd.obs_info->magic_str() + << ", over region " << pd_ptr->mask_name + << "), using " << pd_ptr->n_obs << " matched pairs.\n"; + + // List counts for reasons why observations were rejected + cs << cs_erase + << "Number of matched pairs = " << pd_ptr->n_obs << "\n" + << "Observations processed = " << vx_ptr->vx_pd.n_try << "\n" + << "Rejected: station id = " << vx_ptr->vx_pd.rej_sid << "\n" + << "Rejected: obs var name = " << vx_ptr->vx_pd.rej_var << "\n" + << "Rejected: valid time = " << vx_ptr->vx_pd.rej_vld << "\n" + << "Rejected: bad obs value = " << vx_ptr->vx_pd.rej_obs << "\n" + << "Rejected: off the grid = " << vx_ptr->vx_pd.rej_grd << "\n" + << "Rejected: topography = " << vx_ptr->vx_pd.rej_topo << "\n" + << "Rejected: level mismatch = " << vx_ptr->vx_pd.rej_lvl << "\n" + << "Rejected: quality marker = " << vx_ptr->vx_pd.rej_qty << "\n" + << "Rejected: message type = " << vx_ptr->vx_pd.rej_typ[i_mask] << "\n" + << "Rejected: masking region = " << vx_ptr->vx_pd.rej_mask[i_mask] << "\n" + << "Rejected: bad fcst value = " << vx_ptr->vx_pd.rej_fcst[i_mask] << "\n" + << "Rejected: bad climo mean = " << vx_ptr->vx_pd.rej_cmn[i_mask] << "\n" + << "Rejected: bad climo stdev = " << vx_ptr->vx_pd.rej_csd[i_mask] << "\n" + << "Rejected: mpr filter = " << vx_ptr->vx_pd.rej_mpr[i_mask] << "\n" + << "Rejected: duplicates = " << vx_ptr->vx_pd.rej_dup[i_mask] << "\n"; + + // Print report based on the number of matched pairs + if(pd_ptr->n_obs > 0) mlog << Debug(3) << cs; + else mlog << Debug(2) << cs; + + // Process percentile thresholds + vx_ptr->set_perc_thresh(pd_ptr); + + // Write out the MPR lines + if(vx_ptr->output_flag[i_mpr] != STATOutputType::None) { + write_mpr_row(shc, pd_ptr, + vx_ptr->output_flag[i_mpr], + stat_at, i_stat_row, + txt_at[i_mpr], i_txt_row[i_mpr], false); + + // Reset the obtype column + shc.set_obtype(na_str); + + // Reset the observation valid time + shc.set_obs_valid_beg(vx_ptr->vx_pd.beg_ut); + shc.set_obs_valid_end(vx_ptr->vx_pd.end_ut); + } + + // Write out the SEEPS MPR lines + if(vx_ptr->output_flag[i_seeps_mpr] != STATOutputType::None) { + write_seeps_mpr_row(shc, pd_ptr, + vx_ptr->output_flag[i_seeps_mpr], + stat_at, i_stat_row, + txt_at[i_seeps_mpr], i_txt_row[i_seeps_mpr], false); + + // Reset the obtype column + shc.set_obtype(na_str); + + // Reset the observation valid time + shc.set_obs_valid_beg(vx_ptr->vx_pd.beg_ut); + shc.set_obs_valid_end(vx_ptr->vx_pd.end_ut); + } + + // Write out the SEEPS lines + if(vx_ptr->output_flag[i_seeps] != STATOutputType::None) { + compute_aggregated_seeps(pd_ptr, &pd_ptr->seeps_agg); + write_seeps_row(shc, &pd_ptr->seeps_agg, + vx_ptr->output_flag[i_seeps], + stat_at, i_stat_row, + txt_at[i_seeps], i_txt_row[i_seeps]); + } + + // Compute CTS scores + if(!vx_ptr->vx_pd.fcst_info->is_prob() && + vx_ptr->fcat_ta.n() > 0 && + (vx_ptr->output_flag[i_fho] != STATOutputType::None || + vx_ptr->output_flag[i_ctc] != STATOutputType::None || + vx_ptr->output_flag[i_cts] != STATOutputType::None || + vx_ptr->output_flag[i_eclv] != STATOutputType::None)) { + + // Initialize + for(int i_cat=0; i_catfcat_ta.n(); i_cat++) { + + if(cts_info[i_cat].cts.n_pairs() == 0) continue; + + // Write out FHO + if(vx_ptr->output_flag[i_fho] != STATOutputType::None) { + write_fho_row(shc, cts_info[i_cat], + vx_ptr->output_flag[i_fho], + stat_at, i_stat_row, + txt_at[i_fho], i_txt_row[i_fho]); } - // Write out the SEEPS lines - if(conf_info.vx_opt[i_vx].output_flag[i_seeps] != STATOutputType::None) { - compute_aggregated_seeps(pd_ptr, &pd_ptr->seeps_agg); - write_seeps_row(shc, &pd_ptr->seeps_agg, - conf_info.vx_opt[i_vx].output_flag[i_seeps], + // Write out CTC + if(vx_ptr->output_flag[i_ctc] != STATOutputType::None) { + write_ctc_row(shc, cts_info[i_cat], + vx_ptr->output_flag[i_ctc], stat_at, i_stat_row, - txt_at[i_seeps], i_txt_row[i_seeps]); + txt_at[i_ctc], i_txt_row[i_ctc]); } - // Compute CTS scores - if(!conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_prob() && - conf_info.vx_opt[i_vx].fcat_ta.n() > 0 && - (conf_info.vx_opt[i_vx].output_flag[i_fho] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_ctc] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_cts] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_eclv] != STATOutputType::None)) { - - // Initialize - for(int i_cat=0; i_catis_prob() && - conf_info.vx_opt[i_vx].fcat_ta.n() > 1 && - (conf_info.vx_opt[i_vx].output_flag[i_mctc] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_mcts] != STATOutputType::None)) { - - // Initialize - mcts_info.clear(); - - // Compute MCTS Info - do_mcts(mcts_info, i_vx, pd_ptr); - - if(mcts_info.cts.n_pairs() == 0) continue; - - // Write out MCTC - if(conf_info.vx_opt[i_vx].output_flag[i_mctc] != STATOutputType::None) { - write_mctc_row(shc, mcts_info, - conf_info.vx_opt[i_vx].output_flag[i_mctc], - stat_at, i_stat_row, - txt_at[i_mctc], i_txt_row[i_mctc]); - } - - // Write out MCTS - if(conf_info.vx_opt[i_vx].output_flag[i_mcts] != STATOutputType::None) { - write_mcts_row(shc, mcts_info, - conf_info.vx_opt[i_vx].output_flag[i_mcts], - stat_at, i_stat_row, - txt_at[i_mcts], i_txt_row[i_mcts]); - } - } // end Compute MCTS scores - - // Compute CNT, SL1L2, and SAL1L2 scores - if(!conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_prob() && - (conf_info.vx_opt[i_vx].output_flag[i_cnt] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_sl1l2] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_sal1l2] != STATOutputType::None)) { - do_cnt_sl1l2(conf_info.vx_opt[i_vx], pd_ptr); + // Write out CTS + if(vx_ptr->output_flag[i_cts] != STATOutputType::None) { + write_cts_row(shc, cts_info[i_cat], + vx_ptr->output_flag[i_cts], + stat_at, i_stat_row, + txt_at[i_cts], i_txt_row[i_cts]); } - // Compute VL1L2 and VAL1L2 partial sums for UGRD and VGRD - if(!conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_prob() && - conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_v_wind() && - conf_info.vx_opt[i_vx].vx_pd.fcst_info->uv_index() >= 0 && - (conf_info.vx_opt[i_vx].output_flag[i_vl1l2] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_val1l2] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_vcnt] != STATOutputType::None)) { - - // Store the forecast variable name - shc.set_fcst_var(ugrd_vgrd_abbr_str); - - // Store the observation variable name - shc.set_obs_var(ugrd_vgrd_abbr_str); - - // Initialize - for(int i_wind=0; i_winduv_index(); - - // Check to make sure message types, masking regions, - // and interpolation methods match - if(conf_info.vx_opt[i_vx].get_n_msg_typ() != - conf_info.vx_opt[u_vx].get_n_msg_typ() || - conf_info.vx_opt[i_vx].get_n_mask() != - conf_info.vx_opt[u_vx].get_n_mask() || - conf_info.vx_opt[i_vx].get_n_interp() != - conf_info.vx_opt[u_vx].get_n_interp()) { - mlog << Warning << "\nprocess_scores() -> " - << "when computing VL1L2 and/or VAL1L2 vector " - << "partial sums, the U and V components must " - << "be processed using the same set of message " - << "types, masking regions, and interpolation " - << "methods. Failing to do so will cause " - << "unexpected results!\n\n"; - } - - // Compute VL1L2 and VAL1L2 - do_vl1l2(vl1l2_info, i_vx, - &conf_info.vx_opt[u_vx].vx_pd.pd[n], - &conf_info.vx_opt[i_vx].vx_pd.pd[n]); - - // Loop through all of the wind speed thresholds - for(int i_wind=0; i_wind 0) { - write_vl1l2_row(shc, vl1l2_info[i_wind], - conf_info.vx_opt[i_vx].output_flag[i_vl1l2], - stat_at, i_stat_row, - txt_at[i_vl1l2], i_txt_row[i_vl1l2]); - } - - // Write out VAL1L2 - if(conf_info.vx_opt[i_vx].output_flag[i_val1l2] != STATOutputType::None && - vl1l2_info[i_wind].vacount > 0) { - write_val1l2_row(shc, vl1l2_info[i_wind], - conf_info.vx_opt[i_vx].output_flag[i_val1l2], - stat_at, i_stat_row, - txt_at[i_val1l2], i_txt_row[i_val1l2]); - } - - // Write out VCNT - if(conf_info.vx_opt[i_vx].output_flag[i_vcnt] != STATOutputType::None && - vl1l2_info[i_wind].vcount > 0) { - write_vcnt_row(shc, vl1l2_info[i_wind], - conf_info.vx_opt[i_vx].output_flag[i_vcnt], - stat_at, i_stat_row, - txt_at[i_vcnt], i_txt_row[i_vcnt]); - } - - } // end for i - - // Reset the forecast variable name - shc.set_fcst_var(conf_info.vx_opt[i_vx].vx_pd.fcst_info->name_attr()); - - // Reset the observation variable name - shc.set_obs_var(conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr()); - - } // end Compute VL1L2 and VAL1L2 - - // Compute PCT counts and scores - if(conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_prob() && - (conf_info.vx_opt[i_vx].output_flag[i_pct] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_pstd] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_pjc] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_prc] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_eclv] != STATOutputType::None)) { - do_pct(conf_info.vx_opt[i_vx], pd_ptr); + // Write out ECLV + if(vx_ptr->output_flag[i_eclv] != STATOutputType::None) { + write_eclv_row(shc, cts_info[i_cat], vx_ptr->eclv_points, + vx_ptr->output_flag[i_eclv], + stat_at, i_stat_row, + txt_at[i_eclv], i_txt_row[i_eclv]); } + } // end for i_cat + } // end Compute CTS scores - // Reset the verification masking region - shc.set_mask(conf_info.vx_opt[i_vx].mask_name[i_mask].c_str()); + // Compute MCTS scores + if(!vx_ptr->vx_pd.fcst_info->is_prob() && + vx_ptr->fcat_ta.n() > 1 && + (vx_ptr->output_flag[i_mctc] != STATOutputType::None || + vx_ptr->output_flag[i_mcts] != STATOutputType::None)) { - } // end for i_interp + // Initialize + mcts_info.clear(); - // Apply HiRA ensemble verification logic - if(!conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_prob() && - conf_info.vx_opt[i_vx].hira_info.flag && - (conf_info.vx_opt[i_vx].output_flag[i_ecnt] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_rps] != STATOutputType::None)) { + // Compute MCTS Info + do_mcts(mcts_info, i_vx, pd_ptr); - int n = conf_info.vx_opt[i_vx].vx_pd.three_to_one(i_msg_typ, i_mask, 0); + if(mcts_info.cts.n_pairs() == 0) continue; - pd_ptr = &conf_info.vx_opt[i_vx].vx_pd.pd[n]; + // Write out MCTC + if(vx_ptr->output_flag[i_mctc] != STATOutputType::None) { + write_mctc_row(shc, mcts_info, + vx_ptr->output_flag[i_mctc], + stat_at, i_stat_row, + txt_at[i_mctc], i_txt_row[i_mctc]); + } - // Process percentile thresholds - conf_info.vx_opt[i_vx].set_perc_thresh(pd_ptr); + // Write out MCTS + if(vx_ptr->output_flag[i_mcts] != STATOutputType::None) { + write_mcts_row(shc, mcts_info, + vx_ptr->output_flag[i_mcts], + stat_at, i_stat_row, + txt_at[i_mcts], i_txt_row[i_mcts]); + } + } // end Compute MCTS scores + + // Compute CNT, SL1L2, and SAL1L2 scores + if(!vx_ptr->vx_pd.fcst_info->is_prob() && + (vx_ptr->output_flag[i_cnt] != STATOutputType::None || + vx_ptr->output_flag[i_sl1l2] != STATOutputType::None || + vx_ptr->output_flag[i_sal1l2] != STATOutputType::None)) { + do_cnt_sl1l2(*vx_ptr, pd_ptr); + } - // Appy HiRA verification and write ensemble output - do_hira_ens(i_vx, pd_ptr); + // Compute VL1L2 and VAL1L2 partial sums for UGRD and VGRD + if(!vx_ptr->vx_pd.fcst_info->is_prob() && + vx_ptr->vx_pd.fcst_info->is_v_wind() && + vx_ptr->vx_pd.fcst_info->uv_index() >= 0 && + (vx_ptr->output_flag[i_vl1l2] != STATOutputType::None || + vx_ptr->output_flag[i_val1l2] != STATOutputType::None || + vx_ptr->output_flag[i_vcnt] != STATOutputType::None)) { + + // Store the forecast variable name + shc.set_fcst_var(ugrd_vgrd_abbr_str); + + // Store the observation variable name + shc.set_obs_var(ugrd_vgrd_abbr_str); + + // Initialize + for(int i_wind=0; i_windvx_pd.fcst_info->uv_index(); + + // Check to make sure the masking regions match + if(conf_info.vx_opt[i_vx].get_n_mask() != + conf_info.vx_opt[u_vx].get_n_mask()) { + mlog << Warning << "\nprocess_scores() -> " + << "when computing VL1L2 and/or VAL1L2 vector " + << "partial sums, the U and V components must " + << "be processed using the same set of mask regions. " + << "Failing to do so will cause unexpected results!\n\n"; + } - } // end HiRA for ensembles + // Compute VL1L2 and VAL1L2 + do_vl1l2(vl1l2_info, i_vx, + &conf_info.vx_opt[u_vx].vx_pd.pd[i_mask], + &conf_info.vx_opt[i_vx].vx_pd.pd[i_mask]); - // Apply HiRA probabilistic verification logic - if(!conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_prob() && - conf_info.vx_opt[i_vx].hira_info.flag && - (conf_info.vx_opt[i_vx].output_flag[i_mpr] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_pct] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_pstd] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_pjc] != STATOutputType::None || - conf_info.vx_opt[i_vx].output_flag[i_prc] != STATOutputType::None)) { + // Loop through all of the wind speed thresholds + for(int i_wind=0; i_windfwind_ta.n(); i_wind++) { - int n = conf_info.vx_opt[i_vx].vx_pd.three_to_one(i_msg_typ, i_mask, 0); + // Write out VL1L2 + if(vx_ptr->output_flag[i_vl1l2] != STATOutputType::None && + vl1l2_info[i_wind].vcount > 0) { + write_vl1l2_row(shc, vl1l2_info[i_wind], + vx_ptr->output_flag[i_vl1l2], + stat_at, i_stat_row, + txt_at[i_vl1l2], i_txt_row[i_vl1l2]); + } - pd_ptr = &conf_info.vx_opt[i_vx].vx_pd.pd[n]; + // Write out VAL1L2 + if(vx_ptr->output_flag[i_val1l2] != STATOutputType::None && + vl1l2_info[i_wind].vacount > 0) { + write_val1l2_row(shc, vl1l2_info[i_wind], + vx_ptr->output_flag[i_val1l2], + stat_at, i_stat_row, + txt_at[i_val1l2], i_txt_row[i_val1l2]); + } - // Process percentile thresholds - conf_info.vx_opt[i_vx].set_perc_thresh(pd_ptr); + // Write out VCNT + if(vx_ptr->output_flag[i_vcnt] != STATOutputType::None && + vl1l2_info[i_wind].vcount > 0) { + write_vcnt_row(shc, vl1l2_info[i_wind], + vx_ptr->output_flag[i_vcnt], + stat_at, i_stat_row, + txt_at[i_vcnt], i_txt_row[i_vcnt]); + } + } // end for i_wind - // Apply HiRA verification and write probabilistic output - do_hira_prob(i_vx, pd_ptr); + // Reset the forecast variable name + shc.set_fcst_var(vx_ptr->vx_pd.fcst_info->name_attr()); - } // end HiRA for probabilities + // Reset the observation variable name + shc.set_obs_var(vx_ptr->vx_pd.obs_info->name_attr()); - } // end for i_mask - } // end for i_msg_typ + } // end Compute VL1L2 and VAL1L2 + + // Compute PCT counts and scores + if(vx_ptr->vx_pd.fcst_info->is_prob() && + (vx_ptr->output_flag[i_pct] != STATOutputType::None || + vx_ptr->output_flag[i_pstd] != STATOutputType::None || + vx_ptr->output_flag[i_pjc] != STATOutputType::None || + vx_ptr->output_flag[i_prc] != STATOutputType::None || + vx_ptr->output_flag[i_eclv] != STATOutputType::None)) { + do_pct(conf_info.vx_opt[i_vx], pd_ptr); + } + + // Reset the verification masking region + shc.set_mask(vx_ptr->mask_name[i_mask].c_str()); + + } // end for i_mask mlog << Debug(2) << "\n" << sep_str << "\n\n"; @@ -1730,377 +1663,6 @@ void do_pct(const PairStatVxOpt &vx_opt, const PairDataPoint *pd_ptr) { //////////////////////////////////////////////////////////////////////// -void do_hira_ens(int i_vx, const PairDataPoint *pd_ptr) { - PairDataEnsemble hira_pd; - int i, j, k, lvl_blw, lvl_abv; - NumArray f_ens; - - // Set flag for specific humidity - bool spfh_flag = conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_specific_humidity() && - conf_info.vx_opt[i_vx].vx_pd.obs_info->is_specific_humidity(); - - shc.set_interp_mthd(InterpMthd::Nbrhd, - conf_info.vx_opt[i_vx].hira_info.shape); - - // Loop over the HiRA widths - for(i=0; i " - << "failed to get GridTemplate for " << i << "-th width.\n\n"; - continue; - } - - // Initialize - hira_pd.clear(); - hira_pd.extend(pd_ptr->n_obs); - hira_pd.set_ens_size(gt->size()); - hira_pd.set_climo_cdf_info_ptr(&conf_info.vx_opt[i_vx].cdf_info); - f_ens.extend(gt->size()); - - // Process each observation point - for(j=0; jn_obs; j++) { - - // Determine the forecast level values - find_vert_lvl(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa, - pd_ptr->lvl_na[j], lvl_blw, lvl_abv); - - // Get the nearby forecast values - get_interp_points(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa, - pd_ptr->x_na[j], pd_ptr->y_na[j], - InterpMthd::Nbrhd, conf_info.vx_opt[i_vx].hira_info.width[i], - conf_info.vx_opt[i_vx].hira_info.shape, grid.wrap_lon(), - conf_info.vx_opt[i_vx].hira_info.vld_thresh, spfh_flag, - conf_info.vx_opt[i_vx].vx_pd.fcst_info->level().type(), - pd_ptr->lvl_na[j], lvl_blw, lvl_abv, f_ens); - - // Check for values - if(f_ens.n() == 0) continue; - - // TODO: Add has_climo member function instead - - // Skip points where climatology has been specified but is bad data - if((conf_info.vx_opt[i_vx].vx_pd.fcmn_dpa.n_planes() > 0 && - is_bad_data(pd_ptr->fcmn_na[j])) || - (conf_info.vx_opt[i_vx].vx_pd.ocmn_dpa.n_planes() > 0 && - is_bad_data(pd_ptr->ocmn_na[j]))) continue; - - // Store climo data - ClimoPntInfo cpi(pd_ptr->fcmn_na[j], pd_ptr->fcsd_na[j], - pd_ptr->ocmn_na[j], pd_ptr->ocsd_na[j]); - - // Store the observation value - hira_pd.add_point_obs( - pd_ptr->typ_sa[j].c_str(), pd_ptr->sid_sa[j].c_str(), - pd_ptr->lat_na[j], pd_ptr->lon_na[j], - pd_ptr->x_na[j], pd_ptr->y_na[j], pd_ptr->vld_ta[j], - pd_ptr->lvl_na[j], pd_ptr->elv_na[j], - pd_ptr->o_na[j], pd_ptr->o_qc_sa[j].c_str(), - cpi, pd_ptr->wgt_na[j]); - - // Store the ensemble mean and member values - hira_pd.mn_na.add(f_ens.mean()); - for(k=0; kmagic_str() - << " versus " - << conf_info.vx_opt[i_vx].vx_pd.obs_info->magic_str() - << ", for observation type " << pd_ptr->msg_typ - << ", over region " << pd_ptr->mask_name - << ", for interpolation method HiRA Ensemble NBRHD(" - << shc.get_interp_pnts_str() - << "), using " << hira_pd.n_obs << " matched pairs.\n"; - - // Check for zero matched pairs - if(hira_pd.o_na.n() == 0) { - if(gt) { delete gt; gt = nullptr; } - continue; - } - - // Compute the pair values - hira_pd.compute_pair_vals(rng_ptr); - - // Write out the ECNT line - if(conf_info.vx_opt[i_vx].output_flag[i_ecnt] != STATOutputType::None) { - - // Compute ensemble statistics - ECNTInfo ecnt_info; - ecnt_info.set(hira_pd); - - write_ecnt_row(shc, ecnt_info, - conf_info.vx_opt[i_vx].output_flag[i_ecnt], - stat_at, i_stat_row, - txt_at[i_ecnt], i_txt_row[i_ecnt]); - } // end if ECNT - - // Write out the ORANK line - if(conf_info.vx_opt[i_vx].output_flag[i_orank] != STATOutputType::None) { - - write_orank_row(shc, &hira_pd, - conf_info.vx_opt[i_vx].output_flag[i_orank], - stat_at, i_stat_row, - txt_at[i_orank], i_txt_row[i_orank], false); - - // Reset the obtype column - shc.set_obtype(pd_ptr->msg_typ.c_str()); - - // Reset the observation valid time - shc.set_obs_valid_beg(conf_info.vx_opt[i_vx].vx_pd.beg_ut); - shc.set_obs_valid_end(conf_info.vx_opt[i_vx].vx_pd.end_ut); - } // end if ORANK - - // Write out the RPS line - if(conf_info.vx_opt[i_vx].output_flag[i_rps] != STATOutputType::None) { - - // Store ensemble RPS thresholds - RPSInfo rps_info; - rps_info.set_prob_cat_thresh(conf_info.vx_opt[i_vx].hira_info.prob_cat_ta); - - // If prob_cat_thresh is empty, try to select other thresholds - if(rps_info.fthresh.n() == 0) { - - // Use observation climo data, if avaiable - if(hira_pd.ocmn_na.n_valid() > 0 && - hira_pd.ocsd_na.n_valid() > 0 && - conf_info.vx_opt[i_vx].cdf_info.cdf_ta.n() > 0) { - mlog << Debug(3) << "Resetting the empty HiRA \"" - << conf_key_prob_cat_thresh << "\" thresholds to " - << "climatological distribution thresholds.\n"; - rps_info.set_cdp_thresh(conf_info.vx_opt[i_vx].cdf_info.cdf_ta); - } - // Otherwise, use categorical observation thresholds - else { - mlog << Debug(3) << "Resetting the empty HiRA \"" - << conf_key_prob_cat_thresh << "\" thresholds to the " - << "observed categorical thresholds.\n"; - rps_info.set_prob_cat_thresh(conf_info.vx_opt[i_vx].ocat_ta); - } - } - - // Check for no thresholds - if(rps_info.fthresh.n() == 0) { - mlog << Debug(3) << "Skipping HiRA RPS output since no " - << "\"" << conf_key_prob_cat_thresh << "\" thresholds are " - << "defined in the \"" << conf_key_hira - << "\" dictionary.\n"; - if(gt) { delete gt; gt = nullptr; } - break; - } - - // Compute ensemble RPS statistics - rps_info.set(hira_pd); - - write_rps_row(shc, rps_info, - conf_info.vx_opt[i_vx].output_flag[i_rps], - stat_at, i_stat_row, - txt_at[i_rps], i_txt_row[i_rps]); - } // end if RPS - - if(gt) { delete gt; gt = nullptr; } - - } // end for i - - return; -} - -//////////////////////////////////////////////////////////////////////// - -void do_hira_prob(int i_vx, const PairDataPoint *pd_ptr) { - PairDataPoint hira_pd; - int i, j, k, lvl_blw, lvl_abv; - double f_cov, ocmn_cov; - NumArray ocmn_cov_na; - SingleThresh cat_thresh; - PCTInfo pct_info; - - // Set flag for specific humidity - bool spfh_flag = conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_specific_humidity() && - conf_info.vx_opt[i_vx].vx_pd.obs_info->is_specific_humidity(); - bool precip_flag = conf_info.vx_opt[i_vx].vx_pd.fcst_info->is_precipitation() && - conf_info.vx_opt[i_vx].vx_pd.obs_info->is_precipitation(); - - shc.set_interp_mthd(InterpMthd::Nbrhd, - conf_info.vx_opt[i_vx].hira_info.shape); - - // Loop over categorical thresholds and HiRA widths - for(i=0; in_obs; k++) { - - // Store climo data - ClimoPntInfo cpi(pd_ptr->fcmn_na[k], pd_ptr->fcsd_na[k], - pd_ptr->ocmn_na[k], pd_ptr->ocsd_na[k]); - - // Compute the fractional coverage forecast value using the - // observation level value - find_vert_lvl(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa, - pd_ptr->lvl_na[k], lvl_blw, lvl_abv); - - f_cov = compute_interp(conf_info.vx_opt[i_vx].vx_pd.fcst_dpa, - pd_ptr->x_na[k], pd_ptr->y_na[k], pd_ptr->o_na[k], &cpi, - InterpMthd::Nbrhd, conf_info.vx_opt[i_vx].hira_info.width[j], - conf_info.vx_opt[i_vx].hira_info.shape, grid.wrap_lon(), - conf_info.vx_opt[i_vx].hira_info.vld_thresh, spfh_flag, - conf_info.vx_opt[i_vx].vx_pd.fcst_info->level().type(), - pd_ptr->lvl_na[k], lvl_blw, lvl_abv, &cat_thresh); - - // Check for bad data - if(is_bad_data(f_cov)) continue; - - // Compute the climatological event probability as the fractional - // coverage of the observation climatology mean field - if(conf_info.vx_opt[i_vx].vx_pd.ocmn_dpa.n_planes() > 0) { - - // Interpolate to the observation level - find_vert_lvl(conf_info.vx_opt[i_vx].vx_pd.ocmn_dpa, - pd_ptr->lvl_na[k], lvl_blw, lvl_abv); - - ocmn_cov = compute_interp(conf_info.vx_opt[i_vx].vx_pd.ocmn_dpa, - pd_ptr->x_na[k], pd_ptr->y_na[k], pd_ptr->o_na[k], &cpi, - InterpMthd::Nbrhd, conf_info.vx_opt[i_vx].hira_info.width[j], - conf_info.vx_opt[i_vx].hira_info.shape, grid.wrap_lon(), - conf_info.vx_opt[i_vx].hira_info.vld_thresh, spfh_flag, - conf_info.vx_opt[i_vx].vx_pd.fcst_info->level().type(), - pd_ptr->lvl_na[k], lvl_blw, lvl_abv, &cat_thresh); - - // Check for bad data - if(is_bad_data(ocmn_cov)) continue; - else ocmn_cov_na.add(ocmn_cov); - } - - // Store the fractional coverage pair - hira_pd.add_point_pair( - pd_ptr->typ_sa[k].c_str(), - pd_ptr->sid_sa[k].c_str(), - pd_ptr->lat_na[k], pd_ptr->lon_na[k], - pd_ptr->x_na[k], pd_ptr->y_na[k], pd_ptr->vld_ta[k], - pd_ptr->lvl_na[k], pd_ptr->elv_na[k], - f_cov, pd_ptr->o_na[k], pd_ptr->o_qc_sa[k].c_str(), - cpi, pd_ptr->wgt_na[k]); - } // end for k - - mlog << Debug(2) - << "Processing " - << conf_info.vx_opt[i_vx].vx_pd.fcst_info->magic_str() - << conf_info.vx_opt[i_vx].fcat_ta[i].get_str() - << " versus " - << conf_info.vx_opt[i_vx].vx_pd.obs_info->magic_str() - << conf_info.vx_opt[i_vx].ocat_ta[i].get_str() - << ", for observation type " << pd_ptr->msg_typ - << ", over region " << pd_ptr->mask_name - << ", for interpolation method HiRA Probability NBRHD(" - << shc.get_interp_pnts_str() - << "), using " << hira_pd.n_obs << " matched pairs.\n"; - - // Check for zero matched pairs - if(hira_pd.f_na.n() == 0 || hira_pd.o_na.n() == 0) continue; - - // Set up the PCTInfo thresholds and alpha values - pct_info.fthresh = conf_info.vx_opt[i_vx].hira_info.cov_ta; - pct_info.othresh = conf_info.vx_opt[i_vx].ocat_ta[i]; - pct_info.allocate_n_alpha(conf_info.vx_opt[i_vx].get_n_ci_alpha()); - - for(k=0; kmsg_typ.c_str()); - - // Reset the observation valid time - shc.set_obs_valid_beg(conf_info.vx_opt[i_vx].vx_pd.beg_ut); - shc.set_obs_valid_end(conf_info.vx_opt[i_vx].vx_pd.end_ut); - } - - // Set cov_thresh column using the HiRA coverage thresholds - shc.set_cov_thresh(conf_info.vx_opt[i_vx].hira_info.cov_ta); - - // Write out PCT - if(conf_info.vx_opt[i_vx].output_flag[i_pct] != STATOutputType::None) { - write_pct_row(shc, pct_info, - conf_info.vx_opt[i_vx].output_flag[i_pct],1, 1, - stat_at, i_stat_row, - txt_at[i_pct], i_txt_row[i_pct], false); - } - - // Write out PSTD - if(conf_info.vx_opt[i_vx].output_flag[i_pstd] != STATOutputType::None) { - write_pstd_row(shc, pct_info, - conf_info.vx_opt[i_vx].output_flag[i_pstd], 1, 1, - stat_at, i_stat_row, - txt_at[i_pstd], i_txt_row[i_pstd], false); - } - - // Write out PJC - if(conf_info.vx_opt[i_vx].output_flag[i_pjc] != STATOutputType::None) { - write_pjc_row(shc, pct_info, - conf_info.vx_opt[i_vx].output_flag[i_pjc], 1, 1, - stat_at, i_stat_row, - txt_at[i_pjc], i_txt_row[i_pjc], false); - } - - // Write out PRC - if(conf_info.vx_opt[i_vx].output_flag[i_prc] != STATOutputType::None) { - write_prc_row(shc, pct_info, - conf_info.vx_opt[i_vx].output_flag[i_prc], 1, 1, - stat_at, i_stat_row, - txt_at[i_prc], i_txt_row[i_prc], false); - } - - } // end for j - } // end for i - - return; -} - -//////////////////////////////////////////////////////////////////////// - void finish_txt_files() { int i; @@ -2152,18 +1714,17 @@ void usage() { << ") ***\n\n" << "Usage: " << program_name << "\n" - << "\t-pairs file\n" + << "\t-pairs file_1 ... file_n | file_list\n" << "\t-format type\n" << "\t-config config_file\n" << "\t[-outdir path]\n" << "\t[-log file]\n" << "\t[-v level]\n\n" - -// JHG change -pairs file to -pairs file_list to support a long list of inputs - << "\twhere\t\"-pairs file\" is one or more files containing " - << "forecast/observation pairs. May be used multiple times " - << "(required).\n" + << "\twhere\t\"-pairs\" defines one or more input files containing " + << "forecast/observation pairs. May be set as a list of file names " + << "(file_1 ... file_n) or as an ASCII file containing a list of " + << "file names (file_list). May be used multiple times (required)." << "\t\t\"-format type\" defines the input pairs file format " << "and may be set to \"mpr\" or \"ioda\" (required).\n" diff --git a/src/tools/core/pair_stat/pair_stat.h b/src/tools/core/pair_stat/pair_stat.h index 7d35492d0b..4186811a11 100644 --- a/src/tools/core/pair_stat/pair_stat.h +++ b/src/tools/core/pair_stat/pair_stat.h @@ -60,38 +60,35 @@ static const char * ioda_data_config_filename = // Header columns static const char * const * txt_columns[n_txt] = { - fho_columns, ctc_columns, cts_columns, - mctc_columns, mcts_columns, cnt_columns, - sl1l2_columns, sal1l2_columns, vl1l2_columns, - val1l2_columns, pct_columns, pstd_columns, - pjc_columns, prc_columns, ecnt_columns, - orank_columns, rps_columns, eclv_columns, - mpr_columns, vcnt_columns, seeps_mpr_columns, - seeps_columns + fho_columns, ctc_columns, cts_columns, + mctc_columns, mcts_columns, + cnt_columns, sl1l2_columns, sal1l2_columns, + vcnt_columns, vl1l2_columns, val1l2_columns, + pct_columns, pstd_columns, pjc_columns, + prc_columns, eclv_columns, + mpr_columns, seeps_mpr_columns, seeps_columns }; // Length of header columns static const int n_txt_columns[n_txt] = { - n_fho_columns, n_ctc_columns, n_cts_columns, - n_mctc_columns, n_mcts_columns, n_cnt_columns, - n_sl1l2_columns, n_sal1l2_columns, n_vl1l2_columns, - n_val1l2_columns, n_pct_columns, n_pstd_columns, - n_pjc_columns, n_prc_columns, n_ecnt_columns, - n_orank_columns, n_rps_columns, n_eclv_columns, - n_mpr_columns, n_vcnt_columns, n_seeps_mpr_columns, - n_seeps_columns + n_fho_columns, n_ctc_columns, n_cts_columns, + n_mctc_columns, n_mcts_columns, + n_cnt_columns, n_sl1l2_columns, n_sal1l2_columns, + n_vcnt_columns, n_vl1l2_columns, n_val1l2_columns, + n_pct_columns, n_pstd_columns, n_pjc_columns, + n_prc_columns, n_eclv_columns, + n_mpr_columns, n_seeps_mpr_columns, n_seeps_columns }; // Text file abbreviations static const char * const txt_file_abbr[n_txt] = { - "fho", "ctc", "cts", - "mctc", "mcts", "cnt", - "sl1l2", "sal1l2", "vl1l2", - "val1l2", "pct", "pstd", - "pjc", "prc", "ecnt", - "orank", "rps", "eclv", - "mpr", "vcnt", "seeps_mpr", - "seeps" + "fho", "ctc", "cts", + "mctc", "mcts", + "cnt", "sl1l2", "sal1l2", + "vcnt", "vl1l2", "val1l2", + "pct", "pstd", "pjc", + "prc", "eclv", + "mpr", "seeps_mpr", "seeps" }; /////////////////////////////////////////////////////////////////////////////// diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.cc b/src/tools/core/pair_stat/pair_stat_conf_info.cc index 957c526056..0d093dac66 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.cc +++ b/src/tools/core/pair_stat/pair_stat_conf_info.cc @@ -610,26 +610,6 @@ int PairStatConfInfo::get_max_n_eclv_points() const { //////////////////////////////////////////////////////////////////////// -int PairStatConfInfo::get_max_n_hira_ens() const { - int n = 0; - - for(int i=0; i " + << "The length of \"" << conf_key_mpr_column << "\" and \"" + << conf_key_mpr_thresh << "\" must match (" << mpr_sa.n() + << " != " << mpr_ta.n() << ")!\n\n"; + exit(1); + } + + // Store in map + for(int i=0; mpr_sa.n(); i++) { + if(mpr_thr_inc_map.count(mpr_sa[i]) == 0) { + ThreshArray ta; + mpr_thr_inc_map[(mpr_sa[i])] = ta; + } + mpr_thr_inc_map[(mpr_sa[i])].add(mpr_ta[i]); + } // Dump the contents of the current thresholds if(mlog.verbosity_level() >= 5) { @@ -953,32 +939,14 @@ void PairStatVxOpt::process_config(PairsFormat ftype, // Conf: boot boot_info = parse_conf_boot(&odict); - // Conf: interp - interp_info = parse_conf_interp(&odict, conf_key_interp); - - // Conf: hira - hira_info = parse_conf_hira(&odict); - // Conf: hss_ec_value hss_ec_value = odict.lookup_double(conf_key_hss_ec_value); // Conf: rank_corr_flag rank_corr_flag = odict.lookup_bool(conf_key_rank_corr_flag); - // Conf: message_type - msg_typ = parse_conf_message_type(&odict); - - // Conf: duplicate_flag - duplicate_flag = parse_conf_duplicate_flag(&odict); - - // Conf: obs_summary - obs_summary = parse_conf_obs_summary(&odict); - - // Conf: obs_perc_value - obs_perc = parse_conf_percentile(&odict); - // Conf: desc - vx_pd.set_desc(parse_conf_string(&odict, conf_key_desc).c_str()); + vx_pd.set_desc(parse_conf_string(&odict, conf_key_desc, false).c_str()); // Conf: sid_inc vx_pd.set_sid_inc_filt(parse_conf_sid_list(&odict, conf_key_sid_inc)); @@ -998,23 +966,11 @@ void PairStatVxOpt::process_config(PairsFormat ftype, //////////////////////////////////////////////////////////////////////// void PairStatVxOpt::set_vx_pd(PairStatConfInfo *conf_info) { - int i, n; - int n_msg_typ = msg_typ.n(); - int n_mask = mask_name.n(); - int n_interp = interp_info.n_interp; + int n_mask = mask_name.n(); ConcatString cs; StringArray sa; - // Setup the VxPairDataPoint object with these dimensions: - // [n_msg_typ][n_mask][n_interp] - - // Check for at least one message type - if(n_msg_typ == 0) { - mlog << Error << "\nPairStatVxOpt::set_vx_pd() -> " - << "At least one output message type must be requested in \"" - << conf_key_message_type << "\".\n\n"; - exit(1); - } + // Setup the VxPairDataPoint object for each mask // Check for at least one masking region if(n_mask == 0) { @@ -1027,19 +983,11 @@ void PairStatVxOpt::set_vx_pd(PairStatConfInfo *conf_info) { exit(1); } - // Check for at least one interpolation method - if(n_interp == 0) { - mlog << Error << "\nPairStatVxOpt::set_vx_pd() -> " - << "At least one interpolation method must be requested in \"" - << conf_key_interp << "\".\n\n"; - exit(1); - } - - // Define the dimensions - vx_pd.set_size(n_msg_typ, n_mask, n_interp); + // Define the dimensions with n_msg_typ = n_interp = 1 + vx_pd.set_size(1, n_mask, 1); - // Store the MPR filter threshold - vx_pd.set_mpr_thresh(mpr_sa, mpr_ta); + // Store the MPR filtering thresholds + vx_pd.set_mpr_thr_inc_map(mpr_thr_inc_map); // Store the climo CDF info vx_pd.set_climo_cdf_info_ptr(&cdf_info); @@ -1074,59 +1022,43 @@ void PairStatVxOpt::set_vx_pd(PairStatConfInfo *conf_info) { vx_pd.set_msg_typ_wtr(sa); } - // Define the verifying message type name and values - for(i=0; imsg_typ_group_map[msg_typ[i]]; - if(sa.n() == 0) sa.add(msg_typ[i]); - vx_pd.set_msg_typ_vals(i, sa); - } - // Define the masking information: grid, poly, sid, point + int n; // Define the grid masks - for(i=0; imask_area_map[mask_name[n]])); } // Define the poly masks - for(i=0; imask_area_map[mask_name[n]])); } // Define the station ID masks - for(i=0; imask_sid_map[mask_name[n]])); } // Define the Lat/Lon point masks - for(i=0; i<(int) mask_llpnt.size(); i++) { + for(int i=0; i<(int) mask_llpnt.size(); i++) { n = i + mask_grid.n() + mask_poly.n() + mask_sid.n(); vx_pd.set_mask_llpnt(n, mask_name[n].c_str(), &mask_llpnt[i]); } - // Define the interpolation methods - for(i=0; iseeps_climo_name); vx_pd.set_seeps_thresh(conf_info->seeps_p1_thresh); } + return; } @@ -1185,7 +1117,7 @@ int PairStatVxOpt::n_txt_row(int i_txt_row) const { bool vect_flag = vx_pd.fcst_info->is_v_wind() && vx_pd.fcst_info->uv_index() >= 0; - int n_pd = get_n_msg_typ() * get_n_mask() * get_n_interp(); + int n_pd = get_n_mask(); // Determine row multiplier for climatology bins if(cdf_info.write_bins) { @@ -1242,14 +1174,6 @@ int PairStatVxOpt::n_txt_row(int i_txt_row) const { n = (prob_flag ? 0 : n_pd * get_n_cnt_thresh() * n_bin); break; - case i_vl1l2: - case i_val1l2: - // Number of VL1L2 or VAL1L2 lines = - // Message Types * Masks * Interpolations * Thresholds - n = (!vect_flag ? 0 : n_pd * - get_n_wind_thresh()); - break; - case i_vcnt: // Number of VCNT lines = // Message Types * Masks * Interpolations * Thresholds * @@ -1258,6 +1182,14 @@ int PairStatVxOpt::n_txt_row(int i_txt_row) const { get_n_wind_thresh() * get_n_ci_alpha()); break; + case i_vl1l2: + case i_val1l2: + // Number of VL1L2 or VAL1L2 lines = + // Message Types * Masks * Interpolations * Thresholds + n = (!vect_flag ? 0 : n_pd * + get_n_wind_thresh()); + break; + case i_pct: case i_pjc: case i_prc: @@ -1265,14 +1197,6 @@ int PairStatVxOpt::n_txt_row(int i_txt_row) const { // Message Types * Masks * Interpolations * Thresholds * // Climo Bins n = (!prob_flag ? 0 : n_pd * get_n_oprob_thresh() * n_bin); - - // Number of HiRA PCT, PJC, or PRC lines = - // Message Types * Masks * HiRA widths * Thresholds - if(hira_info.flag) { - n += (prob_flag ? 0 : n_pd * get_n_cat_thresh() * - hira_info.width.n()); - } - break; case i_pstd: @@ -1281,44 +1205,6 @@ int PairStatVxOpt::n_txt_row(int i_txt_row) const { // Alphas * Climo Bins n = (!prob_flag ? 0 : n_pd * get_n_oprob_thresh() * get_n_ci_alpha() * n_bin); - - // Number of HiRA PSTD lines = - // Message Types * Masks * HiRA widths * Thresholds * - // Alphas - if(hira_info.flag) { - n += (prob_flag ? 0 : n_pd * - get_n_cat_thresh() * hira_info.width.n() * - get_n_ci_alpha()); - } - - break; - - case i_ecnt: - case i_rps: - // Number of HiRA ECNT and RPS lines = - // Message Types * Masks * HiRA widths * - // Alphas - if(hira_info.flag) { - n = n_pd * hira_info.width.n() * get_n_ci_alpha(); - } - else { - n = 0; - } - - break; - - case i_orank: - // Number of HiRA ORANK lines possible = - // Number of pairs * Categorical Thresholds * - // HiRA widths - if(hira_info.flag) { - n = vx_pd.get_n_pair() * get_n_cat_thresh() * - hira_info.width.n(); - } - else { - n = 0; - } - break; case i_eclv: @@ -1333,34 +1219,21 @@ int PairStatVxOpt::n_txt_row(int i_txt_row) const { // Forecast Probability Thresholds * Climo Bins n += (!prob_flag ? 0 : n_pd * get_n_oprob_thresh() * get_n_fprob_thresh() * n_bin); - break; case i_mpr: // Compute the number of matched pairs to be written n = vx_pd.get_n_pair(); - - // Maximum number of HiRA MPR lines possible = - // Number of pairs * Max Scalar Categorical Thresholds * - // HiRA widths - if(hira_info.flag) { - n += (prob_flag ? 0 : - vx_pd.get_n_pair() * get_n_cat_thresh() * - hira_info.width.n()); - } - break; case i_seeps_mpr: // Compute the number of matched pairs to be written n = vx_pd.get_n_pair(); - break; case i_seeps: // Compute the number of matched pairs to be written n = vx_pd.get_n_pair(); - break; default: @@ -1408,16 +1281,3 @@ int PairStatVxOpt::get_n_oprob_thresh() const { } //////////////////////////////////////////////////////////////////////// - -int PairStatVxOpt::get_n_hira_ens() const { - int n = (hira_info.flag ? hira_info.width.max() : 0); - return n*n; -} - -//////////////////////////////////////////////////////////////////////// - -int PairStatVxOpt::get_n_hira_prob() const { - return hira_info.flag ? hira_info.cov_ta.n() : 0; -} - -//////////////////////////////////////////////////////////////////////// diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.h b/src/tools/core/pair_stat/pair_stat_conf_info.h index 1ebea15d53..dd5dd72da4 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.h +++ b/src/tools/core/pair_stat/pair_stat_conf_info.h @@ -37,24 +37,22 @@ static const int i_mcts = 4; static const int i_cnt = 5; static const int i_sl1l2 = 6; static const int i_sal1l2 = 7; -static const int i_vl1l2 = 8; -static const int i_val1l2 = 9; -static const int i_pct = 10; -static const int i_pstd = 11; -static const int i_pjc = 12; -static const int i_prc = 13; -static const int i_ecnt = 14; +static const int i_vcnt = 8; +static const int i_vl1l2 = 9; +static const int i_val1l2 = 10; -static const int i_orank = 15; -static const int i_rps = 16; -static const int i_eclv = 17; -static const int i_mpr = 18; -static const int i_vcnt = 19; -static const int i_seeps_mpr = 20; -static const int i_seeps = 21; +static const int i_pct = 11; +static const int i_pstd = 12; +static const int i_pjc = 13; +static const int i_prc = 14; +static const int i_eclv = 15; -static const int n_txt = 22; +static const int i_mpr = 16; +static const int i_seeps_mpr = 17; +static const int i_seeps = 18; + +static const int n_txt = 19; // Text file type static const STATLineType txt_file_type[n_txt] = { @@ -68,23 +66,20 @@ static const STATLineType txt_file_type[n_txt] = { STATLineType::cnt, // 5 STATLineType::sl1l2, // 6 STATLineType::sal1l2, // 7 - STATLineType::vl1l2, // 8 - STATLineType::val1l2, // 9 - - STATLineType::pct, // 10 - STATLineType::pstd, // 11 - STATLineType::pjc, // 12 - STATLineType::prc, // 13 - STATLineType::ecnt, // 14 - - STATLineType::orank, // 15 - STATLineType::rps, // 16 - STATLineType::eclv, // 17 - STATLineType::mpr, // 18 - STATLineType::vcnt, // 19 - - STATLineType::seeps_mpr, // 20 - STATLineType::seeps // 21 + + STATLineType::vcnt, // 8 + STATLineType::vl1l2, // 9 + STATLineType::val1l2, // 10 + + STATLineType::pct, // 11 + STATLineType::pstd, // 12 + STATLineType::pjc, // 13 + STATLineType::prc, // 14 + STATLineType::eclv, // 15 + + STATLineType::mpr, // 16 + STATLineType::seeps_mpr, // 17 + STATLineType::seeps // 18 }; /////////////////////////////////////////////////////////////////////////////// @@ -124,7 +119,7 @@ class PairStatVxOpt { ////////////////////////////////////////////////////////////////// - VxPairDataPoint vx_pd; // Matched pair data [n_msg_typ][n_mask][n_interp] + VxPairDataPoint vx_pd; // Matched pair data [n_mask] int beg_ds; // Begin observation time window offset int end_ds; // End observation time window offset @@ -147,8 +142,8 @@ class PairStatVxOpt { StringArray mask_poly; // Masking polyline strings StringArray mask_sid; // Masking station ID's - StringArray mpr_sa; // MPR column names - ThreshArray mpr_ta; // MPR column thresholds + // Matched pair inclusion thresholds + std::map mpr_thr_inc_map; // Vector of MaskLatLon objects defining Lat/Lon Point masks std::vector mask_llpnt; @@ -162,18 +157,12 @@ class PairStatVxOpt { NumArray ci_alpha; // Alpha value for confidence intervals BootInfo boot_info; // Bootstrapping information - InterpInfo interp_info; // Interpolation information - HiRAInfo hira_info; // HiRA verification logic double hss_ec_value; // HSS expected correct value bool rank_corr_flag; // Flag for computing rank correlations StringArray msg_typ; // Array of message types - DuplicateType duplicate_flag; // Duplicate observations - ObsSummary obs_summary; // Summarize observations - int obs_perc; // Summary percentile value - // Output file options STATOutputType output_flag[n_txt]; // Flag for each output line type @@ -190,9 +179,7 @@ class PairStatVxOpt { // Compute the number of output lines for this task int n_txt_row(int i) const; - int get_n_msg_typ() const; int get_n_mask() const; - int get_n_interp() const; int get_n_cnt_thresh() const; int get_n_cat_thresh() const; @@ -202,17 +189,13 @@ class PairStatVxOpt { int get_n_oprob_thresh() const; int get_n_eclv_points() const; - int get_n_hira_ens() const; - int get_n_hira_prob() const; int get_n_cdf_bin() const; int get_n_ci_alpha() const; }; //////////////////////////////////////////////////////////////////////// -inline int PairStatVxOpt::get_n_msg_typ() const { return msg_typ.n(); } inline int PairStatVxOpt::get_n_mask() const { return mask_name.n(); } -inline int PairStatVxOpt::get_n_interp() const { return interp_info.n_interp; } inline int PairStatVxOpt::get_n_eclv_points() const { return eclv_points.n(); } inline int PairStatVxOpt::get_n_cdf_bin() const { return cdf_info.n_bin; } @@ -298,8 +281,6 @@ class PairStatConfInfo { int get_max_n_fprob_thresh() const; int get_max_n_oprob_thresh() const; int get_max_n_eclv_points() const; - int get_max_n_hira_ens() const; - int get_max_n_hira_prob() const; // Check for any verification of vectors bool get_vflag() const; diff --git a/src/tools/core/point_stat/point_stat_conf_info.cc b/src/tools/core/point_stat/point_stat_conf_info.cc index cfd5e10432..c083d2fe4d 100644 --- a/src/tools/core/point_stat/point_stat_conf_info.cc +++ b/src/tools/core/point_stat/point_stat_conf_info.cc @@ -762,8 +762,7 @@ void PointStatVxOpt::clear() { mask_sid.clear(); mask_llpnt.clear(); - mpr_sa.clear(); - mpr_ta.clear(); + mpr_thr_inc_map.clear(); mask_name.clear(); @@ -919,8 +918,26 @@ void PointStatVxOpt::process_config(GrdFileType ftype, int_to_setlogic(odict.lookup_int(conf_key_wind_logic))); // Conf: mpr_column and mpr_thresh - mpr_sa = odict.lookup_string_array(conf_key_mpr_column); - mpr_ta = odict.lookup_thresh_array(conf_key_mpr_thresh); + StringArray mpr_sa(odict.lookup_string_array(conf_key_mpr_column)); + ThreshArray mpr_ta(odict.lookup_thresh_array(conf_key_mpr_thresh)); + + // Check for the same length + if(mpr_sa.n() != mpr_ta.n()) { + mlog << Error << "\nPointStatVxOpt::process_config() -> " + << "The length of \"" << conf_key_mpr_column << "\" and \"" + << conf_key_mpr_thresh << "\" must match (" << mpr_sa.n() + << " != " << mpr_ta.n() << ")!\n\n"; + exit(1); + } + + // Store in map + for(int i=0; mpr_sa.n(); i++) { + if(mpr_thr_inc_map.count(mpr_sa[i]) == 0) { + ThreshArray ta; + mpr_thr_inc_map[(mpr_sa[i])] = ta; + } + mpr_thr_inc_map[(mpr_sa[i])].add(mpr_ta[i]); + } // Dump the contents of the current thresholds if(mlog.verbosity_level() >= 5) { @@ -1089,7 +1106,7 @@ void PointStatVxOpt::set_vx_pd(PointStatConfInfo *conf_info) { vx_pd.set_size(n_msg_typ, n_mask, n_interp); // Store the MPR filter threshold - vx_pd.set_mpr_thresh(mpr_sa, mpr_ta); + vx_pd.set_mpr_thr_inc_map(mpr_thr_inc_map); // Store the climo CDF info vx_pd.set_climo_cdf_info_ptr(&cdf_info); diff --git a/src/tools/core/point_stat/point_stat_conf_info.h b/src/tools/core/point_stat/point_stat_conf_info.h index 9db3081dd7..3660cb78d8 100644 --- a/src/tools/core/point_stat/point_stat_conf_info.h +++ b/src/tools/core/point_stat/point_stat_conf_info.h @@ -129,8 +129,8 @@ class PointStatVxOpt { StringArray mask_poly; // Masking polyline strings StringArray mask_sid; // Masking station ID's - StringArray mpr_sa; // MPR column names - ThreshArray mpr_ta; // MPR column thresholds + // Matched pair inclusion thresholds + std::map mpr_thr_inc_map; // Vector of MaskLatLon objects defining Lat/Lon Point masks std::vector mask_llpnt; From c6dbfb6f56600da1935e9759830c5e0b74ce0e43 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 27 Dec 2024 22:46:55 +0000 Subject: [PATCH 07/15] Per #3006, use ConcatString instead of std::string for consistency. --- src/basic/vx_config/config_constants.h | 2 ++ src/libcode/vx_statistics/pair_base.cc | 6 ++--- src/libcode/vx_statistics/pair_base.h | 12 +++++----- src/libcode/vx_statistics/pair_data_point.cc | 4 ++-- src/libcode/vx_statistics/pair_data_point.h | 4 ++-- .../core/grid_stat/grid_stat_conf_info.h | 2 +- .../core/pair_stat/pair_stat_conf_info.cc | 23 +++++++++++++++---- .../core/pair_stat/pair_stat_conf_info.h | 6 ++++- .../core/point_stat/point_stat_conf_info.h | 2 +- 9 files changed, 40 insertions(+), 21 deletions(-) diff --git a/src/basic/vx_config/config_constants.h b/src/basic/vx_config/config_constants.h index ee2b379274..686e3dd52b 100644 --- a/src/basic/vx_config/config_constants.h +++ b/src/basic/vx_config/config_constants.h @@ -609,6 +609,8 @@ static const char conf_key_censor_thresh[] = "censor_thresh"; static const char conf_key_censor_val[] = "censor_val"; static const char conf_key_mpr_column[] = "mpr_column"; static const char conf_key_mpr_thresh[] = "mpr_thresh"; +static const char conf_key_mpr_str_inc[] = "mpr_str_inc"; +static const char conf_key_mpr_str_exc[] = "mpr_str_exc"; static const char conf_key_cnt_thresh[] = "cnt_thresh"; static const char conf_key_cnt_logic[] = "cnt_logic"; static const char conf_key_cat_thresh[] = "cat_thresh"; diff --git a/src/libcode/vx_statistics/pair_base.cc b/src/libcode/vx_statistics/pair_base.cc index 4f07b87362..75a8d1a19f 100644 --- a/src/libcode/vx_statistics/pair_base.cc +++ b/src/libcode/vx_statistics/pair_base.cc @@ -1436,7 +1436,7 @@ void VxPairBase::set_interp(int i_interp, //////////////////////////////////////////////////////////////////////// -void VxPairBase::set_mpr_thr_inc_map(const map &m) { +void VxPairBase::set_mpr_thr_inc_map(const map &m) { mpr_thr_inc_map = m; @@ -1445,7 +1445,7 @@ void VxPairBase::set_mpr_thr_inc_map(const map &m) { //////////////////////////////////////////////////////////////////////// -void VxPairBase::set_mpr_str_inc_map(const map &m) { +void VxPairBase::set_mpr_str_inc_map(const map &m) { mpr_str_inc_map = m; @@ -1454,7 +1454,7 @@ void VxPairBase::set_mpr_str_inc_map(const map &m) { //////////////////////////////////////////////////////////////////////// -void VxPairBase::set_mpr_str_exc_map(const map &m) { +void VxPairBase::set_mpr_str_exc_map(const map &m) { mpr_str_exc_map = m; diff --git a/src/libcode/vx_statistics/pair_base.h b/src/libcode/vx_statistics/pair_base.h index 4da5c29a51..62e5ec5c03 100644 --- a/src/libcode/vx_statistics/pair_base.h +++ b/src/libcode/vx_statistics/pair_base.h @@ -288,12 +288,12 @@ class VxPairBase { // Mapping of numeric MPR columns or diffs of colums to // inclusion thresholds - std::map mpr_thr_inc_map; + std::map mpr_thr_inc_map; // Mapping of string MPR columns to list of inclusion // and exclusion strings - std::map mpr_str_inc_map; - std::map mpr_str_exc_map; + std::map mpr_str_inc_map; + std::map mpr_str_exc_map; ////////////////////////////////////////////////////////////////// @@ -385,9 +385,9 @@ class VxPairBase { void set_interp(int i_interp, InterpMthd mthd, int width, GridTemplateFactory::GridTemplates shape); - void set_mpr_thr_inc_map(const std::map &); - void set_mpr_str_inc_map(const std::map &); - void set_mpr_str_exc_map(const std::map &); + void set_mpr_thr_inc_map(const std::map &); + void set_mpr_str_inc_map(const std::map &); + void set_mpr_str_exc_map(const std::map &); void set_climo_cdf_info_ptr(const ClimoCDFInfo *); diff --git a/src/libcode/vx_statistics/pair_data_point.cc b/src/libcode/vx_statistics/pair_data_point.cc index d34b65798f..b3144c768e 100644 --- a/src/libcode/vx_statistics/pair_data_point.cc +++ b/src/libcode/vx_statistics/pair_data_point.cc @@ -742,7 +742,7 @@ bool check_fo_thresh(double f, double o, const ClimoPntInfo &cpi, //////////////////////////////////////////////////////////////////////// bool check_mpr_thresh(double f, double o, const ClimoPntInfo &cpi, - const map &m, + const map &m, ConcatString *reason_ptr) { // Initialize if(reason_ptr) reason_ptr->erase(); @@ -846,7 +846,7 @@ double get_mpr_column_value(double f, double o, const ClimoPntInfo &cpi, void apply_mpr_thresh_mask(DataPlane &fcst_dp, DataPlane &obs_dp, DataPlane &fcmn_dp, DataPlane &fcsd_dp, DataPlane &ocmn_dp, DataPlane &ocsd_dp, - const map &m) { + const map &m) { // Check for no work to be done if(m.size() == 0) return; diff --git a/src/libcode/vx_statistics/pair_data_point.h b/src/libcode/vx_statistics/pair_data_point.h index 57084675d1..aa0e135204 100644 --- a/src/libcode/vx_statistics/pair_data_point.h +++ b/src/libcode/vx_statistics/pair_data_point.h @@ -141,7 +141,7 @@ extern bool check_fo_thresh(double, double, const ClimoPntInfo &, const SetLogic); extern bool check_mpr_thresh(double, double, const ClimoPntInfo &, - const std::map &, + const std::map &, ConcatString * = 0); extern double get_mpr_column_value(double, double, const ClimoPntInfo &, @@ -150,7 +150,7 @@ extern double get_mpr_column_value(double, double, const ClimoPntInfo &, extern void apply_mpr_thresh_mask(DataPlane &, DataPlane &, DataPlane &, DataPlane &, DataPlane &, DataPlane &, - const std::map &); + const std::map &); extern bool check_seeps_thresh(double, double, const StringArray &, const ThreshArray &, diff --git a/src/tools/core/grid_stat/grid_stat_conf_info.h b/src/tools/core/grid_stat/grid_stat_conf_info.h index c46eef12a1..8319bbb6dd 100644 --- a/src/tools/core/grid_stat/grid_stat_conf_info.h +++ b/src/tools/core/grid_stat/grid_stat_conf_info.h @@ -150,7 +150,7 @@ class GridStatVxOpt { // nc_pairs_var_str is deprecated // Matched pair inclusion thresholds - std::map mpr_thr_inc_map; + std::map mpr_thr_inc_map; ThreshArray fcat_ta; // fcst categorical thresholds ThreshArray ocat_ta; // obs categorical thresholds diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.cc b/src/tools/core/pair_stat/pair_stat_conf_info.cc index 0d093dac66..20819793d8 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.cc +++ b/src/tools/core/pair_stat/pair_stat_conf_info.cc @@ -693,6 +693,8 @@ void PairStatVxOpt::clear() { mask_llpnt.clear(); mpr_thr_inc_map.clear(); + mpr_str_inc_map.clear(); + mpr_str_exc_map.clear(); mask_name.clear(); @@ -763,6 +765,7 @@ void PairStatVxOpt::process_config(PairsFormat ftype, VarInfoFactory info_factory; mapoutput_map; Dictionary *dict; + const char *method_name = "PairStatVxOpt::process_config() -> "; // Initialize clear(); @@ -788,14 +791,14 @@ void PairStatVxOpt::process_config(PairsFormat ftype, // No support for wind direction if(vx_pd.fcst_info->is_wind_direction() || vx_pd.obs_info->is_wind_direction()) { - mlog << Error << "\nPairStatVxOpt::process_config() -> " + mlog << Error << "\n" << method_name << "wind direction may not be verified using pair_stat.\n\n"; exit(1); } // Check that the observation field does not contain probabilities if(vx_pd.obs_info->is_prob()) { - mlog << Error << "\nPairStatVxOpt::process_config() -> " + mlog << Error << "\n" << method_name << "the observation field cannot contain probabilities.\n\n"; exit(1); } @@ -842,7 +845,7 @@ void PairStatVxOpt::process_config(PairsFormat ftype, // Check for the same length if(mpr_sa.n() != mpr_ta.n()) { - mlog << Error << "\nPairStatVxOpt::process_config() -> " + mlog << Error << "\n" << method_name << "The length of \"" << conf_key_mpr_column << "\" and \"" << conf_key_mpr_thresh << "\" must match (" << mpr_sa.n() << " != " << mpr_ta.n() << ")!\n\n"; @@ -858,6 +861,14 @@ void PairStatVxOpt::process_config(PairsFormat ftype, mpr_thr_inc_map[(mpr_sa[i])].add(mpr_ta[i]); } + // Conf: mpr_str_inc + parse_add_conf_key_values_map(&odict, conf_key_mpr_str_inc, + &mpr_str_inc_map, method_name); + + // Conf: mpr_str_exc + parse_add_conf_key_values_map(&odict, conf_key_mpr_str_exc, + &mpr_str_exc_map, method_name); + // Dump the contents of the current thresholds if(mlog.verbosity_level() >= 5) { mlog << Debug(5) @@ -883,7 +894,7 @@ void PairStatVxOpt::process_config(PairsFormat ftype, if(!vx_pd.fcst_info->is_prob() && fcat_ta.n() != ocat_ta.n()) { - mlog << Error << "\nPairStatVxOpt::process_config() -> " + mlog << Error << "\n" << method_name << "The number of thresholds for each field in \"fcst." << conf_key_cat_thresh << "\" must match the number of thresholds for each " @@ -986,8 +997,10 @@ void PairStatVxOpt::set_vx_pd(PairStatConfInfo *conf_info) { // Define the dimensions with n_msg_typ = n_interp = 1 vx_pd.set_size(1, n_mask, 1); - // Store the MPR filtering thresholds + // Store the MPR filtering maps vx_pd.set_mpr_thr_inc_map(mpr_thr_inc_map); + vx_pd.set_mpr_str_inc_map(mpr_str_inc_map); + vx_pd.set_mpr_str_exc_map(mpr_str_exc_map); // Store the climo CDF info vx_pd.set_climo_cdf_info_ptr(&cdf_info); diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.h b/src/tools/core/pair_stat/pair_stat_conf_info.h index dd5dd72da4..e35538d8fd 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.h +++ b/src/tools/core/pair_stat/pair_stat_conf_info.h @@ -143,7 +143,11 @@ class PairStatVxOpt { StringArray mask_sid; // Masking station ID's // Matched pair inclusion thresholds - std::map mpr_thr_inc_map; + std::map mpr_thr_inc_map; + + // Matched pair inclusion and exclusion strings + std::map mpr_str_inc_map; + std::map mpr_str_exc_map; // Vector of MaskLatLon objects defining Lat/Lon Point masks std::vector mask_llpnt; diff --git a/src/tools/core/point_stat/point_stat_conf_info.h b/src/tools/core/point_stat/point_stat_conf_info.h index 3660cb78d8..732a3fd4ec 100644 --- a/src/tools/core/point_stat/point_stat_conf_info.h +++ b/src/tools/core/point_stat/point_stat_conf_info.h @@ -130,7 +130,7 @@ class PointStatVxOpt { StringArray mask_sid; // Masking station ID's // Matched pair inclusion thresholds - std::map mpr_thr_inc_map; + std::map mpr_thr_inc_map; // Vector of MaskLatLon objects defining Lat/Lon Point masks std::vector mask_llpnt; From d926506f7d8aeb440c58cb777e1807480787e693 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 27 Dec 2024 22:53:15 +0000 Subject: [PATCH 08/15] Per #3006, work in progress --- src/tools/core/pair_stat/pair_stat.cc | 4 ++-- src/tools/core/pair_stat/pair_stat_conf_info.cc | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/tools/core/pair_stat/pair_stat.cc b/src/tools/core/pair_stat/pair_stat.cc index 508883ef14..e86708c2ff 100644 --- a/src/tools/core/pair_stat/pair_stat.cc +++ b/src/tools/core/pair_stat/pair_stat.cc @@ -219,8 +219,8 @@ void process_command_line(int argc, char **argv) { // List the input pair files mlog << Debug(1) - << "Reading " << pairs_files.n() << " " - << pairsformat_to_string(pairs_format) << " Pairs File(s): " + << "Reading " << pairs_files.n() << " \"" + << pairsformat_to_string(pairs_format) << "\" format pairs file(s): " << write_css(pairs_files) << "\n"; // Set the model name diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.cc b/src/tools/core/pair_stat/pair_stat_conf_info.cc index 20819793d8..184a462331 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.cc +++ b/src/tools/core/pair_stat/pair_stat_conf_info.cc @@ -959,18 +959,6 @@ void PairStatVxOpt::process_config(PairsFormat ftype, // Conf: desc vx_pd.set_desc(parse_conf_string(&odict, conf_key_desc, false).c_str()); - // Conf: sid_inc - vx_pd.set_sid_inc_filt(parse_conf_sid_list(&odict, conf_key_sid_inc)); - - // Conf: sid_exc - vx_pd.set_sid_exc_filt(parse_conf_sid_list(&odict, conf_key_sid_exc)); - - // Conf: obs_qty_inc - vx_pd.set_obs_qty_inc_filt(parse_conf_obs_qty_inc(&odict)); - - // Conf: obs_qty_exc - vx_pd.set_obs_qty_exc_filt(parse_conf_obs_qty_exc(&odict)); - return; } From 909401e4044cfaf9557218b124f989be9b9005f6 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Mon, 30 Dec 2024 17:23:41 +0000 Subject: [PATCH 09/15] Unrelated to #3006, but fix typo in log message. --- src/tools/core/stat_analysis/aggr_stat_line.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/core/stat_analysis/aggr_stat_line.cc b/src/tools/core/stat_analysis/aggr_stat_line.cc index 98df91caad..83152bd678 100644 --- a/src/tools/core/stat_analysis/aggr_stat_line.cc +++ b/src/tools/core/stat_analysis/aggr_stat_line.cc @@ -2173,7 +2173,7 @@ void aggr_mpr_lines(LineDataFile &f, STATAnalysisJob &job, // if(m[key].fcst_var != cur.fcst_var || m[key].obs_var != cur.obs_var) { - mlog << Error << "\nread_mpr_lines() -> " + mlog << Error << "\naggr_mpr_lines() -> " << "both the forecast and observation variable types must " << "remain constant. Try setting \"-fcst_var\" and/or " << "\"-obs_var\".\n" From f3b577a6ddb0676e249930a575dfb93bc8dfd18b Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 31 Dec 2024 17:14:51 +0000 Subject: [PATCH 10/15] Per #3006, default_column_union was defined in 2 spots. Renaming one of them to avoid compilation conflict. --- src/tools/tc_utils/tc_stat/tc_stat_job.cc | 4 ++-- src/tools/tc_utils/tc_stat/tc_stat_job.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools/tc_utils/tc_stat/tc_stat_job.cc b/src/tools/tc_utils/tc_stat/tc_stat_job.cc index eb908b928f..4017a04468 100644 --- a/src/tools/tc_utils/tc_stat/tc_stat_job.cc +++ b/src/tools/tc_utils/tc_stat/tc_stat_job.cc @@ -2015,7 +2015,7 @@ void TCStatJobSummary::clear() { SummaryMap.clear(); // Set to default value - ColumnUnion = default_column_union; + ColumnUnion = default_tc_column_union; OutAlpha = default_tc_alpha; FSPThresh = default_fsp_thresh; @@ -2125,7 +2125,7 @@ ConcatString TCStatJobSummary::serialize() const { // Add summary job-specific options for(i=0; i Date: Tue, 31 Dec 2024 17:19:37 +0000 Subject: [PATCH 11/15] Per #3006, move StatHdrInfo out of aggr_stat_line.h/.cc and into vx_stat_out/stat_hdr_info.h/.cc. This make it available to both Stat-Analysis and the Pair-Stat tool to track the unique STAT headers elements read. --- src/libcode/vx_stat_out/Makefile.am | 1 + src/libcode/vx_stat_out/Makefile.in | 24 +- src/libcode/vx_stat_out/stat_hdr_info.cc | 453 ++++++++++++++++++ src/libcode/vx_stat_out/stat_hdr_info.h | 54 +++ src/libcode/vx_stat_out/vx_stat_out.h | 1 + .../core/stat_analysis/aggr_stat_line.cc | 425 ---------------- src/tools/core/stat_analysis/aggr_stat_line.h | 26 - 7 files changed, 531 insertions(+), 453 deletions(-) create mode 100644 src/libcode/vx_stat_out/stat_hdr_info.cc create mode 100644 src/libcode/vx_stat_out/stat_hdr_info.h diff --git a/src/libcode/vx_stat_out/Makefile.am b/src/libcode/vx_stat_out/Makefile.am index 219ba60ddf..83473eaa97 100644 --- a/src/libcode/vx_stat_out/Makefile.am +++ b/src/libcode/vx_stat_out/Makefile.am @@ -14,5 +14,6 @@ noinst_LIBRARIES = libvx_stat_out.a libvx_stat_out_a_SOURCES = \ stat_columns.cc stat_columns.h \ stat_hdr_columns.cc stat_hdr_columns.h \ + stat_hdr_info.cc stat_hdr_info.h \ vx_stat_out.h libvx_stat_out_a_CPPFLAGS = ${MET_CPPFLAGS} diff --git a/src/libcode/vx_stat_out/Makefile.in b/src/libcode/vx_stat_out/Makefile.in index 77d31a4ea1..117c6ff9bc 100644 --- a/src/libcode/vx_stat_out/Makefile.in +++ b/src/libcode/vx_stat_out/Makefile.in @@ -108,7 +108,8 @@ am__v_AR_1 = libvx_stat_out_a_AR = $(AR) $(ARFLAGS) libvx_stat_out_a_LIBADD = am_libvx_stat_out_a_OBJECTS = libvx_stat_out_a-stat_columns.$(OBJEXT) \ - libvx_stat_out_a-stat_hdr_columns.$(OBJEXT) + libvx_stat_out_a-stat_hdr_columns.$(OBJEXT) \ + libvx_stat_out_a-stat_hdr_info.$(OBJEXT) libvx_stat_out_a_OBJECTS = $(am_libvx_stat_out_a_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) @@ -126,7 +127,8 @@ DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/libvx_stat_out_a-stat_columns.Po \ - ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_columns.Po + ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_columns.Po \ + ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Po am__mv = mv -f AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -349,6 +351,7 @@ noinst_LIBRARIES = libvx_stat_out.a libvx_stat_out_a_SOURCES = \ stat_columns.cc stat_columns.h \ stat_hdr_columns.cc stat_hdr_columns.h \ + stat_hdr_info.cc stat_hdr_info.h \ vx_stat_out.h libvx_stat_out_a_CPPFLAGS = ${MET_CPPFLAGS} @@ -402,6 +405,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_stat_out_a-stat_columns.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_stat_out_a-stat_hdr_columns.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @@ -451,6 +455,20 @@ libvx_stat_out_a-stat_hdr_columns.obj: stat_hdr_columns.cc @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_stat_out_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libvx_stat_out_a-stat_hdr_columns.obj `if test -f 'stat_hdr_columns.cc'; then $(CYGPATH_W) 'stat_hdr_columns.cc'; else $(CYGPATH_W) '$(srcdir)/stat_hdr_columns.cc'; fi` +libvx_stat_out_a-stat_hdr_info.o: stat_hdr_info.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_stat_out_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libvx_stat_out_a-stat_hdr_info.o -MD -MP -MF $(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Tpo -c -o libvx_stat_out_a-stat_hdr_info.o `test -f 'stat_hdr_info.cc' || echo '$(srcdir)/'`stat_hdr_info.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Tpo $(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stat_hdr_info.cc' object='libvx_stat_out_a-stat_hdr_info.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_stat_out_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libvx_stat_out_a-stat_hdr_info.o `test -f 'stat_hdr_info.cc' || echo '$(srcdir)/'`stat_hdr_info.cc + +libvx_stat_out_a-stat_hdr_info.obj: stat_hdr_info.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_stat_out_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libvx_stat_out_a-stat_hdr_info.obj -MD -MP -MF $(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Tpo -c -o libvx_stat_out_a-stat_hdr_info.obj `if test -f 'stat_hdr_info.cc'; then $(CYGPATH_W) 'stat_hdr_info.cc'; else $(CYGPATH_W) '$(srcdir)/stat_hdr_info.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Tpo $(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='stat_hdr_info.cc' object='libvx_stat_out_a-stat_hdr_info.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libvx_stat_out_a_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libvx_stat_out_a-stat_hdr_info.obj `if test -f 'stat_hdr_info.cc'; then $(CYGPATH_W) 'stat_hdr_info.cc'; else $(CYGPATH_W) '$(srcdir)/stat_hdr_info.cc'; fi` + ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am @@ -577,6 +595,7 @@ clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/libvx_stat_out_a-stat_columns.Po -rm -f ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_columns.Po + -rm -f ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -624,6 +643,7 @@ installcheck-am: maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libvx_stat_out_a-stat_columns.Po -rm -f ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_columns.Po + -rm -f ./$(DEPDIR)/libvx_stat_out_a-stat_hdr_info.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/src/libcode/vx_stat_out/stat_hdr_info.cc b/src/libcode/vx_stat_out/stat_hdr_info.cc new file mode 100644 index 0000000000..19187b5534 --- /dev/null +++ b/src/libcode/vx_stat_out/stat_hdr_info.cc @@ -0,0 +1,453 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2024 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +//////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include "vx_log.h" + +#include "stat_hdr_info.h" + +using namespace std; + +//////////////////////////////////////////////////////////////////////// + +static const string case_str = "CASE"; + +//////////////////////////////////////////////////////////////////////// +// +// Code for StatHdrInfo structure. +// +//////////////////////////////////////////////////////////////////////// + +StatHdrInfo::StatHdrInfo() { + clear(); +} + +//////////////////////////////////////////////////////////////////////// + +void StatHdrInfo::clear() { + model.clear(); + desc.clear(); + fcst_lead.clear(); + fcst_valid_beg = fcst_valid_end = (unixtime) 0; + obs_lead.clear(); + obs_valid_beg = obs_valid_end = (unixtime) 0; + fcst_var.clear(); + fcst_units.clear(); + fcst_lev.clear(); + obs_var.clear(); + obs_units.clear(); + obs_lev.clear(); + obtype.clear(); + vx_mask.clear(); + interp_mthd.clear(); + interp_pnts.clear(); + fcst_thresh.clear(); + obs_thresh.clear(); + cov_thresh.clear(); + alpha.clear(); + + return; +} + +//////////////////////////////////////////////////////////////////////// +// +// Keep track the unique STAT header entries for each line. +// +//////////////////////////////////////////////////////////////////////// + +void StatHdrInfo::add(const STATLine &line) { + ConcatString cs; + if(!model.has(line.model())) + model.add(line.model()); + if(!desc.has(line.desc())) + desc.add(line.desc()); + if(!fcst_lead.has(line.fcst_lead())) + fcst_lead.add(line.fcst_lead()); + if(fcst_valid_beg == (unixtime) 0 || line.fcst_valid_beg() < fcst_valid_beg) + fcst_valid_beg = line.fcst_valid_beg(); + if(fcst_valid_end == (unixtime) 0 || line.fcst_valid_end() > fcst_valid_end) + fcst_valid_end = line.fcst_valid_end(); + if(!obs_lead.has(line.obs_lead())) + obs_lead.add(line.obs_lead()); + if(obs_valid_beg == (unixtime) 0 || line.obs_valid_beg() < obs_valid_beg) + obs_valid_beg = line.obs_valid_beg(); + if(obs_valid_end == (unixtime) 0 || line.obs_valid_end() > obs_valid_end) + obs_valid_end = line.obs_valid_end(); + if(!fcst_var.has(line.fcst_var())) + fcst_var.add(line.fcst_var()); + if(!fcst_units.has(line.fcst_units())) + fcst_units.add(line.fcst_units()); + if(!fcst_lev.has(line.fcst_lev())) + fcst_lev.add(line.fcst_lev()); + if(!obs_var.has(line.obs_var())) + obs_var.add(line.obs_var()); + if(!obs_units.has(line.obs_units())) + obs_units.add(line.obs_units()); + if(!obs_lev.has(line.obs_lev())) + obs_lev.add(line.obs_lev()); + if(!obtype.has(line.obtype())) + obtype.add(line.obtype()); + if(!vx_mask.has(line.vx_mask())) + vx_mask.add(line.vx_mask()); + if(!interp_mthd.has(line.interp_mthd())) + interp_mthd.add(line.interp_mthd()); + if(!interp_pnts.has(line.interp_pnts())) + interp_pnts.add(line.interp_pnts()); + cs = line.get_item("FCST_THRESH", false); + cs.strip_paren(); + if(!fcst_thresh.has(cs)) fcst_thresh.add(cs); + cs = line.get_item("OBS_THRESH", false); + cs.strip_paren(); + if(!obs_thresh.has(cs)) obs_thresh.add(cs); + cs = line.get_item("COV_THRESH", false); + cs.strip_paren(); + if(!cov_thresh.has(cs)) cov_thresh.add(cs); + if(!alpha.has(line.alpha())) + alpha.add(line.alpha()); + + return; +} + +//////////////////////////////////////////////////////////////////////// +// +// Check for and print debug and warning messages about multiple header +// column values found. +// +//////////////////////////////////////////////////////////////////////// + +void StatHdrInfo::check_shc(const ConcatString &cur_case) { + + // MODEL + if(model.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << model.n() + << " unique MODEL values: " + << write_css(model) << "\n"; + } + + // DESC + if(desc.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << desc.n() + << " unique DESC values: " + << write_css(desc) << "\n"; + } + + // FCST_LEAD + if(fcst_lead.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << fcst_lead.n() + << " unique FCST_LEAD values: " + << write_css_hhmmss(fcst_lead) << "\n"; + } + + // OBS_LEAD + if(obs_lead.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << obs_lead.n() + << " unique OBS_LEAD values: " + << write_css_hhmmss(obs_lead) << "\n"; + } + + // FCST_VAR + if(fcst_var.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << fcst_var.n() + << " unique FCST_VAR values: " + << write_css(fcst_var) << "\n"; + } + + // FCST_UNITS + if(fcst_units.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << fcst_units.n() + << " unique FCST_UNITS values: " + << write_css(fcst_units) << "\n"; + } + + // FCST_LEV + if(fcst_lev.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << fcst_lev.n() + << " unique FCST_LEV values: " + << write_css(fcst_lev) << "\n"; + } + + // OBS_VAR + if(obs_var.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << obs_var.n() + << " unique OBS_VAR values: " + << write_css(obs_var) << "\n"; + } + + // OBS_UNITS + if(obs_units.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << obs_units.n() + << " unique OBS_UNITS values: " + << write_css(obs_units) << "\n"; + } + + // OBS_LEV + if(obs_lev.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << obs_lev.n() + << " unique OBS_LEV values: " + << write_css(obs_lev) << "\n"; + } + + // OBTYPE + if(obtype.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << obtype.n() + << " unique OBTYPE values: " + << write_css(obtype) << "\n"; + } + + // VX_MASK + if(vx_mask.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << vx_mask.n() + << " unique VX_MASK values: " + << write_css(vx_mask) << "\n"; + } + + // INTERP_MTHD + if(interp_mthd.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << interp_mthd.n() + << " unique INTERP_MTHD values: " + << write_css(interp_mthd) << ".\n"; + } + + // INTERP_PNTS + if(interp_pnts.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << interp_pnts.n() + << " unique INTERP_PNTS values: " + << write_css(interp_pnts) << ".\n"; + } + + // FCST_THRESH + if(fcst_thresh.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << fcst_thresh.n() + << " unique FCST_THRESH values: " + << write_css(fcst_thresh) << "\n"; + } + + // OBS_THRESH + if(obs_thresh.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << obs_thresh.n() + << " unique OBS_THRESH values: " + << write_css(obs_thresh) << "\n"; + } + + // COV_THRESH + if(cov_thresh.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << cov_thresh.n() + << " unique COV_THRESH values: " + << write_css(cov_thresh) << ".\n"; + } + + // ALPHA + if(alpha.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << alpha.n() + << " unique ALPHA values: " + << write_css(alpha) << ".\n"; + } + + return; +} + +//////////////////////////////////////////////////////////////////////// +// +// Use the StatHdrInfo struct to populate a StatHdrColumns object +// +//////////////////////////////////////////////////////////////////////// + +StatHdrColumns StatHdrInfo::get_shc(const ConcatString &cur_case, + const StringArray &case_cols, + const StringArray &hdr_cols, + const StringArray &hdr_vals, + const STATLineType lt) { + ThreshArray ta; + ConcatString css; + double out_alpha; + int wdth; + StatHdrColumns shc; + + // MODEL + shc.set_model(get_col_css(cur_case, "MODEL", model, false).c_str()); + + // DESC + shc.set_desc(get_col_css(cur_case, "DESC", desc, false).c_str()); + + // FCST_LEAD + css = write_css_hhmmss(fcst_lead); + if(fcst_lead.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << fcst_lead.n() + << " unique FCST_LEAD values: " << css << "\n"; + } + shc.set_fcst_lead_sec(fcst_lead.max()); + + // FCST_VALID_BEG, FCST_VALID_END + shc.set_fcst_valid_beg(fcst_valid_beg); + shc.set_fcst_valid_end(fcst_valid_end); + + // OBS_LEAD + css = write_css_hhmmss(obs_lead); + if(obs_lead.n() > 1) { + mlog << Debug(2) + << "For case \"" << cur_case << "\", found " + << obs_lead.n() + << " unique OBS_LEAD values: " << css << "\n"; + } + shc.set_obs_lead_sec(obs_lead.max()); + + // OBS_VALID_BEG, OBS_VALID_END + shc.set_obs_valid_beg(obs_valid_beg); + shc.set_obs_valid_end(obs_valid_end); + + // FCST_VAR + shc.set_fcst_var(get_col_css(cur_case, "FCST_VAR", fcst_var, false)); + + // FCST_UNITS + shc.set_fcst_units(get_col_css(cur_case, "FCST_UNITS", fcst_units, false)); + + // FCST_LEV + shc.set_fcst_lev(get_col_css(cur_case, "FCST_LEV", fcst_lev, false).c_str()); + + // OBS_VAR + shc.set_obs_var(get_col_css(cur_case, "OBS_VAR", obs_var, false)); + + // OBS_UNITS + shc.set_obs_units(get_col_css(cur_case, "OBS_UNITS", obs_units, false)); + + // OBS_LEV + shc.set_obs_lev(get_col_css(cur_case, "OBS_LEV", obs_lev, false).c_str()); + + // OBTYPE + shc.set_obtype(get_col_css(cur_case, "OBTYPE", obtype, false).c_str()); + + // VX_MASK + shc.set_mask(get_col_css(cur_case, "VX_MASK", vx_mask, false).c_str()); + + // INTERP_MTHD + shc.set_interp_mthd(get_col_css(cur_case, "INTERP_MTHD", interp_mthd, true)); + + // INTERP_PNTS + css = write_css(interp_pnts); + if(interp_pnts.n() == 0 || interp_pnts.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << interp_pnts.n() + << " unique INTERP_PNTS values: " << css << ".\n"; + wdth = bad_data_int; + } + else { + wdth = nint(sqrt(interp_pnts[0])); + } + shc.set_interp_wdth(wdth); + + // FCST_THRESH + ta.clear(); + ta.add_css(get_col_css(cur_case, "FCST_THRESH", fcst_thresh, true).c_str()); + shc.set_fcst_thresh(ta); + + // OBS_THRESH + ta.clear(); + ta.add_css(get_col_css(cur_case, "OBS_THRESH", obs_thresh, true).c_str()); + shc.set_obs_thresh(ta); + + // COV_THRESH + ta.clear(); + ta.add_css(get_col_css(cur_case, "COV_THRESH", cov_thresh, true).c_str()); + shc.set_cov_thresh(ta); + + // ALPHA + css = write_css(alpha); + if(alpha.n() == 0 || alpha.n() > 1) { + mlog << Warning + << "For case \"" << cur_case << "\", found " + << alpha.n() + << " unique ALPHA values: " << css << ".\n"; + out_alpha = bad_data_double; + } + else { + out_alpha = alpha[0]; + } + shc.set_alpha(out_alpha); + + // LINE_TYPE + shc.set_line_type(statlinetype_to_string(lt)); + + // Apply the -set_hdr options + StringArray case_vals = cur_case.split(":"); + shc.apply_set_hdr_opts(hdr_cols, hdr_vals, case_cols, case_vals); + + return shc; +} + +//////////////////////////////////////////////////////////////////////// + +ConcatString StatHdrInfo::get_col_css(const ConcatString &cur_case, + const char *col_name, + const StringArray &col_vals, + bool warning) const { + + // Build comma-separated list of column values + ConcatString css(write_css(col_vals)); + + // Check for multiple entries + if(col_vals.n() > 1) { + ConcatString msg; + msg << "For case \"" << cur_case << "\", found " + << col_vals.n() << " unique " << col_name + << " values: " << css << "\n"; + if(warning) mlog << Warning << msg; + else mlog << Debug(2) << msg; + } + + return css; +} + +//////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_stat_out/stat_hdr_info.h b/src/libcode/vx_stat_out/stat_hdr_info.h new file mode 100644 index 0000000000..f2a2e0ffe6 --- /dev/null +++ b/src/libcode/vx_stat_out/stat_hdr_info.h @@ -0,0 +1,54 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2024 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +//////////////////////////////////////////////////////////////////////// + +#ifndef __STAT_HDR_INFO_H__ +#define __STAT_HDR_INFO_H__ + +//////////////////////////////////////////////////////////////////////// + +#include "vx_config.h" +#include "vx_util.h" +#include "vx_analysis_util.h" + +#include "stat_hdr_columns.h" + +//////////////////////////////////////////////////////////////////////// + +struct StatHdrInfo { + StringArray model, desc; + StringArray fcst_var, fcst_units, fcst_lev; + StringArray obs_var, obs_units, obs_lev; + StringArray obtype, vx_mask, interp_mthd; + StringArray fcst_thresh, obs_thresh, cov_thresh; + NumArray fcst_lead, obs_lead, interp_pnts, alpha; + unixtime fcst_valid_beg, fcst_valid_end; + unixtime obs_valid_beg, obs_valid_end; + + StatHdrInfo(); + + void clear(); + void add(const STATLine &line); + void check_shc(const ConcatString &cur_case); + StatHdrColumns get_shc(const ConcatString &cur_case, + const StringArray &case_cols, + const StringArray &hdr_cols, + const StringArray &hdr_vals, + const STATLineType lt); + ConcatString get_col_css(const ConcatString &cur_case, + const char *col_name, + const StringArray &col_vals, + bool warning) const; +}; + +//////////////////////////////////////////////////////////////////////// + +#endif // __STAT_HDR_INFO_H__ + +//////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_stat_out/vx_stat_out.h b/src/libcode/vx_stat_out/vx_stat_out.h index 3c2f669cc4..9746c4d1e4 100644 --- a/src/libcode/vx_stat_out/vx_stat_out.h +++ b/src/libcode/vx_stat_out/vx_stat_out.h @@ -20,6 +20,7 @@ #include "stat_columns.h" #include "stat_hdr_columns.h" +#include "stat_hdr_info.h" //////////////////////////////////////////////////////////////////////// diff --git a/src/tools/core/stat_analysis/aggr_stat_line.cc b/src/tools/core/stat_analysis/aggr_stat_line.cc index 83152bd678..80b3ead850 100644 --- a/src/tools/core/stat_analysis/aggr_stat_line.cc +++ b/src/tools/core/stat_analysis/aggr_stat_line.cc @@ -66,433 +66,8 @@ using namespace std; //////////////////////////////////////////////////////////////////////// static bool is_precip_var_name(const ConcatString &s); -static const string case_str = "CASE"; static bool is_vector_dir_stat(const STATLineType &t, const ConcatString &s); -//////////////////////////////////////////////////////////////////////// -// -// Code for StatHdrInfo structure. -// -//////////////////////////////////////////////////////////////////////// - -StatHdrInfo::StatHdrInfo() { - clear(); -} - -//////////////////////////////////////////////////////////////////////// - -void StatHdrInfo::clear() { - model.clear(); - desc.clear(); - fcst_lead.clear(); - fcst_valid_beg = fcst_valid_end = (unixtime) 0; - obs_lead.clear(); - obs_valid_beg = obs_valid_end = (unixtime) 0; - fcst_var.clear(); - fcst_units.clear(); - fcst_lev.clear(); - obs_var.clear(); - obs_units.clear(); - obs_lev.clear(); - obtype.clear(); - vx_mask.clear(); - interp_mthd.clear(); - interp_pnts.clear(); - fcst_thresh.clear(); - obs_thresh.clear(); - cov_thresh.clear(); - alpha.clear(); - - return; -} - -//////////////////////////////////////////////////////////////////////// -// -// Keep track the unique STAT header entries for each line. -// -//////////////////////////////////////////////////////////////////////// - -void StatHdrInfo::add(const STATLine &line) { - ConcatString cs; - if(!model.has(line.model())) - model.add(line.model()); - if(!desc.has(line.desc())) - desc.add(line.desc()); - if(!fcst_lead.has(line.fcst_lead())) - fcst_lead.add(line.fcst_lead()); - if(fcst_valid_beg == (unixtime) 0 || line.fcst_valid_beg() < fcst_valid_beg) - fcst_valid_beg = line.fcst_valid_beg(); - if(fcst_valid_end == (unixtime) 0 || line.fcst_valid_end() > fcst_valid_end) - fcst_valid_end = line.fcst_valid_end(); - if(!obs_lead.has(line.obs_lead())) - obs_lead.add(line.obs_lead()); - if(obs_valid_beg == (unixtime) 0 || line.obs_valid_beg() < obs_valid_beg) - obs_valid_beg = line.obs_valid_beg(); - if(obs_valid_end == (unixtime) 0 || line.obs_valid_end() > obs_valid_end) - obs_valid_end = line.obs_valid_end(); - if(!fcst_var.has(line.fcst_var())) - fcst_var.add(line.fcst_var()); - if(!fcst_units.has(line.fcst_units())) - fcst_units.add(line.fcst_units()); - if(!fcst_lev.has(line.fcst_lev())) - fcst_lev.add(line.fcst_lev()); - if(!obs_var.has(line.obs_var())) - obs_var.add(line.obs_var()); - if(!obs_units.has(line.obs_units())) - obs_units.add(line.obs_units()); - if(!obs_lev.has(line.obs_lev())) - obs_lev.add(line.obs_lev()); - if(!obtype.has(line.obtype())) - obtype.add(line.obtype()); - if(!vx_mask.has(line.vx_mask())) - vx_mask.add(line.vx_mask()); - if(!interp_mthd.has(line.interp_mthd())) - interp_mthd.add(line.interp_mthd()); - if(!interp_pnts.has(line.interp_pnts())) - interp_pnts.add(line.interp_pnts()); - cs = line.get_item("FCST_THRESH", false); - cs.strip_paren(); - if(!fcst_thresh.has(cs)) fcst_thresh.add(cs); - cs = line.get_item("OBS_THRESH", false); - cs.strip_paren(); - if(!obs_thresh.has(cs)) obs_thresh.add(cs); - cs = line.get_item("COV_THRESH", false); - cs.strip_paren(); - if(!cov_thresh.has(cs)) cov_thresh.add(cs); - if(!alpha.has(line.alpha())) - alpha.add(line.alpha()); - - return; -} - -//////////////////////////////////////////////////////////////////////// -// -// Check for and print debug and warning messages about multiple header -// column values found. -// -//////////////////////////////////////////////////////////////////////// - -void StatHdrInfo::check_shc(const ConcatString &cur_case) { - - // MODEL - if(model.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << model.n() - << " unique MODEL values: " - << write_css(model) << "\n"; - } - - // DESC - if(desc.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << desc.n() - << " unique DESC values: " - << write_css(desc) << "\n"; - } - - // FCST_LEAD - if(fcst_lead.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << fcst_lead.n() - << " unique FCST_LEAD values: " - << write_css_hhmmss(fcst_lead) << "\n"; - } - - // OBS_LEAD - if(obs_lead.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << obs_lead.n() - << " unique OBS_LEAD values: " - << write_css_hhmmss(obs_lead) << "\n"; - } - - // FCST_VAR - if(fcst_var.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << fcst_var.n() - << " unique FCST_VAR values: " - << write_css(fcst_var) << "\n"; - } - - // FCST_UNITS - if(fcst_units.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << fcst_units.n() - << " unique FCST_UNITS values: " - << write_css(fcst_units) << "\n"; - } - - // FCST_LEV - if(fcst_lev.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << fcst_lev.n() - << " unique FCST_LEV values: " - << write_css(fcst_lev) << "\n"; - } - - // OBS_VAR - if(obs_var.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << obs_var.n() - << " unique OBS_VAR values: " - << write_css(obs_var) << "\n"; - } - - // OBS_UNITS - if(obs_units.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << obs_units.n() - << " unique OBS_UNITS values: " - << write_css(obs_units) << "\n"; - } - - // OBS_LEV - if(obs_lev.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << obs_lev.n() - << " unique OBS_LEV values: " - << write_css(obs_lev) << "\n"; - } - - // OBTYPE - if(obtype.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << obtype.n() - << " unique OBTYPE values: " - << write_css(obtype) << "\n"; - } - - // VX_MASK - if(vx_mask.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << vx_mask.n() - << " unique VX_MASK values: " - << write_css(vx_mask) << "\n"; - } - - // INTERP_MTHD - if(interp_mthd.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << interp_mthd.n() - << " unique INTERP_MTHD values: " - << write_css(interp_mthd) << ".\n"; - } - - // INTERP_PNTS - if(interp_pnts.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << interp_pnts.n() - << " unique INTERP_PNTS values: " - << write_css(interp_pnts) << ".\n"; - } - - // FCST_THRESH - if(fcst_thresh.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << fcst_thresh.n() - << " unique FCST_THRESH values: " - << write_css(fcst_thresh) << "\n"; - } - - // OBS_THRESH - if(obs_thresh.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << obs_thresh.n() - << " unique OBS_THRESH values: " - << write_css(obs_thresh) << "\n"; - } - - // COV_THRESH - if(cov_thresh.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << cov_thresh.n() - << " unique COV_THRESH values: " - << write_css(cov_thresh) << ".\n"; - } - - // ALPHA - if(alpha.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << alpha.n() - << " unique ALPHA values: " - << write_css(alpha) << ".\n"; - } - - return; -} - -//////////////////////////////////////////////////////////////////////// -// -// Use the StatHdrInfo struct to populate a StatHdrColumns object -// -//////////////////////////////////////////////////////////////////////// - -StatHdrColumns StatHdrInfo::get_shc(const ConcatString &cur_case, - const StringArray &case_cols, - const StringArray &hdr_cols, - const StringArray &hdr_vals, - const STATLineType lt) { - ThreshArray ta; - ConcatString css; - double out_alpha; - int wdth; - StatHdrColumns shc; - - // MODEL - shc.set_model(get_col_css(cur_case, "MODEL", model, false).c_str()); - - // DESC - shc.set_desc(get_col_css(cur_case, "DESC", desc, false).c_str()); - - // FCST_LEAD - css = write_css_hhmmss(fcst_lead); - if(fcst_lead.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << fcst_lead.n() - << " unique FCST_LEAD values: " << css << "\n"; - } - shc.set_fcst_lead_sec(fcst_lead.max()); - - // FCST_VALID_BEG, FCST_VALID_END - shc.set_fcst_valid_beg(fcst_valid_beg); - shc.set_fcst_valid_end(fcst_valid_end); - - // OBS_LEAD - css = write_css_hhmmss(obs_lead); - if(obs_lead.n() > 1) { - mlog << Debug(2) - << "For case \"" << cur_case << "\", found " - << obs_lead.n() - << " unique OBS_LEAD values: " << css << "\n"; - } - shc.set_obs_lead_sec(obs_lead.max()); - - // OBS_VALID_BEG, OBS_VALID_END - shc.set_obs_valid_beg(obs_valid_beg); - shc.set_obs_valid_end(obs_valid_end); - - // FCST_VAR - shc.set_fcst_var(get_col_css(cur_case, "FCST_VAR", fcst_var, false)); - - // FCST_UNITS - shc.set_fcst_units(get_col_css(cur_case, "FCST_UNITS", fcst_units, false)); - - // FCST_LEV - shc.set_fcst_lev(get_col_css(cur_case, "FCST_LEV", fcst_lev, false).c_str()); - - // OBS_VAR - shc.set_obs_var(get_col_css(cur_case, "OBS_VAR", obs_var, false)); - - // OBS_UNITS - shc.set_obs_units(get_col_css(cur_case, "OBS_UNITS", obs_units, false)); - - // OBS_LEV - shc.set_obs_lev(get_col_css(cur_case, "OBS_LEV", obs_lev, false).c_str()); - - // OBTYPE - shc.set_obtype(get_col_css(cur_case, "OBTYPE", obtype, false).c_str()); - - // VX_MASK - shc.set_mask(get_col_css(cur_case, "VX_MASK", vx_mask, false).c_str()); - - // INTERP_MTHD - shc.set_interp_mthd(get_col_css(cur_case, "INTERP_MTHD", interp_mthd, true)); - - // INTERP_PNTS - css = write_css(interp_pnts); - if(interp_pnts.n() == 0 || interp_pnts.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << interp_pnts.n() - << " unique INTERP_PNTS values: " << css << ".\n"; - wdth = bad_data_int; - } - else { - wdth = nint(sqrt(interp_pnts[0])); - } - shc.set_interp_wdth(wdth); - - // FCST_THRESH - ta.clear(); - ta.add_css(get_col_css(cur_case, "FCST_THRESH", fcst_thresh, true).c_str()); - shc.set_fcst_thresh(ta); - - // OBS_THRESH - ta.clear(); - ta.add_css(get_col_css(cur_case, "OBS_THRESH", obs_thresh, true).c_str()); - shc.set_obs_thresh(ta); - - // COV_THRESH - ta.clear(); - ta.add_css(get_col_css(cur_case, "COV_THRESH", cov_thresh, true).c_str()); - shc.set_cov_thresh(ta); - - // ALPHA - css = write_css(alpha); - if(alpha.n() == 0 || alpha.n() > 1) { - mlog << Warning - << "For case \"" << cur_case << "\", found " - << alpha.n() - << " unique ALPHA values: " << css << ".\n"; - out_alpha = bad_data_double; - } - else { - out_alpha = alpha[0]; - } - shc.set_alpha(out_alpha); - - // LINE_TYPE - shc.set_line_type(statlinetype_to_string(lt)); - - // Apply the -set_hdr options - StringArray case_vals = cur_case.split(":"); - shc.apply_set_hdr_opts(hdr_cols, hdr_vals, case_cols, case_vals); - - return shc; -} - -//////////////////////////////////////////////////////////////////////// - -ConcatString StatHdrInfo::get_col_css(const ConcatString &cur_case, - const char *col_name, - const StringArray &col_vals, - bool warning) const { - - // Build comma-separated list of column values - ConcatString css(write_css(col_vals)); - - // Check for multiple entries - if(col_vals.n() > 1) { - ConcatString msg; - msg << "For case \"" << cur_case << "\", found " - << col_vals.n() << " unique " << col_name - << " values: " << css << "\n"; - if(warning) mlog << Warning << msg; - else mlog << Debug(2) << msg; - } - - return css; -} - //////////////////////////////////////////////////////////////////////// // // Code for AggrENSInfo structure diff --git a/src/tools/core/stat_analysis/aggr_stat_line.h b/src/tools/core/stat_analysis/aggr_stat_line.h index d0ec0d9c7b..ab82d17e69 100644 --- a/src/tools/core/stat_analysis/aggr_stat_line.h +++ b/src/tools/core/stat_analysis/aggr_stat_line.h @@ -60,32 +60,6 @@ static const int min_time_series = 10; //////////////////////////////////////////////////////////////////////// -struct StatHdrInfo { - StringArray model, desc; - StringArray fcst_var, fcst_units, fcst_lev; - StringArray obs_var, obs_units, obs_lev; - StringArray obtype, vx_mask, interp_mthd; - StringArray fcst_thresh, obs_thresh, cov_thresh; - NumArray fcst_lead, obs_lead, interp_pnts, alpha; - unixtime fcst_valid_beg, fcst_valid_end; - unixtime obs_valid_beg, obs_valid_end; - - StatHdrInfo(); - - void clear(); - void add(const STATLine &line); - void check_shc(const ConcatString &cur_case); - StatHdrColumns get_shc(const ConcatString &cur_case, - const StringArray &case_cols, - const StringArray &hdr_cols, - const StringArray &hdr_vals, - const STATLineType lt); - ConcatString get_col_css(const ConcatString &cur_case, - const char *col_name, - const StringArray &col_vals, - bool warning) const; -}; - struct AggrSummaryInfo { StatHdrInfo hdr; std::map val; From 7a5415a2edf870cbc39796c7dd0e04b59cb31079 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 31 Dec 2024 17:22:47 +0000 Subject: [PATCH 12/15] Per #3006, remove the unused land/topo/msg_type type config options from the pair_stat tool's configuration file and code that parses it. If needed, we can add it back in the future. --- data/config/PairStatConfig_default | 48 ---- .../core/pair_stat/pair_stat_conf_info.cc | 270 +++++++----------- .../core/pair_stat/pair_stat_conf_info.h | 25 +- 3 files changed, 113 insertions(+), 230 deletions(-) diff --git a/data/config/PairStatConfig_default b/data/config/PairStatConfig_default index 2e165335f0..c56cfe470a 100644 --- a/data/config/PairStatConfig_default +++ b/data/config/PairStatConfig_default @@ -44,20 +44,6 @@ obs = { //////////////////////////////////////////////////////////////////////////////// -// -// Mapping of message type group name to comma-separated list of values -// -message_type_group_map = [ - { key = "SURFACE"; val = "ADPSFC,SFCSHP,MSONET"; }, - { key = "ANYAIR"; val = "AIRCAR,AIRCFT"; }, - { key = "ANYSFC"; val = "ADPSFC,SFCSHP,ADPUPA,PROFLR,MSONET"; }, - { key = "ONLYSF"; val = "ADPSFC,SFCSHP"; }, - { key = "LANDSF"; val = "ADPSFC,MSONET"; }, - { key = "WATERSF"; val = "SFCSHP"; } -]; - -//////////////////////////////////////////////////////////////////////////////// - // // Forecast and observation data censoring, thresholding, and filtering options // May be set separately in each "fcst.pairs" or "obs.pairs" entry @@ -123,40 +109,6 @@ climo_cdf = { //////////////////////////////////////////////////////////////////////////////// -// -// Land/Sea mask -// For LANDSF message types, only use forecast grid points where land = TRUE. -// For WATERSF message types, only use forecast grid points where land = FALSE. -// land_mask.flag may be set separately in each "obs.pairs" entry. -// -land_mask = { - flag = FALSE; - file_name = []; - field = { name = "LAND"; level = "L0"; } - regrid = { method = NEAREST; width = 1; } - thresh = eq1; -} - -// -// Topography -// For SURFACE message types, only use observations where the topo - station -// elevation difference meets the use_obs_thresh threshold. -// For the observations kept, when interpolating forecast data to the -// observation location, only use forecast grid points where the topo - station -// difference meets the interp_fcst_thresh threshold. -// topo_mask.flag may be set separately in each "obs.pairs" entry. -// -topo_mask = { - flag = FALSE; - file_name = []; - field = { name = "TOPO"; level = "L0"; } - regrid = { method = BILIN; width = 2; } - use_obs_thresh = ge-100&&le100; - interp_fcst_thresh = ge-50&&le50; -} - -//////////////////////////////////////////////////////////////////////////////// - // // Point observation time window // May be set separately in each "obs.pairs" entry diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.cc b/src/tools/core/pair_stat/pair_stat_conf_info.cc index 184a462331..c3877c215a 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.cc +++ b/src/tools/core/pair_stat/pair_stat_conf_info.cc @@ -91,11 +91,6 @@ void PairStatConfInfo::clear() { // Initialize values model.clear(); vx_opt.clear(); - land_mask.clear(); - topo_dp.clear(); - topo_use_obs_thresh.clear(); - topo_interp_fcst_thresh.clear(); - msg_typ_group_map.clear(); mask_area_map.clear(); mask_sid_map.clear(); point_weight_flag = PointWeightType::None; @@ -153,9 +148,6 @@ void PairStatConfInfo::process_config(PairsFormat ftype) { // Conf: output_prefix output_prefix = conf.lookup_string(conf_key_output_prefix); - // Conf: message_type_group_map - msg_typ_group_map = parse_conf_message_type_group_map(&conf); - // Conf: fcst.pairs and obs.pairs fdict = conf.lookup_array(conf_key_fcst_pairs); odict = conf.lookup_array(conf_key_obs_pairs); @@ -332,9 +324,6 @@ void PairStatConfInfo::process_flags() { //////////////////////////////////////////////////////////////////////// void PairStatConfInfo::process_masks() { - -/* JHG need to work on this since grid is no longer defined as an input - int i, j; MaskPlane mp; ConcatString name; @@ -352,169 +341,86 @@ void PairStatConfInfo::process_masks() { mask_sid_map.clear(); // Process the masks for each vx task - for(i=0; ilookup_thresh(conf_key_thresh)); - land_mask = geog_dp.mask_plane(); - - // Conf: message_type_group_map for LANDSF and WATERSF - if(msg_typ_group_map.count((string)landsf_msg_typ_group_str) == 0 || - msg_typ_group_map.count((string)watersf_msg_typ_group_str) == 0 ) { - mlog << Error << "\nPairStatConfInfo::process_geog() -> " - << "when \"" << conf_key_land_mask_flag << "\" is true, \"" - << conf_key_message_type_group_map - << "\" must contain entries for \"" - << landsf_msg_typ_group_str << "\" and \"" - << watersf_msg_typ_group_str << "\".\n\n"; - exit(1); - } - } - - // Conf: topo - if(topo) { - dict = conf.lookup_dictionary(conf_key_topo_mask); - topo_dp = parse_geog_data(dict, grid, fcst_file); - topo_use_obs_thresh = dict->lookup_thresh(conf_key_use_obs_thresh); - topo_interp_fcst_thresh = dict->lookup_thresh(conf_key_interp_fcst_thresh); - - // Conf: message_type_group_map for SURFACE - if(msg_typ_group_map.count((string)surface_msg_typ_group_str) == 0) { - mlog << Error << "\nPairStatConfInfo::process_geog() -> " - << "when \"" << conf_key_topo_mask_flag << "\" is true, \"" - << conf_key_message_type_group_map - << "\" must contain an entry for \"" - << surface_msg_typ_group_str << "\".\n\n"; - exit(1); - } - } - - // Loop over the verification tasks and set the geography info - for(i=0; ireq_level_name()) || !(beg_ds == v.beg_ds ) || !(end_ds == v.end_ds ) || - !(land_flag == v.land_flag ) || - !(topo_flag == v.topo_flag ) || !(mask_grid == v.mask_grid ) || !(mask_poly == v.mask_poly ) || !(mask_sid == v.mask_sid ) || @@ -920,12 +832,6 @@ void PairStatVxOpt::process_config(PairsFormat ftype, check_mctc_thresh(ocat_ta); } - // Conf: land.flag - land_flag = odict.lookup_bool(conf_key_land_mask_flag); - - // Conf: topo.flag - topo_flag = odict.lookup_bool(conf_key_topo_mask_flag); - // Conf: mask_grid mask_grid = odict.lookup_string_array(conf_key_mask_grid); @@ -993,36 +899,6 @@ void PairStatVxOpt::set_vx_pd(PairStatConfInfo *conf_info) { // Store the climo CDF info vx_pd.set_climo_cdf_info_ptr(&cdf_info); - // Store the surface message type group - cs = surface_msg_typ_group_str; - if(conf_info->msg_typ_group_map.count(cs) > 0) { - vx_pd.set_msg_typ_sfc(conf_info->msg_typ_group_map[cs]); - } - else { - sa.parse_css(default_msg_typ_group_surface); - vx_pd.set_msg_typ_sfc(sa); - } - - // Store the surface land message type group - cs = landsf_msg_typ_group_str; - if(conf_info->msg_typ_group_map.count(cs) > 0) { - vx_pd.set_msg_typ_lnd(conf_info->msg_typ_group_map[cs]); - } - else { - sa.parse_css(default_msg_typ_group_landsf); - vx_pd.set_msg_typ_lnd(sa); - } - - // Store the surface water message type group - cs = watersf_msg_typ_group_str; - if(conf_info->msg_typ_group_map.count(cs) > 0) { - vx_pd.set_msg_typ_wtr(conf_info->msg_typ_group_map[cs]); - } - else { - sa.parse_css(default_msg_typ_group_watersf); - vx_pd.set_msg_typ_wtr(sa); - } - // Define the masking information: grid, poly, sid, point int n; @@ -1282,3 +1158,63 @@ int PairStatVxOpt::get_n_oprob_thresh() const { } //////////////////////////////////////////////////////////////////////// + +bool PairStatVxOpt::add_mpr_line(const STATLine &l) { + bool keep = false; + + // Check name and level strings + if(l.fcst_var() == vx_pd.fcst_info->name_attr() && + l.fcst_lev() == vx_pd.fcst_info->level_attr() && + l.obs_var() == vx_pd.obs_info->name_attr() && + l.obs_lev() == vx_pd.obs_info->level_attr()) { + + // Parse climo data from the line + ClimoPntInfo cpi; + + // In met-6.1 and later: + // - CLIMO was replaced by CLIMO_MEAN + if(l.has("CLIMO")) { + double cmn = atof(l.get_item("CLIMO")); + double csd = bad_data_double; + cpi.set(cmn, csd, cmn, csd); + } + // In met-12.0.0 and later: + // - CLIMO_MEAN was replaced by OBS_CLIMO_MEAN + // - CLIMO_STDEV was replaced by OBS_CLIMO_STDEV + // - CLIMO_CDF was replaced by OBS_CLIMO_CDF + else if(l.has("CLIMO_MEAN")) { + double cmn = atof(l.get_item("CLIMO_MEAN")); + double csd = atof(l.get_item("CLIMO_STDEV")); + cpi.set(cmn, csd, cmn, csd); + } + else { + cpi.set(atof(l.get_item("FCST_CLIMO_MEAN")), + atof(l.get_item("FCST_CLIMO_STDEV")), + atof(l.get_item("OBS_CLIMO_MEAN")), + atof(l.get_item("OBS_CLIMO_STDEV"))); + } + + // Attempt to add pair to each masking region + for(auto &pairs : vx_pd.pd) { + if(pairs.add_point_pair( + l.obtype(), + l.get_item("OBS_SID"), + atof(l.get_item("OBS_LAT")), + atof(l.get_item("OBS_LON")), + bad_data_double, + bad_data_double, + timestring_to_unix(l.get_item("OBS_VALID_BEG")), + atof(l.get_item("OBS_LVL")), + atof(l.get_item("OBS_ELV")), + atof(l.get_item("FCST")), + atof(l.get_item("OBS")), + l.get_item("OBS_QC"), + cpi, + default_weight)) keep = true; + } + } + + return keep; +} + +//////////////////////////////////////////////////////////////////////// diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.h b/src/tools/core/pair_stat/pair_stat_conf_info.h index e35538d8fd..51d3d00461 100644 --- a/src/tools/core/pair_stat/pair_stat_conf_info.h +++ b/src/tools/core/pair_stat/pair_stat_conf_info.h @@ -22,11 +22,15 @@ #include "vx_cal.h" #include "vx_math.h" #include "vx_gsl_prob.h" +#include "vx_analysis_util.h" #include "vx_statistics.h" #include "vx_stat_out.h" //////////////////////////////////////////////////////////////////////// +// Reference global grid +static Grid grid("G004"); + // Indices for the output flag types in the configuration file static const int i_fho = 0; static const int i_ctc = 1; @@ -135,9 +139,6 @@ class PairStatVxOpt { ThreshArray owind_ta; // Array for obs wind speed thresholds SetLogic wind_logic; // Array of wind speed field logic - bool land_flag; // Flag for land/sea mask filtering - bool topo_flag; // Flag for topography filtering - StringArray mask_grid; // Masking grid strings StringArray mask_poly; // Masking polyline strings StringArray mask_sid; // Masking station ID's @@ -165,8 +166,6 @@ class PairStatVxOpt { double hss_ec_value; // HSS expected correct value bool rank_corr_flag; // Flag for computing rank correlations - StringArray msg_typ; // Array of message types - // Output file options STATOutputType output_flag[n_txt]; // Flag for each output line type @@ -195,6 +194,9 @@ class PairStatVxOpt { int get_n_eclv_points() const; int get_n_cdf_bin() const; int get_n_ci_alpha() const; + + // Add paired data + bool add_mpr_line(const STATLine &); }; //////////////////////////////////////////////////////////////////////// @@ -231,15 +233,6 @@ class PairStatConfInfo { std::vector vx_opt; // Vector of vx options [n_vx] - // Land/sea mask and topography info for data filtering - MaskPlane land_mask; - DataPlane topo_dp; - SingleThresh topo_use_obs_thresh; - SingleThresh topo_interp_fcst_thresh; - - // Message type groups - std::map msg_typ_group_map; - // Mapping of mask names to DataPlanes std::map mask_area_map; @@ -267,7 +260,6 @@ class PairStatConfInfo { void process_config(PairsFormat); void process_flags(); void process_masks(); - void process_geog(); void set_vx_pd(); // Dump out the counts @@ -288,6 +280,9 @@ class PairStatConfInfo { // Check for any verification of vectors bool get_vflag() const; + + // Add paired data + bool add_mpr_line(const STATLine &); }; //////////////////////////////////////////////////////////////////////// From fc7f0c832ea19312bb5002c0e8c94586ead71c45 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 31 Dec 2024 17:30:23 +0000 Subject: [PATCH 13/15] Per #3006, update VarInfoPairs::set_dict() to also call VarInfo::set_magic(). --- src/libcode/vx_data2d/var_info_pairs.cc | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcode/vx_data2d/var_info_pairs.cc b/src/libcode/vx_data2d/var_info_pairs.cc index 3cbf5dcddc..fabee61f54 100644 --- a/src/libcode/vx_data2d/var_info_pairs.cc +++ b/src/libcode/vx_data2d/var_info_pairs.cc @@ -128,7 +128,23 @@ void VarInfoPairs::dump(ostream &out) const { /////////////////////////////////////////////////////////////////////////////// void VarInfoPairs::set_dict(Dictionary & dict) { + VarInfo::set_dict(dict); + + // + // Parse the required name and optional level strings + // + ConcatString nstr = dict.lookup_string(conf_key_name); + ReqName = nstr; + Name = nstr; + + ConcatString lstr = dict.lookup_string(conf_key_level, false); + Level.set_req_name(lstr.c_str()); + Level.set_name(lstr.c_str()); + + VarInfo::set_magic(nstr, lstr); + + return; } /////////////////////////////////////////////////////////////////////////////// From b066f5bf1190ad7a0ed184d3f7c857caf00db076 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 31 Dec 2024 17:32:22 +0000 Subject: [PATCH 14/15] Per #3006, since python_line.h lives in src/basic/vx_util, the vx_util library now also depends on the --- src/tools/core/pair_stat/Makefile.am | 1 + src/tools/core/pair_stat/Makefile.in | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/core/pair_stat/Makefile.am b/src/tools/core/pair_stat/Makefile.am index 8d462aabfa..f8bbc63022 100644 --- a/src/tools/core/pair_stat/Makefile.am +++ b/src/tools/core/pair_stat/Makefile.am @@ -40,6 +40,7 @@ pair_stat_LDADD = -lvx_stat_out \ -lvx_color \ -lvx_util_math \ -lvx_util \ + $(PYTHON_MET_LIBS) \ -lvx_math \ -lvx_cal \ -lvx_log \ diff --git a/src/tools/core/pair_stat/Makefile.in b/src/tools/core/pair_stat/Makefile.in index e3bd911ba1..48f6f33d88 100644 --- a/src/tools/core/pair_stat/Makefile.in +++ b/src/tools/core/pair_stat/Makefile.in @@ -107,7 +107,8 @@ pair_stat_OBJECTS = $(am_pair_stat_OBJECTS) am__DEPENDENCIES_1 = pair_stat_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) pair_stat_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ $(pair_stat_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) @@ -361,6 +362,7 @@ pair_stat_LDADD = -lvx_stat_out \ -lvx_color \ -lvx_util_math \ -lvx_util \ + $(PYTHON_MET_LIBS) \ -lvx_math \ -lvx_cal \ -lvx_log \ From 54bc949f84b290495d61840a9d63dd27ba4f1860 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 31 Dec 2024 18:03:55 +0000 Subject: [PATCH 15/15] Per #3006, saving off version that compiles before trying changes that may not. --- src/tools/core/pair_stat/pair_stat.cc | 648 ++++++-------------------- src/tools/core/pair_stat/pair_stat.h | 4 - 2 files changed, 149 insertions(+), 503 deletions(-) diff --git a/src/tools/core/pair_stat/pair_stat.cc b/src/tools/core/pair_stat/pair_stat.cc index e86708c2ff..cdc7d40804 100644 --- a/src/tools/core/pair_stat/pair_stat.cc +++ b/src/tools/core/pair_stat/pair_stat.cc @@ -58,7 +58,7 @@ using namespace netCDF; //////////////////////////////////////////////////////////////////////// static void process_command_line(int, char **); -static void setup_first_pass(const DataPlane &, const Grid &); +static void setup_pairs(); static void setup_txt_files(); static void setup_table (AsciiTable &); @@ -217,6 +217,12 @@ void process_command_line(int argc, char **argv) { // Process the configuration conf_info.process_config(pairs_format); + // Process the masks + conf_info.process_masks(); + + // Setup the VxPairDataPoint objects + conf_info.set_vx_pd(); + // List the input pair files mlog << Debug(1) << "Reading " << pairs_files.n() << " \"" @@ -242,33 +248,6 @@ void process_command_line(int argc, char **argv) { //////////////////////////////////////////////////////////////////////// -void setup_first_pass(const DataPlane &dp, const Grid &data_grid) { - - // Unset the flag - is_first_pass = false; - - // Determine the verification grid - grid = parse_vx_grid(conf_info.vx_opt[0].vx_pd.fcst_info->regrid(), - &data_grid, &data_grid); - - // Process the masks - conf_info.process_masks(); - - // Process the geography data - conf_info.process_geog(); - - // Setup the VxPairDataPoint objects - conf_info.set_vx_pd(); - - // Store the lead and valid times - if(fcst_valid_ut == (unixtime) 0) fcst_valid_ut = dp.valid(); - if(is_bad_data(fcst_lead_sec)) fcst_lead_sec = dp.lead(); - - return; -} - -//////////////////////////////////////////////////////////////////////// - void setup_txt_files() { int max_col, max_prob_col, max_mctc_col, max_orank_col; int n_prob, n_cat, n_eclv; @@ -469,381 +448,52 @@ void build_outfile_name(unixtime valid_ut, int lead_sec, //////////////////////////////////////////////////////////////////////// void process_mpr_pairs(const ConcatString &file_name, PairsFormat format) { + LineDataFile f; + const char *method_name = "process_mpr_pairs() -> "; - return; -} - -/* JHG - int j; - int n_fcst; - DataPlaneArray fcst_dpa; - DataPlaneArray fcmn_dpa, fcsd_dpa; - DataPlaneArray ocmn_dpa, ocsd_dpa; - unixtime file_ut, beg_ut, end_ut; - - // Loop through each of the fields to be verified and extract - // the forecast and climatological fields for verification - for(int i=0; idata_plane_array(*fcst_info, fcst_dpa); - mlog << Debug(2) << "\n" << sep_str << "\n\n" - << "Reading data for " << fcst_info->magic_str() << ".\n"; - - // Check for zero fields - if(n_fcst == 0) { - mlog << Warning << "\nprocess_fcst_climo_files() -> " - << "no fields matching " << fcst_info->magic_str() - << " found in file: " << fcst_file << "\n\n"; - continue; - } - - // MET #2795, for multiple individual forecast levels, print a - // warning if the observations levels are not fully covered. - if(n_fcst > 1 && - !is_eq(fcst_info->level().lower(), fcst_info->level().upper()) && - (obs_info->level().lower() < fcst_info->level().lower() || - obs_info->level().upper() > fcst_info->level().upper())) { - mlog << Warning << "\nprocess_fcst_climo_files() -> " - << "The forecast level range (" << fcst_info->magic_str() - << ") does not fully contain the observation level range (" - << obs_info->magic_str() << "). No vertical interpolation " - << "will be performed for observations falling outside " - << "the range of forecast levels. Instead, they will be " - << "matched to the single nearest forecast level.\n\n"; - } - - // Setup the first pass through the data - if(is_first_pass) setup_first_pass(fcst_dpa[0], fcst_mtddf->grid()); - - // Regrid, if necessary - if(!(fcst_mtddf->grid() == grid)) { - mlog << Debug(1) - << "Regridding " << fcst_dpa.n_planes() - << " forecast field(s) for " << fcst_info->magic_str() - << " to the verification grid using " - << fcst_info->regrid().get_str() << ".\n"; - - // Loop through the forecast fields - for(j=0; jgrid(), grid, - fcst_info->regrid()); - } - } + // + // Open the input file + // + if(!f.open(file_name.c_str())) { + mlog << Warning << "\n" << method_name + << "can't open matched pair file \"" << file_name + << "\" for reading!\n\n"; + return; + } - // Rescale probabilities from [0, 100] to [0, 1] - if(fcst_info->p_flag()) { - for(j=0; j> line) { - // Dump out the number of levels found - mlog << Debug(2) - << "For " << fcst_info->magic_str() << ", found " - << n_fcst << " forecast levels, " - << fcmn_dpa.n_planes() << " forecast climatology mean and " - << fcsd_dpa.n_planes() << " standard deviation level(s), and " - << ocmn_dpa.n_planes() << " observation climatology mean and " - << ocsd_dpa.n_planes() << " standard deviation level(s).\n"; + // Skip header and non-MPR lines + if(line.is_header() || line.type() != STATLineType::mpr) continue; - } // end for i + n_read++; - // Check for no data - if(is_first_pass) { - mlog << Error << "\nprocess_fcst_climo_files() -> " - << "no requested forecast data found! Exiting...\n\n"; - exit(1); + if(conf_info.add_mpr_line(line)) n_keep++; } - - mlog << Debug(2) - << "\n" << sep_str << "\n\n"; - + + mlog << Debug(3) << "Keeping " << n_keep << " of " << n_read + << " MPR lines from \"" << file_name << "\".\n"; + return; } -*/ + //////////////////////////////////////////////////////////////////////// void process_ioda_pairs(const ConcatString &file_name) { - + // TODO: work here return; } -/* JHG - int j, i_obs; - float obs_arr[OBS_ARRAY_LEN], hdr_arr[HDR_ARRAY_LEN]; - float prev_obs_arr[OBS_ARRAY_LEN]; - ConcatString hdr_typ_str; - ConcatString hdr_sid_str; - ConcatString hdr_vld_str; - ConcatString obs_qty_str; - unixtime hdr_ut; - NcFile *obs_in = (NcFile *) nullptr; - const char *method_name = "process_obs_file() -> "; - - // Set flags for vectors - bool vflag = conf_info.get_vflag(); - bool is_ugrd, is_vgrd; - - // Open the observation file as a NetCDF file. - // The observation file must be in NetCDF format as the - // output of the PB2NC or ASCII2NC tool. - bool status; - bool use_var_id = true; - bool use_arr_vars = false; - bool use_python = false; - MetNcPointObsIn nc_point_obs; - MetPointData *met_point_obs = nullptr; - - // Check for python format - string python_command = obs_file[i_nc]; - bool use_xarray = (0 == python_command.find(conf_val_python_xarray)); - use_python = use_xarray || (0 == python_command.find(conf_val_python_numpy)); - -#ifdef WITH_PYTHON - MetPythonPointDataFile met_point_file; - if (use_python) { - int offset = python_command.find("="); - if (offset == std::string::npos) { - mlog << Error << "\n" << method_name - << "trouble parsing the python command " << python_command << ".\n\n"; - exit(1); - } - - if(!met_point_file.open(python_command.substr(offset+1).c_str(), use_xarray)) { - met_point_file.close(); - mlog << Error << "\n" << method_name - << "trouble getting point observation file from python command " - << python_command << ".\n\n"; - exit(1); - } - - met_point_obs = met_point_file.get_met_point_data(); - use_var_id = met_point_file.is_using_var_id(); - } - else { -#else - if (use_python) python_compile_error(method_name); -#endif - if( !nc_point_obs.open(obs_file[i_nc].c_str()) ) { - nc_point_obs.close(); - - mlog << Warning << "\n" << method_name - << "can't open observation netCDF file: " - << obs_file[i_nc] << "\n\n"; - return; - } - - nc_point_obs.read_dim_headers(); - nc_point_obs.check_nc(obs_file[i_nc].c_str(), method_name); - nc_point_obs.read_obs_data_table_lookups(); - met_point_obs = (MetPointData *)&nc_point_obs; - use_var_id = nc_point_obs.is_using_var_id(); - use_arr_vars = nc_point_obs.is_using_obs_arr(); -#ifdef WITH_PYTHON - } -#endif - - // Perform GRIB table lookups, if needed - is_vgrd = is_ugrd = false; - - int hdr_count = met_point_obs->get_hdr_cnt(); - int obs_count = met_point_obs->get_obs_cnt(); - mlog << Debug(2) - << "Searching " << obs_count - << " observations from " << hdr_count - << " messages.\n"; - - ConcatString var_name(""); - StringArray var_names; - StringArray obs_qty_array = met_point_obs->get_qty_data(); - if(use_var_id) var_names = met_point_obs->get_var_names(); - - const int buf_size = (obs_count > BUFFER_SIZE) ? BUFFER_SIZE : obs_count; - int obs_qty_idx_block[buf_size]; - float obs_arr_block[buf_size][OBS_ARRAY_LEN]; - - // Process each observation in the file - int block_size; - int prev_grib_code = bad_data_int; - for(int i_block_start_idx=0; i_block_start_idx buf_size) block_size = buf_size; - -#ifdef WITH_PYTHON - if (use_python) - status = met_point_obs->get_point_obs_data()->fill_obs_buf( - block_size, i_block_start_idx, (float *)obs_arr_block, obs_qty_idx_block); - else -#endif - status = nc_point_obs.read_obs_data(block_size, i_block_start_idx, - (float *)obs_arr_block, - obs_qty_idx_block, (char *)nullptr); - if (!status) exit(1); - - int hdr_idx; - for(int i_block_idx=0; i_block_idxget_header_offset(obs_arr); - - // Range check the header offset - if(headerOffset < 0 || headerOffset >= hdr_count) { - mlog << Warning << "\n" << method_name - << "range check error for header index " << headerOffset - << " from observation number " << i_obs - << " of point observation file: " << obs_file[i_nc] - << "\n\n"; - continue; - } - - // Read the corresponding header array for this observation - // - the corresponding header type, header Station ID, and valid time -#ifdef WITH_PYTHON - if (use_python) - met_point_obs->get_header(headerOffset, hdr_arr, hdr_typ_str, hdr_sid_str, hdr_vld_str); - else -#endif - nc_point_obs.get_header(headerOffset, hdr_arr, hdr_typ_str, - hdr_sid_str, hdr_vld_str); - - // Store the variable name - int org_grib_code = met_point_obs->get_grib_code_or_var_index(obs_arr); - int grib_code = org_grib_code; - if (prev_grib_code != org_grib_code) { - if (use_var_id && grib_code < var_names.n()) { - var_name = var_names[grib_code]; - grib_code = bad_data_int; - } - else { - var_name = ""; - } - - // Check for wind components - is_ugrd = ( use_var_id && var_name == ugrd_abbr_str ) || - (!use_var_id && nint(grib_code) == ugrd_grib_code); - is_vgrd = ( use_var_id && var_name == vgrd_abbr_str ) || - (!use_var_id && nint(grib_code) == vgrd_grib_code); - prev_grib_code = org_grib_code; - } - - // If the current observation is UGRD, save it as the - // previous. If vector winds are to be computed, UGRD - // must be followed by VGRD - if(vflag && is_ugrd) { - for(j=0; j<4; j++) prev_obs_arr[j] = obs_arr[j]; - } - - // If the current observation is VGRD and vector - // winds are to be computed. Make sure that the - // previous observation was UGRD with the same header - // and at the same vertical level. - if(vflag && is_vgrd) { - - if(!met_point_obs->is_same_obs_values(obs_arr, prev_obs_arr)) { - mlog << Error << "\n" << method_name - << "for observation index " << i_obs - << ", when computing VL1L2 and/or VAL1L2 vector winds " - << "each UGRD observation must be followed by a VGRD " - << "observation with the same header and at the same " - << "level.\n\n"; - exit(1); - } - } - - // Convert string to a unixtime - hdr_ut = timestring_to_unix(hdr_vld_str.c_str()); - - // Check each conf_info.vx_pd object to see if this observation - // should be added - for(j=0; jset_grib_code_or_var_index(obs_arr, org_grib_code); - } - - } // end for i_block_start_idx - - // Deallocate and clean up -#ifdef WITH_PYTHON - if (use_python) met_point_file.close(); - else -#endif - nc_point_obs.close(); - - return; -} -*/ //////////////////////////////////////////////////////////////////////// void process_scores() { @@ -851,9 +501,9 @@ void process_scores() { ConcatString cs; // Initialize pointers - CTSInfo *cts_info = (CTSInfo *) nullptr; - MCTSInfo mcts_info; - VL1L2Info *vl1l2_info = (VL1L2Info *) nullptr; + CTSInfo *cts_info = (CTSInfo *) nullptr; + MCTSInfo mcts_info; + VL1L2Info *vl1l2_info = (VL1L2Info *) nullptr; mlog << Debug(2) << "\n" << sep_str << "\n\n"; @@ -870,107 +520,107 @@ void process_scores() { vl1l2_info = new VL1L2Info [n_wind]; // Compute scores for each PairData object and write output - for(int i_vx=0; i_vxvx_pd.fcst_dpa.n_planes() == 0) continue; + i_vx++; // Store the description - if(vx_ptr->vx_pd.desc.empty()) { + if(vx.vx_pd.desc.empty()) { shc.set_desc(na_str); } else { - shc.set_desc(vx_ptr->vx_pd.desc.c_str()); + shc.set_desc(vx.vx_pd.desc.c_str()); } // Store the forecast variable name - shc.set_fcst_var(vx_ptr->vx_pd.fcst_info->name_attr()); + shc.set_fcst_var(vx.vx_pd.fcst_info->name_attr()); // Store the forecast variable units - shc.set_fcst_units(vx_ptr->vx_pd.fcst_info->units_attr()); + shc.set_fcst_units(vx.vx_pd.fcst_info->units_attr()); // Set the forecast level name - shc.set_fcst_lev(vx_ptr->vx_pd.fcst_info->level_attr().c_str()); + shc.set_fcst_lev(vx.vx_pd.fcst_info->level_attr().c_str()); // Store the observation variable name - shc.set_obs_var(vx_ptr->vx_pd.obs_info->name_attr()); + shc.set_obs_var(vx.vx_pd.obs_info->name_attr()); // Store the observation variable units - cs = vx_ptr->vx_pd.obs_info->units_attr(); + cs = vx.vx_pd.obs_info->units_attr(); if(cs.empty()) cs = na_string; shc.set_obs_units(cs); // Set the observation level name - shc.set_obs_lev(vx_ptr->vx_pd.obs_info->level_attr().c_str()); + shc.set_obs_lev(vx.vx_pd.obs_info->level_attr().c_str()); + // TODO: figure out the actual timing info! // Set the forecast lead time - shc.set_fcst_lead_sec(vx_ptr->vx_pd.fcst_dpa[0].lead()); + shc.set_fcst_lead_sec(0); + // TODO: figure out the actual timing info! // Set the forecast valid time - shc.set_fcst_valid_beg(vx_ptr->vx_pd.fcst_dpa[0].valid()); - shc.set_fcst_valid_end(vx_ptr->vx_pd.fcst_dpa[0].valid()); + shc.set_fcst_valid_beg(0); + shc.set_fcst_valid_end(0); // Set the observation lead time shc.set_obs_lead_sec(0); // Set the observation valid time - shc.set_obs_valid_beg(vx_ptr->vx_pd.beg_ut); - shc.set_obs_valid_end(vx_ptr->vx_pd.end_ut); + shc.set_obs_valid_beg(vx.vx_pd.beg_ut); + shc.set_obs_valid_end(vx.vx_pd.end_ut); // Store the message type in the obtype column shc.set_obtype(na_str); // Loop through the verification masking regions - for(int i_mask=0; i_maskget_n_mask(); i_mask++) { + for(int i_mask=0; i_maskmask_name[i_mask].c_str()); + shc.set_mask(vx.mask_name[i_mask].c_str()); // Store the interpolation method as nearest shc.set_interp_mthd(InterpMthd::Nearest); shc.set_interp_wdth(1); - PairDataPoint *pd_ptr = &vx_ptr->vx_pd.pd[i_mask]; + PairDataPoint *pd_ptr = &vx.vx_pd.pd[i_mask]; mlog << Debug(2) - << "Processing " << vx_ptr->vx_pd.fcst_info->magic_str() - << " versus " << vx_ptr->vx_pd.obs_info->magic_str() + << "Processing " << vx.vx_pd.fcst_info->magic_str() + << " versus " << vx.vx_pd.obs_info->magic_str() << ", over region " << pd_ptr->mask_name - << "), using " << pd_ptr->n_obs << " matched pairs.\n"; + << ", using " << pd_ptr->n_obs << " matched pairs.\n"; // List counts for reasons why observations were rejected cs << cs_erase << "Number of matched pairs = " << pd_ptr->n_obs << "\n" - << "Observations processed = " << vx_ptr->vx_pd.n_try << "\n" - << "Rejected: station id = " << vx_ptr->vx_pd.rej_sid << "\n" - << "Rejected: obs var name = " << vx_ptr->vx_pd.rej_var << "\n" - << "Rejected: valid time = " << vx_ptr->vx_pd.rej_vld << "\n" - << "Rejected: bad obs value = " << vx_ptr->vx_pd.rej_obs << "\n" - << "Rejected: off the grid = " << vx_ptr->vx_pd.rej_grd << "\n" - << "Rejected: topography = " << vx_ptr->vx_pd.rej_topo << "\n" - << "Rejected: level mismatch = " << vx_ptr->vx_pd.rej_lvl << "\n" - << "Rejected: quality marker = " << vx_ptr->vx_pd.rej_qty << "\n" - << "Rejected: message type = " << vx_ptr->vx_pd.rej_typ[i_mask] << "\n" - << "Rejected: masking region = " << vx_ptr->vx_pd.rej_mask[i_mask] << "\n" - << "Rejected: bad fcst value = " << vx_ptr->vx_pd.rej_fcst[i_mask] << "\n" - << "Rejected: bad climo mean = " << vx_ptr->vx_pd.rej_cmn[i_mask] << "\n" - << "Rejected: bad climo stdev = " << vx_ptr->vx_pd.rej_csd[i_mask] << "\n" - << "Rejected: mpr filter = " << vx_ptr->vx_pd.rej_mpr[i_mask] << "\n" - << "Rejected: duplicates = " << vx_ptr->vx_pd.rej_dup[i_mask] << "\n"; + << "Observations processed = " << vx.vx_pd.n_try << "\n" + << "Rejected: station id = " << vx.vx_pd.rej_sid << "\n" + << "Rejected: obs var name = " << vx.vx_pd.rej_var << "\n" + << "Rejected: valid time = " << vx.vx_pd.rej_vld << "\n" + << "Rejected: bad obs value = " << vx.vx_pd.rej_obs << "\n" + << "Rejected: off the grid = " << vx.vx_pd.rej_grd << "\n" + << "Rejected: topography = " << vx.vx_pd.rej_topo << "\n" + << "Rejected: level mismatch = " << vx.vx_pd.rej_lvl << "\n" + << "Rejected: quality marker = " << vx.vx_pd.rej_qty << "\n" + << "Rejected: message type = " << vx.vx_pd.rej_typ[i_mask] << "\n" + << "Rejected: masking region = " << vx.vx_pd.rej_mask[i_mask] << "\n" + << "Rejected: bad fcst value = " << vx.vx_pd.rej_fcst[i_mask] << "\n" + << "Rejected: bad climo mean = " << vx.vx_pd.rej_cmn[i_mask] << "\n" + << "Rejected: bad climo stdev = " << vx.vx_pd.rej_csd[i_mask] << "\n" + << "Rejected: mpr filter = " << vx.vx_pd.rej_mpr[i_mask] << "\n" + << "Rejected: duplicates = " << vx.vx_pd.rej_dup[i_mask] << "\n"; // Print report based on the number of matched pairs if(pd_ptr->n_obs > 0) mlog << Debug(3) << cs; else mlog << Debug(2) << cs; // Process percentile thresholds - vx_ptr->set_perc_thresh(pd_ptr); + vx.set_perc_thresh(pd_ptr); // Write out the MPR lines - if(vx_ptr->output_flag[i_mpr] != STATOutputType::None) { + if(vx.output_flag[i_mpr] != STATOutputType::None) { write_mpr_row(shc, pd_ptr, - vx_ptr->output_flag[i_mpr], + vx.output_flag[i_mpr], stat_at, i_stat_row, txt_at[i_mpr], i_txt_row[i_mpr], false); @@ -978,14 +628,14 @@ void process_scores() { shc.set_obtype(na_str); // Reset the observation valid time - shc.set_obs_valid_beg(vx_ptr->vx_pd.beg_ut); - shc.set_obs_valid_end(vx_ptr->vx_pd.end_ut); + shc.set_obs_valid_beg(vx.vx_pd.beg_ut); + shc.set_obs_valid_end(vx.vx_pd.end_ut); } // Write out the SEEPS MPR lines - if(vx_ptr->output_flag[i_seeps_mpr] != STATOutputType::None) { + if(vx.output_flag[i_seeps_mpr] != STATOutputType::None) { write_seeps_mpr_row(shc, pd_ptr, - vx_ptr->output_flag[i_seeps_mpr], + vx.output_flag[i_seeps_mpr], stat_at, i_stat_row, txt_at[i_seeps_mpr], i_txt_row[i_seeps_mpr], false); @@ -993,26 +643,26 @@ void process_scores() { shc.set_obtype(na_str); // Reset the observation valid time - shc.set_obs_valid_beg(vx_ptr->vx_pd.beg_ut); - shc.set_obs_valid_end(vx_ptr->vx_pd.end_ut); + shc.set_obs_valid_beg(vx.vx_pd.beg_ut); + shc.set_obs_valid_end(vx.vx_pd.end_ut); } // Write out the SEEPS lines - if(vx_ptr->output_flag[i_seeps] != STATOutputType::None) { + if(vx.output_flag[i_seeps] != STATOutputType::None) { compute_aggregated_seeps(pd_ptr, &pd_ptr->seeps_agg); write_seeps_row(shc, &pd_ptr->seeps_agg, - vx_ptr->output_flag[i_seeps], + vx.output_flag[i_seeps], stat_at, i_stat_row, txt_at[i_seeps], i_txt_row[i_seeps]); } // Compute CTS scores - if(!vx_ptr->vx_pd.fcst_info->is_prob() && - vx_ptr->fcat_ta.n() > 0 && - (vx_ptr->output_flag[i_fho] != STATOutputType::None || - vx_ptr->output_flag[i_ctc] != STATOutputType::None || - vx_ptr->output_flag[i_cts] != STATOutputType::None || - vx_ptr->output_flag[i_eclv] != STATOutputType::None)) { + if(!vx.vx_pd.fcst_info->is_prob() && + vx.fcat_ta.n() > 0 && + (vx.output_flag[i_fho] != STATOutputType::None || + vx.output_flag[i_ctc] != STATOutputType::None || + vx.output_flag[i_cts] != STATOutputType::None || + vx.output_flag[i_eclv] != STATOutputType::None)) { // Initialize for(int i_cat=0; i_catfcat_ta.n(); i_cat++) { + for(int i_cat=0; i_catoutput_flag[i_fho] != STATOutputType::None) { + if(vx.output_flag[i_fho] != STATOutputType::None) { write_fho_row(shc, cts_info[i_cat], - vx_ptr->output_flag[i_fho], + vx.output_flag[i_fho], stat_at, i_stat_row, txt_at[i_fho], i_txt_row[i_fho]); } // Write out CTC - if(vx_ptr->output_flag[i_ctc] != STATOutputType::None) { + if(vx.output_flag[i_ctc] != STATOutputType::None) { write_ctc_row(shc, cts_info[i_cat], - vx_ptr->output_flag[i_ctc], + vx.output_flag[i_ctc], stat_at, i_stat_row, txt_at[i_ctc], i_txt_row[i_ctc]); } // Write out CTS - if(vx_ptr->output_flag[i_cts] != STATOutputType::None) { + if(vx.output_flag[i_cts] != STATOutputType::None) { write_cts_row(shc, cts_info[i_cat], - vx_ptr->output_flag[i_cts], + vx.output_flag[i_cts], stat_at, i_stat_row, txt_at[i_cts], i_txt_row[i_cts]); } // Write out ECLV - if(vx_ptr->output_flag[i_eclv] != STATOutputType::None) { - write_eclv_row(shc, cts_info[i_cat], vx_ptr->eclv_points, - vx_ptr->output_flag[i_eclv], + if(vx.output_flag[i_eclv] != STATOutputType::None) { + write_eclv_row(shc, cts_info[i_cat], vx.eclv_points, + vx.output_flag[i_eclv], stat_at, i_stat_row, txt_at[i_eclv], i_txt_row[i_eclv]); } @@ -1060,10 +710,10 @@ void process_scores() { } // end Compute CTS scores // Compute MCTS scores - if(!vx_ptr->vx_pd.fcst_info->is_prob() && - vx_ptr->fcat_ta.n() > 1 && - (vx_ptr->output_flag[i_mctc] != STATOutputType::None || - vx_ptr->output_flag[i_mcts] != STATOutputType::None)) { + if(!vx.vx_pd.fcst_info->is_prob() && + vx.fcat_ta.n() > 1 && + (vx.output_flag[i_mctc] != STATOutputType::None || + vx.output_flag[i_mcts] != STATOutputType::None)) { // Initialize mcts_info.clear(); @@ -1074,37 +724,37 @@ void process_scores() { if(mcts_info.cts.n_pairs() == 0) continue; // Write out MCTC - if(vx_ptr->output_flag[i_mctc] != STATOutputType::None) { + if(vx.output_flag[i_mctc] != STATOutputType::None) { write_mctc_row(shc, mcts_info, - vx_ptr->output_flag[i_mctc], + vx.output_flag[i_mctc], stat_at, i_stat_row, txt_at[i_mctc], i_txt_row[i_mctc]); } // Write out MCTS - if(vx_ptr->output_flag[i_mcts] != STATOutputType::None) { + if(vx.output_flag[i_mcts] != STATOutputType::None) { write_mcts_row(shc, mcts_info, - vx_ptr->output_flag[i_mcts], + vx.output_flag[i_mcts], stat_at, i_stat_row, txt_at[i_mcts], i_txt_row[i_mcts]); } } // end Compute MCTS scores // Compute CNT, SL1L2, and SAL1L2 scores - if(!vx_ptr->vx_pd.fcst_info->is_prob() && - (vx_ptr->output_flag[i_cnt] != STATOutputType::None || - vx_ptr->output_flag[i_sl1l2] != STATOutputType::None || - vx_ptr->output_flag[i_sal1l2] != STATOutputType::None)) { - do_cnt_sl1l2(*vx_ptr, pd_ptr); + if(!vx.vx_pd.fcst_info->is_prob() && + (vx.output_flag[i_cnt] != STATOutputType::None || + vx.output_flag[i_sl1l2] != STATOutputType::None || + vx.output_flag[i_sal1l2] != STATOutputType::None)) { + do_cnt_sl1l2(vx, pd_ptr); } // Compute VL1L2 and VAL1L2 partial sums for UGRD and VGRD - if(!vx_ptr->vx_pd.fcst_info->is_prob() && - vx_ptr->vx_pd.fcst_info->is_v_wind() && - vx_ptr->vx_pd.fcst_info->uv_index() >= 0 && - (vx_ptr->output_flag[i_vl1l2] != STATOutputType::None || - vx_ptr->output_flag[i_val1l2] != STATOutputType::None || - vx_ptr->output_flag[i_vcnt] != STATOutputType::None)) { + if(!vx.vx_pd.fcst_info->is_prob() && + vx.vx_pd.fcst_info->is_v_wind() && + vx.vx_pd.fcst_info->uv_index() >= 0 && + (vx.output_flag[i_vl1l2] != STATOutputType::None || + vx.output_flag[i_val1l2] != STATOutputType::None || + vx.output_flag[i_vcnt] != STATOutputType::None)) { // Store the forecast variable name shc.set_fcst_var(ugrd_vgrd_abbr_str); @@ -1116,7 +766,7 @@ void process_scores() { for(int i_wind=0; i_windvx_pd.fcst_info->uv_index(); + int u_vx = vx.vx_pd.fcst_info->uv_index(); // Check to make sure the masking regions match if(conf_info.vx_opt[i_vx].get_n_mask() != @@ -1134,56 +784,56 @@ void process_scores() { &conf_info.vx_opt[i_vx].vx_pd.pd[i_mask]); // Loop through all of the wind speed thresholds - for(int i_wind=0; i_windfwind_ta.n(); i_wind++) { + for(int i_wind=0; i_windoutput_flag[i_vl1l2] != STATOutputType::None && + if(vx.output_flag[i_vl1l2] != STATOutputType::None && vl1l2_info[i_wind].vcount > 0) { write_vl1l2_row(shc, vl1l2_info[i_wind], - vx_ptr->output_flag[i_vl1l2], + vx.output_flag[i_vl1l2], stat_at, i_stat_row, txt_at[i_vl1l2], i_txt_row[i_vl1l2]); } // Write out VAL1L2 - if(vx_ptr->output_flag[i_val1l2] != STATOutputType::None && + if(vx.output_flag[i_val1l2] != STATOutputType::None && vl1l2_info[i_wind].vacount > 0) { write_val1l2_row(shc, vl1l2_info[i_wind], - vx_ptr->output_flag[i_val1l2], + vx.output_flag[i_val1l2], stat_at, i_stat_row, txt_at[i_val1l2], i_txt_row[i_val1l2]); } // Write out VCNT - if(vx_ptr->output_flag[i_vcnt] != STATOutputType::None && + if(vx.output_flag[i_vcnt] != STATOutputType::None && vl1l2_info[i_wind].vcount > 0) { write_vcnt_row(shc, vl1l2_info[i_wind], - vx_ptr->output_flag[i_vcnt], + vx.output_flag[i_vcnt], stat_at, i_stat_row, txt_at[i_vcnt], i_txt_row[i_vcnt]); } } // end for i_wind // Reset the forecast variable name - shc.set_fcst_var(vx_ptr->vx_pd.fcst_info->name_attr()); + shc.set_fcst_var(vx.vx_pd.fcst_info->name_attr()); // Reset the observation variable name - shc.set_obs_var(vx_ptr->vx_pd.obs_info->name_attr()); + shc.set_obs_var(vx.vx_pd.obs_info->name_attr()); } // end Compute VL1L2 and VAL1L2 // Compute PCT counts and scores - if(vx_ptr->vx_pd.fcst_info->is_prob() && - (vx_ptr->output_flag[i_pct] != STATOutputType::None || - vx_ptr->output_flag[i_pstd] != STATOutputType::None || - vx_ptr->output_flag[i_pjc] != STATOutputType::None || - vx_ptr->output_flag[i_prc] != STATOutputType::None || - vx_ptr->output_flag[i_eclv] != STATOutputType::None)) { + if(vx.vx_pd.fcst_info->is_prob() && + (vx.output_flag[i_pct] != STATOutputType::None || + vx.output_flag[i_pstd] != STATOutputType::None || + vx.output_flag[i_pjc] != STATOutputType::None || + vx.output_flag[i_prc] != STATOutputType::None || + vx.output_flag[i_eclv] != STATOutputType::None)) { do_pct(conf_info.vx_opt[i_vx], pd_ptr); } // Reset the verification masking region - shc.set_mask(vx_ptr->mask_name[i_mask].c_str()); + shc.set_mask(vx.mask_name[i_mask].c_str()); } // end for i_mask @@ -1722,12 +1372,12 @@ void usage() { << "\t[-v level]\n\n" << "\twhere\t\"-pairs\" defines one or more input files containing " - << "forecast/observation pairs. May be set as a list of file names " - << "(file_1 ... file_n) or as an ASCII file containing a list of " - << "file names (file_list). May be used multiple times (required)." + << "forecast/observation pairs (required).\n" + << "\t\t Set as a list of file names (file_1 ... file_n) or as an ASCII file list (file_list).\n" + << "\t\t May be used multiple times.\n" - << "\t\t\"-format type\" defines the input pairs file format " - << "and may be set to \"mpr\" or \"ioda\" (required).\n" + << "\t\t\"-format type\" defines the input pairs file format (required).\n" + << "\t\t May be set to \"mpr\", \"python\", or \"ioda\".\n" << "\t\t\"-config config_file\" is a PairStatConfig file containing " << "the desired configuration settings (required).\n" diff --git a/src/tools/core/pair_stat/pair_stat.h b/src/tools/core/pair_stat/pair_stat.h index 4186811a11..7949140745 100644 --- a/src/tools/core/pair_stat/pair_stat.h +++ b/src/tools/core/pair_stat/pair_stat.h @@ -136,10 +136,6 @@ static int i_txt_row[n_txt]; // /////////////////////////////////////////////////////////////////////////////// -// Grid variables -static Grid grid; -static bool is_first_pass = true; - // Data file factory and input files static Met2dDataFileFactory mtddf_factory; static Met2dDataFile *fcst_mtddf = (Met2dDataFile *) nullptr;