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 power flow module provides a parallel Newton-Raphson AC power flow solver built on top of PETSc. The PFAppModule class in the gridpack::powerflow namespace encapsulates every phase of a power flow calculation—reading and partitioning the network, initializing internal data structures, solving the nonlinear system, and writing results—so that the same object can serve as a standalone solver or as the first stage in a larger workflow such as contingency analysis or dynamic simulation initialization.

Setting up and running a power flow

1

Open the configuration file

Parse the XML input deck and obtain a cursor pointing at the Powerflow block. The configuration object is created once in the calling program and passed by pointer to all module calls.
gridpack::utility::Configuration *config =
    gridpack::utility::Configuration::configuration();
config->open("input.xml", world);
2

Read and partition the network

Create an empty PFNetwork and pass it to readNetwork(). The method reads the PSS/E RAW file named in the networkConfiguration field and partitions the network across MPI ranks.
boost::shared_ptr<gridpack::powerflow::PFNetwork>
    pf_network(new gridpack::powerflow::PFNetwork(world));

gridpack::powerflow::PFAppModule pf_app;
pf_app.readNetwork(pf_network, config);
The optional idx argument selects a specific Powerflow block when the input file contains more than one.
3

Initialize exchange buffers

Call initialize() to set up internal indices and the MPI exchange buffers used during matrix assembly. This must be called before solve().
pf_app.initialize();
4

Solve the power flow

Two solvers are available. The default hand-coded Newton-Raphson loop is recommended for production use because it applies direct LU factorization once per iteration and avoids spurious divergence checks.
pf_app.solve();       // hand-coded Newton-Raphson (recommended)
pf_app.nl_solve();    // library nonlinear solver via PETSc SNES
Both return false if the solver catches an error during the iteration.
5

Write and export results

Write bus voltages and branch flows to standard output or a file:
pf_app.write();                    // buses and branches
pf_app.writeBus("pq");             // bus complex voltage only
pf_app.writeBranch("flow");        // branch power flows only
Export structured results to JSON or CSV via ResultsExporter:
pf_app.exportResults("pf_result",
    gridpack::utility::ResultsExporter::JSON);  // writes pf_result_buses.json and pf_result_branches.json
pf_app.exportResults("pf_result",
    gridpack::utility::ResultsExporter::CSV);   // writes pf_result_buses.csv and pf_result_branches.csv
6

Save results for downstream modules

Persist bus voltages and generator outputs into each bus’s DataCollection object so they can be transferred to a dynamic simulation or state estimation network:
pf_app.saveData();
Stored variables include BUS_PF_VMAG, BUS_PF_VANG, GENERATOR_PF_PGEN[i], and GENERATOR_PF_QGEN[i].

XML configuration reference

The Powerflow block controls all solver parameters. Below is a complete annotated example:
<?xml version="1.0" encoding="utf-8"?>
<Configuration>
  <Powerflow>
    <!-- Network input: PSS/E RAW file; use networkConfiguration_v33/v34/v35/v36 for explicit version -->
    <networkConfiguration> IEEE14.raw </networkConfiguration>

    <!-- Newton-Raphson convergence parameters -->
    <maxIteration>50</maxIteration>
    <tolerance>1.0e-6</tolerance>
    <dampingFactor>1.0</dampingFactor>   <!-- 1.0 = undamped; <1.0 for ill-conditioned cases -->
    <initStart>warm</initStart>           <!-- "warm" reads VM/VA from RAW; "flat" uses 1.0 pu / 0 deg -->

    <!-- Reactive power limit enforcement (PV→PQ bus switching) -->
    <qlim>true</qlim>
    <maxQlimIterations>3</maxQlimIterations>
    <qlimDeadband>0.1</qlimDeadband>      <!-- Mvar tolerance to prevent spurious switching -->

    <!-- Switched shunt voltage control (MODSW=1 discrete, MODSW=2 continuous) -->
    <SwitchedShunt>false</SwitchedShunt>

    <!-- Load tap changer transformer control (COD1=1 in PSS/E data) -->
    <LTC>false</LTC>

    <!-- Area interchange MW control -->
    <AreaInterchange>false</AreaInterchange>

    <!-- Shared iteration limit for all active controls -->
    <maxControllerIterations>10</maxControllerIterations>

    <!-- Structured result export -->
    <outputFormat>json</outputFormat>     <!-- "json", "csv", or omit for text-only -->
    <outputFile>pf_result</outputFile>

    <!-- Linear solver: direct LU factorization is recommended -->
    <LinearSolver>
      <PETScOptions>
        -ksp_type preonly
        -pc_type lu
        -pc_factor_mat_solver_type superlu_dist
      </PETScOptions>
    </LinearSolver>
  </Powerflow>
