From fe6529693cd978ce6ae1efd45bd629168cad4ee5 Mon Sep 17 00:00:00 2001 From: George McCabe <23407799+georgemccabe@users.noreply.github.com> Date: Tue, 16 Nov 2021 15:17:04 -0700 Subject: [PATCH] Update Develop-ref after #1272 and #1275 (#1276) Co-authored-by: George McCabe <23407799+georgemccabe@users.noreply.github.com> Co-authored-by: Julie Prestopnik Co-authored-by: TaraJensen Co-authored-by: bikegeek <3753118+bikegeek@users.noreply.github.com> Co-authored-by: bikegeek Co-authored-by: johnhg Co-authored-by: Christina Kalb Co-authored-by: lisagoodrich <33230218+lisagoodrich@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/new_use_case.md | 2 +- .github/parm/use_case_groups.json | 7 +- docs/Users_Guide/index.rst | 1 + docs/Users_Guide/statistics_list.rst | 2098 +++++++++++++++++ docs/_static/s2s-OMI_GFS_phase_diagram.png | Bin 0 -> 55990 bytes docs/_templates/theme_override.css | 16 + .../met_tool_wrapper/GenEnsProd/GenEnsProd.py | 31 +- .../s2s/UserScript_fcstGFS_obsERA_OMI.py | 20 +- .../s2s/UserScript_fcstGFS_obsERA_RMM.py | 263 --- .../s2s/UserScript_obsERA_obsOnly_OMI.py | 141 ++ ...UserScript_obsERA_obsOnly_PhaseDiagram.py} | 36 +- .../s2s/UserScript_obsERA_obsOnly_RMM.py | 147 ++ .../test_ensemble_stat_wrapper.py | 4 +- internal_tests/use_cases/all_use_cases.txt | 7 +- metplus/util/met_util.py | 6 +- metplus/wrappers/command_builder.py | 104 +- metplus/wrappers/ensemble_stat_wrapper.py | 28 +- metplus/wrappers/gen_ens_prod_wrapper.py | 77 +- parm/met_config/GenEnsProdConfig_wrapped | 4 +- .../GenEnsProd/GenEnsProd.conf | 16 +- .../s2s/UserScript_fcstGFS_obsERA_OMI.conf | 78 +- .../OMI_driver.py | 3 +- .../s2s/UserScript_fcstGFS_obsERA_RMM.conf | 214 -- .../s2s/UserScript_obsERA_obsOnly_OMI.conf | 157 ++ .../OMI_driver.py | 1 + ...erScript_obsERA_obsOnly_PhaseDiagram.conf} | 8 +- .../PhaseDiagram_driver.py | 0 .../save_input_files_txt.py | 0 .../s2s/UserScript_obsERA_obsOnly_RMM.conf | 436 ++++ .../RMM_driver.py | 28 +- .../compute_harmonic_anomalies.py | 110 + 31 files changed, 3438 insertions(+), 605 deletions(-) create mode 100644 docs/Users_Guide/statistics_list.rst create mode 100644 docs/_static/s2s-OMI_GFS_phase_diagram.png create mode 100644 docs/_templates/theme_override.css delete mode 100644 docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.py create mode 100644 docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.py rename docs/use_cases/model_applications/s2s/{UserScript_fcstGFS_obsERA_PhaseDiagram.py => UserScript_obsERA_obsOnly_PhaseDiagram.py} (82%) create mode 100644 docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.py delete mode 100644 parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf create mode 100644 parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf create mode 120000 parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py rename parm/use_cases/model_applications/s2s/{UserScript_fcstGFS_obsERA_PhaseDiagram.conf => UserScript_obsERA_obsOnly_PhaseDiagram.conf} (92%) rename parm/use_cases/model_applications/s2s/{UserScript_fcstGFS_obsERA_PhaseDiagram => UserScript_obsERA_obsOnly_PhaseDiagram}/PhaseDiagram_driver.py (100%) rename parm/use_cases/model_applications/s2s/{UserScript_fcstGFS_obsERA_PhaseDiagram => UserScript_obsERA_obsOnly_PhaseDiagram}/save_input_files_txt.py (100%) create mode 100644 parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf rename parm/use_cases/model_applications/s2s/{UserScript_fcstGFS_obsERA_RMM => UserScript_obsERA_obsOnly_RMM}/RMM_driver.py (88%) create mode 100755 parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py diff --git a/.github/ISSUE_TEMPLATE/new_use_case.md b/.github/ISSUE_TEMPLATE/new_use_case.md index ad54e6baf7..d16e19960f 100644 --- a/.github/ISSUE_TEMPLATE/new_use_case.md +++ b/.github/ISSUE_TEMPLATE/new_use_case.md @@ -1,7 +1,7 @@ --- name: New use case about: Add a new use case -title: '' +title: 'New Use Case:' labels: 'alert: NEED ACCOUNT KEY, alert: NEED MORE DEFINITION, alert: NEED PROJECT ASSIGNMENT, type: new use case' assignees: '' diff --git a/.github/parm/use_case_groups.json b/.github/parm/use_case_groups.json index 4cb2de818b..6c5f13f407 100644 --- a/.github/parm/use_case_groups.json +++ b/.github/parm/use_case_groups.json @@ -136,7 +136,7 @@ }, { "category": "s2s", - "index_list": "8-9", + "index_list": "7-9", "run": false }, { @@ -144,6 +144,11 @@ "index_list": "10", "run": false }, + { + "category": "s2s", + "index_list": "11", + "run": false + }, { "category": "space_weather", "index_list": "0-1", diff --git a/docs/Users_Guide/index.rst b/docs/Users_Guide/index.rst index acd989ed11..a1ab31578a 100644 --- a/docs/Users_Guide/index.rst +++ b/docs/Users_Guide/index.rst @@ -85,6 +85,7 @@ is sponsored by NSF. quicksearch glossary references + statistics_list .. Indices and tables diff --git a/docs/Users_Guide/statistics_list.rst b/docs/Users_Guide/statistics_list.rst new file mode 100644 index 0000000000..856f073ee1 --- /dev/null +++ b/docs/Users_Guide/statistics_list.rst @@ -0,0 +1,2098 @@ +****************************** +METplus Database of Statistics +****************************** + + +.. Number of characters per line: + Statistic Name - no more that 32 characters + METplus Name - no more than 17 characters + Statistic Type - no more than 19 characters + METplus Line Type - currently unlimited (approx 33 characters) + + +.. role:: raw-html(raw) + :format: html + +.. list-table:: Statistics List + :widths: auto + :header-rows: 1 + + * - Statistics :raw-html:`
` + Long Name + - METplus Name + - Statistic Type + - Tools + - METplus :raw-html:`
` + Line Type + * - Accuracy + - ACC + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + MODE + - CTS :raw-html:`
` + MCTS :raw-html:`
` + NBRCTS :raw-html:`
` + MODE cts + * - Asymptotic Fractions Skill Score + - AFSS + - Neighborhood + - Grid-Stat + - NBRCNT + * - Along track error (nm) + - ALTK_ERR + - Continuous + - TC-Pairs :raw-html:`
` + TC-Stat + - TCMPR :raw-html:`
` + TCST + * - Difference between the axis :raw-html:`
` + angles of two objects (in degrees) + - ANGLE_DIFF + - Diagnostic + - MODE + - MODE + * - Anomaly Correlation :raw-html:`
` + including mean error + - ANOM_CORR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Series-Analysis :raw-html:`
` + Stat-Analysis + - CNT + * - Uncentered Anomaly :raw-html:`
` + Correlation excluding mean :raw-html:`
` + error + - ANOM_CORR :raw-html:`
` _UNCNTR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Series-Analysis :raw-html:`
` + Stat-Analysis + - CNT + * - Object area (in grid squares) + - AREA + - Diagnostic + - MODE :raw-html:`
` + MTD + - MODE obj + * - Forecast object area :raw-html:`
` + divided by the observation :raw-html:`
` + object area (unitless) + - AREA_RATIO + - Diagnostic + - MODE + - MODE obj + * - Area of the object :raw-html:`
` + that meet the object :raw-html:`
` + definition threshold :raw-html:`
` + criteria (in grid squares) + - AREA_THRESH + - Diagnostic + - MODE + - MODE obj + * - Absolute value of :raw-html:`
` + the difference :raw-html:`
` + between the aspect :raw-html:`
` + ratios of two objects :raw-html:`
` + (unitless) + - ASPECT_DIFF + - Diagnostic + - MODE + - MODE obj + * - Object axis angle :raw-html:`
` + (in degrees) + - AXIS_ANG + - Diagnostic + - MODE :raw-html:`
` + MTD + - MTD obj + * - Difference in spatial :raw-html:`
` + axis plane angles + - AXIS_DIFF + - Diagnostic + - MTD + - MTD obj + * - Baddeley’s Delta Metric + - BADDELEY + - Distance Map + - Grid-Stat + - DMAP + * - Bias Adjusted Gilbert :raw-html:`
` + Skill Score + - BAGSS + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Base Rate + - BASER + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Wavelet-Stat :raw-html:`
` + MODE + - CTS :raw-html:`
` + ECLV :raw-html:`
` + MODE cts :raw-html:`
` + NBRCTCS :raw-html:`
` + PSTD :raw-html:`
` + PJC + * - Bias-corrected mean :raw-html:`
` + squared error + - BCMSE + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Ensemble-Stat + - CNT :raw-html:`
` + SSVAR + * - Minimum distance between :raw-html:`
` + the boundaries of two objects + - BOUNDARY :raw-html:`
` + _DIST + - Diagnostic + - MODE + - MODE obj + * - Brier Score + - BRIER + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Climatological Brier Score + - BRIERCL + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Brier Skill Score relative :raw-html:`
` + to sample climatology + - BSS + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Brier Skill Score relative :raw-html:`
` + to external climatology + - BSS_SMPL + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Calibration when forecast :raw-html:`
` + is between the ith and :raw-html:`
` + i+1th probability :raw-html:`
` + thresholds (repeated) + - CALIBRATION :raw-html:`
` + _i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PJC + * - Total great circle distance :raw-html:`
` + travelled by the 2D spatial :raw-html:`
` + centroid over the lifetime :raw-html:`
` + of the 3D object + - CDIST :raw-html:`
` + _TRAVELLED + - Diagnostic + - MTD + - MTD 3D obj + * - Distance between two :raw-html:`
` + objects centroids :raw-html:`
` + (in grid units) + - CENTROID :raw-html:`
` + _DIST + - Diagnostic + - MODE + - MODE obj + * - Latitude of centroid :raw-html:`
` + - CENTROID :raw-html:`
` + _LAT + - Diagnostic + - MTD :raw-html:`
` + MODE + - MTD 2D & 3D obj :raw-html:`
` + MODE obj + * - Longitude of centroid :raw-html:`
` + - CENTROID :raw-html:`
` + _LON + - Diagnostic + - MTD :raw-html:`
` + MODE + - MTD 2D & 3D obj :raw-html:`
` + MODE obj + * - Time coordinate of centroid + - CENTROID_T + - Diagnostic + - MTD + - MTD 3D obj + * - X coordinate of centroid :raw-html:`
` + - CENTROID_X + - Diagnostic + - MTD :raw-html:`
` + MODE + - MTD 2D & 3D obj :raw-html:`
` + MODE obj + * - Y coordinate of centroid :raw-html:`
` + - CENTROID_Y + - Diagnostic + - MTD :raw-html:`
` + MODE + - MTD 2D & 3D obj :raw-html:`
` + MODE obj + * - Climatological mean value + - CLIMO_MEAN + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Ensemble-Stat + - MPR :raw-html:`
` + ORANK + * - Climatological standard :raw-html:`
` + deviation value + - CLIMO_STDEV + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Ensemble-Stat + - MPR :raw-html:`
` + ORANK + * - Ratio of the difference :raw-html:`
` + between the area of an :raw-html:`
` + object and the area of :raw-html:`
` + its convex hull divided :raw-html:`
` + by the area of the :raw-html:`
` + complex hull (unitless) + - COMPLEXITY + - Diagnostic + - MODE + - MODE obj + * - Ratio of complexities of :raw-html:`
` + two objects defined as :raw-html:`
` + the lesser of the forecast :raw-html:`
` + complexity divided by the :raw-html:`
` + observation complexity or :raw-html:`
` + its reciprocal (unitless) + - COMPLEXITY :raw-html:`
` + _RATIO + - Diagnostic + - MODE + - MODE obj + * - Minimum distance between :raw-html:`
` + the convex hulls of two :raw-html:`
` + objects (in grid units) + - CONVEX_HULL :raw-html:`
` + _DIST + - Diagnostic + - MODE + - MODE obj + * - Continuous Ranked :raw-html:`
` + Probability Score :raw-html:`
` + (normal dist.) + - CRPS + - Ensemble + - Ensemble-Stat + - ECNT + * - Continuous Ranked :raw-html:`
` + Probability Score :raw-html:`
` + (empirical dist.) + - CRPS_EMP + - Ensemble + - Ensemble-Stat + - ECNT + * - Climatological Continuous :raw-html:`
` + Ranked Probability Score :raw-html:`
` + (normal dist.) + - CRPSCL + - Ensemble + - Ensemble-Stat + - ECNT + * - Climatological Continuous :raw-html:`
` + Ranked Probability Score :raw-html:`
` + (empirical dist.) + - CRPSCL_EMP + - Ensemble + - Ensemble-Stat + - ECNT + * - Continuous Ranked :raw-html:`
` + Probability Skill Score :raw-html:`
` + (normal dist.) + - CRPSS + - Ensemble + - Ensemble-Stat + - ECNT + * - Continuous Ranked :raw-html:`
` + Probability Skill Score :raw-html:`
` + (empirical dist.) + - CRPSS_EMP + - Ensemble + - Ensemble-Stat + - ECNT + * - Cross track error (nm) + - CRTK_ERR + - Continuous + - TC-Pairs :raw-html:`
` + TC-Stat + - TCMPR :raw-html:`
` + TCST + * - Critical Success Index + - CSI + - Categorical + - Point-Stat :raw-html:`
` + MODE cts :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + MODE :raw-html:`
` + MBRCTCS + * - Radius of curvature + - CURVATURE + - Diagnostic + - MODE + - MODE obj + * - Ratio of the curvature + - CURVATURE :raw-html:`
` + _RATIO + - Diagnostic + - MODE + - MODE obj + * - Center of curvature :raw-html:`
` + (in grid coordinates) + - CURVATURE :raw-html:`
` + _X + - Diagnostic + - MODE + - MODE obj + * - Center of curvature :raw-html:`
` + (in grid coordinates) + - CURVATURE :raw-html:`
` + _Y + - Diagnostic + - MODE + - MODE obj + * - Absolute value of :raw-html:`
` + DIR_ERR (see below) + - DIR_ABSERR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Signed angle between :raw-html:`
` + the directions of the :raw-html:`
` + average forecast and :raw-html:`
` + observed wind vectors + - DIR_ERR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Difference in object :raw-html:`
` + direction of movement + - DIRECTION :raw-html:`
` + _DIFF + - Diagnostic + - MTD + - MTD 3D obj + * - Difference in the :raw-html:`
` + lifetimes of the :raw-html:`
` + two objects + - DURATION :raw-html:`
` + _DIFF + - Diagnostic + - MTD + - MTD 3D obj + * - Expected correct rate :raw-html:`
` + used for MCTS HSS_EC + - EC_VALUE + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - MCTC + * - Extreme Dependency Index + - EDI + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Extreme Dependency Score + - EDS + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Mean of absolute value :raw-html:`
` + of forecast minus :raw-html:`
` + observed gradients + - EGBAR + - Continuous + - Grid-Stat + - GRAD + * - Object end time + - END_TIME + - Diagnostic + - MTD + - MTD 3D obj + * - Difference in object :raw-html:`
` + ending time steps + - END_TIME :raw-html:`
` + _DELTA + - Diagnostic + - MTD + - MTD 3D obj + * - The unperturbed :raw-html:`
` + ensemble mean value + - ENS_MEAN + - Ensemble + - Ensemble-Stat + - ORANK + * - The PERTURBED ensemble :raw-html:`
` + mean (e.g. with :raw-html:`
` + Observation Error). + - ENS_MEAN :raw-html:`
` + _OERR + - Ensemble + - Ensemble-Stat + - ORANK + * - Standard deviation of :raw-html:`
` + the error + - ESTDEV + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Ensemble-Stat + - CNT :raw-html:`
` + SSVAR + * - Forecast rate/event :raw-html:`
` + frequency + - F_RATE + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - FHO :raw-html:`
` + NBRCNT + * - Mean forecast wind speed + - F_SPEED :raw-html:`
` + _BAR + - Continous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Mean Forecast Anomaly + - FABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - SAL1L2 + * - False alarm ratio + - FAR + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + MODE + - CTS :raw-html:`
` + MODE :raw-html:`
` + NBRCTCS + * - Forecast mean + - FBAR + - Categorical + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + - SSVAR :raw-html:`
` + CNT :raw-html:`
` + SL1L2 :raw-html:`
` + VCNT + * - Length (speed) of the :raw-html:`
` + average forecast :raw-html:`
` + wind vector + - FBAR :raw-html:`
` + _SPEED + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Frequency Bias + - FBIAS + - Categorical + - Wavelet-Stat :raw-html:`
` + MODE :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + - ISC :raw-html:`
` + MODE :raw-html:`
` + CTS :raw-html:`
` + NBRCTCS :raw-html:`
` + DMAP + * - Fractions Brier Score + - FBS + - Continuous + - Grid-Stat + - NBRCNT + * - Number of forecast :raw-html:`
` + clusters + - fcst_clus + - Diagnostic + - MODE + - MODE obj + * - Number of points used to :raw-html:`
` + define the hull of all :raw-html:`
` + of the cluster forecast :raw-html:`
` + objects + - fcst_clus :raw-html:`
` + _hull + - Diagnostic + - MODE + - MODE obj + * - Forecast Cluster Convex :raw-html:`
` + Hull Point Latitude + - fcst_clus :raw-html:`
` + _hull_lat + - Diagnostic + - MODE + - MODE obj + * - Forecast Cluster Convex :raw-html:`
` + Hull Point Longitude + - fcst_clus :raw-html:`
` + _hull _lon + - Diagnostic + - MODE + - MODE obj + * - Number of Forecast :raw-html:`
` + Cluster Convex Hull Points + - fcst_clus :raw-html:`
` + _hull_npts + - Diagnostic + - MODE + - MODE obj + * - Forecast Cluster Convex :raw-html:`
` + Hull Starting Index + - fcst_clus :raw-html:`
` + _hull_start + - Diagnostic + - MODE + - MODE obj + * - Forecast Cluster Convex :raw-html:`
` + Hull Point X-Coordinate + - fcst_clus :raw-html:`
` + _hull_x + - Diagnostic + - MODE + - MODE obj + * - Forecast Cluster Convex :raw-html:`
` + Hull Point Y-Coordinate + - fcst_clus :raw-html:`
` + _hull_y + - Diagnostic + - MODE + - MODE obj + * - Forecast Object Raw :raw-html:`
` + Values + - fcst_obj :raw-html:`
` + _raw + - Diagnostic + - MODE + - MODE obj + * - Number of simple :raw-html:`
` + forecast objects + - fcst_simp + - Diagnostic + - MODE + - MODE obj + * - Number of points used :raw-html:`
` + to define the boundaries :raw-html:`
` + of all of the simple :raw-html:`
` + forecast objects + - fcst_simp :raw-html:`
` + _bdy + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple :raw-html:`
` + Boundary Latitude + - fcst_simp :raw-html:`
` + _bdy_lat + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple :raw-html:`
` + Boundary Longitude + - fcst_simp :raw-html:`
` + _bdy_lon + - Diagnostic + - MODE + - MODE obj + * - Number of Forecast :raw-html:`
` + Simple Boundary Points + - fcst_simp :raw-html:`
` + _bdy_npts + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple :raw-html:`
` + Boundary Starting Index + - fcst_simp :raw-html:`
` + _bdy_start + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple :raw-html:`
` + Boundary X-Coordinate + - fcst_simp :raw-html:`
` + _bdy_x + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple :raw-html:`
` + Boundary Y-Coordinate + - fcst_simp :raw-html:`
` + _bdy_y + - Diagnostic + - MODE + - MODE obj + * - Number of points used to :raw-html:`
` + define the hull of all :raw-html:`
` + of the simple forecast :raw-html:`
` + objects + - fcst_simp :raw-html:`
` + _hull + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple Convex :raw-html:`
` + Hull Point Latitude + - fcst_simp :raw-html:`
` + _hull_lat + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple Convex :raw-html:`
` + Hull Point Longitude + - fcst_simp :raw-html:`
` + _hull_lon + - Diagnostic + - MODE + - MODE obj + * - Number of Forecast :raw-html:`
` + Simple Convex Hull Points + - fcst_simp :raw-html:`
` + _hull_npts + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple Convex :raw-html:`
` + Hull Starting Index + - fcst_simp :raw-html:`
` + _hull_start + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple Convex :raw-html:`
` + Hull Point X-Coordinate + - fcst_simp :raw-html:`
` + _hull_x + - Diagnostic + - MODE + - MODE obj + * - Forecast Simple Convex :raw-html:`
` + Hull Point Y-Coordinate + - fcst_simp :raw-html:`
` + _hull_y + - Diagnostic + - MODE + - MODE obj + * - Number of thresholds :raw-html:`
` + applied to the forecast + - fcst :raw-html:`
` + _thresh :raw-html:`
` + _length + - Diagnostic + - MODE + - MODE obj + * - Number of thresholds :raw-html:`
` + applied to the forecast + - fcst_thresh :raw-html:`
` + _length + - Diagnostic + - MODE + - MODE obj + * - Direction of the average :raw-html:`
` + forecast wind vector + - FDIR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Forecast energy squared :raw-html:`
` + for this scale + - FENERGY + - + - Wavelet-Stat + - ISC + * - Mean Forecast Anomaly Squared + - FFABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - SAL1L2 + * - Average of forecast :raw-html:`
` + squared. + - FFBAR + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + SL1L2 + * - Mean of absolute value :raw-html:`
` + of forecast gradients + - FGBAR + - + - Grid-Stat + - GRAD + * - Ratio of forecast and :raw-html:`
` + observed gradients + - FGOG_RATIO + - + - Grid-Stat + - GRAD + * - Count of events in :raw-html:`
` + forecast category i and :raw-html:`
` + observation category j + - Fi_Oj + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - MCTC + * - Forecast mean + - FMEAN + - Continuous + - MODE :raw-html:`
` + Grid-Stat :raw-html:`
` + Point-Stat + - MODE :raw-html:`
` + NBRCTCS :raw-html:`
` + CTS + * - Number of forecast no :raw-html:`
` + and observation no + - FN_ON + - Categorical + - MODE :raw-html:`
` + Grid-Stat :raw-html:`
` + Point-Stat + - MODE :raw-html:`
` + NBRCTC :raw-html:`
` + CTC + * - Number of forecast no :raw-html:`
` + and observation yes + - FN_OY + - Categorical + - MODE :raw-html:`
` + Grid-Stat :raw-html:`
` + Point-Stat + - MODE :raw-html:`
` + NBRCTC :raw-html:`
` + CTC + * - Attributes for pairs of :raw-html:`
` + simple forecast and :raw-html:`
` + observation objects + - FNNN_ONNN + - Categorical + - MODE + - MODE obj + * - Average product of :raw-html:`
` + forecast-climo and :raw-html:`
` + observation-climo :raw-html:`
` + / Mean(f-c)*(o-c) + - FOABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - SAL1L2 + * - Average product of :raw-html:`
` + forecast and observation :raw-html:`
` + / Mean(f*o) + - FOBAR + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + SL1L2 + * - Pratt’s Figure of Merit :raw-html:`
` + from observation to :raw-html:`
` + forecast + - FOM_FO + - Diagnostic + - Grid-Stat + - DMAP + * - Maximum of FOM_FO :raw-html:`
` + and FOM_OF + - FOM_MAX + - Diagnostic + - Grid-Stat + - DMAP + * - Mean of FOM_FO :raw-html:`
` + and FOM_OF :raw-html:`
` + - FOM_MEAN + - Diagnostic + - Grid-Stat + - DMAP + * - Minimum of FOM_FO :raw-html:`
` + and FOM_OF + - FOM_MIN + - Diagnostic + - Grid-Stat + - DMAP + * - Pratt’s Figure of Merit :raw-html:`
` + from forecast to :raw-html:`
` + observation + - FOM_OF + - Diagnostic + - Grid-Stat + - DMAP + * - Number of tied forecast :raw-html:`
` + ranks used in computing :raw-html:`
` + Kendall’s tau statistic + - FRANK_TIES + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Root mean square forecast :raw-html:`
` + wind speed + - FS_RMS + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Fractions Skill Score :raw-html:`
` + - FSS + - Neighborhood + - Grid-Stat + - NBRCNT + * - Standard deviation of the :raw-html:`
` + error + - FSTDEV + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + CNT :raw-html:`
` + VCNT + * - Number of forecast events + - FY + - Categorical + - Grid-Stat + - DMAP + * - Number of forecast yes :raw-html:`
` + and observation no + - FY_ON + - Categorical + - MODE :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - MODE :raw-html:`
` + CTC :raw-html:`
` + NBRCTC + * - Number of forecast yes :raw-html:`
` + and observation yes + - FY_OY + - Categorical + - MODE :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - MODE :raw-html:`
` + CTC :raw-html:`
` + NBRCTC + * - Distance between the :raw-html:`
` + forecast and Best track :raw-html:`
` + genesis events (km) + - GEN_DIST + - Diagnostic + - TC-Gen + - GENMPR + * - Forecast minus Best track :raw-html:`
` + genesis time in HHMMSS :raw-html:`
` + format + - GEN_TDIFF + - Diagnostic + - TC-Gen + - GENMPR + * - Gerrity Score and :raw-html:`
` + bootstrap confidence limits + - GER + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - MCTS + * - Gilbert Skill Score + - GSS + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + MODE + - CTS :raw-html:`
` + NBRCTCS :raw-html:`
` + MODE + * - Hit rate + - H_RATE + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - FHO + * - Hausdorff Distance + - HAUSDORFF + - Diagnostic + - Grid-Stat + - DMAP + * - Hanssen and Kuipers :raw-html:`
` + Discriminant + - HK + - Categorical + - MODE :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - MODE cts :raw-html:`
` + MCTS :raw-html:`
` + CTS :raw-html:`
` + NBRCTS + * - Heidke Skill Score + - HSS + - Categorical + - MODE :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - MODE cts :raw-html:`
` + MCTS :raw-html:`
` + CTS :raw-html:`
` + NBRCTS + * - Heidke Skill Score :raw-html:`
` + user-specific expected :raw-html:`
` + correct + - HSS_EC + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - MCTS + * - Ignorance Score + - IGN + - Ensemble + - Ensemble-Stat + - ECNT + * - Best track genesis minus :raw-html:`
` + forecast initialization :raw-html:`
` + time in HHMMSS format + - INIT_TDIFF + - Diagnostic + - TC-Gen + - GENMPR + * - 10th, 25th, 50th, 75th, :raw-html:`
` + 90th, and user-specified :raw-html:`
` + percentiles of :raw-html:`
` + intensity of the raw :raw-html:`
` + field within the :raw-html:`
` + object or time slice + - INTENSITY :raw-html:`
` + _10, _25, :raw-html:`
` + _50, _75, :raw-html:`
` + _90, _NN + - Diagnostic + - MODE + - MODE obj + * - Sum of the intensities of :raw-html:`
` + the raw field within the :raw-html:`
` + object (variable units) + - INTENSITY :raw-html:`
` + _SUM + - Diagnostics + - MODE + - MODE obj + * - Total interest for this :raw-html:`
` + object pair + - INTEREST + - Diagnostic + - MTD :raw-html:`
` + MODE + - MTD 3D obj :raw-html:`
` + MODE obj + * - Intersection area of two :raw-html:`
` + objects (in grid squares) + - INTERSECT :raw-html:`
` + ION_AREA + - Diagnostic + - MODE + - MODE obj + * - Ratio of intersection area :raw-html:`
` + to the lesser of the :raw-html:`
` + forecast and observation :raw-html:`
` + object areas (unitless) + - INTERSECT :raw-html:`
` + ION_OVER :raw-html:`
` + _AREA + - Diagnostic + - MODE + - MODE obj + * - “Volume” of object :raw-html:`
` + intersection + - INTERSECT :raw-html:`
` + ION_VOLUME + - Diagnostic + - MTD + - MTD 3D obj + * - Interquartile Range :raw-html:`
` + - IQR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - The intensity scale :raw-html:`
` + skill score + - ISC + - + - Wavelet-Stat + - ISC + * - The scale at which all :raw-html:`
` + information following :raw-html:`
` + applies + - ISCALE + - + - Wavelet-Stat + - ISC + * - Kendall’s tau statistic + - KT_CORR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Dimension of the latitude + - LAT + - Diagnostic + - MODE + - MODE obj + * - Length of the :raw-html:`
` + enclosing rectangle + - LENGTH + - Diagnostic + - MODE + - MODE obj + * - Likelihood when forecast :raw-html:`
` + is between the ith and :raw-html:`
` + i+1th probability :raw-html:`
` + thresholds repeated + - LIKELIHOOD :raw-html:`
` + _i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PJC + * - Logarithm of the Odds Ratio + - LODDS + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Dimension of the longitude + - LON + - Diagnostic + - MODE + - MODE obj + * - The Median Absolute :raw-html:`
` + Deviation + - MAD + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Mean absolute error + - MAE + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT :raw-html:`
` + SAL1L2 :raw-html:`
` + SL1L2 + * - Magnitude & :raw-html:`
` + Multiplicative bias + - MBIAS + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + CNT + * - The Mean Error + - ME + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - ECNT :raw-html:`
` + SSVAR :raw-html:`
` + CNT + * - The Mean Error of the :raw-html:`
` + PERTURBED ensemble mean + - ME_OERR + - Continuous + - Ensemble-Stat + - ECNT + * - The square of the :raw-html:`
` + mean error (bias) + - ME2 + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Mean-error Distance from :raw-html:`
` + observation to forecast + - MED_FO + - Distance + - Grid-Stat + - DMAP + * - Maximum of MED_FO :raw-html:`
` + and MED_OF + - MED_MAX + - Distance + - Grid-Stat + - DMAP + * - Mean of MED_FO :raw-html:`
` + and MED_OF + - MED_MEAN + - Distance + - Grid-Stat + - DMAP + * - Minimum of MED_FO :raw-html:`
` + and MED_OF + - MED_MIN + - Distance + - Grid-Stat + - DMAP + * - Mean-error Distance from :raw-html:`
` + forecast to observation + - MED_OF + - Distance + - Grid-Stat + - DMAP + * - Mean of maximum of :raw-html:`
` + absolute values of :raw-html:`
` + forecast and observed :raw-html:`
` + gradients + - MGBAR + - + - Grid-Stat + - GRAD + * - Mean squared error + - MSE + - Continuous + - Ensemble-Stat :raw-html:`
` + Wavelet-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + ISC :raw-html:`
` + CNT :raw-html:`
` + * - The mean squared error :raw-html:`
` + skill + - MSESS + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Mean squared length of :raw-html:`
` + the vector difference :raw-html:`
` + between the forecast :raw-html:`
` + and observed winds + - MSVE + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Dimension of the :raw-html:`
` + contingency table & the :raw-html:`
` + total number of :raw-html:`
` + categories in each :raw-html:`
` + dimension + - N_CAT + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - MCTC :raw-html:`
` + MCTS + * - Number of cluster objects + - N_CLUS + - Diagnostic + - MODE + - MODE obj + * - Number of simple :raw-html:`
` + forecast objects + - N_FCST_SIMP + - Diagnostic + - MODE + - MODE obj + * - Number of simple :raw-html:`
` + observation objects + - N_OBS_SIMP + - Diagnostic + - MODE + - MODE obj + * - Observation rate + - O_RATE + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - NBRCNT :raw-html:`
` + FHO + * - Mean observed wind speed + - O_SPEED_BAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Mean Observation Anomaly + - OABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - SAL1L2 + * - Average observed value :raw-html:`
` + - OBAR + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` . + - SSVAR :raw-html:`
` + CNT :raw-html:`
` + SL1L2 :raw-html:`
` + VCNT + * - Length (speed) of the :raw-html:`
` + average observed wind :raw-html:`
` + vector + - OBAR_SPEED + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Number of observed :raw-html:`
` + clusters + - obs_clus + - Diagnostic + - MODE + - MODE obj + * - Number of points used to :raw-html:`
` + define the hull of all of :raw-html:`
` + the cluster observation :raw-html:`
` + objects + - obs_clus :raw-html:`
` + _hull + - Diagnostic + - MODE + - MODE obj + * - Observation Cluster Convex :raw-html:`
` + Hull Point Latitude + - obs_clus :raw-html:`
` + _hull_lat + - Diagnostic + - MODE + - MODE obj + * - Observation Cluster Convex :raw-html:`
` + Hull Point Longitude + - obs_clus :raw-html:`
` + _hull_lon + - Diagnostic + - MODE + - MODE obj + * - Number of Observation :raw-html:`
` + Cluster Convex Hull Points + - obs_clus :raw-html:`
` + _hull_npts + - Diagnostic + - MODE + - MODE obj + * - Observation Cluster Convex :raw-html:`
` + Hull Starting Index + - obs_clus :raw-html:`
` + _hull_start + - Diagnostic + - MODE + - MODE obj + * - Observation Cluster Convex :raw-html:`
` + Hull Point X-Coordinate + - obs_clus :raw-html:`
` + _hull_x + - Diagnostic + - MODE + - MODE obj + * - Observation Cluster Convex :raw-html:`
` + Hull Point Y-Coordinate + - obs_clus :raw-html:`
` + _hull_y + - Diagnostic + - MODE + - MODE obj + * - Number of simple :raw-html:`
` + observation objects + - obs_simp + - Diagnostic + - MODE + - MODE obj + * - Number of points used :raw-html:`
` + to define the boundaries :raw-html:`
` + of the simple observation :raw-html:`
` + objects + - obs_simp :raw-html:`
` + _bdy + - Diagnostic + - MODE + - MODE obj + * - Observation Simple :raw-html:`
` + Boundary Point Latitude + - obs_simp :raw-html:`
` + _bdy_lat + - Diagnostic + - MODE + - MODE obj + * - Observation Simple :raw-html:`
` + Boundary Point Longitude + - obs_simp :raw-html:`
` + _bdy_lon + - Diagnostic + - MODE + - MODE obj + * - Number of Observation :raw-html:`
` + Simple Boundary Points + - obs_simp :raw-html:`
` + _bdy_npts + - Diagnostic + - MODE + - MODE obj + * - Number of points used to :raw-html:`
` + define the hull of the :raw-html:`
` + simple observation objects + - obs_simp :raw-html:`
` + _hull + - Diagnostic + - MODE + - MODE obj + * - Number of Observation :raw-html:`
` + Simple Convex Hull Points + - obs_simp :raw-html:`
` + _hull_npts + - Diagnostic + - MODE + - MODE obj + * - Odds Ratio + - ODDS + - Categorical + - MODE :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - MODE :raw-html:`
` + CTS :raw-html:`
` + NBRCTS + * - Direction of the average :raw-html:`
` + observed wind vector + - ODIR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Observed energy squared :raw-html:`
` + for this scale + - OENERGY + - + - Wavelet-Stat + - ISC + * - Mean of absolute value :raw-html:`
` + of observed gradients + - OGBAR + - + - Grid-Stat + - GRAD + * - Number of observation :raw-html:`
` + when forecast is between :raw-html:`
` + the ith and i+1th :raw-html:`
` + probability thresholds + - ON_i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PTC + * - Number of observation :raw-html:`
` + when forecast is between :raw-html:`
` + the ith and i+1th :raw-html:`
` + probability thresholds + - ON_TP_i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PJC + * - Mean Squared :raw-html:`
` + Observation Anomaly + - OOABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - SAL1L2 + * - Average of observation :raw-html:`
` + squared + - OOBAR + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + SL1L2 :raw-html:`
` + * - Number of tied observation :raw-html:`
` + ranks used in computing :raw-html:`
` + Kendall’s tau statistic + - ORANK_TIES + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Odds Ratio Skill Score + - ORSS + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Root mean square observed :raw-html:`
` + wind speed + - OS_RMS + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Standard deviation :raw-html:`
` + of observations + - OSTDEV + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + CNT :raw-html:`
` + VCNT + * - Number of observation :raw-html:`
` + events + - OY + - Categorical + - Grid-Stat + - DMAP + * - Number of observation yes :raw-html:`
` + when forecast is between :raw-html:`
` + the ith and i+1th :raw-html:`
` + probability thresholds + - OY_i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PTC + * - Number of observation yes :raw-html:`
` + when forecast is between :raw-html:`
` + the ith and i+1th :raw-html:`
` + probability thresholds :raw-html:`
` + as a proportion of the :raw-html:`
` + total OY (repeated) + - OY_TP_i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PJC + * - Ratio of the nth percentile :raw-html:`
` + (INTENSITY_NN column) of :raw-html:`
` + intensity of the two :raw-html:`
` + objects + - PERCENTILE :raw-html:`
` + _INTENSITY :raw-html:`
` + _RATIO + - Diagnostic + - MODE + - MODE obj + * - Probability Integral :raw-html:`
` + Transform + - PIT + - Ensemble + - Ensemble-Stat + - ORANK + * - Probability of false :raw-html:`
` + detection + - PODF + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS + * - Probability of detecting no + - PODN + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + MODE + - CTS :raw-html:`
` + NBRCTCS :raw-html:`
` + MODE + * - Probability of detecting :raw-html:`
` + yes + - PODY + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + MODE + - CTS :raw-html:`
` + NBRCTCS :raw-html:`
` + MODE + * - Probability of detecting :raw-html:`
` + yes when forecast is :raw-html:`
` + greater than the ith :raw-html:`
` + probability thresholds + - PODY_i + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - PRC + * - Probability of false :raw-html:`
` + detection + - POFD + - Categorical + - MODE :raw-html:`
` + Grid-Stat + - MODE :raw-html:`
` + NBRCTCS + * - Probability of false :raw-html:`
` + detection when forecast is :raw-html:`
` + greater than the ith :raw-html:`
` + probability thresholds + - POFD_i + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - PRC + * - Pearson correlation :raw-html:`
` + coefficient + - PR_CORR + - Continuous + - Ensemble-Stat :raw-html:`
` + Point-Stat :raw-html:`
` + Grid-Stat + - SSVAR :raw-html:`
` + CNT :raw-html:`
` + * - Rank of the observation + - RANK + - Ensemble + - Ensemble-Stat + - ORANK + * - Count of observations :raw-html:`
` + with the i-th rank + - RANK_i + - Ensemble + - Ensemble-Stat + - RHIST + * - Number of ranks used in :raw-html:`
` + computing Kendall’s tau :raw-html:`
` + statistic + - RANKS + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Refinement when forecast :raw-html:`
` + is between the ith and :raw-html:`
` + i+1th probability :raw-html:`
` + thresholds (repeated) + - REFINEMENT :raw-html:`
` + _i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PJC + * - Reliability + - RELIABILITY + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Number of times the i-th :raw-html:`
` + ensemble member’s value :raw-html:`
` + was closest to the :raw-html:`
` + observation (repeated). :raw-html:`
` + When n members tie, :raw-html:`
` + 1/n is assigned to each :raw-html:`
` + member. + - RELP_i + - Ensemble + - Ensemble-Stat + - RELP + * - Resolution + - RESOLUTION + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Root mean squared error + - RMSE + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat :raw-html:`
` + Ensemble-Stat :raw-html:`
` + - CNT :raw-html:`
` + ECNT :raw-html:`
` + SSVAR + * - Root Mean Square Error :raw-html:`
` + of the PERTURBED :raw-html:`
` + ensemble mean + - RMSE_OERR + - Continuous + - Ensemble-Stat + - ECNT + * - Root mean squared forecast :raw-html:`
` + anomaly + - RMSFA + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Root mean squared :raw-html:`
` + observation anomaly + - RMSOA + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Square root of MSVE + - RMSVE + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Area under the receiver :raw-html:`
` + operating characteristic :raw-html:`
` + curve + - ROC_AUC + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Mean of the Brier Scores :raw-html:`
` + for each RPS threshold + - RPS + - Ensemble + - Ensemble-Stat + - RPS + * - Mean of the reliabilities :raw-html:`
` + for each RPS threshold + - RPS_REL + - Ensemble + - Ensemble-Stat + - RPS + * - Mean of the resolutions :raw-html:`
` + for each RPS threshold + - RPS_RES + - Ensemble + - Ensemble-Stat + - RPS + * - Mean of the uncertainties :raw-html:`
` + for each RPS threshold + - RPS_UNC + - Ensemble + - Ensemble-Stat + - RPS + * - Ranked Probability Skill :raw-html:`
` + Score relative to external :raw-html:`
` + climatology + - RPSS + - Ensemble + - Ensemble-Stat + - RPS + * - Ranked Probability Skill :raw-html:`
` + Score relative to sample :raw-html:`
` + climatology + - RPSS_SMPL + - Ensemble + - Ensemble-Stat + - RPS + * - S1 score + - S1 + - Continuous + - Grid-Stat + - GRAD + * - S1 score with respect to :raw-html:`
` + observed gradient + - S1_OG + - Continuous + - Grid-Stat + - GRAD + * - Symmetric Extremal :raw-html:`
` + Dependency Index + - SEDI + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Symmetric Extreme :raw-html:`
` + Dependency Score + - SEDS + - Categorical + - Point-Stat :raw-html:`
` + Grid-Stat + - CTS :raw-html:`
` + NBRCTS + * - Scatter Index + - SI + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Spearman’s rank :raw-html:`
` + correlation coefficient + - SP_CORR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - CNT + * - Spatial distance between :raw-html:`
` + (𝑥,𝑦)(x,y) coordinates of :raw-html:`
` + object spacetime centroid + - SPACE :raw-html:`
` + _CENTROID :raw-html:`
` + _DIST + - Diagnostics + - MTD + - MTD 3D obs + * - Absolute value of SPEED_ERR + - SPEED :raw-html:`
` + _ABSERR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Difference in object speeds + - SPEED_DELTA + - Diagnostics + - MTD + - MTD 3D obs + * - Difference between the :raw-html:`
` + length of the average :raw-html:`
` + forecast wind vector and :raw-html:`
` + the average observed wind :raw-html:`
` + vector (in the sense F - O) + - SPEED_ERR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Standard deviation :raw-html:`
` + of the mean of the :raw-html:`
` + UNPERTURBED ensemble + - SPREAD + - Ensemble + - Ensemble-Stat + - ECNT :raw-html:`
` + ORANK + * - Standard deviation :raw-html:`
` + of the mean of the :raw-html:`
` + PERTURBED ensemble + - SPREAD_OERR + - Ensemble + - Ensemble-Stat + - ECNT :raw-html:`
` + ORANK + * - Standard Deviation :raw-html:`
` + of unperturbed ensemble :raw-html:`
` + variance and the :raw-html:`
` + observation error variance + - SPREAD_PLUS :raw-html:`
` + _OERR + - Ensemble + - Ensemble-Stat + - ECNT :raw-html:`
` + ORANK + * - Difference in object :raw-html:`
` + starting time steps + - START_TIME :raw-html:`
` + _DELTA + - Diagnostic + - MTD + - MTD 3D obj + * - Symmetric difference of :raw-html:`
` + two objects :raw-html:`
` + (in grid squares) + - SYMMETRIC :raw-html:`
` + _DIFF + - Diagnostics + - MODE + - MODE obj + * - Difference in t index of :raw-html:`
` + object spacetime centroid + - TIME :raw-html:`
` + _CENTROID :raw-html:`
` + _DELTA + - Diagnostic + - MTD + - MTD 3D obj + * - Track error of adeck :raw-html:`
` + relative to bdeck (nm) + - TK_ERR + - Continuous + - TC-Pairs + - PROBRIRW + * - Track error of adeck :raw-html:`
` + relative to bdeck (nm) + - TK_ERR + - Continuous + - TC-Pairs + - TCMPR + * - Mean U-component :raw-html:`
` + Forecast Anomaly + - UFABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean U-component + - UFBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Uniform Fractions Skill :raw-html:`
` + Score + - UFSS + - Neighborhood + - Grid-Stat + - NBRCNT + * - Variability of :raw-html:`
` + Observations + - UNCERTAINTY + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - PSTD + * - Union area of :raw-html:`
` + two objects :raw-html:`
` + (in grid squares) + - UNION_AREA + - Diagnostic + - MODE + - MODE obj + * - Mean U-component :raw-html:`
` + Observation Anomaly + - UOABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean U-component :raw-html:`
` + Observation + - UOBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Mean U-component :raw-html:`
` + Squared :raw-html:`
` + Forecast Anomaly :raw-html:`
` + plus Squared :raw-html:`
` + Observation :raw-html:`
` + Anomaly + - UVFFABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean U-component :raw-html:`
` + Squared :raw-html:`
` + Forecast :raw-html:`
` + plus Squared :raw-html:`
` + Observation + - UVFFBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Mean((uf-uc)*(uo-uc)+ :raw-html:`
` + (vf-vc)*(vo-vc)) + - UVFOABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean(uf*uo+vf*vo) + - UVFOBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Mean((uo-uc)²+(vo-vc)²) + - UVOOABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean(uo²+vo²) + - UVOOBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Economic value of the :raw-html:`
` + base rate + - VALUE_BASER + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - ECLV + * - Relative value for the :raw-html:`
` + ith Cost/Loss ratio + - VALUE_i + - Probability + - Point-Stat :raw-html:`
` + Grid-Stat + - ECLV + * - Maximum variance + - VAR_MAX + - Ensemble + - Ensemble-Stat + - SSVAR + * - Average variance + - VAR_MEAN + - Ensemble + - Ensemble-Stat + - SSVAR + * - Minimum variance + - VAR_MIN + - Ensemble + - Ensemble-Stat + - SSVAR + * - Direction of the vector :raw-html:`
` + difference between the :raw-html:`
` + average forecast and :raw-html:`
` + average wind vectors + - VDIFF_DIR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Length (speed) of the :raw-html:`
` + vector difference between :raw-html:`
` + the average forecast and :raw-html:`
` + average observed wind :raw-html:`
` + vectors + - VDIFF_SPEED + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VCNT + * - Mean(vf-vc) + - VFABAR + - Continous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean(vf) + - VFBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Mean(vo-vc) + - VOABAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VAL1L2 + * - Mean(vo) + - VOBAR + - Continuous + - Point-Stat :raw-html:`
` + Grid-Stat + - VL1L2 + * - Integer count of the :raw-html:`
` + number of 3D “cells” :raw-html:`
` + in an object + - VOLUME + - Diagnostic + - MTD + - MTD 3D obj + * - Forecast object volume :raw-html:`
` + divided by observation :raw-html:`
` + object volume + - VOLUME :raw-html:`
` + _RATIO + - Diagnostic + - MTD + - MTD 3D obj + * - Width of the enclosing :raw-html:`
` + rectangle (in grid units) + - WIDTH + - Diagnostic + - MODE + - MODE obj + * - X component of :raw-html:`
` + object velocity + - X_DOT + - Diagnostic + - MTD + - MTD 3D obj + * - X component position :raw-html:`
` + error (nm) + - X_ERR + - Diagnostic + - TC-Pairs + - PROBRIRW + * - X component position :raw-html:`
` + error (nm) + - X_ERR + - Diagnostic + - TC-Pairs + - TCMPR + * - y component of :raw-html:`
` + object velocity + - Y_DOT + - Diagnostic + - MTD + - MTD 3D obj + * - Y component position :raw-html:`
` + error (nm) + - Y_ERR + - Diagnostic + - TC-Pairs + - PROBRIRW :raw-html:`
` + TCMPR + * - Zhu’s Measure from :raw-html:`
` + observation to forecast + - ZHU_FO + - Diagnostic + - Grid-Stat + - DMAP + * - Maximum of ZHU_FO :raw-html:`
` + and ZHU_OF + - ZHU_MAX + - Diagnostic + - Grid-Stat + - DMAP + * - Mean of ZHU_FO :raw-html:`
` + and ZHU_OF + - ZHU_MEAN + - Diagnostic + - Grid-Stat + - DMAP + * - Minimum of ZHU_FO :raw-html:`
` + and ZHU_OF + - ZHU_MIN + - Diagnostic + - Grid-Stat + - DMAP + * - Zhu’s Measure from :raw-html:`
` + forecast to observation + - ZHU_OF + - Diagnostic + - Grid-Stat + - DMAP diff --git a/docs/_static/s2s-OMI_GFS_phase_diagram.png b/docs/_static/s2s-OMI_GFS_phase_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec1b3adb66614f7a9bb525374cacbf2c257c98c GIT binary patch literal 55990 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%0D1YG=!A1Si{2FwTbo$=dxB}l;;Ct~~ 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, -# `RegridDataPlaneUseCase `_, -# `PCPCombineUseCase `_ - diff --git a/docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.py b/docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.py deleted file mode 100644 index b6b618c66b..0000000000 --- a/docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.py +++ /dev/null @@ -1,263 +0,0 @@ -""" -UserScript: Make RMM plots from calculated MJO indices -=========================================================================== - -model_applications/ -s2s/ -UserScript_fcstGFS_obsERA_RMM.py - -""" - -############################################################################## -# Scientific Objective -# -------------------- -# -# To compute the Real-time Multivariate MJO Index (RMM) using Outgoing Longwave Radiation (OLR), 850 hPa wind (U850), and 200 hPa wind (U200). Specifically, RMM is computed using OLR, U850, andU200 data between 15N and 15S. Anomalies of OLR, U850, and U200 are then created, 120 day day mean removed, and the data are normalized by normalization factors (generally the square root of the average variance) The anomalies are projected onto Empirical Orthogonal Function (EOF) data. The OLR is then filtered for 20 - 96 days, and regressed onto the daily EOFs. Finally, it's normalized and these normalized components are plotted on a phase diagram and timeseries plot. -# - -############################################################################## -# Datasets -# -------- -# -# * Forecast dataset: GFS Model Outgoing Longwave Radiation -# * Observation dataset: ERA Reanlaysis Outgoing Longwave Radiation. - -############################################################################## -# External Dependencies -# --------------------- -# -# You will need to use a version of Python 3.6+ that has the following packages installed:: -# -# * numpy -# * netCDF4 -# * datetime -# * xarray -# * matplotlib -# * scipy -# * pandas -# -# If the version of Python used to compile MET did not have these libraries at the time of compilation, you will need to add these packages or create a new Python environment with these packages. -# -# If this is the case, you will need to set the MET_PYTHON_EXE environment variable to the path of the version of Python you want to use. If you want this version of Python to only apply to this use case, set it in the [user_env_vars] section of a METplus configuration file.: -# -# [user_env_vars] -# MET_PYTHON_EXE = /path/to/python/with/required/packages/bin/python -# - -############################################################################## -# METplus Components -# ------------------ -# -# This use case runs the OMI driver which computes OMI and creates a phase diagram. Inputs to the OMI driver include netCDF files that are in MET's netCDF version. In addition, a txt file containing the listing of these input netCDF files is required, as well as text file listings of the EOF1 and EOF2 files. Some optional pre-processing steps include using regrid_data_plane to either regrid your data or cut the domain t0 20N - 20S. -# - -############################################################################## -# METplus Workflow -# ---------------- -# -# The OMI driver script python code is run for each lead time on the forecast and observations data. This example loops by valid time for the model pre-processing, and valid time for the other steps. This version is set to only process the OMI calculation and creating a text file listing of the EOF files, omitting the regridding, and anomaly caluclation pre-processing steps. However, the configurations for pre-processing are available for user reference. - -############################################################################## -# METplus Configuration -# --------------------- -# -# METplus first loads all of the configuration files found in parm/metplus_config, -# then it loads any configuration files passed to METplus via the command line -# i.e. parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf. -# The file OMI_driver.py runs the python program and -# UserScript_fcstGFS_obsERA_OMI/UserScript_fcstGFS_obsERA_OMI.conf sets the -# variables for all steps of the OMI use case. -# -# .. highlight:: bash -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf - -############################################################################## -# MET Configuration -# --------------------- -# -# METplus sets environment variables based on the values in the METplus configuration file. -# These variables are referenced in the MET configuration file. **YOU SHOULD NOT SET ANY OF THESE ENVIRONMENT VARIABLES YOURSELF! THEY WILL BE OVERWRITTEN BY METPLUS WHEN IT CALLS THE MET TOOLS!** If there is a setting in the MET configuration file that is not controlled by an environment variable, you can add additional environment variables to be set only within the METplus environment using the [user_env_vars] section of the METplus configuration files. See the 'User Defined Config' section on the 'System Configuration' page of the METplus User's Guide for more information. -# -# - -############################################################################## -# Python Scripts -# ---------------- -# -# The OMI driver script orchestrates the calculation of the MJO indices and -# the generation of a phase diagram OMI plot: -# parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py: -# -# .. highlight:: python -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py -# - -############################################################################## -# Running METplus -# --------------- -# -# This use case is run in the following ways: -# -# 1) Passing in UserScript_fcstGFS_obsERA_OMI.conf then a user-specific system configuration file:: -# -# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf -c /path/to/user_system.conf -# -# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_fcstGFS_obsERA_OMI.py:: -# -# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf -# -# The following variables must be set correctly: -# -# * **INPUT_BASE** - Path to directory where sample data tarballs are unpacked (See Datasets section to obtain tarballs). This is not required to run METplus, but it is required to run the examples in parm/use_cases -# * **OUTPUT_BASE** - Path where METplus output will be written. This must be in a location where you have write permissions -# * **MET_INSTALL_DIR** - Path to location where MET is installed locally -# -# Example User Configuration File:: -# -# [dir] -# INPUT_BASE = /path/to/sample/input/data -# OUTPUT_BASE = /path/to/output/dir -# MET_INSTALL_DIR = /path/to/met-X.Y -# - -############################################################################## -# Expected Output -# --------------- -# -# Refer to the value set for **OUTPUT_BASE** to find where the output data was generated. Output for this use case will be found in model_applications/s2s/UserScript_fcstGFS_obsERA_OMI. This may include the regridded data and daily averaged files. In addition, the phase diagram plots will be generated and the output location can be specified as OMI_PLOT_OUTPUT_DIR. If it is not specified, plots will be sent to model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/plots (relative to **OUTPUT_BASE**). - -############################################################################## -# Keywords -# -------- -# -# sphinx_gallery_thumbnail_path = '_static/s2s-OMI_phase_diagram.png' -# -# .. note:: `XXXX`, `S2SAppUseCase `_ -# `RegridDataPlaneUseCase `_, -# `PCPCombineUseCase `_ - - -# -# - -############################################################################## -# Datasets -# -------- -# -# * Forecast dataset: GFS Model Outgoing Longwave Radiation, 850 hPa wind and 200 hPa wind -# * Observation dataset: ERA Reanlaysis Outgoing Longwave Radiation, 850 hPa wind and 200 hPa wind - -############################################################################## -# External Dependencies -# --------------------- -# -# You will need to use a version of Python 3.6+ that has the following packages installed:: -# -# * numpy -# * netCDF4 -# * datetime -# * xarray -# * matplotlib -# * scipy -# * pandas -# -# If the version of Python used to compile MET did not have these libraries at the time of compilation, you will need to add these packages or create a new Python environment with these packages. -# -# If this is the case, you will need to set the MET_PYTHON_EXE environment variable to the path of the version of Python you want to use. If you want this version of Python to only apply to this use case, set it in the [user_env_vars] section of a METplus configuration file.: -# -# [user_env_vars] -# MET_PYTHON_EXE = /path/to/python/with/required/packages/bin/python -# - -############################################################################## -# METplus Components -# ------------------ -# -# This use case runs the RMM driver which computes RMM and creates a phase diagram, time series, and EOF plot. Inputs to the RMM driver include netCDF files that are in MET's netCDF version. In addition, a text file containing the listing of these input netCDF files for OLR, u850 and u200 is required. Some optional pre-processing steps include using regrid_data_plane to either regrid your data or cut the domain t0 20N - 20S. -# - -############################################################################## -# METplus Workflow -# ---------------- -# The RMM driver script python code is run for each lead time on the forecast and observations data. This example loops by valid time for the model pre-processing, and valid time for the other steps. This version is set to only process the RMM calculation, omitting the regridding, and anomaly caluclation, and creation of the text file listing for OLR, u850, and u200 pre-processing steps. However, the configurations for pre-processing are available for user reference. -# - -############################################################################## -# METplus Configuration -# --------------------- -# -# METplus first loads all of the configuration files found in parm/metplus_config, -# then it loads any configuration files passed to METplus via the command line -# i.e. parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf. -# The file UserScript_fcstGFS_obsERA_RMM/RMM_driver.py runs the python program and -# UserScript_fcstGFS_obsERA_RMM.conf sets the variables for all steps of the RMM use case. -# -# .. highlight:: bash -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf - -############################################################################## -# MET Configuration -# --------------------- -# -# METplus sets environment variables based on the values in the METplus configuration file. -# These variables are referenced in the MET configuration file. **YOU SHOULD NOT SET ANY OF THESE ENVIRONMENT VARIABLES YOURSELF! THEY WILL BE OVERWRITTEN BY METPLUS WHEN IT CALLS THE MET TOOLS!** If there is a setting in the MET configuration file that is not controlled by an environment variable, you can add additional environment variables to be set only within the METplus environment using the [user_env_vars] section of the METplus configuration files. See the 'User Defined Config' section on the 'System Configuration' page of the METplus User's Guide for more information. -# -# - -############################################################################## -# Python Scripts -# ---------------- -# -# The RMM driver script orchestrates the calculation of the MJO indices and -# the generation of three RMM plots: -# parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/RMM_driver.py: -# -# .. highlight:: python -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/RMM_driver.py -# - -############################################################################## -# Running METplus -# --------------- -# -# This use case is run in the following ways: -# -# 1) Passing in UserScript_fcstGFS_obsERA_RMM.conf then a user-specific system configuration file:: -# -# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf -c /path/to/user_system.conf -# -# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_fcstGFS_obsERA_RMM.py:: -# -# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf -# -# The following variables must be set correctly: -# -# * **INPUT_BASE** - Path to directory where sample data tarballs are unpacked (See Datasets section to obtain tarballs). This is not required to run METplus, but it is required to run the examples in parm/use_cases -# * **OUTPUT_BASE** - Path where METplus output will be written. This must be in a location where you have write permissions -# * **MET_INSTALL_DIR** - Path to location where MET is installed locally -# -# Example User Configuration File:: -# -# [dir] -# INPUT_BASE = /path/to/sample/input/data -# OUTPUT_BASE = /path/to/output/dir -# MET_INSTALL_DIR = /path/to/met-X.Y -# - -############################################################################## -# Expected Output -# --------------- -# -# Refer to the value set for **OUTPUT_BASE** to find where the output data was generated. Output for this use case will be found in model_applications/s2s/UserScript_fcstGFS_obsERA_RMM. This may include the regridded data and daily averaged files. In addition, three plots will be generated, a phase diagram, time series, and EOF plot, and the output location can be specified as RMM_PLOT_OUTPUT_DIR. If it is not specified, plots will be sent to model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/plots (relative to **OUTPUT_BASE**). -# - -############################################################################## -# Keywords -# -------- -# -# sphinx_gallery_thumbnail_path = '_static/s2s-RMM_time_series.png' -# -# .. note:: `XXXX`, `S2SAppUseCase `_, -# `NetCDFFileUseCase ` -# `RegridDataPlaneUseCase `_, -# `PCPCombineUseCase `__ diff --git a/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.py b/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.py new file mode 100644 index 0000000000..90450b8134 --- /dev/null +++ b/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.py @@ -0,0 +1,141 @@ +""" +UserScript: Make OMI plot from calculated MJO indices +=========================================================================== + +model_applications/ +s2s/ +UserScript_obsERA_obsOnly_OMI.py + +""" + +############################################################################## +# Scientific Objective +# -------------------- +# +# To use Outgoing Longwave Radiation (OLR) to compute the OLR based MJO Index (OMI). Specifically, OMI is computed using OLR data between 20N and 20S. The OLR data are then projected onto Empirical Orthogonal Function (EOF) data that is computed for each day of the year, latitude, and longitude. The OLR is then filtered for 20 - 96 days, and regressed onto the daily EOFs. Finally, it's normalized and these normalized components are plotted on a phase diagram. +# + +############################################################################## +# Datasets +# -------- +# +# * Forecast dataset: None +# * Observation dataset: ERA Reanlaysis Outgoing Longwave Radiation. + +############################################################################## +# External Dependencies +# --------------------- +# +# You will need to use a version of Python 3.6+ that has the following packages installed:: +# +# * numpy +# * netCDF4 +# * datetime +# * xarray +# * matplotlib +# * scipy +# * pandas +# +# If the version of Python used to compile MET did not have these libraries at the time of compilation, you will need to add these packages or create a new Python environment with these packages. +# +# If this is the case, you will need to set the MET_PYTHON_EXE environment variable to the path of the version of Python you want to use. If you want this version of Python to only apply to this use case, set it in the [user_env_vars] section of a METplus configuration file.: +# +# [user_env_vars] +# MET_PYTHON_EXE = /path/to/python/with/required/packages/bin/python +# + +############################################################################## +# METplus Components +# ------------------ +# +# This use case runs the OMI driver which computes OMI and creates a phase diagram. Inputs to the OMI driver include netCDF files that are in MET's netCDF version. In addition, a txt file containing the listing of these input netCDF files is required, as well as text file listings of the EOF1 and EOF2 files. These text files can be generated using the USER_SCRIPT_INPUT_TEMPLATES in the [create_eof_filelist] and [script_omi] sections. Some optional pre-processing steps include using regrid_data_plane to either regrid your data or cut the domain to 20N - 20S. +# + +############################################################################## +# METplus Workflow +# ---------------- +# +# The OMI driver script python code is run for each lead time on the forecast and observations data. This example loops by valid time for the model pre-processing, and valid time for the other steps. This version is set to only process the OMI calculation and creating a text file listing of the EOF files, omitting the creation of daily means for the model and the regridding pre-processing steps. However, the configurations for pre-processing are available for user reference. + +############################################################################## +# METplus Configuration +# --------------------- +# +# METplus first loads all of the configuration files found in parm/metplus_config, +# then it loads any configuration files passed to METplus via the command line +# i.e. parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf. +# The file UserScript_obsERA_obsOnly_OMI/OMI_driver.py runs the python program and +# UserScript_fcstGFS_obsERA_OMI.conf sets the variables for all steps of the OMI use case. +# +# .. highlight:: bash +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf + +############################################################################## +# MET Configuration +# --------------------- +# +# METplus sets environment variables based on the values in the METplus configuration file. +# These variables are referenced in the MET configuration file. **YOU SHOULD NOT SET ANY OF THESE ENVIRONMENT VARIABLES YOURSELF! THEY WILL BE OVERWRITTEN BY METPLUS WHEN IT CALLS THE MET TOOLS!** If there is a setting in the MET configuration file that is not controlled by an environment variable, you can add additional environment variables to be set only within the METplus environment using the [user_env_vars] section of the METplus configuration files. See the 'User Defined Config' section on the 'System Configuration' page of the METplus User's Guide for more information. +# +# + +############################################################################## +# Python Scripts +# ---------------- +# +# The OMI driver script orchestrates the calculation of the MJO indices and +# the generation of a phase diagram OMI plot: +# parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py: +# +# .. highlight:: python +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py +# + +############################################################################## +# Running METplus +# --------------- +# +# This use case is run in the following ways: +# +# 1) Passing in UserScript_obsERA_obsOnly_OMI.conf then a user-specific system configuration file:: +# +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf -c /path/to/user_system.conf +# +# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_obsERA_obsOnly_OMI.py:: +# +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf +# +# The following variables must be set correctly: +# +# * **INPUT_BASE** - Path to directory where sample data tarballs are unpacked (See Datasets section to obtain tarballs). This is not required to run METplus, but it is required to run the examples in parm/use_cases +# * **OUTPUT_BASE** - Path where METplus output will be written. This must be in a location where you have write permissions +# * **MET_INSTALL_DIR** - Path to location where MET is installed locally +# +# Example User Configuration File:: +# +# [dir] +# INPUT_BASE = /path/to/sample/input/data +# OUTPUT_BASE = /path/to/output/dir +# MET_INSTALL_DIR = /path/to/met-X.Y +# + +############################################################################## +# Expected Output +# --------------- +# +# Refer to the value set for **OUTPUT_BASE** to find where the output data was generated. Output for this use case will be found in model_applications/s2s/UserScript_obsERA_obsOnly_OMI. This may include the regridded data and daily averaged files. In addition, the phase diagram plots will be generated and the output location can be specified as OMI_PLOT_OUTPUT_DIR. If it is not specified, plots will be sent to model_applications/s2s/UserScript_obsERA_obsOnly_OMI/plots (relative to **OUTPUT_BASE**). + +############################################################################## +# Keywords +# -------- +# +# .. note:: +# +# * S2SAppUseCase +# * RegridDataPlaneUseCase +# * PCPCombineUseCase +# +# Navigate to :ref:`quick-search` to discover other similar use cases. +# +# sphinx_gallery_thumbnail_path = '_static/s2s-OMI_phase_diagram.png' +# \ No newline at end of file diff --git a/docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.py b/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.py similarity index 82% rename from docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.py rename to docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.py index 9a9e2996e3..3266d628dd 100644 --- a/docs/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.py +++ b/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.py @@ -4,7 +4,7 @@ model_applications/ s2s/ -UserScript_fcstGFS_obsERA_PhaseDiagram.py +UserScript_obsERA_obsOnly_PhaseDiagram.py """ @@ -63,13 +63,13 @@ # # METplus first loads all of the configuration files found in parm/metplus_config, # then it loads any configuration files passed to METplus via the command line -# i.e. parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf. -# The file UserScript_fcstGFS_obsERA_PhaseDiagram/PhaseDiagram_driver.py runs the python -# program and UserScript_fcstGFS_obsERA_PhaseDiagram.conf sets the variables for all steps +# i.e. parm/use_cases/model_applications/s2s/UserScript_obsERA_obsERA_OMI.conf. +# The file UserScript_obsERA_obsOnly_PhaseDiagram/PhaseDiagram_driver.py runs the python +# program and UserScript_obsERA_obsOnly_PhaseDiagram.conf sets the variables for all steps # of the use case. # # .. highlight:: bash -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf ############################################################################## # MET Configuration @@ -84,11 +84,11 @@ # ---------------- # # The phase diagram driver script orchestrates the generation of a phase diagram plot: -# parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/PhaseDiagram_driver.py: +# parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/PhaseDiagram_driver.py: # # .. highlight:: python -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/PhaseDiagram_driver.py -# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/save_input_files_txt.py +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/PhaseDiagram_driver.py +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/save_input_files_txt.py # ############################################################################## @@ -97,13 +97,13 @@ # # This use case is run in the following ways: # -# 1) Passing in UserScript_fcstGFS_obsERA_OMI.conf then a user-specific system configuration file:: +# 1) Passing in UserScript_obsERA_obsOnly_PhaseDiagram.conf then a user-specific system configuration file:: # -# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf -c /path/to/user_system.conf +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf -c /path/to/user_system.conf # -# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_fcstGFS_obsERA_PhaseDiagram.py:: +# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_obsERA_obsOnly_PhaseDiagram.py:: # -# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf # # The following variables must be set correctly: # @@ -123,12 +123,18 @@ # Expected Output # --------------- # -# Refer to the value set for **OUTPUT_BASE** to find where the output data was generated. Output for this use case will be found in model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram. This may include the regridded data and daily averaged files. In addition, the phase diagram plots will be generated and the output location can be specified as OMI_PLOT_OUTPUT_DIR. If it is not specified, plots will be sent to model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/plots (relative to **OUTPUT_BASE**). +# Refer to the value set for **OUTPUT_BASE** to find where the output data was generated. Output for this use case will be found in model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram. This may include the regridded data and daily averaged files. In addition, the phase diagram plots will be generated and the output location can be specified as PHASE_DIAGRAM_PLOT_OUTPUT_DIR. If it is not specified, plots will be sent to model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/plots (relative to **OUTPUT_BASE**). ############################################################################## # Keywords # -------- # -# sphinx_gallery_thumbnail_path = '_static/s2s-PhaseDiagram.png' # -# .. note:: `XXXX`, `S2SAppUseCase `_ +# .. note:: +# +# * S2SAppUseCase +# +# Navigate to :ref:`quick-search` to discover other similar use cases. +# +# sphinx_gallery_thumbnail_path = '_static/s2s-PhaseDiagram.png' +# \ No newline at end of file diff --git a/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.py b/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.py new file mode 100644 index 0000000000..6c4f3e5c6c --- /dev/null +++ b/docs/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.py @@ -0,0 +1,147 @@ +""" +UserScript: Make RMM plots from calculated MJO indices +=========================================================================== + +model_applications/ +s2s/ +UserScript_obsERA_obsOnly_RMM.py + +""" + +############################################################################## +# Scientific Objective +# -------------------- +# +# To compute the Real-time Multivariate MJO Index (RMM) using Outgoing Longwave Radiation (OLR), 850 hPa wind (U850), and 200 hPa wind (U200). Specifically, RMM is computed using OLR, U850, and U200 data between 15N and 15S. Anomalies of OLR, U850, and U200 are created using a harmonic analysis, 120 day day mean removed, and the data are normalized by normalization factors (generally the square root of the average variance) The anomalies are projected onto Empirical Orthogonal Function (EOF) data. The OLR is then filtered for 20 - 96 days, and regressed onto the daily EOFs. Finally, it's normalized and these normalized components are plotted on a phase diagram and timeseries plot. +# + +############################################################################## +# Datasets +# -------- +# +# * Forecast dataset: None +# * Observation dataset: ERA Reanlaysis Outgoing Longwave Radiation, 850 hPa wind and 200 hPa wind + +############################################################################## +# External Dependencies +# --------------------- +# +# You will need to use a version of Python 3.6+ that has the following packages installed:: +# +# * numpy +# * netCDF4 +# * datetime +# * xarray +# * matplotlib +# * scipy +# * pandas +# +# If the version of Python used to compile MET did not have these libraries at the time of compilation, you will need to add these packages or create a new Python environment with these packages. +# +# If this is the case, you will need to set the MET_PYTHON_EXE environment variable to the path of the version of Python you want to use. If you want this version of Python to only apply to this use case, set it in the [user_env_vars] section of a METplus configuration file.: +# +# [user_env_vars] +# MET_PYTHON_EXE = /path/to/python/with/required/packages/bin/python +# + +############################################################################## +# METplus Components +# ------------------ +# +# This use case runs the RMM driver which computes first computes anomalies of outgoing longwave raidation, 850 hPa wind and 200 hPa wind. Then, it regrids the data to 15S to 15N. Next, RMM is computed and a phase diagram, time series, and EOF plot are created. Inputs to the RMM driver include netCDF files that are in MET's netCDF version. In addition, a text file containing the listing of these input netCDF files for OLR, u850 and u200 is required. Some optional pre-processing steps include using pcp_combine to compute daily means and the mean daily annual cycle for the data. +# + +############################################################################## +# METplus Workflow +# ---------------- +# The RMM driver script python code is run for each lead time on the forecast and observations data. This example loops by valid time for the model pre-processing, and valid time for the other steps. This version is set to only process the creation of anomalies, regridding, and RMM calculation, omitting the caluclation of daily means and the mean daily annucal cycle pre-processing steps. However, the configurations for pre-processing are available for user reference. +# + +############################################################################## +# METplus Configuration +# --------------------- +# +# METplus first loads all of the configuration files found in parm/metplus_config, +# then it loads any configuration files passed to METplus via the command line +# i.e. parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf. +# The file UserScript_obsERA_obsOnly_RMM/RMM_driver.py runs the python program and +# UserScript_obsERA_obsOnly_RMM.conf sets the variables for all steps of the RMM use case. +# +# .. highlight:: bash +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf + +############################################################################## +# MET Configuration +# --------------------- +# +# METplus sets environment variables based on the values in the METplus configuration file. +# These variables are referenced in the MET configuration file. **YOU SHOULD NOT SET ANY OF THESE ENVIRONMENT VARIABLES YOURSELF! THEY WILL BE OVERWRITTEN BY METPLUS WHEN IT CALLS THE MET TOOLS!** If there is a setting in the MET configuration file that is not controlled by an environment variable, you can add additional environment variables to be set only within the METplus environment using the [user_env_vars] section of the METplus configuration files. See the 'User Defined Config' section on the 'System Configuration' page of the METplus User's Guide for more information. +# +# + +############################################################################## +# Python Scripts +# ---------------- +# +# The RMM driver script orchestrates the calculation of the MJO indices and +# the generation of three RMM plots: +# parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/RMM_driver.py: +# The harmonic anomalies script creates anomalies of input data using a harmonic analysis: +# parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py +# +# .. highlight:: python +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/RMM_driver.py +# .. literalinclude:: ../../../../parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py +# + +############################################################################## +# Running METplus +# --------------- +# +# This use case is run in the following ways: +# +# 1) Passing in UserScript_obsERA_obsOnly_RMM.conf then a user-specific system configuration file:: +# +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf -c /path/to/user_system.conf +# +# 2) Modifying the configurations in parm/metplus_config, then passing in UserScript_obsERA_obsOnly_RMM.py:: +# +# run_metplus.py -c /path/to/METplus/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf +# +# The following variables must be set correctly: +# +# * **INPUT_BASE** - Path to directory where sample data tarballs are unpacked (See Datasets section to obtain tarballs). This is not required to run METplus, but it is required to run the examples in parm/use_cases +# * **OUTPUT_BASE** - Path where METplus output will be written. This must be in a location where you have write permissions +# * **MET_INSTALL_DIR** - Path to location where MET is installed locally +# +# Example User Configuration File:: +# +# [dir] +# INPUT_BASE = /path/to/sample/input/data +# OUTPUT_BASE = /path/to/output/dir +# MET_INSTALL_DIR = /path/to/met-X.Y +# + +############################################################################## +# Expected Output +# --------------- +# +# Refer to the value set for **OUTPUT_BASE** to find where the output data was generated. Output for this use case will be found in model_applications/s2s/UserScript_obsERA_obsOnly_RMM. This may include the regridded data and daily averaged files. In addition, three plots will be generated, a phase diagram, time series, and EOF plot, and the output location can be specified as RMM_PLOT_OUTPUT_DIR. If it is not specified, plots will be sent to model_applications/s2s/UserScript_obsERA_obsOnly_RMM/plots (relative to **OUTPUT_BASE**). +# + +############################################################################## +# Keywords +# -------- +# +# +# .. note:: +# +# * S2SAppUseCase +# * NetCDFFileUseCase +# * RegridDataPlaneUseCase +# * PCPCombineUseCase +# +# Navigate to :ref:`quick-search` to discover other similar use cases. +# +# sphinx_gallery_thumbnail_path = '_static/s2s-RMM_time_series.png' +# \ No newline at end of file diff --git a/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py b/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py index 750fe994af..be6ee1acb4 100644 --- a/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py +++ b/internal_tests/pytests/ensemble_stat/test_ensemble_stat_wrapper.py @@ -568,10 +568,10 @@ def test_ensemble_stat_single_field(metplus_config, config_overrides, config_file = wrapper.c_dict.get('CONFIG_FILE') out_dir = wrapper.c_dict.get('OUTPUT_DIR') expected_cmds = [(f"{app_path} {verbosity} " - f"{file_list_dir}/20050807000000_12_ensemble.txt " + f"{file_list_dir}/20050807000000_12_ensemble_stat.txt " f"{config_file} -outdir {out_dir}/2005080712"), (f"{app_path} {verbosity} " - f"{file_list_dir}/20050807120000_12_ensemble.txt " + f"{file_list_dir}/20050807120000_12_ensemble_stat.txt " f"{config_file} -outdir {out_dir}/2005080800"), ] diff --git a/internal_tests/use_cases/all_use_cases.txt b/internal_tests/use_cases/all_use_cases.txt index 2d196b9b67..b6cd0a3af5 100644 --- a/internal_tests/use_cases/all_use_cases.txt +++ b/internal_tests/use_cases/all_use_cases.txt @@ -123,10 +123,11 @@ Category: s2s 4::TCGen_fcstGFSO_obsBDECKS_GDF_TDF:: model_applications/s2s/TCGen_fcstGFSO_obsBDECKS_GDF_TDF.conf:: metplotpy_env,cartopy,metplus 5::UserScript_obsPrecip_obsOnly_Hovmoeller:: model_applications/s2s/UserScript_obsPrecip_obsOnly_Hovmoeller.conf:: metplotpy_env,cartopy 6:: UserScript_obsPrecip_obsOnly_CrossSpectraPlot:: model_applications/s2s/UserScript_obsPrecip_obsOnly_CrossSpectraPlot.conf:: spacetime_env -7:: UserScript_fcstGFS_obsERA_PhaseDiagram:: model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf:: spacetime_env +7:: UserScript_obsERA_obsOnly_PhaseDiagram:: model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf:: spacetime_env 8:: UserScript_fcstGFS_obsERA_OMI:: model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf:: spacetime_env, metdatadb -9:: UserScript_fcstGFS_obsERA_RMM:: model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf:: spacetime_env, metdatadb -10::UserScript_fcstGFS_obsERA_WeatherRegime:: model_applications/s2s/UserScript_fcstGFS_obsERA_WeatherRegime.conf:: weatherregime_env,cartopy,metplus +9:: UserScript_obsERA_obsOnly_OMI:: model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf:: spacetime_env, metdatadb +10:: UserScript_obsERA_obsOnly_RMM:: model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf:: spacetime_env, metdatadb +11:: UserScript_fcstGFS_obsERA_WeatherRegime:: model_applications/s2s/UserScript_fcstGFS_obsERA_WeatherRegime.conf:: weatherregime_env,cartopy,metplus Category: space_weather 0::GridStat_fcstGloTEC_obsGloTEC_vx7:: model_applications/space_weather/GridStat_fcstGloTEC_obsGloTEC_vx7.conf diff --git a/metplus/util/met_util.py b/metplus/util/met_util.py index 414b9795a4..105740e420 100644 --- a/metplus/util/met_util.py +++ b/metplus/util/met_util.py @@ -2282,7 +2282,11 @@ def format_var_items(field_configs, time_info=None): return var_items def find_var_name_indices(config, data_types, met_tool=None): - data_type_regex = f"{'|'.join(data_types)}|BOTH" + data_type_regex = f"{'|'.join(data_types)}" + + # if data_types includes FCST or OBS, also search for BOTH + if any([item for item in ['FCST', 'OBS'] if item in data_types]): + data_type_regex += '|BOTH' regex_string = f"({data_type_regex})" diff --git a/metplus/wrappers/command_builder.py b/metplus/wrappers/command_builder.py index 4384f45307..22b1052721 100755 --- a/metplus/wrappers/command_builder.py +++ b/metplus/wrappers/command_builder.py @@ -22,6 +22,7 @@ from ..util import do_string_sub, ti_calculate, get_seconds_from_string from ..util import config_metplus from ..util import METConfigInfo as met_config +from ..util import MISSING_DATA_VALUE # pylint:disable=pointless-string-statement '''!@namespace CommandBuilder @@ -659,6 +660,8 @@ def find_exact_file(self, level, data_type, time_info, mandatory=True, # then add it back after the string sub call saved_level = time_info.pop('level', None) + input_must_exist = self.c_dict.get('INPUT_MUST_EXIST', True) + for template in template_list: # perform string substitution filename = do_string_sub(template, @@ -671,9 +674,9 @@ def find_exact_file(self, level, data_type, time_info, mandatory=True, if os.path.sep not in full_path: self.logger.debug(f"{full_path} is not a file path. " "Returning that string.") - if return_list: - full_path = [full_path] - return full_path + check_file_list.append(full_path) + input_must_exist = False + continue self.logger.debug(f"Looking for {data_type}INPUT file {full_path}") @@ -719,7 +722,7 @@ def find_exact_file(self, level, data_type, time_info, mandatory=True, for file_path in check_file_list: # if file doesn't need to exist, skip check - if not self.c_dict.get('INPUT_MUST_EXIST', True): + if not input_must_exist: found_file_list.append(file_path) continue @@ -736,6 +739,9 @@ def find_exact_file(self, level, data_type, time_info, mandatory=True, f"using template {template}") if not mandatory or not self.c_dict.get('MANDATORY', True): self.logger.warning(msg) + if self.c_dict.get(f'{data_type}FILL_MISSING'): + found_file_list.append(f'MISSING{file_path}') + continue else: self.log_error(msg) @@ -843,6 +849,96 @@ def find_file_in_window(self, level, data_type, time_info, mandatory=True, return out + def find_input_files_ensemble(self, time_info): + """! Get a list of all input files and optional control file. + Warn and remove control file if found in ensemble list. Ensure that + if defined, the number of ensemble members (N_MEMBERS) corresponds to + the file list that was found. + + @param time_info dictionary containing timing information + @returns True on success + """ + # get list of ensemble files to process + input_files = self.find_model(time_info, return_list=True) + if not input_files: + self.log_error("Could not find any input files") + return False + + # get control file if requested + if self.c_dict.get('CTRL_INPUT_TEMPLATE'): + ctrl_file = self.find_data(time_info, data_type='CTRL') + + # return if requested control file was not found + if not ctrl_file: + return False + + self.args.append(f'-ctrl {ctrl_file}') + + # check if control file is found in ensemble list + if ctrl_file in input_files: + # warn and remove control file if found + self.logger.warning(f"Control file found in ensemble list: " + f"{ctrl_file}. Removing from list.") + input_files.remove(ctrl_file) + + # compare number of files found to expected number of members + if not self._check_expected_ensembles(input_files): + return False + + # write file that contains list of ensemble files + list_filename = (f"{time_info['init_fmt']}_" + f"{time_info['lead_hours']}_{self.app_name}.txt") + list_file = self.write_list_file(list_filename, input_files) + if not list_file: + self.log_error("Could not write filelist file") + return False + + self.infiles.append(list_file) + + return True + + def _check_expected_ensembles(self, input_files): + """! Helper function for find_input_files_ensemble(). + If number of expected ensemble members was defined in the config, + then ensure that the number of files found correspond to the expected + number. If more files were found, error and return False. If fewer + files were found, fill in input_files list with MISSING to allow valid + threshold check inside MET tool to work properly. + """ + num_expected = self.c_dict['N_MEMBERS'] + + # if expected members count is unset, skip check + if num_expected == MISSING_DATA_VALUE: + return True + + num_found = len(input_files) + + # error and return if more than expected number was found + if num_found > num_expected: + self.log_error( + "Found more files than expected! " + f"Found {num_found} expected {num_expected}. " + "Adjust wildcard expression in template or adjust " + "number of expected members (N_MEMBERS). " + f"Files found: {input_files}" + ) + return False + + # if fewer files found than expected, warn and add fake files + if num_found < num_expected: + self.logger.warning( + f"Found fewer files than expected. " + f"Found {num_found} expected {num_expected}" + ) + # add fake files to list for ens_thresh checking + diff = num_expected - num_found + self.logger.warning(f'Adding {diff} fake files to ' + 'ensure ens_thresh check is accurate') + for _ in range(0, diff, 1): + input_files.append('MISSING') + + return True + def write_list_file(self, filename, file_list, output_dir=None): """! Writes a file containing a list of filenames to the staging dir diff --git a/metplus/wrappers/ensemble_stat_wrapper.py b/metplus/wrappers/ensemble_stat_wrapper.py index 652170ffbe..2c532ec05f 100755 --- a/metplus/wrappers/ensemble_stat_wrapper.py +++ b/metplus/wrappers/ensemble_stat_wrapper.py @@ -153,11 +153,18 @@ def create_c_dict(self): elif c_dict['OBS_GRID_INPUT_DATATYPE'] in util.PYTHON_EMBEDDING_TYPES: c_dict['OBS_INPUT_DATATYPE'] = c_dict['OBS_GRID_INPUT_DATATYPE'] - c_dict['N_MEMBERS'] = \ - self.config.getint('config', 'ENSEMBLE_STAT_N_MEMBERS', -1) + c_dict['N_MEMBERS'] = ( + self.config.getint('config', 'ENSEMBLE_STAT_N_MEMBERS') + ) + + # allow multiple files in CommandBuilder.find_data logic + c_dict['ALLOW_MULTIPLE_FILES'] = True + + # not all input files are mandatory to be found + c_dict['MANDATORY'] = False - if c_dict['N_MEMBERS'] < 0: - self.log_error("Must set ENSEMBLE_STAT_N_MEMBERS to a integer > 0") + # fill inputs that are not found with fake path to note it is missing + c_dict['FCST_FILL_MISSING'] = True c_dict['OBS_POINT_INPUT_DIR'] = \ self.config.getdir('OBS_ENSEMBLE_STAT_POINT_INPUT_DIR', '') @@ -177,11 +184,9 @@ def create_c_dict(self): c_dict['FCST_INPUT_DIR'] = \ self.config.getdir('FCST_ENSEMBLE_STAT_INPUT_DIR', '') - # This is a raw string and will be interpreted to generate the - # ensemble member filenames. This may be a list of 1 or n members. - c_dict['FCST_INPUT_TEMPLATE'] = \ - util.getlist(self.config.getraw('filename_templates', - 'FCST_ENSEMBLE_STAT_INPUT_TEMPLATE')) + c_dict['FCST_INPUT_TEMPLATE'] = ( + self.config.getraw('config', 'FCST_ENSEMBLE_STAT_INPUT_TEMPLATE') + ) if not c_dict['FCST_INPUT_TEMPLATE']: self.log_error("Must set FCST_ENSEMBLE_STAT_INPUT_TEMPLATE") @@ -364,12 +369,9 @@ def run_at_time_all_fields(self, time_info): @param time_info dictionary containing timing information """ # get ensemble model files - fcst_file_list = self.find_model_members(time_info) - if not fcst_file_list: + if not self.find_input_files_ensemble(time_info): return - self.infiles.append(fcst_file_list) - # parse var list for ENS fields ensemble_var_list = util.sub_var_list(self.c_dict['ENS_VAR_LIST_TEMP'], time_info) diff --git a/metplus/wrappers/gen_ens_prod_wrapper.py b/metplus/wrappers/gen_ens_prod_wrapper.py index 00c7c58e73..3beaebc66e 100755 --- a/metplus/wrappers/gen_ens_prod_wrapper.py +++ b/metplus/wrappers/gen_ens_prod_wrapper.py @@ -7,6 +7,7 @@ from ..util import do_string_sub, ti_calculate, get_lead_sequence from ..util import skip_time, parse_var_list, sub_var_list + from . import LoopTimesWrapper class GenEnsProdWrapper(LoopTimesWrapper): @@ -21,8 +22,8 @@ class GenEnsProdWrapper(LoopTimesWrapper): 'METPLUS_CAT_THRESH', 'METPLUS_NC_VAR_STR', 'METPLUS_ENS_FILE_TYPE', - 'METPLUS_ENS_ENS_THRESH', - 'METPLUS_ENS_VLD_THRESH', + 'METPLUS_ENS_THRESH', + 'METPLUS_VLD_THRESH', 'METPLUS_ENS_FIELD', 'METPLUS_NBRHD_PROB_DICT', 'METPLUS_NMEP_SMOOTH_DICT', @@ -65,15 +66,27 @@ def create_c_dict(self): ) # get input template/dir - template is required - c_dict['INPUT_TEMPLATE'] = self.config.getraw( + c_dict['FCST_INPUT_TEMPLATE'] = self.config.getraw( 'config', 'GEN_ENS_PROD_INPUT_TEMPLATE' ) - c_dict['INPUT_DIR'] = self.config.getdir('GEN_ENS_PROD_INPUT_DIR', '') + c_dict['FCST_INPUT_DIR'] = self.config.getdir('GEN_ENS_PROD_INPUT_DIR', + '') - if not c_dict['INPUT_TEMPLATE']: + if not c_dict['FCST_INPUT_TEMPLATE']: self.log_error('GEN_ENS_PROD_INPUT_TEMPLATE must be set') + # not all input files are mandatory to be found + c_dict['MANDATORY'] = False + + # fill inputs that are not found with fake path to note it is missing + c_dict['FCST_FILL_MISSING'] = True + + # number of expected ensemble members + c_dict['N_MEMBERS'] = ( + self.config.getint('config', 'GEN_ENS_PROD_N_MEMBERS') + ) + # get ctrl (control) template/dir - optional c_dict['CTRL_INPUT_TEMPLATE'] = self.config.getraw( 'config', @@ -195,68 +208,30 @@ def run_at_time_once(self, time_info): @param time_info dictionary containing timing information """ + # add config file to arguments + config_file = do_string_sub(self.c_dict['CONFIG_FILE'], **time_info) + self.args.append(f"-config {config_file}") + if not self.find_field_info(time_info): return False - if not self.find_input_files(time_info): + if not self.find_input_files_ensemble(time_info): return False if not self.find_and_check_output_file(time_info): return False - # add config file to arguments - config_file = do_string_sub(self.c_dict['CONFIG_FILE'], **time_info) - self.args.append(f"-config {config_file}") - - if not self.find_ctrl_file(time_info): - return False - # set environment variables that are passed to the MET config self.set_environment_variables(time_info) return self.build() - def find_input_files(self, time_info): - """! Get a list of all input files - - @param time_info dictionary containing timing information - @returns True on success - """ - input_files = self.find_data(time_info, return_list=True) - if not input_files: - self.log_error("Could not find any input files") - return False - - # write file that contains list of ensemble files - list_filename = (f"{time_info['init_fmt']}_" - f"{time_info['lead_hours']}_gen_ens_prod.txt") - list_file = self.write_list_file(list_filename, input_files) - if not list_file: - self.log_error("Could not write filelist file") - return False - - self.infiles.append(list_file) - - return True - - def find_ctrl_file(self, time_info): - """! Find optional ctrl (control) file if requested + def find_field_info(self, time_info): + """! parse var list for ENS fields @param time_info dictionary containing timing information - @returns True on success or if ctrl not requested + @returns True if successful, False if something went wrong """ - if not self.c_dict['CTRL_INPUT_TEMPLATE']: - return True - - input_file = self.find_data(time_info, data_type='CTRL') - if not input_file: - return False - - self.args.append(f'-ctrl {input_file}') - return True - - def find_field_info(self, time_info): - # parse var list for ENS fields ensemble_var_list = sub_var_list(self.c_dict['ENS_VAR_LIST_TEMP'], time_info) all_fields = [] diff --git a/parm/met_config/GenEnsProdConfig_wrapped b/parm/met_config/GenEnsProdConfig_wrapped index 59c794310a..2da107e1d4 100644 --- a/parm/met_config/GenEnsProdConfig_wrapped +++ b/parm/met_config/GenEnsProdConfig_wrapped @@ -53,10 +53,10 @@ ens = { ${METPLUS_ENS_FILE_TYPE} //ens_thresh = - ${METPLUS_ENS_ENS_THRESH} + ${METPLUS_ENS_THRESH} //vld_thresh = - ${METPLUS_ENS_VLD_THRESH} + ${METPLUS_VLD_THRESH} //field = ${METPLUS_ENS_FIELD} diff --git a/parm/use_cases/met_tool_wrapper/GenEnsProd/GenEnsProd.conf b/parm/use_cases/met_tool_wrapper/GenEnsProd/GenEnsProd.conf index 757db28a04..b545614bde 100644 --- a/parm/use_cases/met_tool_wrapper/GenEnsProd/GenEnsProd.conf +++ b/parm/use_cases/met_tool_wrapper/GenEnsProd/GenEnsProd.conf @@ -22,12 +22,22 @@ LOOP_ORDER = processes GEN_ENS_PROD_INPUT_DIR = {INPUT_BASE}/met_test/data/sample_fcst +# ensemble gep4 does not exist in sample input data GEN_ENS_PROD_INPUT_TEMPLATE = - {init?fmt=%Y%m%d%H}/*gep*/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib + {init?fmt=%Y%m%d%H}/arw-fer-gep1/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib, + {init?fmt=%Y%m%d%H}/arw-sch-gep2/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib, + {init?fmt=%Y%m%d%H}/arw-tom-gep3/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib, + {init?fmt=%Y%m%d%H}/arw-tom-gep4/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib, + {init?fmt=%Y%m%d%H}/arw-fer-gep5/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib, + {init?fmt=%Y%m%d%H}/arw-sch-gep6/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib, + {init?fmt=%Y%m%d%H}/arw-tom-gep7/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib GEN_ENS_PROD_CTRL_INPUT_DIR = {INPUT_BASE}/met_test/data/sample_fcst GEN_ENS_PROD_CTRL_INPUT_TEMPLATE = - {init?fmt=%Y%m%d%H}/arw-tom-gep3/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib + {init?fmt=%Y%m%d%H}/arw-fer-gep1/d01_{init?fmt=%Y%m%d%H}_{lead?fmt=%3H}00.grib + +# there are 7 ensembles but 1 is used as control, so specify 6 members +GEN_ENS_PROD_N_MEMBERS = 6 GEN_ENS_PROD_OUTPUT_DIR = {OUTPUT_BASE}/gen_ens_prod GEN_ENS_PROD_OUTPUT_TEMPLATE = gen_ens_prod_{valid?fmt=%Y%m%d_%H%M%S}V_ens.nc @@ -78,7 +88,7 @@ ENS_VAR5_THRESH = >=5.0 # GEN_ENS_PROD_CAT_THRESH = # GEN_ENS_PROD_NC_VAR_STR = -# GEN_ENS_PROD_ENS_THRESH = 1.0 +GEN_ENS_PROD_ENS_THRESH = 0.8 # GEN_ENS_PROD_VLD_THRESH = 1.0 # GEN_ENS_PROD_NBRHD_PROB_WIDTH = 5 diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf index 628ff33271..8ca46eba79 100644 --- a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf +++ b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI.conf @@ -1,7 +1,7 @@ # OMI UserScript wrapper [config] # All steps, including pre-processing: -#PROCESS_LIST = RegridDataPlane(regrid_obs_olr), UserScript(create_eof_filelist), UserScript(script_omi) +#PROCESS_LIST = PcpCombine(daily_mean_fcst), RegridDataPlane(regrid_obs_olr), RegridDataPlane(regrid_fcst_olr), UserScript(create_eof_filelist), UserScript(script_omi) # Finding EOF files and OMI Analysis script for the observations PROCESS_LIST = UserScript(create_eof_filelist), UserScript(script_omi) @@ -19,10 +19,10 @@ LOOP_BY = VALID VALID_TIME_FMT = %Y%m%d%H # Start time for METplus run -VALID_BEG = 1979010100 +VALID_BEG = 2017010100 # End time for METplus run -VALID_END = 2012123000 +VALID_END = 2018123100 # Increment between METplus runs in seconds. Must be >= 60 VALID_INCREMENT = 86400 @@ -47,7 +47,7 @@ CONFIG_DIR={PARM_BASE}/use_cases/model_applications/s2s # Run the obs for these cases OBS_RUN = True -FCST_RUN = False +FCST_RUN = True # Mask to use for regridding REGRID_DATA_PLANE_VERIF_GRID = latlon 144 17 -20 0 2.5 2.5 @@ -59,12 +59,36 @@ REGRID_DATA_PLANE_METHOD = NEAREST REGRID_DATA_PLANE_WIDTH = 1 # Input and Output Directories for the OBS OLR Files and output text file containing the file list -OBS_OLR_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/ERA +OBS_OLR_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/ERA/Regrid OBS_OLR_INPUT_TEMPLATE = OLR_{valid?fmt=%Y%m%d}.nc +# Input and Output Directories for the OBS OLR Files and output text file containing the file list +FCST_OLR_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/GFS/Regrid +FCST_OLR_INPUT_TEMPLATE = OLR_{valid?fmt=%Y%m%d}.nc + + +# Configurations for pcp_combine: Create daily means for the GFS +[daily_mean_fcst] +# run pcp_combine on obs data +FCST_PCP_COMBINE_RUN = {FCST_RUN} + +# method to run pcp_combine on forecast data +# Options are ADD, SUM, SUBTRACT, DERIVE, and USER_DEFINED +FCST_PCP_COMBINE_METHOD = USER_DEFINED + +FCST_PCP_COMBINE_COMMAND = -derive mean {FCST_PCP_COMBINE_INPUT_DIR}/{valid?fmt=%Y}/{valid?fmt=%Y%m%d}/gfs.0p25.{valid?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=86400}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{valid?fmt=%Y}/{valid?fmt=%Y%m%d}/gfs.0p25.{valid?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=75600}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{valid?fmt=%Y}/{valid?fmt=%Y%m%d}/gfs.0p25.{valid?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=64800}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{init?fmt=%Y}/{init?fmt=%Y%m%d}/gfs.0p25.{init?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=54000}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{init?fmt=%Y}/{init?fmt=%Y%m%d}/gfs.0p25.{init?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=43200}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{init?fmt=%Y}/{init?fmt=%Y%m%d}/gfs.0p25.{init?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=32400}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{init?fmt=%Y}/{init?fmt=%Y%m%d}/gfs.0p25.{init?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=21600}.grib2 {FCST_PCP_COMBINE_INPUT_DIR}/{init?fmt=%Y}/{init?fmt=%Y%m%d}/gfs.0p25.{init?fmt=%Y%m%d%H}.f{lead?fmt=%HHH?shift=10800}.grib2 -field 'name="ULWRF"; level="L0"; set_attr_valid = "{valid?fmt=%Y%m%d_%H%M%S}"; GRIB2_ipdtmpl_index = 9; GRIB2_ipdtmpl_val = 8;' + +FCST_PCP_COMBINE_INPUT_DIR = /gpfs/fs1/collections/rda/data/ds084.1 +FCST_PCP_COMBINE_INPUT_TEMPLATE = {valid?fmt=%Y%m}/gfs.0p25.{init?fmt=%y%m%d%H}.f{lead?fmt=%HHH}.grib2 + +FCST_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_OMI/GFS/daily_mean +FCST_PCP_COMBINE_OUTPUT_TEMPLATE = GFS_mean_{valid?fmt=%Y%m%d}.nc -# Configurations for regrid_data_plane: Regrid OLR to -20 to 20 latitude + +# Configurations for regrid_data_plane: Regrid ERA OLR to -20 to 20 latitude [regrid_obs_olr] +LEAD_SEQ = 0 + # Run regrid_data_plane on forecast data OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} @@ -84,7 +108,7 @@ OBS_REGRID_DATA_PLANE_VAR1_OPTIONS = file_type=NETCDF_NCCF; censor_thresh=eq-999 OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = olr # input and output data directories for each application in PROCESS_LIST -OBS_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI +OBS_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/ERA/daily_mean OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OBS_OLR_INPUT_DIR} # format of filenames @@ -93,6 +117,34 @@ OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = olr.1x.7920.nc OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = {OBS_OLR_INPUT_TEMPLATE} +# Configurations for regrid_data_plane: Regrid GFS OLR to -20 to 20 latitude +[regrid_fcst_olr] +# Run regrid_data_plane on forecast data +FCST_REGRID_DATA_PLANE_RUN = {FCST_RUN} + +# If true, process each field individually and write a file for each +# If false, run once per run time passing in all fields specified +REGRID_DATA_PLANE_ONCE_PER_FIELD = False + +# Name of input field to process +FCST_REGRID_DATA_PLANE_VAR1_NAME = ULWRF_L0_mean + +# Level of input field to process +FCST_REGRID_DATA_PLANE_VAR1_LEVELS = "(*,*)" + +# Name of output field to create +FCST_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = olr + +# input and output data directories for each application in PROCESS_LIST +FCST_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/GFS/daily_mean +FCST_REGRID_DATA_PLANE_OUTPUT_DIR = {FCST_OLR_INPUT_DIR} + +# format of filenames +# Input ERA Interim +FCST_REGRID_DATA_PLANE_INPUT_TEMPLATE = GFS_mean_{valid?fmt=%Y%m%d}.nc +FCST_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = {FCST_OLR_INPUT_TEMPLATE} + + # Create the EOF filelists [create_eof_filelist] # Find the files for each time to create the time list @@ -133,11 +185,13 @@ OBS_PER_DAY = 1 OMI_PLOT_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_OMI/plots # Phase Plot start date, end date, output name, and format -PHASE_PLOT_TIME_BEG = 2012010100 -PHASE_PLOT_TIME_END = 2012033000 +PHASE_PLOT_TIME_BEG = 2017010100 +PHASE_PLOT_TIME_END = 2017033100 PHASE_PLOT_TIME_FMT = {VALID_TIME_FMT} OBS_PHASE_PLOT_OUTPUT_NAME = obs_OMI_comp_phase -OBS_PHASE_PLOT_OUTPUT_FORMAT = png +OBS_PHASE_PLOT_OUTPUT_FORMAT = png +FCST_PHASE_PLOT_OUTPUT_NAME = fcst_OMI_comp_phase +FCST_PHASE_PLOT_OUTPUT_FORMAT = png # Configurations for UserScript: Run the RMM Analysis driver @@ -146,12 +200,12 @@ OBS_PHASE_PLOT_OUTPUT_FORMAT = png USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD ## Template of OLR filenames to input to the user-script -USER_SCRIPT_INPUT_TEMPLATE = {OBS_OLR_INPUT_DIR}/{OBS_OLR_INPUT_TEMPLATE} +USER_SCRIPT_INPUT_TEMPLATE = {OBS_OLR_INPUT_DIR}/{OBS_OLR_INPUT_TEMPLATE},{FCST_OLR_INPUT_DIR}/{FCST_OLR_INPUT_TEMPLATE} ## Name of the file containing the listing of OLR input files ## The options are OBS_OLR_INPUT and FCST_OLR_INPUT ## *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE -USER_SCRIPT_INPUT_TEMPLATE_LABELS = OBS_OLR_INPUT +USER_SCRIPT_INPUT_TEMPLATE_LABELS = OBS_OLR_INPUT,FCST_OLR_INPUT # Command to run the user script with input configuration file USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py index 1c63b88104..9e1ab61d05 100755 --- a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py +++ b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_OMI/OMI_driver.py @@ -84,6 +84,7 @@ def run_omi_steps(inlabel, olr_filetxt, spd, EOF1, EOF2, oplot_dir): # Get the output name and format for the PC plase diagram phase_plot_name = os.path.join(oplot_dir,os.environ.get(inlabel+'_PHASE_PLOT_OUTPUT_NAME',inlabel+'_OMI_comp_phase')) + print(phase_plot_name) phase_plot_format = os.environ.get(inlabel+'_PHASE_PLOT_OUTPUT_FORMAT','png') # plot the PC phase diagram @@ -128,7 +129,7 @@ def main(): # Determine if doing forecast or obs run_obs_omi = os.environ.get('RUN_OBS','False').lower() - run_fcst_omi = os.environ.get('FCST_RUN_FCST', 'False').lower() + run_fcst_omi = os.environ.get('RUN_FCST', 'False').lower() # Run the steps to compute OMM # Observations diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf b/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf deleted file mode 100644 index 2eb51d1608..0000000000 --- a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM.conf +++ /dev/null @@ -1,214 +0,0 @@ -# RMM UserScript wrapper -[config] -# All steps, including pre-processing: -#PROCESS_LIST = RegridDataPlane(regrid_obs_olr), RegridDataPlane(regrid_obs_u850), RegridDataPlane(regrid_obs_u200), UserScript(script_rmm) -# Only RMM Analysis script for the observations -PROCESS_LIST = UserScript(script_rmm) - -# time looping - options are INIT, VALID, RETRO, and REALTIME -# If set to INIT or RETRO: -# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set -# If set to VALID or REALTIME: -# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set -LOOP_BY = VALID - -# Format of VALID_BEG and VALID_END using % items -# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. -# see www.strftime.org for more information -# %Y%m%d%H expands to YYYYMMDDHH -VALID_TIME_FMT = %Y%m%d%H - -# Start time for METplus run -VALID_BEG = 2000010100 - -# End time for METplus run -VALID_END = 2002123000 - -# Increment between METplus runs in seconds. Must be >= 60 -VALID_INCREMENT = 86400 - -# List of forecast leads to process for each run time (init or valid) -# In hours if units are not specified -# If unset, defaults to 0 (don't loop through forecast leads) -LEAD_SEQ = 0 - -# Order of loops to process data - Options are times, processes -# Not relevant if only one item is in the PROCESS_LIST -# times = run all wrappers in the PROCESS_LIST for a single run time, then -# increment the run time and run all wrappers again until all times have -# been evaluated. -# processes = run the first wrapper in the PROCESS_LIST for all times -# specified, then repeat for the next item in the PROCESS_LIST until all -# wrappers have been run -LOOP_ORDER = processes - -# location of configuration files used by MET applications -CONFIG_DIR={PARM_BASE}/use_cases/model_applications/s2s - -# Run the obs for these cases -OBS_RUN = True -FCST_RUN = False - -# Mask to use for regridding -REGRID_DATA_PLANE_VERIF_GRID = latlon 144 13 -15 0 2.5 2.5 - -# Method to run regrid_data_plane, not setting this will default to NEAREST -REGRID_DATA_PLANE_METHOD = NEAREST - -# Regridding width used in regrid_data_plane, not setting this will default to 1 -REGRID_DATA_PLANE_WIDTH = 1 - - -# Configurations for regrid_data_plane: Regrid OLR to -15 to 15 latitude -[regrid_obs_olr] -# Run regrid_data_plane on forecast data -OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} - -# If true, process each field individually and write a file for each -# If false, run once per run time passing in all fields specified -OBS_DATA_PLANE_ONCE_PER_FIELD = False - -# Name of input field to process -OBS_REGRID_DATA_PLANE_VAR1_NAME = olr - -# Level of input field to process -OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "({valid?fmt=%Y%m%d_%H%M%S},*,*)" - -OBS_REGRID_DATA_PLANE_VAR1_OPTIONS = file_type=NETCDF_NCCF; censor_thresh=eq-999.0; censor_val=-9999.0; - -# Name of output field to create -OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = olr - -# input and output data directories for each application in PROCESS_LIST -OBS_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM -OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_RMM/ERA - -# format of filenames -# Input ERA Interim -OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = olr.1x.7920.anom7901.nc -OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = OLR_{valid?fmt=%Y%m%d}.nc - - -# Configurations for regrid_data_plane: Regrid u850 to -15 to 15 latitude -[regrid_obs_u850] -# Run regrid_data_plane on forecast data -OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} - -# If true, process each field individually and write a file for each -# If false, run once per run time passing in all fields specified -OBS_DATA_PLANE_ONCE_PER_FIELD = False - -# Name of input field to process -OBS_REGRID_DATA_PLANE_VAR1_NAME = uwnd - -# Level of input field to process -OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "({valid?fmt=%Y%m%d_%H%M%S},*,*)" - -OBS_REGRID_DATA_PLANE_VAR1_OPTIONS = file_type=NETCDF_NCCF; censor_thresh=eq-999.0; censor_val=-9999.0; - -# Name of output field to create -OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = uwnd850 - -# input and output data directories for each application in PROCESS_LIST -OBS_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM -OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_RMM/ERA - -# format of filenames -# Input ERA Interim -OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = uwnd.erai.an.2p5.850.daily.anom7901.nc -OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = u850_{valid?fmt=%Y%m%d}.nc - - -# Configurations for regrid_data_plane: Regrid u200 to -15 to 15 latitude -[regrid_obs_u200] -# Run regrid_data_plane on forecast data -OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} - -# If true, process each field individually and write a file for each -# If false, run once per run time passing in all fields specified -OBS_DATA_PLANE_ONCE_PER_FIELD = False - -# Name of input field to process -OBS_REGRID_DATA_PLANE_VAR1_NAME = uwnd - -# Level of input field to process -OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "({valid?fmt=%Y%m%d_%H%M%S},*,*)" - -OBS_REGRID_DATA_PLANE_VAR1_OPTIONS = file_type=NETCDF_NCCF; censor_thresh=eq-999.0; censor_val=-9999.0; - -# Name of output field to create -OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = uwnd200 - -# input and output data directories for each application in PROCESS_LIST -OBS_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM -OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_RMM/ERA - -# format of filenames -# Input ERA Interim -OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = uwnd.erai.an.2p5.200.daily.anom7901.nc -OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = u200_{valid?fmt=%Y%m%d}.nc - - -# Configurations for the RMM analysis script -[user_env_vars] -# Whether to Run the model or obs -RUN_OBS = {OBS_RUN} -RUN_FCST = {FCST_RUN} - -# Make OUTPUT_BASE Available to the script -SCRIPT_OUTPUT_BASE = {OUTPUT_BASE} - -# Number of obs per day -OBS_PER_DAY = 1 - -# EOF Filename -OLR_EOF_INPUT_TEXTFILE = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/EOF/rmm_olr_eofs.txt -U850_EOF_INPUT_TEXTFILE = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/EOF/rmm_u850_eofs.txt -U200_EOF_INPUT_TEXTFILE = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/EOF/rmm_u200_eofs.txt - -# Normalization factors for RMM -RMM_OLR_NORM = 15.11623 -RMM_U850_NORM = 1.81355 -RMM_U200_NORM = 4.80978 -PC1_NORM = 8.618352504159244 -PC2_NORM = 8.40736449709697 - -# Output Directory for the plots -# If not set, it this will default to {OUTPUT_BASE}/plots -RMM_PLOT_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_RMM/plots - -# EOF plot information -EOF_PLOT_OUTPUT_NAME = RMM_EOFs -EOF_PLOT_OUTPUT_FORMAT = png - -# Phase Plot start date, end date, output name, and format -PHASE_PLOT_TIME_BEG = 2002010100 -PHASE_PLOT_TIME_END = 2002123000 -PHASE_PLOT_TIME_FMT = {VALID_TIME_FMT} -OBS_PHASE_PLOT_OUTPUT_NAME = obs_RMM_comp_phase -OBS_PHASE_PLOT_OUTPUT_FORMAT = png - -# Time Series Plot start date, end date, output name, and format -TIMESERIES_PLOT_TIME_BEG = 2002010100 -TIMESERIES_PLOT_TIME_END = 2002123000 -TIMESERIES_PLOT_TIME_FMT = {VALID_TIME_FMT} -OBS_TIMESERIES_PLOT_OUTPUT_NAME = obs_RMM_time_series -OBS_TIMESERIES_PLOT_OUTPUT_FORMAT = png - - -# Configurations for UserScript: Run the RMM Analysis driver -[script_rmm] -# list of strings to loop over for each run time. -# Run the user script once per lead -USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD - -# Template of filenames to input to the user-script -USER_SCRIPT_INPUT_TEMPLATE = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/ERA/OLR_{valid?fmt=%Y%m%d}.nc,{INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/ERA/u850_{valid?fmt=%Y%m%d}.nc,{INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/ERA/u200_{valid?fmt=%Y%m%d}.nc - -# Name of the file containing the listing of input files -# The options are OBS_OLR_INPUT, OBS_U850_INPUT, OBS_U200_INPUT, FCST_OLR_INPUT, FCST_U850_INPUT, and FCST_U200_INPUT -# *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE -USER_SCRIPT_INPUT_TEMPLATE_LABELS = OBS_OLR_INPUT,OBS_U850_INPUT, OBS_U200_INPUT - -# Command to run the user script with input configuration file -USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/RMM_driver.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf new file mode 100644 index 0000000000..fff56cde25 --- /dev/null +++ b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI.conf @@ -0,0 +1,157 @@ +# OMI UserScript wrapper +[config] +# All steps, including pre-processing: +#PROCESS_LIST = RegridDataPlane(regrid_obs_olr), UserScript(create_eof_filelist), UserScript(script_omi) +# Finding EOF files and OMI Analysis script for the observations +PROCESS_LIST = UserScript(create_eof_filelist), UserScript(script_omi) + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = VALID + +# Format of VALID_BEG and VALID_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +VALID_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +VALID_BEG = 1979010100 + +# End time for METplus run +VALID_END = 2012123000 + +# Increment between METplus runs in seconds. Must be >= 60 +VALID_INCREMENT = 86400 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = 0 + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = processes + +# location of configuration files used by MET applications +CONFIG_DIR={PARM_BASE}/use_cases/model_applications/s2s + +# Run the obs for these cases +OBS_RUN = True +FCST_RUN = False + +# Mask to use for regridding +REGRID_DATA_PLANE_VERIF_GRID = latlon 144 17 -20 0 2.5 2.5 + +# Method to run regrid_data_plane, not setting this will default to NEAREST +REGRID_DATA_PLANE_METHOD = NEAREST + +# Regridding width used in regrid_data_plane, not setting this will default to 1 +REGRID_DATA_PLANE_WIDTH = 1 + +# Input and Output Directories for the OBS OLR Files and output text file containing the file list +OBS_OLR_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/ERA +OBS_OLR_INPUT_TEMPLATE = OLR_{valid?fmt=%Y%m%d}.nc + + +# Configurations for regrid_data_plane: Regrid OLR to -20 to 20 latitude +[regrid_obs_olr] +# Run regrid_data_plane on forecast data +OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} + +# If true, process each field individually and write a file for each +# If false, run once per run time passing in all fields specified +OBS_DATA_PLANE_ONCE_PER_FIELD = False + +# Name of input field to process +OBS_REGRID_DATA_PLANE_VAR1_NAME = olr + +# Level of input field to process +OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "({valid?fmt=%Y%m%d_%H%M%S},*,*)" + +OBS_REGRID_DATA_PLANE_VAR1_OPTIONS = file_type=NETCDF_NCCF; censor_thresh=eq-999.0; censor_val=-9999.0; + +# Name of output field to create +OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = olr + +# input and output data directories for each application in PROCESS_LIST +OBS_REGRID_DATA_PLANE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_OMI +OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OBS_OLR_INPUT_DIR} + +# format of filenames +# Input ERA Interim +OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = olr.1x.7920.nc +OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = {OBS_OLR_INPUT_TEMPLATE} + + +# Create the EOF filelists +[create_eof_filelist] +# Find the files for each time to create the time list +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE + +# Valid Begin and End Times for the EOF files +VALID_BEG = 2012010100 +VALID_END = 2012123100 + +# Find the EOF files for each time +# Filename templates for EOF1 and EOF2 +USER_SCRIPT_INPUT_TEMPLATE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/EOF/eof1/eof{valid?fmt=%j}.txt,{INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/EOF/eof2/eof{valid?fmt=%j}.txt + +# Name of the file containing the listing of input files +# The options are EOF1_INPUT and EOF2_INPUT +# *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE +USER_SCRIPT_INPUT_TEMPLATE_LABELS = EOF1_INPUT, EOF2_INPUT + +# Placeholder command just to build the file list +# This just states that it's building the file list +USER_SCRIPT_COMMAND = echo Populated file list for EOF1 and EOF2 Input + + +# Configurations for the OMI analysis script +[user_env_vars] +# Whether to Run the model or obs +RUN_OBS = {OBS_RUN} +RUN_FCST = {FCST_RUN} + +# Make OUTPUT_BASE Available to the script +SCRIPT_OUTPUT_BASE = {OUTPUT_BASE} + +# Number of obs per day +OBS_PER_DAY = 1 + +# Output Directory for the plots +# If not set, it this will default to {OUTPUT_BASE}/plots +OMI_PLOT_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_OMI/plots + +# Phase Plot start date, end date, output name, and format +PHASE_PLOT_TIME_BEG = 2012010100 +PHASE_PLOT_TIME_END = 2012033000 +PHASE_PLOT_TIME_FMT = {VALID_TIME_FMT} +OBS_PHASE_PLOT_OUTPUT_NAME = obs_OMI_comp_phase +OBS_PHASE_PLOT_OUTPUT_FORMAT = png + + +# Configurations for UserScript: Run the RMM Analysis driver +[script_omi] +# Run the script once per lead time +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD + +## Template of OLR filenames to input to the user-script +USER_SCRIPT_INPUT_TEMPLATE = {OBS_OLR_INPUT_DIR}/{OBS_OLR_INPUT_TEMPLATE} + +## Name of the file containing the listing of OLR input files +## The options are OBS_OLR_INPUT and FCST_OLR_INPUT +## *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE +USER_SCRIPT_INPUT_TEMPLATE_LABELS = OBS_OLR_INPUT + +# Command to run the user script with input configuration file +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py new file mode 120000 index 0000000000..ff871c910e --- /dev/null +++ b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_OMI/OMI_driver.py @@ -0,0 +1 @@ +../UserScript_fcstGFS_obsERA_OMI/OMI_driver.py \ No newline at end of file diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf similarity index 92% rename from parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf rename to parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf index 9326a96e2b..7f435f4034 100644 --- a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram.conf +++ b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram.conf @@ -50,7 +50,7 @@ FCST_RUN = False # Input and Output Directories for the OBS OLR Files and output text file containing the file list OBS_PDTIME_FMT = %Y%m%d-%H%M%S OBS_PDTIME_INPUT_TEMPLATE = {valid?fmt=%Y%m%d-%H%M%S} -OBS_PDTIME_OUTPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/ +OBS_PDTIME_OUTPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/ OBS_PDTIME_OUTPUT_TEMPLATE = time_list_lead{lead?fmt=%HHH}.txt @@ -59,7 +59,7 @@ OBS_PDTIME_OUTPUT_TEMPLATE = time_list_lead{lead?fmt=%HHH}.txt # Find the files for each time USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_FOR_EACH -USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/save_input_files_txt.py {OBS_PDTIME_INPUT_TEMPLATE} {OBS_PDTIME_OUTPUT_DIR}/{OBS_PDTIME_OUTPUT_TEMPLATE} +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/save_input_files_txt.py {OBS_PDTIME_INPUT_TEMPLATE} {OBS_PDTIME_OUTPUT_DIR}/{OBS_PDTIME_OUTPUT_TEMPLATE} # Configurations for the Phase Diagram Plotting Script @@ -86,7 +86,7 @@ OBS_PHASE_DIAGRAM_INPUT_TIMELIST_TEXTFILE = {OBS_PDTIME_OUTPUT_DIR}/{OBS_PDTIME_ OBS_PHASE_DIAGRAM_INPUT_TIME_FMT = {OBS_PDTIME_FMT} # Plot Output Directory -PHASE_DIAGRAM_PLOT_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/plots +PHASE_DIAGRAM_PLOT_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/plots # Plot Ouptut Name OBS_PHASE_PLOT_OUTPUT_NAME = RMM_phase_diagram @@ -99,4 +99,4 @@ OBS_PHASE_PLOT_OUTPUT_NAME = RMM_phase_diagram USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD # Command to run the user script with input configuration file -USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/PhaseDiagram_driver.py +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/PhaseDiagram_driver.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/PhaseDiagram_driver.py b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/PhaseDiagram_driver.py similarity index 100% rename from parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/PhaseDiagram_driver.py rename to parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/PhaseDiagram_driver.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/save_input_files_txt.py b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/save_input_files_txt.py similarity index 100% rename from parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_PhaseDiagram/save_input_files_txt.py rename to parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_PhaseDiagram/save_input_files_txt.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf new file mode 100644 index 0000000000..495a124b2f --- /dev/null +++ b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM.conf @@ -0,0 +1,436 @@ +# RMM UserScript wrapper +[config] +# All steps, including creating daily means and mean daily annual cycle +#PROCESS_LIST = PcpCombine(mean_daily_annual_cycle_obs_wind), PcpCombine(mean_daily_annual_cycle_obs_olr), PcpCombine(daily_mean_obs_wind), PcpCombine(daily_mean_obs_olr), UserScript(create_mda_filelist), UserScript(harmonic_anomalies_olr), UserScript(harmonic_anomalies_u850), UserScript(harmonic_anomalies_u200), RegridDataPlane(regrid_obs_olr), RegridDataPlane(regrid_obs_u850), RegridDataPlane(regrid_obs_u200), UserScript(script_rmm) +# Computing anomalies, regridding, and RMM Analysis script +PROCESS_LIST = UserScript(create_mda_filelist), UserScript(harmonic_anomalies_olr), UserScript(harmonic_anomalies_u850), UserScript(harmonic_anomalies_u200), RegridDataPlane(regrid_obs_olr), RegridDataPlane(regrid_obs_u850), RegridDataPlane(regrid_obs_u200), UserScript(script_rmm) + +# time looping - options are INIT, VALID, RETRO, and REALTIME +# If set to INIT or RETRO: +# INIT_TIME_FMT, INIT_BEG, INIT_END, and INIT_INCREMENT must also be set +# If set to VALID or REALTIME: +# VALID_TIME_FMT, VALID_BEG, VALID_END, and VALID_INCREMENT must also be set +LOOP_BY = VALID + +# Format of VALID_BEG and VALID_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +VALID_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +VALID_BEG = 2000010100 + +# End time for METplus run +VALID_END = 2002123000 + +# Increment between METplus runs in seconds. Must be >= 60 +VALID_INCREMENT = 86400 + +# List of forecast leads to process for each run time (init or valid) +# In hours if units are not specified +# If unset, defaults to 0 (don't loop through forecast leads) +LEAD_SEQ = 0 + +# Order of loops to process data - Options are times, processes +# Not relevant if only one item is in the PROCESS_LIST +# times = run all wrappers in the PROCESS_LIST for a single run time, then +# increment the run time and run all wrappers again until all times have +# been evaluated. +# processes = run the first wrapper in the PROCESS_LIST for all times +# specified, then repeat for the next item in the PROCESS_LIST until all +# wrappers have been run +LOOP_ORDER = processes + +# location of configuration files used by MET applications +CONFIG_DIR={PARM_BASE}/use_cases/model_applications/s2s + +# Run the obs for these cases +OBS_RUN = True +FCST_RUN = False + +# Mask to use for regridding +REGRID_DATA_PLANE_VERIF_GRID = latlon 144 13 -15 0 2.5 2.5 + +# Method to run regrid_data_plane, not setting this will default to NEAREST +REGRID_DATA_PLANE_METHOD = NEAREST + +# Regridding width used in regrid_data_plane, not setting this will default to 1 +REGRID_DATA_PLANE_WIDTH = 1 + + +# Configurations for creating U200 and U850 mean daily annual cycle obs +# Mean daily annual cycle anomalies are computed for 1979 - 2001 +[mean_daily_annual_cycle_obs_wind] +LOOP_BY = VALID + +# Format of VALID_BEG and VALID_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +VALID_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +# Set to one year, since we want a mean daily across all years +# Using 2012 because leap day will be included +VALID_BEG = 2012010100 + +# End time for METplus run +VALID_END = 2012123100 + +# Increment between METplus runs in seconds. Must be >= 60 +VALID_INCREMENT = 86400 + +# run pcp_combine on obs data +OBS_PCP_COMBINE_RUN = {OBS_RUN} + +# method to run pcp_combine on forecast data +# Options are ADD, SUM, SUBTRACT, DERIVE, and USER_DEFINED +OBS_PCP_COMBINE_METHOD = USER_DEFINED + +OBS_PCP_COMBINE_COMMAND = -derive mean {OBS_PCP_COMBINE_INPUT_DIR}/{OBS_PCP_COMBINE_INPUT_TEMPLATE} -field 'name="U_P850_mean"; level="(*,*)"; set_attr_valid = "{valid?fmt=%Y%m%d_%H%M%S}";' -field 'name="U_P200_mean"; level="(*,*)"; set_attr_valid = "{valid?fmt=%Y%m%d_%H%M%S}";' -name U_P850_mean,U_P200_mean + +OBS_PCP_COMBINE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean +OBS_PCP_COMBINE_INPUT_TEMPLATE = ERA_wind_daily_mean_*{valid?fmt=%m%d}.nc + +OBS_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/mean_daily_annual_cycle +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = ERA_wind_daily_annual_{valid?fmt=%m%d}.nc + + +# Configurations for creating OLR mean daily annual cycle obs +# Mean daily annual cycle anomalies are computed for 1979 - 2001 +[mean_daily_annual_cycle_obs_olr] +LOOP_BY = VALID + +# Format of VALID_BEG and VALID_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +VALID_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +# Set to one year, since we want a mean daily across all years +# Using 2012 because leap day will be included +VALID_BEG = 2012010100 + +# End time for METplus run +VALID_END = 2012123100 + +# Increment between METplus runs in seconds. Must be >= 60 +VALID_INCREMENT = 86400 + +# run pcp_combine on obs data +OBS_PCP_COMBINE_RUN = {OBS_RUN} + +# method to run pcp_combine on forecast data +# Options are ADD, SUM, SUBTRACT, DERIVE, and USER_DEFINED +OBS_PCP_COMBINE_METHOD = USER_DEFINED + +OBS_PCP_COMBINE_COMMAND = -derive mean {OBS_PCP_COMBINE_INPUT_DIR}/{OBS_PCP_COMBINE_INPUT_TEMPLATE} -field 'name="olr"; level="(*,*)";' + +OBS_PCP_COMBINE_INPUT_DIR = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean +OBS_PCP_COMBINE_INPUT_TEMPLATE = ERA_OLR_daily_mean_*{valid?fmt=%m%d}.nc + +OBS_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/mean_daily_annual_cycle +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = ERA_OLR_daily_annual_{valid?fmt=%m%d}.nc + + +# Configurations for creating U200 and U850 daily mean obs +[daily_mean_obs_wind] +LOOP_BY = VALID + +# Format of VALID_BEG and VALID_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +VALID_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +VALID_BEG = 1979010100 + +# End time for METplus run +VALID_END = 2002123100 + +# Increment between METplus runs in seconds. Must be >= 60 +VALID_INCREMENT = 86400 + +# run pcp_combine on obs data +OBS_PCP_COMBINE_RUN = {OBS_RUN} + +# method to run pcp_combine on forecast data +# Options are ADD, SUM, SUBTRACT, DERIVE, and USER_DEFINED +OBS_PCP_COMBINE_METHOD = USER_DEFINED + +OBS_PCP_COMBINE_COMMAND = -derive mean {OBS_PCP_COMBINE_INPUT_DIR}/{OBS_PCP_COMBINE_INPUT_TEMPLATE} -field 'name="U"; level="P850"; set_attr_valid = "{valid?fmt=%Y%m%d_%H%M%S}";' -field 'name="U"; level="P200"; set_attr_valid = "{valid?fmt=%Y%m%d_%H%M%S}";' + +OBS_PCP_COMBINE_INPUT_DIR = /gpfs/fs1/collections/rda/data/ds627.0/ei.oper.an.pl +OBS_PCP_COMBINE_INPUT_TEMPLATE = {valid?fmt=%Y%m}/ei.oper.an.pl.regn128uv.{valid?fmt=%Y%m%d}* + +OBS_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = ERA_wind_daily_mean_{valid?fmt=%Y%m%d}.nc + + +# Configurations for creating mean daily annual cycle obs OLR +[daily_mean_obs_olr] +LOOP_BY = VALID + +# Format of VALID_BEG and VALID_END using % items +# %Y = 4 digit year, %m = 2 digit month, %d = 2 digit day, etc. +# see www.strftime.org for more information +# %Y%m%d%H expands to YYYYMMDDHH +VALID_TIME_FMT = %Y%m%d%H + +# Start time for METplus run +VALID_BEG = 1979010100 + +# End time for METplus run +VALID_END = 2002123100 + +# Increment between METplus runs in seconds. Must be >= 60 +VALID_INCREMENT = 86400 + +# run pcp_combine on obs data +OBS_PCP_COMBINE_RUN = {OBS_RUN} + +# method to run pcp_combine on forecast data +# Options are ADD, SUM, SUBTRACT, DERIVE, and USER_DEFINED +OBS_PCP_COMBINE_METHOD = USER_DEFINED + +OBS_PCP_COMBINE_COMMAND = -add {OBS_PCP_COMBINE_INPUT_DIR}/{OBS_PCP_COMBINE_INPUT_TEMPLATE} -field 'name="olr"; level="({valid?fmt=%Y%m%d_%H%M%S},*,*)"; file_type=NETCDF_NCCF;' + +OBS_PCP_COMBINE_INPUT_DIR = /glade/u/home/kalb/MJO +OBS_PCP_COMBINE_INPUT_TEMPLATE = olr.1x.7920.nc + +OBS_PCP_COMBINE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean +OBS_PCP_COMBINE_OUTPUT_TEMPLATE = ERA_OLR_daily_mean_{valid?fmt=%Y%m%d}.nc + + +# Creating a file list of the mean daily annual cycle files +# This is run separately since it has different start/end times +[create_mda_filelist] +# Find the files for each lead time +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD + +# Valid Begin and End Times for the CBL File Climatology +VALID_BEG = 2012010100 +VALID_END = 2012123100 +VALID_INCREMENT = 86400 +LEAD_SEQ = 0 + +# Template of filenames to input to the user-script +USER_SCRIPT_INPUT_TEMPLATE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/mean_daily_annual_cycle/ERA_OLR_daily_annual_{valid?fmt=%m%d}.nc,{INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/mean_daily_annual_cycle/ERA_wind_daily_annual_{valid?fmt=%m%d}.nc + +# Name of the file containing the listing of input files +USER_SCRIPT_INPUT_TEMPLATE_LABELS = input_mean_daily_annual_infiles_olr,input_mean_daily_annual_infiles_wind + +# Placeholder command just to build the file list +# This just states that it's building the file list +USER_SCRIPT_COMMAND = echo Populated file list for Mean daily annual cycle Input + + +# Configurations to create anomalies for OLR +[harmonic_anomalies_olr] +# list of strings to loop over for each run time. +# Run the user script once per lead +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD + +# Template of filenames to input to the user-script +USER_SCRIPT_INPUT_TEMPLATE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean/ERA_OLR_daily_mean_{valid?fmt=%Y%m%d}.nc + +# Name of the file containing the listing of input files +# The options are OBS_OLR_INPUT, OBS_U850_INPUT, OBS_U200_INPUT, FCST_OLR_INPUT, FCST_U850_INPUT, and FCST_U200_INPUT +# *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE +USER_SCRIPT_INPUT_TEMPLATE_LABELS = input_daily_mean_infiles + +# Command to run the user script with input configuration file +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py 'METPLUS_FILELIST_INPUT_MEAN_DAILY_ANNUAL_INFILES_OLR' 'olr' 'olr_NA_mean' '{OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Anomaly' 'ERA_OLR_anom' + + +# Configurations to create anomalies for U850 +[harmonic_anomalies_u850] +# list of strings to loop over for each run time. +# Run the user script once per lead +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD + +# Template of filenames to input to the user-script +USER_SCRIPT_INPUT_TEMPLATE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean/ERA_wind_daily_mean_{valid?fmt=%Y%m%d}.nc + +# Name of the file containing the listing of input files +# The options are OBS_OLR_INPUT, OBS_U850_INPUT, OBS_U200_INPUT, FCST_OLR_INPUT, FCST_U850_INPUT, and FCST_U200_INPUT +# *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE +USER_SCRIPT_INPUT_TEMPLATE_LABELS = input_daily_mean_infiles + +# Command to run the user script with input configuration file +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py 'METPLUS_FILELIST_INPUT_MEAN_DAILY_ANNUAL_INFILES_WIND' 'U_P850_mean' 'U_P850_mean' '{OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Anomaly' 'ERA_U850_anom' + + +# Configurations to create anomalies for U200 +[harmonic_anomalies_u200] +# list of strings to loop over for each run time. +# Run the user script once per lead +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD + +# Template of filenames to input to the user-script +USER_SCRIPT_INPUT_TEMPLATE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/ERA/daily_mean/ERA_wind_daily_mean_{valid?fmt=%Y%m%d}.nc + +# Name of the file containing the listing of input files +# The options are OBS_OLR_INPUT, OBS_U850_INPUT, OBS_U200_INPUT, FCST_OLR_INPUT, FCST_U850_INPUT, and FCST_U200_INPUT +# *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE +USER_SCRIPT_INPUT_TEMPLATE_LABELS = input_daily_mean_infiles + +# Command to run the user script with input configuration file +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py 'METPLUS_FILELIST_INPUT_MEAN_DAILY_ANNUAL_INFILES_WIND' 'U_P200_mean' 'U_P200_mean' '{OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Anomaly' 'ERA_U200_anom' + + +# Configurations for regrid_data_plane: Regrid OLR to -15 to 15 latitude +[regrid_obs_olr] +# Run regrid_data_plane on forecast data +OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} + +# If true, process each field individually and write a file for each +# If false, run once per run time passing in all fields specified +REGRID_DATA_PLANE_ONCE_PER_FIELD = False + +# Name of input field to process +OBS_REGRID_DATA_PLANE_VAR1_NAME = olr_anom + +# Level of input field to process +OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "(*,*)" + +# Name of output field to create +OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = OLR_anom + +# input and output data directories for each application in PROCESS_LIST +OBS_REGRID_DATA_PLANE_INPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Anomaly +OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Regrid + +# format of filenames +# Input ERA Interim +OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = ERA_OLR_anom_{lead?fmt=%H%M%S}L_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V.nc +OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = ERA_OLR_{valid?fmt=%Y%m%d}.nc + + +# Configurations for regrid_data_plane: Regrid u850 to -15 to 15 latitude +[regrid_obs_u850] +# Run regrid_data_plane on forecast data +OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} + +# If true, process each field individually and write a file for each +# If false, run once per run time passing in all fields specified +REGRID_DATA_PLANE_ONCE_PER_FIELD = False + +# Name of input field to process +OBS_REGRID_DATA_PLANE_VAR1_NAME = U_P850_mean_anom + +# Level of input field to process +OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "(*,*)" + +# Name of output field to create +OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = U_P850_anom + +# input and output data directories for each application in PROCESS_LIST +OBS_REGRID_DATA_PLANE_INPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Anomaly +OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Regrid + +# format of filenames +# Input ERA Interim +OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = ERA_U850_anom_{lead?fmt=%H%M%S}L_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V.nc +OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = ERA_U850_{valid?fmt=%Y%m%d}.nc + + +# Configurations for regrid_data_plane: Regrid u200 to -15 to 15 latitude +[regrid_obs_u200] +# Run regrid_data_plane on forecast data +OBS_REGRID_DATA_PLANE_RUN = {OBS_RUN} + +# If true, process each field individually and write a file for each +# If false, run once per run time passing in all fields specified +REGRID_DATA_PLANE_ONCE_PER_FIELD = False + +# Name of input field to process +OBS_REGRID_DATA_PLANE_VAR1_NAME = U_P200_mean_anom + +# Level of input field to process +OBS_REGRID_DATA_PLANE_VAR1_LEVELS = "(*,*)" + +# Name of output field to create +OBS_REGRID_DATA_PLANE_VAR1_OUTPUT_FIELD_NAME = U_P200_anom + +# input and output data directories for each application in PROCESS_LIST +OBS_REGRID_DATA_PLANE_INPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Anomaly +OBS_REGRID_DATA_PLANE_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Regrid + +# format of filenames +# Input ERA Interim +OBS_REGRID_DATA_PLANE_INPUT_TEMPLATE = ERA_U200_anom_{lead?fmt=%H%M%S}L_{valid?fmt=%Y%m%d}_{valid?fmt=%H%M%S}V.nc +OBS_REGRID_DATA_PLANE_OUTPUT_TEMPLATE = ERA_U200_{valid?fmt=%Y%m%d}.nc + + +# Configurations for the RMM analysis script +[user_env_vars] +# Whether to Run the model or obs +RUN_OBS = {OBS_RUN} +RUN_FCST = {FCST_RUN} + +# Make OUTPUT_BASE Available to the script +SCRIPT_OUTPUT_BASE = {OUTPUT_BASE} + +# Number of obs per day +OBS_PER_DAY = 1 + +# Variable names for OLR, U850, U200 +OBS_OLR_VAR_NAME = OLR_anom +OBS_U850_VAR_NAME = U_P850_anom +OBS_U200_VAR_NAME = U_P200_anom + +# EOF Filename +OLR_EOF_INPUT_TEXTFILE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/EOF/rmm_olr_eofs.txt +U850_EOF_INPUT_TEXTFILE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/EOF/rmm_u850_eofs.txt +U200_EOF_INPUT_TEXTFILE = {INPUT_BASE}/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/EOF/rmm_u200_eofs.txt + +# Normalization factors for RMM +RMM_OLR_NORM = 15.11623 +RMM_U850_NORM = 1.81355 +RMM_U200_NORM = 4.80978 +PC1_NORM = 8.618352504159244 +PC2_NORM = 8.40736449709697 + +# Output Directory for the plots +# If not set, it this will default to {OUTPUT_BASE}/plots +RMM_PLOT_OUTPUT_DIR = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/plots + +# EOF plot information +EOF_PLOT_OUTPUT_NAME = RMM_EOFs +EOF_PLOT_OUTPUT_FORMAT = png + +# Phase Plot start date, end date, output name, and format +PHASE_PLOT_TIME_BEG = 2002010100 +PHASE_PLOT_TIME_END = 2002123000 +PHASE_PLOT_TIME_FMT = {VALID_TIME_FMT} +OBS_PHASE_PLOT_OUTPUT_NAME = obs_RMM_comp_phase +OBS_PHASE_PLOT_OUTPUT_FORMAT = png + +# Time Series Plot start date, end date, output name, and format +TIMESERIES_PLOT_TIME_BEG = 2002010100 +TIMESERIES_PLOT_TIME_END = 2002123000 +TIMESERIES_PLOT_TIME_FMT = {VALID_TIME_FMT} +OBS_TIMESERIES_PLOT_OUTPUT_NAME = obs_RMM_time_series +OBS_TIMESERIES_PLOT_OUTPUT_FORMAT = png + + +# Configurations for UserScript: Run the RMM Analysis driver +[script_rmm] +# list of strings to loop over for each run time. +# Run the user script once per lead +USER_SCRIPT_RUNTIME_FREQ = RUN_ONCE_PER_LEAD + +# Template of filenames to input to the user-script +USER_SCRIPT_INPUT_TEMPLATE = {OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Regrid/ERA_OLR_{valid?fmt=%Y%m%d}.nc,{OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Regrid/ERA_U850_{valid?fmt=%Y%m%d}.nc,{OUTPUT_BASE}/s2s/UserScript_obsERA_obsOnly_RMM/ERA/Regrid/ERA_U200_{valid?fmt=%Y%m%d}.nc + +# Name of the file containing the listing of input files +# The options are OBS_OLR_INPUT, OBS_U850_INPUT, OBS_U200_INPUT, FCST_OLR_INPUT, FCST_U850_INPUT, and FCST_U200_INPUT +# *** Make sure the order is the same as the order of templates listed in USER_SCRIPT_INPUT_TEMPLATE +USER_SCRIPT_INPUT_TEMPLATE_LABELS = OBS_OLR_INPUT,OBS_U850_INPUT, OBS_U200_INPUT + +# Command to run the user script with input configuration file +USER_SCRIPT_COMMAND = {METPLUS_BASE}/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/RMM_driver.py diff --git a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/RMM_driver.py b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/RMM_driver.py similarity index 88% rename from parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/RMM_driver.py rename to parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/RMM_driver.py index d33906c9d8..3e3f5b741f 100755 --- a/parm/use_cases/model_applications/s2s/UserScript_fcstGFS_obsERA_RMM/RMM_driver.py +++ b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/RMM_driver.py @@ -48,11 +48,15 @@ def read_rmm_eofs(olrfile, u850file, u200file): def run_rmm_steps(inlabel, spd, EOF1, EOF2, oplot_dir): - # Get OLR, U850, U200 file listings + # Get OLR, U850, U200 file listings and variable names olr_filetxt = os.environ['METPLUS_FILELIST_'+inlabel+'_OLR_INPUT'] u850_filetxt = os.environ['METPLUS_FILELIST_'+inlabel+'_U850_INPUT'] u200_filetxt = os.environ['METPLUS_FILELIST_'+inlabel+'_U200_INPUT'] + olr_var = os.environ[inlabel+'_OLR_VAR_NAME'] + u850_var = os.environ[inlabel+'_U850_VAR_NAME'] + u200_var = os.environ[inlabel+'_U200_VAR_NAME'] + # Read the listing of OLR, U850, U200 files with open(olr_filetxt) as ol: olr_input_files = ol.read().splitlines() @@ -67,6 +71,18 @@ def run_rmm_steps(inlabel, spd, EOF1, EOF2, oplot_dir): if (u200_input_files[0] == 'file_list'): u200_input_files = u200_input_files[1:] + # Check the input data to make sure it's not all missing + olr_allmissing = all(elem == 'missing' for elem in olr_input_files) + if olr_allmissing: + raise IOError ('No input OLR files were found, check file paths') + u850_allmissing = all(elem == 'missing' for elem in u850_input_files) + if u850_allmissing: + raise IOError('No input U850 files were found, check file paths') + u200_allmissing = all(elem == 'missing' for elem in u200_input_files) + if u200_allmissing: + raise IOError('No input U200 files were found, check file paths') + + # Read OLR, U850, U200 data from file netcdf_reader_olr = read_netcdf.ReadNetCDF() ds_olr = netcdf_reader_olr.read_into_xarray(olr_input_files) @@ -81,7 +97,7 @@ def run_rmm_steps(inlabel, spd, EOF1, EOF2, oplot_dir): time = [] for din in range(len(ds_olr)): colr = ds_olr[din] - ctime = datetime.datetime.strptime(colr['olr'].valid_time,'%Y%m%d_%H%M%S') + ctime = datetime.datetime.strptime(colr[olr_var].valid_time,'%Y%m%d_%H%M%S') time.append(ctime.strftime('%Y-%m-%d')) colr = colr.assign_coords(time=ctime) ds_olr[din] = colr.expand_dims("time") @@ -97,17 +113,17 @@ def run_rmm_steps(inlabel, spd, EOF1, EOF2, oplot_dir): time = np.array(time,dtype='datetime64[D]') everything_olr = xr.concat(ds_olr,"time") - olr = everything_olr['olr'] + olr = everything_olr[olr_var] olr = olr.mean('lat') print(olr.min(), olr.max()) everything_u850 = xr.concat(ds_u850,"time") - u850 = everything_u850['uwnd850'] + u850 = everything_u850[u850_var] u850 = u850.mean('lat') print(u850.min(), u850.max()) everything_u200 = xr.concat(ds_u200,"time") - u200 = everything_u200['uwnd200'] + u200 = everything_u200[u200_var] u200 = u200.mean('lat') print(u200.min(), u200.max()) @@ -186,7 +202,7 @@ def main(): # Determine if doing forecast or obs run_obs_rmm = os.environ.get('RUN_OBS', 'False').lower() - run_fcst_rmm = os.environ.get('FCST_RUN_FCST', 'False').lower() + run_fcst_rmm = os.environ.get('RUN_FCST', 'False').lower() if (run_obs_rmm == 'true'): run_rmm_steps('OBS', spd, EOF1, EOF2, oplot_dir) diff --git a/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py new file mode 100755 index 0000000000..6c6fe9dad7 --- /dev/null +++ b/parm/use_cases/model_applications/s2s/UserScript_obsERA_obsOnly_RMM/compute_harmonic_anomalies.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +import numpy as np +import xarray as xr +import glob +import os +import sys +import datetime +import METreadnc.util.read_netcdf as read_netcdf + +input_mean_daily_annual_infiles_list = os.environ[sys.argv[1]] +dm_var = sys.argv[2] +mda_var = sys.argv[3] +anom_output_dir = sys.argv[4] +anom_output_base = sys.argv[5] +input_daily_mean_infiles_list = os.environ['METPLUS_FILELIST_INPUT_DAILY_MEAN_INFILES'] + +# Environment variables for script +nobs = int(os.environ.get('OBS_PER_DAY',1)) +out_var = dm_var+'_anom' + +# Read the listing of files +with open(input_daily_mean_infiles_list) as idm: + input_daily_mean_infiles = idm.read().splitlines() +if (input_daily_mean_infiles[0] == 'file_list'): + input_daily_mean_infiles = input_daily_mean_infiles[1:] + +with open(input_mean_daily_annual_infiles_list) as imda: + input_mean_daily_annual_infiles = imda.read().splitlines() +if (input_mean_daily_annual_infiles[0] == 'file_list'): + input_mean_daily_annual_infiles = input_mean_daily_annual_infiles[1:] + + +# Read in the data +netcdf_reader = read_netcdf.ReadNetCDF() +dm_orig = netcdf_reader.read_into_xarray(input_daily_mean_infiles) +# Add some needed attributes +dm_list = [] +time_dm = [] +yr_dm = [] +doy_dm = [] +for din in dm_orig: + ctime = datetime.datetime.strptime(din[dm_var].valid_time,'%Y%m%d_%H%M%S') + time_dm.append(ctime.strftime('%Y-%m-%d')) + yr_dm.append(int(ctime.strftime('%Y'))) + doy_dm.append(int(ctime.strftime('%j'))) + din = din.assign_coords(time=ctime) + din = din.expand_dims("time") + dm_list.append(din) +time_dm = np.array(time_dm,dtype='datetime64[D]') +yr_dm = np.array(yr_dm) +doy_dm = np.array(doy_dm) +everything = xr.concat(dm_list,"time") +dm_data = np.array(everything[dm_var]) + +netcdf_reader2 = read_netcdf.ReadNetCDF() +mda_orig = netcdf_reader2.read_into_xarray(input_mean_daily_annual_infiles) +# Add some needed attributes +mda_list = [] +time_mda = [] +for din in mda_orig: + ctime = datetime.datetime.strptime(din[mda_var].valid_time,'%Y%m%d_%H%M%S') + time_mda.append(ctime.strftime('%Y-%m-%d')) + din = din.assign_coords(time=ctime) + din = din.expand_dims("time") + mda_list.append(din) +time_mda = np.array(time_mda,dtype='datetime64[D]') +everything2 = xr.concat(mda_list,"time") +mda_data = np.array(everything2[mda_var]) + +# Harmonic Analysis, first step is Forward Fast Fourier Transform +clmfft = np.fft.rfft(mda_data,axis=0) + +smthfft = np.zeros(clmfft.shape,dtype=complex) +for f in np.arange(0,3): + smthfft[f,:,:] = clmfft[f,:,:] + +clmout = np.fft.irfft(smthfft,axis=0) + +# Subtract the clmout from the data to create anomalies, each year at a time +yrstrt = yr_dm[0] +yrend = yr_dm[-1] +anom = np.zeros(dm_data.shape) + +for y in np.arange(yrstrt,yrend+1,1): + curyr = np.where(yr_dm == y) + dd = doy_dm[curyr] - 1 + ndd = len(curyr[0]) + clmshp = [np.arange(dd[0]*nobs,dd[0]*nobs+ndd,1)] + anom[curyr,:,:] = dm_data[curyr,:,:] - clmout[clmshp,:,:] + +# Assign to an xarray and write output +if not os.path.exists(anom_output_dir): + os.makedirs(anom_output_dir) +for o in np.arange(0,len(dm_orig)): + dm_orig_cur = dm_orig[o] + dout = xr.Dataset({out_var: (("lat", "lon"),anom[o,:,:])}, + coords={"lat": dm_orig_cur.coords['lat'], "lon": dm_orig_cur.coords['lon']}, + attrs=dm_orig_cur.attrs) + dout[out_var].attrs = dm_orig_cur[dm_var].attrs + dout[out_var].attrs['long_name'] = dm_orig_cur[dm_var].attrs['long_name']+' Anomalies' + dout[out_var].attrs['name'] = out_var + + # write to a file + cvtime = datetime.datetime.strptime(dm_orig_cur[dm_var].valid_time,'%Y%m%d_%H%M%S') + citime = datetime.datetime.strptime(dm_orig_cur[dm_var].init_time,'%Y%m%d_%H%M%S') + cltime = (cvtime - citime) + leadmin,leadsec = divmod(cltime.total_seconds(), 60) + leadhr,leadmin = divmod(leadmin,60) + lead_str = str(int(leadhr)).zfill(2)+str(int(leadmin)).zfill(2)+str(int(leadsec)).zfill(2) + dout.to_netcdf(os.path.join(anom_output_dir,anom_output_base+'_'+lead_str+'L_'+cvtime.strftime('%Y%m%d')+'_'+cvtime.strftime('%H%M%S')+'V.nc'))