R/runWaterValuesSimulation.R

Defines functions runWaterValuesSimulationMultiStock resetStudy runWaterValuesSimulation

Documented in resetStudy runWaterValuesSimulation runWaterValuesSimulationMultiStock

#' Run a simulation for calculating water values for a specific area
#'
#' @param area The area concerned by the simulation.
#' @param simulation_name The name of the simulation, \code{s} is a placeholder for the constraint value defined by \code{nb_disc_stock}.
#' @param nb_disc_stock Number of simulation to launch, a vector of energy constraint
#'  will be created from maximum pumping power to the hydro storage maximum and of length this parameter.
#' @param nb_mcyears Number of Monte Carlo years to simulate or a vector of years indexes to launch.
#' @param binding_constraint Name of the binding constraint.
#  constraint_values Vector of energy constraints on the link between the area and the fictive area.
#' @param fictive_area Name of the fictive area to create, argument passed to \code{\link{setupWaterValuesSimulation}}.
#'
#' @param thermal_cluster Name of the thermal cluster to create, argument passed to \code{\link{setupWaterValuesSimulation}}.
#' @param path_solver Character containing the Antares Solver path, argument passed to \code{\link[antaresEditObject]{runSimulation}}.
#' @param wait Argument passed to \code{\link[antaresEditObject]{runSimulation}}.
#' @param show_output_on_console Argument passed to \code{\link[antaresEditObject]{runSimulation}}.
#' @param overwrite If area or cluster already exists, should they be overwritten?
#' @param link_from area that will be linked to the created fictive area. If it's
#' \code{NULL} it will takes the area concerned by the simulation.
#' @param otp_dest the path in which the script save Rdata file.
#' @param file_name the Rdata file name.
#' @param remove_areas 	Character vector of area(s) to remove from the created district.
#' @param shiny Boolean. True to run the script in shiny mod.
#' @param pumping Boolean. True to take into account the pumping.
#' @param efficiency in [0,1]. efficient ratio of pumping.
#' @param launch_simulations Boolean. True to to run the simulations.
#' @param reset_hydro Boolean. True to reset hydro inflow to 0 before the simulation.
#' @param opts
#'   List of simulation parameters returned by the function
#'   \code{antaresRead::setSimulationPath}
#' @param ... further arguments passed to or from other methods.
#' @param area area
#' @param simulation_name character
#' @param nb_disc_stock integer
#' @param nb_mcyears list
#' @param constraint_values constraint values to use to run simulations, generated by the function \code{\link{constraint_generator}}
#' @param binding_constraint character
#' @param expansion Binary. True if mode expansion was used to run simulations
#'
#' @note This function have side effects on the Antares study used, a fictive area is created and a new district as well.
#'
#' @export
#'

