Dispatch with Energy Storage#

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.

[1]:
import pandas as pd

import ams

import datetime
[2]:
print("Last run time:", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

print(f'ams:{ams.__version__}')
Last run time: 2024-04-21 17:32:43
ams:0.9.6
[3]:
ams.config_logger(stream_level=20)

A small-size PJM 5-bus case with ESD1 is used in this example.

[4]:
sp = ams.load(ams.get_case('5bus/pjm5bus_uced_esd1.xlsx'),
              setup=True,)
Parsing input file "/Users/jinningwang/Documents/work/mambaforge/envs/amsre/lib/python3.9/site-packages/ams/cases/5bus/pjm5bus_uced_esd1.xlsx"...
Input file parsed in 0.1406 seconds.
Zero line rates detacted in rate_b, rate_c, adjusted to 999.
System set up in 0.0019 seconds.

The model information can be inspected as follow.

[5]:
sp.ESD1.as_df()
[5]:
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.

[6]:
sp.RTEDES.run(solver='SCIP')
<RTEDES> initialized in 0.0198 seconds.
<RTEDES> solved as optimal in 0.0547 seconds, converged in -1 iteration with SCIP.
[6]:
True

Note that, in RTED, the time interval is 5/60 [H] by default, and the dispatch model has been adjusted accordingly.

[7]:
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    [5.76]     ESD1 discharging power
4      SOC  [0.1952]       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.

[8]:
sp.EDES.config.t
[8]:
1
[9]:
sp.EDES.run(solver='SCIP')
<EDES> initialized in 0.0321 seconds.
<EDES> solved as optimal in 0.0529 seconds, converged in -1 iteration with SCIP.
[9]:
True
[10]:
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
[11]:
sp.UCES.run(solver='SCIP')
All generators are online at initial, make initial guess for commitment.
Turn off StaticGen ['PV_1'] as initial commitment guess.
<UCES> initialized in 0.0369 seconds.
<UCES> solved as optimal in 0.1760 seconds, converged in -1 iteration with SCIP.
[11]:
True
[12]:
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  [[1.0, 1.0, 1.0, 1.0]]     ESD1 charging decision
1      ude  [[0.0, 0.0, 0.0, 0.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