Source code for src.datafev.algorithms.vehicle.scheduling_lp

# The datafev framework

# Copyright (C) 2022,
# Institute for Automation of Complex Power Systems (ACS),
# E.ON Energy Research Center (E.ON ERC),
# RWTH Aachen University

# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
# persons to whom the Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
# Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


from pyomo.core import *


[docs]def minimize_cost( solver, opt_step, opt_horizon, ecap, tarsoc, minsoc, maxsoc, crtsoc, crttime, inisoc, p_ch, p_ds, dps, ): """ This function optimizes the charging schedule of a single EV with the objective of charging cost minimization for the given price signal. The losses in power transfer are neglected. Parameters ---------- opt_step : float Size of one time step in the optimization (seconds). opt_horizon : list of integers Time step identifiers in the optimization horizon. ecap : float Energy capacity of battery (kWs). v2gall : float V2G allowance discharge (kWs). tarsoc : float Target final soc (0<inisoc<1). minsoc : float Minimum soc. maxsoc : float Maximum soc. crtsoc : float Target soc at crttime. crttime : int Critical time s.t. s(srttime) > crtsoc. inisoc : dict of float Initial soc \in [0,1). p_ch : dict of float Nominal charging power (kW). p_ds : dict of float Nominal charging power (kW). dps : dict of float Dynamic price signal (Eur/kWh). Returns ------- p_schedule : dict Power schedule. Each item in the EV dictionary indicates the power to be supplied to the EV(kW) during a particular time step. s_schedule : dict SOC schedule. Each item in the EV dictionary indicates the SOC to be achieved by the EV by a particular time step. """ conf_period = {} for t in opt_horizon: if t < crttime: conf_period[t] = 0 else: conf_period[t] = 1 ####################Constructing the optimization model#################### model = ConcreteModel() model.T = Set(initialize=opt_horizon, ordered=True) # Time index set model.dt = opt_step # Step size model.E = ecap # Battery capacity in kWs model.P_CH = p_ch # Maximum charging power in kW model.P_DS = p_ds # Maximum discharging power in kW model.price = dps # Energy price series model.SoC_F = tarsoc # SoC to be achieved at the end model.conf = conf_period # Confidence period where SOC must be larger than crtsoc model.SoC_R = crtsoc # Minimim SOC must be ensured in the confidence period model.p = Var(model.T, bounds=(-model.P_DS, model.P_CH)) model.SoC = Var(model.T, within=NonNegativeReals, bounds=(minsoc, maxsoc)) # CONSTRAINTS def initialsoc(model): return model.SoC[0] == inisoc model.inisoc = Constraint(rule=initialsoc) def storageConservation( model, t ): # SOC of EV batteries will change with respect to the charged power and battery energy capacity if t < max(model.T): return model.SoC[t + 1] == (model.SoC[t] + model.p[t] * model.dt / model.E) else: return model.SoC[t] == model.SoC_F model.socconst = Constraint(model.T, rule=storageConservation) def socconfidence(model, t): return model.SoC[t] >= model.SoC_R * model.conf[t] model.socconfi = Constraint(model.T, rule=socconfidence) def supplyrule(model): return model.p[max(model.T)] == 0.0 model.supconst = Constraint(rule=supplyrule) # OBJECTIVE FUNCTION def obj_rule(model): return ( sum(model.p[t] * model.price[t] for t in opt_horizon[:-1]) * opt_step / 3600 ) model.obj = Objective(rule=obj_rule, sense=minimize) solver.solve(model) p_schedule = {} s_schedule = {} for t in model.T: p_schedule[t] = model.p[t]() s_schedule[t] = model.SoC[t]() return p_schedule, s_schedule
if __name__ == "__main__": from pyomo.environ import SolverFactory import pandas as pd ########################################################################### # Input parameters solver = SolverFactory("gurobi") step = 600 # Time step size= 600 seconds = 10 minutes horizon = list(range(7)) # Optimization horizon= 6 steps = 60 minutes ecap = 55 * 3600 # Battery capacity= 55 kWh tarsoc = 0.8 # Target SOC minsoc = 0.2 # Minimum SOC maxsoc = 1.0 # Maximum SOC crtsoc = 0.6 # Critical SOC crttime = 4 # Critical time inisoc = 0.5 # Initial SOC pch = 22 # Maximum charge power pds = 22 # Maximum discharge power ########################################################################### print("Size of one time step:", step, "seconds") print("Optimization horizon covers", max(horizon), "time steps") print("Battery capacity of the EV:", ecap / 3600, "kWh") print("Initial SOC of the EV:", inisoc) print("Target SOC (at the end of optimization horizon):", tarsoc) print( "Critical SOC condition: SOC", crtsoc, "must be achieved by", crttime, "and must be maintained afterwards", ) print() print("Optimization is run for three dynamic price signals") print() dps1 = dict(enumerate([1, 1, 1, 0, 0, 0])) # Dynamic price signal 1 dps2 = dict(enumerate([0, 0, 1, 1, 1, 0])) # Dynamic price signal 2 dps3 = dict(enumerate([0, 0, 0, 1, 1, 1])) # Dynamic price signal 3 print("For the profile dps1:") print(dps1) p1, s1 = minimize_cost( solver, step, horizon, ecap, tarsoc, minsoc, maxsoc, crtsoc, crttime, inisoc, pch, pds, dps1, ) print("For the profile dps2:") print(dps2) p2, s2 = minimize_cost( solver, step, horizon, ecap, tarsoc, minsoc, maxsoc, crtsoc, crttime, inisoc, pch, pds, dps2, ) print("For the profile dps2:") print(dps2) p3, s3 = minimize_cost( solver, step, horizon, ecap, tarsoc, minsoc, maxsoc, crtsoc, crttime, inisoc, pch, pds, dps3, ) print() print("Printing optimization results in tables:") sched1 = pd.DataFrame(columns=["DPS", "SOC (%)"]) sched2 = pd.DataFrame(columns=["DPS", "SOC (%)"]) sched3 = pd.DataFrame(columns=["DPS", "SOC (%)"]) print("SOC (%): SOC trajectory in optimized schedule") print("P (kW): Power supply to the EV in optimized schedule") print() print("dps1") sched1["P (kW)"] = pd.Series(p1) sched1["SOC (%)"] = pd.Series(s1) * 100 sched1["DPS"] = pd.Series(dps1) print(sched1) print() print("dps2") sched2["P (kW)"] = pd.Series(p2) sched2["SOC (%)"] = pd.Series(s2) * 100 sched2["DPS"] = pd.Series(dps2) print(sched2) print() print("dps3") sched3["P (kW)"] = pd.Series(p3) sched3["SOC (%)"] = pd.Series(s3) * 100 sched3["DPS"] = pd.Series(dps3) print(sched3) print()