knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(ggplot2) library(dplyr) library(purrr) library(tibble) library(ropenmeteo) library(lubridate) library(readr)
The open-meteo project combines the the best models for each location across the globe to provide the best possible forecast. open-meteo defines this as model = "generic"
.
[https://open-meteo.com/en/docs]
df <- get_forecast(latitude = 37.30, longitude = -79.83, forecast_days = 7, past_days = 2, model = "generic", variables = c("temperature_2m")) head(df)
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction)) + geom_line(color = "#F8766D") + geom_vline(aes(xintercept = reference_datetime)) + facet_wrap(~variable, scale = "free")
Ensemble forecasts from individual models are available.
[https://open-meteo.com/en/docs/ensemble-api]
df <- get_ensemble_forecast( latitude = 37.30, longitude = -79.83, forecast_days = 7, past_days = 2, model = "gfs_seamless", variables = c("temperature_2m")) head(df)
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction, color = ensemble)) + geom_line() + geom_vline(aes(xintercept = reference_datetime)) + facet_wrap(~variable, scale = "free", ncol = 2)
Options for models and variables are at https://open-meteo.com/en/docs/ensemble-api
Note that ecmwf_ifs04
does not include solar radiation.
List of global model ids:
icon_seamless, icon_global, gfs_seamless, gfs025, gfs05, ecmwf_ifs04, gem_global
We have included functions that allow the output to be used with the General Lake Model ([https://doi.org/10.5194/gmd-12-473-2019]). Since the open-meteo models do not include longwave radiation, the package provides a function to calculate it from the cloud cover and air temperature.
GLM requires a set of variables that are provided
df <- get_ensemble_forecast( latitude = 37.30, longitude = -79.83, forecast_days = 7, past_days = 2, model = "gfs_seamless", variables = glm_variables(product = "ensemble_forecast", time_step = "hourly")) head(df)
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction, color = ensemble)) + geom_line() + geom_vline(aes(xintercept = reference_datetime)) + facet_wrap(~variable, scale = "free", ncol = 2)
The following converts to GLM format
path <- tempdir() df |> add_longwave() |> write_glm_format(path = path) head(read_csv(list.files(path = path, full.names = TRUE, pattern = ".csv")[1]))
The standard used in the NEON Ecological Forecasting Challenge is slightly different from the standard in this package. It uses the column parameter
for ensemble because the Challenge standard allows the flexibility to use parametric distributions (i.e., normal distribution mean
and sd
) in the same standard as a ensemble (or sample) forecast. The family
column defines the distribution (here family
= ensemble
).
The EFI standard also follows CF-conventions so the variable names are converted to be CF compliant.
The output from convert_to_efi_standard()
is the same as the output from neon4cast::stage2()
Learn more about neon4cast::stage2()
here: [https://projects.ecoforecast.org/neon4cast-docs/Shared-Forecast-Drivers.html]
df |> add_longwave() |> convert_to_efi_standard()
Note that neon4cast::stage3()
is similar to
df |> add_longwave() |> convert_to_efi_standard() |> filter(datetime < reference_datetime)
With the only difference that the number of days is equal to the past_days
in the call to get_ensemble_forecast()
. The max past_days
from open-meteo is ~60 days.
If you need more historical days for model calibration and testing, historical data are available through open-meteo's historical weather API.
[https://open-meteo.com/en/docs/historical-weather-api]
df <- get_historical_weather( latitude = 37.30, longitude = -79.83, start_date = "2023-01-01", end_date = Sys.Date() - lubridate::days(1), variables = c("temperature_2m")) tail(df |> na.omit())
Notice the delay of ~7 days.
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction)) + geom_line(color = "#F8766D") + geom_vline(aes(xintercept = lubridate::with_tz(Sys.time(), tzone = "UTC"))) + facet_wrap(~variable, scale = "free")
Weather forecasts for up to 9 months in the future are available from the NOAA Climate Forecasting System
[https://open-meteo.com/en/docs/seasonal-forecast-api]
df <- get_seasonal_forecast( latitude = 37.30, longitude = -79.83, forecast_days = 274, past_days = 5, variables = c("temperature_2m")) head(df)
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction, color = ensemble)) + geom_line() + geom_vline(aes(xintercept = reference_datetime)) + facet_wrap(~variable, scale = "free")
The downscaling uses the GLM variables
df <- get_seasonal_forecast( latitude = 37.30, longitude = -79.83, forecast_days = 30, past_days = 5, variables = glm_variables(product = "seasonal_forecast", time_step = "6hourly"))
df |> six_hourly_to_hourly(latitude = 37.30, longitude = -79.83, use_solar_geom = TRUE) |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction, color = ensemble)) + geom_line() + geom_vline(aes(xintercept = reference_datetime)) + facet_wrap(~variable, scale = "free", ncol = 2)
Climate projections from different models are available through 2050. The output is a daily time-step.
Note the units for shortwave radiation are different for the climate projection.
[https://open-meteo.com/en/docs/climate-api]
df <- get_climate_projections( latitude = 37.30, longitude = -79.83, start_date = Sys.Date(), end_date = Sys.Date() + lubridate::years(1), model = "EC_Earth3P_HR", variables = c("temperature_2m_mean")) head(df)
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction)) + geom_line(color = "#F8766D") + facet_wrap(~variable, scale = "free")
models <- c("CMCC_CM2_VHR4","FGOALS_f3_H","HiRAM_SIT_HR","MRI_AGCM3_2_S","EC_Earth3P_HR","MPI_ESM1_2_XR","NICAM16_8S") df <- map_df(models, function(model){ get_climate_projections( latitude = 37.30, longitude = -79.83, start_date = Sys.Date(), end_date = Sys.Date() + lubridate::years(1), model = model, variables = c("temperature_2m_mean")) })
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction, color = model_id)) + geom_line() + facet_wrap(~variable, scale = "free")
The download of multiple sites uses the optional site_id
to add column that denotes the different sites.
sites <- tibble(site_id = c("fcre", "sunp"), latitude = c(37.30, 43.39), longitude = c(-79.83, -72.05)) df <- map_df(1:nrow(sites), function(i, sites){ get_climate_projections( latitude = sites$latitude[i], longitude = sites$longitude[i], site_id = sites$site_id[i], start_date = Sys.Date(), end_date = Sys.Date() + lubridate::years(1), model = "MPI_ESM1_2_XR", variables = c("temperature_2m_mean")) }, sites) head(df)
df |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction, color = site_id)) + geom_line() + facet_wrap(~variable, scale = "free")
Photosynthesis is non-linearly sensitive to shortwave radiation. Therefore, the photosynthesis response to hourly radiation is different than the response to the aggregated daily mean radiation. To address this issue, we provide a function to convert the daily sum of shortwave radiation to hourly values that uses solar geometry to impute. Additionally, the sum of precipitation is divided by 24 hours to convert to an hourly time-step. All other variables have their daily mean applied to each hour.
df <- get_climate_projections( latitude = 37.30, longitude = -79.83, start_date = Sys.Date(), end_date = Sys.Date() + lubridate::years(1), model = "EC_Earth3P_HR", variables = glm_variables(product = "climate_projection", time_step = "daily"))
df |> daily_to_hourly(latitude = 37.30, longitude = -79.83) |> mutate(variable = paste(variable, unit)) |> ggplot(aes(x = datetime, y = prediction)) + geom_line(color = "#F8766D") + facet_wrap(~variable, scale = "free", ncol = 2)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.