Simulate#

This example gives a "hello world" example to use AMS.

Import and Setting the Verbosity Level#

We first import the ams library.

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: 2024-01-24 09:37:17
ams:0.8.1.post5+ge752692

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.

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 support 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.

sp = ams.load(ams.get_case('5bus/pjm5bus_uced.xlsx'),
              setup=True,
              no_output=True,)
Parsing input file "/Users/jinningwang/Documents/work/ams/ams/cases/5bus/pjm5bus_uced.xlsx"...
Input file parsed in 0.1218 seconds.
Zero line rates detacted in rate_a, rate_b, rate_c, adjusted to 999.
If expect a line outage, please set 'u' to 0.
System set up in 0.0021 seconds.

Inspect Models and Routines#

In AMS, model refers to the device model, and all models are registered to an OrderedDict models.

sp.models
OrderedDict([('Summary', Summary (3 devices) at 0x105584d30),
             ('Bus', Bus (5 devices) at 0x1056110d0),
             ('PQ', PQ (3 devices) at 0x12f9b8df0),
             ('PV', PV (3 devices) at 0x12f9caa60),
             ('Slack', Slack (1 device) at 0x12f9e0910),
             ('Shunt', Shunt (0 devices) at 0x12f9eb3d0),
             ('Line', Line (7 devices) at 0x12f9eb880),
             ('PVD1', PVD1 (0 devices) at 0x12f9f4f70),
             ('ESD1', ESD1 (0 devices) at 0x12fa065b0),
             ('REGCA1', REGCA1 (0 devices) at 0x12fa06b20),
             ('REGCV1', REGCV1 (0 devices) at 0x12fa11160),
             ('REGCV2', REGCV2 (0 devices) at 0x12fa11940),
             ('Area', Area (3 devices) at 0x12fa11e80),
             ('Region', Region (2 devices) at 0x12fa1e640),
             ('SFR', SFR (2 devices) at 0x12fa1edf0),
             ('SR', SR (2 devices) at 0x12fa2e490),
             ('NSR', NSR (2 devices) at 0x12fa2e8b0),
             ('VSGR', VSGR (0 devices) at 0x12fa2ecd0),
             ('GCost', GCost (4 devices) at 0x12fa3a160),
             ('SFRCost', SFRCost (4 devices) at 0x12fa3a7f0),
             ('SRCost', SRCost (4 devices) at 0x12fa3ad90),
             ('NSRCost', NSRCost (4 devices) at 0x12fa471f0),
             ('VSGCost', VSGCost (0 devices) at 0x12fa47610),
             ('DCost', DCost (3 devices) at 0x12fa47910),
             ('TimeSlot', TimeSlot (0 devices) at 0x12fa47e80),
             ('EDTSlot', EDTSlot (24 devices) at 0x12fa50940),
             ('UCTSlot', UCTSlot (24 devices) at 0x12fa50d60)])

One can inspect the detailed model data by converting it to a pandas DataFrame.

sp.PQ.as_df()
idx u name bus Vn p0 q0 vmax vmin owner ctrl
uid
0 PQ_1 1.0 PQ 1 1 230.0 3.0 0.9861 1.1 0.9 None 1.0
1 PQ_2 1.0 PQ 2 2 230.0 3.0 0.9861 1.1 0.9 None 1.0
2 PQ_3 1.0 PQ 3 3 230.0 4.0 1.3147 1.1 0.9 None 1.0

In AMS, all supported routines are registered to an OrderedDict routines.

sp.routines
OrderedDict([('DCPF', DCPF at 0x12f9b8490),
             ('PFlow', PFlow at 0x12fa5fa00),
             ('CPF', CPF at 0x12fa73070),
             ('ACOPF', ACOPF at 0x12fa736a0),
             ('DCOPF', DCOPF at 0x12fa73fa0),
             ('ED', ED at 0x12fca9100),
             ('EDDG', EDDG at 0x12fcb40a0),
             ('EDES', EDES at 0x12fcc7ac0),
             ('RTED', RTED at 0x12fe09fd0),
             ('RTEDDG', RTEDDG at 0x12fe1c0d0),
             ('RTEDES', RTEDES at 0x12fe42760),
             ('RTEDVIS', RTEDVIS at 0x12fe684f0),
             ('UC', UC at 0x12fe7ac40),
             ('UCDG', UCDG at 0x160845430),
             ('UCES', UCES at 0x160866370),
             ('DOPF', DOPF at 0x16088dd60),
             ('DOPFVIS', DOPFVIS at 0x1608b0070)])

Solve an Routine#

Before solving an routine, we need to initialize it first. Here Real-time Economic Dispatch (RTED) is used as an example.

sp.RTED.init()
Routine <RTED> initialized in 0.0130 seconds.
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.

ams.shared.INSTALLED_SOLVERS
['CLARABEL',
 'CVXOPT',
 'ECOS',
 'ECOS_BB',
 'GLPK',
 'GLPK_MI',
 'GUROBI',
 'MOSEK',
 'OSQP',
 'PIQP',
 'PROXQP',
 'SCIPY',
 'SCS']
sp.RTED.run(solver='ECOS')
RTED solved as optimal in 0.0173 seconds, converged after 9 iterations using solver ECOS.
True

The solved results are stored in each variable itself. For example, the solved power generation of ten generators are stored in pg.v.

sp.RTED.pg.v
array([2.1, 5.2, 0.7, 2. ])

Here, get_idx() can be used to get the index of a variable.

sp.RTED.pg.get_idx()
['PV_1', 'PV_3', 'PV_5', 'Slack_4']

Part of the solved results can be accessed with given indices.

sp.RTED.get(src='pg', attr='v', idx=['PV_1', 'PV_3'])
array([2.1, 5.2])

All Vars are listed in an OrderedDict vars.

sp.RTED.vars
OrderedDict([('pg', Var: StaticGen.pg),
             ('aBus', Var: Bus.aBus),
             ('plf', Var: Line.plf),
             ('pru', Var: StaticGen.pru),
             ('prd', Var: StaticGen.prd)])

The Objective value can be accessed with obj.v.

sp.RTED.obj.v
0.19537500005072062

Similarly, all Constrs are listed in an OrderedDict constrs, and the expression values can also be accessed.

sp.RTED.constrs
OrderedDict([('pglb', Constraint: pglb [ON]),
             ('pgub', Constraint: pgub [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 Constr values.

sp.RTED.rgu.v
array([-996.9, -993.8, -998.3, -997. ])