From 169b6709b3a236cd5cc316fd122343c1ce37d00b Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Fri, 5 Jul 2024 16:12:05 -0600 Subject: [PATCH] Per #2924, update the Stat-Analysis parsing logic to parse the new MPR and ORANK climatology columns. --- .../core/stat_analysis/aggr_stat_line.cc | 38 +++++++------ .../core/stat_analysis/parse_stat_line.cc | 57 +++++++++++++++---- .../core/stat_analysis/parse_stat_line.h | 8 ++- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/tools/core/stat_analysis/aggr_stat_line.cc b/src/tools/core/stat_analysis/aggr_stat_line.cc index eb7caeedf6..5ecbe20638 100644 --- a/src/tools/core/stat_analysis/aggr_stat_line.cc +++ b/src/tools/core/stat_analysis/aggr_stat_line.cc @@ -1817,16 +1817,18 @@ void aggr_mpr_wind_lines(LineDataFile &f, STATAnalysisJob &job, job.dump_stat_line(line); + // TODO: Update parsing logic to handle separate forecast and observation climatology data + parse_mpr_line(line, cur); is_ugrd = (cur.fcst_var == ugrd_abbr_str); - uf = (is_ugrd ? cur.fcst : bad_data_double); - uo = (is_ugrd ? cur.obs : bad_data_double); - ucmn = (is_ugrd ? cur.climo_mean : bad_data_double); - ucsd = (is_ugrd ? cur.climo_stdev : bad_data_double); - vf = (is_ugrd ? bad_data_double : cur.fcst); - vo = (is_ugrd ? bad_data_double : cur.obs); - vcmn = (is_ugrd ? bad_data_double : cur.climo_mean); - vcsd = (is_ugrd ? bad_data_double : cur.climo_stdev); + uf = (is_ugrd ? cur.fcst : bad_data_double); + uo = (is_ugrd ? cur.obs : bad_data_double); + ucmn = (is_ugrd ? cur.obs_climo_mean : bad_data_double); + ucsd = (is_ugrd ? cur.obs_climo_stdev : bad_data_double); + vf = (is_ugrd ? bad_data_double : cur.fcst); + vo = (is_ugrd ? bad_data_double : cur.obs); + vcmn = (is_ugrd ? bad_data_double : cur.obs_climo_mean); + vcsd = (is_ugrd ? bad_data_double : cur.obs_climo_stdev); // // Build header string for matching UGRD and VGRD lines @@ -2159,9 +2161,9 @@ void aggr_mpr_lines(LineDataFile &f, STATAnalysisJob &job, aggr.pd.n_obs = 1; aggr.pd.f_na.add(cur.fcst); aggr.pd.o_na.add(cur.obs); - aggr.pd.cmn_na.add(cur.climo_mean); - aggr.pd.csd_na.add(cur.climo_stdev); - aggr.pd.cdf_na.add(cur.climo_cdf); + aggr.pd.cmn_na.add(cur.obs_climo_mean); + aggr.pd.csd_na.add(cur.obs_climo_stdev); + aggr.pd.cdf_na.add(cur.obs_climo_cdf); aggr.pd.wgt_na.add(default_grid_weight); aggr.fcst_var = cur.fcst_var; @@ -2188,9 +2190,9 @@ void aggr_mpr_lines(LineDataFile &f, STATAnalysisJob &job, m[key].pd.n_obs++; m[key].pd.f_na.add(cur.fcst); m[key].pd.o_na.add(cur.obs); - m[key].pd.cmn_na.add(cur.climo_mean); - m[key].pd.csd_na.add(cur.climo_stdev); - m[key].pd.cdf_na.add(cur.climo_cdf); + m[key].pd.cmn_na.add(cur.obs_climo_mean); + m[key].pd.csd_na.add(cur.obs_climo_stdev); + m[key].pd.cdf_na.add(cur.obs_climo_cdf); m[key].pd.wgt_na.add(default_grid_weight); // @@ -3086,8 +3088,8 @@ void aggr_orank_lines(LineDataFile &f, STATAnalysisJob &job, // ensemble spread, ensemble member values, and // valid ensemble count // - m[key].ens_pd.add_grid_obs(cur.obs, cur.climo_mean, - cur.climo_stdev, default_grid_weight); + m[key].ens_pd.add_grid_obs(cur.obs, cur.obs_climo_mean, + cur.obs_climo_stdev, default_grid_weight); m[key].ens_pd.skip_ba.add(false); m[key].ens_pd.n_pair++; m[key].ens_pd.r_na.add(cur.rank); @@ -3112,7 +3114,7 @@ void aggr_orank_lines(LineDataFile &f, STATAnalysisJob &job, // Derive ensemble from climo mean and standard deviation derive_climo_vals(&m[key].cdf_info, - cur.climo_mean, cur.climo_stdev, climo_vals); + cur.obs_climo_mean, cur.obs_climo_stdev, climo_vals); // Store empirical CRPS stats and CRPS-Fair double crps_emp = compute_crps_emp(cur.obs, cur.ens_na); @@ -3123,7 +3125,7 @@ void aggr_orank_lines(LineDataFile &f, STATAnalysisJob &job, // Store Gaussian CRPS stats m[key].ens_pd.crps_gaus_na.add(compute_crps_gaus(cur.obs, cur.ens_mean, cur.spread)); - m[key].ens_pd.crpscl_gaus_na.add(compute_crps_gaus(cur.obs, cur.climo_mean, cur.climo_stdev)); + m[key].ens_pd.crpscl_gaus_na.add(compute_crps_gaus(cur.obs, cur.obs_climo_mean, cur.obs_climo_stdev)); m[key].ens_pd.ign_na.add(compute_ens_ign(cur.obs, cur.ens_mean, cur.spread)); m[key].ens_pd.pit_na.add(compute_ens_pit(cur.obs, cur.ens_mean, cur.spread)); diff --git a/src/tools/core/stat_analysis/parse_stat_line.cc b/src/tools/core/stat_analysis/parse_stat_line.cc index b3662a8eeb..b96e79bbf7 100644 --- a/src/tools/core/stat_analysis/parse_stat_line.cc +++ b/src/tools/core/stat_analysis/parse_stat_line.cc @@ -327,16 +327,35 @@ void parse_mpr_line(STATLine &l, MPRData &m_data) { m_data.fcst = atof(l.get_item("FCST")); m_data.obs = atof(l.get_item("OBS")); - // In met-6.1 and later, CLIMO column was replaced by CLIMO_MEAN + // In met-6.1 and later: + // - CLIMO was replaced by CLIMO_MEAN if(l.has("CLIMO")) { - m_data.climo_mean = atof(l.get_item("CLIMO")); - m_data.climo_stdev = bad_data_double; - m_data.climo_cdf = bad_data_double; + m_data.obs_climo_mean = atof(l.get_item("CLIMO")); + m_data.obs_climo_stdev = bad_data_double; + m_data.obs_climo_cdf = bad_data_double; + m_data.fcst_climo_mean = bad_data_double; + m_data.fcst_climo_stdev = bad_data_double; + m_data.fcst_climo_cdf = bad_data_double; + } + // In met-12.0.0 and later: + // - CLIMO_MEAN was replaced by OBS_CLIMO_MEAN + // - CLIMO_STDEV was replaced by OBS_CLIMO_STDEV + // - CLIMO_CDF was replaced by OBS_CLIMO_CDF + else if(l.has("CLIMO_MEAN")) { + m_data.obs_climo_mean = atof(l.get_item("CLIMO_MEAN")); + m_data.obs_climo_stdev = atof(l.get_item("CLIMO_STDEV")); + m_data.obs_climo_cdf = atof(l.get_item("CLIMO_CDF")); + m_data.fcst_climo_mean = bad_data_double; + m_data.fcst_climo_stdev = bad_data_double; + m_data.fcst_climo_cdf = bad_data_double; } else { - m_data.climo_mean = atof(l.get_item("CLIMO_MEAN")); - m_data.climo_stdev = atof(l.get_item("CLIMO_STDEV")); - m_data.climo_cdf = atof(l.get_item("CLIMO_CDF")); + m_data.obs_climo_mean = atof(l.get_item("OBS_CLIMO_MEAN")); + m_data.obs_climo_stdev = atof(l.get_item("OBS_CLIMO_STDEV")); + m_data.obs_climo_cdf = atof(l.get_item("OBS_CLIMO_CDF")); + m_data.fcst_climo_mean = atof(l.get_item("FCST_CLIMO_MEAN")); + m_data.fcst_climo_stdev = atof(l.get_item("FCST_CLIMO_STDEV")); + m_data.fcst_climo_cdf = atof(l.get_item("FCST_CLIMO_CDF")); } m_data.obs_qc = l.get_item("OBS_QC", false); @@ -530,14 +549,28 @@ void parse_orank_line(STATLine &l, ORANKData &o_data) { o_data.spread_oerr = atof(l.get_item("SPREAD_OERR")); o_data.spread_plus_oerr = atof(l.get_item("SPREAD_PLUS_OERR")); - // In met-10.0.0 and later, CLIMO column was replaced by CLIMO_MEAN + // In met-10.0.0 and later: + // - CLIMO was replaced by CLIMO_MEAN if(l.has("CLIMO")) { - o_data.climo_mean = atof(l.get_item("CLIMO")); - o_data.climo_stdev = bad_data_double; + o_data.obs_climo_mean = atof(l.get_item("CLIMO")); + o_data.obs_climo_stdev = bad_data_double; + o_data.fcst_climo_mean = bad_data_double; + o_data.fcst_climo_stdev = bad_data_double; + } + // In met-12.0.0 and later: + // - CLIMO_MEAN was replaced by OBS_CLIMO_MEAN + // - CLIMO_STDEV was replaced by OBS_CLIMO_STDEV + else if(l.has("CLIMO_MEAN")) { + o_data.obs_climo_mean = atof(l.get_item("CLIMO_MEAN")); + o_data.obs_climo_stdev = atof(l.get_item("CLIMO_STDEV")); + o_data.fcst_climo_mean = bad_data_double; + o_data.fcst_climo_stdev = bad_data_double; } else { - o_data.climo_mean = atof(l.get_item("CLIMO_MEAN")); - o_data.climo_stdev = atof(l.get_item("CLIMO_STDEV")); + o_data.obs_climo_mean = atof(l.get_item("OBS_CLIMO_MEAN")); + o_data.obs_climo_stdev = atof(l.get_item("OBS_CLIMO_STDEV")); + o_data.fcst_climo_mean = atof(l.get_item("FCST_CLIMO_MEAN")); + o_data.fcst_climo_stdev = atof(l.get_item("FCST_CLIMO_STDEV")); } return; diff --git a/src/tools/core/stat_analysis/parse_stat_line.h b/src/tools/core/stat_analysis/parse_stat_line.h index c890b45ff7..ab24d41c94 100644 --- a/src/tools/core/stat_analysis/parse_stat_line.h +++ b/src/tools/core/stat_analysis/parse_stat_line.h @@ -60,7 +60,9 @@ struct MPRData { int total, index; ConcatString obs_sid, obs_qc; double obs_lat, obs_lon, obs_lvl, obs_elv; - double fcst, obs, climo_mean, climo_stdev, climo_cdf; + double fcst, obs; + double fcst_climo_mean, fcst_climo_stdev, fcst_climo_cdf; + double obs_climo_mean, obs_climo_stdev, obs_climo_cdf; }; // Ensemble continuous statistics (ECNT) data structure @@ -101,7 +103,9 @@ struct ORANKData { int total, index; ConcatString obs_sid, obs_qc; double obs_lat, obs_lon, obs_lvl, obs_elv; - double obs, pit, climo_mean, climo_stdev; + double obs, pit; + double fcst_climo_mean, fcst_climo_stdev; + double obs_climo_mean, obs_climo_stdev; double ens_mean, spread, ens_mean_oerr, spread_oerr; double spread_plus_oerr; int rank, n_ens_vld, n_ens;