Skip to content

Commit

Permalink
Read ST clusters with readAntares() (#252)
Browse files Browse the repository at this point in the history
* Add .importOutputForSTClusters()

* Add 'clustersST' argument in readAntares()

* create a wrapper for calling .reshape_details_file()

* Simplify .get_value_columns_details_file() with a reference table

* Correct areasWithSTClusters parameter in .getSimOptions()

* Add unit tests for 'areasWithSTClusters' parameter

* Add DETAILS_FILES_TYPE column in the simulation_variables_names_by_support.csv

* Update NEWS.md

* Make new parameter 'clustersST' API compatible

* Update documentation with the new function .importOutputForSTClusters()

* Import simulation_variables_names_by_support.csv in data.frame type rather than data.table

* Specify the separator for the simulation_variables_names_by_support.csv import

* Check reverse dependencies

* revdep check ok
  • Loading branch information
boitardn authored Jun 14, 2024
1 parent 0e7628a commit d2d30ef
Show file tree
Hide file tree
Showing 15 changed files with 266 additions and 84 deletions.
4 changes: 3 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Authors@R: c(
person("Clement", "Berthet", role = "ctb"),
person("Kamel", "Kemiha", role = "ctb"),
person("Abdallah", "Mahoudi", role = "ctb"),
person("Nicolas", "Boitard", role = "ctb"),
person("RTE", role = "cph")
)
Description: Import, manipulate and explore results generated by 'Antares', a
Expand All @@ -40,7 +41,8 @@ Imports:
utils,
memuse,
purrr,
lifecycle
lifecycle,
assertthat
Suggests:
rhdf5 (>= 2.24.0),
testthat,
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import(doParallel)
import(jsonlite)
import(parallel)
import(plyr)
importFrom(assertthat,assert_that)
importFrom(doParallel,registerDoParallel)
importFrom(grDevices,col2rgb)
importFrom(grDevices,rgb)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ NEW FEATURES:
* `readInputRES()` new parameter **areas** to get desired clusters from selected areas.
* `setSimulationPath()` return a new parameter `binding` (for studies >= v8.7.0).
It contains a table with group dimensions of time series for binding constraints.
* `readAntares()` new parameter **clustersST** to read (output simulation) short-term clusters

BREAKING CHANGES :

Expand All @@ -18,6 +19,7 @@ BREAKING CHANGES :
BUGFIXES :

* `readInputThermal()` return data from file data.txt with `thermalData` parameter
* `setSimulationPath()` has also the parameter **areasWithSTClusters** in 'output' mode


# antaresRead 2.7.0
Expand Down
167 changes: 92 additions & 75 deletions R/importOutput.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#' - "areas", "values" => areas
#' - "areas", "details" => clusters
#' - "areas", "details-res" => renewables clusters
#' - "areas", "details-STstorage" => short-term clusters
#' - "links", "values" => links
#'
#' @return
Expand Down Expand Up @@ -281,30 +282,37 @@

#' .get_value_columns_details_file
#'
#' Private function used to get the column names for the details-timeStep.txt or details-res-timeStep.txt.
#' Used in .importOutputForClusters() and .importOutputForResClusters()
#' Private function used to get the column names for the details-timeStep.txt, details-res-timeStep.txt, or details-STstorage-timeStep.txt.
#' Used in .importOutputForClusters(), .importOutputForResClusters(), and .importOutputForSTClusters()
#' From the opts, we detect which outputs the user decides to take
#'
#' @return
#' a vector
#'
#' @importFrom assertthat assert_that
#'
#' @noRd
#'
.get_value_columns_details_file <- function(opts, type) {

if(type == "details") {
# Order is important. There is a correspondance between elements.
all_thematic_variables <- c("DTG by plant", "NP Cost by plant", "NODU by plant")
colNames <- c("production", "NP Cost", "NODU")
if (opts$antaresVersion >= 830){
all_thematic_variables <- c(all_thematic_variables, "Profit by plant")
colNames <- c(colNames, "profit")
}
} else if(type == "details-res") {
# Order is important. There is a correspondance between elements.
all_thematic_variables <- c("RES generation by plant")
colNames <- c("production")
}
assert_that(type %in% c("details","details-res","details-STstorage"))

simulation_variables_names_by_support <- read.table(system.file(
"format_output","simulation_variables_names_by_support.csv",package="antaresRead"
),sep=";",fileEncoding="UTF-8",header = TRUE)

filtered_variables_names <- subset(simulation_variables_names_by_support,DETAILS_FILES_TYPE==type)
if (type=="details" && opts$antaresVersion < 830)
filtered_variables_names <- subset(filtered_variables_names,ANTARES_DISPLAYED_NAME!="Profit by plant")

# Order is important. There is a correspondance between elements
ordered_filtered_variables_names <- filtered_variables_names[
order(filtered_variables_names$ORDINAL_POSITION_BY_TOPIC),
]

all_thematic_variables <- ordered_filtered_variables_names$ANTARES_DISPLAYED_NAME
colNames <- ordered_filtered_variables_names$RPACKAGE_DISPLAYED_NAME

# With thematic-trimming enabled
if (opts$parameters$general$`thematic-trimming`) {
if ("variables selection" %in% names(opts$parameters)) {
Expand Down Expand Up @@ -346,36 +354,8 @@
.importOutputForClusters <- function(areas, timeStep, select = NULL, mcYears = NULL,
showProgress, opts, mustRun = FALSE, parallel) {

# In output files, there is one file per area with the follwing form:
# cluster1-var1 | cluster2-var1 | cluster1-var2 | cluster2-var2
# the following function reshapes the result to have variable cluster in column.
# To improve greatly the performance we use our knowledge of the position of
# the columns instead of using more general functions like dcast.
reshapeFun <- function(x) {

# Get cluster names
n <- names(x)
idx <- ! n %in% pkgEnv$idVars
clusterNames <- tolower(unique(n[idx]))

# Id vars names
idVarsId <- which(!idx)
idVarsNames <- n[idVarsId]

# Column names of the output table
colNames <- .get_value_columns_details_file(opts, "details")

# Loop over clusters
nclusters <- length(clusterNames)

res <- llply(1:nclusters, function(i) {
dt <- x[, c(nclusters * 0:(length(colNames) - 1) + i, idVarsId), with = FALSE]
setnames(dt, c(colNames, idVarsNames))
dt[, cluster := as.factor(clusterNames[i])]
dt
})

rbindlist(res)
reshapeFun <- function(x){
.reshape_details_file(x,file_type="details",opts=opts)
}

if (!mustRun) {
Expand Down Expand Up @@ -488,6 +468,47 @@
}


#' .reshape_details_file
#'
#' In output files, there is one file per area with the follwing form:
#' cluster1-var1 | cluster2-var1 | cluster1-var2 | cluster2-var2
#' the following function reshapes the result to have variable cluster in column.
#' To improve greatly the performance we use our knowledge of the position of
#' the columns instead of using more general functions like dcast.
#'
#' @return
#' a data.table
#'
#' @noRd
#'
.reshape_details_file <- function(x,file_type,opts) {

# Get cluster names
n <- names(x)
idx <- ! n %in% pkgEnv$idVars
clusterNames <- tolower(unique(n[idx]))

# Id vars names
idVarsId <- which(!idx)
idVarsNames <- n[idVarsId]

# Column names of the output table
colNames <- .get_value_columns_details_file(opts=opts,type=file_type)

# Loop over clusters
nclusters <- length(clusterNames)

res <- llply(1:nclusters, function(i) {
dt <- x[, c(nclusters * 0:(length(colNames) - 1) + i, idVarsId), with = FALSE]
setnames(dt, c(colNames, idVarsNames))
dt[, cluster := as.factor(clusterNames[i])]
dt
})

rbindlist(res)
}


#' .importOutputForResClusters
#'
#' Private function used to import the output for the renewable clusters of one area
Expand All @@ -500,38 +521,11 @@
.importOutputForResClusters <- function(areas, timeStep, select = NULL, mcYears = NULL,
showProgress, opts, parallel) {

# In output files, there is one file per area with the follwing form:
# cluster1-var1 | cluster2-var1 | cluster1-var2 | cluster2-var2
# the following function reshapes the result to have variable cluster in column.
# To improve greatly the performance we use our knowledge of the position of
# the columns instead of using more general functions like dcast.

reshapeFun <- function(x) {

# Get cluster names
n <- names(x)
idx <- ! n %in% pkgEnv$idVars
clusterNames <- tolower(unique(n[idx]))

# Id vars names
idVarsId <- which(!idx)
idVarsNames <- n[idVarsId]

# Column names of the output table
colNames <- .get_value_columns_details_file(opts, "details-res")

# Loop over clusters
nclusters <- length(clusterNames)

res <- llply(1:nclusters, function(i) {
dt <- x[, c(nclusters * 0:(length(colNames) - 1) + i, idVarsId), with = FALSE]
setnames(dt, c(colNames, idVarsNames))
dt[, cluster := as.factor(clusterNames[i])]
dt
})

rbindlist(res)
.reshape_details_file(x,file_type="details-res",opts=opts)
}

suppressWarnings(
.importOutput("areas", "details-res", "area", areas, timeStep, NULL,
mcYears, showProgress, opts, reshapeFun, sameNames = FALSE,
Expand All @@ -540,6 +534,29 @@
}


#' .importOutputForSTClusters
#'
#' Private function used to import the output for the short-term clusters of one area
#'
#' @return
#' a data.table
#'
#' @noRd
#'
.importOutputForSTClusters <- function(areas, timeStep, select = NULL, mcYears = NULL,
showProgress, opts, parallel) {

reshapeFun <- function(x) {
.reshape_details_file(x,file_type="details-STstorage",opts=opts)
}

suppressWarnings(
.importOutput("areas", "details-STstorage", "area", areas, timeStep, NULL,
mcYears, showProgress, opts, reshapeFun, sameNames = FALSE,
objectDisplayName = "clustersST", parallel = parallel)
)
}

#' .importOutputForBindingConstraints
#'
#' Private function used to import the output for binding constraints.
Expand Down
32 changes: 27 additions & 5 deletions R/readAntares.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#' Read the data of an Antares simulation
#'
#' @description
#' `r antaresRead:::badge_api_ok()`
#'
#' \code{readAntares} is a swiss-army-knife function used to read almost every
#' possible time series of an antares Project at any desired time resolution
#' (hourly, daily, weekly, monthly or annual).
Expand Down Expand Up @@ -85,6 +87,11 @@
#' import results at renewable cluster level. If \code{NULL} no cluster is imported. The
#' special value \code{"all"} tells the function to import renewable clusters from all
#' areas.
#' @param clustersST
#' Vector containing the name of the areas for which you want to
#' import results at short-term cluster level. If \code{NULL} no cluster is imported. The
#' special value \code{"all"} tells the function to import short-term clusters from all
#' areas.
#' @param bindingConstraints
#' Should binding constraints be imported (v8.4+)?
#' @param districts
Expand Down Expand Up @@ -210,8 +217,8 @@
#' @export
#'
readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
districts = NULL, clustersRes = NULL, bindingConstraints = FALSE,
misc = FALSE, thermalAvailabilities = FALSE,
districts = NULL, clustersRes = NULL, clustersST = NULL,
bindingConstraints = FALSE, misc = FALSE, thermalAvailabilities = FALSE,
hydroStorage = FALSE, hydroStorageMaxPower = FALSE,
reserve = FALSE, linkCapacity = FALSE, mustRun = FALSE,
thermalModulation = FALSE,
Expand All @@ -221,7 +228,7 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
mcWeights = NULL,
opts = simOptions(),
parallel = FALSE, simplify = TRUE, showProgress = TRUE) {

if((!is.null(opts$parameters$`other preferences`$`renewable-generation-modelling`) &&
!opts$parameters$`other preferences`$`renewable-generation-modelling` %in% "clusters") ||
is.null(opts$parameters$`other preferences`$`renewable-generation-modelling`)){
Expand Down Expand Up @@ -309,6 +316,7 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
links = links,
clusters = clusters,
clustersRes = clustersRes,
clustersST = clustersST,
districts = districts,
mcYears = mcYears)

Expand All @@ -317,6 +325,7 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
links <- reqInfos$links
clusters <- reqInfos$clusters
clustersRes <- reqInfos$clustersRes
clustersST <- reqInfos$clustersST
districts <- reqInfos$districts
mcYears <- reqInfos$mcYears
synthesis <- reqInfos$synthesis
Expand All @@ -328,7 +337,7 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
return(aggregateResult(opts = opts,
verbose = showProgress,
filtering = TRUE,
selected = list(areas = areas, links = links, clusters = clusters, clustersRes = clustersRes),
selected = list(areas = areas, links = links, clusters = clusters, clustersRes = clustersRes, clustersST = clustersST),
timestep = timeStep,
writeOutput = FALSE,
mcWeights = mcWeights, mcYears = mcYears))
Expand All @@ -342,7 +351,7 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
}

# If all arguments are NULL, import all areas
if (is.null(areas) & is.null(links) & is.null(clusters) & is.null(clustersRes) & is.null(districts)) {
if (is.null(areas) & is.null(links) & is.null(clusters) & is.null(clustersRes) & is.null(clustersST) & is.null(districts)) {
areas <- "all"
}

Expand All @@ -353,6 +362,7 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
links <- .checkArg(links, opts$linkList, "Links %s do not exist in the simulation.")
clusters <- .checkArg(clusters, opts$areasWithClusters, "Areas %s do not exist in the simulation or do not have any thermal cluster.")
clustersRes <- .checkArg(clustersRes, opts$areasWithResClusters, "Areas %s do not exist in the simulation or do not have any renewable cluster.")
clustersST <- .checkArg(clustersST, opts$areasWithSTClusters, "Areas %s do not exist in the simulation or do not have any short-term cluster.")
districts <- .checkArg(districts, opts$districtList, "Districts %s do not exist in the simulation.")
mcYears <- .checkArg(mcYears, opts$mcYears, "Monte-Carlo years %s have not been exported.", allowDup = TRUE)

Expand Down Expand Up @@ -476,6 +486,12 @@ readAntares <- function(areas = NULL, links = NULL, clusters = NULL,
opts, parallel = parallel)
if(!is.null(res$clustersRes) && nrow(res$clustersRes) == 0) res$clustersRes <- NULL

# Import short-term clusters
res$clustersST <- .importOutputForSTClusters(clustersST, timeStep, NULL,
mcYears, showProgress,
opts, parallel = parallel)
if(!is.null(res$clustersST) && nrow(res$clustersST) == 0) res$clustersST <- NULL

# Import thermal clusters and eventually must run
if (!mustRun) {
res$clusters <- .importOutputForClusters(clusters, timeStep, NULL, mcYears,
Expand Down Expand Up @@ -820,6 +836,7 @@ readAntaresAreas <- function(areas, links = TRUE, clusters = TRUE, clustersRes =
links,
clusters,
clustersRes,
clustersST,
districts,
mcYears){

Expand Down Expand Up @@ -873,6 +890,10 @@ readAntaresAreas <- function(areas, links = TRUE, clusters = TRUE, clustersRes =
if (!is.null(areas)) clustersRes <- areas
else clustersRes <- "all"
}
if ("clustersST" %in% unlist(select) & is.null(clustersST)) {
if (!is.null(areas)) clustersST <- areas
else clustersST <- "all"
}
if ("mcYears" %in% unlist(select) & is.null(mcYears)) mcYears <- "all"

# If all arguments are NULL, import all areas
Expand All @@ -888,6 +909,7 @@ readAntaresAreas <- function(areas, links = TRUE, clusters = TRUE, clustersRes =
links = links,
clusters = clusters,
clustersRes = clustersRes,
clustersST = clustersST,
districts = districts,
mcYears = mcYears,
synthesis = synthesis,
Expand Down
Loading

0 comments on commit d2d30ef

Please sign in to comment.