# class model ####
# setTimeSlices <- .setTimeSlices
#' An S4 class to represent model
#'
#' @name class-model
#'
#' @slot name `r get_slot_info("model", "name")`
#' @slot desc `r get_slot_info("model", "desc")`
#' @slot data `r get_slot_info("model", "data")`
#' @slot config `r get_slot_info("model", "config")`
#' @slot misc `r get_slot_info("model", "misc")`
#'
#' @include class-config.R class-repository.R
#'
#' @export
setClass("model",
representation(
name = "character",
desc = "character", # Details
data = "list",
config = "config",
# LECdata = "list",
# optimizeRetirement = "logical",
misc = "list"
),
prototype(
name = "",
desc = "", # Details
data = list(),
config = new("config"),
# LECdata = list(),
# optimizeRetirement = FALSE,
misc = list()
),
S3methods = FALSE
)
setMethod("initialize", "model", function(.Object, ...) {
.Object
})
# add <- function(...) UseMethod("add")
#' Create new model object
#'
#' @param name name of the model
#' @param ... configuration parameters (see class config) and model elements (classes commodity, technology, etc.)
#'
#' @return model object containing model elements (`@data`) and configuration (`@config`)
#' @rdname newModel
#' @family model scenario
#' @export
#'
#' @examples
#' \dontrun{
#' mod <- newModel(
#' name = "MyModel",
#' desc = "My first model",
#' data = model_repository,
#' discount = 0.05,
#' horizon = newHorizon(period = 2020:2050,
#' intervals = rep(5, 10)),
#' calendar = calendars$d365h24
#' )
#' }
newModel <- function(name = "", desc = "", ...) {
# browser()
# mdl <- .data2slots("model", name,
# ignore_args = unique(c(config_slots, horizon_slots)),
# ignore_classes = "repository", ...)
obj <- new("model")
obj@name <- name
obj@desc <- desc
arg <- list(...)
if (is_empty(arg)) return(obj)
#
## named slots ####
repo <- newRepository("default")
### @misc ####
if (!is.null(arg$misc)) {
if (!inherits(arg$misc, "list")) stop('"misc" must be a named list')
if (is_empty(obj@misc)) {
obj@misc <- arg$misc
} else {
obj@misc <- c(obj@misc, arg$misc)
}
arg$misc <- NULL}
### @data | @repository ####
if (!is.null(arg$data) | !is.null(arg$repository)) {
if (is.null(arg$data)) {
arg$data <- arg$repository; arg$repository <- NULL
} else {
if (!is.null(arg$repository))
stop("Only one of 'data' or 'repository' arguments can be assigned.")
}
if (inherits(arg$data, c("repository"))) {
repo <- arg$data
} else if (!inherits(arg$data, "list")) {
repo <- do.call("add", c(object = repo, arg$data))
} else {
stop('"data" ("repository") must be a "repository" or "list" object')
}
# obj@data <- repo@data
obj <- add(obj, arg$data)
arg$data <- NULL
}
### @config ####
if (!is.null(arg$config)) {
if (!inherits(arg$config, "config")) {
stop('"config" argument must be an object of class "cofig"')
}
obj@config <- arg$config
arg$config <- NULL
}
### @horizon ####
if (!is.null(arg$horizon)) {
if (!inherits(arg$horizon, "horizon")) {
stop('"horizon" argument must be an object of class "horizon"')
}
obj@config@horizon <- arg$horizon
arg$horizon <- NULL
}
### @horizon ####
if (!is.null(arg$calendar)) {
if (!inherits(arg$calendar, "calendar")) {
stop('"calendar" argument must be an object of class "calendar"')
}
obj@config@calendar <- arg$calendar
arg$calendar <- NULL
}
if (is_empty(arg)) return(obj)
#
## unnamed args, process by class ####
### repository objects ####
ii <- sapply(arg, function(x) inherits(x, c("repository")))
if (any(ii)) {
for (ob in arg[ii]) {obj <- add(obj, ob)}
}
arg <- arg[!ii]
### @config obj ####
ii <- sapply(arg, function(x) inherits(x, c("config")))
if (any(ii)) {
if (sum(ii) > 1) stop('Two or more "config" objects found.')
obj@config <- arg[ii]
arg[ii] <- NULL
}
### @horizon obj ####
ii <- sapply(arg, function(x) inherits(x, c("horizon")))
if (any(ii)) {
if (sum(ii) > 1) stop('Two or more "horizon" objects found.')
obj@config@horizon <- arg[ii]
arg[ii] <- NULL
}
if (is_empty(arg)) return(obj)
#
## named other slots ####
ex_slots <- c(".S3Class", "name", "desc")
### @config slots ####
config_slots <- names(getSlots("config"))
config_slots <- config_slots[!(config_slots %in% ex_slots)]
ii <- names(arg) %in% config_slots
if (any(ii)) {
obj@config <- do.call("update", c(object = obj@config, arg[ii]))
arg[ii] <- NULL
}
if (is_empty(arg)) return(obj)
### @horizon slots #### !!! write update(config) with config & horizon slots
horizon_slots <- names(getSlots("horizon"))
horizon_slots <- horizon_slots[!(horizon_slots %in% ex_slots)]
ii <- names(arg) %in% horizon_slots
if (any(ii)) {
obj@config@horizon <- .data2slots("horizon", obj@config@horizon, arg[ii])
obj@config@horizon <- do.call("update",
c(object = obj@config@horizon, arg[ii]))
arg[ii] <- NULL
}
if (is_empty(arg)) return(obj)
ii <- sapply(arg, inherits, what = newRepository()@permit)
if (any(ii)) obj <- add(obj, arg[ii])
arg <- arg[!ii]
if (is_empty(arg)) return(obj)
warning("Ignoring ", length(arg), " arguments.\n",
"names: ", paste(names(arg), collapse = ", "), "\nclasses: ",
paste(sapply(arg, class), collapse = ", "))
obj
#
# config_slots <- config_slots[config_slots %in% names(args)]
# mdl@config <- .data2slots(
# "config", "", ignore_classes = "repository",
# ignore_args = c("slice", names(args)[!(names(args) %in% config_slots)]),
# ...)
# # ignore_args = c(names(args)[!(names(args) %in% config_slots)], mlst_vec), ...)
#
# if (any(names(args) == "slice")) {
# mdl@config <- setTimeSlices(mdl@config, slice = args$slice)
# } else {
# mdl@config <- setTimeSlices(mdl@config, slice = "ANNUAL")
# }
#
# # args <- list(...)
# # if (any(names(args) %in% mlst_vec)) {
# # if (sum(names(args) %in% mlst_vec) != 2) stop('Undefined all need parameters for setMileStoneYears')
# # mdl <- setMileStoneYears(mdl, start = args$start, interval = args$interval)
# # }
# mdl
}
#' @rdname newModel
#' @export
setMethod("setHorizon", signature(obj = "model"),
# signature(obj = "model", period = "numeric", intervals = "numeric"),
function(obj, ...) {
args <- list(...)
# browser()
has_h <- sapply(args, function(x) inherits(x, "horizon"))
if (any(has_h)) {
if (sum(has_h) > 1) stop('Two or more "horizon" objects found.')
obj@config@horizon <- args[has_h]
} else {
obj@config <- setHorizon(obj@config, ...)
}
obj
}
)
#' @rdname newModel
#' @export
setMethod("getHorizon", signature(obj = "model"), function(obj) {
getHorizon(obj@config)
})
# Methods ####
## [[ ####
#' @export
setMethod("[[", c("model", "ANY"), function(x, i) {
# browser()
flatten_mod_data(x@data)[i]
}
)
#' @export
setMethod("[", c("model", "ANY"), function(x, i) {
# browser()
flatten_mod_data(x@data)[i]
}
)
## $ ####
#' @export
setMethod("$", "repository", function(x, name) x@data[[name]])
setReplaceMethod("$", c("repository", "ANY"),
function(x, name, value) {
nm <- names(x@data)
ii <- which(nm == value@name)
if (length(ii) > 0) {
# replace name
nm[ii] <- value@name
x@data[[name]] <- value
names(x@data) <- nm
} else {
x@data[[name]] <- value
}
x
}
)
## names ####
#' @export
#' @family repository
setMethod("names", "repository", function(x) names(x@data))
add.model <- function(obj, ..., overwrite = FALSE, repo_name = NULL) {
# browser()
# cls <- c('technology', 'commodity', 'region', 'commodity',
# 'constraint', 'costs',
# 'stock', 'reserve',
# 'supply', 'weather', 'demand',
# 'trade', 'export', 'import', 'storage', 'tax', 'sub')
cls <- newRepository()@permit
# if (class(obj) != "model") stop('Applying add.model to class ', class(obj))
arg <- list(...)
while (any(sapply(arg, function(x) class(x)[1] == 'list'))) {
# fl <- seq_along(arg)[sapply(arg, class) == 'list']
# for (i in fl) {
# for (j in seq_along(arg[[i]])) {
# arg[[length(arg) + 1]] <- arg[[i]][[j]]
# }
# }
# arg <- arg[-fl]
arg <- list_flatten(arg, name_spec = "{inner}")
}
## Calendar from solve must be added to interpolate
arg_classes <- sapply(arg, class)
# if (any(arg_classes == "calendar")) {
# if (length(arg_classes[arg_classes == "calendar"]) > 1) {
# stop("Only one calendar object is allowed")
# }
# obj@data$calendar <- arg[arg_classes == "calendar"]
# arg <- arg[arg_classes != "calendar"]
# }
## Add to repository
if (any(!(sapply(arg, class) %in% c(cls, 'repository')))) {
stop(paste('Unknown class "', paste(unique(sapply(arg, class)[
!(sapply(arg, class) %in% c(cls, 'repository'))]), collapse = '", "'),
'"', sep = ''))
}
# cc <- sapply(arg, function(x) class(x)[1])
ii <- sapply(arg, function(x) inherits(x, cls))
if (any(ii)) {
# arg <- arg[cc != 'repository']
# Generate name
if (is.null(repo_name)) {
# if (length(obj@data) >= 1) {
# # repo_name <- obj@data[[length(obj@data)]]@name
# repo_name <- names(obj@data)[length(obj@data)]
# warning('"repo_name" is not specified, adding objects to "',
# repo_name, '" repository')
# } else {
# if (length(obj@data) == 0) {
add_repo <- new('repository', repo_name)
repo_name <- add_repo@name
# repo_name <- "default_repository"
if (is.null(obj@data[[repo_name]])) {
obj@data[[repo_name]] <- add_repo
}
# repo_name <- obj@data[[1]]@name # default name
# }
} else {
ff <- c(sapply(obj@data, function(x) x@name), recursive = TRUE)
if (all(ff != repo_name)) {
obj@data[[repo_name]] <- new('repository', name = repo_name)
}
}
ff <- c(sapply(obj@data, function(x) x@name), recursive = TRUE)
fl <- seq(alon = ff)[ff == repo_name]
for (i in seq(along = arg[ii])) {
obj@data[[fl]] <- add(obj@data[[fl]], arg[ii][[i]], overwrite = overwrite)
}
}
arg <- arg[!ii]
if (is_empty(arg)) return(obj)
# cc <- sapply(arg, function(x) class(x)[1])
ii <- sapply(arg, function(x) inherits(x, "repository"))
if (any(ii)) {
# if (any(sapply(arg, class) != 'repository'))
# stop('You can not mix class repository and other for command add')
# arg <- arg[sapply(arg, class) == 'repository']
ff <- c(sapply(obj@data, function(x) x@name), recursive = TRUE)
for (i in seq(along = arg[ii])) {
nm <- arg[ii][[i]]@name # new repository name
if (nm == "") stop('Empty repository name is not allowed.')
if (any(ff == nm)) {
# add data to existing repository
obj@data[[nm]] <- add(obj@data[[nm]], arg[ii][[i]])
} else {
# !!! add name-check with other repositories
obj@data[[nm]] <- arg[ii][[i]]
}
}
arg <- arg[!ii]
}
# check duplicated names in class
hh <- c(
sapply(obj@data, function(x) {
sapply(x@data, function(y) paste(class(y), ' - ', y@name, sep = ''))
}), recursive = TRUE)
if (anyDuplicated(hh)) {
hh <- unique(hh[duplicated(hh)])
stop('Duplicated objects in "class - name"\n',
paste(hh, sep = "\n"))
}
## check duplicated names in all objects
ff <- c(lapply(obj@data, function(x) sapply(x@data, function(y) y@name)),
recursive = TRUE)
if (anyDuplicated(ff)) {
stop(paste('Duplicated objects "',
paste(unique(ff[duplicated(ff)]), collapse = '", "'),
'"', sep = ''))
}
if (length(arg) > 0) {
warning("Ignored objects: ", paste(names(arg), ", "))
}
obj
}
#' Add an object to the model's repository
#'
#' @param obj model object
#' @param ... model elements, allowed classes: ...
#' @param overwrite logical, if TRUE, objects with the same name will be overwritten, error will be reported if FALSE
#' @param repo_name character, optional name of a (sub-)repository to add the object.
#'
#' @method add model
#' @rdname add
#'
#' @return model object with added elements to the repository
#' @export
setMethod("add", "model", add.model)
summary.model <- function(object, ...) {
cat("Model: ", object@name, "\n")
cat("Description: ", object@desc, "\n")
cat("Repositories: ", names(object@data), "\n")
# cat("Horizon: ", getHorizon(object), "\n")
# cat("Calendar: ", getCalendar(object), "\n")
# invisible(object)
}
#' @export
setMethod("summary", "model", summary.model)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.