Copy - Paste the script below. You will need to set the dates, fcst_model, paths etc. Save it and run with source("<script_file_name.R>") or click on Source in RStudio.

library(harp)
library(purrr)

# The following variables are expected to change for each user / use case

dttm       <- seq_dttm(2018030800, 2018033100, "1d")
fcst_model <- c("REF", "SPP")
lead_time  <- seq(0, 48, 3)
fcst_type  <- "eps"
lags       <- "0s"
fcst_path  <- "/path/to/FCTABLE"
obs_path   <- "/path/to/OBSTABLE"
verif_path <- "/path/to/verif"
grps       <- "lead_time"

# Add more parameters below using the same format. For upper air parameters,
# don't forget the vc = "pressure"
params <- list(
  
  # Parameter that won't work!
  apple = list(
    thresholds = seq(5, 50, 5)
  ),
  
  T2m = list(
    thresholds = c(-20, -10, seq(-5, 25, 5)),
    scale_fcst = list(scaling = -273.15, new_units = "degC"),
    scale_obs  = list(scaling = -273.15, new_units = "degC")
  ), 
  
  S10m = list(
    thresholds = seq(0, 25, 5)
  ), 
  
  T = list(
    scale_fcst = list(scaling = -273.15, new_units = "degC"),
    scale_obs  = list(scaling = -273.15, new_units = "degC"),
    vc         = "pressure"
  )
  
)

# Function that runs the verification
run_verif <- function(prm_info, prm_name) {
  
  if (!is.null(prm_info$vc)) {
    vertical_coordinate <- prm_info$vc
  } else {
    vertical_coordinate <- NA_character_
  }
  
  # Read the forecast
  fcst <- read_point_forecast(
    dttm          = dttm,
    fcst_model    = fcst_model,
    fcst_type     = fcst_type,
    parameter     = prm_name,
    lead_time     = lead_time,
    lags          = lags,
    file_path     = fcst_path,
    vertical_coordinate = vertical_coordinate
  )
  
  # Find the common cases - for upper air parmeters we need to ensure 
  # that the level column  is included in the check
  fcst <- switch(
    vertical_coordinate,
    "pressure" = common_cases(fcst, p),
    "height"   = common_cases(fcst, z),
    common_cases(fcst)
  )
  
  # optional rescaling of forecasts using the scale_fcst part of the
  # params list. We use do.call to call the scale_point_forecast 
  # function with a named list containing the arguments. 
  if (!is.null(prm_info$scale_fcst)) {
    fcst <- do.call(
      scale_param, 
      c(list(x = fcst), prm_info$scale_fcst))
  }
  
  # Read the observations getting the dates and stations from 
  # the forecast
  obs <- read_point_obs(
    dttm       = unique_valid_dttm(fcst),
    parameter  = prm_name,
    obs_path   = obs_path,
    stations   = unique_stations(fcst),
    vertical_coordinate = vertical_coordinate
  )
  
  # optional rescaling of observations using the scale_obs part of the
  # params list. We use do.call to call the scale_point_forecast 
  # function with a named list containing the arguments.
  if (!is.null(prm_info$scale_obs)) {
    obs <- do.call(
      scale_point_obs, 
      c(list(x = obs, col = {{prm_name}}), prm_info$scale_obs)
    )
  }
  
  # Join observations to the forecast
  fcst <- join_to_fcst(fcst, obs)
  
  # Check for errors removing obs that are more than a certain number 
  # of standard deviations from the forecast. You could add a number 
  # of standard deviations to use in the params list 
  fcst <- check_obs_against_fcst(fcst, {{prm_name}})
  
  # Make sure that grps is a list so that it adds on the vertical 
  # coordinate group correctly
  if (!is.list(grps)) {
    grps <- list(grps)
  }
  
  grps <- switch(
    vertical_coordinate,
    "pressure" = map(grps, ~c(.x, "p")),
    "height"   = map(grps, ~c(.x, "z")),
    grps
  )
  
  # Do the verification
  if (fcst_type == "eps") {
    verif <- ens_verify(
      fcst, prm_name, thresholds = prm_info$thresholds, groupings = grps
    )
  } else {
    verif <- det_verify(
      fcst, prm_name, thresholds = prm_info$thresholds, groupings = grps
    )
  }
  
  # Save the scores
  save_point_verif(verif, verif_path = verif_path)
  
  # Return the data to the calling environment (normally global)
  verif
  
}

