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 contingency analysis application distributes a set of power system contingencies across multiple MPI communicator groups, evaluating each one by running an independent power flow solve. The CADriver class in the gridpack::contingency_analysis namespace orchestrates this parallel sweep: it reads or auto-generates the contingency list, divides contingencies among process groups using a task manager, evaluates voltage and thermal violations, and writes per-contingency result files alongside aggregate statistical summaries. Because the underlying solver is PFAppModule, any feature of the power flow module—Q-limit enforcement, switched shunts, LTC control—can be activated in the contingency analysis by setting the corresponding XML flags.

Contingency definition

Contingencies are represented by the gridpack::powerflow::Contingency struct, which supports both branch (line) outages and generator outages:
struct Contingency {
    int p_type;                         // Branch or Generator (enum ContingencyType)
    std::string p_name;                 // Unique contingency identifier

    // Branch outage fields
    std::vector<int> p_from;            // From-bus original indices
    std::vector<int> p_to;              // To-bus original indices
    std::vector<std::string> p_ckt;    // Two-character circuit identifier

    // Generator outage fields
    std::vector<int> p_busid;           // Bus original indices
    std::vector<std::string> p_genid;  // Two-character generator identifier
};
Each vector holds one element for a single-element N-1 contingency, or multiple elements for multi-element N-k events.

Specifying contingencies

Three options can be used separately or in combination.

Option 1: Auto-generate N-1 contingencies

Set FullBranchN1 and/or FullGeneratorN1 to true to automatically create one contingency per in-service branch or generator in the network. Branch contingencies are named BR_<from>_<to>_<ckt> and generator contingencies are named GN_<bus>_<id>.
<Contingency_analysis>
  <FullBranchN1>true</FullBranchN1>
  <FullGeneratorN1>true</FullGeneratorN1>
</Contingency_analysis>

Option 2: Explicit contingency list file

Provide a contingency list in a separate XML file:
<Contingency_analysis>
  <contingencyList>contingencies.xml</contingencyList>
</Contingency_analysis>
The contingency list file format is:
<Contingencies>
  <!-- N-1 line outage -->
  <Contingency>
    <contingencyType>Line</contingencyType>
    <contingencyName>LINE_1_2_1</contingencyName>
    <contingencyLineBuses>1 2</contingencyLineBuses>
    <contingencyLineNames>1</contingencyLineNames>
  </Contingency>

  <!-- N-1 generator outage -->
  <Contingency>
    <contingencyType>Generator</contingencyType>
    <contingencyName>GEN_69_1</contingencyName>
    <contingencyBuses>69</contingencyBuses>
    <contingencyGenerators>1</contingencyGenerators>
  </Contingency>

  <!-- N-2 double-circuit line outage (multiple elements in one contingency) -->
  <Contingency>
    <contingencyType>Line</contingencyType>
    <contingencyName>N2_LINE_1_2</contingencyName>
    <contingencyLineBuses>1 2 1 2</contingencyLineBuses>
    <contingencyLineNames>1 2</contingencyLineNames>
  </Contingency>
</Contingencies>

Option 3: Combined auto-generated and explicit

When both FullBranchN1/FullGeneratorN1 and a contingencyList are specified, the driver loads both sources and calls isDuplicateContingency() to skip any entries in the file that duplicate an auto-generated contingency.
<Contingency_analysis>
  <FullBranchN1>true</FullBranchN1>
  <FullGeneratorN1>true</FullGeneratorN1>
  <contingencyList>custom_nk_contingencies.xml</contingencyList>
</Contingency_analysis>

Full input file example

<?xml version="1.0" encoding="utf-8"?>
<Configuration>
  <Contingency_analysis>
    <networkConfiguration>IEEE14.raw</networkConfiguration>

    <!-- Contingency sources -->
    <FullBranchN1>true</FullBranchN1>
    <FullGeneratorN1>false</FullGeneratorN1>
    <contingencyList>contingencies.xml</contingencyList>

    <!-- Parallelism: number of MPI ranks per contingency group -->
    <groupSize>1</groupSize>

    <!-- Violation thresholds -->
    <minVoltage>0.9</minVoltage>
    <maxVoltage>1.1</maxVoltage>

    <!-- Enable reactive power limit enforcement (PV→PQ bus switching) -->
    <qlim>false</qlim>

    <!-- Write detailed output file for each contingency -->
    <printCalcFiles>true</printCalcFiles>

    <LinearSolver>
      <PETScOptions>
        -ksp_type preonly
        -pc_type lu
        -pc_factor_mat_solver_type superlu_dist
      </PETScOptions>
    </LinearSolver>
  </Contingency_analysis>
