save_metrics.R 7.55 KB
Newer Older
                         metrics,
                         dictionary = NULL,
                         outdir = NULL,
                         module = "skill") {
  # This function adds metadata to the skill metrics in 'skill'
  # and exports them to a netCDF file inside 'outdir'.
  # Define grid dimensions and names
  lalo <- c('longitude', 'latitude')
  archive <- get_archive(recipe)
  dictionary <- read_yaml("conf/variable-dictionary.yml")

  global_attributes <- .get_global_attributes(recipe, archive)
  ## TODO: Sort out the logic once default behavior is decided
  if ((!is.null(recipe$Analysis$Workflow$Anomalies$compute)) && 
      (recipe$Analysis$Workflow$Anomalies$compute)) {
    global_attributes <- c(list(from_anomalies = "Yes"),
                           global_attributes)
  } else {
    global_attributes <- c(list(from_anomalies = "No"),
                           global_attributes)
  }
  # Time indices and metadata
  fcst.horizon <- tolower(recipe$Analysis$Horizon)
  store.freq <- recipe$Analysis$Variables$freq
  if (global_attributes$system == 'Multimodel'){
    if (fcst.horizon == 'decadal'){
      calendar <- archive$System[[recipe$Analysis$Datasets$System$models[[1]]$name]]$calendar
    } else {
      calendar <- archive$System[[recipe$Analysis$Datasets$System$models[[1]]]]$calendar
    }
  } else {
    calendar <- archive$System[[global_attributes$system]]$calendar
  }

  # Generate vector containing leadtimes
  dates <- as.PCICt(ClimProjDiags::Subset(data_cube$attrs$Dates, 'syear', 1),
    # init_month <- archive$System[[recipe$Analysis$Datasets$System$name]]$initial_month
    # init_date <- as.PCICt(paste0(recipe$Analysis$Time$hcst_start, '-',
    #                              sprintf('%02d', init_month), '-01'),
    #                       cal = calendar)
    init_date <- as.PCICt(paste0(as.numeric(recipe$Analysis$Time$hcst_start)+1, 
                                 '-01-01'), cal = calendar)
  } else {
    init_date <- as.PCICt(paste0(recipe$Analysis$Time$hcst_start,
                          recipe$Analysis$Time$sdate),
                          format = '%Y%m%d', cal = calendar)
  }

  # Get time difference in hours
  leadtimes <- as.numeric(dates - init_date)/3600

  # Select start date
  # If a fcst is provided, use that as the ref. year. Otherwise use 1970.
  if (fcst.horizon == 'decadal') {
    if (!is.null(recipe$Analysis$Time$fcst_year)) {
      #PROBLEM: May be more than one fcst_year
      # fcst.sdate <- paste0(recipe$Analysis$Time$fcst_year[1],
      #                      sprintf('%02d', init_month), '01')
      fcst.sdate <- paste0(recipe$Analysis$Time$fcst_year[1])
    } else {
      fcst.sdate <- paste0("1970", sprintf('%02d', init_month), '01')
    }
  } else {
    if (!is.null(recipe$Analysis$Time$fcst_year)) {
      fcst.sdate <- paste0(recipe$Analysis$Time$fcst_year,
                           recipe$Analysis$Time$sdate)
    } else {
      fcst.sdate <- paste0("1970", recipe$Analysis$Time$sdate)
    }
  }

  times <- .get_times(store.freq, fcst.horizon, leadtimes, fcst.sdate, calendar)
  time <- times$time
  # Loop over variable dimension
  for (var in 1:data_cube$dims[['var']]) {
    # Subset skill arrays
    subset_metric <- lapply(metrics, function(x) {
                            ClimProjDiags::Subset(x, along = 'var',
                                                 indices = var,
                                                 drop = 'selected')})
    # Generate name of output file
    variable <- data_cube$attrs$Variable$varName[[var]]
    outdir <- get_dir(recipe = recipe, variable = variable)
    if (!dir.exists(outdir)) {
      dir.create(outdir, recursive = T)
    }
    if (tolower(recipe$Analysis$Output_format) == "scorecards") {
      for (i in 1:length(subset_metric)) {
        if (any('syear' %in% names(dim(subset_metric[[i]])))) {
          sdate_dim_save = 'syear'
          dates <- data_cube$attrs$Dates
        } else {
          sdate_dim_save = NULL
          dates <- Subset(data_cube$attrs$Dates, along = 'syear', indices = 1)
        }
        ## TODO: Maybe 'scorecards' condition could go here to further simplify
        ##       the code
        extra_string <- get_filename(NULL, recipe, variable,
                                     fcst.sdate, agg, names(subset_metric)[[i]])
        SaveExp(data = subset_metric[[i]], destination = outdir, 
                Dates = dates, 
                coords = c(data_cube$coords['longitude'],
                           data_cube$coords['latitude']), 
                varname = names(subset_metric)[[i]], 
                metadata = data_cube$attrs$Variable$metadata, Datasets = NULL, 
                startdates = NULL, dat_dim = NULL, sdate_dim = sdate_dim_save, 
                ftime_dim = 'time', var_dim = NULL, memb_dim = NULL,
                drop_dims = NULL, single_file = TRUE, 
                extra_string = extra_string)
      }
    } else {
      outfile <- get_filename(outdir, recipe, variable,
                              fcst.sdate, agg, module)
      # Remove singleton dimensions and rearrange lon, lat and time dims
      if (tolower(agg) == "global") {
        subset_metric <- lapply(subset_metric, function(x) {
                               Reorder(x, c(lalo, 'time'))})
      }
      attr(subset_metric[[1]], 'global_attrs') <- global_attributes
      for (i in 1:length(subset_metric)) {
        metric <- names(subset_metric[i])
        long_name <- dictionary$metrics[[metric]]$long_name
        missing_val <- -9.e+33
        subset_metric[[i]][is.na(subset_metric[[i]])] <- missing_val
        if (tolower(agg) == "country") {
          sdname <- paste0(metric, " region-aggregated metric")
          dims <- c('Country', 'time')
        } else if (tolower(agg) == "region") {
          sdname <- paste0(metric, " region-aggregated metric")
          dims <- c('region', 'time')
        } else {
          sdname <- paste0(metric)
          dims <- c(lalo, 'time')
        }
        metadata <- list(metric = list(name = metric,
                                       standard_name = sdname,
                                       long_name = long_name,
                                       missing_value = missing_val))
        attr(subset_metric[[i]], 'variables') <- metadata
        names(dim(subset_metric[[i]])) <- dims
      }
      # Get grid data and metadata and export to netCDF
      if (tolower(agg) == "country") { 
        country <- get_countries(grid)
        ArrayToNc(append(country, time, subset_metric), outfile)
      } else if (tolower(agg) == "region") {
        region <- array(1:dim(metrics[[1]])['region'], c(dim(metrics[[1]])['region']))
        # TODO: check metadata when more than 1 region is store in the data array
        metadata <- list(region = list(long_name = data_cube$attrs$Variable$metadata$region$name))
        attr(region, 'variables') <-  metadata
        vars <- list(region, time)
        vars <- c(vars, subset_metric)
        ArrayToNc(vars, outfile)
        latitude <- data_cube$coords$lat[1:length(data_cube$coords$lat)]
        longitude <- data_cube$coords$lon[1:length(data_cube$coords$lon)]
        latlon <- .get_latlon(latitude, longitude)
        # Compile variables into a list and export to netCDF
        vars <- list(latlon$lat, latlon$lon, time)
        vars <- c(vars, subset_metric)
        ArrayToNc(vars, outfile)
  info(recipe$Run$logger,
       paste("#####", toupper(module), " METRICS SAVED TO NETCDF FILE #####"))