R/nct_create.r

#' Serializes data.frame to NetCDF file
#'
#' @author Ben Fasoli
#'
#' @param df data.frame to be written
#' @param filename character string specifying output file ending in `.nc`
#' @param dims character vector specifying at least one column as a dimension
#' @param longnames optional long names to include as dimension or variable
#'   attributes, formatted as a named list or vector where keys match column
#'   names in `df` and values specify the desired `long_name` NetCDF attribute
#' @param units optional units to include as dimension or variable attributes,
#'   using the same format as `longnames`, except POSIXct columns will override
#'   a user specified units field with "seconds since 1970-01-01T00:00:00Z" for
#'   POSIX compliance
#'
#' @import ncdf4
#' @export

nct_create <- function(df, filename, dims, longnames = NA, units = NA) {

  cols <- colnames(df)

  if (is.na(longnames[1])) {
    longnames <- cols
    names(longnames) <- cols
  }

  if (is.na(units[1])) {
    units <- rep('', times = length(cols))
    names(units) <- cols
  }

  if (file.exists(filename)) {
    unlink(filename)
  }

  if (!all(dims %in% colnames(df))) {
    stop('Dimensions not in data.frame columns.')
  }

  if (!all(colnames(df) %in% names(longnames))) {
    stop('Must provide longnames for all columns in data.frame.')
  }

  if (!all(colnames(df) %in% names(units))) {
    stop('Must provide units for all columns in data.frame.')
  }

  longnames = trimws(longnames)
  units = trimws(units)

  vars <- setdiff(cols, dims)
  metas <- lapply(df, nct_serialize)

  nc_dims <- list()
  for (dim in dims) {
    meta <- metas[[dim]]
    unit <- ifelse(is.na(meta$units), units[[dim]], meta$units)
    nc_dims[[dim]] <- ncdf4::ncdim_def(calendar = meta$calendar,
                                       longname = longnames[[dim]],
                                       name = dim,
                                       units = unit,
                                       unlim = T,
                                       vals = meta$vals)
  }

  nc_vars <- list()
  for (var in vars) {
    meta <- metas[[var]]
    unit <- ifelse(is.na(meta$units), units[[var]], meta$units)
    nc_vars[[var]] <- ncdf4::ncvar_def(compression = 9,
                                       dim = nc_dims,
                                       longname = longnames[[var]],
                                       name = var,
                                       prec = meta$prec,
                                       units = unit)
  }

  nc <- ncdf4::nc_create(filename, vars = nc_vars, force_v4 = T)

  for (var in vars) {
    meta <- metas[[var]]
    ncdf4::ncvar_put(nc = nc,
                     varid = var,
                     vals = meta$vals)
    ncdf4::ncatt_put(nc = nc,
                     varid = var,
                     attname = 'nct_type',
                     attval = meta$type,
                     prec = 'text')
  }

  for (dim in dims) {
    meta <- metas[[dim]]
    ncdf4::ncatt_put(nc = nc,
                     varid = dim,
                     attname = 'nct_type',
                     attval = meta$type,
                     prec = 'text')
  }

  ncdf4::nc_close(nc)
}
benfasoli/nctables documentation built on May 21, 2019, 11:30 a.m.