Skip to content

API Reference

The pyramses.cfg class defines a simulation scenario: data files, disturbance file, output files, observables, and runtime options.


Create an empty configuration or load one from a previously saved command file:

import pyramses
case = pyramses.cfg() # empty configuration
case = pyramses.cfg("cmd.txt") # load from command file

Load multiple cases in a loop:

import pyramses
list_of_cases = []
for i in range(12):
list_of_cases.append(pyramses.cfg('cmd' + str(i) + '.txt'))

Save the current configuration to a command file. Useful for reproducing a run later. When called without an argument, it returns the command-file content as a string instead of writing a file.

case.writeCmdFile('cmd.txt')

Save multiple cases in a loop:

for i in range(12):
list_of_cases[i].writeCmdFile('cmd' + str(i) + '.txt')

Data files describe the network topology, dynamic models, and solver settings. At least one must be provided.

Add a data file to the case.

case.addData('dyn_A.dat')
case.addData('settings1.dat')

Remove a specific data file from the case.

case.delData('dyn_A.dat')

Return the list of currently registered data files.

files = case.getData()

Remove all data files from the case.

case.clearData()

Specifies where the simulator writes initialization procedure output.

case.addInit('init.trace')

Return the currently registered initialization file path.

path = case.getInit()

Describes the disturbances to be simulated (generator trips, faults, parameter changes, etc.).

case.addDst('events.dst')

Return the currently registered disturbance file path.

path = case.getDst()

Remove the disturbance file from the case.

case.clearDst()

Specifies the file where time-series simulation results (trajectories) are saved for post-processing. This file is used by pyramses.extractor to access results after the simulation completes.

case.addTrj('output.trj')

Return the currently registered trajectory file path.

path = case.getTrj()

Defines which components and quantities are recorded in the trajectory file.

case.addObs('obs.dat')

Return the currently registered observables file path.

path = case.getObs()

Set the main output trace file for simulation progress logging.

case.addOut('output.trace')

Return the currently registered output trace file path.

path = case.getOut()

Set the continuous trace file. Records Newton solver convergence information at each step. Useful for debugging but can slow down the simulation.

case.addCont('cont.trace')

Return the currently registered continuous trace file path.

path = case.getCont()

Set the discrete trace file. Records discrete events: switching actions from disturbance files, discrete controllers, or discrete variables in injector/torque/exciter/two-port models.

case.addDisc('disc.trace')

Return the currently registered discrete trace file path.

path = case.getDisc()

Remove the discrete trace file from the case.

case.clearDisc()

Runtime observables are displayed live during simulation using Gnuplot.

Add a runtime observable. The following observable types are supported:

BV BUSNAME, Voltage magnitude of a bus:

case.addRunObs('BV 1041')

MS MACHINE_NAME, Rotor speed of a synchronous machine:

case.addRunObs('MS g1')

BPE / BQE / BPO / BQO BRANCH_NAME, Active (P) or reactive (Q) power at the origin (O) or extremity (E) of a branch:

case.addRunObs('BPO 1041-01') # active power at origin of branch 1041-01
case.addRunObs('BQO 1041-01') # reactive power at origin
case.addRunObs('BPE 1041-01') # active power at extremity
case.addRunObs('BQE 1041-01') # reactive power at extremity

ON INJECTOR_NAME OBSERVABLE_NAME, Named observable from an injector model:

case.addRunObs('ON WT1a Pw') # observable Pw from injector WT1a

TO TWOP_NAME OBSERVABLE_NAME, Named observable from a two-port model:

case.addRunObs('TO hvdc1 P1') # observable P1 from two-port hvdc1

RT RT, Real-time versus simulated-time plot (useful to gauge simulation speed):

case.addRunObs('RT RT')

Remove all runtime observables.

case.clearRunObs()

The pyramses.sim class runs simulations. It wraps the RAMSES dynamic library and supports start/pause/continue, runtime queries, and disturbance injection.


import pyramses
ram = pyramses.sim() # use bundled RAMSES libraries
ram = pyramses.sim(custLibDir='/path/to/') # use custom library directory
ParameterTypeDescription
custLibDirstr or NoneCustom path to the RAMSES library directory. Default: use bundled libraries.

A properly configured pyramses.cfg test case is required before running a simulation.

ram.execSim(case)

execSim(case, t): start and pause at time t

Section titled “execSim(case, t): start and pause at time t”

Start the simulation and pause at a specific time (in seconds):

ram.execSim(case, 10.0) # start and pause at t = 10 s

