Examples
All examples assume the working directory contains the relevant data and disturbance files.
Running a Basic Simulation
Section titled “Running a Basic Simulation”Define the test case, run the simulation, and extract results:
import pyramses
case = pyramses.cfg()case.addData('dyn_A.dat') # dynamic modelscase.addData('volt_rat_A.dat') # power-flow initialisationcase.addData('settings1.dat') # solver settingscase.addDst('short_trip_branch.dst')case.addInit('init.trace')case.addTrj('output.trj') # save trajectories for post-processingcase.addObs('obs.dat') # define which observables to recordcase.addCont('cont.trace')case.addDisc('disc.trace')case.addRunObs('BV 4044') # live voltage display (requires Gnuplot)case.addRunObs('BV 1041')case.writeCmdFile('cmd.txt') # save for future reuse
ram = pyramses.sim()ram.execSim(case) # run to completion
ext = pyramses.extractor(case.getTrj())ext.getBus('1041').mag.plot() # voltage magnitude at bus 1041Pause and Continue
Section titled “Pause and Continue”Pause the simulation at intermediate time points to inspect state or add disturbances:
ram = pyramses.sim()ram.execSim(case, 0.0) # initialise, paused at t=0ram.contSim(10.0) # simulate to t=10 sram.contSim(ram.getSimTime() + 60.0) # advance 60 s from current timeram.contSim(ram.getInfTime()) # run to end of time horizonQuerying System State
Section titled “Querying System State”Query bus voltages, branch flows, observables, and parameters while paused:
ram.execSim(case, 10.0)
# Bus voltagesbusNames = ['g1', 'g2', 'g3']voltages = ram.getBusVolt(busNames) # list of voltage magnitudes (pu)phases = ram.getBusPha(busNames) # list of phase angles (rad)
# Branch power flowsbranch_pq = ram.getBranchPow(['1041-01']) # [[P_from, Q_from, P_to, Q_to]]
# Component observables: P of injector L_11, vf of exciter g2, Pm of governor g3comp_type = ['INJ', 'EXC', 'TOR']comp_name = ['L_11', 'g2', 'g3']obs_name = ['P', 'vf', 'Pm']obs = ram.getObs(comp_type, comp_name, obs_name)
# Component parameters: V0 of exciter g1, KPSS of exciter g2comp_type = ['EXC', 'EXC']comp_name = ['g1', 'g2']prm_name = ['V0', 'KPSS']prms = ram.getPrm(comp_type, comp_name, prm_name)
# All component names of a typeall_buses = ram.getAllCompNames('BUS')all_gens = ram.getAllCompNames('SYNC')Adding Disturbances at Runtime
Section titled “Adding Disturbances at Runtime”Inject disturbances and parameter changes while the simulation is running:
ram.execSim(case, 80.0)
# LTC voltage setpoint changes at t=100 s (ramp)for i in range(1, 6): ram.addDisturb(100.0, f'CHGPRM DCTL {i}-104{i} Vsetpt -0.05 0')
# Fault and clearanceram.addDisturb(100.0, 'FAULT BUS 4032 0. 0.') # 3-phase short circuitram.addDisturb(100.1, 'CLEAR BUS 4032') # clear faultram.addDisturb(100.1, 'BREAKER BRANCH 4032-4044 0 0') # trip line
# Generator tripram.addDisturb(100.0, 'BREAKER SYNC_MACH g7 0')
ram.contSim(ram.getInfTime())For full disturbance syntax, see the Disturbances reference.
Plotting Results
Section titled “Plotting Results”Extract and plot time-series results after the simulation:
import pyramsesext = pyramses.extractor('output.trj')
# Single curveext.getSync('g5').S.plot() # rotor speed of generator g5ext.getBus('4044').mag.plot() # voltage magnitude at bus 4044
# Multiple curves on the same plotcurves = [ext.getSync(f'g{i}').S for i in range(1, 5)]pyramses.curplot(curves)
# Exciter and governor outputsext.getExc('g1').vf.plot() # field voltageext.getTor('g1').Pm.plot() # mechanical power
# Branch power flowsext.getBranch('1041-01').PF.plot()
# Injector (wind/PV/BESS)ext.getInj('WT1a').Pw.plot()
# Two-port (HVDC)ext.getTwop('hvdc1').P1.plot()Parameter Sweep
Section titled “Parameter Sweep”Run multiple simulations with varying parameters and collect results:
import pyramsesimport numpy as np
results = {}for disturbance_time in [5.0, 10.0, 20.0]: case = pyramses.cfg('cmd.txt') trj_file = f'output_{disturbance_time:.0f}.trj' case.addTrj(trj_file) case.addObs('obs.dat')
ram = pyramses.sim() ram.execSim(case, 0.0) ram.addDisturb(disturbance_time, 'BREAKER SYNC_MACH g7 0') ram.contSim(ram.getInfTime()) ram.endSim()
ext = pyramses.extractor(trj_file) min_freq = np.min(ext.getSync('g5').S.value) results[disturbance_time] = min_freq print(f't_dist={disturbance_time:5.1f}s min_speed={min_freq:.5f} pu')Eigenanalysis Workflow
Section titled “Eigenanalysis Workflow”Export the system Jacobian for small-signal stability analysis:
import pyramses
case = pyramses.cfg('cmd.txt')ram = pyramses.sim()
# Pause at steady-state operating pointram.execSim(case, 0.0)
# Export Jacobian matrices (writes jac_val.dat, jac_eqs.dat, jac_var.dat, jac_struc.dat)ram.getJac()ram.endSim()The generated files can then be analysed in MATLAB using the RAMSES Eigenanalysis tool:
% In MATLAB:ssa('jac_val.dat', 'jac_eqs.dat', 'jac_var.dat', 'jac_struc.dat')Test System Examples
Section titled “Test System Examples”The following examples use the ready-to-run test systems. For system descriptions, data files, and disturbance scenarios, see the Test Systems section.
Nordic Test System: Generator Trip
Section titled “Nordic Test System: Generator Trip”Trips generator g7 at s on the heavily-stressed Operating Point B and observes the voltage collapse dynamics over 150 seconds. See the Nordic Test System page for full system details and file descriptions.
import pyramsesimport os
case = pyramses.cfg()case.addData('dyn_B.dat')case.addData('volt_rat_B.dat')case.addData('settings1.dat')case.addDst('nothing.dst')case.addObs('obs.dat')case.addTrj('output.trj')
for f in os.listdir('.'): if f.endswith('.trj') or f.endswith('.trace'): os.remove(f)
ram = pyramses.sim()ram.execSim(case, 0.0)ram.addDisturb(10.0, 'BREAKER SYNC_MACH g7 0')ram.contSim(150.0)ram.endSim()
ext = pyramses.extractor(case.getTrj())ext.getSync('g7').S.plot() # rotor speedext.getBus('1041').mag.plot() # voltage at central bus5-Bus System: Exciter Parameter Change
Section titled “5-Bus System: Exciter Parameter Change”Applies a step change to the exciter voltage setpoint at s and plots the generator response. See the 5-Bus Test System page for details.
import pyramsesimport os
case = pyramses.cfg()case.addData('dyn.dat')case.addData('lf1solv.dat')case.addData('solveroptions.dat')case.addDst('nothing.dst')case.addObs('obs.dat')case.addTrj('output.trj')
for f in os.listdir('.'): if f.endswith('.trj') or f.endswith('.trace'): os.remove(f)
ram = pyramses.sim()ram.execSim(case, 0.0)ram.addDisturb(1.0, 'CHGPRM EXC G Vo 0.05 2')ram.contSim(60.0)ram.endSim()
ext = pyramses.extractor(case.getTrj())ext.getSync('G').P.plot()ext.getSync('G').Q.plot()