Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/GridOPTICS/GridPACK/llms.txt

Use this file to discover all available pages before exploring further.

GridPACK’s dynamic simulation module uses a full Y-matrix formulation to integrate the differential-algebraic equations (DAE) governing synchronous machine transient behavior. The DSFullApp class in the gridpack::dynamic_simulation namespace implements the complete simulation workflow: loading a PSS/E network, reading .dyr generator parameters, initializing state from a converged power flow, and stepping through time with branch-fault events. The module is designed to be extended—generator, exciter, governor, PSS, relay, dynamic load, and inverter-based resource (IBR) models are plugged in via a factory pattern, and users can add new device types without modifying the integration loop.

Supported device models

The full-Y dynamic simulation module supports the following model types. These are read from a PSS/E .dyr file specified in the generatorParameters field of the input deck. Generator models
ModelDescription
GENCLSClassical generator (constant voltage behind reactance)
GENSALSalient-pole synchronous generator
GENROURound-rotor synchronous generator with full flux dynamics
IBR / renewable energy models
ModelDescription
REGCA1Renewable energy generator/converter model A type 1
REGCB1Renewable energy generator/converter model B type 1
REGCC1Renewable energy generator/converter model C type 1
GDFORMGrid-forming inverter model
REECA1Renewable energy electrical control model A type 1
REPCA1Renewable energy plant control model A type 1
The EPRIA1 inverter-based resource model is also available when GridPACK is compiled with the ENABLE_EPRI_IBR_MODEL CMake flag.
Exciter models: EXDC1, ESST1A, IEEET1, SEXS, ESST4B Governor models: WSIEG1, WSHYGP, TGOV1, GAST, HYGOV, GGOV1 Power system stabilizer: PSSSIM Wind turbine models: WTARA1, WTDTA1, WTPTA1, WTTQA1 Relay models: LVSHBL, FRQTPAT, DISTR1 Dynamic load models: ACMTBLU1, IEEL, MOTORW, CIM6BL

Simulation workflow

1

Initialize power flow

The recommended entry point is solvePowerFlowBeforeDynSimu(), which runs a full power flow internally and maps the converged bus voltages onto the dynamic simulation network. The power flow network is destroyed inside its own scope, avoiding Global Arrays handle conflicts.
gridpack::dynamic_simulation::DSFullApp ds_app;
ds_app.solvePowerFlowBeforeDynSimu("input.xml");
This is equivalent to creating a PFAppModule, running solve(), calling saveData(), and then cloning the network into a DSFullNetwork—but with proper lifecycle management.
2

Read generator parameters

Load dynamic model parameters from the PSS/E .dyr file named in generatorParameters:
ds_app.readGenerators();
The optional ds_idx argument selects from a list of .dyr files when the input deck specifies multiple files.
3

Read sequence data (optional)

For applications that require sequence network data (e.g., unsymmetrical fault studies):
ds_app.readSequenceData();
4

Initialize the simulation

Set up internal state variables and the full Y-matrix. When equilibriumInit is true in the input deck, this step runs an iterative Norton-equivalent initialization that eliminates pre-fault drift by rebalancing generator states (Pmech = Telec, Efd = LadIfd) at the network-solved voltage.
ds_app.initialize();
5

Configure generator monitoring

Activate time-series output for watched generators specified in the generatorWatch block:
ds_app.setGeneratorWatch();
The watched variables are rotor speed and rotor angle for each monitored generator. Results are written to the file named in generatorWatchFileName at the interval set by generatorWatchFrequency (in time steps).
6

Load fault events

Build the list of fault events from the input deck’s Events block:
gridpack::utility::Configuration::CursorPtr cursor;
cursor = config->getCursor("Configuration.Dynamic_simulation");
std::vector<gridpack::dynamic_simulation::Event> faults;
faults = ds_app.getEvents(cursor);
Faults can also be declared in a separate file; point the cursor at any block containing an Events child to load from that source.
7

Run the time integration

Pre-initialize the integrator for the first fault and then advance through each time step:
ds_app.solvePreInitialize(faults[0]);

while (!ds_app.isDynSimuDone()) {
    ds_app.executeOneSimuStep();
}
Alternatively, solve(fault) runs the entire simulation in one call. Use run(tend) to advance to a specific time, or run() to run to the configured end time.