Resume a paused simulation until a specified time:

ram.contSim(20.0) # resume until t = 20 s
ram.contSim(ram.getSimTime() + 60.0) # advance by 60 s from current time
ram.contSim(ram.getInfTime()) # run to the end of the time horizon

Terminate the simulation before reaching the time horizon:

ram.endSim()

Schedule a pause at a given simulated time; it takes effect on the next execSim() or contSim() call:

ram.pauseSim(10.0)
ram.execSim(case) # will pause at t = 10 s

Return 0 while the simulation is still running, 1 once it has ended:

if ram.getEndSim():
print('simulation finished')

Return the last error message issued by RAMSES as a string. Useful after catching a RAMSESError:

msg = ram.getLastErr()

When the simulation is paused, the following methods query the current system state.

Return the current simulation time in seconds.

t = ram.getSimTime()

Return the value used as “infinity” (i.e., the end of the simulation time horizon). Pass this to contSim() to run to completion.

t_inf = ram.getInfTime()
ram.contSim(ram.getInfTime())

Return a list of all component names of the given type.

buses = ram.getAllCompNames('BUS') # list of all bus names
gens = ram.getAllCompNames('SYNC') # list of all generator names
injs = ram.getAllCompNames('INJ') # list of all injector names
dctls = ram.getAllCompNames('DCTL') # list of all discrete controller names
branches = ram.getAllCompNames('BRANCH') # list of all branch names
twops = ram.getAllCompNames('TWOP') # list of all two-port names
shunts = ram.getAllCompNames('SHUNT') # list of all shunt names
loads = ram.getAllCompNames('LOAD') # list of all load names

Supported component types: BUS, SYNC, INJ, DCTL, BRANCH, TWOP, SHUNT, LOAD.

Return the name of the num-th component (1-based) of the given type. Accepts the same component types as getAllCompNames().

first_bus = ram.getCompName('BUS', 1) # e.g. 'B1'

Return voltage magnitudes (in pu) for a list of bus names.

ram.execSim(case, 10.0)
bus_names = ['g1', 'g2', '4032']
voltages = ram.getBusVolt(bus_names)

Return voltage phase angles (in degrees) for a list of bus names.

phases = ram.getBusPha(bus_names)

Return power flows for a list of branch names. Each entry is [P_from, Q_from, P_to, Q_to] in MW and Mvar.

powers = ram.getBranchPow(['1041-01'])
# powers[0] == [P_from, Q_from, P_to, Q_to]

Return branch currents for a list of branch names. Each entry contains the x–y current components at the origin and extremity: [ix_orig, iy_orig, ix_extr, iy_extr].

currents = ram.getBranchCur(['1011-1013', '1012-1014'])

Get the current value of named observables for a list of components. Lists must be the same length.

comp_type = ['INJ', 'EXC', 'TOR']
comp_name = ['L_11', 'g2', 'g3']
obs_name = ['P', 'vf', 'Pm']
obs = ram.getObs(comp_type, comp_name, obs_name)

Supported model types: EXC (exciter), TOR (governor), INJ (injector), TWOP (two-port), DCTL (discrete controller), SYN (synchronous generator).

Get parameter values for a list of components. Lists must be the same length.

comp_type = ['EXC', 'EXC']
comp_name = ['g1', 'g2']
prm_name = ['V0', 'KPSS']
prms = ram.getPrm(comp_type, comp_name, prm_name)

List the parameter names of one or more model instances. Accepts single strings or equal-length lists; component types are EXC, TOR, INJ, DCTL, TWOP.

names = ram.getPrmNames('EXC', 'g1') # list of parameter names of g1's exciter

Observables can also be selected programmatically after the simulation starts, instead of via an observables file. Call the three methods in order, after execSim(case, 0.0):

Initialize the runtime observable recording system and set the output trajectory file.

Register one observable selector in RAMSES format (e.g. 'BUS *', 'SYNC g1'). Call once per selector.

Finalize the selection, allocate the recording buffers, and write the trajectory file header.

ram.execSim(case, 0.0)
ram.initObserv('obs.trj')
ram.addObserv('BUS *') # record all bus voltages
ram.addObserv('SYNC g1') # record machine g1
ram.finalObserv()
ram.contSim(ram.getInfTime())

Subsystems select a group of buses for aggregate queries.

Define subsystem ssID as the intersection of three filters: voltage levels, zones, and bus names. Each filter is a list of strings; an empty list deactivates that filter.

ram.defineSS(1, ['735'], [], []) # subsystem 1 = all 735 kV buses

