Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature_342_add_write_mpr_file #359

Merged
merged 1 commit into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/Users_Guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ National Center for Atmospheric Research (NCAR) is sponsored by NSF.
vertical_interpolation
difficulty_index
aggregation
write_mpr
release-notes

**Indices and tables**
Expand Down
98 changes: 98 additions & 0 deletions docs/Users_Guide/write_mpr.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
**********************
Write MPR
**********************

Description
===========

This program writes data to an output file in MET’s Matched Pair (MPR) format. It
takes several inputs, which are described in the list below. The script will compute
the observation input and total number of observations. It will also check to see if
the output directory is present and will create that directory if it does not exist.

Example
=======

Examples for how to use this script can be found in the driver scripts of the use cases
listed below.

* `Stratosphere Polar <https://metplus.readthedocs.io/en/latest/generated/model_applications/s2s/UserScript_fcstGFS_obsERA_StratospherePolar.html#sphx-glr-generated-model-applications-s2s-userscript-fcstgfs-obsera-stratospherepolar-py>`_
* `Blocking <https://metplus.readthedocs.io/en/latest/generated/model_applications/s2s_mid_lat/UserScript_fcstGFS_obsERA_Blocking.html#sphx-glr-generated-model-applications-s2s-mid-lat-userscript-fcstgfs-obsera-blocking-py>`_
* `Weather Regime <https://metplus.readthedocs.io/en/latest/generated/model_applications/s2s_mid_lat/UserScript_fcstGFS_obsERA_WeatherRegime.html#sphx-glr-generated-model-applications-s2s-mid-lat-userscript-fcstgfs-obsera-weatherregime-py>`_

Information about Input Data
============================

At this time, all input arrays have to be one dimensional only and should be the same size.
The script does not make an attempt to check if input arrays are the same size. If any of
your input arrays are larger than the observation input array, the data will be chopped at
the length of the observation input. If an array is shorter than the observation input, the
program will error.

Currently, the the following variables cannot be set and will be output as NA: FCST_THRESH,
OBS_THRESH, COV_THRESH, ALPHA, OBS_QC, CLIMO_MEAN, CLIMO_STDEV, CLIMO_CDF. Additionally the
following variables also cannot be set and have default values: INTERP_MTHD = NEAREST,
INTERP_PNTS = 1, and OBTYPE = ADPUPA.

data_fcst: 1D array float
forecast data to write to MPR file
data_obs: 1D array float
observation data to write to MPR file
lats_in: 1D array float
data latitudes
lons_in: 1D array float
data longitudes
fcst_lead: 1D array string of format HHMMSS
forecast lead time
fcst_valid: 1D array string of format YYYYmmdd_HHMMSS
forecast valid time
obs_lead: 1D array string of format HHMMSS
observation lead time
obs_valid: 1D array string of format YYYYmmdd_HHMMSS
observation valid time
mod_name: string
output model name (the MODEL column in MET)
desc: string
output description (the DESC column in MET)
fcst_var: 1D array string
forecast variable name
fcst_unit: 1D array string
forecast variable units
fcst_lev: 1D array string
forecast variable level
obs_var: 1D array string
observation variable name
obs_unit: 1D array string
observation variable units
obs_lev: 1D array string
observation variable level
maskname: string
name of the verification masking region
obsslev: 1D array string
Pressure level of the observation in hPA or accumulation
interval in hours
outdir: string
Full path including where the output data should go
outfile_prefix: string
Prefix to use for the output filename. The time stamp will
be added in MET's format based off the first forecast time


Run from a python script
=========================

* Make sure you have these required Python packages:

* Python 3.7

* metcalcpy

* numpy

* os

.. code-block:: ini

write_mpr_file(data_fcst,data_obs,lats_in,lons_in,fcst_lead,fcst_valid,obs_lead,obs_valid,mod_name,desc,fcst_var,fcst_unit,fcst_lev,obs_var,obs_unit,obs_lev,maskname,obsslev,outdir,outfile_prefix)

The output fill be a .stat file located in outdir with data in `MET's Matched Pair Format <https://met.readthedocs.io/en/latest/Users_Guide/point-stat.html#id24>`_. The file will be labeled with outfile_prefix and then have lead time, valid YYYYMMDD, and valid HHMMSS stamped onto the file name.
122 changes: 122 additions & 0 deletions metcalcpy/util/write_mpr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# ============================*
# ** Copyright UCAR (c) 2020
# ** University Corporation for Atmospheric Research (UCAR)
# ** National Center for Atmospheric Research (NCAR)
# ** Research Applications Lab (RAL)
# ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA
# ============================*
import os
import numpy as np


def write_mpr_file(data_fcst,data_obs,lats_in,lons_in,fcst_lead,fcst_valid,obs_lead,obs_valid,mod_name,desc,fcst_var,fcst_unit,fcst_lev,obs_var,obs_unit,obs_lev,maskname,obsslev,outdir,outfile_prefix):