runWaterValuesSimulation <- function(area,
                                     simulation_name = "wv_sim_%s",
                                     nb_disc_stock = 10,
                                     nb_mcyears = NULL,
                                     binding_constraint = "weekly_water_amount",
                                     fictive_area = NULL,
                                     thermal_cluster = NULL,
                                     path_solver=NULL,
                                     wait = TRUE,
                                     show_output_on_console = FALSE,
                                     overwrite = FALSE,
                                     link_from=NULL,
                                     remove_areas=NULL,
                                     opts = antaresRead::simOptions(),
                                     shiny=F,otp_dest=NULL,file_name=NULL,
                                     pumping=F,
                                     efficiency=NULL,
                                     launch_simulations=T,
                                     reset_hydro=T,
                                     constraint_values=NULL,
                                     expansion=T,
                                     ...){






  #check the study is well selected
  assertthat::assert_that(class(opts) == "simOptions")

  fictive_areas <- area

  # check the name format

  if(!endsWith(simulation_name,"_%s")){
    simulation_name <- paste0(simulation_name,"_%s")
  }

  if (!stringr::str_detect(file_name,area)){
    file_name <- paste0(area,"_",file_name)
  }


  # restore hydro inflow if there is a previous intercepted simulation.
  restoreHydroStorage(area = area, opts = opts,silent = T)
  # restore Pump power if there is a previous intercepted simulation.
  restorePumpPower(area = area, opts = opts,silent = T)

  restore_fictive_fatal_prod_demand(area = area, opts = opts,silent = T)

  # MC years
  assertthat::assert_that(is.numeric(nb_mcyears)==TRUE)

  if(length(nb_mcyears)==1){
    play_years <- seq(1,nb_mcyears)
  }else{
    play_years <- nb_mcyears
  }

  antaresEditObject::setPlaylist(playlist = play_years,opts = opts)

  #assert the weekly output of the area:

  antaresEditObject::editArea(name = area,
                              filtering =
                                antaresEditObject::filteringOptions(filter_synthesis = c("hourly" , "weekly", "annual"),
                                                 filter_year_by_year = c("hourly", "weekly", "annual"))
                              ,opts = opts)

  #generating the fictive area parameters

  fictive_area <- if (!is.null(fictive_area)) fictive_area else paste0("watervalue_", area)
  thermal_cluster <- if (!is.null(thermal_cluster)) thermal_cluster else "water_value_cluster"

  # Get max hydro power that can be generated in a week
  if (is.null(constraint_values)){
    constraint_values <- constraint_generator(area=area,nb_disc_stock=nb_disc_stock,
                                              pumping=pumping,
                                              pumping_efficiency = efficiency,
                                              opts=opts, mcyears=play_years)
  }
  if ("mcYear" %in% names(constraint_values)){
    constraint_values <- constraint_values %>%
      dplyr::filter(.data$mcYear %in% play_years, .data$week %in% 1:52)
  } else {
    constraint_values <- constraint_values %>%
      dplyr::filter(.data$week %in% 1:52)
  }
  nb_disc_stock <- dplyr::n_distinct(constraint_values$sim)

  # Get efficiency

  if (is.null(efficiency)){
    efficiency <- getPumpEfficiency(area = area)

  }

  #create the fictive areas

  opts <- setupWaterValuesSimulation(
    area = area,
    fictive_area_name = fictive_area,
    thermal_cluster = thermal_cluster,
    overwrite = overwrite,
    remove_areas=remove_areas,
    reset_hydro=reset_hydro,
    opts = opts,
    link_from = link_from,
    pumping=pumping,
    max_load=max(abs(constraint_values$u))*10
  )



  #generate the flow sens
  fictive_areas <- c(paste0(fictive_area,"_turb"),paste0(fictive_area,"_bc"))
  coeff_turb <- generate_link_coeff(area,fictive_areas[1], pumping, opts)
  coeff_bc <- generate_link_coeff(area,fictive_areas[2], pumping, opts)
  coeff <- c(coeff_turb,coeff_bc)

  if(pumping){
    fictive_areas <- c(fictive_areas,paste0(fictive_area,"_pump"))
    coeff_pump <- generate_link_coeff(area,fictive_areas[3], pumping, opts)
    coeff <- c(coeff,coeff_pump)
  }

  restoreScenarioBuilder(opts=opts, fictive_area = fictive_areas[2])

  # Start the simulations

  simulation_names <- vector(mode = "character", length = nb_disc_stock)

  # Implement binding constraint
  generate_constraints(coeff=coeff,name_constraint=binding_constraint,
                       efficiency=efficiency,opts=opts,area = area)

  for (i in 1:nb_disc_stock) {
    # Prepare simulation parameters
    name_sim <- dplyr::distinct(constraint_values,.data$sim)$sim[[i]]
    constraint_value <- dplyr::filter(constraint_values,.data$sim==name_sim)

    generate_rhs_bc(constraint_value=constraint_value,coeff=coeff,opts=opts)

    sim_name <- paste0(file_name,"_",sprintf(simulation_name, format(
      stringr::str_extract(name_sim, "\\d+$"), decimal.mark = ",")))
    message("#  ------------------------------------------------------------------------")
    message(paste0("Running simulation: ", i, " - ", sim_name))
    message("#  ------------------------------------------------------------------------")
    # run the simulation
    if(launch_simulations){
      antaresEditObject::runSimulation(
        name = sim_name,
        mode = if (!expansion){"economy"}else{"expansion"},
        wait = wait,
        path_solver = path_solver,
        show_output_on_console = show_output_on_console,
        opts = opts
      )
    }
    simulation_names[i] <- sim_name

    if(launch_simulations){
      #Simulation Control
      sim_name <- utils::tail(getSimulationNames(pattern =sim_name , opts = opts),n=1)
      sim_check <- file.path(opts$studyPath,"output",sim_name)

      if(!dir.exists(file.path(sim_check,"economy","mc-all"))){
        #remove the Binding Constraints

        disable_constraint(binding_constraint,opts,pumping,area = area)
        restoreScenarioBuilder(opts=opts, fictive_area = fictive_areas[2])
        # remove the fictive area
        suppressWarnings({
          for (fictive_area in fictive_areas){
            antaresEditObject::removeArea(fictive_area,opts = opts)
          }
        })

        # restore hydrostorage
        restoreHydroStorage(area = area, opts = opts)
        restorePumpPower(area = area, opts = opts)
        restore_fictive_fatal_prod_demand(area = area, opts = opts)
        stop("Simulation Error. Please check simulation log.")
      }
    }
  }

  #remove the Binding Constraints

  disable_constraint(binding_constraint,opts,pumping,area = area)
  restoreScenarioBuilder(opts=opts, fictive_area = fictive_areas[2])

  # remove the fictive area
  if(launch_simulations){
    suppressWarnings({
      for (fictive_area in fictive_areas){
        antaresEditObject::removeArea(fictive_area,opts = opts)
      }
    })
  }

  # restore hydrostorage
  restoreHydroStorage(area = area, opts = opts)
  restorePumpPower(area = area, opts = opts)
  restore_fictive_fatal_prod_demand(area = area, opts = opts)

  simulation_res <- list(
    simulation_names = simulation_names,
    simulation_values = constraint_values,
    area = area,
    mc_years = nb_mcyears,
    pumping = pumping,
    eff = efficiency,
    expansion = expansion,
    fictive_areas = fictive_areas
  )

  if(!is.null(otp_dest)){

    main_path <- getwd()

    setwd(otp_dest)

    save(simulation_res,file=paste0(file_name,".RData"))

    setwd(main_path)
  }

  return(simulation_res)

}