</Configuration>
When outputFormat is json, two files are written: <outputFile>_buses.json and <outputFile>_branches.json. When set to csv, the suffixes become _buses.csv and _branches.csv.

PSS/E input format versions

GridPACK supports PSS/E RAW files for versions 23, 33, 34, 35, and 36. For v30+ files the parser automatically reads the version number from the third field of the RAW file header, so no special tag is needed in most cases. Version-specific tags take precedence over auto-detection and are retained for backward compatibility.
<networkConfiguration> network.raw </networkConfiguration>
PSS/E v23 files, which lack a version field in the header, are treated as the default when auto-detection finds no version indicator.

Newton-Raphson solver details

The hand-coded solve() routine runs a Newton-Raphson iteration loop controlled by maxIteration and tolerance. The dampingFactor parameter (default 1.0) scales each correction vector before it is applied to bus voltages and angles. Setting it below 1.0 reduces the step size and can improve convergence for heavily loaded or poorly initialized networks. A value of 1.0 is recommended for RAW files that already store a converged operating point. The initStart parameter controls initialization:
  • warm (default): reads voltage magnitude (VM) and angle (VA) directly from the PSS/E RAW bus section.
  • flat: sets all bus voltages to 1.0 pu and all angles to 0 degrees, useful when stored voltages are unreliable.

Q-limit enforcement and PV→PQ bus switching

When qlim is true (default), the solver checks each PV bus after Newton-Raphson convergence. If a generator’s reactive output exceeds its Qmax or Qmin limits by more than qlimDeadband (default 0.1 Mvar), the bus is converted to a PQ bus and the power flow is re-solved. The outer switching loop runs up to maxQlimIterations (default 3) times. The deadband prevents oscillation in cases where the required Q is close to a limit.
When qlim=false, warm-start cases with pre-solved voltages may not correctly restore PV/PQ bus types from RAW file. Use qlim=true (the default) for production runs.

Switched shunt control

When SwitchedShunt is enabled, buses with switched shunt data are monitored after each Newton-Raphson convergence. Two control modes are supported:
MODSW valueBehavior
1 (discrete)Switches one capacitor or reactor bank step per controller iteration. Cycle detection locks shunts that oscillate between two states.
2 (continuous)Adjusts susceptance B smoothly toward the [VSWLO, VSWHI] deadband midpoint.
Shunts with a nonzero SWREM field regulate voltage at the specified remote bus rather than the local bus. The initial susceptance value BINIT is absorbed into the fixed bus shunt admittance during network setup, consistent with commercial power system tools.

Load tap changer (LTC) transformer control

When LTC is enabled, transformers with COD1=1 in their PSS/E data automatically adjust their tap ratios to regulate voltage at the controlled bus within the [VMI, VMA] deadband. Tap ratios are adjusted by one discrete step per controller iteration, bounded by [RMI, RMA]. The step size is derived from the tap range and number of tap positions (NTP), or read from the STEP field when available. Cycle detection prevents tap hunting.

Area interchange control

When AreaInterchange is enabled, the solver computes actual MW exports for each area by summing tie-line flows across area boundaries. If the export deviates from the desired value (PDES) by more than the tolerance (PTOL), the solver adjusts real power generation at the area’s slack bus (ISW) and re-solves. This outer loop runs up to 10 iterations.

Running the standalone binary

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

# Multi-process with MPI (4 ranks)
mpiexec -n 4 ./pf.x input.xml
The solver prints per-iteration maximum mismatch during convergence and a timing summary at the end. To suppress all output, add <suppressOutput>true</suppressOutput> to the Powerflow block.

Island detection

After calling solve(), the method getIslandCount() returns the number of electrical islands in the network. A value greater than 1 indicates the network is fragmented. hasLoneBus() identifies any bus that has become completely isolated with no active branch connections. These checks are useful before attempting a post-contingency re-solve.

ZIP load model

The power flow module supports voltage-dependent ZIP loads. The load power at voltage V is computed as:
P_load = PL + IP·V + YP·V²
Q_load = QL + IQ·V − YQ·V²
ZIP coefficients are read automatically from PSS/E network files when present and follow PSS/E sign conventions.

Contingency analysis

Run N-1 contingency screening using PFAppModule as the base solver.

Dynamic simulation

Initialize transient stability simulation from a converged power flow.

Build docs developers (and LLMs) love