Return the list of buses belonging to a subsystem.

buses = ram.getSS(1)

getTrfoSS(ssID, location, in_service, rettype)

Section titled “getTrfoSS(ssID, location, in_service, rettype)”

Return transformer information for a subsystem. location: 1 = both ends inside the subsystem, 2 = tie transformers, 3 = both. in_service: 1 = in-service only, 2 = all. rettype selects the returned quantity: NAME, From, To, Status, Tap, Currentf, Currentt, Pf, Qf, Pt, Qt.

status = ram.getTrfoSS(1, 3, 2, 'Status')

Compiled user-defined model libraries (built with URAMSES) can be loaded at runtime.

Load a shared library of user-defined models (.dll on Windows, .so on Linux). The models stay available for the lifetime of the sim instance.

ram.load_MDL('MDLs.dll')

Unload a previously loaded user-model library.

ram.unload_MDL('MDLs.dll')

Return the number of user-model libraries currently loaded.

n = ram.get_MDL_no()

Disturbances can be added dynamically while the simulation is paused, enabling interactive scenario analysis.

Schedule a disturbance to occur at a given simulation time.

The disturbance description string follows the same syntax as the disturbance file format. See Disturbances for the complete reference.

ram.execSim(case, 80.0)
# Trip generator g7 at t = 100 s
ram.addDisturb(100.0, 'BREAKER SYNC_MACH g7 0')
# Apply a 3-phase fault at bus 4032 and clear it 100 ms later
ram.addDisturb(100.0, 'FAULT BUS 4032 0. 0.')
ram.addDisturb(100.1, 'CLEAR BUS 4032')
# Step change in an LTC setpoint
ram.addDisturb(100.0, 'CHGPRM DCTL 1-1041 Vsetpt -0.05 0')
ram.contSim(ram.getInfTime())

Export the system Jacobian in descriptor form at the current pause point. Returns a tuple (A, E) of scipy.sparse.csc_matrix objects, where A holds the numerical Jacobian values and E is the structural incidence matrix of the descriptor system. Two intermediate text files are also written to the working directory:

FileContents
py_val.datJacobian values (parsed into A)
py_eqs.datStructural incidence matrix (parsed into E)
ram.execSim(case, 10.0)
A, E = ram.getJac()

The matrices can be used for small-signal stability analysis, e.g. with the RAMSES Eigenanalysis tool or scipy.sparse.linalg.


The pyramses.extractor class extracts and visualises time-series results from a trajectory file produced during simulation.


Pass the trajectory file path to the extractor:

import pyramses
case = pyramses.cfg('cmd.txt')
# ... run simulation ...
ext = pyramses.extractor(case.getTrj())

Or provide the file path directly:

ext = pyramses.extractor('output.trj')

All extraction methods return objects whose attributes are curve objects (pyramses.cur named tuples). Every curve object has:

AttributeTypeDescription
timenumpy.ndarrayTime values in seconds
valuenumpy.ndarrayObservable values
msgstrDescription string (used as plot legend label)

Display the curve using Matplotlib:

bus = ext.getBus('4044')
bus.mag.plot()

Retrieve voltage time series for a bus. Returns an object with:

AttributeDescription
.magVoltage magnitude (pu)
.phaVoltage phase angle (deg)
bus = ext.getBus('4044')
bus.mag.plot() # voltage magnitude (pu)
bus.pha.plot() # voltage phase angle (deg)

Retrieve the full set of synchronous machine observables. Returns an object with:

AttributeDescription
.PActive power (MW)
.QReactive power (Mvar)
.SRotor speed (pu)
.ARotor angle w.r.t. COI (deg)
.FVField voltage (pu)
.FCField current (pu)
.TMechanical torque (pu)
.ETElectromagnetic torque (pu)
.FWField winding flux
.DDd1 damper flux
.QDq1 damper flux
.QWq2 winding flux
.SCCOI speed
gen = ext.getSync('g1')
gen.P.plot() # active power (MW)
gen.Q.plot() # reactive power (Mvar)
gen.S.plot() # rotor speed (pu)
gen.A.plot() # rotor angle w.r.t. COI (deg)
gen.FV.plot() # field voltage (pu)
gen.FC.plot() # field current (pu)
gen.T.plot() # mechanical torque (pu)
gen.ET.plot() # electromagnetic torque (pu)

Retrieve exciter observables. Available observables depend on the exciter model.

