R/readClusterDesc.R

Defines functions .convert_list_clusterDesc_to_datatable get_input_cluster_properties .readClusterDesc readClusterSTDesc readClusterResDesc readClusterDesc

Documented in readClusterDesc readClusterResDesc readClusterSTDesc

#Copyright © 2016 RTE Réseau de transport d’électricité

#' Import clusters description
#'
#' @description 
#' This function reads in the input files of an antares study the
#' characteristics of each cluster. 
#' 
#' Be aware that clusters descriptions are read
#' in the input files so they may have changed since a simulation has been run.
#'
#' @inheritParams readAntares
#' @param dot_format `logical` default TRUE to return `character` with "valid" format (see [make.names()]) 
#'
#' @return
#' A data.table with one line per cluster. The columns of the data.table may
#' change between different projects, but there will always be the following 
#' columns:
#' 
#' \item{area}{Name of the area containing the cluster}
#' \item{cluster}{Name of the cluster}
#' \item{group}{Type of cluster (gaz, nuclear, etc.)}
#' \item{unitcount}{number of production units}
#' \item{nominalcapacity}{production capacity of each unit}
#' 
#' The other present columns depends on the version of antares and the options
#' that have been set: if an option is unset for all clusters, it will not 
#' appear in the table.
#' 
#' By default, the function reads the cluster description of the default antares
#' study. You can use the argument \code{opts} to specify another study.
#' 
#' \code{readClusterDesc} : read thermal clusters
#' 
#' \code{readClusterResDesc} : read renewable clusters (Antares >= V8.1)
#' 
#' \code{readClusterSTDesc} : read st-storage clusters (Antares >= V8.6)
#' 
#' If you have no clusters properties, `Null data.table (0 rows and 0 cols)` is returned.
#' 
#' @section Warning:  
#' You have now two format output to display input properties. 
#' Default is format uses by operating team, eg `min.down.time`.
#' Other format is according to antares simulator, eg `min-down-time`.  
#' 
#' All properties are returned with default values according to Antares Study version.
#' 
#' 
#'
#' @examples
#' 
#' \dontrun{
#' 
#' # Default format with "dot separator"
#' 
#' # thermal
#' readClusterDesc()
#' 
#' # renewable
#' readClusterResDesc()
#' 
#' # st-storage
#' readClusterSTDesc()
#' 
#' # Antares Simulator format 
#' 
#' #' # thermal
#' readClusterDesc(dot_format = FALSE)
#' 
#' # renewable
#' readClusterResDesc(dot_format = FALSE)
#' 
#' # st-storage
#' readClusterSTDesc(dot_format = FALSE)
#' 
#' 
#' # By default, the function reads cluster descriptions for the default study,
#' # but it is possible to specify another study with parameter "opts"
#' sim1 <- setSimulationPath()
#' 
#' #[... code that modifies the default antares study]
#' 
#' readClusterDesc(sim1)
#' 
#' }
#' 
#' @export
#' 
#' @rdname readClusterDesc
readClusterDesc <- function(opts = simOptions(), dot_format = TRUE) {
  .readClusterDesc(opts = opts, 
                   dir = "thermal/clusters",
                   dot_format = dot_format)
}

