In this case, we will show the usage of energy storage included dispatch.
In AMS, ESD1
is an dispatch model for energy storage, which has a corresponding
dynamic model ESD1
in ANDES.
import pandas as pd
import ams
import datetime
print("Last run time:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(f'ams:{ams.__version__}')
Last run time: 2025-01-27 06:04:56 ams:1.0.1.post0.dev0+g26601dec
ams.config_logger(stream_level=20)
A small-size PJM 5-bus case with ESD1 is used in this example.
sp = ams.load(ams.get_case('5bus/pjm5bus_uced_esd1.xlsx'),
setup=True,
no_output=True)
Parsing input file "/Users/jinningwang/work/ams/ams/cases/5bus/pjm5bus_uced_esd1.xlsx"... Input file parsed in 0.0641 seconds. Zero line rates detacted in rate_b, rate_c, adjusted to 999. System set up in 0.0017 seconds.
The model information can be inspected as follow.
sp.ESD1.as_df()
idx | u | name | bus | gen | Sn | gammap | gammaq | SOCmin | SOCmax | SOCinit | En | EtaC | EtaD | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
uid | ||||||||||||||
0 | ESD1_1 | 1.0 | ESD1_1 | 1 | PV_2 | 100.0 | 1.0 | 1.0 | 0.0 | 1.0 | 0.2 | 100.0 | 1.0 | 1.0 |
RTEDES
extends RTED to include energy storage.
Note that mixed integer linear programming (MILP) requires capable solvers such as Gurobi or CPLEX. They might require extra installation and have their own license.
The example here only aims to show the usage of RTEDES. More details can be found at CVXPY - Choosing a solver.
sp.RTEDES.run()
Building system matrices Parsing OModel for <RTEDES> Evaluating OModel for <RTEDES> Finalizing OModel for <RTEDES> <RTEDES> initialized in 0.0170 seconds.
Restricted license - for non-production use only - expires 2026-11-23
<RTEDES> solved as optimal in 0.0198 seconds, converged in 5 iterations with GUROBI.
True
Note that, in RTED, the time interval is 5/60 [H] by default, and the dispatch model has been adjusted accordingly.
RTEDESres = pd.DataFrame()
items = [sp.RTEDES.uce, sp.RTEDES.ude,
sp.RTEDES.pce, sp.RTEDES.pde,
sp.RTEDES.SOC, sp.RTEDES.SOCinit]
RTEDESres['Var'] = [item.name for item in items]
RTEDESres['Value'] = [item.v.round(4) for item in items]
RTEDESres['info'] = [item.info for item in items]
print(RTEDESres)
Var Value info 0 uce [0.0] ESD1 charging decision 1 ude [1.0] ESD1 discharging decision 2 pce [0.0] ESD1 charging power 3 pde [0.0] ESD1 discharging power 4 SOC [0.2] ESD1 State of Charge 5 SOCinit [0.2] Initial SOC
Similarly, multi-period dispatch EDES
and UCES
are also available.
They have 1 [H] time interval by default.
sp.EDES.config.t
1
sp.EDES.run()
Parsing OModel for <EDES> Evaluating OModel for <EDES> Finalizing OModel for <EDES> <EDES> initialized in 0.0421 seconds. <EDES> solved as optimal in 0.0252 seconds, converged in 4 iterations with GUROBI.
True
EDESres = pd.DataFrame()
items = [sp.EDES.uce, sp.EDES.ude,
sp.EDES.pce, sp.EDES.pde,
sp.EDES.SOC, sp.EDES.SOCinit]
EDESres['Var'] = [item.name for item in items]
EDESres['Value'] = [item.v.round(4) for item in items]
EDESres['info'] = [item.info for item in items]
print(EDESres)
Var Value info 0 uce [[0.0, 0.0, 0.0, 0.0]] ESD1 charging decision 1 ude [[1.0, 1.0, 1.0, 1.0]] ESD1 discharging decision 2 pce [[0.0, 0.0, 0.0, 0.0]] ESD1 charging power 3 pde [[0.0, 0.0, 0.0, 0.0]] ESD1 discharging power 4 SOC [[0.2, 0.2, 0.2, 0.2]] ESD1 State of Charge 5 SOCinit [0.2] Initial SOC
sp.UCES.run()
All generators are online at initial, make initial guess for commitment. As initial commitment guess, turn off StaticGen: PV_1 Parsing OModel for <UCES> Evaluating OModel for <UCES> Finalizing OModel for <UCES> <UCES> initialized in 0.0249 seconds. <UCES> solved as optimal in 0.0298 seconds, converged in 4 iterations with GUROBI.
True
UCESres = pd.DataFrame()
items = [sp.UCES.uce, sp.UCES.ude,
sp.UCES.pce, sp.UCES.pde,
sp.UCES.SOC, sp.UCES.SOCinit]
UCESres['Var'] = [item.name for item in items]
UCESres['Value'] = [item.v.round(4) for item in items]
UCESres['info'] = [item.info for item in items]
print(UCESres)
Var Value info 0 uce [[0.0, 0.0, 0.0, 0.0]] ESD1 charging decision 1 ude [[1.0, 1.0, 1.0, 1.0]] ESD1 discharging decision 2 pce [[0.0, 0.0, 0.0, 0.0]] ESD1 charging power 3 pde [[0.0, 0.0, 0.0, 0.0]] ESD1 discharging power 4 SOC [[0.2, 0.2, 0.2, 0.2]] ESD1 State of Charge 5 SOCinit [0.2] Initial SOC