"""
Function to write an output mpr file given a 1d array of observation and forecast data
Parameters:
----------
data_fcst: 1D array float
forecast data to write to MPR file
data_obs: 1D array float
observation data to write to MPR file
lats_in: 1D array float
data latitudes
lons_in: 1D array float
data longitudes
fcst_lead: 1D array string of format HHMMSS
forecast lead time
fcst_valid: 1D array string of format YYYYmmdd_HHMMSS
forecast valid time
obs_lead: 1D array string of format HHMMSS
observation lead time
obs_valid: 1D array string of format YYYYmmdd_HHMMSS
observation valid time
mod_name: string
output model name (the MODEL column in MET)
desc: string
output description (the DESC column in MET)
fcst_var: 1D array string
forecast variable name
fcst_unit: 1D array string
forecast variable units
fcst_lev: 1D array string
forecast variable level
obs_var: 1D array string
observation variable name
obs_unit: 1D array string
observation variable units
obs_lev: 1D array string
observation variable level
maskname: string
name of the verification masking region
obsslev: 1D array string
Pressure level of the observation in hPA or accumulation
interval in hours
outdir: string
Full path including where the output data should go
outfile_prefix: string
Prefix to use for the output filename. The time stamp will
be added in MET's format based off the first forecast time
"""

"""
Get the data length to create the INDEX and TOTAL variables in the MPR line
"""
dlength = len(data_obs)
index_num = np.arange(0,dlength,1)+1

"""
Get the length of the model, FCST_VAR, FCST_LEV, OBS_VAR, OBS_LEV, VX_MASK, etc for formatting
"""
mname_len = str(max([5,len(mod_name)])+3)
desc_len = str(max([4,len(desc)])+3)
mask_len = str(max([7,len(maskname)])+3)
fvar_len = str(max([8,max([len(l) for l in fcst_var])])+3)
funit_len = str(max([8,max([len(l) for l in fcst_unit])])+3)
flev_len = str(max([8,max([len(l) for l in fcst_lev])])+3)
ovar_len = str(max([7,max([len(l) for l in obs_var])])+3)
ounit_len = str(max([8,max([len(l) for l in obs_unit])])+3)
olev_len = str(max([7,max([len(l) for l in obs_lev])])+3)

"""
Set up format strings for the header (format_string) and data (format_string2)
"""
format_string = '%-7s %-'+mname_len+'s %-'+desc_len+'s %-12s %-18s %-18s %-12s %-17s %-17s %-'+fvar_len+'s ' \
'%-'+funit_len+'s %-'+flev_len+'s %-'+ovar_len+'s %-'+ounit_len+'s %-'+olev_len+'s %-10s %-'+mask_len+'s ' \
'%-13s %-13s %-13s %-13s %-13s %-13s %-9s\n'
format_string2 = '%-7s %-'+mname_len+'s %-'+desc_len+'s %-12s %-18s %-18s %-12s %-17s %-17s %-'+fvar_len+'s ' \
'%-'+funit_len+'s %-'+flev_len+'s %-'+ovar_len+'s %-'+ounit_len+'s %-'+olev_len+'s %-10s %-'+mask_len+'s ' \
'%-13s %-13s %-13s %-13s %-13s %-13s %-9s %-10s %-10s %-10s %-12.4f %-12.4f %-10s %-10s %-12.4f %-12.4f ' \
'%-10s %-10s %-10s %-10s\n'

"""
Create the output directory if it doesn't exist
"""
if not os.path.exists(outdir):
os.makedirs(outdir)

"""
Put the timestamp on the output file
"""
fcst_valid_str = fcst_valid[0]
ft_stamp = fcst_lead[0]+'L_'+fcst_valid_str[0:8]+'_'+fcst_valid_str[9:15]+'V'
full_outfile = os.path.join(outdir,outfile_prefix+'_'+ft_stamp+'.stat')

"""
Write the file
"""
#print('Writing output MPR file: '+full_outfile)
with open(full_outfile, 'w') as mf:
# Write the header
mf.write(format_string % ('VERSION', 'MODEL', 'DESC', 'FCST_LEAD', 'FCST_VALID_BEG', 'FCST_VALID_END',
'OBS_LEAD', 'OBS_VALID_BEG', 'OBS_VALID_END', 'FCST_VAR', 'FCST_UNITS', 'FCST_LEV', 'OBS_VAR',
'OBS_UNITS', 'OBS_LEV', 'OBTYPE', 'VX_MASK', 'INTERP_MTHD', 'INTERP_PNTS', 'FCST_THRESH',
'OBS_THRESH', 'COV_THRESH', 'ALPHA', 'LINE_TYPE'))
for dpt in range(dlength):
# Write the data
mf.write(format_string2 % ('V9.1',mod_name,desc,fcst_lead[dpt],fcst_valid[dpt],fcst_valid[dpt],
obs_lead[dpt],obs_valid[dpt],obs_valid[dpt],fcst_var[dpt],fcst_unit[dpt],fcst_lev[dpt],
obs_var[dpt],obs_unit[dpt],obs_lev[dpt],'ADPUPA',maskname,'NEAREST','1','NA','NA','NA','NA','MPR',
str(dlength),str(index_num[dpt]),'NA',lats_in[dpt],lons_in[dpt],obsslev[dpt],'NA',data_fcst[dpt],
data_obs[dpt],'NA','NA','NA','NA'))