-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #165 from pascal-sauer/master
ncdf4-based nc writing (+ extend helper)
- Loading branch information
Showing
19 changed files
with
338 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
ValidationKey: '121045680' | ||
ValidationKey: '121449200' | ||
AcceptedWarnings: | ||
- 'Warning: package ''.*'' was built under R version' | ||
- 'Warning: namespace ''.*'' is not available and has been replaced' | ||
- is.na\(\) applied to non-\(list or vector\) of type 'closure' | ||
AcceptedNotes: unable to verify current time | ||
AutocreateReadme: yes | ||
allowLinterWarnings: no | ||
enforceVersionUpdate: no |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
#' extend | ||
#' | ||
#' Extend a magpie object to a dense grid based on the given xRange, yRange and resolution. | ||
#' This is e.g. required when writing netCDF files. Extending a sparse magpie object to a dense grid | ||
#' requires much more memory, so use with caution. | ||
#' | ||
#' @param x A magpie object | ||
#' @param xRange Range of x coordinates, in ascending order when writing to netCDF | ||
#' @param yRange Range of y coordinates, in descending order when writing to netCDF | ||
#' @param res Resolution of the data, if not provided it will be guessed | ||
#' @return An extended magpie object with the same data as x and gaps filled with NA | ||
#' @author Pascal Sauer | ||
#' @export | ||
extend <- function(x, | ||
xRange = c(-179.75, 179.75), | ||
yRange = c(89.75, -89.75), | ||
res = NULL) { | ||
stopifnot(length(xRange) == 2, length(yRange) == 2) | ||
if (is.null(res)) { | ||
res <- guessResolution(x) | ||
} | ||
coords <- expand.grid(x = seq(xRange[1], xRange[2], if (xRange[1] < xRange[2]) res else -res), | ||
y = seq(yRange[1], yRange[2], if (yRange[1] < yRange[2]) res else -res)) | ||
coords <- paste0(coords$x, "|", coords$y) | ||
coords <- gsub("\\.", "p", coords) | ||
coords <- sub("\\|", ".", coords) | ||
|
||
sparseCoords <- paste0(getItems(x, "x", full = TRUE), | ||
".", | ||
getItems(x, "y", full = TRUE)) | ||
if (!all(sparseCoords %in% coords)) { | ||
stop("The coordinates of the input object are not a subset of the extended coordinates. ", | ||
"Try changing res, xRange or yRange.") | ||
} | ||
|
||
subdims1 <- getSets(x)[grep("^d1\\.", names(getSets(x)))] | ||
notCoords <- subdims1[!subdims1 %in% c("x", "y")] | ||
|
||
dim1 <- paste0(coords, paste(rep(".NA", length(notCoords)), collapse = "")) | ||
|
||
extended <- new.magpie(dim1, getItems(x, 2), getItems(x, 3)) | ||
|
||
# dimOrder subdims x and y to where they are in x | ||
perm <- match(getSets(x), c("x", "y"))[seq_along(subdims1)] | ||
perm[is.na(perm)] <- seq_along(notCoords) + 2 | ||
extended <- dimOrder(extended, perm, dim = 1) | ||
|
||
getSets(extended) <- getSets(x) | ||
|
||
posInCoords <- match(sparseCoords, coords) | ||
|
||
# fill subdims for dim 1 other than x and y (e.g. country code) if they were set in x | ||
dimnames(extended)[[1]][posInCoords] <- getItems(x, 1) | ||
|
||
# fill extended with data from x where available | ||
extended[posInCoords, , ] <- x | ||
|
||
return(extended) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
#' guessResolution | ||
#' | ||
#' Guess the resolution of the given magpie object/coordinates by looking at the minimum | ||
#' difference between unique sorted values. Fall back to 0.5 if guess is infinite. | ||
#' | ||
#' @param x A magpie object or the coordinates of a magpie object (the result | ||
#' of \code{\link{getCoords}}) | ||
#' @return The guessed resolution of the data | ||
#' @author Jan Philipp Dietrich, Pascal Sauer | ||
#' @export | ||
guessResolution <- function(x) { | ||
if (is.magpie(x)) { | ||
xy <- getCoords(x) | ||
} else { | ||
xy <- x | ||
} | ||
.tmp <- function(x) { | ||
return(min(diff(sort(unique(x))))) | ||
} | ||
guess <- min(.tmp(xy[[1]]), .tmp(xy[[2]])) | ||
# use 0.5deg as guess if it cannot be determined otherwise as this is | ||
# the default spatial resolution in the magpie universe. | ||
if (is.infinite(guess)) guess <- 0.5 | ||
return(guess) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
#' Write a magpie object to a netCDF file | ||
#' | ||
#' @param x A magpie object | ||
#' @param filename Name of the netCDF file to write | ||
#' @param unit Unit of the data, to omit pass "" (empty string) | ||
#' @param ... For future expansion. | ||
#' @param compression Level of compression to use (1-9), NA for no compression | ||
#' @param missval The value that encodes NA in the resulting netCDF file | ||
#' @param res Resolution of the data, if not provided it will be guessed | ||
#' @param zname Name of the z dimension in the netCDF file | ||
#' @author Pascal Sauer | ||
writeNC <- function(x, filename, unit, ..., compression = 2, missval = NA, | ||
res = NULL, zname = "time") { | ||
if (!requireNamespace("ncdf4", quietly = TRUE)) { | ||
stop("The ncdf4 package is required to write netCDF files, please install it.") | ||
} | ||
# fail immediately if arguments are not set | ||
stopifnot(is.character(filename), is.character(unit)) | ||
if (!(...length() == 0 || all(...names() == "verbose"))) { | ||
stop("Unknown argument passed to writeNC: ", paste(...names(), collapse = ", ")) | ||
} | ||
|
||
# magclass objects are sparse, fill gaps with NA | ||
coords <- getCoords(x) | ||
x <- extend(x, xRange = c(min(coords$x), max(coords$x)), yRange = c(max(coords$y), min(coords$y)), res = res) | ||
coords <- getCoords(x) | ||
|
||
if (zname != "time") { | ||
message("terra will not recognize zname != 'time' as time dimension") | ||
} | ||
|
||
if (is.null(getItems(x, 3))) { | ||
getItems(x, 3) <- sub("\\.nc$", "", basename(filename)) | ||
} | ||
|
||
# create netCDF file | ||
dimVars <- list(ncdf4::ncdim_def("lon", "degrees_east", unique(coords$x)), | ||
ncdf4::ncdim_def("lat", "degrees_north", unique(coords$y))) | ||
if (!is.null(getItems(x, 2))) { | ||
dimVars <- c(dimVars, list(ncdf4::ncdim_def(zname, "years since 0", getYears(x, as.integer = TRUE), unlim = TRUE))) | ||
} | ||
vars <- lapply(getItems(x, 3), function(vname) { | ||
return(ncdf4::ncvar_def(vname, units = unit, dim = dimVars, | ||
missval = missval, compression = compression)) | ||
}) | ||
|
||
nc <- ncdf4::nc_create(filename, vars = vars) | ||
withr::defer(ncdf4::nc_close(nc)) | ||
|
||
if (!is.null(getItems(x, 2)) && zname == "time") { | ||
ncdf4::ncatt_put(nc, "time", "axis", "T") | ||
} | ||
|
||
for (vname in getItems(x, 3)) { | ||
ncdf4::ncvar_put(nc, vname, x[, , vname]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.