Skip to content
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
59 changes: 8 additions & 51 deletions modules/data.atmosphere/R/Ameriflux_met_ensemble.R
Original file line number Diff line number Diff line change
Expand Up @@ -178,57 +178,14 @@ AmeriFlux_met_ensemble <- function(site_id,
overwrite = overwrite
)

# ERA5 fallback
if (verbose) PEcAn.logger::logger.info("Checking data coverage for ERA5 fallback")
# check coverage of radiation variables (PAR and Rg) needed for metgapfill
nc <- ncdf4::nc_open(cf_results$file)
time_dim <- ncdf4::ncvar_get(nc, "time")
n_total <- length(time_dim)
# check shortwave radiation(Rg) coverage
has_rg <- "surface_downwelling_shortwave_flux_in_air" %in% names(nc$var)
rg_coverage <- 0
if (has_rg) {
rg_data <- ncdf4::ncvar_get(nc, "surface_downwelling_shortwave_flux_in_air")
rg_coverage <- sum(!is.na(rg_data)) / n_total
}
# check PAR coverage
has_par <- "surface_downwelling_photosynthetic_photon_flux_in_air" %in% names(nc$var)
par_coverage <- 0
if (has_par) {
par_data <- ncdf4::ncvar_get(nc, "surface_downwelling_photosynthetic_photon_flux_in_air")
par_coverage <- sum(!is.na(par_data)) / n_total
}
# check soil moisture coverage since this is not filled by metgapfill
has_swc <- "volume_fraction_of_condensed_water_in_soil" %in% names(nc$var)
swc_coverage <- 0
if (has_swc) {
swc_data <- ncdf4::ncvar_get(nc, "volume_fraction_of_condensed_water_in_soil")
swc_coverage <- sum(!is.na(swc_data)) / n_total
}
ncdf4::nc_close(nc)

if(verbose) {
PEcAn.logger::logger.info(paste("Shortwave radiation (Rg) coverage:", round(rg_coverage * 100, 1), "%"))
PEcAn.logger::logger.info(paste("PAR coverage:", round(par_coverage * 100, 1), "%"))
PEcAn.logger::logger.info(paste("Soil moisture coverage:", round(swc_coverage * 100, 1), "%"))
}

fill_vars <- c()
# if BOTH PAR and Rg have insufficient coverage
if ((!has_rg || rg_coverage < threshold) &&
(!has_par || par_coverage < threshold)) {
fill_vars <- c(fill_vars, "surface_solar_radiation_downwards")
if(verbose) {
PEcAn.logger::logger.info("Adding shortwave radiation to ERA5 fallback (insufficient PAR and Rg coverage)")
}
}
# if variable exists but has ANY missing values
if (has_swc && swc_coverage < 1.0) {
fill_vars <- c(fill_vars, "volumetric_soil_water_layer_1")
if(verbose) {
PEcAn.logger::logger.info("Adding soil moisture to ERA5 fallback (missing data detected)")
}
}
coverage_results <- check_met_coverage_for_fallback(
cf_file = cf_results$file,
threshold = threshold,
verbose = verbose
)

fill_vars <- coverage_results$fill_vars

if (length(fill_vars) > 0) {
start_year <- lubridate::year(as.Date(start_date))
end_year <- lubridate::year(as.Date(end_date))
Expand Down
80 changes: 80 additions & 0 deletions modules/data.atmosphere/R/check_met_coverage_for_fallback.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#' Check AmeriFlux CF coverage for ERA5 fallback
#'
#' Determines whether radiation and/or soil moisture require ERA5 fallback
#' based on variable presence and data coverage.
#'
#' @param cf_file character. Path to CF-compliant NetCDF file
#' @param threshold numeric. Coverage threshold (0–1) for radiation fallback
#' @param verbose logical. Emit logger messages
#'
#' @return list with:
#' \itemize{
#' \item fill_vars: ERA5 variables to request
#' \item coverage: named list of coverage fractions
#' }
#'
#' @noRd
check_met_coverage_for_fallback <- function(cf_file,
threshold = 0.5,
verbose = FALSE) {

if (verbose) {
PEcAn.logger::logger.info("Checking data coverage for ERA5 fallback")
}

nc <- ncdf4::nc_open(cf_file)
on.exit(ncdf4::nc_close(nc), add = TRUE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the on.exit -- this is a nice upgrade!!


time_vals <- ncdf4::ncvar_get(nc, "time")
n_total <- length(time_vals)

# ---- Radiation (Rg)
has_rg <- "surface_downwelling_shortwave_flux_in_air" %in% names(nc$var)
rg_coverage <- 0
if (has_rg) {
rg_data <- ncdf4::ncvar_get(nc, "surface_downwelling_shortwave_flux_in_air")
rg_coverage <- sum(!is.na(rg_data)) / n_total
}

# ---- PAR
has_par <- "surface_downwelling_photosynthetic_photon_flux_in_air" %in% names(nc$var)
par_coverage <- 0
if (has_par) {
par_data <- ncdf4::ncvar_get(nc, "surface_downwelling_photosynthetic_photon_flux_in_air")
par_coverage <- sum(!is.na(par_data)) / n_total
}

# ---- Soil moisture
has_swc <- "volume_fraction_of_condensed_water_in_soil" %in% names(nc$var)
swc_coverage <- 0
if (has_swc) {
swc_data <- ncdf4::ncvar_get(nc, "volume_fraction_of_condensed_water_in_soil")
swc_coverage <- sum(!is.na(swc_data)) / n_total
}

if (verbose) {
PEcAn.logger::logger.info(paste("Rg coverage:", round(rg_coverage * 100, 1), "%"))
PEcAn.logger::logger.info(paste("PAR coverage:", round(par_coverage * 100, 1), "%"))
PEcAn.logger::logger.info(paste("Soil moisture coverage:", round(swc_coverage * 100, 1), "%"))
}

fill_vars <- character(0)

if ((!has_rg || rg_coverage < threshold) &&
(!has_par || par_coverage < threshold)) {
fill_vars <- c(fill_vars, "surface_solar_radiation_downwards")
}

if (has_swc && swc_coverage < 1.0) {
fill_vars <- c(fill_vars, "volumetric_soil_water_layer_1")
}

list(
fill_vars = fill_vars,
coverage = list(
rg = rg_coverage,
par = par_coverage,
swc = swc_coverage
)
)
}
Loading