#' @export
#'
#' @rdname readClusterDesc
readClusterResDesc <- function(opts = simOptions(), dot_format = 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`)){
    stop("readClusterDesc is available only on studies with 'renewable-generation-modelling' = 'clusters' (and Antares >= 8.1)", call. = FALSE)
  }
  .readClusterDesc(opts = opts, 
                   dir = "renewables/clusters",
                   dot_format = dot_format)
}


#' @export
#'
#' @rdname readClusterDesc
readClusterSTDesc <- function(opts = simOptions(), dot_format = TRUE) {
  if (opts$antaresVersion < 860) {
    stop("readClusterSTDesc is available only on Antares >= 8.6)", call. = FALSE)
  }
  .readClusterDesc(opts = opts, 
                   dir = "st-storage/clusters",
                   dot_format = dot_format)
}

#' @importFrom stats setNames
.readClusterDesc <- function(opts = simOptions(), 
                             dir = "thermal/clusters",
                             dot_format = TRUE) {
  path <- file.path(opts$inputPath, dir)
  api_study <- is_api_study(opts)

  table_type <- switch(
    dir,
    "thermal/clusters" = "thermals",
    "renewables/clusters" = "renewables",
    "st-storage/clusters" =  "st-storages"
  )
  
  if (api_study) {
    # api request with all columns
    list_clusters <- api_get(
      opts = opts,
      endpoint = paste0(opts$study_id, "/table-mode/", table_type),
      query = list(columns = "")
    )
    
    dt_clusters <- .convert_list_clusterDesc_to_datatable(list_clusters, 
                                                          type = table_type,
                                                          dot_format = dot_format)
  
    return(dt_clusters)
  }
      
  # "text" mode
  areas <- list.files(path)
  
  # READ cluster properties
  properties <- get_input_cluster_properties(table_type = table_type, 
                                             opts = opts, 
                                             dot_format = dot_format)
   
  # read properties for each area
  res <- plyr::llply(areas, function(x, prop_ref=properties) {
    clusters <- readIniFile(file.path(path, x, "list.ini"))
    if (length(clusters) == 0) 
      return(NULL)
    # conversion list to data.frame
    clusters <- plyr::ldply(clusters, function(x){
      df_clust <- data.frame(x, check.names = dot_format) 
      colnames_to_add <- setdiff(names(prop_ref), names(df_clust))
      if(!identical(colnames_to_add, character(0)))
        df_clust <- cbind(df_clust, prop_ref[, .SD, .SDcols = colnames_to_add])
      df_clust
      }) # check.names = FALSE (no automatic conversion)
    clusters$.id <- NULL
    clusters$area <- x
    # re order columns
    clusters[, c("area", setdiff(colnames(clusters), "area"))]
  })
  
  res <- data.table::rbindlist(l = res, fill = TRUE)
  
  # NO PROPERTIES CLUSTER FOUND
  if(length(res) == 0)
    return(data.table())
  
  # output format conversion
  res <- data.table::as.data.table(res)
  data.table::setnames(res, "name", "cluster")
  res$cluster <- as.factor(tolower(res$cluster))
  res
}


# read and manage referential properties 
  # return referential according to type and study version
get_input_cluster_properties <- function(table_type, opts, dot_format = TRUE){
  # READ cluster properties
  full_ref_properties <- pkgEnv[["inputProperties"]]
  
  category_ref_cluster <- switch(
    table_type,
    "thermals" = "thermal",
    "renewables" = "renewable",
    "st-storages" = "storage"
  )
  
  # filter by category
  ref_filter_by_cat <- full_ref_properties[`Category` %in%
                                             category_ref_cluster]
  # filter by study version
  ref_filter_by_vers <- ref_filter_by_cat[Version.Antares <= 
                                            opts$antaresVersion | 
                                            Version.Antares %in% NA]
  
  # detect evolution on parameter ? (new value according to study version) 
    # filter on value according to study version 
    # select column according to format
  select_col <- ifelse(dot_format, "operating_format", "INI.Name")
  df_multi_params <- ref_filter_by_vers[, 
                                        count := .N, 
                                        by = select_col, 
                                        keyby = TRUE][
                                          count>1][, 
                                                   .SD[which.max(Version.Antares)], 
                                                   by=select_col]
  
  df_unique_params <- ref_filter_by_vers[, 
                                         count := .N, 
                                         by = select_col, 
                                         keyby = TRUE][
                                           count==1]
  
  ref_filter_by_vers <- rbind(df_unique_params, df_multi_params)
  
  # select key colums and put wide format
  ref_filter_by_vers <- ref_filter_by_vers[ , 
                                            .SD, 
                                            .SDcols = c(select_col, 
                                                        "Default", 
                                                        "Type")]
  
  # select names columns to convert to logical + numerical
  logical_col_names <- ref_filter_by_vers[Type%in%"bool"][[select_col]]
  numerical_col_names <- ref_filter_by_vers[Type%in%c("int", "float")][[select_col]]
  
  wide_ref <- data.table::dcast(data = ref_filter_by_vers, 
                                formula = as.formula(paste0(".~", select_col)),
                                value.var = "Default")[
                                  , 
                                  .SD,
                                  .SDcols = -c(".", "name")]
  # /!\ column type conversion on 
  wide_ref[, 
           (logical_col_names):= lapply(.SD, as.logical), 
           .SDcols = logical_col_names][
             ,
             (numerical_col_names):= lapply(.SD, as.numeric), 
             .SDcols = numerical_col_names
           ]
  
  return(wide_ref)
}


.convert_list_clusterDesc_to_datatable <- function(list_clusters, 
                                                   type, 
                                                   dot_format) {
  # return like disk mode 
  if (length(list_clusters) == 0) 
    return(data.table())
  
  # to convert camel case to operating format
  category_ref_cluster <- switch(
    type,
    "thermals" = "thermal",
    "renewables" = "renewable",
    "st-storages" = "storage"
  )
  
  # format output according to parameter
  format_field <- ifelse(dot_format, "operating_format", "INI.Name")
  
  # Tech.Name is the field corresponding to what the API returns
  params_categ <- pkgEnv$inputProperties[Category%in%category_ref_cluster, 
                                         Tech.Name]
    
  rows_cluster <- lapply(
    names(list_clusters), 
    function(cl_name) {
      row_cluster <- as.data.frame(list_clusters[[cl_name]])
      row_cluster[,c("area", "cluster")] <- unlist(strsplit(cl_name, 
                                                            split = " / "))
      return(row_cluster)
    }
  )

  # hamburger
  df_clusters <- do.call("rbind", rows_cluster)
  
  # matching columns in internal referential
  col_names <- setdiff(names(df_clusters), 
                       c("area", "cluster")) 
  index <- match(col_names, params_categ)
  new_names <- pkgEnv$inputProperties[Category%in%category_ref_cluster,
                                      ..format_field][index]
  new_names <- append(new_names[[format_field]],  c("area", "cluster"))
  
  # rename cols
  names(df_clusters) <- new_names
  
  # to order cols
  id_cols <- intersect(c("area", "cluster", "group"), colnames(df_clusters))
  additional_cols <- setdiff(colnames(df_clusters), id_cols)  
  df_clusters <- df_clusters[,c(id_cols, additional_cols)]
  
  # # no camel case on colnames + tolower
  # names(df_clusters) <- tolower(
  #   gsub("(?<=[A-Za-z])(?=[A-Z])", ".", names(df_clusters), perl = TRUE)
  # )
  
  # convention ? (return class object like disk mode)
  df_clusters$cluster <- as.factor(tolower(df_clusters$cluster))
  
  return(as.data.table(df_clusters))
}
rte-antares-rpackage/antaresRead documentation built on Feb. 16, 2025, 4:23 p.m.