# Use possibly from the purrr package to allow the script to continue
# if it fails for a parameter - it returns NULL if it fails. See
# ?safely and ?quietly if you want to retain the errors.
possible_run_verif <- possibly(run_verif, otherwise = NULL)

# Use imap from the purrr package to map each element of the params list
# to the possible_run_verif function. imap passes the element of the list
# as the first argument and the name of the element as the second.
verif <- imap(params, possible_run_verif)

# You can open the results in a shiny app using 
# shiny_plot_point_verif(verif_path)
LS0tCnRpdGxlOiAiaGFycCBQb2ludCB2ZXJpZmljYXRpb24gc2NyaXB0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpDb3B5IC0gUGFzdGUgdGhlIHNjcmlwdCBiZWxvdy4gWW91IHdpbGwgbmVlZCB0byBzZXQgdGhlIGRhdGVzLCBmY3N0X21vZGVsLCBwYXRocyBldGMuIFNhdmUgaXQgYW5kIHJ1biB3aXRoIGBzb3VyY2UoIjxzY3JpcHRfZmlsZV9uYW1lLlI+IilgIG9yIGNsaWNrIG9uIFNvdXJjZSBpbiBSU3R1ZGlvLiAKCmBgYHtyfQpsaWJyYXJ5KGhhcnApCmxpYnJhcnkocHVycnIpCgojIFRoZSBmb2xsb3dpbmcgdmFyaWFibGVzIGFyZSBleHBlY3RlZCB0byBjaGFuZ2UgZm9yIGVhY2ggdXNlciAvIHVzZSBjYXNlCgpkdHRtICAgICAgIDwtIHNlcV9kdHRtKDIwMTgwMzA4MDAsIDIwMTgwMzMxMDAsICIxZCIpCmZjc3RfbW9kZWwgPC0gYygiUkVGIiwgIlNQUCIpCmxlYWRfdGltZSAgPC0gc2VxKDAsIDQ4LCAzKQpmY3N0X3R5cGUgIDwtICJlcHMiCmxhZ3MgICAgICAgPC0gIjBzIgpmY3N0X3BhdGggIDwtICIvcGF0aC90by9GQ1RBQkxFIgpvYnNfcGF0aCAgIDwtICIvcGF0aC90by9PQlNUQUJMRSIKdmVyaWZfcGF0aCA8LSAiL3BhdGgvdG8vdmVyaWYiCmdycHMgICAgICAgPC0gImxlYWRfdGltZSIKCiMgQWRkIG1vcmUgcGFyYW1ldGVycyBiZWxvdyB1c2luZyB0aGUgc2FtZSBmb3JtYXQuIEZvciB1cHBlciBhaXIgcGFyYW1ldGVycywKIyBkb24ndCBmb3JnZXQgdGhlIHZjID0gInByZXNzdXJlIgpwYXJhbXMgPC0gbGlzdCgKICAKICAjIFBhcmFtZXRlciB0aGF0IHdvbid0IHdvcmshCiAgYXBwbGUgPSBsaXN0KAogICAgdGhyZXNob2xkcyA9IHNlcSg1LCA1MCwgNSkKICApLAogIAogIFQybSA9IGxpc3QoCiAgICB0aHJlc2hvbGRzID0gYygtMjAsIC0xMCwgc2VxKC01LCAyNSwgNSkpLAogICAgc2NhbGVfZmNzdCA9IGxpc3Qoc2NhbGluZyA9IC0yNzMuMTUsIG5ld191bml0cyA9ICJkZWdDIiksCiAgICBzY2FsZV9vYnMgID0gbGlzdChzY2FsaW5nID0gLTI3My4xNSwgbmV3X3VuaXRzID0gImRlZ0MiKQogICksIAogIAogIFMxMG0gPSBsaXN0KAogICAgdGhyZXNob2xkcyA9IHNlcSgwLCAyNSwgNSkKICApLCAKICAKICBUID0gbGlzdCgKICAgIHNjYWxlX2Zjc3QgPSBsaXN0KHNjYWxpbmcgPSAtMjczLjE1LCBuZXdfdW5pdHMgPSAiZGVnQyIpLAogICAgc2NhbGVfb2JzICA9IGxpc3Qoc2NhbGluZyA9IC0yNzMuMTUsIG5ld191bml0cyA9ICJkZWdDIiksCiAgICB2YyAgICAgICAgID0gInByZXNzdXJlIgogICkKICAKKQoKIyBGdW5jdGlvbiB0aGF0IHJ1bnMgdGhlIHZlcmlmaWNhdGlvbgpydW5fdmVyaWYgPC0gZnVuY3Rpb24ocHJtX2luZm8sIHBybV9uYW1lKSB7CiAgCiAgaWYgKCFpcy5udWxsKHBybV9pbmZvJHZjKSkgewogICAgdmVydGljYWxfY29vcmRpbmF0ZSA8LSBwcm1faW5mbyR2YwogIH0gZWxzZSB7CiAgICB2ZXJ0aWNhbF9jb29yZGluYXRlIDwtIE5BX2NoYXJhY3Rlcl8KICB9CiAgCiAgIyBSZWFkIHRoZSBmb3JlY2FzdAogIGZjc3QgPC0gcmVhZF9wb2ludF9mb3JlY2FzdCgKICAgIGR0dG0gICAgICAgICAgPSBkdHRtLAogICAgZmNzdF9tb2RlbCAgICA9IGZjc3RfbW9kZWwsCiAgICBmY3N0X3R5cGUgICAgID0gZmNzdF90eXBlLAogICAgcGFyYW1ldGVyICAgICA9IHBybV9uYW1lLAogICAgbGVhZF90aW1lICAgICA9IGxlYWRfdGltZSwKICAgIGxhZ3MgICAgICAgICAgPSBsYWdzLAogICAgZmlsZV9wYXRoICAgICA9IGZjc3RfcGF0aCwKICAgIHZlcnRpY2FsX2Nvb3JkaW5hdGUgPSB2ZXJ0aWNhbF9jb29yZGluYXRlCiAgKQogIAogICMgRmluZCB0aGUgY29tbW9uIGNhc2VzIC0gZm9yIHVwcGVyIGFpciBwYXJtZXRlcnMgd2UgbmVlZCB0byBlbnN1cmUgCiAgIyB0aGF0IHRoZSBsZXZlbCBjb2x1bW4gIGlzIGluY2x1ZGVkIGluIHRoZSBjaGVjawogIGZjc3QgPC0gc3dpdGNoKAogICAgdmVydGljYWxfY29vcmRpbmF0ZSwKICAgICJwcmVzc3VyZSIgPSBjb21tb25fY2FzZXMoZmNzdCwgcCksCiAgICAiaGVpZ2h0IiAgID0gY29tbW9uX2Nhc2VzKGZjc3QsIHopLAogICAgY29tbW9uX2Nhc2VzKGZjc3QpCiAgKQogIAogICMgb3B0aW9uYWwgcmVzY2FsaW5nIG9mIGZvcmVjYXN0cyB1c2luZyB0aGUgc2NhbGVfZmNzdCBwYXJ0IG9mIHRoZQogICMgcGFyYW1zIGxpc3QuIFdlIHVzZSBkby5jYWxsIHRvIGNhbGwgdGhlIHNjYWxlX3BvaW50X2ZvcmVjYXN0IAogICMgZnVuY3Rpb24gd2l0aCBhIG5hbWVkIGxpc3QgY29udGFpbmluZyB0aGUgYXJndW1lbnRzLiAKICBpZiAoIWlzLm51bGwocHJtX2luZm8kc2NhbGVfZmNzdCkpIHsKICAgIGZjc3QgPC0gZG8uY2FsbCgKICAgICAgc2NhbGVfcGFyYW0sIAogICAgICBjKGxpc3QoeCA9IGZjc3QpLCBwcm1faW5mbyRzY2FsZV9mY3N0KSkKICB9CiAgCiAgIyBSZWFkIHRoZSBvYnNlcnZhdGlvbnMgZ2V0dGluZyB0aGUgZGF0ZXMgYW5kIHN0YXRpb25zIGZyb20gCiAgIyB0aGUgZm9yZWNhc3QKICBvYnMgPC0gcmVhZF9wb2ludF9vYnMoCiAgICBkdHRtICAgICAgID0gdW5pcXVlX3ZhbGlkX2R0dG0oZmNzdCksCiAgICBwYXJhbWV0ZXIgID0gcHJtX25hbWUsCiAgICBvYnNfcGF0aCAgID0gb2JzX3BhdGgsCiAgICBzdGF0aW9ucyAgID0gdW5pcXVlX3N0YXRpb25zKGZjc3QpLAogICAgdmVydGljYWxfY29vcmRpbmF0ZSA9IHZlcnRpY2FsX2Nvb3JkaW5hdGUKICApCiAgCiAgIyBvcHRpb25hbCByZXNjYWxpbmcgb2Ygb2JzZXJ2YXRpb25zIHVzaW5nIHRoZSBzY2FsZV9vYnMgcGFydCBvZiB0aGUKICAjIHBhcmFtcyBsaXN0LiBXZSB1c2UgZG8uY2FsbCB0byBjYWxsIHRoZSBzY2FsZV9wb2ludF9mb3JlY2FzdCAKICAjIGZ1bmN0aW9uIHdpdGggYSBuYW1lZCBsaXN0IGNvbnRhaW5pbmcgdGhlIGFyZ3VtZW50cy4KICBpZiAoIWlzLm51bGwocHJtX2luZm8kc2NhbGVfb2JzKSkgewogICAgb2JzIDwtIGRvLmNhbGwoCiAgICAgIHNjYWxlX3BvaW50X29icywgCiAgICAgIGMobGlzdCh4ID0gb2JzLCBjb2wgPSB7e3BybV9uYW1lfX0pLCBwcm1faW5mbyRzY2FsZV9vYnMpCiAgICApCiAgfQogIAogICMgSm9pbiBvYnNlcnZhdGlvbnMgdG8gdGhlIGZvcmVjYXN0CiAgZmNzdCA8LSBqb2luX3RvX2Zjc3QoZmNzdCwgb2JzKQogIAogICMgQ2hlY2sgZm9yIGVycm9ycyByZW1vdmluZyBvYnMgdGhhdCBhcmUgbW9yZSB0aGFuIGEgY2VydGFpbiBudW1iZXIgCiAgIyBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIGZyb20gdGhlIGZvcmVjYXN0LiBZb3UgY291bGQgYWRkIGEgbnVtYmVyIAogICMgb2Ygc3RhbmRhcmQgZGV2aWF0aW9ucyB0byB1c2UgaW4gdGhlIHBhcmFtcyBsaXN0IAogIGZjc3QgPC0gY2hlY2tfb2JzX2FnYWluc3RfZmNzdChmY3N0LCB7e3BybV9uYW1lfX0pCiAgCiAgIyBNYWtlIHN1cmUgdGhhdCBncnBzIGlzIGEgbGlzdCBzbyB0aGF0IGl0IGFkZHMgb24gdGhlIHZlcnRpY2FsIAogICMgY29vcmRpbmF0ZSBncm91cCBjb3JyZWN0bHkKICBpZiAoIWlzLmxpc3QoZ3JwcykpIHsKICAgIGdycHMgPC0gbGlzdChncnBzKQogIH0KICAKICBncnBzIDwtIHN3aXRjaCgKICAgIHZlcnRpY2FsX2Nvb3JkaW5hdGUsCiAgICAicHJlc3N1cmUiID0gbWFwKGdycHMsIH5jKC54LCAicCIpKSwKICAgICJoZWlnaHQiICAgPSBtYXAoZ3JwcywgfmMoLngsICJ6IikpLAogICAgZ3JwcwogICkKICAKICAjIERvIHRoZSB2ZXJpZmljYXRpb24KICBpZiAoZmNzdF90eXBlID09ICJlcHMiKSB7CiAgICB2ZXJpZiA8LSBlbnNfdmVyaWZ5KAogICAgICBmY3N0LCBwcm1fbmFtZSwgdGhyZXNob2xkcyA9IHBybV9pbmZvJHRocmVzaG9sZHMsIGdyb3VwaW5ncyA9IGdycHMKICAgICkKICB9IGVsc2UgewogICAgdmVyaWYgPC0gZGV0X3ZlcmlmeSgKICAgICAgZmNzdCwgcHJtX25hbWUsIHRocmVzaG9sZHMgPSBwcm1faW5mbyR0aHJlc2hvbGRzLCBncm91cGluZ3MgPSBncnBzCiAgICApCiAgfQogIAogICMgU2F2ZSB0aGUgc2NvcmVzCiAgc2F2ZV9wb2ludF92ZXJpZih2ZXJpZiwgdmVyaWZfcGF0aCA9IHZlcmlmX3BhdGgpCiAgCiAgIyBSZXR1cm4gdGhlIGRhdGEgdG8gdGhlIGNhbGxpbmcgZW52aXJvbm1lbnQgKG5vcm1hbGx5IGdsb2JhbCkKICB2ZXJpZgogIAp9CgojIFVzZSBwb3NzaWJseSBmcm9tIHRoZSBwdXJyciBwYWNrYWdlIHRvIGFsbG93IHRoZSBzY3JpcHQgdG8gY29udGludWUKIyBpZiBpdCBmYWlscyBmb3IgYSBwYXJhbWV0ZXIgLSBpdCByZXR1cm5zIE5VTEwgaWYgaXQgZmFpbHMuIFNlZQojID9zYWZlbHkgYW5kID9xdWlldGx5IGlmIHlvdSB3YW50IHRvIHJldGFpbiB0aGUgZXJyb3JzLgpwb3NzaWJsZV9ydW5fdmVyaWYgPC0gcG9zc2libHkocnVuX3ZlcmlmLCBvdGhlcndpc2UgPSBOVUxMKQoKIyBVc2UgaW1hcCBmcm9tIHRoZSBwdXJyciBwYWNrYWdlIHRvIG1hcCBlYWNoIGVsZW1lbnQgb2YgdGhlIHBhcmFtcyBsaXN0CiMgdG8gdGhlIHBvc3NpYmxlX3J1bl92ZXJpZiBmdW5jdGlvbi4gaW1hcCBwYXNzZXMgdGhlIGVsZW1lbnQgb2YgdGhlIGxpc3QKIyBhcyB0aGUgZmlyc3QgYXJndW1lbnQgYW5kIHRoZSBuYW1lIG9mIHRoZSBlbGVtZW50IGFzIHRoZSBzZWNvbmQuCnZlcmlmIDwtIGltYXAocGFyYW1zLCBwb3NzaWJsZV9ydW5fdmVyaWYpCgojIFlvdSBjYW4gb3BlbiB0aGUgcmVzdWx0cyBpbiBhIHNoaW55IGFwcCB1c2luZyAKIyBzaGlueV9wbG90X3BvaW50X3ZlcmlmKHZlcmlmX3BhdGgpCmBgYAoK