#' Smart charging algorithm
#'
#' @param sessions sessions data set
#' @param fitting_data optimization fitting data, first column being `datetime`. The other columns could be `solar` (solar generation) and `fixed` (static demand from other sectors like buildings, offices, ...).
#' @param dttm_seq datetime sequence to apply smart charging
#' @param window_length optimization window length
#' @param opt_weights Named list with the optimization weight `w`. The names of the list must exactly match the user profiles names.
#' @param responsive Named list with the ratio of sessions responsive to smart charging program for each profile. The names of the list must exactly match the user profiles names.
#' @param power_th power threshold from to consider flexibility required
#' @param grid_cap numeric, grid power capacity (in kW)
#' @param up_to_G logical, whether to limit the flexible EV demand up to renewable Generation
#' @param sort_by_flex logical, whether to sort the sessions to shift from higher to lower flexibility
#' @param include_msg logical, whether to output the algorithm messages for every user profile and time-slot
#'
#' @importFrom dplyr %>% filter mutate_if mutate select everything row_number left_join bind_rows
#' @importFrom tibble column_to_rownames as_tibble
#' @importFrom rlang .data
#' @importFrom reticulate dict r_to_py import_from_path
#'
#' @return a list with two elements: optimization setpoints and coordinated sessions schedule
#' @export
#'
smart_charging <- function(sessions, fitting_data, dttm_seq, window_length, opt_weights, responsive, power_th = 0, grid_cap = NULL, up_to_G = TRUE, sort_by_flex = TRUE, include_msg = FALSE) {
if (!pyenv.exists()) load.pyenv()
# pyenv <- import_utils()
time_interval <- as.integer(as.numeric(dttm_seq[2] - dttm_seq[1], unit = 'hours')*60)
start <- dttm_seq[1]
end <- dttm_seq[length(dttm_seq)]
window <- c(0, length(dttm_seq)) %>% as.integer
window_length <- as.integer(window_length)
sessions_norm <- sessions %>%
filter(.data$ConnectionStartDateTime >= start) %>%
normalize_sessions(start, time_interval)
fitting_data_norm <- fitting_data %>%
filter(.data$datetime >= start, .data$datetime <= end) %>%
mutate(timeslot = row_number()) %>%
select(.data$timeslot, -.data$datetime, everything()) %>%
tibble::column_to_rownames("timeslot")
profiles_demand <- pyenv$get_demand(sessions_norm, window)
# Smart charging results
results <- pyenv$smart_charging(sessions_norm, profiles_demand, fitting_data_norm, window_length, dict(opt_weights), dict(responsive), power_th, r_to_py(grid_cap), r_to_py(up_to_G), r_to_py(sort_by_flex), r_to_py(include_msg))
setpoints <- as_tibble(results[[1]]) %>% mutate(datetime = dttm_seq) %>% select('datetime', everything())
sessions_opt <- denormalize_sessions(results[[2]], start, time_interval)
# Add sessions discarded by optimization windows
sessions_out <- sessions[!(sessions[['Session']] %in% sessions_norm[['Session']]), ]
sessions_opt_final <- bind_rows(sessions_opt, sessions_out)
sessions_opt_final_sorted <- left_join(sessions['Session'], sessions_opt_final, by = 'Session') %>%
select('Profile', everything())
if (include_msg) {
list(setpoints = setpoints, sessions = sessions_opt_final_sorted, msg = results[[3]])
} else {
list(setpoints = setpoints, sessions = sessions_opt_final_sorted)
}
}
# # DR potential ---------------------------------------------------------------
#
# get_interval_flexible_power <- function(interval, sessions_flex, interval_mins) {
# sessions_flex %>%
# group_by(Profile) %>%
# filter(
# StartTime <= interval,
# (StartTime + convert_time_num_to_period(ChargingTime)) >= (interval + minutes(interval_mins)),
# Flexibility > interval_mins/60
# ) %>%
# summarise(Power = sum(ChargingPower)) %>%
# mutate(datetime = interval) %>%
# spread(Profile, Power)
# }
#
# get_flexible_power <- function(sessions_flex, seq_dt, interval_mins) {
# tibble(datetime = seq_dt) %>%
# left_join(
# map_dfr(seq_dt, ~get_interval_flexible_power(.x, sessions_flex, interval_mins)),
# by = "datetime"
# ) %>%
# replace(is.na(.), 0)
# }
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.