# !!! rename? slice_share -> share
# all_slice -> ???
# all_parent_child -> ???
# levels -> table?
#
#' @export
setClass("slice",
representation(
levels = "data.frame",
slice_share = "data.frame", # ANNUAL, WINTER, WINTER_DAY, ..., with share
parent_child = "data.frame", # parent-child mapping
all_parent_child = "data.frame", # All levels of parents and children
slice_map = "list", # Slices set by level
default_slice_level = "character", # Default slice map
all_slice = "character",
misc = "list"
),
prototype(
levels = data.frame(stringsAsFactors = FALSE),
slice_share = data.frame(
slice = character(),
share = numeric(),
stringsAsFactors = FALSE
),
parent_child = data.frame(
parent = character(),
child = character(),
stringsAsFactors = FALSE
),
all_parent_child = data.frame(
parent = character(),
child = character(),
stringsAsFactors = FALSE
),
slice_map = list(), # Slices set by level
default_slice_level = character(), # Default slice map
all_slice = character(),
misc = list()
),
S3methods = TRUE
)
.init_slice <- function(sl) {
browser()
if (nrow(sl@levels) == 0) {
warning('no slices info, using default: "ANNUAL"')
sl@levels <- .setSlice(ANNUAL = "ANNUAL")
}
# Check for correctness of data frame
.slice_check_data(sl@levels)
sl@misc <- list()
# Calculate other data
dtf <- sl@levels
# deep level slice
sl@misc$deep <- (2:ncol(dtf) - 1)
names(sl@misc$deep) <- colnames(dtf)[-ncol(dtf)]
# count level slice
sl@misc$nlevel <- sapply(dtf[, -ncol(dtf), drop = FALSE],
function(x) length(unique(x)))
names(sl@misc$nlevel) <- colnames(dtf)[-ncol(dtf)]
sl@slice_share[1:sum(sapply(seq(along = sl@misc$nlevel),
function(x) prod(sl@misc$nlevel[1:x]))), ] <- NA
#
sl@slice_share[1, "slice"] <- dtf[1, 1]
sl@slice_share[1, "share"] <- 1
k <- 1
if (ncol(dtf) > 2) {
for (i in 2:(ncol(dtf) - 1)) {
tmp <- apply(dtf[, 2:i, drop = FALSE], 1, paste, collapse = "_")
tmp <- tapply(dtf[, ncol(dtf)], tmp, sum)
sl@slice_share[k + seq(along = tmp), "slice"] <- names(tmp)
sl@slice_share[k + seq(along = tmp), "share"] <- tmp
k <- (k + length(tmp))
}
}
# slice_map & all_slice
tmp <- nchar(sl@slice_share$slice) -
nchar(gsub("[_]", "", sl@slice_share$slice)) + 2
names(tmp) <- sl@slice_share$slice
tmp[sl@levels[1, 1]] <- 1
sl@slice_map <- lapply(1:(ncol(sl@levels) - 1),
function(x) names(tmp)[tmp == x])
names(sl@slice_map) <- colnames(sl@levels)[-ncol(sl@levels)]
sl@default_slice_level <- colnames(sl@levels)[ncol(sl@levels) - 1]
sl@all_slice <- sl@slice_share$slice
# parent_child
if (nrow(sl@levels) == 1) {
sl@parent_child <- sl@parent_child[0, , drop = FALSE]
sl@all_parent_child <- sl@all_parent_child[0, , drop = FALSE]
} else {
sl@parent_child <- sl@parent_child[0, ]
# sl@parent_child$lev <- numeric()
sl@parent_child[1:(nrow(sl@slice_share) - 1), ] <- NA
i <- 1
k <- 0
z <- 1
while (i != ncol(dtf) - 1) {
l <- sl@misc$nlevel[i + 1]
for (j in 1:sl@misc$nlevel[i]) {
sl@parent_child[k + 1:l, "parent"] <- sl@slice_share[z, "slice"]
sl@parent_child[k + 1:l, "child"] <- sl@slice_share[1 + k + 1:l, "slice"]
# sl@parent_child[k + 1:l, 'lev'] <- i + 1
k <- k + l
z <- z + 1
}
i <- i + 1
}
# all parent child realtion fill
tmp <- sl@parent_child
tmp$nlev <- NA
for (i in seq_along(sl@slice_map)) {
tmp[tmp$parent %in% sl@slice_map[[i]], "nlev"] <- i
}
ll <- tmp[tmp$nlev + 1 == length(sl@slice_map), -3]
for (i in rev(seq_along(sl@slice_map))[-(1:2)]) {
gg <- tmp[tmp$nlev == i, -3]
g3 <- gg
colnames(gg)[2] <- "sht"
l2 <- ll
colnames(l2)[1] <- "sht"
g2 <- merge(gg, l2)
g2$sht <- NULL
ll <- rbind(ll, g2, g3)
}
sl@all_parent_child <- ll
}
# next_slice <- list()
sl@misc$next_slice <- NULL
if (nrow(sl@levels) != 1) {
tmp <- sl@parent_child
tmp$next_slice <- NA
j <- 1
for (i in 1:(nrow(tmp) - 1)) {
if (tmp[i, "parent"] == tmp[i + 1, "parent"]) {
tmp[i, "next_slice"] <- tmp[i + 1, "child"]
} else {
tmp[i, "next_slice"] <- tmp[j, "child"]
j <- i + 1
}
}
tmp[i + 1, "next_slice"] <- tmp[j, "child"]
sl@misc$next_slice <- data.frame(slice = tmp$child, slicep = tmp$next_slice,
stringsAsFactors = FALSE)
n1 <- c(lapply(sl@slice_map[-1], function(x) x), recursive = TRUE)
names(n1) <- NULL
n2 <- c(lapply(sl@slice_map[-1], function(x) c(x[-1], x[1])), recursive = TRUE)
names(n2) <- NULL
sl@misc$fyear_next_slice <- data.frame(slice = n1, slicep = n2,
stringsAsFactors = FALSE)
}
sl
}
.slice_check_data <- function(dtf) {
if (ncol(dtf) < 2) {
stop(".setTimeSlices: time-slices data.frame should have more than two columns")
}
if (colnames(dtf)[ncol(dtf)] != "share") {
stop(
".setTimeSlices: the name of the last column of time-slices data.frame",
" should be 'share'"
)
}
rcs <- colnames(dtf)[-ncol(dtf)]
if (anyDuplicated(rcs)) {
stop(paste('.setTimeSlices: duplicated slice levels: "',
paste(unique(rcs[duplicated(rcs)]), collapse = '", "'), '"',
sep = ""
))
}
fl <- apply(dtf[, -c(1, ncol(dtf)), drop = FALSE], 2, function(x) length(unique(x)) == 1)
if (any(fl)) {
stop(paste('.setTimeSlices: all slice levels except "ANNUAL", should have more than one elements, check: "',
paste(colnames(dtf)[c(FALSE, fl, FALSE)], collapse = '", "'), '"',
sep = ""
))
}
if (length(unique(dtf[, 1])) != 1) {
stop(".setTimeSlices: first slice should have only one 'ANNUAL' element")
}
rcs <- c(apply(dtf[, -ncol(dtf), drop = FALSE], 2, function(x) unique(x)), recursive = TRUE)
if (anyDuplicated(rcs)) {
stop(paste('.setTimeSlices: duplicated slice names in levels: "',
paste(unique(rcs[duplicated(rcs)]), collapse = '", "'), '"',
sep = ""
))
}
# Check
if (round(sum(dtf$share), 5) != 1) {
stop(".setTimeSlices: Sum of slice shares should be equal to one, check: ", sum(dtf$share))
}
ll <- apply(dtf[, -ncol(dtf), drop = FALSE], 1, paste, collapse = ".")
if (anyDuplicated(ll)) {
stop(paste('.setTimeSlices: duplicated sets in time-slices. ("',
paste(ll[duplicated(ll)], collapse = '", "'), '").',
sep = ""
))
}
if (length(ll) != prod(sapply(dtf[, -ncol(dtf), drop = FALSE], function(x) length(unique(x))))) {
dtf2 <- unique(dtf[, 1])
for (i in seq(length = ncol(dtf) - 2) + 1) {
ln <- length(unique(dtf[, i]))
dtf2 <- paste(c(t(matrix(dtf2, length(dtf2), ln))), ".", unique(dtf[, i]),
sep = ""
)
}
stop(paste('.setTimeSlices: (empty?) time-slices. ("',
paste(dtf2[!(dtf2 %in% ll)], collapse = '", "'), '").',
sep = ""
))
}
}
# set Slice name vectors
.setTimeSlices <- function(slice = NULL, ...) {
# browser()
if (!is.null(slice) && length(list(...))) {
stop('setTimeSlices: only one argument could be used: "slice" or "..."')
}
if (!is.null(slice)) {
arg <- slice
} else {
arg <- list(...)
}
rcs <- names(arg)
if (anyDuplicated(rcs)) {
stop(paste('.setTimeSlices: duplicated slice levels: "',
paste(unique(rcs[duplicated(rcs)]), collapse = '", "'), '"',
sep = ""
))
}
# check_colnames <- function(dtf, nm) {
# if (any(colnames(dtf) == nm) ||
# any(grep("^[!A-z]", nm)) ||
# any(gsub("[[:alnum:]]*", nm))) {
# stop(paste('Unexpected slice level names "', nm, '"', sep = ""))
# }
# }
check_slice <- function(nm) {
if (any(grep("^[A-z]", nm, invert = TRUE)) ||
any(gsub("[[:alnum:]]*", "", nm) != "") ||
anyDuplicated(nm)) {
n1 <- unique(c(grep("^[A-z]", nm, invert = TRUE, value = TRUE),
nm[(gsub("[[:alnum:]]*", "", nm) != "")]))
ms1 <- NULL
ms2 <- NULL
if (length(n1) != 0) {
ms1 <- paste('Check slice names "',
paste(n1, collapse = '", "'), '". ',
sep = "")
}
n2 <- unique(nm[duplicated(nm)])
if (length(n2) != 0) {
ms2 <- paste('Check slice names "',
paste(n2, collapse = '", "'), '"',
sep = "")
}
ms <- paste(ms1, ms2, sep = "")
stop(ms)
}
}
# Check full of slice sample
# check_full_slice <- function(dtf) {
# stop("check_full_slice")
# }
slice_def <- function(dtf, arg) {
# browser()
if (is.null(names(arg)) || any(names(arg) == "")) {
stop(paste(".setTimeSlices: Unnamed arguments: ",
paste(capture.output(print(arg)), collapse = "\n"),
sep = "\n"
))
}
add_val <- function(dtf, val_sh, val_nm) {
dtf0 <- dtf
dtf <- dtf[0, , drop = FALSE]
dtf[, lv] <- character()
if (nrow(dtf0) != 0) {
dtf[1:(nrow(dtf0) * length(val_sh)), ] <- NA
for (i in 2:ncol(dtf0)) dtf[, i] <- dtf0[, i]
dtf[, lv] <- c(t(matrix(val_nm, length(val_sh), nrow(dtf0))))
dtf[, "share"] <- dtf0[, "share"] * c(t(matrix(val_sh,
length(val_sh),
nrow(dtf0))))
} else {
dtf[1:length(val_sh), ] <- NA
dtf[, lv] <- val_nm
dtf[, "share"] <- val_sh
}
dtf
}
while (length(arg) != 0) {
lv <- names(arg)[1]
dtf[, lv] <- rep(character(), nrow(dtf))
if (is.character(arg[[1]]) ||
(!is.null(names(arg[[1]])) &&
is.numeric(arg[[1]]))) {
if (is.character(arg[[1]])) {
val_sh <- rep(1 / length(arg[[1]]), length(arg[[1]]))
val_nm <- arg[[1]]
} else {
val_sh <- arg[[1]]
val_nm <- names(arg[[1]])
}
check_slice(val_nm)
if (any(val_sh <= 0) || round(sum(val_sh), 10) != 1) { # avoiding precision issues on some systems (Mac/M2-Si)
stop(paste(paste('.setTimeSlices: Check time-slice data for level "', lv, '"\n',
sep = ""
), paste(capture.output(print(arg[[1]])), collapse = "\n"), sep = "\n"))
}
arg <- arg[-1]
dtf <- add_val(dtf, val_sh, val_nm)
} else if (is.list(arg[[1]])) {
arg2 <- arg[[1]] # arg <- arg[-1]
if (is.null(names(arg2)) || any(names(arg2) == "")) {
stop(paste(paste('.setTimeSlices: Check time-slice data for level "', lv, '"\n',
sep = ""
), paste(capture.output(print(arg[[1]])), collapse = "\n"), sep = "\n"))
}
if (is.numeric(arg2[[1]])) {
if (!all(sapply(arg2, is.numeric))) {
stop(paste(paste('.setTimeSlices: Check time-slice data for level "', lv, '"\n',
sep = ""
), paste(capture.output(print(arg[[1]])), collapse = "\n"), sep = "\n"))
}
dtf <- add_val(dtf, c(arg2, recursive = TRUE), names(arg2))
arg <- arg[-1]
} else {
if (!all(sapply(arg2, is.list))) {
stop(paste(paste('.setTimeSlices: Check time-slice data for level "', lv, '"\n',
sep = ""
), paste(capture.output(print(arg[[1]])), collapse = "\n"), sep = "\n"))
}
dtf0 <- dtf
dtf <- NULL
arg2 <- arg[[1]]
for (i in seq(length.out = length(arg2))) {
dtf1 <- slice_def(add_val(dtf0, arg2[[i]][[1]], names(arg2)[i]), arg2[[i]][-1])
if (i == 1) {
dtf <- dtf1
} else {
if (ncol(dtf) != ncol(dtf1) || any(colnames(dtf) != colnames(dtf1))) {
stop(paste(".setTimeSlices: Set of slice have to be the same for all (check list slice arguments).", sep = ""))
}
dtf <- rbind(dtf, dtf1)
}
}
arg <- arg[-1]
}
} else {
stop(paste('.setTimeSlices: Unknown type of argument for slice level "', lv, '"', sep = ""))
}
}
dtf
}
dtf <- data.frame(share = numeric(), stringsAsFactors = FALSE)
if (length(arg) == 1 && is.character(arg[[1]]) && length(arg[[1]]) == 1) {
dtf <- data.frame(share = 1, ANNUAL = arg[[1]], stringsAsFactors = FALSE)
if (!is.null(names(arg))) colnames(dtf)[2] <- names(arg)[1]
} else {
dtf <- slice_def(dtf, arg)
}
dtf <- dtf[, c(2:ncol(dtf), 1), drop = FALSE]
if (length(unique(dtf[, 1])) != 1) {
warning('.setTimeSlices: the first level should have only one element, add "ANNUAL"?')
if (any(colnames(dtf) == "ANNUAL") || any(c(dtf == "ANNUAL", recursive = TRUE))) {
stop('.setTimeSlices: cannot add level "ANNUAL" slice, with level "ANNUAL"')
}
dtf$ANNUAL <- rep("ANNUAL", nrow(dtf))
dtf <- dtf[, c(ncol(dtf), 2:ncol(dtf) - 1), drop = FALSE]
}
if (abs(sum(dtf$share) - 1) < 1e-10) dtf$share <- (dtf$share / sum(dtf$share))
.slice_check_data(dtf)
sl <- new("slice")
sl@levels <- dtf
sl <- .init_slice(sl)
sl
}
# setMethod("setTimeSlices", signature(obj = "model"), function(obj, ...) {
# obj@config@slice <- .setTimeSlices(...)
# obj
# })
# setMethod("setTimeSlices", signature(obj = "scenario"), function(obj, ...) {
# obj@model@config@slice <- .setTimeSlices(...)
# obj
# })
# setMethod("setTimeSlices", signature(obj = "config"), function(obj, ...) {
# obj@slice <- .setTimeSlices(...)
# obj
# })
#' @export
timeSlices <- function(x, asTibble = T, stringsAsFactors = FALSE) {
# invisible(newModel("dummymod", slice = xx)@config@slice)
mm <- newModel("dummymod", slice = x)
slev <- mm@config@slice@levels
nlev <- length(mm@config@slice@slice_map)
if (nlev == 1) {
slev$slice <- slev$ANNUAL
} else {
slev$slice <- apply(slev[, 2:nlev, drop = FALSE], 1, paste0, collapse = "_")
}
if (!stringsAsFactors) slev <- fact2char(slev)
if (asTibble) slev <- tibble::as_tibble(slev)
slev
}
#==============================================================================#
# Check if slice level exist ####
#==============================================================================#
.checkSliceLevel <- function(app, approxim) {
if (length(app@slice) != 0 && all(app@slice != colnames(approxim$slice@levels)[-ncol(approxim$slice@levels)]))
stop(paste0('Unknown slice level "', app@slice, '" for ', class(app), ': "', app@name, '"'))
}
#==============================================================================#
# Disaggregate slice ####
# e.g. from WINTER to WINTER_DAY and WINTER_NIGHT
#==============================================================================#
.disaggregateSliceLevel <- function(app, approxim) {
slt <- getSlots(class(app))
slt <- names(slt)[slt == 'data.frame']
if (class(app) == 'technology') slt <- slt[slt != 'afs']
for (ss in slt) if (any(colnames(slot(app, ss)) == 'slice')) {
tmp <- slot(app, ss)
fl <- (!is.na(tmp$slice) & !(tmp$slice %in% approxim$slice))
if (any(fl)) {
mark_col <- (sapply(tmp, is.character) | colnames(tmp) == 'year')
mark_coli <- colnames(tmp)[mark_col]
t1 <- tmp[fl,, drop = FALSE]
t2 <- tmp[!fl,, drop = FALSE]
# Sort from lowest level to largest
ff <- approxim$parent_child$parent[!duplicated(approxim$parent_child$parent)]
f1 <- seq_along(ff)
names(f1) <- ff
if (!all(t1$slice %in% ff))
stop(paste0('Unknown slice or slice is not parrent slice, for "', app@name, '" (class ', class(app), '), slot: "',
ss, '", slice: "', paste0(t1$slice[!(t1$slice %in% ff)], collapse = '", "'), '"'))
t1 <- t1[sort(f1[t1$slice], index.return = TRUE, decreasing = TRUE)$ix,, drop = FALSE]
# Add child desaggregation
for (i in seq_len(nrow(t1))) {
ll <- approxim$parent_child[approxim$parent_child$parent == t1[i, 'slice'], 'child']
t0 <- t1[rep(i, length(ll)),, drop = FALSE]
t0$slice <- ll
tes <- t0[, mark_coli, drop = FALSE]; tes[is.na(tes)] <- '-'
z1 <- apply(tes, 1, paste0, collapse = '##')
tes <- t2[, mark_coli, drop = FALSE]; tes[is.na(tes)] <- '-'
z2 <- apply(tes, 1, paste0, collapse = '##')
# If there are the same row, after splititng
if (any(z1 %in% z2)) {
merge_col <- merge(t0, t2, by = mark_coli)
colnames(merge_col)[seq_len(ncol(t0))] <- colnames(t0)
for (j in colnames(tmp)[!mark_col])
merge_col[!is.na(merge_col[, paste0(j, '.y')]), j] <- NA
t0 <- rbind(t0[!((z1 %in% z2)), ], merge_col[, 1:ncol(t0)])
}
t2 <- rbind(t2, t0)
}
slot(app, ss) <- t2
}
}
app
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.