# interpolate(scenario, overwrite = TRUE) - updates interpolation in scenario objects
# solve_model(scenario, interpolate = NULL) - solves scenario, interpolate if required (NULL), force (TRUE), or no interpolation (FALSE, error if not interpolated)
# returns list with solution status and folder
# read_solution(scen = NULL, folder) - reads results and updates scen, if scen = NULL, creates empty scenario with solution data
# The function creates scenario object with interpolated data, ready to pass to a solver
#' @export
#' @rdname interpolate
#' @family interpolate model scenario
interpolate_model <- function(object, ...) { #- returns class scenario
## arguments
# obj - scenario or model
# name
# desc
# (!!! depreciated) n.threads - number of threads use for approximation
# (!!! depreciated) startYear && fixTo have to define both (or not define both) - run with startYear
# (!!! depreciated) year - basic horizon year definition (not recommended for use), use only if horizon not defined
# discount - define discount, not good practice
# region - define region, not good practice
# repository - class for add to model (repository or list of repository)
# echo - print working data
# !!! ADD: adjust_weather_sample, adjust_demand_sample
# browser()
obj <- object
arg <- list(...)
tictoc::tic()
# browser()
interpolation_start_time <- proc.time()[3]
if (is.null(arg$echo)) arg$echo <- FALSE
if (is(obj, "model")) {
scen <- new("scenario")
# scen <- newScenario()
scen@model <- obj
scen@name <- paste("scen", obj@name, sep = "_")
scen@desc <- ""
scen@settings <- .config_to_settings(obj@config) # import model settings
} else if (is(obj, "scenario")) {
scen <- obj
} else {
stop('Interpolation is not available for class: "', class(obj), '"')
}
# tictoc::toc()
if (!is.null(arg$overwrite)) {
overwrite <- arg$overwrite; arg$overwrite <- NULL
} else {
overwrite <- FALSE
}
if (isTRUE(arg$force)) { # force interpolation of interpolated model
scen@status$interpolated <- FALSE
arg$force <- NULL
}
if (!is.null(arg$name)) {scen@name <- arg$name; arg$name <- NULL}
if (!is.null(arg$desc)) {scen@desc <- arg$desc; arg$desc <- NULL}
#!!! browser()
# if (!is.null(arg$path)) {
# scen@path <- arg$path; arg$path <- NULL
# } else {
# scen@path <- fp(get_scenarios_path(), make_scenario_dirname(scen))
# }
# if (!is.null(arg$inMemory)) {
# scen@inMemory <- arg$inMemory;
# arg$inMemory <- NULL
# }
# cat("model: '", object@name, "'\n", sep = "")
# cat("scenario: '", scen@name, "'\n", sep = "")
# if (!(scen@desc == "")) cat(" '", arg$desc, "'\n", sep = "")
# if (!is.null(scen@path) || !scen@inMemory) {
# cat("path: ", scen@path, "\n", sep = "")
# cat("inMemory: ", scen@inMemory, "\n", sep = "")
# }
# repository ############################################
if (!is.null(arg$repository)) {
if (!is.null(arg$data))
stop("Only one of arguments 'repository' or 'data' can be used.",
call. = FALSE)
scen@model <- .add_repository(scen@model, arg$repository) # !!! use add?
arg$repository <- NULL
}
# data ############################################
if (!is.null(arg$data)) {
scen@model <- .add_repository(scen@model, arg$data) # !!! use add instead?
arg$data <- NULL
scen@status$interpolated <- FALSE
}
carg <- sapply(arg, function(x) class(x)[1])
# more repositories ############################################
# check if there are more repositories to add
ii <- carg == "repository"
if (any(ii)) {
for (ob in arg[ii]) {
scen@model <- add(scen@model, ob, overwrite = overwrite)
}
arg[ii] <- NULL; carg <- carg[!ii]
scen@status$interpolated <- FALSE
}
# "bricks" ############################################
# check if there are any objects to add to a repository
repo_objs <- newRepository("")@permit
ii <- carg %in% repo_objs
if (any(ii)) {
scen_repo <- newRepository(name = paste0(scen@name, "_repo"), arg[ii])
scen@model <- add(scen@model, scen_repo); rm(scen_repo)
arg[ii] <- NULL; carg <- carg[!ii]
scen@status$interpolated <- FALSE
}
# config ############################################
ii <- carg %in% "config"
if (any(ii)) {
if (sum(ii) > 1) {
stop("Two or more 'config' objects found in 'interpolation' arguments.",
call. = FALSE)
}
if (any(carg %in% "settings") || !is.null(arg@settings)) {
stop("Both 'config' and 'settings' objects found in 'interpolation' arguments.",
"Only one of them can be used in 'interpolation' arguments.",
call. = FALSE)
}
scen@settings <- .config_to_settings(arg[ii][[1]])
arg[ii] <- NULL; carg <- carg[!ii]
scen@status$interpolated <- FALSE
}
# settings ############################################
ii <- carg %in% "settings"
if (any(ii)) {
if (sum(ii) > 1) {
stop("Two or more 'settings' objects found in 'interpolation' arguments.",
call. = FALSE)
}
scen@settings <- arg[ii][[1]]
arg[ii] <- NULL; carg <- carg[!ii]
scen@status$interpolated <- FALSE
}
# calendar ############################################
ii <- carg %in% "calendar"
if (any(ii)) {
if (sum(ii) > 1) {
stop("Two or more 'calendar' objects found in 'interpolation' arguments.",
call. = FALSE)
}
# scen <- setCalendar(scen, arg[ii][[1]]) # !!! ToDo
scen@settings@calendar <- arg[ii][[1]]
scen@settings@yearFraction$fraction <-
sum(scen@settings@calendar@timetable$share)
arg[ii] <- NULL; carg <- carg[!ii]
scen@status$interpolated <- FALSE
}
# horizon ############################################
ii <- carg %in% "horizon"
if (any(ii)) {
if (sum(ii) > 1) {
stop("Two or more 'horizon' objects found in 'interpolation' arguments.",
call. = FALSE)
}
# browser()
scen <- setHorizon(scen, arg[ii][[1]])
# scen@settings <- arg[ii]
arg[ii] <- NULL; carg <- carg[!ii]
scen@status$interpolated <- FALSE
}
# SETTINGS slots ############################################
# check if `...` has data for `settings` or `horizon` parameters
# ToDo: rewrite with 'add' once implemented for settings/horizon
# !!! currently one-by-one
# discountFirstYear ############################################
if (any(names(arg) %in% "discountFirstYear")) {
scen@settings@discountFirstYear <- arg$discountFirstYear
arg$discountFirstYear <- NULL
scen@status$interpolated <- FALSE
}
# optimizeRetirement ############################################
if (any(names(arg) %in% "optimizeRetirement")) {
scen@settings@optimizeRetirement <- arg$optimizeRetirement
arg$optimizeRetirement <- NULL
scen@status$interpolated <- FALSE
}
# defValue ############################################
if (any(names(arg) %in% "defValue")) {
scen@settings@defValue <- arg$defValue
arg$defValue <- NULL
scen@status$interpolated <- FALSE
}
# interpolation ############################################
if (any(names(arg) %in% "interpolation")) {
scen@settings@interpolation <- arg$interpolation
arg$interpolation <- NULL
scen@status$interpolated <- FALSE
}
# debug ############################################
if (any(names(arg) %in% "debug")) {
scen@settings@debug <- arg$debug
arg$debug <- NULL
scen@status$interpolated <- FALSE
}
# discount ############################################
if (!is.null(arg$discount)) {
scen@settings@discount <- arg$discount
arg$discount <- NULL
scen@status$interpolated <- FALSE
}
# solver ############################################
if (!is.null(arg$solver)) {
if (is.character(arg$solver)) {
if (length(arg$solver) > 1) {
stop("Solver must be a list or a single string.")
}
arg$solver <- list(nane = arg$solver, lang = arg$solver)
}
scen@settings@solver <- arg$solver
arg$solver <- NULL
# scen@status$interpolated <- FALSE
}
# *DEPRICIATED ############################################
# year
if (!is.null(arg$year)) {
stop("\nThe 'year' argument is depreciated. \nUse 'period' ",
"to set planning (optimization) period. \n",
"See ?horizon and ?settings for help", call. = FALSE)
}
# region
if (!is.null(arg$region)) {
stop("Regions must be defined before the interpolation")
scen@settings@region <- arg$region
arg$region <- NULL
}
# HORIZON slots ############################################
if (!is.null(arg$period) | !is.null(arg$intervals)) {
if (!is.null(arg$period)) {
upd_period <- arg$period
} else {
upd_period <- scen@settings@horizon@period
}
if (!is.null(arg$intervals)) {
upd_intervals <- arg$intervals
} else {
upd_intervals <- scen@settings@horizon@intervals
}
scen@settings@horizon <- newHorizon(
period = upd_period,
intervals = upd_intervals,
desc = scen@settings@horizon@desc
)
scen@status$interpolated <- FALSE
}
# INTERPOLATE ############################################
# Check if the interpolation is needed
if (scen@status$interpolated) {
message("The scenario is already interpolated. Use 'force = TRUE' ",
"to re-interpolate the scenario.")
return(invisible(scen))
}
# tictoc::toc()
# other interpolation parameters
if (is.null(arg$n.threads)) arg$n.threads <- 1 #+ 0 * detectCores()
if (is.null(arg$verbose)) arg$verbose <- 0
if (!is.null(arg$table_format)) { # !!! draft, not actual
scen@misc$table_format <- arg$table_format
# set_table_format(scen@misc$table_format)
arg$table_format <- NULL
} else {
scen@misc$table_format <- "data.table"
# set_table_format(scen@misc$table_format)
}
# tictoc::toc(); tictoc::tic()
### Interpolation
scen@modInp <- new("modInp")
# browser()
## Fill basic sets
# Fill year
if (!is.null(arg$year)) { #
if (nrow(scen@settings@horizon@intervals) != 0) {
stop("argument can't be used with horizon")
}
scen@settings@horizon@period <- arg$year
}
# browser()
if (nrow(scen@settings@horizon@intervals) == 0) {
# if (any(sort(scen@settings@horizon@period) !=
# scen@settings@horizon@period) ||
# max(scen@settings@horizon@period) -
# min(scen@settings@horizon@period) + 1 !=
# length(scen@settings@horizon@period)) {
if (length(scen@settings@horizon@period) == 0) {
stop("Empty 'period' parameter. \n",
"Add 'settings' or 'horizon' to the model or 'interpolation(...)'")
}
scen@settings <- setHorizon(scen@settings,
horizon = scen@settings@horizon@period[1],
intervals = rep(1, length(scen@settings@horizon@period))
)
}
#!!!
# browser()
if (!is.null(arg$path)) {
scen@path <- arg$path; arg$path <- NULL
} else {
scen@path <- fp(get_scenarios_path(), make_scenario_dirname(scen))
}
if (!is.null(arg$inMemory)) {
scen@inMemory <- arg$inMemory;
arg$inMemory <- NULL
}
cat("model: '", object@name, "'\n", sep = "")
cat("scenario: '", scen@name, "'\n", sep = "")
if (!(scen@desc == "")) cat(" '", arg$desc, "'\n", sep = "")
if (!is.null(scen@path) || !scen@inMemory) {
cat("path: ", scen@path, "\n", sep = "")
cat("inMemory: ", scen@inMemory, "\n", sep = "")
}
# browser()
#!!! Suppressed parameter
# newParameter("horizon", dimSets = "horizon", type = "map")
# scen@modInp@parameters[["horizon"]] <-
# .dat2par(scen@modInp@parameters[["horizon"]],
# scen@settings@horizon@period)
# tictoc::toc(); tictoc::tic()
scen@modInp@parameters[["year"]] <-
.dat2par(scen@modInp@parameters[["year"]],
scen@settings@horizon@intervals$mid)
# .dat2par(scen@modInp@parameters[["year"]], scen@settings@horizon@period)
# browser()
# nYears <- length(scen@settings@horizon@intervals$mid)
# scen@modInp@parameters[["nextYear"]] <-
# .dat2par(scen@modInp@parameters[["nextYear"]],
# data.table(
# year = scen@settings@horizon@intervals$mid[-nYears],
# value = scen@settings@horizon@intervals$mid[-1]
# )
# )
#!!! Suppressed parameter
# scen@modInp@parameters[["pYear"]] <-
# .dat2par(scen@modInp@parameters[["pYear"]],
# data.table(
# year = scen@settings@horizon@intervals$mid,
# value = scen@settings@horizon@intervals$mid
# )
# )
scen@modInp@parameters[["mMidMilestone"]] <-
.dat2par(scen@modInp@parameters[["mMidMilestone"]],
data.table(year = scen@settings@horizon@intervals$mid)
)
# slices ####
# browser()
# scen@settings@timeframe <- .init_slice(scen@settings@timeframe)
# browser()
# tictoc::toc(); tictoc::tic()
if (mean(scen@settings@yearFraction$fraction) != 1.) {
# filter out unused slices
# browser()
# warning(
# "Solving for a fraction of a year.\n",
# "Variables without slice dimension scaled to the annual level using weights.",
# "The solution might differ from the whole-year optimization."
# )
cat("Subsetting time-slices\n")
scen@model@data <- subset_slices_repo(
repo = scen@model@data,
yearFraction = mean(scen@settings@yearFraction$fraction),
keep_slices = scen@settings@calendar@slice_share$slice
)
}
# !!!??? add filtering slices here
# nslices <- nrow(scen@settings@calendar@timetable)
# scen@settings@calendar@timetable$share <- scen@settings@calendar@timetable$share * nslices/8760
# scen@settings@calendar@slice_share$share <- scen@settings@calendar@slice_share$share * nslices/8760
# browser()
scen@modInp@parameters[["slice"]] <- .dat2par(
scen@modInp@parameters[["slice"]],
scen@settings@calendar@slice_share$slice
)
# region ####
scen@modInp@parameters[["region"]] <-
.dat2par(scen@modInp@parameters[["region"]], scen@settings@region)
# browser()
# List for approximation
# Generate approxim list, that contain basic data for approximation
xx <- c(
scen@settings@horizon@intervals$mid[-1] -
scen@settings@horizon@intervals$mid[-nrow(scen@settings@horizon@intervals)],
1)
names(xx) <- scen@settings@horizon@intervals$mid
if (is.null(arg$fullsets)) fullsets <- TRUE else fullsets <- arg$fullsets
scen@status$fullsets <- fullsets # !!!???
# browser()
approxim <- list(
region = scen@settings@region,
year = scen@settings@horizon@period,
# slice = scen@settings@slice,
calendar = scen@settings@calendar,
solver = arg$solver,
mileStoneYears = scen@settings@horizon@intervals$mid,
mileStoneForGrowth = xx,
fullsets = fullsets,
optimizeRetirement = scen@settings@optimizeRetirement
)
approxim$ry <- merge0(
data.table(region = approxim$region, stringsAsFactors = FALSE),
data.table(year = approxim$mileStoneYears, stringsAsFactors = FALSE)
) |> as.data.table()
approxim$rys <- merge0(
approxim$ry,
data.table(
slice = approxim$calendar@slice_share$slice,
stringsAsFactors = FALSE
)
) |> as.data.table()
approxim$ry <- as.data.table(approxim$ry)
approxim$rys <- as.data.table(approxim$rys)
# Basic interpolation parameter from config
approxim$all_comm <-
c(lapply(scen@model@data, function(x) {
c(lapply(x@data, function(y) {
if (!is(y, "commodity")) {
return(NULL)
}
return(y@name)
}), recursive = TRUE)
}), recursive = TRUE)
names(approxim$all_comm) <- NULL
scen@modInp <- .read_default_data(scen@modInp, scen@settings)
# (Optional/experimental) trimming the model == dropping unused dimensions
if (!is.null(arg$trim) && arg$trim) {
## Trim before interpolation
par_name <- grep("^p", names(scen@modInp@parameters), value = TRUE)
par_name <- par_name[
!(par_name %in% c("pEmissionFactor", "pTechEmisComm", "pDiscount"))
]
# Get repository / class structure
rep_class <- NULL
for (i in seq_along(scen@model@data)) {
rep_class <- rbind(
rep_class,
data.table(
repos = rep(i, length(scen@model@data[[i]]@data)),
class = sapply(scen@model@data[[i]]@data, class),
name = c(sapply(scen@model@data[[i]]@data, function(x) x@name)),
stringsAsFactors = FALSE
)
)
}
# Trim data
for (pr in par_name) {
tmp <- scen@modInp@parameters[[pr]]
if (!is.null(tmp@inClass$class) &&
(length(tmp@inClass$colName) != 1 || tmp@inClass$colName != "") &&
length(tmp@dimSets) > 1) {
# Get prototype
prot <- new(tmp@inClass$class)
psb_slot <- getSlots(tmp@inClass$class)
psb_slot <- names(psb_slot)[psb_slot %in% "data.frame"]
psb_slot <- psb_slot[!(psb_slot %in% c("defVal", "interpolation"))]
fl <- sapply(psb_slot, function(x) {
any(colnames(slot(prot, x)) %in% tmp@inClass$colName)
})
if (sum(fl) != 1) stop("Internal error")
slt <- psb_slot[fl]
need_col <- tmp@dimSets[tmp@dimSets %in% colnames(slot(prot, slt))]
if (any(pr == c("pDummyImportCost", "pDummyExportCost")))
need_col <- need_col[need_col != "comm"]
if (tmp@type == "numpar") {
val_col <- tmp@inClass$colName
} else {
val_col <- c(tmp@inClass$colName,
gsub("[.].*", ".fx", tmp@inClass$colName[1]))
}
# Try find reduce column
rep_class2 <- rep_class[rep_class$class == tmp@inClass$class, ]
i <- 0
while (i < nrow(rep_class2) && length(need_col) != 0) {
i <- i + 1
tbl <- slot(
scen@model@data[[rep_class2[i, "repos"]]]@data[[rep_class2[i, "name"]]],
slt)
if (nrow(tbl) > 0) {
# need_col <- need_col[apply(is.na(tbl[apply(!is.na(tbl[, val_col, drop = FALSE]), 1, any), need_col, drop = FALSE]), 2, all)]
# tb_nna <- tbl |> select(all_of(val_col))
if (anyDuplicated(colnames(val_col))) browser() # mappings check
ii <- apply(!is.na(select(all_of(val_col))), 1, any)
ii <- apply(is.na(filter(tbl, ii)), 2, all)
need_col <- need_col[ii]
}
}
if (length(need_col) > 0) {
scen@modInp@parameters[[pr]]@misc$rem_col <-
seq_along(tmp@dimSets)[tmp@dimSets %in% need_col]
scen@modInp@parameters[[pr]]@misc$not_need_interpolate <- need_col
scen@modInp@parameters[[pr]]@misc$init_dim <- tmp@dimSets
scen@modInp@parameters[[pr]]@dimSets <-
tmp@dimSets[!(tmp@dimSets %in% need_col)]
# scen@modInp@parameters[[pr]]@data <-
# scen@modInp@parameters[[pr]]@data[,!(colnames(
# scen@modInp@parameters[[pr]]@data) %in% need_col), drop = FALSE]
ii <-
scen@modInp@parameters[[pr]]@data <- select(
scen@modInp@parameters[[pr]]@data,
!(colnames(scen@modInp@parameters[[pr]]@data) %in% need_col)
)
if (arg$verbose >= 1) {
scen@misc$trimDroppedDimensions <- rbind(
scen@misc$trimDroppedDimensions,
data.table(parameter = rep(pr, length(need_col)),
dimname = need_col, stringsAsFactors = FALSE)
)
warning(paste0('Dropping dimension "',
paste0(need_col, collapse = '", "'),
'" from parameter "', pr, '"'))
}
}
}
}
}
scen@modInp <- .obj2modInp(scen@modInp, scen@settings, approxim = approxim)
# browser()
# Add discount data to approxim
approxim <- .add_discount_approxim(scen, approxim)
# Update early retirement parameter
# browser()
if (!scen@settings@optimizeRetirement) {
scen <- .remove_early_retirment(scen)
}
approxim$debug <- scen@settings@debug
# Fill slice level for commodity if not defined
scen <- .fill_default_slice_leve4comm(scen, def.level = approxim$calendar@default_timeframe)
# Add commodity slice_level map to approxim
approxim$commodity_slice_map <- .get_map_commodity_slice_map(scen)
scen@misc$approxim <- approxim
# Fill set list for interpolation and os one
# browser()
scen <- .add_name_for_basic_set(scen, approxim)
scen@modInp@set <-
lapply(scen@modInp@parameters[sapply(scen@modInp@parameters,
function(x) x@type == "set")],
function(x) .get_data_slot(x)[[1]])
## interpolate data by year, slice, ...
# if (arg$echo) cat("Interpolation: \n")
cat("Interpolating parameters\n")
interpolation_count <- .get_objects_count(scen) + 46
len_name <- .get_objects_len_name(scen)
if (arg$n.threads == 1) {
# scen <- .add2_nthreads_1(0, 1, scen, arg, approxim,
# interpolation_start_time = interpolation_start_time,
# interpolation_count = interpolation_count, len_name = len_name
# )
} else {
warning("Multiple threads are not implemented yet,
ignoring `n.threads` parameter")
# use_par <- names(scen@modInp@parameters)[sapply(scen@modInp@parameters, function(x) nrow(x@data) == 0)]
# # require(parallel)
# cl <- makeCluster(arg$n.threads)
# scen_pr <- parLapply(
# cl, 0:(arg$n.threads - 1), .add2_nthreads_1, arg$n.threads, scen, arg, approxim,
# interpolation_start_time, interpolation_count, len_name
# )
# stopCluster(cl)
# scen <- .merge_scen(scen_pr, use_par)
}
# browser()
scen <- .add2_nthreads_1(n.thread = 0, max.thread = 1,
scen = scen, arg = arg, approxim = approxim,
interpolation_start_time = interpolation_start_time,
interpolation_count = interpolation_count,
len_name = len_name
)
# Remove duplicates
scen@modInp@parameters$group <- .unique_set(scen@modInp@parameters$group)
scen@modInp@parameters$mvDemInp <- .unique_set(scen@modInp@parameters$mvDemInp)
# browser()
# Check for unknown set in model and duplicated set
.check_sets(scen)
# Check for unknown set in constraints
.check_constraint(scen)
# Check for unknown weather
.check_weather(scen)
# # Check for unknown set in model and duplicated set
# .check_sets(scen)
#!!!ToDo: add NA checks for sets
# Tune for LEC
# if (length(scen@model@LECdata) != 0) {
# scen@modInp@parameters$mLECRegion <-
# addMultipleSet(
# scen@modInp@parameters$mLECRegion,
# scen@model@LECdata$region
# )
# if (length(obj@LECdata$pLECLoACT) == 1) {
# scen@modInp@parameters$pLECLoACT <- .dat2par(
# scen@modInp@parameters$pLECLoAC= TRUE,
# data.frame(
# region = scen@model@LECdata$region,
# value = scen@model@LECdata$pLECLoACT
# )
# )
# }
# }
# Reduce mapping
# browser()
# mCommReg ####
# rest <- rest + 1
# .interpolation_message("mCommReg", rest, interpolation_count,
# interpolation_start_time, len_name)
# browser()
# scan all "^p"-parameters for (comm, region)
# allpar <- names(scen@modInp@parameters)
# allpar <- allpar[grepl("^p", allpar)] # parameters
# allpar <- allpar[!grepl("Dummy", allpar)] # drop Dummy-Imp/Exp (for filtering)
# allpar <- c(allpar, "mSupAva") # add sup with default/missing data
# mCommReg <- lapply(scen@modInp@parameters[allpar], function(x) {
# if (!all(c("comm", "region") %in% x@dimSets)) return(NULL)
# select(x@data, comm, region) |> unique()
# }) |>
# rbindlist() |>
# unique()
# browser()
mCommReg <- fmCommReg(scen@model, scen@settings@region) |>
filter(region %in% scen@settings@region)
scen@modInp@parameters[["mCommReg"]] <-
.dat2par(scen@modInp@parameters[["mCommReg"]], mCommReg)
# browser()
# !!!patch: update parameters (drop technologies with unavailable in regs inputs)
# ToDo: take into account of other mapping and parameters in new interpolate
# mCommReg - filter with comm-reg dims
filter_comreg <- function(p, y = mCommReg) {
p@data <-
p@data |>
semi_join(y, by = intersect(colnames(p@data), colnames(y))) |>
unique()
p@misc$nValues <- nrow(p@data)
p
}
# filter with "tech-region" dims
y_tech_reg <- scen@modInp@parameters[["mTechInpComm"]]@data |>
# rbind(scen@modInp@parameters[["mTechOutComm"]]@data) |>
rbind(scen@modInp@parameters[["mTechAInp"]]@data) |>
# rbind(scen@modInp@parameters[["mTechAOut"]]@data) |>
unique() |>
right_join(mCommReg, by = "comm") |>
filter(!is.na(tech)) |>
select(-comm) |> unique()
scen@modInp@parameters[["mvTechInp"]] <-
filter_comreg(scen@modInp@parameters[["mvTechInp"]])
scen@modInp@parameters[["mvTechOut"]] <-
filter_comreg(scen@modInp@parameters[["mvTechOut"]], y_tech_reg)
scen@modInp@parameters[["mvTechAInp"]] <-
filter_comreg(scen@modInp@parameters[["mvTechAInp"]], y_tech_reg)
scen@modInp@parameters[["mvTechAOut"]] <-
filter_comreg(scen@modInp@parameters[["mvTechAOut"]])
# scen@modInp@parameters[["mTechInpTot"]]
# y_out <- scen@modInp@parameters[["mTechOutComm"]]@data |>
# rbind(scen@modInp@parameters[["mTechAOut"]]@data) |>
# unique() |>
# right_join(mCommReg, by = "comm") |>
# filter(!is.na(tech))
scen@modInp@parameters[["mTechNew"]] <-
filter_comreg(scen@modInp@parameters[["mTechNew"]], y_tech_reg)
# scen@modInp@parameters[["mTechNew"]] |> filter_comreg(y_out)
scen@modInp@parameters[["mTechSpan"]] <-
filter_comreg(scen@modInp@parameters[["mTechSpan"]], y_tech_reg)
# scen@modInp@parameters[["mTechSpan"]] |> filter_comreg(y_out)
scen@modInp@parameters[["mvTechAct"]] <-
filter_comreg(scen@modInp@parameters[["mvTechAct"]], y_tech_reg)
scen@modInp@parameters[["mTechInv"]] <-
filter_comreg(scen@modInp@parameters[["mTechInv"]], y_tech_reg)
scen@modInp@parameters[["mTechEac"]] <-
filter_comreg(scen@modInp@parameters[["mTechEac"]], y_tech_reg)
# scen@modInp@parameters[["mTechOMCost"]] <-
# filter_comreg(scen@modInp@parameters[["mTechOMCost"]], y_tech_reg)
scen@modInp@parameters[["mTechFixom"]] <-
filter_comreg(scen@modInp@parameters[["mTechFixom"]], y_tech_reg)
scen@modInp@parameters[["mTechVarom"]] <-
filter_comreg(scen@modInp@parameters[["mTechVarom"]], y_tech_reg)
scen@modInp@parameters[["mTechCapLo"]] <-
filter_comreg(scen@modInp@parameters[["mTechCapLo"]], y_tech_reg)
scen@modInp@parameters[["mTechCapUp"]] <-
filter_comreg(scen@modInp@parameters[["mTechCapUp"]], y_tech_reg)
scen@modInp@parameters[["mTechNewCapLo"]] <-
filter_comreg(scen@modInp@parameters[["mTechNewCapLo"]], y_tech_reg)
scen@modInp@parameters[["mTechNewCapUp"]] <-
filter_comreg(scen@modInp@parameters[["mTechNewCapUp"]], y_tech_reg)
# scen@modInp@parameters[["mStorageFixom"]] <-
# filter_comreg(scen@modInp@parameters[["mStorageFixom"]], y_tech_reg)
# scen@modInp@parameters[["mStorageVarom"]] <-
# filter_comreg(scen@modInp@parameters[["mStorageVarom"]], y_tech_reg)
# pTechEac(tech, region, year)
# scen@modInp@parameters[["pTechEac"]] <-
# filter_comreg(scen@modInp@parameters[["pTechEac"]], y_tech_reg)
# scen@modInp@parameters[["pTechEac"]] <-
# filter_comreg(scen@modInp@parameters[["pTechEac"]], y_inp)
# mTechAct2AInp(tech, comm, region, year, slice)
scen@modInp@parameters[["mTechAct2AInp"]] <-
filter_comreg(scen@modInp@parameters[["mTechAct2AInp"]], y_tech_reg)
# mTechCap2AInp(tech, comm, region, year, slice)
scen@modInp@parameters[["mTechCap2AInp"]] <-
filter_comreg(scen@modInp@parameters[["mTechCap2AInp"]], y_tech_reg)
# mTechNCap2AInp(tech, comm, region, year, slice)
scen@modInp@parameters[["mTechNCap2AInp"]] <-
filter_comreg(scen@modInp@parameters[["mTechNCap2AInp"]], y_tech_reg)
# mTechCinp2AInp(tech, comm, comm, region, year, slice)
scen@modInp@parameters[["mTechCinp2AInp"]] <-
filter_comreg(scen@modInp@parameters[["mTechCinp2AInp"]], y_tech_reg)
# mTechCout2AInp(tech, comm, comm, region, year, slice)
scen@modInp@parameters[["mTechCout2AInp"]] <-
filter_comreg(scen@modInp@parameters[["mTechCout2AInp"]], y_tech_reg)
# mTechAct2AOut(tech, comm, region, year, slice)
scen@modInp@parameters[["mTechAct2AOut"]] <-
filter_comreg(scen@modInp@parameters[["mTechAct2AOut"]], y_tech_reg)
# mTechCap2AOut(tech, comm, region, year, slice)
scen@modInp@parameters[["mTechCap2AOut"]] <-
filter_comreg(scen@modInp@parameters[["mTechCap2AOut"]], y_tech_reg)
# mTechNCap2AOut(tech, comm, region, year, slice)
scen@modInp@parameters[["mTechNCap2AOut"]] <-
filter_comreg(scen@modInp@parameters[["mTechNCap2AOut"]], y_tech_reg)
# mTechCinp2AOut(tech, comm, comm, region, year, slice)
scen@modInp@parameters[["mTechCinp2AOut"]] <-
filter_comreg(scen@modInp@parameters[["mTechCinp2AOut"]], y_tech_reg)
# mTechCout2AOut(tech, comm, comm, region, year, slice)
scen@modInp@parameters[["mTechCout2AOut"]] <-
filter_comreg(scen@modInp@parameters[["mTechCout2AOut"]], y_tech_reg)
# browser()
# meqTechSng2Sng
scen@modInp@parameters[["meqTechSng2Sng"]] <-
filter_comreg(scen@modInp@parameters[["meqTechSng2Sng"]], y_tech_reg)
# meqTechGrp2Sng
scen@modInp@parameters[["meqTechGrp2Sng"]] <-
filter_comreg(scen@modInp@parameters[["meqTechGrp2Sng"]], y_tech_reg)
# meqTechSng2Grp
scen@modInp@parameters[["meqTechSng2Grp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechSng2Grp"]], y_tech_reg)
# meqTechGrp2Grp
scen@modInp@parameters[["meqTechGrp2Grp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechGrp2Grp"]], y_tech_reg)
# meqTechAfLo
scen@modInp@parameters[["meqTechAfLo"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfLo"]], y_tech_reg)
# meqTechAfUp
scen@modInp@parameters[["meqTechAfUp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfUp"]], y_tech_reg)
# meqTechAfsLo
scen@modInp@parameters[["meqTechAfsLo"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfsLo"]], y_tech_reg)
# meqTechAfsUp
scen@modInp@parameters[["meqTechAfsUp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfsUp"]], y_tech_reg)
# mTechRampUp
scen@modInp@parameters[["mTechRampUp"]] <-
filter_comreg(scen@modInp@parameters[["mTechRampUp"]], y_tech_reg)
# mTechRampDown
scen@modInp@parameters[["mTechRampDown"]] <-
filter_comreg(scen@modInp@parameters[["mTechRampDown"]], y_tech_reg)
# meqTechActSng
scen@modInp@parameters[["meqTechActSng"]] <-
filter_comreg(scen@modInp@parameters[["meqTechActSng"]], y_tech_reg)
# meqTechActGrp
scen@modInp@parameters[["meqTechActGrp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechActGrp"]], y_tech_reg)
# meqTechAfcOutLo
scen@modInp@parameters[["meqTechAfcOutLo"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfcOutLo"]], y_tech_reg)
# meqTechAfcOutUp
scen@modInp@parameters[["meqTechAfcOutUp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfcOutUp"]], y_tech_reg)
# meqTechAfcInpLo
scen@modInp@parameters[["meqTechAfcInpLo"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfcInpLo"]], y_tech_reg)
# meqTechAfcInpUp
scen@modInp@parameters[["meqTechAfcInpUp"]] <-
filter_comreg(scen@modInp@parameters[["meqTechAfcInpUp"]], y_tech_reg)
# browser()
# !!! End of patch
rm(mCommReg)
# filter parameters by (comm, region)
filter_params <- c("pDummyExportCost", "pDummyImportCost")
for (p in filter_params) {
d <- scen@modInp@parameters[[p]]@data |>
inner_join(scen@modInp@parameters[["mCommReg"]]@data,
by = c("comm", "region"))
scen@modInp@parameters[[p]]@data <- scen@modInp@parameters[[p]]@data[0,]
scen@modInp@parameters[[p]] <- .dat2par(scen@modInp@parameters[[p]], d)
}
# scen@modInp <- .write_mapping(scen@modInp,
# interpolation_count = interpolation_count,
# interpolation_start_time = interpolation_start_time,
# len_name = len_name
# )
scen@modInp <- .make_mapping(
scen@modInp,
interpolation_count = interpolation_count,
interpolation_start_time = interpolation_start_time,
len_name = len_name,
scen_settings = scen@settings
)
# Clean parameters, need when nValues != -1, and mean that add NA row for speed
# browser()
for (i in names(scen@modInp@parameters)) {
if (scen@modInp@parameters[[i]]@misc$nValues != -1) {
# scen@modInp@parameters[[i]]@data <- scen@modInp@parameters[[i]]@data[
# seq(length.out = scen@modInp@parameters[[i]]@misc$nValues), ,
# drop = FALSE
# ]
nrow_i <- scen@modInp@parameters[[i]]@data |> nrow()
scen@modInp@parameters[[i]]@data <- scen@modInp@parameters[[i]]@data |>
slice_head(n = min(nrow_i,
scen@modInp@parameters[[i]]@misc$nValues,
na.rm = TRUE)
)
}
}
scen@settings@sourceCode <- .modelCode
scen@status$interpolated <- TRUE
scen@status$script <- FALSE
# Check parameters
scen <- .check_scen_par(scen)
# if (arg$echo) cat(" ", round(proc.time()[3] - interpolation_start_time, 2), "s\n")
# cat("\n")
tictoc::toc()
invisible(scen)
}
#' Interpolate model
#'
#' @param object model or scenario type of object.
#'
#' @return scenario object with enclosed model (slot `@model`) and interpolated parameters (slot `@modInp`).
#' @export
#' @family interpolate model
#'
#' @examples
#' \dontrun{
#' scen <- interpolate(mod)
#' }
setMethod("interpolate", signature(object = "model"),
function(object, ...) {
interpolate_model(object, ...)
})
#' @rdname interpolate
#' @family interpolate scenario
#' @method interpolate scenario
#' @export
setMethod("interpolate", "scenario", function(object, ...) {
interpolate_model(object, ...)
})
subset_slices <- function(obj, yearFraction = 1, keep_slices = NULL) {
# subset_hours <- length(SLICE_SUBSET)
# subset_fraction <- subset_hours/8760
if (yearFraction == 1) {
return(obj)
}
keep_slices <- unique(c(NA, "ANNUAL", keep_slices))
if (inherits(obj, "data.frame")) { # unnesecary - reserved for future
if (any(names(obj) == "slice")) {
obj <- filter(obj, slice %in% keep_slices)
}
return(obj)
} else if (!isS4(obj)) {
return(obj)
}
# S4
slot_names <- slotNames(obj)
ii <- sapply(slot_names, function(x) {
inherits(slot(obj, x), "data.frame") &&
any(colnames(slot(obj, x)) == "slice")
})
# summary(ii)
for (s in slot_names[ii]) {
# stop()
slot(obj, s) <- slot(obj, s) |>
filter(slice %in% keep_slices)
}
#
# obj <- fract_year_adj(obj, subset_hours, check = TRUE)
#
return(obj)
}
subset_slices_repo <- function(repo, yearFraction = 1, keep_slices = NULL) {
# browser()
if (yearFraction == 1) {
return(repo)
}
# browser()
if (inherits(repo, "list")) {
# list of repositories
repo <- lapply(repo, function(o) {
subset_slices_repo(o, yearFraction, keep_slices)
})
return(repo)
}
# stopifnot(inherits(repo, c("repository")))
# if (repo)
# subset_hours <- length(SLICE_SUBSET)
# subset_fraction <- subset_hours/8760
# i <- 19
# browser()
if (inherits(repo, c("repository"))) {
cat(" Repository '", repo@name, "'\n", sep = "")
x <- repo@data
} else {
# x <- repo
# browser()
stop("Unrecognized class of object in the repository.")
}
p <- progressr::progressor(
along = names(x)
# message = paste(" Repository '", repo@name, "'\n", sep = "")
)
for (i in 1:length(x)) {
# print(i)
obj <- x[[i]]
p(obj@name)
if (inherits(obj, c("repository"))) {
# nested repository - should not be here, check repo@misc$permit
stop("Nested repositories are not supported. ", obj@name,
" is a part of another repository.")
subset_slices_repo(obj, yearFraction, keep_slices)
} else {
obj <- subset_slices(obj, yearFraction, keep_slices)
}
x[[i]] <- obj
}
if (inherits(repo, c("repository"))) {
repo@data <- x
} else {
repo <- x
}
return(repo)
}
# Check parameters
.check_scen_par <- function(scen) {
# Check for non negative parameters, all except 'pAggregateFactor', 'pTechCvarom', 'pTechAvarom', 'pTechVarom', 'pTechInvcost'
non_negative <- unique(c(
"pSliceShare", "pSliceWeight", "pTechOlife", "pTechCinp2ginp",
"pTechGinp2use", "pTechCinp2use", "pTechUse2cact", "pTechCact2cout",
"pTechEmisComm", "pTechAct2AInp", "pTechCap2AInp", "pTechNCap2AInp",
"pTechCinp2AInp", "pTechCout2AInp",
"pTechAct2AOut", "pTechCap2AOut", "pTechNCap2AOut", "pTechCinp2AOut",
"pTechCout2AOut", "pTechFixom", "pTechShare",
"pTechShare", "pTechAf", "pTechAf", "pTechAfs", "pTechAfs", "pTechAfc",
"pTechAfc", "pTechStock", "pTechCap2act", "pDiscount",
"pDiscountFactor", "pSupCost", "pSupAva", "pSupAva", "pSupReserve",
"pSupReserve", "pDemand", "pEmissionFactor", "pDummyImportCost",
"pDummyExportCost", "pTaxCostInp", "pSubCostInp", "pTaxCostOut",
"pSubCostOut", "pTaxCostBal", "pSubCostBal",
"pWeather", "pSupWeather", "pSupWeather", "pTechWeatherAf",
"pTechWeatherAf", "pTechWeatherAfs", "pTechWeatherAfs",
"pTechWeatherAfc", "pTechWeatherAfc", "pStorageWeatherAf",
"pStorageWeatherAf", "pStorageWeatherCinp", "pStorageWeatherCinp",
"pStorageWeatherCout", "pStorageWeatherCout", "pStorageInpEff",
"pStorageOutEff", "pStorageStgEff", "pStorageStock", "pStorageOlife",
"pStorageCostStore", "pStorageCostInp",
"pStorageCostOut", "pStorageFixom", "pStorageInvcost", "pStorageCap2stg",
"pStorageAf", "pStorageAf", "pStorageCinp", "pStorageCinp", "pStorageCout",
"pStorageCout", "pStorageStg2AInp", "pStorageStg2AOut", "pStorageCinp2AInp",
"pStorageCinp2AOut", "pStorageCout2AInp", "pStorageCout2AOut",
"pStorageCap2AInp", "pStorageCap2AOut", "pStorageNCap2AInp",
"pStorageNCap2AOut", "pTradeIrEff", "pTradeIr", "pTradeIr",
"pTradeIrCost", "pTradeIrMarkup", "pTradeIrCsrc2Ainp",
"pTradeIrCsrc2Aout", "pTradeIrCdst2Ainp", "pTradeIrCdst2Aout",
"pExportRowRes", "pExportRow",
# "pExportRowPrice",
"pImportRowRes", "pImportRow",
"pImportRow",
"pTechRet", "pTechCap", "pTechNewCap",
"pStorageRet", "pStorageCap", "pStorageNewCap",
"pTradeRet", "pTradeCap", "pTradeNewCap"
# "pImportRowPrice"
))
# browser()
msg_small_err <- NULL
for (i in non_negative) {
if (any(scen@modInp@parameters[[i]]@data$value < 0)) {
if (any(scen@modInp@parameters[[i]]@data$value < -1e-7)) {
msg <- paste0('An attempt to assignin negative numbers
to non-negative parameter: "', i)
tmp <- scen@modInp@parameters[[i]]@data[
scen@modInp@parameters[[i]]@data$value < 0, ,
drop = FALSE]
msg <- c(msg, capture.output(print(tmp[1:min(c(10, nrow(tmp))), ,
drop = FALSE])))
if (nrow(tmp) > 10) {
msg <- c(msg,
paste0("Showing only the first 10 errors in data, from ",
nrow(tmp), "\n")
)
}
stop(paste0(msg, collapse = "\n"))
} else {
msg_small_err <- c(msg_small_err, i)
scen@modInp@parameters[[i]]@data[
scen@modInp@parameters[[i]]@data$value > -1e-7 &
scen@modInp@parameters[[i]]@data$value < 0, "value"] <- 0
}
}
}
if (length(msg_small_err) > 0) {
warning(paste0(
"There small negative value (abs(err) < 1e-7) in parameter",
"s"[length(msg_small_err) > 1], ': "',
paste0(msg_small_err, collapse = '", "'), '". Assigned as zerro.'
))
}
# Check share
if (nrow(scen@modInp@parameters$pTechShare@data) > 0) {
# Share check is not working, probably unfinished migration to dplyr & data.table
# !!! ToDo: rewrite this function.
# browser()
# mTechGroupComm <- .get_data_slot(scen@modInp@parameters$mTechGroupComm)
# # scen@modInp@parameters$pTechShare@data <- merge(scen@modInp@parameters$pTechShare@data, mTechGroupComm)
# # if (scen@modInp@parameters$pTechShare@misc$nValues != - 1)
# # scen@modInp@parameters$pTechShare@misc$nValues <- nrow(scen@modInp@parameters$pTechShare@data)
# tmp <- .add_dropped_zeros(scen@modInp, "pTechShare")
# mTechSpan <- .get_data_slot(scen@modInp@parameters$mTechSpan)
# browser()
# tmp <- merge(tmp, mTechSpan)
# tmp_lo <- merge0(tmp[tmp$type == "lo", , drop = FALSE], mTechGroupComm)
# tmp_up <- merge0(tmp[tmp$type == "up", , drop = FALSE], mTechGroupComm)
# tmp_lo <- aggregate(
# tmp_lo[, "value", drop = FALSE],
# select(tmp_lo, -any_of(c("type", "comm", "value"))),
# # tmp_lo[, !(colnames(tmp_lo) %in% c("type", "comm", "value")),
# # drop = FALSE],
# sum)
# tmp_up <- aggregate(
# tmp_up[, "value", drop = FALSE],
# tmp_up[, !(colnames(tmp_up) %in% c("type", "comm", "value")),
# drop = FALSE],
# sum)
# if (any(tmp_lo$value > 1) || any(tmp_up$value < 1)) {
# tech_wrong_lo <- tmp_lo[tmp_lo$value > 1, , drop = FALSE]
# tech_wrong_up <- tmp_up[tmp_up$value < 1, , drop = FALSE]
# tech_wrong <- unique(c(tech_wrong_up$tech, tech_wrong_lo$tech))
# assign("tech_wrong_lo", tech_wrong_lo, globalenv())
# assign("tech_wrong_up", tech_wrong_up, globalenv())
# stop(paste0(
# "Error in share (sum of up < 1 or sum of lo > 1)",
# "(see `tech_wrong_lo` and `tech_wrong_up`)",
# ' for technology "', paste0(tech_wrong, collapse = '", "'), '"'
# ))
# }
# fl <- colnames(tmp)[!(colnames(tmp) %in% c("type"))]
# tmp_cmd <- merge(tmp[tmp$type == "lo", fl, drop = FALSE],
# tmp[tmp$type == "up", fl, drop = FALSE],
# by = fl[fl != "value"])
# if (any(tmp_cmd$value.x > tmp_cmd$value.y)) {
# tech_wrong <- tmp_cmd[tmp_cmd$value.x > tmp_cmd$value.y, , drop = FALSE]
# assign("tech_wrong", tech_wrong, globalenv())
# stop(paste0(
# 'Error in share data (tuple (tech, comm, region, year, slice) lo",
# " share > up), see `tech_wrong`"',
# paste0(unique(tech_wrong$tech), collapse = '", "'), '"'
# ))
# }
}
scen
}
.unique_set <- function(obj) {
if (obj@misc$nValues != -1) {
# browser()
obj@data <- obj@data[seq(length.out = obj@misc$nValues), , drop = FALSE]
obj@data <- obj@data[!duplicated(obj@data), , drop = FALSE]
}
obj@data <- obj@data[!duplicated(obj@data), , drop = FALSE]
if (obj@misc$nValues != -1) {
obj@misc$nValues <- nrow(obj@data)
}
return(obj)
}
# Read default parameter from config
.read_default_data <- function(prec, ss) {
for (i in seq(along = prec@parameters)) {
# assign('test', prec@parameters[[i]], globalenv())
# if (i == 342) browser()
# if (prec@parameters[[i]]@name == "pTechRet") browser() # DEBUG
if (any(prec@parameters[[i]]@inClass$colName != "")) {
prec@parameters[[i]]@defVal <-
as.numeric(ss@defVal[1, prec@parameters[[i]]@inClass$colName])
prec@parameters[[i]]@interpolation <-
as.character(ss@interpolation[1, prec@parameters[[i]]@inClass$colName])
}
}
prec
}
.add_repository <- function(mdl, x) {
if (is(x, "list")) {
for (i in seq_along(x)) {
mdl <- .add.repository(mdl, x[[i]])
}
} else {
mdl <- add(mdl, x)
}
mdl
}
.add_discount_approxim <- function(scen, approxim) {
# browser()
approxim$discountFactor <- .add_dropped_zeros(scen@modInp,
"pDiscountFactor", FALSE)
approxim$discount <- .add_dropped_zeros(scen@modInp, "pDiscount", FALSE)
yy <- approxim$discountFactor
# ll <- NULL
# for (rg in unique(yy$region)) {
# l1 <- yy[yy$region == rg, ]
# l1$value <- cumsum(l1$value)
# if (is.null(ll)) ll <- l1 else ll <- rbind(ll, l1)
# }
# approxim$discountCum <- ll
approxim
}
# Get commodity slice map for interpolate
.get_map_commodity_slice_map <- function(obj) {
xx <- list()
for (i in seq(along = obj@data)) {
for (j in seq(along = obj@data[[i]]@data)) { #
prec <- .add2set(prec, obj@data[[i]]@data[[j]], approxim = approxim)
if (is(obj@data[[i]]@data[[j]], "commodity")) {
if (length(obj@data[[i]]@data[[j]]@timeframe) == 0) {
obj@data[[i]]@data[[j]]@timeframe <- approxim$calendar@default_timeframe
}
commodity_slice_map[[obj@data[[i]]@data[[j]]@name]] <- obj@data[[i]]@data[[j]]@timeframe
}
}
}
}
# Apply func to data in scenario by class and return scenario
.apply_to_code_ret_scen <- function(scen, func, ..., clss = NULL) {
for (i in seq(along = scen@model@data)) {
for (j in seq(along = scen@model@data[[i]]@data)) {
if (is.null(clss) || any(class(scen@model@data[[i]]@data[[j]]) == clss)) {
scen@model@data[[i]]@data[[j]] <- func(scen@model@data[[i]]@data[[j]],
...)
}
}
}
scen
}
# Apply func to data in scenario by class and return list
.apply_to_code_ret_list <- function(scen, func, ..., clss = NULL,
need.name = TRUE) {
rs <- list()
for (i in seq(along = scen@model@data)) {
for (j in seq(along = scen@model@data[[i]]@data)) {
if (is.null(clss) || any(class(scen@model@data[[i]]@data[[j]]) == clss)) {
if (need.name) {
rr <- func(scen@model@data[[i]]@data[[j]], ...)
rs[[rr$name]] <- rr$val
} else {
rs[[length(rs) + 1]] <- func(scen@model@data[[i]]@data[[j]], ...)
}
}
}
}
rs
}
# Fill slice level for commodity if not defined
.fill_default_slice_leve4comm <- function(scen, def.level) {
.apply_to_code_ret_scen(
scen = scen, clss = "commodity", def.level,
func = function(x, def.level) {
if (length(x@timeframe) == 0) x@timeframe <- def.level
x
}
)
}
# Add name for basic set
.add_name_for_basic_set <- function(scen, approxim) {
# browser()
for (i in seq(along = scen@model@data)) {
for (j in seq(along = scen@model@data[[i]]@data)) {
inRange <- withinHorizon(scen@model@data[[i]]@data[[j]], scen@settings)
if (!isFALSE(inRange)) { # NULL is allowed
scen@modInp <- .add2set(scen@modInp,
scen@model@data[[i]]@data[[j]],
approxim)
}
}
}
scen
}
.remove_early_retirment <- function(scen) {
scen <- .apply_to_code_ret_scen(
scen = scen, clss = "technology",
func = function(x) {
x@optimizeRetirement <- FALSE
x
}
)
scen
}
# Add commodity slice_level map to approxim
.get_map_commodity_slice_map <- function(scen) {
.apply_to_code_ret_list(scen = scen, clss = "commodity", func = function(x) {
list(name = x@name, val = x@timeframe)
})
}
# Implement add0 for all parameters
.add2_nthreads_1 <- function(n.thread, max.thread, scen, arg, approxim,
interpolation_start_time, interpolation_count,
len_name) {
# browser()
# A couple of string for progress bar
# !!! ToDo: rewrite selection of columns to be compatible with data.table
num_classes_for_progrees_bar <- sum(c(sapply(scen@model@data,
function(x) length(x@data)),
recursive = TRUE))
# if (num_classes_for_progrees_bar < 50) {
# need.tick <- rep(TRUE, num_classes_for_progrees_bar)
# } else {
# need.tick <- rep(FALSE, num_classes_for_progrees_bar)
# need.tick[trunc(seq(1, num_classes_for_progrees_bar, length.out = 50))] <- TRUE
# }
# Fill DB main data
tmlg <- 0
mnch <- 0
# cat(rep(" ", len_name), sep = "")
k <- 0
time.log.nm <- rep(NA, num_classes_for_progrees_bar)
time.log.tm <- rep(NA, num_classes_for_progrees_bar)
mdinp <- list()
for (i in seq(along = scen@model@data)) {
cat(" Repository '", names(scen@model@data)[i], "'\n", sep = "")
nm <- names(scen@model@data[[i]]@data)
p <- progressr::progressor(along = nm)
for (j in seq(along = scen@model@data[[i]]@data)) {
p(nm[j])
k <- k + 1
# if (inherits(scen@model@data[[i]]@data[[j]], "costs")) browser()
if (k %% max.thread == n.thread) {
tmlg <- tmlg + 1
if (arg$echo) {
.interpolation_message(
scen@model@data[[i]]@data[[j]]@name, k, interpolation_count,
interpolation_start_time = interpolation_start_time, len_name
)
}
p1 <- proc.time()[3]
# tryCatch({
inRange <- withinHorizon(scen@model@data[[i]]@data[[j]], scen@settings)
if (!isFALSE(inRange)) { # NULL is allowed
if (inherits(scen@model@data[[i]]@data[[j]], c("constraint", "costs"))) { #isConstraint
scen@modInp <- .obj2modInp(
scen@modInp,
scen@model@data[[i]]@data[[j]],
approxim = approxim
)
} else {
mdinp[[length(mdinp) + 1]] <- .obj2modInp(
scen@modInp,
scen@model@data[[i]]@data[[j]],
approxim = approxim
)@parameters
}
} else {
# ignore this obj
}
# }, error = function(e) {
# assign('add0_message', list(tracedata = sys.calls(),
# add0_arg = list(obj = scen@modInp, app = scen@model@data[[i]]@data[[j]], approxim = approxim)),
# globalenv())
# message('\nError in .obj2modInp function, additional desc in "add0_message" object\n')
# stop(e)
# })
time.log.nm[tmlg] <- scen@model@data[[i]]@data[[j]]@name
time.log.tm[tmlg] <- proc.time()[3] - p1
# if (need.tick[k] && arg$echo) {
# cat('.')
# flush.console()
# }
}
}
}
# browser()
scen <- .filter_sets(scen)
# require(data.table)
nval <- rep(NA, length(mdinp))
for (pr in names(mdinp[[1]])) { # !!! Rewrite this part with rbindlist
if (scen@modInp@parameters[[pr]]@misc$nValues <= 0) {
if (mdinp[[1]][[pr]]@misc$nValues != -1) {
for (i in seq_along(mdinp)) {
nval[i] <- mdinp[[i]][[pr]]@misc$nValues
}
if (any(nval != 0)) {
scen@modInp@parameters[[pr]]@data <-
# as.data.frame(
rbindlist(
lapply(
mdinp[nval != 0], function(x) {
x[[pr]]@data[1:x[[pr]]@misc$nValues, , drop = FALSE]
})
)
# )
scen@modInp@parameters[[pr]]@misc$nValues <- sum(nval)
}
} else {
stop("should not be here - debug is required")
}
}
}
# browser()
scen@misc$time.log <- data.table(
name = time.log.nm[seq_len(tmlg)],
time = time.log.tm[seq_len(tmlg)], stringsAsFactors = FALSE
)
# if (arg$echo) cat(' ')
# if (arg$echo) {
# .remove_char(len_name)
# }
scen
}
.merge_scen <- function(scen_pr, use_par) {
if (scen_pr[[1]]@modInp@parameters$mCommSlice@misc$nValues == -1) {
stop("have to do")
}
scen <- scen_pr[[1]]
scen_pr <- scen_pr[-1]
for (nm in use_par) {
hh <- sapply(scen_pr, function(x) x@modInp@parameters[[nm]]@misc$nValues)
if (sum(hh) != 0) {
scen@modInp@parameters[[nm]]@data[scen@modInp@parameters[[nm]]@misc$nValues +
sum(hh), ] <- NA
}
for (i in seq_along(hh)[hh != 0]) {
scen@modInp@parameters[[nm]]@data[scen@modInp@parameters[[nm]]@misc$nValues +
1:hh[i], ] <-
scen_pr[[i]]@modInp@parameters[[nm]]@data[1:hh[i], ]
scen@modInp@parameters[[nm]]@misc$nValues <-
scen@modInp@parameters[[nm]]@misc$nValues + hh[i]
}
}
for (i in seq_along(scen_pr)) {
scen@misc$time.log <- rbind(scen@misc$time.log, scen_pr[[i]]@misc$time.log)
}
scen
}
# Implement add0 for all parameters
.get_objects_count <- function(scen) {
sum(c(sapply(scen@model@data, function(x) length(x@data)), recursive = TRUE))
}
.get_objects_len_name <- function(scen) {
(25 + max(c(30, max(c(sapply(scen@model@data, function(x) {
max(sapply(x@data, function(y) nchar(y@name)))
}), recursive = TRUE)))))
}
.interpolation_message <- function(name, num, interpolation_count,
interpolation_start_time, len_name) {
jj <- paste0(
num, " (", interpolation_count, "),",
paste0(rep(" ", max(c(1, 15 - (nchar(name) %% 15)))), collapse = ""),
name, ", time: ", round(proc.time()[3] - interpolation_start_time, 2), "s"
)
# bug "invalid langth.out element - workaround
length_out <- len_name - nchar(jj)
if (length_out < 0) {
len_name <- len_name + abs(length_out)
length_out <- 0
}
jj <- paste0(jj, paste0(rep(" ", length_out), collapse = ""))
# cat(rep_len("\b", len_name), jj, sep = "") # , rep(' ', 100), rep('\b', 100)
}
.remove_char <- function(x) {
if (is.character(x)) x <- nchar(x)
if (x == 0) {
return()
}
n1 <- paste0(rep("\b", x), collapse = "")
cat(n1, paste0(rep(" ", x), collapse = ""), n1, sep = "")
}
.check_constraint <- function(scen) {
cat("Validating constraints\n")
# browser()
# Collect sets data
sets <- list()
for (ss in c(
"tech", "sup", "dem", "stg", "expp", "imp", "trade",
"group", "comm", "region", "year", "slice"
)) {
sets[[ss]] <- .get_data_slot(scen@modInp@parameters[[ss]])[[ss]]
}
add_to_err <- function(err_msg, cns, slt, have, psb) {
if (!all(have %in% psb)) {
have <- unique(have[!(have %in% psb)])
have <- have[!is.na(have)]
tmp <- data.table(value = have, stringsAsFactors = FALSE)
tmp$slot <- slt
tmp$constraint <- cns
return(rbind(err_msg,
tmp[, c("constraint", "slot", "value"), drop = FALSE]
)
)
}
return(err_msg)
}
sets$lag.year <- sets$year
sets$lead.year <- sets$year
err_msg <- NULL
# Check sets in constraints
# cat(" Repository ", names(scen@model@data)[i], "\n")
# nm <- names(scen@model@data)
# p <- progressr::progressor(along = nm)
for (i in seq_along(scen@model@data)) {
cat(" Repository '", names(scen@model@data)[i], "'\n", sep = "")
ii <- sapply(scen@model@data[[i]]@data, class) == "constraint"
nn <- seq_along(scen@model@data[[i]]@data)[ii]
if (length(nn) > 0) {
# cat(" Repository ", names(scen@model@data)[i], "\n")
# browser()
p <- progressr::progressor(along = nn)
}
# nm <- names(scen@model@data[[i]]@data)
for (j in nn) {
# for (j in seq_along(scen@model@data[[i]]@data)[
# sapply(scen@model@data[[i]]@data, class) == "constraint"]) {
# browser()
tmp <- scen@model@data[[i]]@data[[j]]
p(tmp@name)
for (k in colnames(tmp@rhs)) {
if (k != "value" && k != "year") {
err_msg <- add_to_err(err_msg, cns = tmp@name, slt = "rhs",
have = tmp@for.each[[k]], psb = sets[[k]])
}
}
for (u in seq_along(tmp@lhs)) {
for (k in colnames(tmp@lhs[[u]]@mult)) {
if (k != "value" && k != "year") {
err_msg <- add_to_err(err_msg, cns = tmp@name,
slt = paste0("lhs (", u, ") mult"),
have = tmp@lhs[[u]]@mult[[k]], psb = sets[[k]])
}
}
for (k in names(tmp@lhs[[u]]@for.sum)) {
if (k != "value" && k != "year" && !all(is.na(tmp@lhs[[u]]@for.sum[[k]]))) {
err_msg <- add_to_err(err_msg, cns = tmp@name,
slt = paste0("lhs (", u, ") for.sum"),
have = tmp@lhs[[u]]@for.sum[[k]], psb = sets[[k]])
}
}
}
}
}
if (!is.null(err_msg) && nrow(err_msg) > 0) {
nn <- capture.output(err_msg)
# print(err_msg); stop("Unknow sets in constrint(s)")
try({
err_msg0 <- err_msg |>
lapply(function(x) {head(unique(x), 3)}) |>
paste(collapse = "\n ")
err_msg0 <- c(" ", err_msg0, "\n...\n",
"See 'scen@misc$dropped_data' for details."
)
})
# browser()
warning("\nUnused (ignored) sets in constraints: \n", head(err_msg0))
}
}
.check_weather <- function(scen) {
cat("Validating weather-sets\n")
# browser()
weather <- scen@modInp@parameters$weather@data$weather
err_msg <- list()
pars <- names(scen@modInp@parameters)[sapply(scen@modInp@parameters, function(x) {
!is.null(x@data$weather) &&
nrow(x@data) != 0
})]
# browser()
p <- progressr::progressor(along = pars)
for (pr in pars) {
p(pr)
tmp <- scen@modInp@parameters[[pr]]@data
tmp <- tmp[!is.na(tmp$weather) & !(tmp$weather %in% weather), ,
drop = FALSE]
if (nrow(tmp) != 0) err_msg[[pr]] <- tmp
}
if (length(err_msg) != 0) {
nn <- capture.output(err_msg)
stop(paste0("Unknow 'weather' set in parameters\n", paste0(nn, collapse = "\n")))
}
}
# unrecognized sets ####
.check_sets <- function(scen) {
cat("Validating sets\n")
# browser()
lsets <- lapply(scen@modInp@parameters, function(x) {
if (x@type == "set") .get_data_slot(x)[[1]]
})
lsets <- lsets[!sapply(lsets, is.null)]
# Add alias for set
lsets$src <- lsets$region
lsets$dst <- lsets$region
dset <- unique(c(lapply(scen@modInp@parameters,
function(x) x@dimSets), recursive = TRUE))
dset <- dset[!(dset %in% names(lsets))]
for (ss in dset) {
i <- 1
while (i <= length(lsets) && length(grep(names(lsets)[i], ss)) != 1) i <- i + 1
if (i > length(lsets)) stop("Internal error. Alias problem")
lsets[[ss]] <- lsets[[i]]
}
error_duplicated_value <- NULL
err_dtf <- NULL
int_err <- NULL
nm <- names(scen@modInp@parameters)
p <- progressr::progressor(along = nm)
for (prm in scen@modInp@parameters) {
p(prm@name)
# if (grepl("CESR_.+_4", prm@name)) browser()
if (!all(prm@dimSets %in% names(lsets))) {
int_err <- unique(c(int_err, prm@dimSets[!(prm@dimSets %in% names(lsets))]))
} else {
# tmp <- .get_data_slot(prm)[, prm@dimSets, drop = FALSE]
tmp <- .get_data_slot(prm) |> select(prm@dimSets)
for (ss in prm@dimSets) {
unq <- unique(tmp[[ss]])
fl <- !(unq %in% lsets[[ss]])
if (any(fl)) {
# isTRUE(options("en_debug")) browser()
err_dtf <- rbind(err_dtf,
data.table(name = prm@name, set = ss, value = unq[fl]
)
)
}
}
# tmp <- .get_data_slot(prm)[, colnames(prm@data) != "value", drop = FALSE]
tmp <- .get_data_slot(prm) |> select(-any_of("value"))
tmp <- tmp[duplicated(tmp), , drop = FALSE]
# tmp <- filter(duplicated(tmp)) # need if_empty check
if (nrow(tmp) != 0) {
error_duplicated_value <- rbind(
error_duplicated_value,
data.table(name = prm@name,
value = apply(tmp, 1, paste0, collapse = "."))
)
}
}
}
if (length(int_err) != 0) {
err_msg0 <- paste0('Internal error. Unknown set "',
paste0(int_err, collapse = '", "'), '"')
if (isFALSE(getOption("en.debug"))) {
message("Use 'option(en.debug = TRUE)' to ignore this error")
stop(err_msg0)
} else {
message(err_msg0)
browser()
}
}
if (!is.null(err_dtf)) {
assign("unknown_sets", err_dtf, globalenv())
# isTRUE(options("en_debug")) browser()
err_msg <- c(
"Unknown sets (see unknown_sets in .globalenv)\n",
paste0(capture.output(print(head(err_dtf))), collapse = "\n")
)
if (nrow(head(err_dtf)) != nrow(err_dtf)) {
err_msg <- c(err_msg, paste0("\n", nrow(err_dtf) - nrow(head(err_dtf)),
" row(s) dropped"))
}
if (!isTRUE(getOption("en.debug"))) {
message("Use 'option(en.debug = TRUE)' to ignore this error")
stop(err_msg)
} else {
message(err_msg)
}
}
if (!is.null(error_duplicated_value)) {
assign("error_duplicated_value", error_duplicated_value, globalenv())
err_msg <- c(
"Duplicated sets/values (see error_duplicated_value in globalenv)\n",
paste0(capture.output(print(head(error_duplicated_value))),
collapse = "\n")
)
if (nrow(head(error_duplicated_value)) != nrow(error_duplicated_value)) {
err_msg <- c(err_msg, paste0("\n",
nrow(error_duplicated_value) -
nrow(head(error_duplicated_value)),
" row(s) dropped"))
}
# stop(err_msg)
if (isFALSE(getOption("en.debug"))) {
message("Use 'option(en.debug = TRUE)' to ignore this error")
stop(err_msg)
} else {
message(err_msg)
}
}
}
# the function checks if the object (from repository)
# is within the settings@horizon@period, returns TRUE if it is
# FALSE, if beyond the period, and NULL if the object cannot be checked
withinHorizon <- function(obj, settings) {
# return(T)
# browser()
# if (inherits(obj, "trade")) browser()
if (inherits(obj, "constraint")) return(NULL)
# if (T) { ## Debug
# if (grepl("", obj@name)) browser()
# }
# yrs <- range()
yrs <- settings@horizon@period
ret <- NULL # return NULL if not applicable to the object
# check stock
sn <- slotNames(obj)
if (any(sn == "capacity")) {
stock <- obj@capacity |>
select(any_of(c("region", "year")), stock) |>
filter(!is.na(stock)) |> unique()
# stock <- obj@stock # !!! add check for interpolation rule or interpolate first
if (nrow(stock) > 0) {
if (all(is.na(stock$year))) return(TRUE) # years are not defined
if (any(stock$year >= min(yrs)) && any(stock$stock[!is.na(stock$stock)] > 0)) {
return(TRUE) # capacity exists within the period
} else {
ret <- FALSE
}
}
}
if (any(sn == "end")) {
if (is.data.frame(obj@end)) {
end <- obj@end$end
} else {
end <- obj@end
}
if (is.null(end) || is_empty(end)) {
end <- TRUE
} else if (any(is.na(end))) { # at least in one region
end <- TRUE
} else if (!all(end < min(yrs))) {
end <- TRUE
} else {
end <- FALSE
return(FALSE) # not available for investment
}
# if (end == TRUE) { supposed to be true
if (is.data.frame(obj@start)) {
start <- obj@start$start
} else {
start <- obj@start
}
if (is.null(start) || is_empty(start)) {
start <- TRUE
} else if (any(is.na(start))) { # at least in one region
start <- TRUE
} else if (!all(start > max(yrs))) {
start <- TRUE
} else {
start <- FALSE
return(FALSE) # not available for investment
}
if (end & start) return(TRUE)
ret <- FALSE
# }
}
return(ret)
}
# filter data for non-valid sets
.filter_sets <- function(scen) {
# browser()
dropped <- list() # log removed data
set_names <- names(scen@modInp@set)
for (i in seq_along(scen@modInp@parameters)) {
x <- scen@modInp@parameters[[i]]
ii <- x@dimSets %in% set_names
for (s in x@dimSets[ii]) {
kk <- x@data[[s]] %in% scen@modInp@set[[s]]
if (!all(kk)) {
dropped[[x@name]] <- x@data[!kk,]
x@data <- x@data[kk,]
x@misc$nValues <- x@misc$nValues - length(sum(!kk))
scen@modInp@parameters[[i]] <- x
}
}
}
scen@misc$dropped_data <- dropped
scen
}
interpolate_slot <- function(
x,
keys = c("region", "slice", "comm", "acomm", "tech", "process",
"weather", "stg", "sub", "dst", "src"),
year_seq = NULL,
val = "value"
) {
# browser()
if (!is.null(x$year)) {
# year_seq = full_seq(c(x$year, year_seq), 1)
if (is.null(year_seq)) year_seq = full_seq(x$year, 1)
x <- x |>
group_by(
across(any_of(keys))
) |>
complete(year = year_seq) |>
ungroup()
if (!is.null(val) && !is.na(val)) {
x <- x |>
mutate(
{{val}} := zoo::na.approx(.data[[val]], x = year)
)
}
}
# if (is.null(year_seq)) year_seq = full_seq(x$year, 1)
#
# mutate(
# {{val}} := zoo::na.approx(.data[[val]], x = year)
# ) |>
# as.data.table() |>
# ungroup()
x
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.