diff --git a/.Rbuildignore b/.Rbuildignore new file mode 100644 index 0000000..4ac6c72 --- /dev/null +++ b/.Rbuildignore @@ -0,0 +1,4 @@ +^\.travis\.yml$ +^appveyor\.yml$ +^antaresThermalTS\.Rproj$ +^\.Rproj\.user$ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c97efb2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.Rhistory +.RData +.Rproj.user +*.Rproj diff --git a/DESCRIPTION b/DESCRIPTION new file mode 100644 index 0000000..c648d01 --- /dev/null +++ b/DESCRIPTION @@ -0,0 +1,23 @@ +Package: antaresThermalTS +Title: Extended Shutdown Simulation with 'Antares' for Power Groups +Version: 0.0.0.9310 +Authors@R: c( + person("Victor", "Perrier", email = "victor.perrier@dreamRs.fr", role = c("aut", "cre")), + person("Fabiola", "Aravena-Rojas", email = "fabiola.aravena-rojas@rte-france.com", role = c("aut")), + person("RTE", role = c("cph", "fnd")) + ) +Description: Setup an 'Antares' study to simulate shutdown of power groups. +License: GPL (>= 2) | file LICENSE +Encoding: UTF-8 +LazyData: true +Imports: + antaresEditObject, + antaresRead, + readxl (>= 1.2.0), + janitor, + data.table, + lubridate, + stringr, + stringi, + zoo +RoxygenNote: 6.1.1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a7d6e13 --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +COPYRIGHT HOLDER: RTE Réseau de transport d’électricité diff --git a/NAMESPACE b/NAMESPACE new file mode 100644 index 0000000..dabf759 --- /dev/null +++ b/NAMESPACE @@ -0,0 +1,47 @@ +# Generated by roxygen2: do not edit by hand + +export(build_weekcal) +export(compute_kd_coefs) +export(compute_kipr) +export(compute_kivt) +export(create_clusters_edf) +export(create_clusters_nuclear) +export(create_clusters_other) +export(read_calendar) +export(read_cluster_desc) +export(read_info) +export(read_kd_cho) +export(read_kd_cho_macro) +export(read_planning) +export(read_planning_rte) +export(setup_study) +importFrom(antaresEditObject,createArea) +importFrom(antaresEditObject,createCluster) +importFrom(antaresEditObject,createStudy) +importFrom(antaresEditObject,updateGeneralSettings) +importFrom(antaresRead,setSimulationPath) +importFrom(antaresRead,simOptions) +importFrom(data.table,"%chin%") +importFrom(data.table,":=") +importFrom(data.table,.SD) +importFrom(data.table,copy) +importFrom(data.table,data.table) +importFrom(data.table,melt) +importFrom(data.table,rbindlist) +importFrom(data.table,setDT) +importFrom(data.table,setnames) +importFrom(data.table,setorder) +importFrom(data.table,uniqueN) +importFrom(janitor,clean_names) +importFrom(lubridate,as_datetime) +importFrom(lubridate,days) +importFrom(lubridate,hours) +importFrom(lubridate,years) +importFrom(readxl,anchored) +importFrom(readxl,cell_limits) +importFrom(readxl,read_excel) +importFrom(stats,setNames) +importFrom(stringi,stri_replace_all_charclass) +importFrom(stringr,str_replace_all) +importFrom(utils,packageVersion) +importFrom(zoo,na.locf) diff --git a/R/build_weekcal.R b/R/build_weekcal.R new file mode 100644 index 0000000..680db0f --- /dev/null +++ b/R/build_weekcal.R @@ -0,0 +1,39 @@ + +#' Build Week calendar +#' +#' @param start Starting year +#' @param end Ending year +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom data.table data.table := +#' @importFrom zoo na.locf +#' +#' @examples +#' +#' build_weekcal() +#' +build_weekcal <- function(start = 2018, end = 2020) { + weekcal <- data.table( + dates = seq( + from = as.Date(paste0(start, "-01-01")) - 7, + to = as.Date(paste0(end, "-12-31")) + 7, + by = "days" + ) + ) + weekcal[, saturdays := format(dates, format = "%u") %in% "6"] + weekcal[, year := format(dates + 7, format = "%Y")] + weekcal[saturdays == TRUE, week := sprintf("S%02d - %s", seq_along(saturdays), year), by = year] + weekcal[, week := zoo::na.locf(week, na.rm = FALSE)] + weekcal <- weekcal[!is.na(week)] + + weekcal <- weekcal[, list( + week_start = min(dates), + week_end = max(dates), + n = .N + ), by = week] + weekcal <- weekcal[n == 7] + weekcal[, n := NULL] + weekcal[] +} diff --git a/R/compute_kd_coefs.R b/R/compute_kd_coefs.R new file mode 100644 index 0000000..13d48ff --- /dev/null +++ b/R/compute_kd_coefs.R @@ -0,0 +1,39 @@ + +#' Compute Kd coefficients +#' +#' @param kipr Kipr coefficient from \code{\link{compute_kipr}}. +#' @param kivt Kivt coefficient from \code{\link{compute_kivt}}. +#' @param kd_cho Kd coefficients read with \code{\link{read_kd_cho}}. +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom data.table copy := setorder data.table +compute_kd_coefs <- function(kipr, kivt, kd_cho) { + kipr <- copy(kipr) + kivt <- copy(kivt) + kd_cho <- copy(kd_cho) + code_palier_dic <- data.table( + type_groupe = c("Nucl\u00e9aire 1300", "Nucl\u00e9aire 900", "Nucl\u00e9aire N4"), + code_palier = c("p4", "cp0_cp_cp2", "n4") + ) + kipr <- merge( + x = kipr[, .SD, .SDcols = c("week", "week_start", "week_end", "type_groupe", "kipr")], + y = code_palier_dic, by = "type_groupe" + ) + kipr_kivt <- merge( + x = kipr, + y = kivt[, .SD, .SDcols = c("week", "type_groupe", "kivt")], + by = c("week", "type_groupe") + ) + kipr_kivt[, type_groupe := NULL] + + kd_coefs <- merge( + x = kipr_kivt, + y = kd_cho[, list(week = n_sem_annee, kif, kistretch, kienv, kihiver, kibouclage, code_palier, palier)], + by = c("week", "code_palier") + ) + setorder(kd_coefs, week_start, code_palier) + kd_coefs[] +} + diff --git a/R/compute_kipr.R b/R/compute_kipr.R new file mode 100644 index 0000000..95ad3b9 --- /dev/null +++ b/R/compute_kipr.R @@ -0,0 +1,71 @@ + +#' Compute Kipr coefficient +#' +#' @param calendar Calendar data read with \code{\link{read_calendar}}. +#' @param clusters_desc Clusters / groups description read with \code{\link{read_cluster_desc}}. +#' @param years Years to consider, if \code{NULL} (default), year range from \code{calendar} will be used. +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom data.table copy setorder := uniqueN +#' +#' @examples +#' \dontrun{ +#' # Calendar data +#' calendar <- read_calendar(path = "REF_Planning_5_ans_mars_2018.xlsx") +#' +#' # Clusters description +#' clusters <- read_cluster_desc("HypothesesRTE_CHO-4145.xlsx") +#' +#' +#' # Kipr computation +#' kipr <- compute_kipr(calendar, clusters) +#' kipr +#' } +compute_kipr <- function(calendar, clusters_desc, years = NULL) { + + calendar <- copy(calendar) + clusters_desc <- copy(clusters_desc) + + if (is.null(years)) { + years <- range(calendar$date_debut, na.rm = TRUE) + years <- format(years, format = "%Y") + } + + weekcal <- build_weekcal(start = years[1], end = years[2]) + + weekcal[, .id := 1] + calendar[, .id := 1] + + week_groups <- weekcal[calendar[, list( + .id, + group = tranche, + shutdown_start = as.Date(date_de_fin_sans_prolongation), + shutdown_end = as.Date(date_de_fin_avec_prolongation) + )], on = ".id", allow.cartesian = TRUE] + + week_groups[, n_overlaps := n_overlaps(week_start, week_end, shutdown_start, shutdown_end)] + + clusters_desc <- clusters_desc[, list(group = corresp_groupes, type_groupe, pcn_mw)] + clusters_desc[, pcn_mw := as.numeric(pcn_mw)] + clusters_desc[, group_power := sum(pcn_mw), by = type_groupe] + + weekclus <- merge( + x = week_groups, + y = clusters_desc, + by = "group", all.x = TRUE, all.y = FALSE + ) + weekclus <- weekclus[!is.na(type_groupe)] + + setorder(weekclus, week, group, -n_overlaps) + weekclus <- unique(weekclus, by = c("week", "group")) + + coef_kipr <- weekclus[, list( + kipr = sum(pcn_mw * n_overlaps / 7) / group_power * 100, + n_days = sum(n_overlaps), + n = .N, n_group = uniqueN(group) + ), by = list(week, week_start, week_end, type_groupe, group_power)] + setorder(coef_kipr, week_start, type_groupe) + coef_kipr[] +} diff --git a/R/compute_kivt.R b/R/compute_kivt.R new file mode 100644 index 0000000..40829cf --- /dev/null +++ b/R/compute_kivt.R @@ -0,0 +1,71 @@ + +#' Compute Kivt coefficient +#' +#' @param calendar Calendar data read with \code{\link{read_calendar}}. +#' @param clusters_desc Clusters / groups description read with \code{\link{read_cluster_desc}}. +#' @param years Years to consider, if \code{NULL} (default), year range from \code{calendar} will be used. +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom data.table copy setorder := uniqueN +#' +#' @examples +#' \dontrun{ +#' # Calendar data +#' calendar <- read_calendar(path = "REF_Planning_5_ans_mars_2018.xlsx") +#' +#' # Clusters description +#' clusters <- read_cluster_desc("HypothesesRTE_CHO-4145.xlsx") +#' +#' +#' # Kivt computation +#' kivt <- compute_kivt(calendar, clusters) +#' kivt +#' } +compute_kivt <- function(calendar, clusters_desc, years = NULL) { + + calendar <- copy(calendar) + clusters_desc <- copy(clusters_desc) + + if (is.null(years)) { + years <- range(calendar$date_debut, na.rm = TRUE) + years <- format(years, format = "%Y") + } + + weekcal <- build_weekcal(start = years[1], end = years[2]) + + weekcal[, .id := 1] + calendar[, .id := 1] + + week_groups <- weekcal[calendar[, list( + .id, + group = tranche, + shutdown_start = as.Date(date_debut), + shutdown_end = as.Date(date_de_fin_sans_prolongation) - 1 + )], on = ".id", allow.cartesian = TRUE] + + week_groups[, n_overlaps := n_overlaps(week_start, week_end, shutdown_start, shutdown_end)] + + clusters_desc <- clusters_desc[, list(group = corresp_groupes, type_groupe, pcn_mw)] + clusters_desc[, pcn_mw := as.numeric(pcn_mw)] + clusters_desc[, group_power := sum(pcn_mw), by = type_groupe] + + weekclus <- merge( + x = week_groups, + y = clusters_desc, + by = "group", all.x = TRUE, all.y = FALSE + ) + weekclus <- weekclus[!is.na(type_groupe)] + + setorder(weekclus, week, group, -n_overlaps) + weekclus <- unique(weekclus, by = c("week", "group")) + + coef_kivt <- weekclus[, list( + kivt = sum(pcn_mw * n_overlaps / 7) / group_power * 100, + n_days = sum(n_overlaps), + n = .N, n_group = uniqueN(group) + ), by = list(week, week_start, week_end, type_groupe, group_power)] + setorder(coef_kivt, week_start, type_groupe) + coef_kivt[] +} diff --git a/R/corresp_gps.R b/R/corresp_gps.R new file mode 100644 index 0000000..15767e9 --- /dev/null +++ b/R/corresp_gps.R @@ -0,0 +1,86 @@ + + + +corresp_gps <- function() { + data.table( + groupe = c("BELLEVILLE 1", "BELLEVILLE 2", "BLAYAIS 1", "BLAYAIS 2", + "BLAYAIS 3", "BLAYAIS 4", "BUGEY 2", "BUGEY 3", "BUGEY 4", + "BUGEY 5", "CATTENOM 1", "CATTENOM 2", "CATTENOM 3", "CATTENOM 4", + "CHINON 1", "CHINON 2", "CHINON 3", "CHINON 4", "CHOOZ 1", + "CHOOZ 2", "CIVAUX 1", "CIVAUX 2", "CRUAS 1", "CRUAS 2", "CRUAS 3", + "CRUAS 4", "DAMPIERRE 1", "DAMPIERRE 2", "DAMPIERRE 3", + "DAMPIERRE 4", "FESSENHEIM 1", "FESSENHEIM 2", "FLAMANVILLE 1", + "FLAMANVILLE 2", "GOLFECH 1", "GOLFECH 2", "GRAVELINES 1", + "GRAVELINES 2", "GRAVELINES 3", "GRAVELINES 4", "GRAVELINES 5", + "GRAVELINES 6", "NOGENT 1", "NOGENT 2", "PALUEL 1", "PALUEL 2", "PALUEL 3", + "PALUEL 4", "PENLY 1", "PENLY 2", "ST ALBAN 1", "ST ALBAN 2", + "ST LAURENT 1", "ST LAURENT 2", "TRICASTIN 1", "TRICASTIN 2", + "TRICASTIN 3", "TRICASTIN 4", "CORDEMAIS 4", "CORDEMAIS 5", "HAVRE 4", + "PROVENCE 5", "EMILE HUCHET 6", "DK6 - Braek 1", + "DK6 - Braek 2", "BOUCHAIN 7", "MARTIGUES PONTEAU 5", "MARTIGUES PONTEAU 6", + "SPEM", "SPEM Pointe", "Grand-Riviere (SPEM)", "CYCOFOS", + "BLENOD 5", "COMBIGOLFE", "EMILE HUCHET 7", "EMILE HUCHET 8", + "Croix-de-Metz", "Pont-sur-Sambre", "FR-GA-MORANT1", "GENNEVILLIERS 1", + "AMFARD14", "AMFARD15", "CORDEMAIS 2", "CORDEMAIS 3", + "PORCHEVILLE 1", "PORCHEVILLE 2", "PORCHEVILLE 3", "PORCHEVILLE 4", + "ARAMON 1", "ARAMON 2", "MONTEREAU FIOUL 6", "MONTEREAU FIOUL 5", + "MONTEREAU GAZ 6", "MONTEREAU GAZ 5", "VAIRES 1", "VAIRES 2", + "VAIRES 3", "ARRIGHI 1", "ARRIGHI 2", "DIRINON 1", "DIRINON 2", + "BRENNILIS 1", "BRENNILIS 2", "BRENNILIS 3", "BILHOT01", "FOSCHT 2", + "Calais Tioxide", "DD HOA 1", "DD HOA 2", "DD HOA DALKIA", + "DD OA - ELD RESTE France", "DD OA - ERDF RESTE France", "DDBZHT 1", + "DK6 TV1", "DK6 TV2"), + code_gp = c("BVIL7T 1", "BVIL7T 2", "BLAYAT 1", "BLAYAT 2", "BLAYAT 3", + "BLAYAT 4", "BUGEYT 2", "BUGEYT 3", "BUGEYT 4", "BUGEYT 5", + "CATTET 1", "CATTET 2", "CATTET 3", "CATTET 4", "CHIN2T 1", + "CHIN2T 2", "CHIN2T 3", "CHIN2T 4", "CHOO2T 1", "CHOO2T 2", + "CIVAUT 1", "CIVAUT 2", "CRUA5T 1", "CRUA5T 2", "CRUA5T 3", "CRUA5T 4", + "D.BURT 1", "D.BURT 2", "D.BURT 3", "D.BURT 4", "FESS5T 1", + "FESS5T 2", "FLAMAT 1", "FLAMAT 2", "GOLF5T 1", "GOLF5T 2", + "GRAV5T 1", "GRAV5T 2", "GRAV5T 3", "GRAV5T 4", "GRAV5T 5", "GRAV5T 6", + "N.SE5T 1", "N.SE5T 2", "PALUET 1", "PALUET 2", "PALUET 3", + "PALUET 4", "PENLYT 1", "PENLYT 2", "SSAL7T 1", "SSAL7T 2", + "SSEA2T 1", "SSEA2T 2", "TRICAT 1", "TRICAT 2", "TRICAT 3", "TRICAT 4", + "CORD5T 4", "CORD5T 5", "HAVRET 4", "PROVET 5", "E.HUCT 6", NA, + NA, "BOUCHT 7", "M.PONT 5", "M.PONT 6", NA, NA, NA, NA, + "BLENOT 5", NA, "E.HUCT 7", "E.HUCT 8", "C.ME5T01", "SAMBRT1", "MORANT 1", + "GENN3T 1", "AMFART14", "AMFART15", "CORD5T 2", "CORD5T 3", + "PORC2T 1", "PORC2T 2", "PORC2T 3", "PORC2T 4", NA, NA, "MTERFT 6", + "MTERFT 5", "MTERGT 6", "MTERGT 5", "VAIR6T 1", "VAIR6T 2", + "VAIR6T 3", "ARRI5T 1", "ARRI5T 2", "DIRINT 1", "DIRINT 2", + "BRENNT 1", "BRENNT 2", "BRENNT 3", NA, NA, "CALAIT1", "DFDC1T 1", + "DFDC2T 1", "DFDCOT 1", "DFELDT 1", "DFEGST 1", "DDBZHT 1", NA, NA), + name_desc = c("nuclear_p4", "nuclear_p4", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_p4", "nuclear_p4", + "nuclear_p4", "nuclear_p4", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_n4", + "nuclear_n4", "nuclear_n4", "nuclear_n4", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", + "nuclear_p4", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "hard_coal_old_1", "hard_coal_old_1", + "hard_coal_old_1", "hard_coal_old_1", "hard_coal_old_1", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ocgt_old", + "gas_cogen_market", "gas_cogen_market", "heavy_oil_old_1", + "heavy_oil_old_1", "heavy_oil_old_1", "heavy_oil_old_1", + "heavy_oil_old_1", "heavy_oil_old_1", "heavy_oil_old_1", "heavy_oil_old_1", + "light_oil", "light_oil", "gas_ocgt_new", "gas_ocgt_new", + "light_oil", "light_oil", "light_oil", "light_oil", "light_oil", + "light_oil", "light_oil", "light_oil", "light_oil", "light_oil", + "gas_cogen_market", "gas_cogen_market", "gas_cogen_market", "light_oil", + "light_oil", "light_oil", "light_oil", "light_oil", "light_oil", + "gas_ccgt_new", "gas_ccgt_new") + ) +} diff --git a/R/create_clusters_edf.R b/R/create_clusters_edf.R new file mode 100644 index 0000000..96603b8 --- /dev/null +++ b/R/create_clusters_edf.R @@ -0,0 +1,114 @@ + +#' Create EDF clusters +#' +#' @param planning Calendar data read with \code{\link{read_calendar}}. +#' @param opts +#' List of simulation parameters returned by the function +#' \code{setSimulationPath} +#' +#' @export +#' +#' @importFrom antaresRead simOptions +#' @importFrom antaresEditObject createCluster +#' @importFrom lubridate hours days as_datetime +#' @importFrom stats setNames +#' @importFrom stringr str_replace_all +create_clusters_edf <- function(planning, opts = simOptions()) { + + planning <- copy(planning) + planning <- planning[!is.na(code_gp)] + + # Modulation data + modulation_list <- lapply( + X = setNames( + object = unique(planning$code_gp), + nm = unique(planning$code_gp) + ), + FUN = function(cluster) { + dat <- planning[code_gp == cluster & !is.na(date_debut)] + if (nrow(dat) == 0) { + matrix( + data = c( + rep(1, times = 8760 * 3), + rep(0, times = 8760 * 1) + ), + ncol = 4 + ) + } else { + datetime_study <- seq(from = as.POSIXct("2018-07-01", tz = "UTC"), length.out = 8760, by = "1 hour") + datetime_study <- as.character(datetime_study) + datetime_prolongation <- lapply( + X = seq_len(nrow(dat)), + FUN = function(i) { + if (dat$date_fin_arret[i] > dat$date_debut[i]) { + res <- seq( + from = as_datetime(dat$date_debut[i]), + to = dat$date_fin_arret[i] - hours(1), + by = "1 hour" + ) + as.character(res) + } + } + ) + + datetime_prolongation <- unlist(datetime_prolongation) + capacity_modulation <- (!datetime_study %in% datetime_prolongation) * 1 + matrix( + data = c( + rep(1, times = 8760 * 2), + capacity_modulation, + rep(0, times = 8760 * 1) + ), + ncol = 4 + ) + } + } + ) + + + for (cluster in unique(planning$code_gp)) { + + infos_clus <- planning[code_gp == cluster] + infos_clus <- unique(infos_clus, by = "code_gp") + + cluster_infos <- descr_clusters(infos_clus$name_desc) + + opts <- createCluster( + opts = opts, + area = "area", + cluster_name = str_replace_all(string = cluster, pattern = "[^[:alnum:]]", replacement = "_"), + add_prefix = FALSE, + group = cluster_infos[["group"]], + unitcount = 1L, + nominalcapacity = floor(infos_clus$pcn_mw), + `min-stable-power` = floor(infos_clus$pmin_mw), + `must-run` = FALSE, + # `min-down-time` = 1L, + # `min-up-time` = 168L, + + `min-up-time` = cluster_infos[["min-up-time"]], + `min-down-time` = cluster_infos[["min-down-time"]], + spinning = cluster_infos[["spinning"]], + `marginal-cost` = cluster_infos[["marginal-cost"]], + `spread-cost` = cluster_infos[["spread-cost"]], + `startup-cost` = cluster_infos[["startup-cost"]], + `market-bid-cost` = cluster_infos[["market-bid-cost"]], + co2 = cluster_infos[["co2"]], + + prepro_data = matrix( + data = c( + rep(1, times = 365 * 2), + rep(1 - 0.5, times = 365 * 1), + rep(0, times = 365 * 2), + rep(1, times = 365 * 1) + ), + ncol = 6 + ), + prepro_modulation = modulation_list[[cluster]] + ) + } + + invisible(opts) +} + + diff --git a/R/create_clusters_nuclear.R b/R/create_clusters_nuclear.R new file mode 100644 index 0000000..2dd1bc1 --- /dev/null +++ b/R/create_clusters_nuclear.R @@ -0,0 +1,180 @@ + +#' Create nuclear clusters +#' +#' @param calendar Calendar data read with \code{\link{read_calendar}}. +#' @param clusters_desc Clusters / groups description read with \code{\link{read_cluster_desc}}. +#' @param kd_cho Kd coefficients read with \code{\link{read_kd_cho}}. +#' @param law_planned Law to use in Antares. +#' @param volatility_planned Volatility for the law. +#' @param opts +#' List of simulation parameters returned by the function +#' \code{setSimulationPath} +#' +#' @export +#' +#' @importFrom antaresRead simOptions +#' @importFrom antaresEditObject createCluster +#' @importFrom lubridate hours days +#' @importFrom stats setNames +#' @importFrom stringr str_replace_all +create_clusters_nuclear <- function(calendar, clusters_desc, kd_cho, law_planned = "geometric", volatility_planned = 1, opts = simOptions()) { + + # Modulation data + modulation_list <- lapply( + X = setNames( + object = unique(calendar$tranche), + nm = unique(calendar$tranche) + ), + FUN = function(cluster) { + dat <- calendar[tranche == cluster] + if (nrow(dat) == 0) { + matrix( + data = c( + rep(1, times = 8760 * 3), + rep(0, times = 8760 * 1) + ), + ncol = 4 + ) + } else { + datetime_study <- seq(from = as.POSIXct("2018-07-01", tz = "UTC"), length.out = 8760, by = "1 hour") + datetime_study <- as.character(datetime_study) + datetime_prolongation <- lapply( + X = seq_len(nrow(dat)), + FUN = function(i) { + if (dat$date_de_fin_sans_prolongation[i] > dat$date_debut[i]) { + res <- seq( + from = dat$date_debut[i], + to = dat$date_de_fin_sans_prolongation[i] - hours(1), + by = "1 hour" + ) + as.character(res) + } + } + ) + + coef_clus <- get_clusters_coef(cluster, clusters_desc, kd_cho, "2018-07-01") + + datetime_prolongation <- unlist(datetime_prolongation) + capacity_modulation <- (!datetime_study %in% datetime_prolongation) * rep(coef_clus$abat_rso, each = 24) + matrix( + data = c( + rep(1, times = 8760 * 2), + capacity_modulation, + rep(0, times = 8760 * 1) + ), + ncol = 4 + ) + } + } + ) + + # Preprop data + data_list <- lapply( + X = setNames( + object = unique(calendar$tranche), + nm = unique(calendar$tranche) + ), + FUN = function(cluster) { + dat <- calendar[tranche == cluster] + if (nrow(dat) == 0) { + matrix( + data = c( + rep(1, times = 365 * 2), + rep(0, times = 365 * 3), + rep(1, times = 365 * 1) + ), + ncol = 6 + ) + } else { + date_study <- seq(from = as.Date("2018-07-01"), length.out = 365, by = "1 day") + date_reprise <- which(as.character(date_study) %in% as.character(dat$date_de_fin_sans_prolongation - days(1))) + duree_prolongation_mean <- dat$duree_prolongation_mean[as.character(dat$date_de_fin_sans_prolongation) %in% as.character(date_study + days(1))] + res <- matrix( + data = c( + rep(1, times = 365 * 2), + rep(0, times = 365 * 3), + rep(1, times = 365 * 1) + ), + ncol = 6 + ) + + date_arret_prolongation <- lapply( + X = seq_len(nrow(dat)), + FUN = function(i) { + if (dat$date_de_fin_sans_prolongation[i] > dat$date_debut[i]) { + res <- seq( + from = as.Date(dat$date_debut[i]), + to = as.Date(dat$date_de_fin_avec_prolongation[i]) - days(1), + by = "1 day" + ) + as.character(res) + } + } + ) + + coef_clus <- get_clusters_coef(cluster, clusters_desc, kd_cho, "2018-07-01") + date_study <- as.character(date_study) + date_arret_prolongation <- unlist(date_arret_prolongation) + fo_rate <- (!date_study %in% date_arret_prolongation) * (1 - coef_clus$kidispo_hqe) + + res[, 3] <- fo_rate + + res[date_reprise, 2] <- duree_prolongation_mean + res[date_reprise, 4] <- 1 + return(res) + } + } + ) + + for (cluster in unique(calendar$tranche)) { + + code_pal <- clusters_desc[corresp_groupes == cluster, c(code_palier)] + cluster_infos <- descr_clusters(paste0("nuclear_", code_pal)) + + opts <- createCluster( + opts = opts, + area = "area", + cluster_name = str_replace_all(string = cluster, pattern = "[^[:alnum:]]", replacement = "_"), + add_prefix = FALSE, + group = "nuclear", + unitcount = 1L, + nominalcapacity = clusters_desc[corresp_groupes == cluster, c(pcn_mw)], + `min-stable-power` = clusters_desc[corresp_groupes == cluster, c(pmin_mw)], + `must-run` = FALSE, + # `min-down-time` = 1L, + # `min-up-time` = 168L, + `volatility.planned` = volatility_planned, + `law.planned` = law_planned, + + `min-up-time` = cluster_infos[["min-up-time"]], + `min-down-time` = cluster_infos[["min-down-time"]], + spinning = cluster_infos[["spinning"]], + `marginal-cost` = cluster_infos[["marginal-cost"]], + `spread-cost` = cluster_infos[["spread-cost"]], + `startup-cost` = cluster_infos[["startup-cost"]], + `market-bid-cost` = cluster_infos[["market-bid-cost"]], + + prepro_data = data_list[[cluster]], + prepro_modulation = modulation_list[[cluster]] + ) + } + + invisible(opts) +} + + +#' @importFrom lubridate years +get_clusters_coef <- function(name, clusters_desc, kd_cho, date_study) { + code_pal <- clusters_desc[corresp_groupes == name, c(code_palier)] + coefkd_week <- kd_cho[code_palier %in% code_pal, list(week = n_sem_annee, abat_rso, kidispo_hqe)] + + coefkd_week <- merge(x = coefkd_week, y = build_weekcal(), all.x = TRUE, all.y = FALSE) + + coefkd_week <- coefkd_week[rep(seq_len(.N), each = 7)] + coefkd_week[, num_seq := seq_len(.N) - 1, by = week] + coefkd_week[, week_start := week_start + num_seq] + coefkd_week <- coefkd_week[, list(date = week_start, abat_rso, kidispo_hqe)] + coefkd_week <- coefkd_week[date >= as.Date(date_study) & date < as.Date(date_study) + lubridate::years(1)] + coefkd_week[] +} + diff --git a/R/create_clusters_other.R b/R/create_clusters_other.R new file mode 100644 index 0000000..e5474bb --- /dev/null +++ b/R/create_clusters_other.R @@ -0,0 +1,124 @@ + +#' Create other clusters +#' +#' @param planning Calendar data read with \code{\link{read_calendar}}. +#' @param infos Info +#' @param opts +#' List of simulation parameters returned by the function +#' \code{setSimulationPath} +#' +#' @export +#' +#' @importFrom antaresRead simOptions +#' @importFrom antaresEditObject createCluster +#' @importFrom lubridate hours days as_datetime +#' @importFrom stats setNames +#' @importFrom stringr str_replace_all +create_clusters_other <- function(planning, infos, opts = simOptions()) { + + planning <- copy(planning) + planning[is.na(code_gp), code_gp := nom_site] + + planning[nom_site == "PONT SUR SAMBRE", code_gp := "SAMBRT1"] + planning[nom_site == "CROIX DE METZ", code_gp := "C.ME5T01"] + + + infos[is.na(`for`), `for` := 1] + + infos[, pmax := as.numeric(pmax)] + infos[is.na(pmax), pmax := 0] + + # Modulation data + modulation_list <- lapply( + X = setNames( + object = unique(planning$code_gp), + nm = unique(planning$code_gp) + ), + FUN = function(cluster) { + dat <- planning[code_gp == cluster & !is.na(dt_debut_arret)] + if (nrow(dat) == 0) { + matrix( + data = c( + rep(1, times = 8760 * 3), + rep(0, times = 8760 * 1) + ), + ncol = 4 + ) + } else { + datetime_study <- seq(from = as.POSIXct("2018-07-01", tz = "UTC"), length.out = 8760, by = "1 hour") + datetime_study <- as.character(datetime_study) + datetime_prolongation <- lapply( + X = seq_len(nrow(dat)), + FUN = function(i) { + if (dat$dt_fin_arret[i] > dat$dt_debut_arret[i]) { + res <- seq( + from = as_datetime(dat$dt_debut_arret[i]), + to = dat$dt_fin_arret[i] - hours(1), + by = "1 hour" + ) + as.character(res) + } + } + ) + + datetime_prolongation <- unlist(datetime_prolongation) + capacity_modulation <- (!datetime_study %in% datetime_prolongation) * 1 + matrix( + data = c( + rep(1, times = 8760 * 2), + capacity_modulation, + rep(0, times = 8760 * 1) + ), + ncol = 4 + ) + } + } + ) + + + for (cluster in unique(planning$code_gp)) { + + code_group <- corr_groupe_descr(cluster) + cluster_infos <- descr_clusters(code_group) + + infos_clus <- infos[code_gp == cluster] + + opts <- createCluster( + opts = opts, + area = "area", + cluster_name = str_replace_all(string = cluster, pattern = "[^[:alnum:]]", replacement = "_"), + add_prefix = FALSE, + group = cluster_infos[["group"]], + unitcount = 1L, + nominalcapacity = floor(infos_clus$pmax), + `min-stable-power` = floor(infos_clus$pmin), + `must-run` = FALSE, + # `min-down-time` = 1L, + # `min-up-time` = 168L, + + `min-up-time` = cluster_infos[["min-up-time"]], + `min-down-time` = cluster_infos[["min-down-time"]], + spinning = cluster_infos[["spinning"]], + `marginal-cost` = cluster_infos[["marginal-cost"]], + `spread-cost` = cluster_infos[["spread-cost"]], + `startup-cost` = cluster_infos[["startup-cost"]], + `market-bid-cost` = cluster_infos[["market-bid-cost"]], + co2 = cluster_infos[["co2"]], + + prepro_data = matrix( + data = c( + rep(1, times = 365 * 2), + rep(1 - infos_clus[["for"]], times = 365 * 1), + rep(0, times = 365 * 2), + rep(1, times = 365 * 1) + ), + ncol = 6 + ), + prepro_modulation = modulation_list[[cluster]] + ) + } + + invisible(opts) +} + + diff --git a/R/descr_clusters.R b/R/descr_clusters.R new file mode 100644 index 0000000..4e0436f --- /dev/null +++ b/R/descr_clusters.R @@ -0,0 +1,187 @@ + + +#' Get cluster description +#' +#' @param name Type of cluster +#' +#' @noRd +descr_clusters <- function(name) { + descr <- list( + nuclear_n4 = list( + `min-up-time` = 168L, + `min-down-time` = 168L, + spinning = 0, + `marginal-cost` = 5.02, + `spread-cost` = 0.4, + `startup-cost` = 35599L, + `market-bid-cost` = 5.02 + ), + nuclear_p4 = list( + `min-up-time` = 168L, + `min-down-time` = 168L, + spinning = 0, + `marginal-cost` = 5.02, + `spread-cost` = 0.4, + `startup-cost` = 35599L, + `market-bid-cost` = 5.02 + ), + nuclear_cp0_cp_cp2 = list( + `min-up-time` = 168L, + `min-down-time` = 168L, + spinning = 0, + `marginal-cost` = 5.02, + `spread-cost` = 0.4, + `startup-cost` = 24435L, + `market-bid-cost` = 5.02 + ), + hard_coal_old_1 = list( + group = "Hard coal", + `min-up-time` = 8L, + `min-down-time` = 8L, + spinning = 0, + co2 = 0.99, + `marginal-cost` = 25.73, + `spread-cost` = 0.4, + `startup-cost` = 67390, + `market-bid-cost` = 25.73 + ), + gas_ccgt_new = list( + group = "gas", + `min-down-time` = 2L, + spinning = 0, + co2 = 0.35, + `marginal-cost` = 25.9, + `spread-cost` = 0.4, + `startup-cost` = 25923.6, + `market-bid-cost` = 25.9 + ), + gas_ocgt_old = list( + group = "gas", + spinning = 0, + co2 = 0.58, + `marginal-cost` = 42.91, + `spread-cost` = 0.4, + `startup-cost` = 10774.9, + `market-bid-cost` = 42.91 + ), + gas_ocgt_new = list( + group = "gas", + spinning = 0, + co2 = 0.49, + `marginal-cost` = 35.76, + `spread-cost` = 0.4, + `startup-cost` = 3120.6, + `market-bid-cost` = 35.76 + ), + light_oil = list( + group = "oil", + `min-up-time` = 3L, + `min-down-time` = 3L, + spinning = 0, co2 = 0.78, + `marginal-cost` = 90.17, + `spread-cost` = 0.4, + `startup-cost` = 5160.4, + `market-bid-cost` = 90.17 + ), + heavy_oil_old_1 = list( + group = "oil", + `min-up-time` = 3L, + `min-down-time` = 3L, + spinning = 0, + co2 = 0.78, + `marginal-cost` = 90.17, + `spread-cost` = 0.4, + `startup-cost` = 93845, + `market-bid-cost` = 90.17 + ), + gas_cogen = list( + group = "gas", + `min-up-time` = 24L, + `min-down-time` = 24L, + spinning = 0, + co2 = 0.58, + `marginal-cost` = 42.91, + `spread-cost` = 0.4, + `startup-cost` = 248007, + `market-bid-cost` = 42.91 + ) + ) + + if (!is.null(name) && name %in% names(descr)) { + descr[[name]] + } else { + warning("Cluster description not found!", call. = FALSE) + NULL + } + +} + + + +#' Correspondence between groups and clusters +#' +#' @param code_groupe Code group +#' +#' @noRd +corr_groupe_descr <- function(code_groupe) { + clus_name_ <- c("nuclear_p4", "nuclear_p4", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_n4", "nuclear_n4", "nuclear_n4", "nuclear_n4", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_p4", "nuclear_p4", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_p4", + "nuclear_p4", "nuclear_p4", "nuclear_p4", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", + "nuclear_cp0_cp_cp2", "nuclear_cp0_cp_cp2", "hard_coal_old_1", + "hard_coal_old_1", "hard_coal_old_1", "hard_coal_old_1", "hard_coal_old_1", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", "gas_ccgt_new", + "gas_ocgt_old", "gas_cogen", "gas_cogen", "heavy_oil_old_1", + "heavy_oil_old_1", "heavy_oil_old_1", "heavy_oil_old_1", "heavy_oil_old_1", + "heavy_oil_old_1", "heavy_oil_old_1", "heavy_oil_old_1", "light_oil", + "light_oil", "gas_ocgt_new", "gas_ocgt_new", "light_oil", "light_oil", + "light_oil", "light_oil", "light_oil", "light_oil", "light_oil", + "light_oil", "light_oil", "light_oil", "gas_cogen", "gas_cogen", + "gas_cogen", "light_oil", "light_oil", "light_oil", "light_oil", + "light_oil", "light_oil", "gas_ccgt_new", "gas_ccgt_new") + code_groupe_ <- c("BVIL7T 1", "BVIL7T 2", "BLAYAT 1", "BLAYAT 2", "BLAYAT 3", + "BLAYAT 4", "BUGEYT 2", "BUGEYT 3", "BUGEYT 4", "BUGEYT 5", "CATTET 1", + "CATTET 2", "CATTET 3", "CATTET 4", "CHIN2T 1", "CHIN2T 2", "CHIN2T 3", + "CHIN2T 4", "CHOO2T 1", "CHOO2T 2", "CIVAUT 1", "CIVAUT 2", "CRUA5T 1", + "CRUA5T 2", "CRUA5T 3", "CRUA5T 4", "D.BURT 1", "D.BURT 2", "D.BURT 3", + "D.BURT 4", "FESS5T 1", "FESS5T 2", "FLAMAT 1", "FLAMAT 2", "GOLF5T 1", + "GOLF5T 2", "GRAV5T 1", "GRAV5T 2", "GRAV5T 3", "GRAV5T 4", "GRAV5T 5", + "GRAV5T 6", "N.SE5T 1", "N.SE5T 2", "PALUET 1", "PALUET 2", "PALUET 3", + "PALUET 4", "PENLYT 1", "PENLYT 2", "SSAL7T 1", "SSAL7T 2", "SSEA2T 1", + "SSEA2T 2", "TRICAT 1", "TRICAT 2", "TRICAT 3", "TRICAT 4", "CORD5T 4", + "CORD5T 5", "HAVRET 4", "PROVET 5", "E.HUCT 6", "DK6 TAG1", "DK6 TAG2", + "BOUCHT 7", "M.PONT 5", "M.PONT 6", "", "", "G.RIVT 1", "FOSCCT1", + "BLENOT 5", "GRACIT 1", "E.HUCT 7", "E.HUCT 8", "C.ME5T01", "SAMBRT1", + "MORANT 1", "GENN3T 1", "AMFART14", "AMFART15", "CORD5T 2", "CORD5T 3", + "PORC2T 1", "PORC2T 2", "PORC2T 3", "PORC2T 4", "", "", "MTERFT 6", + "MTERFT 5", "MTERGT 6", "MTERGT 5", "VAIR6T 1", "VAIR6T 2", "VAIR6T 3", + "ARRI5T 1", "ARRI5T 2", "DIRINT 1", "DIRINT 2", "BRENNT 1", "BRENNT 2", + "BRENNT 3", "BILHOT", "FOSCHT2", "CALAIT1", "DFDC1T 1", "DFDC2T 1", + "DFDCOT 1", "DFELDT 1", "DFEGST 1", "DDBZHT 1", "DK6 TAV1", "DK6 TAV2" + ) + + if (!is.null(code_groupe) && code_groupe %in% code_groupe_) { + clus_name_[which(code_groupe_ == code_groupe)] + } else { + warning("code_groupe not found !", call. = FALSE) + NULL + } +} + + + + diff --git a/R/read-kd-cho.R b/R/read-kd-cho.R new file mode 100644 index 0000000..8fa87ad --- /dev/null +++ b/R/read-kd-cho.R @@ -0,0 +1,85 @@ + +#' Read sheet "Kd CHO" from RTE hypothesis +#' +#' @param path Path to Excel file. +#' +#' @return a \code{data.table} +#' @export +#' +#' @name read-kd-cho +#' +#' @importFrom utils packageVersion +#' @importFrom readxl read_excel +#' @importFrom janitor clean_names +#' @importFrom data.table setDT setnames melt := +#' @importFrom stringi stri_replace_all_charclass +#' +read_kd_cho <- function(path) { + kd_cho <- readxl::read_excel(path = path, sheet = "Kd CHO", skip = 8) + kd_cho <- janitor::clean_names(kd_cho) + setDT(kd_cho) + setnames(x = kd_cho, old = c("x1", "x2", "x3"), new = c("n_days", "year", "n_week")) + kd_cho[, (names(kd_cho)) := lapply(.SD, function(x) { + if (all(is.na(x))) { + return(NULL) + } else { + x + } + }), .SDcols = names(kd_cho)] + kd_cho_long <- melt( + data = kd_cho, + id = 1:4, + measure = patterns(kif = "^kif", kistretch = "^ki_stretch", kienv = "^kienv", kihiver = "^kihiver", kibouclage = "^ki_bouclage"), + variable.factor = FALSE, + variable.name = "palier" + ) + kd_cho_long[palier == "1", `:=`(palier = "Palier 900 MW", code_palier = "cp0_cp_cp2")] + kd_cho_long[palier == "2", `:=`(palier = "Palier 1300 MW", code_palier = "p4")] + kd_cho_long[palier == "3", `:=`(palier = "Palier N4", code_palier = "n4")] + kd_cho_long[, n_days := stringi::stri_replace_all_charclass(str = n_days, pattern = "[:space:]", replacement = "")] + kd_cho_long[, date := as.Date(as.numeric(n_days), origin = "1960-01-01")] + kd_cho_long +} + + +#' @rdname read-kd-cho +#' @export +read_kd_cho_macro <- function(path) { + + kd_cho <- read_excel(path = path, sheet = "Kd CHO", skip = 4, n_max = 105) + + kd_cho <- janitor::clean_names(kd_cho) + setDT(kd_cho) + kd_cho[, (names(kd_cho)) := lapply(.SD, function(x) { + if (all(is.na(x))) { + return(NULL) + } else { + x + } + }), .SDcols = names(kd_cho)] + + + kd_cho_long <- melt( + data = kd_cho, + id = 1, + measure = patterns( + kif = "^kif", kistretch = "^ki_stretch", kienv = "^kienv", kihiver = "^kihiver", kibouclage = "^ki_bouclage", + kivt = "^kivt", kipr = "^kipr", abat_rso = "^abat_rso", kidispo_hqe = "^k_dispo_hqe" + ), + variable.factor = FALSE, + variable.name = "palier" + ) + + kd_cho_long[palier == "1", `:=`(palier = "Palier 900 MW", code_palier = "cp0_cp_cp2")] + kd_cho_long[palier == "2", `:=`(palier = "Palier 1300 MW", code_palier = "p4")] + kd_cho_long[palier == "3", `:=`(palier = "Palier N4", code_palier = "n4")] + + kd_cho_long[is.na(abat_rso), abat_rso := 1] + kd_cho_long[abat_rso > 1 | abat_rso < 0, abat_rso := 1] + + kd_cho_long[] +} + + + + diff --git a/R/read_calendar.R b/R/read_calendar.R new file mode 100644 index 0000000..460ed35 --- /dev/null +++ b/R/read_calendar.R @@ -0,0 +1,28 @@ + +#' Read calendar data +#' +#' @param path Path to a file. +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom data.table setDT := %chin% +#' @importFrom janitor clean_names +#' @importFrom readxl read_excel +#' +read_calendar <- function(path) { + dat <- read_excel(path = path, skip = 3) + dat <- clean_names(dat) + setDT(dat) + dat[is.na(duree_prolongation_semaine) & type_darret %chin% c("Essai TCG", "TCG"), duree_prolongation_semaine := 0] + dat[format(date_debut, "%u") %chin% c("6", "7") & + format(date_de_fin_sans_prolongation, "%u") %chin% c("6", "7") & + abs(as.numeric(difftime(date_debut, date_de_fin_sans_prolongation, units = "day"))) <= 2, duree_prolongation_semaine := 0] + dat[is.na(duree_prolongation_semaine), `:=`(duree_prolongation_semaine = 1, date_de_fin_avec_prolongation = date_de_fin_avec_prolongation + 7 * 86400)] + dat[, duree_prolongation_jour := as.numeric(difftime(date_de_fin_avec_prolongation, date_de_fin_sans_prolongation, units = "day"))] + dat[, duree_prolongation_mean := as.numeric(duree_prolongation_semaine) * 7 + 1] + dat[] +} + + + diff --git a/R/read_cluster_desc.R b/R/read_cluster_desc.R new file mode 100644 index 0000000..25fd802 --- /dev/null +++ b/R/read_cluster_desc.R @@ -0,0 +1,53 @@ + +#' Read Cluster Description +#' +#' @param path Path to Excel file +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom readxl read_excel +#' @importFrom janitor clean_names +#' @importFrom data.table setDT := setnames +#' @importFrom zoo na.locf +#' +#' @examples +#' \dontrun{ +#' +#' cluster_desc <- read_cluster_desc("HypothesesRTE_CHO-4145.xlsx") +#' +#' } +#' +read_cluster_desc <- function(path) { + clusdesc <- read_excel(path = path, sheet = 2, skip = 5) + clusdesc <- janitor::clean_names(clusdesc) + setDT(clusdesc) + + # column with all missing values + clusdesc[, x7 := NULL] + # column with code groups + setnames(clusdesc, "x8", "corresp_groupes") + # rows with missing values + clusdesc <- clusdesc[!is.na(nom)] + + # type of groups + clusdesc[is.na(pcn_mw), type_groupe := nom] + clusdesc[, type_groupe := zoo::na.locf(type_groupe)] + + # wrong corresp + clusdesc[corresp_groupes == "SSEA2T1", corresp_groupes := "SSEA2T 1"] + clusdesc[corresp_groupes == "SSEA2T2", corresp_groupes := "SSEA2T 2"] + # clusdesc[corresp_groupes == "FLAMANVILLE 3", corresp_groupes := "FLAMAT 3"] + clusdesc <- clusdesc[corresp_groupes != "FLAMANVILLE 3"] + + clusdesc <- clusdesc[!is.na(pcn_mw)] + + code_palier_dic <- data.table( + type_groupe = c("Nucl\u00e9aire 1300", "Nucl\u00e9aire 900", "Nucl\u00e9aire N4"), + code_palier = c("p4", "cp0_cp_cp2", "n4") + ) + + clusdesc <- merge(x = clusdesc, y = code_palier_dic, all.x = TRUE) + + clusdesc +} diff --git a/R/read_info.R b/R/read_info.R new file mode 100644 index 0000000..325aa41 --- /dev/null +++ b/R/read_info.R @@ -0,0 +1,42 @@ + +#' Read other clusters informations +#' +#' @param path Path to file. +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom readxl read_excel +#' @importFrom janitor clean_names +#' @importFrom data.table setDT data.table rbindlist +#' +read_info <- function(path) { + clus_infos <- read_excel(path = path, sheet = 2, skip = 6) + clus_infos <- janitor::clean_names(clus_infos) + setDT(clus_infos) + clus_infos <- clus_infos[!is.na(edp_ed_prev)] + + corresp <- rbindlist(list( + data.table( + edp_ed_prev = c("GRACIT 1", "FOSCCT 1", "DKSOLT 1", "DKDUNT 1", "DKSOLT 2", "DKDUNT 2", "G.RIVT 1", "FOSCHT 2", "BILHOT01"), + code_gp = c("GRACIT 1", "FOSCCT1" , "DK6 TAG1", "DK6 TAV1", "DK6 TAG2", "DK6 TAV2", "G.RIVT 1", "FOSCHT2" , "BILHOT") + ), + data.table( + edp_ed_prev = c("EMILE HUCHET 6", "EMILE HUCHET 7", "EMILE HUCHET 8", "PROVENCE 5"), + code_gp = c("E.HUCT 6", "E.HUCT 7", "E.HUCT 8", "PROVET 5") + ), + data.table( + edp_ed_prev = c("PONT SUR SAMBRE", "CROIX DE METZ"), + code_gp = c("SAMBRT1", "C.ME5T01") + ), + data.table( + edp_ed_prev = c("Morandes"), + code_gp = c("MORANT 1") + ) + )) + clus_infos <- merge(x = clus_infos, y = corresp, all.x = TRUE, all.y = FALSE) + clus_infos <- unique(clus_infos, by = "edp_ed_prev") + clus_infos <- clus_infos[edp_ed_prev != "EDP"] + clus_infos[code_gp == "MORANT 1" & is.na(pmin), pmin := 190] + clus_infos[] +} diff --git a/R/read_planning.R b/R/read_planning.R new file mode 100644 index 0000000..3171100 --- /dev/null +++ b/R/read_planning.R @@ -0,0 +1,56 @@ + +#' Read a maintenance planning +#' +#' @param path Character. Path to the Excel file +#' @param sheet Character. Sheet in which the planning can be found. Defaults to 'Planning'. +#' @param start_col Character. Leftmost column of the planning (upper-case letter). Defaults to 'A'. +#' @param start_row Integer. Row number of the planning's header. Defaults to 16. +#' +#' @return A 12-column \code{data.table}: the same 12 columns as in the Excel sheet. Useless rows +#' are dropped, and values from the first 4 columns are repeated in order to obtain a 'tidy' +#' dataset. +#' +#' @export +#' +#' @importFrom readxl read_excel anchored +#' @importFrom data.table setDT := .SD +#' @importFrom zoo na.locf +#' +#' @examples +#' \dontrun{ +#' +#' mydt <- read_planning("1805_Planning Mensuel GDF SUEZ_REF.xlsx") +#' +#' } +#' +read_planning <- function(path, sheet = "Planning", start_col = "A", start_row = 16) { + + data <- read_excel( + path = path, + sheet = sheet, + range = anchored(anchor = paste0(start_col, start_row + 1), dim = c(NA, 12)), + col_names = c("nom_site", "num_tranche", "code_gp", "pcn_mw", + "dt_debut_arret", "dt_fin_arret", + "dt_debut_corr", "dt_fin_corr", "num_corr", + 'dt_debut_acc', "dt_fin_acc", "num_acc"), + col_types = c("text", "numeric", "text", "numeric", + "date", "date", + "date", "date", "text", + "date", "date", "text") + ) + setDT(data) + + # convert POSIXct columns to Date + date_cols <- c("dt_debut_arret", "dt_fin_arret", + "dt_debut_corr", "dt_fin_corr", + "dt_debut_acc", "dt_fin_acc") + data[, (date_cols) := lapply(X = .SD, FUN = as.Date), .SDcols = date_cols] + + # carry forward values in the first 4 columns + first_cols <- c("nom_site", "num_tranche", "code_gp", "pcn_mw") + data[, (first_cols) := lapply(X = .SD, FUN = na.locf, na.rm = FALSE), .SDcols = first_cols] + + # remove empty rows + data2 <- data[, setdiff(names(data), first_cols), with = FALSE] + data <- data[rowSums(is.na(data2)) != ncol(data2), ] +} diff --git a/R/read_planning_rte.R b/R/read_planning_rte.R new file mode 100644 index 0000000..febfd04 --- /dev/null +++ b/R/read_planning_rte.R @@ -0,0 +1,39 @@ + +#' Read Rte planning +#' +#' @param path Path to file. +#' @param clusters_desc Clusters description. +#' +#' @return a \code{data.table} +#' @export +#' +#' @importFrom readxl read_excel cell_limits +#' @importFrom janitor clean_names +#' @importFrom data.table setDT copy := +#' @importFrom stringr str_replace_all +read_planning_rte <- function(path, clusters_desc) { + plan_rte <- read_excel(path = path, sheet = 1, range = cell_limits(c(8, 5), c(NA, NA))) + plan_rte <- janitor::clean_names(plan_rte) + setDT(plan_rte) + plan_rte <- plan_rte[, list(groupe, date_debut, date_fin_arret)] + + corresp_gp <- corresp_gps() + plan_rte <- merge( + x = plan_rte, + y = corresp_gp, + by = "groupe" + ) + plan_rte[, groupe := str_replace_all(groupe, "[:space:]", "")] + + clusters_desc <- copy(clusters_desc) + clusters_desc[, nom := str_replace_all(nom, "[:space:]", "")] + + plan_rte <- merge( + x = plan_rte, all.x = TRUE, all.y = FALSE, by = "groupe", + y = clusters_desc[, list(groupe = nom, pcn_mw, pmin_mw)] + ) + plan_rte[, `:=`(pcn_mw = as.numeric(pcn_mw), pmin_mw = as.numeric(pmin_mw))] + plan_rte[] +} + + diff --git a/R/setup_study.R b/R/setup_study.R new file mode 100644 index 0000000..c529a11 --- /dev/null +++ b/R/setup_study.R @@ -0,0 +1,33 @@ + +#' Create an (empty) Antares study for Extended Shutdown Simulation +#' +#' @param path Path to a directory where to create study. +#' @param study_name Name of the study. +#' @param area_name Name of the area to create +#' +#' @export +#' +#' @importFrom antaresEditObject createStudy updateGeneralSettings createArea +#' @importFrom antaresRead setSimulationPath +setup_study <- function(path, study_name = "prolongation-arrets", area_name = "area") { + createStudy(path = path, study_name = study_name) + + opts <- setSimulationPath(path = path, simulation = "input") + + opts <- updateGeneralSettings( + first.month.in.year = "july", + first.weekday = "Sunday", + horizon = "2018-2019", + opts = opts + ) + + opts <- createArea(name = area_name, opts = opts) + invisible(opts) +} + + + + + + + diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..f0f10de --- /dev/null +++ b/R/utils.R @@ -0,0 +1,14 @@ + + +n_days_overlap <- function(x, y) { + seq_y <- seq(from = y[1], to = y[2], by = "days") + sum(seq_y >= x[1] & seq_y <= x[2]) +} + +n_overlaps <- function(w1, w2, s1, s2) { + x1 <- (as.numeric(w2 - s1) + 1) * (s1 > w1 & s1 < w2 & s2 >= w2) + x2 <- (as.numeric(s2 - w1) + 1) * (s2 > w1 & s2 < w2 & s1 <= w1) + x3 <- 7 * (s1 <= w1 & s2 >= w2) + x4 <- (as.numeric(s2 - s1) + 1) * (s1 > w1 & s2 < w2) + x1 + x2 + x3 + x4 +} diff --git a/R/zzz.R b/R/zzz.R new file mode 100644 index 0000000..95d46da --- /dev/null +++ b/R/zzz.R @@ -0,0 +1,10 @@ + +utils::globalVariables(c("tranche", "date_de_fin_avec_prolongation", "date_de_fin_sans_prolongation", + "duree_prolongation_mean", "duree_prolongation_semaine", "duree_prolongation_jour", + ".SD", "palier", "n_days", "patterns", "nom", "pcn_mw", "type_groupe", "x7", + "dates", "year", "week", "saturdays", "n", ".N", "num_seq", "kidispo_hqe", + ".id", "corresp_groupes", "date_debut", "group", "shutdown_end", "shutdown_start", + "week_end", "week_start", "group_power", "abat_rso", "type_darret", "pmin_mw", + "n_sem_annee", "kif", "kistretch", "kienv", "kihiver", "kibouclage", "code_palier", "palier", + "code_gp", "dt_debut_arret", "edp_ed_prev", "nom_site", "date_fin_arret", + "code_groupe", "date_fin_arret", "groupe")) diff --git a/README.md b/README.md new file mode 100644 index 0000000..3441bd2 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# antaresThermalTS + + + +## Installation + +```r +remotes::install_github("rte-antares-rpackage/antaresThermalTS") +``` diff --git a/man/build_weekcal.Rd b/man/build_weekcal.Rd new file mode 100644 index 0000000..dbe4f85 --- /dev/null +++ b/man/build_weekcal.Rd @@ -0,0 +1,24 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/build_weekcal.R +\name{build_weekcal} +\alias{build_weekcal} +\title{Build Week calendar} +\usage{ +build_weekcal(start = 2018, end = 2020) +} +\arguments{ +\item{start}{Starting year} + +\item{end}{Ending year} +} +\value{ +a \code{data.table} +} +\description{ +Build Week calendar +} +\examples{ + +build_weekcal() + +} diff --git a/man/compute_kd_coefs.Rd b/man/compute_kd_coefs.Rd new file mode 100644 index 0000000..cd73a01 --- /dev/null +++ b/man/compute_kd_coefs.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/compute_kd_coefs.R +\name{compute_kd_coefs} +\alias{compute_kd_coefs} +\title{Compute Kd coefficients} +\usage{ +compute_kd_coefs(kipr, kivt, kd_cho) +} +\arguments{ +\item{kipr}{Kipr coefficient from \code{\link{compute_kipr}}.} + +\item{kivt}{Kivt coefficient from \code{\link{compute_kivt}}.} + +\item{kd_cho}{Kd coefficients read with \code{\link{read_kd_cho}}.} +} +\value{ +a \code{data.table} +} +\description{ +Compute Kd coefficients +} diff --git a/man/compute_kipr.Rd b/man/compute_kipr.Rd new file mode 100644 index 0000000..8cddc95 --- /dev/null +++ b/man/compute_kipr.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/compute_kipr.R +\name{compute_kipr} +\alias{compute_kipr} +\title{Compute Kipr coefficient} +\usage{ +compute_kipr(calendar, clusters_desc, years = NULL) +} +\arguments{ +\item{calendar}{Calendar data read with \code{\link{read_calendar}}.} + +\item{clusters_desc}{Clusters / groups description read with \code{\link{read_cluster_desc}}.} + +\item{years}{Years to consider, if \code{NULL} (default), year range from \code{calendar} will be used.} +} +\value{ +a \code{data.table} +} +\description{ +Compute Kipr coefficient +} +\examples{ +\dontrun{ +# Calendar data +calendar <- read_calendar(path = "REF_Planning_5_ans_mars_2018.xlsx") + +# Clusters description +clusters <- read_cluster_desc("HypothesesRTE_CHO-4145.xlsx") + + +# Kipr computation +kipr <- compute_kipr(calendar, clusters) +kipr +} +} diff --git a/man/compute_kivt.Rd b/man/compute_kivt.Rd new file mode 100644 index 0000000..1522089 --- /dev/null +++ b/man/compute_kivt.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/compute_kivt.R +\name{compute_kivt} +\alias{compute_kivt} +\title{Compute Kivt coefficient} +\usage{ +compute_kivt(calendar, clusters_desc, years = NULL) +} +\arguments{ +\item{calendar}{Calendar data read with \code{\link{read_calendar}}.} + +\item{clusters_desc}{Clusters / groups description read with \code{\link{read_cluster_desc}}.} + +\item{years}{Years to consider, if \code{NULL} (default), year range from \code{calendar} will be used.} +} +\value{ +a \code{data.table} +} +\description{ +Compute Kivt coefficient +} +\examples{ +\dontrun{ +# Calendar data +calendar <- read_calendar(path = "REF_Planning_5_ans_mars_2018.xlsx") + +# Clusters description +clusters <- read_cluster_desc("HypothesesRTE_CHO-4145.xlsx") + + +# Kivt computation +kivt <- compute_kivt(calendar, clusters) +kivt +} +} diff --git a/man/create_clusters_edf.Rd b/man/create_clusters_edf.Rd new file mode 100644 index 0000000..e674f8c --- /dev/null +++ b/man/create_clusters_edf.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_clusters_edf.R +\name{create_clusters_edf} +\alias{create_clusters_edf} +\title{Create EDF clusters} +\usage{ +create_clusters_edf(planning, opts = simOptions()) +} +\arguments{ +\item{planning}{Calendar data read with \code{\link{read_calendar}}.} + +\item{opts}{List of simulation parameters returned by the function +\code{setSimulationPath}} +} +\description{ +Create EDF clusters +} diff --git a/man/create_clusters_nuclear.Rd b/man/create_clusters_nuclear.Rd new file mode 100644 index 0000000..c27ddba --- /dev/null +++ b/man/create_clusters_nuclear.Rd @@ -0,0 +1,27 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_clusters_nuclear.R +\name{create_clusters_nuclear} +\alias{create_clusters_nuclear} +\title{Create nuclear clusters} +\usage{ +create_clusters_nuclear(calendar, clusters_desc, kd_cho, + law_planned = "geometric", volatility_planned = 1, + opts = simOptions()) +} +\arguments{ +\item{calendar}{Calendar data read with \code{\link{read_calendar}}.} + +\item{clusters_desc}{Clusters / groups description read with \code{\link{read_cluster_desc}}.} + +\item{kd_cho}{Kd coefficients read with \code{\link{read_kd_cho}}.} + +\item{law_planned}{Law to use in Antares.} + +\item{volatility_planned}{Volatility for the law.} + +\item{opts}{List of simulation parameters returned by the function +\code{setSimulationPath}} +} +\description{ +Create nuclear clusters +} diff --git a/man/create_clusters_other.Rd b/man/create_clusters_other.Rd new file mode 100644 index 0000000..f68baee --- /dev/null +++ b/man/create_clusters_other.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/create_clusters_other.R +\name{create_clusters_other} +\alias{create_clusters_other} +\title{Create other clusters} +\usage{ +create_clusters_other(planning, infos, opts = simOptions()) +} +\arguments{ +\item{planning}{Calendar data read with \code{\link{read_calendar}}.} + +\item{infos}{Info} + +\item{opts}{List of simulation parameters returned by the function +\code{setSimulationPath}} +} +\description{ +Create other clusters +} diff --git a/man/read-kd-cho.Rd b/man/read-kd-cho.Rd new file mode 100644 index 0000000..26b9070 --- /dev/null +++ b/man/read-kd-cho.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read-kd-cho.R +\name{read-kd-cho} +\alias{read-kd-cho} +\alias{read_kd_cho} +\alias{read_kd_cho_macro} +\title{Read sheet "Kd CHO" from RTE hypothesis} +\usage{ +read_kd_cho(path) + +read_kd_cho_macro(path) +} +\arguments{ +\item{path}{Path to Excel file.} +} +\value{ +a \code{data.table} +} +\description{ +Read sheet "Kd CHO" from RTE hypothesis +} diff --git a/man/read_calendar.Rd b/man/read_calendar.Rd new file mode 100644 index 0000000..aec3989 --- /dev/null +++ b/man/read_calendar.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read_calendar.R +\name{read_calendar} +\alias{read_calendar} +\title{Read calendar data} +\usage{ +read_calendar(path) +} +\arguments{ +\item{path}{Path to a file.} +} +\value{ +a \code{data.table} +} +\description{ +Read calendar data +} diff --git a/man/read_cluster_desc.Rd b/man/read_cluster_desc.Rd new file mode 100644 index 0000000..4de5247 --- /dev/null +++ b/man/read_cluster_desc.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read_cluster_desc.R +\name{read_cluster_desc} +\alias{read_cluster_desc} +\title{Read Cluster Description} +\usage{ +read_cluster_desc(path) +} +\arguments{ +\item{path}{Path to Excel file} +} +\value{ +a \code{data.table} +} +\description{ +Read Cluster Description +} +\examples{ +\dontrun{ + +cluster_desc <- read_cluster_desc("HypothesesRTE_CHO-4145.xlsx") + +} + +} diff --git a/man/read_info.Rd b/man/read_info.Rd new file mode 100644 index 0000000..2033170 --- /dev/null +++ b/man/read_info.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read_info.R +\name{read_info} +\alias{read_info} +\title{Read other clusters informations} +\usage{ +read_info(path) +} +\arguments{ +\item{path}{Path to file.} +} +\value{ +a \code{data.table} +} +\description{ +Read other clusters informations +} diff --git a/man/read_planning.Rd b/man/read_planning.Rd new file mode 100644 index 0000000..d36b638 --- /dev/null +++ b/man/read_planning.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read_planning.R +\name{read_planning} +\alias{read_planning} +\title{Read a maintenance planning} +\usage{ +read_planning(path, sheet = "Planning", start_col = "A", + start_row = 16) +} +\arguments{ +\item{path}{Character. Path to the Excel file} + +\item{sheet}{Character. Sheet in which the planning can be found. Defaults to 'Planning'.} + +\item{start_col}{Character. Leftmost column of the planning (upper-case letter). Defaults to 'A'.} + +\item{start_row}{Integer. Row number of the planning's header. Defaults to 16.} +} +\value{ +A 12-column \code{data.table}: the same 12 columns as in the Excel sheet. Useless rows + are dropped, and values from the first 4 columns are repeated in order to obtain a 'tidy' + dataset. +} +\description{ +Read a maintenance planning +} +\examples{ +\dontrun{ + +mydt <- read_planning("1805_Planning Mensuel GDF SUEZ_REF.xlsx") + +} + +} diff --git a/man/read_planning_rte.Rd b/man/read_planning_rte.Rd new file mode 100644 index 0000000..6dcfdd8 --- /dev/null +++ b/man/read_planning_rte.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/read_planning_rte.R +\name{read_planning_rte} +\alias{read_planning_rte} +\title{Read Rte planning} +\usage{ +read_planning_rte(path, clusters_desc) +} +\arguments{ +\item{path}{Path to file.} + +\item{clusters_desc}{Clusters description.} +} +\value{ +a \code{data.table} +} +\description{ +Read Rte planning +} diff --git a/man/setup_study.Rd b/man/setup_study.Rd new file mode 100644 index 0000000..d2cdfd5 --- /dev/null +++ b/man/setup_study.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/setup_study.R +\name{setup_study} +\alias{setup_study} +\title{Create an (empty) Antares study for Extended Shutdown Simulation} +\usage{ +setup_study(path, study_name = "prolongation-arrets", + area_name = "area") +} +\arguments{ +\item{path}{Path to a directory where to create study.} + +\item{study_name}{Name of the study.} + +\item{area_name}{Name of the area to create} +} +\description{ +Create an (empty) Antares study for Extended Shutdown Simulation +}