From b4741e78d13f94e17bec454d5147dbdfed0ccadc Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Tue, 5 Nov 2024 23:42:38 +0000 Subject: [PATCH] Per #3006, add new pair_stat tool as a full copy of the point_stat tool with all instances of point_stat renamed as pair_stat. --- .github/workflows/testing.yml | 2 +- config.h.in | 3 + configure | 46 +- configure.ac | 21 + data/config/Makefile.am | 1 + data/config/Makefile.in | 1 + data/config/PairStatConfig_default | 316 +++ docs/Users_Guide/index.rst | 1 + docs/Users_Guide/pair-stat.rst | 1634 ++++++++++++ internal/test_unit/bin/unit_test.sh | 1 + internal/test_unit/xml/unit_pair_stat.xml | 532 ++++ src/tools/core/Makefile.am | 4 + src/tools/core/Makefile.in | 13 +- src/tools/core/pair_stat/.gitignore | 6 + src/tools/core/pair_stat/Makefile.am | 50 + src/tools/core/pair_stat/Makefile.in | 728 +++++ src/tools/core/pair_stat/pair_stat.cc | 2376 +++++++++++++++++ src/tools/core/pair_stat/pair_stat.h | 162 ++ .../core/pair_stat/pair_stat_conf_info.cc | 1473 ++++++++++ .../core/pair_stat/pair_stat_conf_info.h | 312 +++ 20 files changed, 7675 insertions(+), 7 deletions(-) create mode 100644 data/config/PairStatConfig_default create mode 100644 docs/Users_Guide/pair-stat.rst create mode 100644 internal/test_unit/xml/unit_pair_stat.xml create mode 100644 src/tools/core/pair_stat/.gitignore create mode 100644 src/tools/core/pair_stat/Makefile.am create mode 100644 src/tools/core/pair_stat/Makefile.in create mode 100644 src/tools/core/pair_stat/pair_stat.cc create mode 100644 src/tools/core/pair_stat/pair_stat.h create mode 100644 src/tools/core/pair_stat/pair_stat_conf_info.cc create mode 100644 src/tools/core/pair_stat/pair_stat_conf_info.h diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 4e6e3872b7..58302f7d6f 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -301,7 +301,7 @@ jobs: matrix: include: - jobid: 'job1' - tests: 'point_stat stat_analysis_ps' + tests: 'point_stat pair_stat stat_analysis_ps' - jobid: 'job2' tests: 'grid_stat stat_analysis_gs' - jobid: 'job3' diff --git a/config.h.in b/config.h.in index 931b16f6f2..e66bc1d535 100644 --- a/config.h.in +++ b/config.h.in @@ -48,6 +48,9 @@ /* "build modis" */ #undef ENABLE_MODIS +/* "build pair_stat" */ +#undef ENABLE_PAIR_STAT + /* "build pb2nc" */ #undef ENABLE_PB2NC diff --git a/configure b/configure index 758f3502f6..8fa7ae8b65 100755 --- a/configure +++ b/configure @@ -711,6 +711,8 @@ ENABLE_WAVELET_STAT_FALSE ENABLE_WAVELET_STAT_TRUE ENABLE_STAT_ANALYSIS_FALSE ENABLE_STAT_ANALYSIS_TRUE +ENABLE_PAIR_STAT_FALSE +ENABLE_PAIR_STAT_TRUE ENABLE_POINT_STAT_FALSE ENABLE_POINT_STAT_TRUE ENABLE_PLOT_POINT_OBS_FALSE @@ -913,6 +915,7 @@ enable_point2grid enable_shift_data_plane enable_plot_point_obs enable_point_stat +enable_pair_stat enable_stat_analysis enable_wavelet_stat enable_series_analysis @@ -1645,6 +1648,7 @@ Optional Features: --disable-plot_point_obs Disable compilation of plot_point_obs --disable-point_stat Disable compilation of point_stat + --disable-pair_stat Disable compilation of pair_stat --disable-stat_analysis Disable compilation of stat_analysis --disable-wavelet_stat Disable compilation of wavelet_stat --disable-series_analysis @@ -6538,6 +6542,41 @@ else printf "%s\n" "$as_me: point_stat will not be compiled" >&6;} fi +# pair_stat + +# Check whether --enable-pair_stat was given. +if test ${enable_pair_stat+y} +then : + enableval=$enable_pair_stat; case "${enableval}" in + yes | no ) ENABLE_PAIR_STAT="${enableval}" ;; + *) as_fn_error $? "bad value ${enableval} for --disable-pair_stat" "$LINENO" 5 ;; + esac +else $as_nop + ENABLE_PAIR_STAT="yes" + +fi + + + if test "x$ENABLE_PAIR_STAT" = "xyes"; then + ENABLE_PAIR_STAT_TRUE= + ENABLE_PAIR_STAT_FALSE='#' +else + ENABLE_PAIR_STAT_TRUE='#' + ENABLE_PAIR_STAT_FALSE= +fi + + +if test "x$ENABLE_PAIR_STAT" = "xyes"; then + +printf "%s\n" "#define ENABLE_PAIR_STAT /**/" >>confdefs.h + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pair_stat will be compiled" >&5 +printf "%s\n" "$as_me: pair_stat will be compiled" >&6;} +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: pair_stat will not be compiled" >&5 +printf "%s\n" "$as_me: pair_stat will not be compiled" >&6;} +fi + # stat_analysis # Check whether --enable-stat_analysis was given. @@ -10158,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_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/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/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 @@ -10391,6 +10430,10 @@ if test -z "${ENABLE_POINT_STAT_TRUE}" && test -z "${ENABLE_POINT_STAT_FALSE}"; as_fn_error $? "conditional \"ENABLE_POINT_STAT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ENABLE_PAIR_STAT_TRUE}" && test -z "${ENABLE_PAIR_STAT_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_PAIR_STAT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${ENABLE_STAT_ANALYSIS_TRUE}" && test -z "${ENABLE_STAT_ANALYSIS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_STAT_ANALYSIS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -11129,6 +11172,7 @@ do "src/tools/core/mode_analysis/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/mode_analysis/Makefile" ;; "src/tools/core/pcp_combine/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/pcp_combine/Makefile" ;; "src/tools/core/point_stat/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/point_stat/Makefile" ;; + "src/tools/core/pair_stat/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/pair_stat/Makefile" ;; "src/tools/core/series_analysis/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/series_analysis/Makefile" ;; "src/tools/core/stat_analysis/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/stat_analysis/Makefile" ;; "src/tools/core/wavelet_stat/Makefile") CONFIG_FILES="$CONFIG_FILES src/tools/core/wavelet_stat/Makefile" ;; diff --git a/configure.ac b/configure.ac index 03436847af..23bbad7bbb 100644 --- a/configure.ac +++ b/configure.ac @@ -898,6 +898,26 @@ else AC_MSG_NOTICE([point_stat will not be compiled]) fi +# pair_stat + +AC_ARG_ENABLE(pair_stat, + [AS_HELP_STRING([--disable-pair_stat], [Disable compilation of pair_stat])], + [case "${enableval}" in + yes | no ) ENABLE_PAIR_STAT="${enableval}" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --disable-pair_stat) ;; + esac], + [ENABLE_PAIR_STAT="yes"] +) + +AM_CONDITIONAL([ENABLE_PAIR_STAT], [test "x$ENABLE_PAIR_STAT" = "xyes"]) + +if test "x$ENABLE_PAIR_STAT" = "xyes"; then + AC_DEFINE([ENABLE_PAIR_STAT], [], ["build pair_stat"]) + AC_MSG_NOTICE([pair_stat will be compiled]) +else + AC_MSG_NOTICE([pair_stat will not be compiled]) +fi + # stat_analysis AC_ARG_ENABLE(stat_analysis, @@ -1378,6 +1398,7 @@ AC_CONFIG_FILES([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 diff --git a/data/config/Makefile.am b/data/config/Makefile.am index f6ed69c168..52f05a1734 100644 --- a/data/config/Makefile.am +++ b/data/config/Makefile.am @@ -34,6 +34,7 @@ config_DATA = \ MTDConfig_default \ PB2NCConfig_default \ PointStatConfig_default \ + PairStatConfig_default \ SeriesAnalysisConfig_default \ STATAnalysisConfig_default \ STATAnalysisConfig_GO_Index \ diff --git a/data/config/Makefile.in b/data/config/Makefile.in index 6ff5c30139..76cdeca692 100644 --- a/data/config/Makefile.in +++ b/data/config/Makefile.in @@ -325,6 +325,7 @@ config_DATA = \ MTDConfig_default \ PB2NCConfig_default \ PointStatConfig_default \ + PairStatConfig_default \ SeriesAnalysisConfig_default \ STATAnalysisConfig_default \ STATAnalysisConfig_GO_Index \ diff --git a/data/config/PairStatConfig_default b/data/config/PairStatConfig_default new file mode 100644 index 0000000000..41cb1ce774 --- /dev/null +++ b/data/config/PairStatConfig_default @@ -0,0 +1,316 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Pair-Stat configuration file. +// +// For additional information, please see the MET User's Guide. +// +//////////////////////////////////////////////////////////////////////////////// + +// +// Output model name to be written +// +model = "FCST"; + +// +// Output description to be written +// May be set separately in each "obs.field" entry +// +desc = "NA"; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification grid +// May be set separately in each "field" entry +// +regrid = { + to_grid = NONE; + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// May be set separately in each "field" entry +// +censor_thresh = []; +censor_val = []; +mpr_column = []; +mpr_thresh = []; +cat_thresh = [ NA ]; +cnt_thresh = [ NA ]; +cnt_logic = UNION; +wind_thresh = [ NA ]; +wind_logic = UNION; +eclv_points = 0.05; +hss_ec_value = NA; +rank_corr_flag = FALSE; + +// +// Forecast and observation fields to be verified +// +fcst = { + field = [ + { + name = "SPFH"; + level = [ "P500" ]; + cat_thresh = [ >80.0 ]; + }, + + { + name = "TMP"; + level = [ "P500" ]; + cat_thresh = [ >273.0 ]; + }, + + { + name = "HGT"; + level = [ "P500" ]; + cat_thresh = [ >0.0 ]; + }, + + { + name = "UGRD"; + level = [ "P500" ]; + cat_thresh = [ >5.0 ]; + }, + + { + name = "VGRD"; + level = [ "P500" ]; + cat_thresh = [ >5.0 ]; + } + ]; + +} +obs = fcst; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Point observation filtering options +// May be set separately in each "obs.field" entry +// +message_type = [ "ADPUPA" ]; +sid_inc = []; +sid_exc = []; +obs_quality_inc = []; +obs_quality_exc = []; +duplicate_flag = NONE; +obs_summary = NONE; +obs_perc_value = 50; + +// +// 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"; } +]; + +obtype_as_group_val_flag = FALSE; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Climatology mean data +// May be set separately in the "fcst" and "obs" dictionaries +// +climo_mean = { + + file_name = []; + field = []; + + regrid = { + method = NEAREST; + width = 1; + vld_thresh = 0.5; + shape = SQUARE; + } + + time_interp_method = DW_MEAN; + day_interval = 31; + hour_interval = 6; +} + +// +// Climatology standard deviation data +// May be set separately in the "fcst" and "obs" dictionaries +// +climo_stdev = climo_mean; +climo_stdev = { + file_name = []; +} + +// +// Climatology distribution settings +// May be set separately in each "obs.field" entry +// +climo_cdf = { + cdf_bins = 1; + center_bins = FALSE; + write_bins = TRUE; + direct_prob = FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// 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.field" 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.field" 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.field" entry +// +obs_window = { + beg = -5400; + end = 5400; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Verification masking regions +// May be set separately in each "obs.field" entry +// +mask = { + grid = [ "FULL" ]; + poly = []; + sid = []; + llpnt = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Confidence interval settings +// May be set separately in each "obs.field" entry +// +ci_alpha = [ 0.05 ]; + +boot = { + interval = PCTILE; + rep_prop = 1.0; + n_rep = 0; + rng = "mt19937"; + seed = ""; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Interpolation methods +// May be set separately in each "obs.field" entry +// +interp = { + vld_thresh = 1.0; + shape = SQUARE; + + type = [ + { + method = NEAREST; + width = 1; + } + ]; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// HiRA verification method +// May be set separately in each "obs.field" entry +// +hira = { + flag = FALSE; + width = [ 2, 3, 4, 5 ]; + vld_thresh = 1.0; + cov_thresh = [ ==0.25 ]; + shape = SQUARE; + prob_cat_thresh = []; +} + +//////////////////////////////////////////////////////////////////////////////// + +// +// Threshold for SEEPS p1 (Probability of being dry) +// +seeps_p1_thresh = >=0.1&&<=0.85; + +//////////////////////////////////////////////////////////////////////////////// + +// +// Statistical output types +// May be set separately in each "obs.field" entry +// +output_flag = { + fho = NONE; + ctc = NONE; + cts = NONE; + mctc = NONE; + mcts = NONE; + cnt = NONE; + sl1l2 = NONE; + sal1l2 = NONE; + vl1l2 = NONE; + val1l2 = NONE; + vcnt = NONE; + pct = NONE; + pstd = NONE; + pjc = NONE; + prc = NONE; + ecnt = NONE; // Only for HiRA. + orank = NONE; // Only for HiRA. + rps = NONE; // Only for HiRA. + eclv = NONE; + mpr = NONE; + seeps = NONE; + seeps_mpr = NONE; +} + +//////////////////////////////////////////////////////////////////////////////// + +point_weight_flag = NONE; + +tmp_dir = "/tmp"; +output_prefix = ""; +version = "V12.0.0"; + +//////////////////////////////////////////////////////////////////////////////// diff --git a/docs/Users_Guide/index.rst b/docs/Users_Guide/index.rst index 1df5c65e53..5b72cd0733 100644 --- a/docs/Users_Guide/index.rst +++ b/docs/Users_Guide/index.rst @@ -54,6 +54,7 @@ The National Center for Atmospheric Research (NCAR) is sponsored by NSF. The DTC gen-ens-prod masking point-stat + pair-stat grid-stat ensemble-stat wavelet-stat diff --git a/docs/Users_Guide/pair-stat.rst b/docs/Users_Guide/pair-stat.rst new file mode 100644 index 0000000000..c470209c0c --- /dev/null +++ b/docs/Users_Guide/pair-stat.rst @@ -0,0 +1,1634 @@ +.. _pair-stat: + +*************** +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. + +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 +================================== + +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: + +Practical Information +===================== + +The Pair-Stat tool is used to perform verification of a gridded model field using point observations. The gridded model field to be verified must be in one of the supported file formats. The point observations must be formatted as the NetCDF output of the point reformatting tools described in :numref:`reformat_point`. The Pair-Stat tool provides the capability of interpolating the gridded forecast data to the observation points using a variety of methods as described in :numref:`matching-methods`. The Pair-Stat tool computes a number of continuous statistics on the matched pair data as well as discrete statistics once the matched pair data have been thresholded. + +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] + [-outdir path] + [-log file] + [-v level] + +pair_stat has three required arguments and can take many 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. + +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`. + +3. The **config_file** argument indicates the name of the configuration file to be used. The contents of the configuration file are discussed below. + +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. + +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. + +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. + +An example of the pair_stat calling sequence is shown below: + +.. code-block:: none + + pair_stat sample_fcst.grb \ + sample_pb.nc \ + PointStatConfig + +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**. + +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. + +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`. diff --git a/internal/test_unit/bin/unit_test.sh b/internal/test_unit/bin/unit_test.sh index e3bc29e181..4b2f52db60 100755 --- a/internal/test_unit/bin/unit_test.sh +++ b/internal/test_unit/bin/unit_test.sh @@ -45,6 +45,7 @@ UNIT_XML="unit_ascii2nc.xml \ unit_pcp_combine.xml \ unit_wwmca_regrid.xml \ unit_point_stat.xml \ + unit_pair_stat.xml \ unit_stat_analysis_ps.xml \ unit_duplicate_flag.xml \ unit_obs_summary.xml \ diff --git a/internal/test_unit/xml/unit_pair_stat.xml b/internal/test_unit/xml/unit_pair_stat.xml new file mode 100644 index 0000000000..2bb99c796e --- /dev/null +++ b/internal/test_unit/xml/unit_pair_stat.xml @@ -0,0 +1,532 @@ + + + + + + + + + + +]> + + + + + + + + + &TEST_DIR; + true + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + MASK_POLY_FILE &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib {name=\"LAND\";level=\"L0\";} + OUTPUT_PREFIX GRIB1_NAM_GDAS + CONFIG_DIR &CONFIG_DIR; + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_PHYS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_sl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_sal1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_vl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_val1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_vcnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_120000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + OUTPUT_PREFIX GRIB1_NAM_GDAS_WINDS + CONFIG_DIR &CONFIG_DIR; + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_WINDS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_WINDS_120000L_20120409_120000V.stat + + + + + &MET_BIN;/pair_stat + + BEG_DS -300 + END_DS 300 + OUTPUT_PREFIX GRIB1_NAM_GDAS_MPR_OBTYPE + CONFIG_DIR &CONFIG_DIR; + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_MPR_OBTYPE \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MPR_OBTYPE_120000L_20120409_120000V.stat + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + OUTPUT_PREFIX GRIB1_NAM_GDAS_MASK_SID + CONFIG_DIR &CONFIG_DIR; + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_MASK_SID \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_sl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_sal1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_vl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_val1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_vcnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_MASK_SID_120000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + MASK_POLY_FILE &DATA_DIR_MODEL;/grib2/nam/nam_2012040900_F012.grib2 {name=\"LAND\";level=\"L0\";} + OUTPUT_PREFIX GRIB2_NAM_NDAS + CLIMO_FILE "&DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F012_gNam.grib2" + + \ + &DATA_DIR_MODEL;/grib2/nam/nam_2012040900_F012.grib2 \ + &OUTPUT_DIR;/pb2nc/ndas.20120409.t12z.prepbufr.tm00.nc \ + &CONFIG_DIR;/PairStatConfig_PHYS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_sl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_sal1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_vl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_val1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_vcnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_NAM_NDAS_120000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + MASK_POLY_FILE &DATA_DIR_MODEL;/grib2/sref_mn/sref_mean_2012040821_F015.grib2 {name=\"TMP\";level=\"Z2\";} <280 + OUTPUT_PREFIX GRIB2_SREF_GDAS + CLIMO_FILE + + \ + &DATA_DIR_MODEL;/grib2/sref_mn/sref_mean_2012040821_F015.grib2 \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_PHYS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_sl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_vl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_vcnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_GDAS_150000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + FCST_FIELD_NAME APCP + FCST_FIELD_LEVEL A3 + OBS_DICT fcst + OUTPUT_PREFIX GRIB1_NAM_TRMM + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/ascii2nc/trmm_2012040912_3hr.nc \ + &CONFIG_DIR;/PairStatConfig_APCP \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_TRMM_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_TRMM_120000L_20120409_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_TRMM_120000L_20120409_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_TRMM_120000L_20120409_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_TRMM_120000L_20120409_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_TRMM_120000L_20120409_120000V_sl1l2.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + FCST_FIELD_NAME APCP + FCST_FIELD_LEVEL A3 + OBS_DICT fcst + OUTPUT_PREFIX GRIB2_SREF_TRMM + + \ + &DATA_DIR_MODEL;/grib2/sref_mn/sref_mean_2012040821_F012.grib2 \ + &OUTPUT_DIR;/ascii2nc/trmm_2012040912_3hr.nc \ + &CONFIG_DIR;/PairStatConfig_APCP \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_150000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_150000L_20120409_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_150000L_20120409_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_150000L_20120409_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_150000L_20120409_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_150000L_20120409_120000V_sl1l2.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + FCST_FIELD_NAME APCP_24 + FCST_FIELD_LEVEL (*,*) + OBS_DICT { field = [ { name = "APCP"; level = "A24"; } ]; } + OUTPUT_PREFIX NCMET_NAM_HMTGAGE + + \ + &DATA_DIR_MODEL;/met_nc/nam/nam_2012040900_F036_APCP24.nc \ + &OUTPUT_DIR;/ascii2nc/gauge_2012041012_24hr.nc \ + &CONFIG_DIR;/PairStatConfig_APCP \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_HMTGAGE_360000L_20120410_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_HMTGAGE_360000L_20120410_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_HMTGAGE_360000L_20120410_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_HMTGAGE_360000L_20120410_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_HMTGAGE_360000L_20120410_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_HMTGAGE_360000L_20120410_120000V_sl1l2.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + FCST_FIELD_NAME APCP_24 + FCST_FIELD_LEVEL (*,*) + OBS_DICT { field = [ { name = "TP24"; level = "L0"; is_precipitation = TRUE; } ]; } + SEEPS_P1_THRESH ge0.1&&le0.85 + SEEPS_POINT_CLIMO_NAME + OUTPUT_PREFIX NCMET_NAM_NDAS_SEEPS + + \ + &DATA_DIR_MODEL;/met_nc/nam/nam_2012040900_F036_APCP24.nc \ + &OUTPUT_DIR;/pb2nc/ndas.20120410.t12z.prepbufr.tm00.nc \ + &CONFIG_DIR;/PairStatConfig_SEEPS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_sl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_seeps.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCMET_NAM_NDAS_SEEPS_360000L_20120410_120000V_seeps_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 150000000 + FCST_FIELD_NAME RAINNC + FCST_FIELD_LEVEL (0,*,*) + OBS_DICT { field = [ { name = "APCP"; level = "A3"; } ]; } + SEEPS_FLAG NONE + SEEPS_P1_THRESH NA + OUTPUT_PREFIX NCPINT_TRMM + + \ + &DATA_DIR_MODEL;/p_interp/wrfout_d01_2008-08-08_12:00:00_PLEV \ + &OUTPUT_DIR;/ascii2nc/trmm_2012040912_3hr.nc \ + &CONFIG_DIR;/PairStatConfig_APCP \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_TRMM_240000L_20080808_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_TRMM_240000L_20080808_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_TRMM_240000L_20080808_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_TRMM_240000L_20080808_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_TRMM_240000L_20080808_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_TRMM_240000L_20080808_120000V_sl1l2.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 150000000 + OUTPUT_PREFIX NCPINT_NDAS + + \ + &DATA_DIR_MODEL;/p_interp/wrfout_d01_2008-08-08_12:00:00_PLEV \ + &OUTPUT_DIR;/pb2nc/ndas.20120409.t12z.prepbufr.tm00.nc \ + &CONFIG_DIR;/PairStatConfig_PHYS_pint \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_NDAS_240000L_20080808_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_NDAS_240000L_20080808_120000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_NDAS_240000L_20080808_120000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_NDAS_240000L_20080808_120000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_NDAS_240000L_20080808_120000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_NCPINT_NDAS_240000L_20080808_120000V_sl1l2.txt + + + + + &MET_BIN;/pair_stat + + OUTPUT_PREFIX GRIB2_SREF_TRMM_prob + + \ + &DATA_DIR_MODEL;/grib2/sref_pr/sref_prob_2012040821_F015.grib2 \ + &OUTPUT_DIR;/ascii2nc/trmm_2012040912_3hr.nc \ + &CONFIG_DIR;/PairStatConfig_prob \ + -outdir &OUTPUT_DIR;/pair_stat -v 4 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_prob_150000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_prob_150000L_20120409_120000V_pct.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_prob_150000L_20120409_120000V_pstd.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_prob_150000L_20120409_120000V_pjc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB2_SREF_TRMM_prob_150000L_20120409_120000V_prc.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -5400 + END_DS 5400 + OUTPUT_PREFIX GTG_lc + + \ + &DATA_DIR_MODEL;/nccf/gtg/lc/gtg_obs_forecast.20130827.i12.f03.nc \ + &OUTPUT_DIR;/ascii2nc/edr_hourly.20130827.nc \ + &CONFIG_DIR;/PairStatConfig_GTG_lc \ + -outdir &OUTPUT_DIR;/pair_stat -v 4 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_lc_030000L_20130827_150000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_lc_030000L_20130827_150000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_lc_030000L_20130827_150000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_lc_030000L_20130827_150000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_lc_030000L_20130827_150000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_lc_030000L_20130827_150000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -5400 + END_DS 5400 + OUTPUT_PREFIX GTG_latlon + + \ + &DATA_DIR_MODEL;/nccf/gtg/latlon/gtg_obs_forecast.20130827.i12.f06.nc \ + &OUTPUT_DIR;/ascii2nc/edr_hourly.20130827.nc \ + &CONFIG_DIR;/PairStatConfig_GTG_latlon \ + -outdir &OUTPUT_DIR;/pair_stat -v 4 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_latlon_060000L_20130827_180000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_latlon_060000L_20130827_180000V_cnt.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_latlon_060000L_20130827_180000V_ctc.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_latlon_060000L_20130827_180000V_cts.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_latlon_060000L_20130827_180000V_fho.txt + &OUTPUT_DIR;/pair_stat/pair_stat_GTG_latlon_060000L_20130827_180000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + CENSOR_THRESH + CENSOR_VAL + OUTPUT_PREFIX SID_INC_EXC + CONFIG_DIR &CONFIG_DIR; + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_sid_inc_exc \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_SID_INC_EXC_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_SID_INC_EXC_120000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + BEG_DS -1800 + END_DS 1800 + CENSOR_THRESH lt-3.0, gt3.0 + CENSOR_VAL -3.0, 3.0 + OUTPUT_PREFIX SID_INC_EXC_CENSOR + CONFIG_DIR &CONFIG_DIR; + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_sid_inc_exc \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_SID_INC_EXC_CENSOR_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_SID_INC_EXC_CENSOR_120000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + OUTPUT_PREFIX GRIB1_NAM_GDAS_INTERP_OPTS + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_INTERP_OPTS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_INTERP_OPTS_120000L_20120409_120000V.stat + + + + + &MET_BIN;/pair_stat + + OUTPUT_PREFIX GRIB1_NAM_GDAS_INTERP_OPTS_name + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/ascii2nc/gdas1.20120409.t12z.prepbufr.ascii_name.nc \ + &CONFIG_DIR;/PairStatConfig_INTERP_OPTS \ + -outdir &OUTPUT_DIR;/pair_stat -v 1 + + + &OUTPUT_DIR;/pair_stat/pair_stat_GRIB1_NAM_GDAS_INTERP_OPTS_name_120000L_20120409_120000V.stat + + + + + &MET_BIN;/pair_stat + + GEOG_FILE "&DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib" + CLIMO_FILE "&DATA_DIR_MODEL;/grib1/gfs/gfs_2012040900_F012_gNam.grib" + OUTPUT_PREFIX LAND_TOPO_MASK + + \ + &DATA_DIR_MODEL;/grib1/nam/nam_2012040900_F012.grib \ + &OUTPUT_DIR;/pb2nc/gdas1.20120409.t12z.prepbufr.nc \ + &CONFIG_DIR;/PairStatConfig_LAND_TOPO_MASK \ + -outdir &OUTPUT_DIR;/pair_stat -v 2 + + + &OUTPUT_DIR;/pair_stat/pair_stat_LAND_TOPO_MASK_120000L_20120409_120000V.stat + &OUTPUT_DIR;/pair_stat/pair_stat_LAND_TOPO_MASK_120000L_20120409_120000V_sl1l2.txt + &OUTPUT_DIR;/pair_stat/pair_stat_LAND_TOPO_MASK_120000L_20120409_120000V_mpr.txt + + + + + &MET_BIN;/pair_stat + + OUTPUT_PREFIX MPR_THRESH + DAY_INTERVAL 1 + HOUR_INTERVAL 6 + CLIMO_MEAN_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cmean_1d.19590409" + + + CLIMO_STDEV_FILE_LIST + "&DATA_DIR_CLIMO;/NCEP_NCAR_40YR_1.0deg/cstdv_1d.19590409" + + + + \ + &DATA_DIR_MODEL;/grib2/gfs/gfs_2012040900_F012.grib2 \ + &OUTPUT_DIR;/pb2nc/ndas.20120409.t12z.prepbufr.tm00.nc \ + &CONFIG_DIR;/PairStatConfig_mpr_thresh \ + -outdir &OUTPUT_DIR;/pair_stat -v 3 + + + &OUTPUT_DIR;/pair_stat/pair_stat_MPR_THRESH_120000L_20120409_120000V.stat + + + + diff --git a/src/tools/core/Makefile.am b/src/tools/core/Makefile.am index 91fd210cf0..5372ec7474 100644 --- a/src/tools/core/Makefile.am +++ b/src/tools/core/Makefile.am @@ -42,6 +42,10 @@ if ENABLE_POINT_STAT SUBDIRS += point_stat endif +if ENABLE_PAIR_STAT + SUBDIRS += pair_stat +endif + if ENABLE_STAT_ANALYSIS SUBDIRS += stat_analysis endif diff --git a/src/tools/core/Makefile.in b/src/tools/core/Makefile.in index cacc9eabec..cd0038cec6 100644 --- a/src/tools/core/Makefile.in +++ b/src/tools/core/Makefile.in @@ -93,9 +93,10 @@ host_triplet = @host@ @ENABLE_MODE_ANALYSIS_TRUE@am__append_4 = mode_analysis @ENABLE_PCP_COMBINE_TRUE@am__append_5 = pcp_combine @ENABLE_POINT_STAT_TRUE@am__append_6 = point_stat -@ENABLE_STAT_ANALYSIS_TRUE@am__append_7 = stat_analysis -@ENABLE_WAVELET_STAT_TRUE@am__append_8 = wavelet_stat -@ENABLE_SERIES_ANALYSIS_TRUE@am__append_9 = series_analysis +@ENABLE_PAIR_STAT_TRUE@am__append_7 = pair_stat +@ENABLE_STAT_ANALYSIS_TRUE@am__append_8 = stat_analysis +@ENABLE_WAVELET_STAT_TRUE@am__append_9 = wavelet_stat +@ENABLE_SERIES_ANALYSIS_TRUE@am__append_10 = series_analysis subdir = src/tools/core ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac @@ -159,7 +160,8 @@ am__define_uniq_tagged_files = \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = ensemble_stat grid_stat mode mode_analysis pcp_combine \ - point_stat stat_analysis wavelet_stat series_analysis + point_stat pair_stat stat_analysis wavelet_stat \ + series_analysis am__DIST_COMMON = $(srcdir)/Makefile.in DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ @@ -348,7 +350,8 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) \ - $(am__append_7) $(am__append_8) $(am__append_9) + $(am__append_7) $(am__append_8) $(am__append_9) \ + $(am__append_10) MAINTAINERCLEANFILES = Makefile.in all: all-recursive diff --git a/src/tools/core/pair_stat/.gitignore b/src/tools/core/pair_stat/.gitignore new file mode 100644 index 0000000000..547b0cdd41 --- /dev/null +++ b/src/tools/core/pair_stat/.gitignore @@ -0,0 +1,6 @@ +pair_stat +*.o +*.a +.deps +Makefile +*.dSYM diff --git a/src/tools/core/pair_stat/Makefile.am b/src/tools/core/pair_stat/Makefile.am new file mode 100644 index 0000000000..8d462aabfa --- /dev/null +++ b/src/tools/core/pair_stat/Makefile.am @@ -0,0 +1,50 @@ +## @start 1 +## Makefile.am -- Process this file with automake to produce Makefile.in +## @end 1 + +MAINTAINERCLEANFILES = Makefile.in + +# Include the project definitions + +include ${top_srcdir}/Make-include + +# The program + +bin_PROGRAMS = pair_stat +pair_stat_SOURCES = pair_stat.cc \ + pair_stat_conf_info.cc +pair_stat_CPPFLAGS = ${MET_CPPFLAGS} +pair_stat_LDFLAGS = ${MET_LDFLAGS} +pair_stat_LDADD = -lvx_stat_out \ + -lvx_statistics \ + -lvx_shapedata \ + -lvx_analysis_util \ + -lvx_data2d_factory \ + -lvx_data2d_nc_met \ + -lvx_data2d_grib \ + $(GRIB2_MET_LIBS) \ + -lvx_data2d_nc_wrf \ + -lvx_data2d_nc_cf \ + $(UGRID_MET_LIBS) \ + $(PYTHON_MET_LIBS) \ + -lvx_data2d \ + -lvx_nc_obs \ + -lvx_seeps \ + -lvx_nc_util \ + -lvx_regrid \ + -lvx_grid \ + -lvx_geodesy \ + -lvx_seeps \ + -lvx_config \ + -lvx_gsl_prob \ + -lvx_color \ + -lvx_util_math \ + -lvx_util \ + -lvx_math \ + -lvx_cal \ + -lvx_log \ + $(GRIB2_DEP_LIBS) $(UGRID_DEP_LIBS) $(PYTHON_DEP_LIBS) \ + -lm -lproj -lnetcdf_c++4 -lnetcdf -lgsl -lgslcblas + +EXTRA_DIST = pair_stat.h \ + pair_stat_conf_info.h diff --git a/src/tools/core/pair_stat/Makefile.in b/src/tools/core/pair_stat/Makefile.in new file mode 100644 index 0000000000..e3bd911ba1 --- /dev/null +++ b/src/tools/core/pair_stat/Makefile.in @@ -0,0 +1,728 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = pair_stat$(EXEEXT) +subdir = src/tools/core/pair_stat +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_pair_stat_OBJECTS = pair_stat-pair_stat.$(OBJEXT) \ + pair_stat-pair_stat_conf_info.$(OBJEXT) +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) +pair_stat_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ + $(pair_stat_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/pair_stat-pair_stat.Po \ + ./$(DEPDIR)/pair_stat-pair_stat_conf_info.Po +am__mv = mv -f +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(pair_stat_SOURCES) +DIST_SOURCES = $(pair_stat_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BUFRLIB_NAME = @BUFRLIB_NAME@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FC_LIBS = @FC_LIBS@ +FFLAGS = @FFLAGS@ +FLIBS = @FLIBS@ +GRIB2CLIB_NAME = @GRIB2CLIB_NAME@ +GRIB2_DEP_LIBS = @GRIB2_DEP_LIBS@ +GRIB2_MET_LIBS = @GRIB2_MET_LIBS@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LEX = @LEX@ +LEXLIB = @LEXLIB@ +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MET_ATLAS = @MET_ATLAS@ +MET_ATLASINC = @MET_ATLASINC@ +MET_ATLASLIB = @MET_ATLASLIB@ +MET_BUFR = @MET_BUFR@ +MET_BUFRLIB = @MET_BUFRLIB@ +MET_CAIRO = @MET_CAIRO@ +MET_CAIROINC = @MET_CAIROINC@ +MET_CAIROLIB = @MET_CAIROLIB@ +MET_CXX_STANDARD = @MET_CXX_STANDARD@ +MET_ECKIT = @MET_ECKIT@ +MET_ECKITINC = @MET_ECKITINC@ +MET_ECKITLIB = @MET_ECKITLIB@ +MET_FREETYPE = @MET_FREETYPE@ +MET_FREETYPEINC = @MET_FREETYPEINC@ +MET_FREETYPELIB = @MET_FREETYPELIB@ +MET_GRIB2C = @MET_GRIB2C@ +MET_GRIB2CINC = @MET_GRIB2CINC@ +MET_GRIB2CLIB = @MET_GRIB2CLIB@ +MET_GSL = @MET_GSL@ +MET_GSLINC = @MET_GSLINC@ +MET_GSLLIB = @MET_GSLLIB@ +MET_HDF = @MET_HDF@ +MET_HDF5 = @MET_HDF5@ +MET_HDF5INC = @MET_HDF5INC@ +MET_HDF5LIB = @MET_HDF5LIB@ +MET_HDFEOS = @MET_HDFEOS@ +MET_HDFEOSINC = @MET_HDFEOSINC@ +MET_HDFEOSLIB = @MET_HDFEOSLIB@ +MET_HDFINC = @MET_HDFINC@ +MET_HDFLIB = @MET_HDFLIB@ +MET_NETCDF = @MET_NETCDF@ +MET_NETCDFINC = @MET_NETCDFINC@ +MET_NETCDFLIB = @MET_NETCDFLIB@ +MET_PROJ = @MET_PROJ@ +MET_PROJINC = @MET_PROJINC@ +MET_PROJLIB = @MET_PROJLIB@ +MET_PYTHON_BIN_EXE = @MET_PYTHON_BIN_EXE@ +MET_PYTHON_CC = @MET_PYTHON_CC@ +MET_PYTHON_LD = @MET_PYTHON_LD@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +OPENMP_CFLAGS = @OPENMP_CFLAGS@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PYTHON_DEP_LIBS = @PYTHON_DEP_LIBS@ +PYTHON_MET_LIBS = @PYTHON_MET_LIBS@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +UGRID_DEP_LIBS = @UGRID_DEP_LIBS@ +UGRID_MET_LIBS = @UGRID_MET_LIBS@ +VERSION = @VERSION@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +MAINTAINERCLEANFILES = Makefile.in +pair_stat_SOURCES = pair_stat.cc \ + pair_stat_conf_info.cc + +pair_stat_CPPFLAGS = ${MET_CPPFLAGS} +pair_stat_LDFLAGS = ${MET_LDFLAGS} +pair_stat_LDADD = -lvx_stat_out \ + -lvx_statistics \ + -lvx_shapedata \ + -lvx_analysis_util \ + -lvx_data2d_factory \ + -lvx_data2d_nc_met \ + -lvx_data2d_grib \ + $(GRIB2_MET_LIBS) \ + -lvx_data2d_nc_wrf \ + -lvx_data2d_nc_cf \ + $(UGRID_MET_LIBS) \ + $(PYTHON_MET_LIBS) \ + -lvx_data2d \ + -lvx_nc_obs \ + -lvx_seeps \ + -lvx_nc_util \ + -lvx_regrid \ + -lvx_grid \ + -lvx_geodesy \ + -lvx_seeps \ + -lvx_config \ + -lvx_gsl_prob \ + -lvx_color \ + -lvx_util_math \ + -lvx_util \ + -lvx_math \ + -lvx_cal \ + -lvx_log \ + $(GRIB2_DEP_LIBS) $(UGRID_DEP_LIBS) $(PYTHON_DEP_LIBS) \ + -lm -lproj -lnetcdf_c++4 -lnetcdf -lgsl -lgslcblas + +EXTRA_DIST = pair_stat.h \ + pair_stat_conf_info.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cc .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/tools/core/pair_stat/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/tools/core/pair_stat/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +pair_stat$(EXEEXT): $(pair_stat_OBJECTS) $(pair_stat_DEPENDENCIES) $(EXTRA_pair_stat_DEPENDENCIES) + @rm -f pair_stat$(EXEEXT) + $(AM_V_CXXLD)$(pair_stat_LINK) $(pair_stat_OBJECTS) $(pair_stat_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pair_stat-pair_stat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pair_stat-pair_stat_conf_info.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +pair_stat-pair_stat.o: pair_stat.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pair_stat-pair_stat.o -MD -MP -MF $(DEPDIR)/pair_stat-pair_stat.Tpo -c -o pair_stat-pair_stat.o `test -f 'pair_stat.cc' || echo '$(srcdir)/'`pair_stat.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pair_stat-pair_stat.Tpo $(DEPDIR)/pair_stat-pair_stat.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pair_stat.cc' object='pair_stat-pair_stat.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) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pair_stat-pair_stat.o `test -f 'pair_stat.cc' || echo '$(srcdir)/'`pair_stat.cc + +pair_stat-pair_stat.obj: pair_stat.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pair_stat-pair_stat.obj -MD -MP -MF $(DEPDIR)/pair_stat-pair_stat.Tpo -c -o pair_stat-pair_stat.obj `if test -f 'pair_stat.cc'; then $(CYGPATH_W) 'pair_stat.cc'; else $(CYGPATH_W) '$(srcdir)/pair_stat.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pair_stat-pair_stat.Tpo $(DEPDIR)/pair_stat-pair_stat.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pair_stat.cc' object='pair_stat-pair_stat.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) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pair_stat-pair_stat.obj `if test -f 'pair_stat.cc'; then $(CYGPATH_W) 'pair_stat.cc'; else $(CYGPATH_W) '$(srcdir)/pair_stat.cc'; fi` + +pair_stat-pair_stat_conf_info.o: pair_stat_conf_info.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pair_stat-pair_stat_conf_info.o -MD -MP -MF $(DEPDIR)/pair_stat-pair_stat_conf_info.Tpo -c -o pair_stat-pair_stat_conf_info.o `test -f 'pair_stat_conf_info.cc' || echo '$(srcdir)/'`pair_stat_conf_info.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pair_stat-pair_stat_conf_info.Tpo $(DEPDIR)/pair_stat-pair_stat_conf_info.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pair_stat_conf_info.cc' object='pair_stat-pair_stat_conf_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) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pair_stat-pair_stat_conf_info.o `test -f 'pair_stat_conf_info.cc' || echo '$(srcdir)/'`pair_stat_conf_info.cc + +pair_stat-pair_stat_conf_info.obj: pair_stat_conf_info.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pair_stat-pair_stat_conf_info.obj -MD -MP -MF $(DEPDIR)/pair_stat-pair_stat_conf_info.Tpo -c -o pair_stat-pair_stat_conf_info.obj `if test -f 'pair_stat_conf_info.cc'; then $(CYGPATH_W) 'pair_stat_conf_info.cc'; else $(CYGPATH_W) '$(srcdir)/pair_stat_conf_info.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pair_stat-pair_stat_conf_info.Tpo $(DEPDIR)/pair_stat-pair_stat_conf_info.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pair_stat_conf_info.cc' object='pair_stat-pair_stat_conf_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) $(pair_stat_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pair_stat-pair_stat_conf_info.obj `if test -f 'pair_stat_conf_info.cc'; then $(CYGPATH_W) 'pair_stat_conf_info.cc'; else $(CYGPATH_W) '$(srcdir)/pair_stat_conf_info.cc'; fi` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/pair_stat-pair_stat.Po + -rm -f ./$(DEPDIR)/pair_stat-pair_stat_conf_info.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/pair_stat-pair_stat.Po + -rm -f ./$(DEPDIR)/pair_stat-pair_stat_conf_info.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ + distclean distclean-compile distclean-generic distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-binPROGRAMS install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS + +.PRECIOUS: Makefile + + +# Include the project definitions + +include ${top_srcdir}/Make-include + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tools/core/pair_stat/pair_stat.cc b/src/tools/core/pair_stat/pair_stat.cc new file mode 100644 index 0000000000..ae51dd8cd3 --- /dev/null +++ b/src/tools/core/pair_stat/pair_stat.cc @@ -0,0 +1,2376 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2024 +// ** University Corporation for Atmospheric Research led(UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + +//////////////////////////////////////////////////////////////////////// +// +// Filename: pair_stat.cc +// +// Description: +// Based on user-specified parameters, this tool compares a +// a gridded forecast field to the point observation output of +// the point pre-processing tools. It computes many verification +// scores and statistics, including confidence intervals, to +// summarize the comparison. +// +// Mod# Date Name Description +// ---- ---- ---- ----------- +// 000 04/18/07 Halley Gotway New +// 001 12/20/07 Halley Gotway Allow verification for level 0 +// for verifying PRMSL +// 002 01/24/08 Halley Gotway In compute_cnt, print a warning +// message when bad data values are encountered. +// 003 01/24/08 Halley Gotway Add support for writing the matched +// pair data to the MPR file. +// 004 02/04/08 Halley Gotway Modify to read new format of the +// intermediate NetCDF point-observation format. +// 005 02/11/08 Halley Gotway Remove BIAS from the CNT line +// since it's the same as the ME. +// 006 02/12/08 Halley Gotway Fix bug in writing COP line to +// write out OY and ON rather than FY and FN. +// 007 02/12/08 Halley Gotway Enable Point-Stat to read the +// NetCDF output of PCP-Combine. +// 008 02/25/08 Halley Gotway Write the output lines using the +// routines in the vx_met_util library. +// 009 07/01/08 Halley Gotway Add the rank_corr_flag to the +// config file to disable computing rank correlations. +// 010 07/18/08 Halley Gotway Fix bug in the write_mpr routine. +// Replace i_fho with i_mpr. +// 011 09/23/08 Halley Gotway Change argument sequence for the +// GRIB record access routines. +// 012 11/03/08 Halley Gotway Use the get_file_type routine to +// determine the input file types. +// 013 03/13/09 Halley Gotway Add support for verifying +// probabilistic forecasts. +// 014 04/21/09 Halley Gotway Fix bug for resetting obs_var. +// 015 05/07/10 Halley Gotway Rename process_grid() to +// setup_first_pass() and modify its logic. +// 016 05/24/10 Halley Gotway Rename command line options: +// From -ncfile to -point_obs +// From -valid_beg to -obs_valid_beg +// From -valid_end to -obs_valid_end +// 017 05/27/10 Halley Gotway Add -fcst_valid and -fcst_lead +// command line options. +// 018 06/08/10 Halley Gotway Add support for multi-category +// contingency tables. +// 019 06/15/10 Halley Gotway Dump reason codes for why +// point observations were rejected. +// 020 06/30/10 Halley Gotway Enhance grid equality checks. +// 021 10/20/11 Holmes Added use of command line class to +// parse the command line arguments. +// 022 11/14/11 Holmes Added code to enable reading of +// multiple config files. +// 023 02/02/12 Bullock Set default output directory to "." +// 024 03/05/12 Halley Gotway Fix bug in processing command line +// for setting valid end times. +// 025 04/16/12 Halley Gotway Switch to using vx_config library. +// 026 04/27/12 Halley Gotway Move -fcst_valid and -fcst_lead +// command line options to config file. +// 027 02/25/13 Halley Gotway Add duplicates rejection counts. +// 028 08/21/13 Halley Gotway Fix sizing of output tables for 12 +// or more probabilstic thresholds. +// 029 07/09/14 Halley Gotway Add station id exclusion option. +// 030 03/02/15 Halley Gotway Add automated regridding. +// 031 07/30/15 Halley Gotway Add conditional continuous verification. +// 032 09/11/15 Halley Gotway Add climatology to config file. +// 033 02/27/17 Halley Gotway Add HiRA verification. +// 034 05/15/17 Prestopnik P Add shape for HiRA, interp and regrid. +// 035 06/16/17 Halley Gotway Add ECLV line type. +// 036 11/01/17 Halley Gotway Add binned climatologies. +// 037 02/06/18 Halley Gotway Restructure config logic to make +// all options settable for each verification task. +// 038 08/15/18 Halley Gotway Add mask.llpnt type. +// 039 08/24/18 Halley Gotway Add ECNT output for HiRA. +// 040 04/01/10 Fillmore Add FCST and OBS units. +// 041 04/08/19 Halley Gotway Add percentile thresholds. +// 042 10/14/19 Halley Gotway Add support for climo distribution +// percentile thresholds. +// 043 11/15/19 Halley Gotway Apply climatology bins to +// continuous and probabilistic statistics. +// 044 01/24/20 Halley Gotway Add HiRA RPS output. +// 045 03/28/21 Halley Gotway Add mpr_column and mpr_thresh +// filtering options. +// 046 05/28/21 Halley Gotway Add MCTS HSS_EC output. +// 047 08/23/21 Seth Linden Add ORANK line type for HiRA. +// 048 09/13/21 Seth Linden Changed obs_qty to obs_qty_inc. +// Added code for obs_qty_exc. +// 049 12/11/21 Halley Gotway MET #1991 Fix VCNT output. +// 050 02/11/22 Halley Gotway MET #2045 Fix HiRA output. +// 051 07/06/22 Howard Soh METplus-Internal #19 Rename main to met_main. +// 052 09/29/22 Halley Gotway MET #2286 Refine GRIB1 table lookup logic. +// 053 10/03/22 Prestopnik MET #2227 Remove using namespace netCDF from header files. +// 054 04/29/24 Halley Gotway MET #2795 Move level mismatch warning. +// 055 07/05/24 Halley Gotway MET #2924 Support forecast climatology. +// 056 10/08/24 Halley Gotway MET #2887 Compute weighted contingency tables. +// 057 10/14/24 Halley Gotway MET #2279 Add point_weight_flag option. +// 058 10/15/24 Halley Gotway MET #2893 Write individual pair OBTYPE. +// +//////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "main.h" +#include "pair_stat.h" + +#include "vx_statistics.h" +#include "vx_nc_util.h" +#include "vx_regrid.h" +#include "vx_log.h" +#include "seeps.h" + +#include "nc_obs_util.h" +#include "nc_point_obs_in.h" + +#ifdef WITH_UGRID +#include "vx_data2d_ugrid.h" +#endif + +#ifdef WITH_PYTHON +#include "data2d_nc_met.h" +#include "pointdata_python.h" +#endif + +using namespace std; +using namespace netCDF; + +//////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////// + +#define BUFFER_SIZE (DEF_NC_BUFFER_SIZE/2) + +static void process_command_line (int, char **); +static void setup_first_pass (const DataPlane &, const Grid &); + +static void setup_txt_files(); +static void setup_table (AsciiTable &); + +static void build_outfile_name(unixtime, int, const char *, + ConcatString &); + +static void process_fcst_climo_files(); +static void process_obs_file(int); +static void process_scores(); + +static void do_cts (CTSInfo *&, int, const PairDataPoint *); +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(); + +static void clean_up(); + +static void usage(); +static void set_point_obs(const StringArray &); +static void set_ncfile(const StringArray &); +static void set_obs_valid_beg_time(const StringArray &); +static void set_obs_valid_end_time(const StringArray &); +static void set_outdir(const StringArray &); +#ifdef WITH_UGRID +static void set_ugrid_config(const StringArray &); +#endif + +//////////////////////////////////////////////////////////////////////// + +int met_main(int argc, char *argv[]) { + int i; + + // Process the command line arguments + process_command_line(argc, argv); + + // Process the forecast and climo files + process_fcst_climo_files(); + + // Process each observation netCDF file + for(i=0; i= beg_ut + if(obs_valid_beg_ut != (unixtime) 0 && + obs_valid_end_ut != (unixtime) 0 && + obs_valid_beg_ut > obs_valid_end_ut) { + + mlog << Error << "\n" << method_name + << "the ending time (" + << unix_to_yyyymmdd_hhmmss(obs_valid_end_ut) + << ") must be greater than the beginning time (" + << unix_to_yyyymmdd_hhmmss(obs_valid_beg_ut) + << ").\n\n"; + exit(1); + } + + // Store the input forecast and observation file names + fcst_file = cline[0]; + obs_file.insert(0, cline[1].c_str()); + config_file = cline[2]; + + // Create the default config file names + default_config_file = replace_path(default_config_filename); + + // List the config files + mlog << Debug(1) + << "Default Config File: " << default_config_file << "\n" + << "User Config File: " << config_file << "\n"; + + // Read the config files + conf_info.read_config(default_config_file.c_str(), config_file.c_str()); +#ifdef WITH_UGRID + conf_info.read_ugrid_configs(ugrid_config_files, config_file.c_str()); +#endif + + // Get the forecast file type from config, if present + ftype = parse_conf_file_type(conf_info.conf.lookup_dictionary(conf_key_fcst)); + + // Read forecast file + if(!(fcst_mtddf = mtddf_factory.new_met_2d_data_file(fcst_file.c_str(), ftype))) { + mlog << Error << "\n" << method_name << "Trouble reading forecast file \"" + << fcst_file << "\". Override the FileType with \"file_type = FileType_;\"\n\n"; + exit(1); + } + + // Store the forecast file type + ftype = fcst_mtddf->file_type(); + + // Process the configuration + conf_info.process_config(ftype); + + // Set the model name + shc.set_model(conf_info.model.c_str()); + + if (FileType_UGrid == ftype) { +#ifdef WITH_UGRID + ConcatString ugrid_dataset = conf_info.ugrid_dataset; + if (0 < ugrid_dataset.length()) { + double max_distance_km = conf_info.ugrid_max_distance_km; + ConcatString ugrid_nc = conf_info.ugrid_nc; + ConcatString ugrid_map_config_filename = conf_info.ugrid_map_config; + MetUGridDataFile *ugrid_mtddf = (MetUGridDataFile *)fcst_mtddf; + + ugrid_mtddf->set_ugrid_configs(ugrid_dataset, max_distance_km, + ugrid_map_config_filename); + if (0 == ugrid_nc.length() || ugrid_nc == "NA") { + ConcatString coordinate_file = ugrid_mtddf->coordinate_file(); + ugrid_nc = (0 < coordinate_file.length()) ? coordinate_file : fcst_file; + } + ugrid_mtddf->open_metadata(ugrid_nc.c_str()); + mlog << Debug(9) << method_name + << "ugrid_coordinate_nc: " << ugrid_nc + << " ugrid_max_distance_km: " << conf_info.ugrid_max_distance_km << "\n"; + } + else { + mlog << Error << "\n" << method_name + << conf_key_ugrid_dataset << " is not defined at the configuration file.\n\n"; + } +#else + ugrid_compile_error(method_name); +#endif + } + + // Use the first verification task to set the random number generator + // and seed value for bootstrap confidence intervals + rng_set(rng_ptr, + conf_info.vx_opt[0].boot_info.rng.c_str(), + conf_info.vx_opt[0].boot_info.seed.c_str()); + + // List the input files + mlog << Debug(1) + << "Forecast File: " << fcst_file << "\n"; + + for(i=0; iregrid(), + &data_grid, &data_grid); + + // Process the masks + conf_info.process_masks(grid); + + // Process the geography data + conf_info.process_geog(grid, fcst_file.c_str()); + + // 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, n_ens; + ConcatString base_name; + + // Create output file names for the stat file and optional text files + build_outfile_name(fcst_valid_ut, fcst_lead_sec, "", base_name); + + ///////////////////////////////////////////////////////////////////// + // + // Setup the output STAT file + // + ///////////////////////////////////////////////////////////////////// + + // 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_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); + if (max_mctc_col > max_col) max_col = max_mctc_col; + if (max_orank_col > max_col) max_col = max_orank_col; + + // Add the header columns + max_col += n_header_columns + 1; + + // Initialize file stream + stat_out = (ofstream *) nullptr; + + // Build the file name + stat_file << base_name << stat_file_ext; + + // Create the output STAT file + open_txt_file(stat_out, stat_file.c_str()); + + // Setup the STAT AsciiTable + stat_at.set_size(conf_info.n_stat_row() + 1, max_col); + setup_table(stat_at); + + // Write the text header row + write_header_row((const char **) 0, 0, 1, stat_at, 0, 0); + + // Initialize the row index to 1 to account for the header + i_stat_row = 1; + + ///////////////////////////////////////////////////////////////////// + // + // Setup each of the optional output text files + // + ///////////////////////////////////////////////////////////////////// + + // Loop through output file type + 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()); + } + } + + // Rescale probabilities from [0, 100] to [0, 1] + if(fcst_info->p_flag()) { + for(j=0; jmagic_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"; + + } // end for i + + // Check for no data + if(is_first_pass) { + mlog << Error << "\nprocess_fcst_climo_files() -> " + << "no requested forecast data found! Exiting...\n\n"; + exit(1); + } + + mlog << Debug(2) + << "\n" << sep_str << "\n\n"; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void process_obs_file(int i_nc) { + 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 + if(!use_var_id) conf_info.process_grib_codes(); + 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() { + int n_cat, n_wind; + ConcatString cs; + + // Initialize pointers + PairDataPoint *pd_ptr = (PairDataPoint *) nullptr; + CTSInfo *cts_info = (CTSInfo *) nullptr; + MCTSInfo mcts_info; + VL1L2Info *vl1l2_info = (VL1L2Info *) nullptr; + + mlog << Debug(2) + << "\n" << sep_str << "\n\n"; + + // Setup the output text files as requested in the config file + setup_txt_files(); + + // Store the maximum number of each threshold type + n_cat = conf_info.get_max_n_cat_thresh(); + n_wind = conf_info.get_max_n_wind_thresh(); + + // Allocate space for output statistics types + cts_info = new CTSInfo [n_cat]; + vl1l2_info = new VL1L2Info [n_wind]; + + // Compute scores for each PairData object and write output + for(int i_vx=0; i_vxname_attr()); + + // Store the forecast variable units + shc.set_fcst_units(conf_info.vx_opt[i_vx].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()); + + // Store the observation variable name + shc.set_obs_var(conf_info.vx_opt[i_vx].vx_pd.obs_info->name_attr()); + + // Store the observation variable units + cs = conf_info.vx_opt[i_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(conf_info.vx_opt[i_vx].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()); + + // 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()); + + // 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; + } + + // Process percentile thresholds + conf_info.vx_opt[i_vx].set_perc_thresh(pd_ptr); + + // 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], + conf_info.obtype_as_group_val_flag); + + // Reset the obtype column + shc.set_obtype(conf_info.vx_opt[i_vx].msg_typ[i_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); + } + + // 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], + conf_info.obtype_as_group_val_flag); + + // Reset the obtype column + shc.set_obtype(conf_info.vx_opt[i_vx].msg_typ[i_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); + } + + // 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], + stat_at, i_stat_row, + txt_at[i_seeps], i_txt_row[i_seeps]); + } + + // 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); + } + + // 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); + } + + // Reset the verification masking region + shc.set_mask(conf_info.vx_opt[i_vx].mask_name[i_mask].c_str()); + + } // end for i_interp + + // 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)) { + + int n = conf_info.vx_opt[i_vx].vx_pd.three_to_one(i_msg_typ, i_mask, 0); + + pd_ptr = &conf_info.vx_opt[i_vx].vx_pd.pd[n]; + + // Process percentile thresholds + conf_info.vx_opt[i_vx].set_perc_thresh(pd_ptr); + + // Appy HiRA verification and write ensemble output + do_hira_ens(i_vx, pd_ptr); + + } // end HiRA for ensembles + + // 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)) { + + int n = conf_info.vx_opt[i_vx].vx_pd.three_to_one(i_msg_typ, i_mask, 0); + + pd_ptr = &conf_info.vx_opt[i_vx].vx_pd.pd[n]; + + // Process percentile thresholds + conf_info.vx_opt[i_vx].set_perc_thresh(pd_ptr); + + // Apply HiRA verification and write probabilistic output + do_hira_prob(i_vx, pd_ptr); + + } // end HiRA for probabilities + + } // end for i_mask + } // end for i_msg_typ + + mlog << Debug(2) << "\n" << sep_str << "\n\n"; + + } // end for i_vx + + // Deallocate memory + if(cts_info) { delete [] cts_info; cts_info = (CTSInfo *) nullptr; } + if(vl1l2_info) { delete [] vl1l2_info; vl1l2_info = (VL1L2Info *) nullptr; } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void do_cts(CTSInfo *&cts_info, int i_vx, const PairDataPoint *pd_ptr) { + int i, j, n_cat; + + mlog << Debug(2) + << "Computing Categorical Statistics.\n"; + + // + // Set up the CTSInfo thresholds and alpha values + // + n_cat = conf_info.vx_opt[i_vx].fcat_ta.n(); + for(i=0; if_na.n() == 0 || pd_ptr->o_na.n() == 0) return; + + // + // Compute the stats, normal confidence intervals, and bootstrap + // bootstrap confidence intervals + // + if(conf_info.vx_opt[i_vx].boot_info.interval == BootIntervalType::BCA) { + compute_cts_stats_ci_bca(rng_ptr, *pd_ptr, + conf_info.vx_opt[i_vx].boot_info.n_rep, + cts_info, n_cat, + conf_info.vx_opt[i_vx].output_flag[i_cts] != STATOutputType::None, + conf_info.vx_opt[i_vx].rank_corr_flag, + conf_info.tmp_dir.c_str()); + } + else { + compute_cts_stats_ci_perc(rng_ptr, *pd_ptr, + conf_info.vx_opt[i_vx].boot_info.n_rep, + conf_info.vx_opt[i_vx].boot_info.rep_prop, + cts_info, n_cat, + conf_info.vx_opt[i_vx].output_flag[i_cts] != STATOutputType::None, + conf_info.vx_opt[i_vx].rank_corr_flag, + conf_info.tmp_dir.c_str()); + } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void do_mcts(MCTSInfo &mcts_info, int i_vx, const PairDataPoint *pd_ptr) { + int i; + + mlog << Debug(2) + << "Computing Multi-Category Statistics.\n"; + + // + // Set up the MCTSInfo size, thresholds, and alpha values + // + mcts_info.cts.set_size(conf_info.vx_opt[i_vx].fcat_ta.n() + 1); + mcts_info.cts.set_ec_value(conf_info.vx_opt[i_vx].hss_ec_value); + mcts_info.set_fthresh(conf_info.vx_opt[i_vx].fcat_ta); + mcts_info.set_othresh(conf_info.vx_opt[i_vx].ocat_ta); + mcts_info.allocate_n_alpha(conf_info.vx_opt[i_vx].get_n_ci_alpha()); + + for(i=0; if_na.n() == 0 || pd_ptr->o_na.n() == 0) return; + + // + // Compute the stats, normal confidence intervals, and bootstrap + // bootstrap confidence intervals + // + if(conf_info.vx_opt[i_vx].boot_info.interval == BootIntervalType::BCA) { + compute_mcts_stats_ci_bca(rng_ptr, *pd_ptr, + conf_info.vx_opt[i_vx].boot_info.n_rep, + mcts_info, + conf_info.vx_opt[i_vx].output_flag[i_mcts] != STATOutputType::None, + conf_info.vx_opt[i_vx].rank_corr_flag, + conf_info.tmp_dir.c_str()); + } + else { + compute_mcts_stats_ci_perc(rng_ptr, *pd_ptr, + conf_info.vx_opt[i_vx].boot_info.n_rep, + conf_info.vx_opt[i_vx].boot_info.rep_prop, + mcts_info, + conf_info.vx_opt[i_vx].output_flag[i_mcts] != STATOutputType::None, + conf_info.vx_opt[i_vx].rank_corr_flag, + conf_info.tmp_dir.c_str()); + } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void do_cnt_sl1l2(const PairStatVxOpt &vx_opt, const PairDataPoint *pd_ptr) { + int i, j, k, n_bin; + PairDataPoint pd_thr, pd; + SL1L2Info *sl1l2_info = (SL1L2Info *) nullptr; + CNTInfo *cnt_info = (CNTInfo *) nullptr; + + mlog << Debug(2) + << "Computing Scalar Partial Sums and Continuous Statistics.\n"; + + // Determine the number of observation climo CDF bins + n_bin = (pd_ptr->ocmn_na.n_valid() > 0 && + pd_ptr->ocsd_na.n_valid() > 0 ? + vx_opt.get_n_cdf_bin() : 1); + + if(n_bin > 1) { + mlog << Debug(2) + << "Applying " << n_bin << " climatology bins.\n"; + } + + // Set flags + bool do_sl1l2 = (vx_opt.output_flag[i_sl1l2] != STATOutputType::None || + vx_opt.output_flag[i_sal1l2] != STATOutputType::None); + bool do_cnt = (vx_opt.output_flag[i_cnt] != STATOutputType::None); + bool precip_flag = (vx_opt.vx_pd.fcst_info->is_precipitation() && + vx_opt.vx_pd.obs_info->is_precipitation()); + + // Allocate memory + cnt_info = new CNTInfo [n_bin]; + sl1l2_info = new SL1L2Info [n_bin]; + + // Process each continuous filtering threshold + for(i=0; isubset_pairs_cnt_thresh(vx_opt.fcnt_ta[i], + vx_opt.ocnt_ta[i], + vx_opt.cnt_logic); + + // Check for no matched pairs to process + if(pd_thr.n_obs == 0) continue; + + // Process the climo CDF bins + for(j=0; j 1) pd = subset_climo_cdf_bin(pd_thr, + vx_opt.cdf_info.cdf_ta, j); + else pd = pd_thr; + + // Check for no matched pairs to process + if(pd.n_obs == 0) continue; + + // Compute and write SL1L2 and SAL1L2 output + if(do_sl1l2) { + + // Store thresholds + sl1l2_info[j].fthresh = vx_opt.fcnt_ta[i]; + sl1l2_info[j].othresh = vx_opt.ocnt_ta[i]; + sl1l2_info[j].logic = vx_opt.cnt_logic; + + // Compute partial sums + sl1l2_info[j].set(pd); + + // Write out SL1L2 + if((n_bin == 1 || vx_opt.cdf_info.write_bins) && + vx_opt.output_flag[i_sl1l2] != STATOutputType::None && + sl1l2_info[j].scount > 0) { + + write_sl1l2_row(shc, sl1l2_info[j], + vx_opt.output_flag[i_sl1l2], + j, n_bin, stat_at, i_stat_row, + txt_at[i_sl1l2], i_txt_row[i_sl1l2]); + } + + // Write out SAL1L2 + if((n_bin == 1 || vx_opt.cdf_info.write_bins) && + vx_opt.output_flag[i_sal1l2] != STATOutputType::None && + sl1l2_info[j].sacount > 0) { + + write_sal1l2_row(shc, sl1l2_info[j], + vx_opt.output_flag[i_sal1l2], + j, n_bin, stat_at, i_stat_row, + txt_at[i_sal1l2], i_txt_row[i_sal1l2]); + } + } // end do_sl1l2 + + // Compute and write CNT output + if(do_cnt) { + + // Store thresholds + cnt_info[j].fthresh = vx_opt.fcnt_ta[i]; + cnt_info[j].othresh = vx_opt.ocnt_ta[i]; + cnt_info[j].logic = vx_opt.cnt_logic; + + // Setup the CNTInfo alpha values + cnt_info[j].allocate_n_alpha(vx_opt.get_n_ci_alpha()); + for(k=0; k 0) { + + write_cnt_row(shc, cnt_info[j], + vx_opt.output_flag[i_cnt], j, n_bin, + stat_at, i_stat_row, txt_at[i_cnt], i_txt_row[i_cnt]); + } + } // end if do_cnt + } // end for j (n_bin) + + // Write the mean of the climo CDF bins + if(n_bin > 1) { + + // Compute SL1L2 climo CDF bin means + if(vx_opt.output_flag[i_sl1l2] != STATOutputType::None || + vx_opt.output_flag[i_sal1l2] != STATOutputType::None) { + + SL1L2Info sl1l2_mean; + compute_sl1l2_mean(sl1l2_info, n_bin, sl1l2_mean); + + // Write out SL1L2 + if(vx_opt.output_flag[i_sl1l2] != STATOutputType::None && + sl1l2_mean.scount > 0) { + + write_sl1l2_row(shc, sl1l2_mean, + vx_opt.output_flag[i_sl1l2], + -1, n_bin, stat_at, i_stat_row, + txt_at[i_sl1l2], i_txt_row[i_sl1l2]); + } + + // Write out SAL1L2 + if(vx_opt.output_flag[i_sal1l2] != STATOutputType::None && + sl1l2_mean.sacount > 0) { + + write_sal1l2_row(shc, sl1l2_mean, + vx_opt.output_flag[i_sal1l2], + -1, n_bin, stat_at, i_stat_row, + txt_at[i_sal1l2], i_txt_row[i_sal1l2]); + } + } + + // Compute CNT climo CDF bin means + if(vx_opt.output_flag[i_cnt] != STATOutputType::None) { + + CNTInfo cnt_mean; + compute_cnt_mean(cnt_info, n_bin, cnt_mean); + + if(cnt_mean.n > 0) { + + write_cnt_row(shc, cnt_mean, + vx_opt.output_flag[i_cnt], + -1, n_bin, stat_at, i_stat_row, + txt_at[i_cnt], i_txt_row[i_cnt]); + } + } + } // end if n_bin > 1 + + } // end for i (fcnt_ta) + + // Dealloate memory + if(sl1l2_info) { delete [] sl1l2_info; sl1l2_info = (SL1L2Info *) nullptr; } + if(cnt_info) { delete [] cnt_info; cnt_info = (CNTInfo *) nullptr; } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void do_vl1l2(VL1L2Info *&v_info, int i_vx, + const PairDataPoint *pd_u_ptr, const PairDataPoint *pd_v_ptr) { + int i, j; + + mlog << Debug(2) + << "Computing Vector Partial Sums and Continuous Vector Statistics.\n"; + + // + // Check that the number of pairs are the same + // + if(pd_u_ptr->n_obs != pd_v_ptr->n_obs) { + mlog << Error << "\ndo_vl1l2() -> " + << "unequal number of UGRD and VGRD pairs (" + << pd_u_ptr->n_obs << " != " << pd_v_ptr->n_obs + << ")\n\n"; + exit(1); + } + + // + // Set all of the VL1L2Info objects + // + for(i=0; iocmn_na.n_valid() > 0 && + pd_ptr->ocsd_na.n_valid() > 0 ? + vx_opt.get_n_cdf_bin() : 1); + + if(n_bin > 1) { + mlog << Debug(2) + << "Applying " << n_bin << " climatology bins.\n"; + } + + // Allocate memory + pct_info = new PCTInfo [n_bin]; + + // Process each probabilistic observation threshold + for(i=0; i 1) pd = subset_climo_cdf_bin(*pd_ptr, + vx_opt.cdf_info.cdf_ta, j); + else pd = *pd_ptr; + + // Store thresholds + pct_info[j].fthresh = vx_opt.fcat_ta; + pct_info[j].othresh = vx_opt.ocat_ta[i]; + pct_info[j].allocate_n_alpha(vx_opt.get_n_ci_alpha()); + + for(k=0; k 1) { + + PCTInfo pct_mean; + compute_pct_mean(pct_info, n_bin, pct_mean); + + // Write out PSTD + if(vx_opt.output_flag[i_pstd] != STATOutputType::None) { + write_pstd_row(shc, pct_mean, + vx_opt.output_flag[i_pstd], + -1, n_bin, stat_at, i_stat_row, + txt_at[i_pstd], i_txt_row[i_pstd]); + } + } // end if n_bin > 1 + + } // end for i (ocnt_ta) + + // Dealloate memory + if(pct_info) { delete [] pct_info; pct_info = (PCTInfo *) nullptr; } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +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], + conf_info.obtype_as_group_val_flag); + + // 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; + + // Write out the contents of the STAT AsciiTable and + // close the STAT output files + if(stat_out) { + *stat_out << stat_at; + close_txt_file(stat_out, stat_file.c_str()); + } + + // Finish up each of the optional text files + for(i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pair_stat_conf_info.h" + +#include "vx_data2d_factory.h" +#include "vx_grid.h" +#include "vx_util.h" +#include "vx_stat_out.h" +#include "vx_gsl_prob.h" + +//////////////////////////////////////////////////////////////////////// +// +// Constants +// +//////////////////////////////////////////////////////////////////////// + +static const char * program_name = "pair_stat"; + +// Default configuration file name +static const char * default_config_filename = + "MET_BASE/config/PairStatConfig_default"; + +// 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 +}; + +// 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 +}; + +// 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" +}; + +//////////////////////////////////////////////////////////////////////// +// +// Variables for Command Line Arguments +// +//////////////////////////////////////////////////////////////////////// + +// Input files +static ConcatString fcst_file; +static StringArray obs_file; + +// Input Config file +static ConcatString config_file; +static StringArray ugrid_config_files; +static PairStatConfInfo conf_info; + +// Optional arguments +static unixtime obs_valid_beg_ut = (unixtime) 0; +static unixtime obs_valid_end_ut = (unixtime) 0; +static ConcatString out_dir; + +//////////////////////////////////////////////////////////////////////// +// +// Variables for Output Files +// +//////////////////////////////////////////////////////////////////////// + +// Timing information +static unixtime fcst_valid_ut = (unixtime) 0; +static int fcst_lead_sec = bad_data_int; + +// Output STAT file +static ConcatString stat_file; +static std::ofstream *stat_out = (std::ofstream *) nullptr; +static AsciiTable stat_at; +static int i_stat_row; + +// Optional ASCII output files +static ConcatString txt_file[n_txt]; +static std::ofstream *txt_out[n_txt]; +static AsciiTable txt_at[n_txt]; +static int i_txt_row[n_txt]; + +//////////////////////////////////////////////////////////////////////// +// +// Miscellaneous Variables +// +//////////////////////////////////////////////////////////////////////// + +// 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; + +// Pointer to the random number generator to be used +static gsl_rng *rng_ptr = (gsl_rng *) nullptr; + +// Strings to be output in the STAT and optional text files +static StatHdrColumns shc; + +//////////////////////////////////////////////////////////////////////// + +#endif // __PAIR_STAT_H__ + +//////////////////////////////////////////////////////////////////////// diff --git a/src/tools/core/pair_stat/pair_stat_conf_info.cc b/src/tools/core/pair_stat/pair_stat_conf_info.cc new file mode 100644 index 0000000000..cd9d36b7e1 --- /dev/null +++ b/src/tools/core/pair_stat/pair_stat_conf_info.cc @@ -0,0 +1,1473 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** 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 "pair_stat_conf_info.h" +#include "vx_data2d_factory.h" +#include "vx_data2d.h" +#include "vx_log.h" + +using namespace std; + + +//////////////////////////////////////////////////////////////////////// +// +// Code for class PairStatConfInfo +// +//////////////////////////////////////////////////////////////////////// + +PairStatConfInfo::PairStatConfInfo() { + + init_from_scratch(); +} + +//////////////////////////////////////////////////////////////////////// + +PairStatConfInfo::~PairStatConfInfo() { + + clear(); +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::init_from_scratch() { + + // Initialize pointers + vx_opt = (PairStatVxOpt *) nullptr; + +#ifdef WITH_UGRID + ignore_ugrid_dataset = false; +#endif + clear(); + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::clear() { + + // Initialize values + model.clear(); + grib_codes_set = false; + land_mask.clear(); + topo_dp.clear(); + topo_use_obs_thresh.clear(); + topo_interp_fcst_thresh.clear(); + msg_typ_group_map.clear(); + obtype_as_group_val_flag = false; + mask_area_map.clear(); + mask_sid_map.clear(); + point_weight_flag = PointWeightType::None; + tmp_dir.clear(); + output_prefix.clear(); + version.clear(); +#ifdef WITH_UGRID + ugrid_nc.clear(); + if (!ignore_ugrid_dataset) ugrid_dataset.clear(); + ugrid_map_config.clear(); + ugrid_max_distance_km = bad_data_double; +#endif + seeps_climo_name.clear(); + seeps_p1_thresh.clear(); + + // Deallocate memory + if(vx_opt) { delete [] vx_opt; vx_opt = (PairStatVxOpt *) nullptr; } + + // Set count to zero + n_vx = 0; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::read_config(const char *default_file_name, + const char *user_file_name) { + + // Read the config file constants + conf.read(replace_path(config_const_filename).c_str()); + + // Read the default config file + conf.read(default_file_name); + + // Read the user-specified config file + conf.read(user_file_name); + + return; +} + +//////////////////////////////////////////////////////////////////////// + +#ifdef WITH_UGRID +void PairStatConfInfo::read_ugrid_configs(StringArray ugrid_config_names, const char * user_config) { + + ConcatString file_name; + for (int i=0; i " + << "The configuration file \"" << ugrid_config_names[i]<< "\" does not exist.\n\n"; + } + if (file_exists(user_config)) conf.read(user_config); /* to avoid overriding by ugrid_config_names */ + + return; +} +#endif + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::process_config(GrdFileType ftype) { + int i, j, n_fvx, n_ovx; + Dictionary *fdict = (Dictionary *) nullptr; + Dictionary *odict = (Dictionary *) nullptr; + Dictionary i_fdict, i_odict; + + // Dump the contents of the config file + if(mlog.verbosity_level() >= 5) conf.dump(cout); + + // Initialize + clear(); + + // Conf: version + version = parse_conf_version(&conf); + + // Conf: model + model = parse_conf_string(&conf, conf_key_model); + + // Conf: point_weight_flag + point_weight_flag = parse_conf_point_weight_flag(&conf); + + // Conf: tmp_dir + tmp_dir = parse_conf_tmp_dir(&conf); + +#ifdef WITH_UGRID + // Conf: ugrid_dataset + if (!ignore_ugrid_dataset) ugrid_dataset = parse_conf_ugrid_dataset(&conf); + + // Conf: ugrid_nc + ugrid_nc = parse_conf_ugrid_coordinates_file(&conf); + + // Conf: ugrid_map_config + ugrid_map_config = parse_conf_ugrid_map_config(&conf); + + // Conf: ugrid_max_distance_km + ugrid_max_distance_km = parse_conf_ugrid_max_distance_km(&conf); +#endif + + // 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: obtype_as_group_val_flag + obtype_as_group_val_flag = + conf.lookup_bool(conf_key_obtype_as_group_val_flag); + + // Conf: fcst.field and obs.field + fdict = conf.lookup_array(conf_key_fcst_field); + odict = conf.lookup_array(conf_key_obs_field); + + // Determine the number of fields (name/level) to be verified + n_fvx = parse_conf_n_vx(fdict); + n_ovx = parse_conf_n_vx(odict); + + // Check for a valid number of verification tasks + 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 + << ") must be non-zero and match the number in \"" + << conf_key_fcst_field << "\" (" << n_fvx << ").\n\n"; + exit(1); + } + + // Allocate memory for the verification task options + n_vx = n_fvx; + vx_opt = new PairStatVxOpt [n_vx]; + + // Check for consistent number of climatology fields + check_climo_n_vx(fdict, n_vx); + check_climo_n_vx(odict, n_vx); + + // Conf: threshold for SEEPS p1 + seeps_p1_thresh = conf.lookup_thresh(conf_key_seeps_p1_thresh); + + // Conf: SEEPS climo filename + seeps_climo_name = conf.lookup_string(conf_key_seeps_point_climo_name, false); + + // Parse settings for each verification task + for(i=0; iis_u_wind() && + vx_opt[i].vx_pd.obs_info->is_u_wind()) { + + // Search for corresponding v-wind + for(j=0; jis_v_wind() && + vx_opt[j].vx_pd.obs_info->is_v_wind() && + vx_opt[i].is_uv_match(vx_opt[j])) { + + mlog << Debug(3) << "U-wind field array entry " << i+1 + << " matches V-wind field array entry " << j+1 << ".\n"; + + // Print warning about multiple matches + if(vx_opt[i].vx_pd.fcst_info->uv_index() >= 0 || + vx_opt[i].vx_pd.obs_info->uv_index() >= 0) { + mlog << Warning << "\nPairStatConfInfo::process_config() -> " + << "For U-wind, found multiple matching V-wind field array entries! " + << "Using the first match found. Set the \"level\" strings to " + << "differentiate between them.\n\n"; + } + // Use the first match + else { + vx_opt[i].vx_pd.fcst_info->set_uv_index(j); + vx_opt[i].vx_pd.obs_info->set_uv_index(j); + } + } + } + + // No match found + if(vx_opt[i].vx_pd.fcst_info->uv_index() < 0 || + vx_opt[i].vx_pd.obs_info->uv_index() < 0) { + mlog << Debug(3) << "U-wind field array entry " << i+1 + << " has no matching V-wind field array entry.\n"; + } + + } + // Process v-wind + else if(vx_opt[i].vx_pd.fcst_info->is_v_wind() && + vx_opt[i].vx_pd.obs_info->is_v_wind()) { + + // Search for corresponding u-wind + for(j=0; jis_u_wind() && + vx_opt[j].vx_pd.obs_info->is_u_wind() && + vx_opt[i].is_uv_match(vx_opt[j])) { + + mlog << Debug(3) << "V-wind field array entry " << i+1 + << " matches U-wind field array entry " << j+1 << ".\n"; + + // Print warning about multiple matches + if(vx_opt[i].vx_pd.fcst_info->uv_index() >= 0 || + vx_opt[i].vx_pd.obs_info->uv_index() >= 0) { + mlog << Warning << "\nPairStatConfInfo::process_config() -> " + << "For U-wind, found multiple matching V-wind field array entries! " + << "Using the first match found. Set the \"level\" strings to " + << "differentiate between them.\n\n"; + } + // Use the first match + else { + vx_opt[i].vx_pd.fcst_info->set_uv_index(j); + vx_opt[i].vx_pd.obs_info->set_uv_index(j); + } + } + } + + // No match found + if(vx_opt[i].vx_pd.fcst_info->uv_index() < 0 || + vx_opt[i].vx_pd.obs_info->uv_index() < 0) { + mlog << Debug(3) << "V-wind field array entry " << i+1 + << " has no matching U-wind field array entry.\n"; + } + + } + } // end for i + } // end if + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::process_grib_codes() { + + // Only needs to be set once + if(grib_codes_set) return; + + mlog << Debug(3) << "Processing each \"" << conf_key_obs_field + << "\" name as a GRIB code abbreviation since the point " + << "observations are specified as GRIB codes.\n"; + + Dictionary *odict = conf.lookup_array(conf_key_obs_field); + Dictionary i_odict; + + // Add the GRIB code by parsing each observation dictionary + for(int i=0; iadd_grib_code(i_odict); + } + + // Flag to prevent processing more than once + grib_codes_set = true; + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::process_flags() { + int i, j; + bool output_ascii_flag = false; + + // Initialize + for(i=0; i " + << "At least one output STAT type must be requested in \"" + << conf_key_output_flag << "\".\n\n"; + exit(1); + } + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatConfInfo::process_masks(const Grid &grid) { + int i, j; + MaskPlane mp; + ConcatString name; + + mlog << Debug(2) + << "Processing masking regions.\n"; + + // Mapping of grid definition strings to mask names + map grid_map; + map poly_map; + map sid_map; + map point_map; + + // Initiailize + mask_area_map.clear(); + 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; iis_u_wind() && + vx_opt[i].vx_pd.obs_info->is_u_wind()) || + (vx_opt[i].vx_pd.fcst_info->is_v_wind() && + vx_opt[i].vx_pd.obs_info->is_v_wind())) { + vflag = true; + break; + } + } + + return vflag; +} + +//////////////////////////////////////////////////////////////////////// +// +// Code for class PairStatVxOpt +// +//////////////////////////////////////////////////////////////////////// + +PairStatVxOpt::PairStatVxOpt() { + + init_from_scratch(); +} + +//////////////////////////////////////////////////////////////////////// + +PairStatVxOpt::~PairStatVxOpt() { + + clear(); +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatVxOpt::init_from_scratch() { + + clear(); + + return; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatVxOpt::clear() { + int i; + + // Initialize values + vx_pd.clear(); + + beg_ds = end_ds = bad_data_int; + + fcat_ta.clear(); + ocat_ta.clear(); + + fcnt_ta.clear(); + ocnt_ta.clear(); + cnt_logic = SetLogic::None; + + fwind_ta.clear(); + owind_ta.clear(); + wind_logic = SetLogic::None; + + land_flag = false; + topo_flag = false; + + mask_grid.clear(); + mask_poly.clear(); + mask_sid.clear(); + mask_llpnt.clear(); + + mpr_sa.clear(); + mpr_ta.clear(); + + mask_name.clear(); + + eclv_points.clear(); + + cdf_info.clear(); + + ci_alpha.clear(); + + boot_info.clear(); + interp_info.clear(); + hira_info.clear(); + + hss_ec_value = bad_data_double; + rank_corr_flag = false; + + msg_typ.clear(); + + duplicate_flag = DuplicateType::None; + obs_summary = ObsSummary::None; + obs_perc = bad_data_int; + + for(i=0; ireq_level_name(), + v.vx_pd.fcst_info->req_level_name()) || + !is_req_level_match( vx_pd.obs_info->req_level_name(), + v.vx_pd.obs_info->req_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 ) || + !(mask_llpnt == v.mask_llpnt ) || + !(mask_name == v.mask_name ) || + !(interp_info == v.interp_info ) || + !(msg_typ == v.msg_typ ) || + !(duplicate_flag == v.duplicate_flag) || + !(obs_summary == v.obs_summary ) || + !(obs_perc == v.obs_perc )) match = false; + + return match; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatVxOpt::process_config(GrdFileType ftype, + Dictionary &fdict, Dictionary &odict) { + int n; + VarInfoFactory info_factory; + mapoutput_map; + Dictionary *dict; + + // Initialize + clear(); + + // Allocate new VarInfo objects + vx_pd.set_fcst_info(info_factory.new_var_info(ftype)); + vx_pd.set_obs_info(new VarInfoGrib); + + // Set the VarInfo objects + vx_pd.fcst_info->set_dict(fdict); + vx_pd.obs_info->set_dict(odict); + + // Dump the contents of the current VarInfo + if(mlog.verbosity_level() >= 5) { + mlog << Debug(5) + << "Parsed forecast field:\n"; + vx_pd.fcst_info->dump(cout); + mlog << Debug(5) + << "Parsed observation field:\n"; + vx_pd.obs_info->dump(cout); + } + + // 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() -> " + << "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() -> " + << "the observation field cannot contain probabilities.\n\n"; + exit(1); + } + + // Conf: output_flag + output_map = parse_conf_output_flag(&odict, txt_file_type, n_txt); + + // Populate the output_flag array with map values + for(int i=0; i= 5) { + mlog << Debug(5) + << "Parsed thresholds:\n" + << "Matched pair filter columns: " << write_css(mpr_sa) << "\n" + << "Matched pair filter thresholds: " << mpr_ta.get_str() << "\n" + << "Forecast categorical thresholds: " << fcat_ta.get_str() << "\n" + << "Observed categorical thresholds: " << ocat_ta.get_str() << "\n" + << "Forecast continuous thresholds: " << fcnt_ta.get_str() << "\n" + << "Observed continuous thresholds: " << ocnt_ta.get_str() << "\n" + << "Continuous threshold logic: " << setlogic_to_string(cnt_logic) << "\n" + << "Forecast wind speed thresholds: " << fwind_ta.get_str() << "\n" + << "Observed wind speed thresholds: " << owind_ta.get_str() << "\n" + << "Wind speed threshold logic: " << setlogic_to_string(wind_logic) << "\n"; + } + + // Verifying a probability field + if(vx_pd.fcst_info->is_prob()) { + fcat_ta = string_to_prob_thresh(fcat_ta.get_str().c_str()); + } + + // Check for equal threshold length for non-probability fields + if(!vx_pd.fcst_info->is_prob() && + fcat_ta.n() != ocat_ta.n()) { + + mlog << Error << "\nPairStatVxOpt::process_config() -> " + << "The number of thresholds for each field in \"fcst." + << conf_key_cat_thresh + << "\" must match the number of thresholds for each " + << "field in \"obs." << conf_key_cat_thresh << "\".\n\n"; + exit(1); + } + + // Add default continuous thresholds until the counts match + n = max(fcnt_ta.n(), ocnt_ta.n()); + while(fcnt_ta.n() < n) fcnt_ta.add(na_str); + while(ocnt_ta.n() < n) ocnt_ta.add(na_str); + + // Add default wind speed thresholds until the counts match + n = max(fwind_ta.n(), owind_ta.n()); + while(fwind_ta.n() < n) fwind_ta.add(na_str); + while(owind_ta.n() < n) owind_ta.add(na_str); + + // Verifying with multi-category contingency tables + if(!vx_pd.fcst_info->is_prob() && + (output_flag[i_mctc] != STATOutputType::None || + output_flag[i_mcts] != STATOutputType::None)) { + check_mctc_thresh(fcat_ta); + 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); + + // Conf: mask_poly + mask_poly = odict.lookup_string_array(conf_key_mask_poly); + + // Conf: mask_sid + mask_sid = odict.lookup_string_array(conf_key_mask_sid); + + // Conf: mask_llpnt + mask_llpnt = parse_conf_llpnt_mask(&odict); + + // Conf: eclv_points + eclv_points = parse_conf_eclv_points(&odict); + + // Conf: climo_cdf + cdf_info = parse_conf_climo_cdf(&odict); + + // Conf: ci_alpha + ci_alpha = parse_conf_ci_alpha(&odict); + + // 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()); + + // 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; +} + +//////////////////////////////////////////////////////////////////////// + +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; + 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); + } + + // Check for at least one masking region + if(n_mask == 0) { + mlog << Error << "\nPairStatVxOpt::set_vx_pd() -> " + << "At least one output masking region must be requested in \"" + << conf_key_mask_grid << "\", \"" + << conf_key_mask_poly << "\", \"" + << conf_key_mask_sid << "\", or \"" + << conf_key_mask_llpnt << "\".\n\n"; + 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); + + // Store the MPR filter threshold + vx_pd.set_mpr_thresh(mpr_sa, mpr_ta); + + // 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 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 + + // 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++) { + 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; +} + +//////////////////////////////////////////////////////////////////////// + +void PairStatVxOpt::set_perc_thresh(const PairDataPoint *pd_ptr) { + + // + // Compute percentiles for forecast and observation thresholds, + // but not for wind speed or climatology CDF thresholds. + // + if(!fcat_ta.need_perc() && !ocat_ta.need_perc() && + !fcnt_ta.need_perc() && !ocnt_ta.need_perc()) return; + + // + // Sort the input arrays + // + NumArray f_sort = pd_ptr->f_na; + NumArray o_sort = pd_ptr->o_na; + NumArray fcmn_sort = pd_ptr->fcmn_na; + NumArray ocmn_sort = pd_ptr->ocmn_na; + f_sort.sort_array(); + o_sort.sort_array(); + fcmn_sort.sort_array(); + ocmn_sort.sort_array(); + + // + // Compute percentiles + // + fcat_ta.set_perc(&f_sort, &o_sort, &fcmn_sort, &ocmn_sort, &fcat_ta, &ocat_ta); + ocat_ta.set_perc(&f_sort, &o_sort, &fcmn_sort, &ocmn_sort, &fcat_ta, &ocat_ta); + fcnt_ta.set_perc(&f_sort, &o_sort, &fcmn_sort, &ocmn_sort, &fcnt_ta, &ocnt_ta); + ocnt_ta.set_perc(&f_sort, &o_sort, &fcmn_sort, &ocmn_sort, &fcnt_ta, &ocnt_ta); + + return; +} + +//////////////////////////////////////////////////////////////////////// + +int PairStatVxOpt::n_txt_row(int i_txt_row) const { + int n = 0; + int n_bin; + const char *method_name = "PairStatVxOpt::n_txt_row(int) -> "; + + // Range check + if(i_txt_row < 0 || i_txt_row >= n_txt) { + mlog << Error << "\n" << method_name + << "range check error for " << i_txt_row << "\n\n"; + exit(1); + } + + // Check if this output line type is requested + if(output_flag[i_txt_row] == STATOutputType::None) return 0; + + bool prob_flag = vx_pd.fcst_info->is_prob(); + 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(); + + // Determine row multiplier for climatology bins + if(cdf_info.write_bins) { + n_bin = get_n_cdf_bin(); + if(n_bin > 1) n_bin++; + } + else { + n_bin = 1; + } + + // Switch on the index of the line type + switch(i_txt_row) { + + case i_fho: + case i_ctc: + // Number of FHO or CTC lines = + // Message Types * Masks * Interpolations * Thresholds + n = (prob_flag ? 0 : n_pd * get_n_cat_thresh()); + break; + + case i_cts: + // Number of CTS lines = + // Message Types * Masks * Interpolations * Thresholds * + // Alphas + n = (prob_flag ? 0 : n_pd * get_n_cat_thresh() * + get_n_ci_alpha()); + break; + + case i_mctc: + // Number of MCTC lines = + // Message Types * Masks * Interpolations + n = (prob_flag ? 0 : n_pd); + break; + + case i_mcts: + // Number of MCTS lines = + // Message Types * Masks * Interpolations * Alphas + n = (prob_flag ? 0 : n_pd * get_n_ci_alpha()); + break; + + case i_cnt: + // Number of CNT lines = + // Message Types * Masks * Interpolations * Thresholds * + // Climo Bins * Alphas + n = (prob_flag ? 0 : n_pd * get_n_cnt_thresh() * n_bin * + get_n_ci_alpha()); + break; + + case i_sl1l2: + case i_sal1l2: + // Number of SL1L2 and SAL1L2 lines = + // Message Types * Masks * Interpolations * Thresholds * + // Climo Bins + 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 * + // Alphas + n = (!vect_flag ? 0 : n_pd * + get_n_wind_thresh() * get_n_ci_alpha()); + break; + + case i_pct: + case i_pjc: + case i_prc: + // Number of PCT, PJC, or PRC lines possible = + // 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: + // Number of PSTD lines = + // Message Types * Masks * Interpolations * Thresholds * + // 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: + // Number of CTC -> ECLV lines = + // Message Types * Masks * Interpolations * Thresholds * + // Climo Bins + n = (prob_flag ? 0 : n_pd * get_n_cat_thresh() * n_bin); + + // Number of PCT -> ECLV lines = + // Message Types * Masks * Interpolations * + // Observation Probability Thresholds * + // 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: + mlog << Error << "\n" << method_name + << "unexpected output type index value: " << i_txt_row + << "\n\n"; + exit(1); + } + return n; +} + +//////////////////////////////////////////////////////////////////////// + +int PairStatVxOpt::get_n_cnt_thresh() const { + return (!vx_pd.fcst_info || vx_pd.fcst_info->is_prob()) ? + 0 : fcnt_ta.n(); +} + +//////////////////////////////////////////////////////////////////////// + +int PairStatVxOpt::get_n_cat_thresh() const { + return (!vx_pd.fcst_info || vx_pd.fcst_info->is_prob()) ? + 0 : fcat_ta.n(); +} + +//////////////////////////////////////////////////////////////////////// + +int PairStatVxOpt::get_n_wind_thresh() const { + return (!vx_pd.fcst_info || vx_pd.fcst_info->is_prob()) ? + 0 : fwind_ta.n(); +} + +//////////////////////////////////////////////////////////////////////// + +int PairStatVxOpt::get_n_fprob_thresh() const { + return (!vx_pd.fcst_info || !vx_pd.fcst_info->is_prob()) ? + 0 : fcat_ta.n(); +} + +//////////////////////////////////////////////////////////////////////// + +int PairStatVxOpt::get_n_oprob_thresh() const { + return (!vx_pd.fcst_info || !vx_pd.fcst_info->is_prob()) ? + 0 : ocat_ta.n(); +} + +//////////////////////////////////////////////////////////////////////// + +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 new file mode 100644 index 0000000000..73446bb915 --- /dev/null +++ b/src/tools/core/pair_stat/pair_stat_conf_info.h @@ -0,0 +1,312 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** 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 __PAIR_STAT_CONF_INFO_H__ +#define __PAIR_STAT_CONF_INFO_H__ + +//////////////////////////////////////////////////////////////////////// + +#include + +#include "vx_config.h" +#include "vx_data2d.h" +#include "vx_grid.h" +#include "vx_util.h" +#include "vx_cal.h" +#include "vx_math.h" +#include "vx_gsl_prob.h" +#include "vx_statistics.h" +#include "vx_stat_out.h" + +//////////////////////////////////////////////////////////////////////// + +// Indices for the output flag types in the configuration file +static const int i_fho = 0; +static const int i_ctc = 1; +static const int i_cts = 2; +static const int i_mctc = 3; +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_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 n_txt = 22; + +// Text file type +static const STATLineType txt_file_type[n_txt] = { + + STATLineType::fho, // 0 + STATLineType::ctc, // 1 + STATLineType::cts, // 2 + STATLineType::mctc, // 3 + STATLineType::mcts, // 4 + + 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 +}; + +//////////////////////////////////////////////////////////////////////// + +class PairStatConfInfo; // forward reference + +//////////////////////////////////////////////////////////////////////// + +class PairStatVxOpt { + + private: + + void init_from_scratch(); + + public: + + PairStatVxOpt(); + ~PairStatVxOpt(); + + ////////////////////////////////////////////////////////////////// + + VxPairDataPoint vx_pd; // Matched pair data [n_msg_typ][n_mask][n_interp] + + int beg_ds; // Begin observation time window offset + int end_ds; // End observation time window offset + + ThreshArray fcat_ta; // Array for fcst categorical thresholds + ThreshArray ocat_ta; // Array for obs categorical thresholds + + ThreshArray fcnt_ta; // Array for fcst continuous thresholds + ThreshArray ocnt_ta; // Array for obs continuous thresholds + SetLogic cnt_logic; // Array of continuous threshold field logic + + ThreshArray fwind_ta; // Array for fcst wind speed thresholds + 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 + + StringArray mpr_sa; // MPR column names + ThreshArray mpr_ta; // MPR column thresholds + + // Vector of MaskLatLon objects defining Lat/Lon Point masks + std::vector mask_llpnt; + + StringArray mask_name; // Masking names + + NumArray eclv_points; // ECLV points + + ClimoCDFInfo cdf_info; // Climo CDF info + + 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 + + ////////////////////////////////////////////////////////////////// + + void clear(); + + void process_config(GrdFileType, Dictionary &, Dictionary &); + void set_vx_pd(PairStatConfInfo *); + bool is_uv_match(const PairStatVxOpt &) const; + + void set_perc_thresh(const PairDataPoint *); + + // 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; + int get_n_wind_thresh() const; + + int get_n_fprob_thresh() const; + 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; } +inline int PairStatVxOpt::get_n_ci_alpha() const { return ci_alpha.n(); } + +//////////////////////////////////////////////////////////////////////// + +class PairStatConfInfo { + + private: + + void init_from_scratch(); + + // Number of verification tasks + int n_vx; + + public: + + PairStatConfInfo(); + ~PairStatConfInfo(); + + ////////////////////////////////////////////////////////////////// + + // Pair-Stat configuration object + MetConfig conf; + + // Store data parsed from the Pair-Stat configuration object + ConcatString model; // Model name + + PairStatVxOpt * vx_opt; // Array of vx task options [n_vx] (allocated) + bool grib_codes_set; + + // 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 that should be processed together + std::map msg_typ_group_map; + bool obtype_as_group_val_flag; + + // Mapping of mask names to DataPlanes + std::map mask_area_map; + + // Mapping of mask names to Station ID lists + std::map mask_sid_map; + + PointWeightType point_weight_flag; // Point weighting flag + + ConcatString tmp_dir; // Directory for temporary files + ConcatString output_prefix; // String to customize output file name + ConcatString version; // Config file version + + ConcatString seeps_climo_name; // SEESP climo filename + SingleThresh seeps_p1_thresh; // SEESP p1 threshold + +#ifdef WITH_UGRID + bool ignore_ugrid_dataset; + ConcatString ugrid_nc; // NetCDF for coordinate variables of unstructured grid + ConcatString ugrid_dataset; // UGRid dataset name (mpas, lfric etc) + ConcatString ugrid_map_config; // User's configuration file which contains ugrid metadata mapping + double ugrid_max_distance_km; // max distance to be the closest neighbor to unstructured grid +#endif + + // Summary of output file options across all verification tasks + STATOutputType output_flag[n_txt]; // Flag for each output line type + + ////////////////////////////////////////////////////////////////// + + void clear(); + + void read_config(const char *, const char *); +#ifdef WITH_UGRID + void read_ugrid_configs(StringArray ugrid_config_names, const char * user_config); +#endif + + void process_config(GrdFileType); + void process_grib_codes(); + void process_flags(); + void process_masks(const Grid &); + void process_geog(const Grid &, const char *); + void set_vx_pd(); + + // Dump out the counts + int get_n_vx() const; + + // Compute the maximum number of output lines possible based + // on the contents of the configuration file + int n_txt_row(int i) const; + int n_stat_row() const; + + // Maximum across all verification tasks + int get_max_n_cat_thresh() const; + int get_max_n_cnt_thresh() const; + int get_max_n_wind_thresh() const; + 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; +}; + +//////////////////////////////////////////////////////////////////////// + +inline int PairStatConfInfo::get_n_vx() const { return(n_vx); } + +//////////////////////////////////////////////////////////////////////// + +#endif /* __PAIR_STAT_CONF_INFO_H__ */ + +////////////////////////////////////////////////////////////////////////