#' Reset an Antares study. In case, there is a problem when executing \code{runWaterValuesSimulation},
#' run this function to restore the study.
#'
#' @param opts  List of simulation parameters returned by the function
#'   \code{antaresRead::setSimulationPath}
#' @param area The area concerned by the simulation
#' @param pumping Boolean. True to take into account the pumping.
#' @param fictive_area Name of the fictive area created
#' @param binding_constraint character
#'
#' @export
resetStudy <- function(opts, area, pumping,fictive_area = NULL,
                       binding_constraint="weekly_water_amount"){

  fictive_area <- if (!is.null(fictive_area)) fictive_area else paste0("watervalue_", area)

  disable_constraint(binding_constraint,opts,pumping,area = area)

  fictive_areas <- c(paste0(fictive_area,"_turb"),paste0(fictive_area,"_bc"))

  if(pumping){
    fictive_areas <- c(fictive_areas,paste0(fictive_area,"_pump"))
  }

  restoreScenarioBuilder(opts=opts, fictive_area = fictive_areas[2])

  for (fictive_area in fictive_areas){
    if (fictive_area %in% opts$areaList){
      antaresEditObject::removeArea(fictive_area,opts = opts)
    }
  }

  # restore hydrostorage
  restoreHydroStorage(area = area, opts = opts)
  restorePumpPower(area = area, opts = opts)
  restore_fictive_fatal_prod_demand(area = area, opts = opts)
}

#' Run a simulation for calculating water values for a specific area
#'
#' @param simulation_name The name of the simulation, \code{s} is a placeholder for the constraint value defined by \code{nb_disc_stock}.
#' @param nb_mcyears Number of Monte Carlo years to simulate or a vector of years indexes to launch.
#' @param binding_constraint Name of the binding constraint.
#' @param path_solver Character containing the Antares Solver path, argument passed to \code{\link[antaresEditObject]{runSimulation}}.
#' @param wait Argument passed to \code{\link[antaresEditObject]{runSimulation}}.
#' @param show_output_on_console Argument passed to \code{\link[antaresEditObject]{runSimulation}}.
#' @param overwrite If area or cluster already exists, should they be overwritten?
#' @param otp_dest the path in which the script save Rdata file.
#' @param file_name the Rdata file name.
#' @param shiny Boolean. True to run the script in shiny mod.
#' @param launch_simulations Boolean. True to to run the simulations.
#' @param reset_hydro Boolean. True to reset hydro inflow to 0 before the simulation.
#' @param opts
#'   List of simulation parameters returned by the function
#'   \code{antaresRead::setSimulationPath}
#' @param ... further arguments passed to or from other methods.
#' @param simulation_name character
#' @param nb_mcyears list
#' @param constraint_values constraint values to use to run simulations, generated by the function \code{\link{constraint_generator}}
#' @param binding_constraint character
#' @param list_areas List of areas concerned by the simulation.
#' @param list_pumping List of bools to tell if pumping is available in areas
#' @param list_efficiency List of pumping efficiency
#' @param expansion Binary. True if mode expansion was used to run simulations
#'
#' @note This function have side effects on the Antares study used, a fictive area is created and a new district as well.
#'
#' @export
#'