XML input file structure

The Dynamic_simulation block controls all simulation parameters:
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
  <Dynamic_simulation>
    <!-- Network and generator model files -->
    <networkConfiguration>IEEE_145.raw</networkConfiguration>
    <generatorParameters>IEEE_145.dyr</generatorParameters>

    <!-- Time integration parameters -->
    <simulationTime>30</simulationTime>   <!-- total simulation time in seconds -->
    <timeStep>0.005</timeStep>            <!-- integration time step in seconds -->

    <!-- Iterative equilibrium initialization (recommended: eliminates pre-fault drift) -->
    <equilibriumInit>true</equilibriumInit>

    <!-- Fault events: currently supports branch faults -->
    <Events>
      <faultEvent>
        <beginFault>2.00</beginFault>     <!-- fault application time (seconds) -->
        <endFault>2.05</endFault>         <!-- fault clearance time (seconds) -->
        <faultBranch>6 7</faultBranch>    <!-- from-bus and to-bus of faulted branch -->
        <timeStep>0.005</timeStep>        <!-- time step during fault interval -->
      </faultEvent>
    </Events>

    <!-- Generator monitoring: rotor speed and angle time series -->
    <generatorWatch>
      <generator>
        <busID>60</busID>
        <generatorID>1</generatorID>
      </generator>
      <generator>
        <busID>112</busID>
        <generatorID>1</generatorID>
      </generator>
    </generatorWatch>
    <generatorWatchFrequency>1</generatorWatchFrequency>
    <generatorWatchFileName>gen_watch.csv</generatorWatchFileName>

    <!-- Linear solver for Y-matrix factorization -->
    <LinearMatrixSolver>
      <PETScOptions>
        -ksp_atol 1.0e-18
        -ksp_rtol 1.0e-10
        -ksp_max_it 200
      </PETScOptions>
    </LinearMatrixSolver>
  </Dynamic_simulation>
</Configuration>
Multiple faultEvent blocks can appear within the Events block. It is also possible to reference an external fault list file, which is convenient for contingency-driven dynamic security assessment workflows with many events.

Fault simulation

Faults are defined on branches. Each faultEvent specifies the begin and end times of the fault, the two bus indices identifying the faulted branch, and an optional time step override for the fault interval. The solver automatically switches between normal and faulted Y-matrix formulations at beginFault and endFault. Negative PG generators (absorbing machines) are supported in GENROU, GENSAL, and classical models.

Time series data access from code

In addition to file-based output, time series data for watched generators can be retrieved programmatically:
// Enable in-memory time series storage before calling solve
ds_app.saveTimeSeries(true);

// After solve completes, retrieve time series
std::vector<std::vector<double>> series = ds_app.getGeneratorTimeSeries();

// Map series indices to generator IDs
std::vector<int> bus_ids;
std::vector<std::string> gen_ids;
ds_app.getListWatchedGenerators(bus_ids, gen_ids);
std::vector<int> ts_map = ds_app.getTimeSeriesMap();
Each element of series alternates between rotor speed and rotor angle for each watched generator on the local MPI rank.

Data collection update

At any point during or after a simulation, the method updateData() copies current internal variable values into each network component’s DataCollection object, making them accessible for post-processing or chaining to other modules:
ds_app.updateData();
Updated variables include BUS_VMAG_CURRENT, GENERATOR_PG_CURRENT, GENERATOR_QG_CURRENT, BRANCH_FROM_P_CURRENT, BRANCH_FROM_Q_CURRENT, and others.

Running the standalone binary

The dsf.x binary reads configuration from input.xml by default. Pass a filename as the first argument to override:
# Single process
./dsf.x input.xml

# Multi-process with MPI (8 ranks)
mpiexec -n 8 ./dsf.x input.xml
For large transmission systems, using one MPI rank per network partition reduces the Y-matrix assembly and factorization time per step. Network partitioning is handled automatically by readNetwork().
Set equilibriumInit to true for all production simulations. Without iterative equilibrium initialization, small machine-state imbalances in the initial condition can cause slow pre-fault drift that contaminates the post-fault response.

Power flow

Use PFAppModule to generate the converged base case that initializes the dynamic simulation.

Contingency analysis

Screen N-1 contingencies using the power flow module before launching dynamic studies.

Build docs developers (and LLMs) love