Note
Go to the end to download the full example code
GenVxMask and Point-Stat: Computing PBLH from AMDAR data using “Theta-increase” method
model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed.conf
Scientific Objective
The Planetary Boundary Layer Height (PBLH) arises from a complex interaction of lower atmosphere and surface processes, and is therefore a useful metric to evaluate models. This PointStat use case computes PBLH from AMDAR aircraft data using the “Theta-increase” method (Nielsen-Gammon et al., 2008, J. App. Met. Clim.), which computes PBLH by finding the lowest altitude in an aircraft profile that exceeds a specified increase in potential temperature from a base value. Generally this theta-increase (pt_delta) ranges from 1.0-2.5 K. The pt_delta, list of airports to process, and sounding are specified in the configuration script.
Datasets
Forecast: HRRR, RRFS (reads the “HPBL” grib2 field) Observation: AMDAR hourly 1-d netcdf files
METplus Components
This use case utilizes GenVxMask and the METplus PointStat tool to compare PBLH from AMDAR data to model output. The python embedding script “calc_amdar_pblh.py” computes PBLH and sends data MET via python embedding. The configuration file also filters output through static geographic masks generated by GenVxMask.
METplus Workflow
GenVxMask and PointStat are called in this example. The following run times are processed:
GenVxMask input file is a two-row text file (met_mask_AIRPORT.txt): row 1: AIRPORT row 2: lat lon GenVxMask output file is a netcdf file w/ geographic radius part of the file name (met_mask_AIRPORT_100km.nc) Input file provided in this example: (met_mask_DENVER.txt): row 1: DENVER row2: 39.856 -104.6764
# PointStat is run with Python embedding (calc_amdar_pblh.py).
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 with the -c option, i.e. -c parm/use_cases/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed.conf
[config]
# Documentation for this use case can be found at
# https://metplus.readthedocs.io/en/latest/generated/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed.html
# For additional information, please see the METplus Users Guide.
# https://metplus.readthedocs.io/en/latest/Users_Guide
###
# Processes to run
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#process-list
###
PROCESS_LIST = GenVxMask, PointStat
###
# Time Info
# LOOP_BY 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
# LEAD_SEQ is the list of forecast leads to process
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#timing-control
###
LOOP_BY = INIT
INIT_TIME_FMT = %Y%m%d%H
INIT_BEG = 2022070108
INIT_END = 2022070108
INIT_INCREMENT = 1H
LEAD_SEQ = 12
# USER SETTINGS HERE
# CUSTOM_LOOP_LIST = DENVER, DALLAS, BOSTON, MINNEAPOLIS [list of airports sepearated by commas; each needs a mask file]
# PY_SOUNDING_FLAG = ALL, ASC, DESC [only one value here]
# PY_PT_DELTA = Potential Temperature delta setting (K) [usually 1.0-2.5]
# Valid_Time(YYYYMMDD_HHMMSS)
GEN_VX_MASK_AIRPORT_RADIUS_KM = 100
CUSTOM_LOOP_LIST = DENVER
PY_SOUNDING_FLAG = ALL
PY_PT_DELTA = 1.25
PY_VAL_TIME = {valid?fmt=%Y%m%d_%H0000}
###
# File I/O
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#directory-and-filename-template-info
###
GEN_VX_MASK_INPUT_DIR = {INPUT_BASE}/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed
GEN_VX_MASK_INPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/pblh_22{init?fmt=%j}{init?fmt=%H}0000{lead?fmt=%HH}
GEN_VX_MASK_INPUT_MASK_DIR = {INPUT_BASE}/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed
GEN_VX_MASK_INPUT_MASK_TEMPLATE = met_mask_{custom?fmt=%s}.txt
GEN_VX_MASK_OUTPUT_DIR = {INPUT_BASE}/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed
GEN_VX_MASK_OUTPUT_TEMPLATE = {OUTPUT_BASE}/gen_vx_mask_pblh/met_mask_{custom?fmt=%s}_{GEN_VX_MASK_AIRPORT_RADIUS_KM}km.nc
FCST_POINT_STAT_INPUT_DIR = {INPUT_BASE}/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed
FCST_POINT_STAT_INPUT_TEMPLATE = {init?fmt=%Y%m%d%H}/pblh_22{init?fmt=%j}{init?fmt=%H}0000{lead?fmt=%HH}
OBS_POINT_STAT_INPUT_DIR =
OBS_POINT_STAT_INPUT_TEMPLATE = PYTHON_NUMPY= {PARM_BASE}/use_cases/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed/calc_amdar_pblh.py {INPUT_BASE}/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed/22{valid?fmt=%j}{valid?fmt=%H}00q.cdf
POINT_STAT_OUTPUT_DIR = {OUTPUT_BASE}/point_stat_pblh
POINT_STAT_OUTPUT_TEMPLATE = {valid?fmt=%Y%m%d}
POINT_STAT_CLIMO_MEAN_INPUT_DIR =
POINT_STAT_CLIMO_MEAN_INPUT_TEMPLATE =
POINT_STAT_CLIMO_STDEV_INPUT_DIR =
POINT_STAT_CLIMO_STDEV_INPUT_TEMPLATE =
###
# Field Info
# https://metplus.readthedocs.io/en/latest/Users_Guide/systemconfiguration.html#field-info
###
POINT_STAT_ONCE_PER_FIELD = False
FCST_VAR1_NAME = HPBL
FCST_VAR1_LEVELS = L0
FCST_VAR1_THRESH = <=0, >10000
OBS_VAR1_NAME = HPBL
OBS_VAR1_LEVELS = L0
OBS_VAR1_THRESH = <=0, >10000
OBS_VAR1_OPTIONS = set_attr_units = "m"
###
# GenVxMask Settings
# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#genvxmask
###
GEN_VX_MASK_SKIP_IF_OUTPUT_EXISTS = True
GEN_VX_MASK_OPTIONS = -type "circle" -thresh le{GEN_VX_MASK_AIRPORT_RADIUS_KM}
# PointStat Settings
# https://metplus.readthedocs.io/en/latest/Users_Guide/wrappers.html#pointstat
###
LOG_POINT_STAT_VERBOSITY = 4
POINT_STAT_CONFIG_FILE ={PARM_BASE}/met_config/PointStatConfig_wrapped
POINT_STAT_CLIMO_MEAN_TIME_INTERP_METHOD = NEAREST
POINT_STAT_INTERP_TYPE_METHOD = BILIN
POINT_STAT_INTERP_TYPE_WIDTH = 2
POINT_STAT_OUTPUT_FLAG_SL1L2 = STAT
POINT_STAT_OUTPUT_FLAG_VL1L2 = STAT
POINT_STAT_OUTPUT_FLAG_MPR = STAT
OBS_POINT_STAT_WINDOW_BEGIN = -3600
OBS_POINT_STAT_WINDOW_END = 3600
POINT_STAT_OFFSETS = 0
MODEL = HRRR
POINT_STAT_DESC = {PY_SOUNDING_FLAG}_{PY_PT_DELTA}
OBTYPE =
POINT_STAT_REGRID_TO_GRID = NONE
POINT_STAT_REGRID_METHOD = BILIN
POINT_STAT_REGRID_WIDTH = 2
POINT_STAT_OUTPUT_PREFIX = {custom?fmt=%s}_{PY_SOUNDING_FLAG}_{PY_PT_DELTA}
POINT_STAT_MASK_GRID =
POINT_STAT_MASK_POLY = {OUTPUT_BASE}/gen_vx_mask_pblh/met_mask_{custom?fmt=%s}_{GEN_VX_MASK_AIRPORT_RADIUS_KM}km.nc
POINT_STAT_MASK_SID =
POINT_STAT_MESSAGE_TYPE = ADPSFC
# INFO TO PASS TO PYTHON SCRIPT
[user_env_vars]
AIRPORT = {custom?fmt=%s}
SOUNDING_FLAG = {PY_SOUNDING_FLAG}
PT_DELTA = {PY_PT_DELTA}
VAL_TIME = {PY_VAL_TIME}
MET Configuration
METplus sets environment variables based on user settings in the METplus configuration file. See How METplus controls MET config file settings for more details.
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 currently not supported by METplus you’d like to control, please refer to: Overriding Unsupported MET config file settings
Note
See the PointStat MET Configuration section of the User’s Guide for more information on the environment variables used in the file below:
////////////////////////////////////////////////////////////////////////////////
//
// Point-Stat configuration file.
//
// For additional information, see the MET_BASE/config/README file.
//
////////////////////////////////////////////////////////////////////////////////
//
// Output model name to be written
//
// model =
${METPLUS_MODEL}
//
// Output description to be written
// May be set separately in each "obs.field" entry
//
// desc =
${METPLUS_DESC}
////////////////////////////////////////////////////////////////////////////////
//
// Verification grid
//
// regrid = {
${METPLUS_REGRID_DICT}
////////////////////////////////////////////////////////////////////////////////
//
// May be set separately in each "field" entry
//
censor_thresh = [];
censor_val = [];
cat_thresh = [ NA ];
cnt_thresh = [ NA ];
cnt_logic = UNION;
wind_thresh = [ NA ];
wind_logic = UNION;
eclv_points = 0.05;
//hss_ec_value =
${METPLUS_HSS_EC_VALUE}
rank_corr_flag = FALSE;
//
// Forecast and observation fields to be verified
//
fcst = {
${METPLUS_FCST_FILE_TYPE}
//field = [
${METPLUS_FCST_FIELD}
}
obs = {
${METPLUS_OBS_FILE_TYPE}
//field = [
${METPLUS_OBS_FIELD}
}
////////////////////////////////////////////////////////////////////////////////
//
// Point observation filtering options
// May be set separately in each "obs.field" entry
//
// message_type =
${METPLUS_MESSAGE_TYPE}
sid_exc = [];
//obs_quality_inc =
${METPLUS_OBS_QUALITY_INC}
//obs_quality_exc =
${METPLUS_OBS_QUALITY_EXC}
//duplicate_flag =
${METPLUS_DUPLICATE_FLAG}
//obs_summary =
${METPLUS_OBS_SUMMARY}
//obs_perc_value =
${METPLUS_OBS_PERC_VALUE}
//
// Mapping of message type group name to comma-separated list of values.
//
//message_type_group_map =
${METPLUS_MESSAGE_TYPE_GROUP_MAP}
////////////////////////////////////////////////////////////////////////////////
//
// Climatology data
//
//climo_mean = {
${METPLUS_CLIMO_MEAN_DICT}
//climo_stdev = {
${METPLUS_CLIMO_STDEV_DICT}
//
// May be set separately in each "obs.field" entry
//
//climo_cdf = {
${METPLUS_CLIMO_CDF_DICT}
////////////////////////////////////////////////////////////////////////////////
//
// Land/Sea mask
// For LANDSF message types, only use forecast grid points where land = TRUE.
// For WATERSF message types, only use forecast grid points where land = FALSE.
// land_mask.flag may be set separately in each "obs.field" entry.
//
//land_mask = {
${METPLUS_LAND_MASK_DICT}
//
// Topography
// For SURFACE message types, only use observations where the topo - station
// elevation difference meets the use_obs_thresh threshold.
// For the observations kept, when interpolating forecast data to the
// observation location, only use forecast grid points where the topo - station
// difference meets the interp_fcst_thresh threshold.
// topo_mask.flag may be set separately in each "obs.field" entry.
//
//topo_mask = {
${METPLUS_TOPO_MASK_DICT}
////////////////////////////////////////////////////////////////////////////////
//
// Point observation time window
//
// obs_window = {
${METPLUS_OBS_WINDOW_DICT}
////////////////////////////////////////////////////////////////////////////////
//
// Verification masking regions
//
//mask = {
${METPLUS_MASK_DICT}
////////////////////////////////////////////////////////////////////////////////
//
// Confidence interval settings
//
ci_alpha = [ 0.05 ];
boot = {
interval = PCTILE;
rep_prop = 1.0;
n_rep = 0;
rng = "mt19937";
seed = "";
}
////////////////////////////////////////////////////////////////////////////////
//
// Interpolation methods
//
//interp = {
${METPLUS_INTERP_DICT}
////////////////////////////////////////////////////////////////////////////////
//
// HiRA verification method
//
//hira = {
${METPLUS_HIRA_DICT}
////////////////////////////////////////////////////////////////////////////////
// Threshold for SEEPS p1 (Probability of being dry)
//seeps_p1_thresh =
${METPLUS_SEEPS_P1_THRESH}
////////////////////////////////////////////////////////////////////////////////
//
// Statistical output types
//
//output_flag = {
${METPLUS_OUTPUT_FLAG_DICT}
////////////////////////////////////////////////////////////////////////////////
//ugrid_dataset =
${METPLUS_UGRID_DATASET}
//ugrid_max_distance_km =
${METPLUS_UGRID_MAX_DISTANCE_KM}
//ugrid_coordinates_file =
${METPLUS_UGRID_COORDINATES_FILE}
////////////////////////////////////////////////////////////////////////////////
tmp_dir = "${MET_TMP_DIR}";
// output_prefix =
${METPLUS_OUTPUT_PREFIX}
//version = "V10.0.0";
////////////////////////////////////////////////////////////////////////////////
${METPLUS_MET_CONFIG_OVERRIDES}
Python Embedding
This use case uses a Python embedding script to read input data
parm/use_cases/model_applications/pbl/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed/calc_amdar_pblh.py
'''
This script reads AMDAR hourly netcdf files, computes PBLH, and sends 11-column ascii table to MET for point-stat
See accompanying PointStat_python_embedding_obs_amdar_pblh.conf for settings and passing in env variables here
Jason M. English, May 2023
'''
import os
import sys
import pandas as pd
import numpy as np
import netCDF4 as nc
# silence this annoying warning about numpy bool being deprecated in favor of python bool
from warnings import filterwarnings
filterwarnings(action='ignore', category=DeprecationWarning, message='`np.bool` is a deprecated alias')
########################################################################
print("Python Script:\t" + repr(sys.argv[0]))
##
## input file specified on the command line
## load the data into the numpy array
##
loc_name = os.environ.get('AIRPORT') # "DENVER", "DALLAS", "BOSTON", "MINNEAPOLIS" # airport, not city
sf_include = os.environ.get('SOUNDING_FLAG') # what sounding flags to include: ASC or DESC
pt_delta = float(os.environ.get('PT_DELTA')) #1.25 # potential temperature delta that triggers PBLH calculation (K)
val_time = os.environ.get('VAL_TIME') # valid time for this call (nearest hour)
rbox = 2.0 # +/- deg; set bigger than you need so MET mask can cut from that later
alt_base = 200. # highest altitude where the alt min is looked for to get base potential temperature
gap_max = 400. # maximum allowable altitude gap (m) between the computed PBLH and the altitude of the data point below it (gap_max + pblh/20)
alt_dp = 4 # minimum number of data points for the flight to be considered
alt_adj = "yes" # adjust minimum altitude to be >= 0 yes or no
out_rej = 2 # number of sigmas to trigger outlier reject
if loc_name == "DENVER":
gnd0 = 5300.*0.3048 # surface elevation at location (msl); DIA is at 5430ft but up to 300 feet lower than that within 500m of the airport
lat0 = 39.856
lon0 = -104.6764
elif loc_name == "DALLAS":
gnd0 = 550.*0.3048
lat0 = 32.8998
lon0 = -97.0403
elif loc_name == "MINNEAPOLIS":
gnd0 = 840.*0.3048
lat0 = 44.8848
lon0 = -93.2223
elif loc_name == "BOSTON":
gnd0 = 20.*0.3048
lat0 = 42.3656
lon0 = -71.0096
# convert tail number array to readable character string
def get_tn(tn):
tnc = tn.astype(str) # convert to character string
tnc = np.char.array(tnc) # removes whitespace and allows vectorized string operations
tnc_splice = tnc[:,0]+tnc[:,1]+tnc[:,2]+tnc[:,3]+tnc[:,4]+tnc[:,5]+tnc[:,6]+tnc[:,7]+tnc[:,8] # tail number spliced into a single string
return tnc_splice
if len(sys.argv) != 2:
print("ERROR: calc_amdar_pblh.py -> Must specify exactly one input file.")
sys.exit(1)
# Read the input file as the first argument
input_file = os.path.expandvars(sys.argv[1])
try:
print("Input File:\t" + repr(input_file))
ncf = nc.Dataset(input_file)
tn = ncf['tailNumber'][:]
sf = ncf['sounding_flag'][:] # -1=descent, 0=cruising, 1=ascent
t = ncf['temperature'][:]
alt = ncf['altitude'][:] - gnd0 # subtract surface height to get AGL
lat = ncf['latitude'][:]
lon = ncf['longitude'][:]
ncf.close()
# set to NaN if cruising flight (not ascent or descent)
t = np.where(sf == 0, np.nan, t)
if sf_include == "ASC":
t = np.where(sf == -1, np.nan, t) # discard descents
if sf_include == "DESC":
t = np.where(sf == 1, np.nan, t) # discard ascents
# set to NaN if outside alt, lat/lon bounds
t = np.where((lat > lat0-rbox) & (lat < lat0+rbox) & (lon > lon0-rbox ) & (lon < lon0+rbox), t, np.nan)
# convert tail number array to readable character string
tns = get_tn(tn)
# set tail number array to NaN wherever temperature array is NaN
tns = np.where(np.isnan(t), np.nan, tns)
# get unique tail numbers within the specified lat/lon range
tn_list = np.unique(tns)
nflight = tn_list.size
# Create arrays for saving PBLH and other fields for each flight
pblh = np.full([nflight],np.nan)
pblh_o = np.full([nflight],np.nan) #pblh interpolated with outliers excluded
pt_min = np.full([nflight],np.nan) # potential temperature minimum
lat_avg = np.full([nflight],np.nan)
lon_avg = np.full([nflight],np.nan)
for i,tn_name in enumerate(tn_list): #loop through tail numbers
if tn_name != "nan":
tn_arr = np.where(tns == tn_name, tns, 'null') # set array to null if it doesn't this tail number
tn_ind = np.where(tns == tn_arr) # get list of indices
# take the elements from each array ing only this flight (via the specified indices)
tn_i = np.squeeze(np.take(tn_arr, tn_ind))
sf_i = np.squeeze(np.take(sf, tn_ind))
t_i = np.squeeze(np.take(t, tn_ind))
alt_i = np.squeeze(np.take(alt, tn_ind))
lat_i = np.squeeze(np.take(lat, tn_ind))
lon_i = np.squeeze(np.take(lon, tn_ind))
# only include ascents/descents that have enough altitude/temperature data
if (np.amin(alt_i) < alt_base) & (np.amax(alt_i) > alt_base) & (alt_i.size >= alt_dp):
# sort altitude and temperature arrays to be ascending
sort_inds = np.argsort(alt_i)
t_d = np.copy(t_i[sort_inds])
alt_d = np.copy(alt_i[sort_inds])
lat_d = np.copy(lat_i[sort_inds])
lon_d = np.copy(lon_i[sort_inds])
# adjust altitude minimum to zero if it's negative
if alt_adj == "yes":
if np.nanmin(alt_d) < 0:
alt_d[:] = alt_d[:] - np.nanmin(alt_d)
# convert altitude to pressure
slp = 101325. # Sea level pressure (Pa)
expon = (-9.80665 *0.0289644) / (8.31432 * -0.0065)
p_d = slp * (1. - (alt_d + gnd0)/44307.694)**expon # needs to be pressure altitude (add ground ht)
# convert temperature to potential temperature
pt_d = np.copy(t_d)
pt_d[:] = t_d[:] * (slp/p_d[:])**0.286
# Find minimum potential temperature that occurs below the specified altitude alt_base
pt_min[i] = np.nanmin(np.where(alt_d < alt_base, pt_d, np.nan))
pt_min_ind = np.where(pt_d == pt_min[i])[0][0] # find array indexing that value
# Only move forward if minimum PT is within a reasonable range
if (pt_min[i] > 0) & (pt_min[i] < 3040):
# consider only potential temperature values above where pt_min was found when searching for pblh
alt_d[:pt_min_ind] = np.nan
pt_d[:pt_min_ind] = np.nan
pt_dif = np.copy(pt_d)
pt_dif[:] = pt_d[:] - pt_min[i]
# determine lowest height that exceeds the specified pt_delta (K)
if np.nanmax(pt_d) >= (pt_min[i]+pt_delta): # make sure it exists in this profile
pblh_alt = np.nanmin(np.where(pt_d >= (pt_min[i]+pt_delta),alt_d, np.nan))
pblh_ind = np.where(alt_d == pblh_alt)[0][0] # altitude index where pblh is found
# only include pblh if the altitude below it isn't too big of a gap
if pblh_ind.size == 1: # make sure only 1 index was found
alt_gap = alt_d[pblh_ind]-alt_d[pblh_ind-1]
if alt_gap < (gap_max + alt_d[pblh_ind]/20.):
pblh[i] = alt_d[pblh_ind]
# linear interpolate PBLH between this data point and the one below it
pblh[i] = np.interp((pt_min[i]+pt_delta), pt_d[pblh_ind-1:pblh_ind+1], alt_d[pblh_ind-1:pblh_ind+1])
# compute lat/lon for this flight by taking the avg lat/lon coordiantes over the flight
lat_avg[i] = np.average(lat_i)
lon_avg[i] = np.average(lon_i)
print("tn=", tn_i[0], ", sf=", sf_include, ", n=", pt_d.size, ", pt_min (K)=", np.array2string(pt_min[i]),
", pblh interp (m)=", np.array2string(pblh[i]), ", pblh closest (m)=", np.array2string(pblh[i]))
########################################################################
# Now that all flights at this hour have been computed, conduct statistics and averaging on them
if np.count_nonzero(~np.isnan(pblh)) > 0:
pblh_o[:] = np.where((pblh >= np.nanmean(pblh)-float(out_rej)*np.nanstd(pblh)) &
(pblh <= np.nanmean(pblh)+float(out_rej)*np.nanstd(pblh)), pblh, np.nan)
# only include flights with a computed PBLH value
lat_avg[np.isnan(pblh_o)] = np.nan
lon_avg[np.isnan(pblh_o)] = np.nan
pblh_o = pblh_o[~np.isnan(pblh_o)]
lat_avg= lat_avg[~np.isnan(lat_avg)]
lon_avg= lon_avg[~np.isnan(lon_avg)]
# Read and format the input 11-column observations:
# (1) string: Message_Type ('ADPSFC')
# (2) string: Station_ID (AIRPORT)
# (3) string: Valid_Time(YYYYMMDD_HHMMSS)
# (4) numeric: Lat(Deg North)
# (5) numeric: Lon(Deg East)
# (6) numeric: Elevation(msl)
# (7) string: Var_Name(or GRIB_Code)
# (8) numeric: Level
# (9) numeric: Height(msl or agl)
# (10) string: QC_String
# (11) numeric: Observation_Value
point_data = pd.DataFrame({'typ':'ADPSFC', 'sid':loc_name, 'vld':val_time,
'lat':lat_avg, 'lon':lon_avg, 'elv':gnd0, 'var':'HPBL',
'lvl':0, 'hgt':0, 'qc':'AMDAR', 'obs':pblh_o}).values.tolist()
print(point_data)
print(" point_data: Data Length:\t" + repr(len(point_data)))
print(" point_data: Data Type:\t" + repr(type(point_data)))
except NameError:
print("Can't find the input file")
sys.exit(1)
Running METplus
It is recommended to run this use case by:
Passing in PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed.conf then a user-specific system configuration file:
run_metplus.py -c /path/to/PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed.conf -c /path/to/user_system.conf
The following METplus configuration variables must be set correctly to run this example.:
INPUT_BASE - Path to directory where sample data tarballs are unpacked (See Datasets section to obtain tarballs).
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
NOTE: All of these items must be found under the [dir] section.
Expected Output
A successful run will output the following both to the screen and to the logfile:
INFO: METplus has successfully finished running.
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 point_stat_pblh (relative to OUTPUT_BASE) with subdirectories for valid time (YYYYMMDD) and will contain .stat files with the following naming convention:
- convention: point_stat_{AIRPORT}_{SOUNDING_FLAG}_{PT_DELTA}_{LEADTIME}L_{VALIDTIME}.stat
example: point_stat_DENVER_ALL_1.25_120000L_20220701_200000V.stat
Keywords
Note
GenVxMaskToolUseCase
PointStatToolUseCase
PythonEmbeddingFileUseCase
PBLAppUseCase
Navigate to the METplus Quick Search for Use Cases page to discover other similar use cases.
sphinx_gallery_thumbnail_path = ‘_static/pbl-PointStat_fcstHRRR_obsAMDAR_PBLH_PyEmbed.png’
Total running time of the script: (0 minutes 0.000 seconds)