runWaterValuesSimulationMultiStock <- function(list_areas,
                                               list_pumping,
                                               list_efficiency,
                                     simulation_name = "wv_sim_%s",
                                     nb_mcyears = NULL,
                                     binding_constraint = "weekly_water_amount",
                                     path_solver=NULL,
                                     wait = TRUE,
                                     show_output_on_console = FALSE,
                                     overwrite = FALSE,
                                     opts = antaresRead::simOptions(),
                                     shiny=F,otp_dest=NULL,file_name=NULL,
                                     launch_simulations=T,
                                     reset_hydro=T,
                                     constraint_values=NULL,
                                     expansion=T,...){






  #check the study is well selected
  assertthat::assert_that(class(opts) == "simOptions")

  # check the name format

  if(!endsWith(simulation_name,"_%s")){
    simulation_name <- paste0(simulation_name,"_%s")
  }

  # MC years
  assertthat::assert_that(is.numeric(nb_mcyears)==TRUE)

  if(length(nb_mcyears)==1){
    play_years <- seq(1,nb_mcyears)
  }else{
    play_years <- nb_mcyears
  }

  antaresEditObject::setPlaylist(playlist = play_years,opts = opts)

  if ("mcYear" %in% names(constraint_values)){
    constraint_values <- constraint_values %>%
      dplyr::filter(.data$mcYear %in% play_years, .data$week %in% 1:52)
  } else {
    constraint_values <- constraint_values %>%
      dplyr::filter(.data$week %in% 1:52)
  }
  nb_disc_stock <- dplyr::n_distinct(constraint_values$sim)

  remove_area <- c()
  list_coeff <- list()

  for (area in list_areas){
    # restore hydro inflow if there is a previous intercepted simulation.
    restoreHydroStorage(area = area, opts = opts,silent = T)
    # restore Pump power if there is a previous intercepted simulation.
    restorePumpPower(area = area, opts = opts,silent = T)

    restore_fictive_fatal_prod_demand(area = area, opts = opts,silent = T)

    #assert the weekly output of the area:

    antaresEditObject::editArea(name = area,
                                filtering =
                                  antaresEditObject::filteringOptions(filter_synthesis = c("hourly" , "weekly", "annual"),
                                                                      filter_year_by_year = c("hourly", "weekly", "annual"))
                                ,opts = opts)

    #generating the fictive area parameters

    fictive_area <- paste0("watervalue_", area)
    thermal_cluster <- "water_value_cluster"

    #create the fictive areas

    opts <- setupWaterValuesSimulation(
      area = area,
      fictive_area_name = fictive_area,
      thermal_cluster = thermal_cluster,
      overwrite = overwrite,
      reset_hydro=reset_hydro,
      opts = opts,
      pumping=list_pumping[area],
      max_load=max(abs(constraint_values$u))*10
    )

    #generate the flow sens
    fictive_areas <- c(paste0(fictive_area,"_turb"),paste0(fictive_area,"_bc"))
    coeff_turb <- generate_link_coeff(area,fictive_areas[1],list_pumping[area], opts)
    coeff_bc <- generate_link_coeff(area,fictive_areas[2], list_pumping[area], opts)
    coeff <- c(coeff_turb,coeff_bc)

    if(list_pumping[area]){
      fictive_areas <- c(fictive_areas,paste0(fictive_area,"_pump"))
      coeff_pump <- generate_link_coeff(area,fictive_areas[3], list_pumping[area], opts)
      coeff <- c(coeff,coeff_pump)
    }

    if (length(list_coeff)==0){
      list_coeff <- list(coeff)
    } else {
      list_coeff <- c(list_coeff,list(coeff))
    }

    remove_area <- c(remove_area,fictive_areas)

    restoreScenarioBuilder(opts=opts, fictive_area = fictive_areas[2])

    # Implement binding constraint
    generate_constraints(coeff=coeff,name_constraint=paste0(binding_constraint,"_",area),
                         efficiency=list_efficiency[area],opts=opts,area = area)

  }

  opts <- antaresEditObject::createDistrict(
    name = "water values district",
    caption = "water values district",
    comments = "Used for calculate water values",
    apply_filter = "add-all",
    remove_area = remove_area,
    output = TRUE,
    overwrite = TRUE,
    opts = opts
  )

  # Start the simulations

  simulation_names <- vector(mode = "character", length = nb_disc_stock)

  for (i in 1:nb_disc_stock) {
    # Prepare simulation parameters
    name_sim <- dplyr::distinct(constraint_values,.data$sim)$sim[[i]]

    for (j in 1:length(list_areas)){
      constraint_value <- dplyr::filter(constraint_values,.data$sim==name_sim,
                                        .data$area==list_areas[[j]]) %>%
        dplyr::select(-c("area"))

      if (length(list_areas)==1){
        coeff <- list_coeff
      } else {
        coeff <- list_coeff[[j]]
      }
      generate_rhs_bc(constraint_value=constraint_value,coeff=coeff,opts=opts)
    }


    sim_name <- paste0(file_name,"_",sprintf(simulation_name, format(
      stringr::str_extract(name_sim, "\\d+$"), decimal.mark = ",")))
    message("#  ------------------------------------------------------------------------")
    message(paste0("Running simulation: ", i, " - ", sim_name))
    message("#  ------------------------------------------------------------------------")
    # run the simulation
    if(launch_simulations){
      antaresEditObject::runSimulation(
        name = sim_name,
        mode = if (!expansion){"economy"}else{"expansion"},
        wait = wait,
        path_solver = path_solver,
        show_output_on_console = show_output_on_console,
        opts = opts
      )
    }
    simulation_names[i] <- sim_name

    if(launch_simulations){
      #Simulation Control
      sim_name <- utils::tail(getSimulationNames(pattern =sim_name , opts = opts),n=1)
      sim_check <- file.path(opts$studyPath,"output",sim_name)

      if(!dir.exists(file.path(sim_check,"economy","mc-all"))){
        #remove the Binding Constraints

        for (j in 1:length(list_areas)){
          area <- list_areas[[j]]
          disable_constraint(paste0(binding_constraint,"_",area),opts,list_pumping[[j]],area = area)
          restoreScenarioBuilder(opts=opts, fictive_area = paste0("watervalue_", area,"_bc"))
          # restore hydrostorage
          restoreHydroStorage(area = area, opts = opts)
          restorePumpPower(area = area, opts = opts)
          restore_fictive_fatal_prod_demand(area = area, opts = opts)
        }
        # remove the fictive area
        suppressWarnings({
          for (fictive_area in remove_area){
            antaresEditObject::removeArea(fictive_area,opts = opts)
          }
        })

        stop("Simulation Error. Please check simulation log.")
      }
    }
  }

  for (j in 1:length(list_areas)){
    area <- list_areas[[j]]
    disable_constraint(paste0(binding_constraint,"_",area),opts,list_pumping[[j]],area = area)
    restoreScenarioBuilder(opts=opts, fictive_area = paste0("watervalue_", area,"_bc"))
    # restore hydrostorage
    restoreHydroStorage(area = area, opts = opts)
    restorePumpPower(area = area, opts = opts)
    restore_fictive_fatal_prod_demand(area = area, opts = opts)
  }

  # remove the fictive area
  if(launch_simulations){
    suppressWarnings({
      for (fictive_area in remove_area){
        antaresEditObject::removeArea(fictive_area,opts = opts)
      }
    })
  }

  simulation_res <- list(
    simulation_names = simulation_names,
    simulation_values = constraint_values,
    list_areas = list_areas,
    mc_years = nb_mcyears
  )

  if(!is.null(otp_dest)){

    main_path <- getwd()

    setwd(otp_dest)

    save(simulation_res,file=paste0(file_name,".RData"))

    setwd(main_path)
  }

  return(simulation_res)

}
rte-antares-rpackage/antaresWaterValues documentation built on Nov. 6, 2024, 11:17 p.m.