AttributeDescription
.obsdictdict mapping observable name → description
(model-dependent)Access by observable name, e.g. .vf
exc = ext.getExc('g1')
print(exc.obsdict) # list available observables for this model
exc.vf.plot() # field voltage (model-dependent name)

Retrieve governor/torque model observables. Available observables depend on the governor model.

AttributeDescription
.obsdictdict mapping observable name → description
(model-dependent)Access by observable name, e.g. .Pm
gov = ext.getTor('g1')
print(gov.obsdict) # list available observables for this model
gov.Pm.plot() # mechanical power (pu)

Retrieve injector observables. Injectors include renewable energy sources (wind, PV, BESS), loads, and other single-bus components.

AttributeDescription
.obsdictdict mapping observable name → description
(model-dependent)Access by observable name, e.g. .Pw
inj = ext.getInj('WT1a')
print(inj.obsdict) # list available observables
inj.Pw.plot() # wind power (model-dependent name)

Retrieve two-port model observables. Two-port models include HVDC links (LCC and VSC), SVCs, and DC systems.

AttributeDescription
.obsdictdict mapping observable name → description
(model-dependent)Access by observable name, e.g. .P1, .P2
twop = ext.getTwop('hvdc1')
print(twop.obsdict) # list available observables
twop.P1.plot() # active power at terminal 1
twop.P2.plot() # active power at terminal 2

Retrieve discrete controller observables. Discrete controllers include LTC transformers, under-voltage load shedding, phase shifters, etc.

AttributeDescription
.obsdictdict mapping observable name → description
dctl = ext.getDctl('1-1041')
print(dctl.obsdict) # list available observables

Retrieve branch (line/transformer) power flow time series.

AttributeDescription
.PFActive power at FROM end (MW)
.QFReactive power at FROM end (Mvar)
.PTActive power at TO end (MW)
.QTReactive power at TO end (Mvar)
.RMTransformer ratio magnitude
.RATransformer phase angle (deg)
branch = ext.getBranch('1041-01')
branch.PF.plot() # active power at FROM end (MW)
branch.QF.plot() # reactive power at FROM end (Mvar)
branch.PT.plot() # active power at TO end (MW)
branch.QT.plot() # reactive power at TO end (Mvar)
branch.RM.plot() # transformer ratio magnitude
branch.RA.plot() # transformer phase angle (deg)

Retrieve shunt compensation time series.

AttributeDescription
.QReactive power produced (Mvar)
ext.getShunt('sh1').Q.plot()

Retrieve load time series.

AttributeDescription
.PActive power consumed (MW)
.QReactive power consumed (Mvar)
ext.getLoad('L_1').P.plot()

Display multiple curve objects on the same axes. Each curve’s msg field is used as the legend label.

import pyramses
ext = pyramses.extractor(case.getTrj())
curves = [
ext.getSync('g1').S,
ext.getSync('g2').S,
ext.getSync('g3').S,
]
pyramses.curplot(curves)

import pyramses
# --- Build test case ---
case = pyramses.cfg()
case.addData('dyn_A.dat')
case.addData('settings1.dat')
case.addInit('init.trace')
case.addDst('events.dst')
case.addTrj('output.trj')
case.addObs('obs.dat')
case.addOut('output.trace')
case.addCont('cont.trace')
case.addDisc('disc.trace')
# Runtime observables (Gnuplot required)
case.addRunObs('BV 1041')
case.addRunObs('MS g1')
case.addRunObs('RT RT')
# Save configuration
case.writeCmdFile('cmd.txt')
# --- Run simulation ---
ram = pyramses.sim()
# Start and pause at t = 80 s
ram.execSim(case, 80.0)
# Inject a disturbance dynamically
ram.addDisturb(100.0, 'FAULT BUS 4032 0. 0.')
ram.addDisturb(100.1, 'CLEAR BUS 4032')
# Export Jacobian at this operating point
A, E = ram.getJac()
# Run to end
ram.contSim(ram.getInfTime())
# --- Extract results ---
ext = pyramses.extractor(case.getTrj())
# Bus voltages
ext.getBus('4044').mag.plot()
# Generator observables
gen = ext.getSync('g1')
gen.S.plot() # rotor speed
gen.A.plot() # rotor angle
# Branch flows
ext.getBranch('1041-01').PF.plot()
# Plot multiple rotor speeds together
pyramses.curplot([
ext.getSync('g1').S,
ext.getSync('g2').S,
ext.getSync('g3').S,
])
  • Examples, Practical simulation examples and workflows
  • Test Systems, Ready-to-run benchmark systems