</Configuration>

Parallel execution model

The driver uses GridPACK’s task manager to divide contingencies across independent MPI communicator groups. The groupSize parameter controls how many MPI ranks share each contingency’s power flow network. For large transmission systems a group size greater than 1 enables intra-contingency parallelism; for most medium-sized cases groupSize=1 is sufficient and maximizes contingency throughput.
# Evaluate 100 contingencies with 4 ranks each (400 total MPI processes)
mpiexec -n 400 ./ca.x input.xml

# Single-process baseline
./ca.x input.xml
Each process group runs an independent copy of PFAppModule. Contingencies are distributed dynamically so that idle ranks pick up new work as soon as they finish their current task.

Automatic slack bus transfer

When a generator contingency removes the slack bus generator from service, the driver automatically transfers the slack bus role to the bus with the largest remaining online generator capacity. This matches the behavior of commercial power flow tools such as PSS/E and PowerWorld.
Slack bus transferred from bus 69 to bus 80 (capacity: 577.0 MW)
After the contingency analysis completes, the slack bus is restored to its original location using restoreSlack().

Slack capacity check

After each post-contingency power flow converges, the driver calls checkSlackCapacity() to verify that the slack bus generator output does not exceed its Pmax rating. If capacity is exceeded, the contingency is flagged as a failure:
WARNING: Slack bus 80 generator output (475.3 MW) exceeds capacity (400.0 MW)
Insufficient generation capacity for contingency GN_69_1

Island detection

Branch outages can split the network into disconnected islands. The driver calls getIslandCount() and hasLoneBus() before attempting a power flow solve. When isolation is detected, the contingency is flagged with a warning: isolated tag in the results and, where possible, the main connected portion is still solved.

Violation checking

After solving each post-contingency power flow, the driver checks for:
  • Voltage violations: bus voltages outside [minVoltage, maxVoltage] (default [0.9, 1.1] pu).
  • Line overload violations: branch currents or power flows exceeding the rating stored in the PSS/E network file (Rate A by default; Rate B can be selected by calling useRateB(true) on the underlying PFAppModule).
Violations that exist in the base case (without any contingency) are registered via ignoreVoltageViolations() and ignoreLineOverloadViolations() so that the contingency screening reports only new violations.

Output files

The application writes aggregate result files to the working directory. All columns are space-delimited.
FileContents
success.txtPer-contingency: convergence status, violation type, isolation warning
vmag.txtPer-bus: average voltage magnitude, RMS deviation from average and from base case
vmag_mm.txtPer-bus: base case value, minimum and maximum voltage over all contingencies, contingency indices
vang.txtPer-bus: average voltage angle (PV buses included)
pgen.txt / pgen_mm.txtPer-generator: average and min/max real power across contingencies
qgen.txt / qgen_mm.txtPer-generator: average and min/max reactive power across contingencies
pflow.txt / pflow_mm.txtPer-branch: average and min/max real power flow, with rate A limits
perf_mm.txtPer-branch: min/max performance index (S/rating)²
perf_sum.txtPer-contingency: sum and average of performance index over all branches
line_flt_cnt.txtPer-branch: total number of contingencies that caused a fault on that branch
pq_changed_cnt.txtPer-bus: number of PV→PQ conversions (only when qlim=true)
A success.txt entry looks like:
contingency: 1 success: true violation: none
contingency: 2 success: true violation: branch
contingency: 3 success: true violation: none warning: isolated
contingency: 4 success: false
Only contingencies that ran to convergence are included in the aggregate statistical files. Failed contingencies (success: false) appear in success.txt but are excluded from vmag.txt, pflow.txt, and similar files.

Power flow

The PFAppModule class that contingency analysis builds on top of.

State estimation

Use state estimation to produce a calibrated base case before contingency screening.

Build docs developers (and LLMs) love