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.

Mappers sit at the boundary between the network topology layer and the linear-algebra layer. After each Newton-Raphson iteration (or time step), component state on every MPI rank is assembled into globally-indexed distributed Matrix and Vector objects that the solvers consume. The mappers handle all inter-rank index coordination through Global Arrays so that application code never has to manage global offsets manually.

How mappers work

Each mapper is constructed once from a shared_ptr to the network and reused across solver iterations. On construction the mapper calls contributions() to count which buses and branches will contribute elements, then sets up Global Array offset tables. Subsequent mapToVector / mapToMatrix calls iterate over active local components, invoke their matVecInterface methods, and scatter the results into the distributed object.
1

Component implements matVecInterface

Each bus and branch class overrides vectorSize, vectorValues, matrixDiagSize, matrixDiagValues, matrixForwardSize, matrixForwardValues, etc. to report the size and values of their contribution.
2

Factory sets the computation mode

Call factory.setMode(MODE_CONSTANT) before mapping so that every component fills values appropriate for the current phase (e.g., Y-matrix assembly vs. residual evaluation).
3

Mapper builds the algebraic object

Call mapper.mapToMatrix(Y) or mapper.mapToVector(b). The mapper zeroes the object, iterates over contributing components, and scatters their values into the distributed layout.
4

Solver receives the assembled object

The resulting Matrix or Vector is passed to LinearSolver::solve, NonlinearSolver::solve, or the DAE integrator.

BusVectorMap

gridpack::mapper::BusVectorMap<_network> assembles a distributed Vector (or RealVector) from bus contributions. Only active (non-ghost) buses whose vectorSize returns true contribute elements.
#include <gridpack/mapper/bus_vector_map.hpp>

// Construct once; ownership of offset arrays stays in the mapper
gridpack::mapper::BusVectorMap<PFNetwork> busMap(network);

// Create a new vector (collective on all ranks)
boost::shared_ptr<gridpack::math::Vector> b = busMap.mapToVector();

// After updating bus state, repopulate an existing vector in-place
busMap.mapToVector(*b);

// Push solution back from vector into bus objects
busMap.mapToBus(*b);

Component interface required

Your bus class must implement:
// Report how many complex values this bus contributes (0 = not active)
bool vectorSize(int *size);

// Fill the complex values starting at the pointer
void vectorValues(ComplexType *values);

// Accept solution values back from the vector
void setValues(ComplexType *values);
mapToBus calls setValues on each contributing bus after retrieving the global elements from the distributed vector.

FullMatrixMap

gridpack::mapper::FullMatrixMap<_network> assembles a distributed Matrix (or RealMatrix) from both bus diagonal blocks and branch off-diagonal blocks. Buses contribute diagonal blocks; branches contribute forward and reverse off-diagonal blocks.
#include <gridpack/mapper/full_map.hpp>

gridpack::mapper::FullMatrixMap<PFNetwork> matMap(network);

// Create a new sparse matrix
boost::shared_ptr<gridpack::math::Matrix> Y = matMap.mapToMatrix();

// Rebuild an existing matrix (zeroes then refills)
matMap.mapToMatrix(*Y);

// Overwrite specific elements without zeroing (additive update)
matMap.incrementMatrix(*Y);

// Validate that branch and bus block sizes are consistent
bool ok = matMap.check();

Dense matrix variant

Pass true to request a dense matrix, useful for small problems or debugging:
auto Y_dense = matMap.mapToMatrix(/*isDense=*/true);

Component interface required

Buses must implement:
bool matrixDiagSize(int *isize, int *jsize);
bool matrixDiagValues(ComplexType *values);
void getMatVecIndex(int *idx);
Branches must implement:
bool matrixForwardSize(int *isize, int *jsize);
bool matrixForwardValues(ComplexType *values);
bool matrixReverseSize(int *isize, int *jsize);
bool matrixReverseValues(ComplexType *values);
void getMatVecIndices(int *idx, int *jdx);
The forward direction corresponds to the branch contribution from the Bus1 side; the reverse direction corresponds to the Bus2 side.
matrixForwardSize and matrixReverseSize return false to indicate that a branch contributes no off-diagonal elements. A branch can contribute to one direction but not the other.

GenVectorMap and GenMatrixMap

For state-estimation and other problems where some variables are associated with branches (not just buses), GridPACK provides generalized mappers in gen_vector_map.hpp and gen_matrix_map.hpp. These use matrixNumRows / matrixNumCols from GenMatVecInterface instead of the block-based MatVecInterface.

The sMode pattern

Application components often need to fill different values depending on the current computation phase (Y-matrix build, Jacobian evaluation, residual evaluation, etc.). The convention is:
// In the factory header, define integer mode constants
enum PFMode { YBus = 0, Jacobian = 1, Residual = 2 };

// In the application driver, switch modes before mapping
factory.setMode(YBus);
yMap.mapToMatrix(Y);      // buses/branches fill admittance values

factory.setMode(Jacobian);
jMap.mapToMatrix(J);      // buses/branches fill Jacobian contributions

factory.setMode(Residual);
busMap.mapToVector(F);    // buses fill mismatch (P, Q) values
Inside each bus or branch class, vectorValues and matrixDiagValues check the mode flag (stored via setMode) to know which values to compute:
void MyBus::vectorValues(ComplexType *values) {
  if (p_mode == Residual) {
    values[0] = ComplexType(p_Pmismatch, p_Qmismatch);
  } else if (p_mode == YBus) {
    values[0] = p_Yself;
  }
}

Complete usage example

#include <gridpack/mapper/bus_vector_map.hpp>
#include <gridpack/mapper/full_map.hpp>

// After network partition, factory.setComponents(), factory.load():
gridpack::mapper::FullMatrixMap<PFNetwork>  yMapper(network);
gridpack::mapper::BusVectorMap<PFNetwork>   busMapper(network);

// --- Build Y-matrix once ---
factory.setMode(YBus);
auto Y = yMapper.mapToMatrix();

gridpack::math::LinearSolver solver(*Y);
solver.configure(config->getCursor("Configuration.PowerFlow.LinearSolver"));

// --- Newton-Raphson loop ---
for (int iter = 0; iter < maxIter; iter++) {
  // Evaluate residual
  factory.setMode(Residual);
  auto F = busMapper.mapToVector();

  if (F->normInfinity() < tolerance) break;

  // Evaluate Jacobian
  factory.setMode(Jacobian);
  yMapper.mapToMatrix(*Y);

  // Solve J * dx = -F
  auto dx = busMapper.mapToVector();
  dx->scale(-1.0);
  solver.solve(*F, *dx);

  // Update bus state
  busMapper.mapToBus(*dx);
}

Math module: solvers

LinearSolver, NonlinearSolver, and DAESolver classes that consume mapper output.

Factory pattern

Use BaseFactory to initialize components and call setMode before each mapping pass.

Build docs developers (and LLMs) love