Simulate#
This example gives a “hello world” example to use AMS.
Import and Setting the Verbosity Level#
We first import the ams
library.
[1]:
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:29:32
ams:0.9.6
We can configure the verbosity level for logging (output messages) by passing a verbosity level (10-DEBUG, 20-INFO, 30-WARNING, 40-ERROR, 50-CRITICAL) to the stream_level
argument of ams.main.config_logger()
. Verbose level 10 is useful for getting debug output.
The logging level can be altered by calling config_logger
again with new stream_level
and file_level
.
[3]:
ams.config_logger(stream_level=20)
Note that the above ams.config_logger()
is a shorthand to ams.main.config_logger()
.
If this step is omitted, the default INFO
level (stream_level=20
) will be used.
Run Simulations#
Load Case#
AMS supports multiple input file formats, including AMS .xlsx
file, MATPOWER .m
file, PYPOWER .py
file, and PSS/E .raw
file.
Here we use the AMS .xlsx
file as an example. The source file locates at $HOME/ams/ams/cases/ieee39/ieee39_uced.xlsx
.
[4]:
sp = ams.load(ams.get_case('5bus/pjm5bus_uced.xlsx'),
setup=True,
no_output=True,)
Parsing input file "/Users/jinningwang/Documents/work/mambaforge/envs/amsre/lib/python3.9/site-packages/ams/cases/5bus/pjm5bus_uced.xlsx"...
Input file parsed in 0.1118 seconds.
Zero line rates detacted in rate_b, rate_c, adjusted to 999.
System set up in 0.0020 seconds.
Inspect Models and Routines#
In AMS, model
refers to the device-level models, and they are registered to an OrderedDict models
.
[5]:
sp.models
[5]:
OrderedDict([('Summary', Summary (3 devices) at 0x1271e9970),
('Bus', Bus (5 devices) at 0x2920881c0),
('PQ', PQ (3 devices) at 0x292088940),
('Slack', Slack (1 device) at 0x29209d5b0),
('PV', PV (3 devices) at 0x2920ad490),
('Shunt', Shunt (0 devices) at 0x2920adee0),
('Line', Line (7 devices) at 0x2920bb3d0),
('PVD1', PVD1 (0 devices) at 0x2920c9ac0),
('ESD1', ESD1 (0 devices) at 0x2920db160),
('REGCA1', REGCA1 (0 devices) at 0x2920db6d0),
('REGCV1', REGCV1 (0 devices) at 0x2920dbcd0),
('REGCV2', REGCV2 (0 devices) at 0x2920e8550),
('Area', Area (3 devices) at 0x2920e8af0),
('Region', Region (2 devices) at 0x2920f02b0),
('SFR', SFR (2 devices) at 0x2920f0a60),
('SR', SR (2 devices) at 0x292207100),
('NSR', NSR (2 devices) at 0x292207520),
('VSGR', VSGR (0 devices) at 0x292207940),
('GCost', GCost (4 devices) at 0x292207d90),
('SFRCost', SFRCost (4 devices) at 0x292211460),
('SRCost', SRCost (4 devices) at 0x292211a00),
('NSRCost', NSRCost (4 devices) at 0x292211e20),
('VSGCost', VSGCost (0 devices) at 0x29221e280),
('DCost', DCost (3 devices) at 0x29221e580),
('TimeSlot', TimeSlot (0 devices) at 0x29221eaf0),
('EDTSlot', EDTSlot (24 devices) at 0x2922295b0),
('UCTSlot', UCTSlot (24 devices) at 0x2922299d0)])
One can inspect the detailed model data in the form of DataFrame.
[6]:
sp.PQ.as_df()
[6]:
idx | u | name | bus | Vn | p0 | q0 | vmax | vmin | owner | ctrl | |
---|---|---|---|---|---|---|---|---|---|---|---|
uid | |||||||||||
0 | PQ_1 | 1.0 | PQ 1 | Bus_2 | 230.0 | 3.0 | 0.9861 | 1.1 | 0.9 | None | 1.0 |
1 | PQ_2 | 1.0 | PQ 2 | Bus_3 | 230.0 | 3.0 | 0.9861 | 1.1 | 0.9 | None | 1.0 |
2 | PQ_3 | 1.0 | PQ 3 | Bus_4 | 230.0 | 4.0 | 1.3147 | 1.1 | 0.9 | None | 1.0 |
In AMS, all supported routines are registered to an OrderedDict routines
.
[7]:
sp.routines
[7]:
OrderedDict([('DCPF', DCPF at 0x2920880d0),
('PFlow', PFlow at 0x292239640),
('CPF', CPF at 0x292239d00),
('ACOPF', ACOPF at 0x29224c3a0),
('DCOPF', DCOPF at 0x29224cc70),
('ED', ED at 0x29226cc40),
('EDDG', EDDG at 0x2922a4100),
('EDES', EDES at 0x2922b8d30),
('RTED', RTED at 0x2922ef490),
('RTEDDG', RTEDDG at 0x2922ef550),
('RTEDES', RTEDES at 0x292327040),
('RTEDVIS', RTEDVIS at 0x29233bfa0),
('UC', UC at 0x29235c940),
('UCDG', UCDG at 0x2960517f0),
('UCES', UCES at 0x296075940),
('DOPF', DOPF at 0x2960ae580),
('DOPFVIS', DOPFVIS at 0x2960c0a60)])
Solve a Routine#
Before solving a routine, we need to initialize it first. Here Real-time Economic Dispatch (RTED) is used as an example.
[8]:
sp.RTED.init()
<RTED> initialized in 0.0133 seconds.
[8]:
True
Then, one can solve it by calling run()
. Here, argument solver
can be passed to specify the solver to use, such as solver='ECOS'
.
Installed solvers can be listed by ams.shared.INSTALLED_SOLVERS
, and more detailes of solver can be found at CVXPY-Choosing a solver.
[9]:
ams.shared.INSTALLED_SOLVERS
[9]:
['CLARABEL', 'ECOS', 'ECOS_BB', 'GUROBI', 'OSQP', 'SCIP', 'SCIPY', 'SCS']
[10]:
sp.RTED.run(solver='ECOS')
<RTED> solved as optimal in 0.0165 seconds, converged in 12 iterations with ECOS.
[10]:
True
The solved results are stored in each variable itself. For example, the solved power generation of ten generators are stored in pg.v
.
[11]:
sp.RTED.pg.v
[11]:
array([2. , 2.1, 5.2, 0.7])
Here, get_idx()
can be used to get the index of a variable.
[12]:
sp.RTED.pg.get_idx()
[12]:
['Slack_4', 'PV_1', 'PV_3', 'PV_5']
Part of the solved results can be accessed with given indices.
[13]:
sp.RTED.get(src='pg', attr='v', idx=['PV_1', 'PV_3'])
[13]:
array([2.1, 5.2])
All Vars are listed in an OrderedDict vars
.
[14]:
sp.RTED.vars
[14]:
OrderedDict([('pg', Var: StaticGen.pg),
('aBus', Var: Bus.aBus),
('pi', Var: Bus.pi),
('plf', Var: Line.plf),
('pru', Var: StaticGen.pru),
('prd', Var: StaticGen.prd)])
The Objective value can be accessed with obj.v
.
[15]:
sp.RTED.obj.v
[15]:
0.19537500005620873
Similarly, all Constrs are listed in an OrderedDict constrs
, and the expression values can also be accessed.
[16]:
sp.RTED.constrs
[16]:
OrderedDict([('pglb', Constraint: pglb [ON]),
('pgub', Constraint: pgub [ON]),
('sba', Constraint: sbus [ON]),
('pb', Constraint: pb [ON]),
('plflb', Constraint: plflb [ON]),
('plfub', Constraint: plfub [ON]),
('alflb', Constraint: alflb [ON]),
('alfub', Constraint: alfub [ON]),
('rbu', Constraint: rbu [ON]),
('rbd', Constraint: rbd [ON]),
('rru', Constraint: rru [ON]),
('rrd', Constraint: rrd [ON]),
('rgu', Constraint: rgu [ON]),
('rgd', Constraint: rgd [ON])])
One can also inspect the Constraint
values.
[17]:
sp.RTED.rgu.v
[17]:
array([-997. , -996.9, -993.8, -998.3])