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 separates power grid topology from grid physics by attaching application-defined component objects to every bus and branch in the network. These objects implement the physics of the model — admittances, generator swing equations, transformer parameters — and expose that physics to the rest of the framework through a standard interface. Understanding how components are structured, how they are initialized from input data, and how they contribute to system matrices is essential for writing GridPACK applications.

Class hierarchy

The component class hierarchy starts with two abstract interface classes and builds to the concrete base classes that applications derive from:
MatVecInterface          GenMatVecInterface
        \                  /
         BaseComponent
              |
    ┌─────────┴──────────┐
BaseBusComponent   BaseBranchComponent
    |                    |
MyBus (user)         MyBranch (user)
All classes reside in the gridpack::component namespace.

MatVecInterface

MatVecInterface defines the contract between a component and the mapper. Buses contribute to diagonal matrix blocks and vector elements; branches contribute to off-diagonal blocks:
class MatVecInterface {
public:
    // Diagonal block size (buses) — return false if no contribution
    virtual bool matrixDiagSize(int *isize, int *jsize) const;
    virtual bool matrixDiagValues(ComplexType *values);
    virtual bool matrixDiagValues(RealType *values);

    // Off-diagonal forward block (branches, from-bus → to-bus)
    virtual bool matrixForwardSize(int *isize, int *jsize) const;
    virtual bool matrixForwardValues(ComplexType *values);

    // Off-diagonal reverse block (branches, to-bus → from-bus)
    virtual bool matrixReverseSize(int *isize, int *jsize) const;
    virtual bool matrixReverseValues(ComplexType *values);

    // Vector contribution (buses)
    virtual bool vectorSize(int *isize) const;
    virtual bool vectorValues(ComplexType *values);

    // Receive solution values back from a vector
    virtual void setValues(ComplexType *values);
};
All methods have default implementations that return false (no contribution). Override only the methods relevant to your calculation.

BaseComponent

BaseComponent inherits from both MatVecInterface and GenMatVecInterface and adds infrastructure shared by all network components:
class BaseComponent : public MatVecInterface, public GenMatVecInterface {
public:
    // Called by factory.load() — transfer DataCollection → component fields
    virtual void load(
        const boost::shared_ptr<gridpack::component::DataCollection> &data);

    // Exchange buffer size in bytes (must be same for all buses or all branches)
    virtual int getXCBufSize(void);

    // Assign the exchange buffer pointer (called by factory.setExchange())
    virtual void setXCBuf(void *buf);

    // Control calculation mode (e.g., YBus vs Jacobian)
    virtual void setMode(int mode);

    // Formatted string for serial output
    virtual bool serialWrite(char *string, const int bufsize,
                             const char *signal = NULL);
};

BaseBusComponent

BaseBusComponent extends BaseComponent with bus-specific topology queries:
class BaseBusComponent : public BaseComponent {
public:
    // Access neighboring branches and buses
    void getNeighborBranches(
        std::vector<boost::shared_ptr<BaseComponent>> &nghbrs) const;
    void getNeighborBuses(
        std::vector<boost::shared_ptr<BaseComponent>> &nghbrs) const;

    // Reference bus designation
    void setReferenceBus(bool status);
    bool getReferenceBus(void) const;

    // Index access
    void setOriginalIndex(int idx);
    int  getOriginalIndex(void) const;
    int  getGlobalIndex(void) const;
};
getNeighborBranches() and getNeighborBuses() only return correct results after factory.setComponents() has been called. The neighbor lists are pushed from the network into individual bus objects during that call.

BaseBranchComponent

BaseBranchComponent extends BaseComponent with endpoint bus access:
class BaseBranchComponent : public BaseComponent {
public:
    boost::shared_ptr<BaseComponent> getBus1(void) const; // "from" bus
    boost::shared_ptr<BaseComponent> getBus2(void) const; // "to" bus

    int getBus1OriginalIndex(void) const;
    int getBus2OriginalIndex(void) const;
    int getBus1GlobalIndex(void) const;
    int getBus2GlobalIndex(void) const;
};

The DataCollection class

Every bus and branch has an associated DataCollection object — a typed key-value store that acts as an intermediary between raw data from input files and the component objects. Keys are defined as #define macros in dictionary.hpp (and included files in src/parser/variable_defs/), providing a compile-time check against misspellings.

Reading values in load()

void MyBus::load(
    const boost::shared_ptr<gridpack::component::DataCollection> &data)
{
    // Single-valued parameter — set a default, then overwrite if present
    p_voltage_mag = 1.0;
    data->getValue(BUS_VOLTAGE_MAG, &p_voltage_mag);

    // Single-valued parameter — use return value to detect absence
    double angle = 0.0;
    if (!data->getValue(BUS_VOLTAGE_ANG, &angle)) {
        // parameter not in file; use default
    }
    p_voltage_ang = angle;

    // Indexed parameter — multiple generators on one bus
    int num_gen = 0;
    data->getValue(GENERATOR_NUMBER, &num_gen);
    p_generators.resize(num_gen);
    for (int i = 0; i < num_gen; i++) {
        data->getValue(GENERATOR_PG, &p_generators[i].pg, i); // 0-based index
        data->getValue(GENERATOR_QG, &p_generators[i].qg, i);
        data->getValue(GENERATOR_ID, &p_generators[i].id, i);
    }
}
Using the macro form BUS_VOLTAGE_MAG instead of the string literal "BUS_VOLTAGE_MAG" causes a compile error if the symbol is undefined or misspelled — a valuable safeguard.

Writing values back

DataCollection can also accept new entries, which is useful when chaining calculations (e.g., writing powerflow results into a DataCollection that a dynamic simulation then reads):
data->addValue(BUS_VOLTAGE_MAG, computed_voltage);       // new entry
data->setValue(BUS_VOLTAGE_ANG, updated_angle);          // overwrite existing

Implementing MatVecInterface methods

The mapper calls MatVecInterface methods on every active component to assemble the system matrix. For a Y-bus calculation, a bus contributes a 1×1 diagonal block and a branch contributes two 1×1 off-diagonal blocks:
// In MyBus — diagonal contribution to Y-bus
bool MyBus::matrixDiagSize(int *isize, int *jsize) const {
    if (p_isReference) return false; // slack bus skipped
    *isize = 1; *jsize = 1;
    return true;
}

bool MyBus::matrixDiagValues(ComplexType *values) {
    std::vector<boost::shared_ptr<gridpack::component::BaseComponent>> branches;
    getNeighborBranches(branches);

    ComplexType y_shunt(p_gl, -p_bl); // shunt admittance
    ComplexType y_sum = y_shunt;
    for (size_t i = 0; i < branches.size(); i++) {
        MyBranch *br = dynamic_cast<MyBranch*>(branches[i].get());
        y_sum -= br->getYContribution(); // Y_ii = -sum(Y_ij)
    }
    values[0] = y_sum;
    return true;
}

Controlling behavior with setMode()

A single bus or branch class can generate different matrix contributions depending on the calculation phase. The setMode(int mode) method sets an internal flag that the MatVecInterface methods inspect:
// In MyBus
void MyBus::setMode(int mode) {
    p_mode = mode;
}

bool MyBus::matrixDiagValues(ComplexType *values) {
    if (p_mode == YBUS) {
        // assemble Y-bus diagonal
    } else if (p_mode == JACOBIAN) {
        // assemble power-flow Jacobian diagonal
    }
    return true;
}
BaseFactory::setMode(int mode) propagates the mode to every bus and branch in a single call. setBusMode() and setBranchMode() set mode on only buses or only branches respectively.

Exchange buffers for ghost synchronization

When ghost buses need updated values from their home processors, the data travels through fixed-size exchange buffers. Each component specifies the buffer size and sets up internal pointers when the buffer is assigned:
// Return size in bytes of data to be exchanged
int MyBus::getXCBufSize(void) {
    return 2 * sizeof(double); // voltage magnitude + angle
}

// Store pointer to the buffer for later use
void MyBus::setXCBuf(void *buf) {
    p_mag_ptr = static_cast<double*>(buf);
    p_ang_ptr = p_mag_ptr + 1;
}
Before a ghost update, each active bus writes its current values into the buffer. After network->updateBuses(), each ghost bus’s buffer contains fresh values from the home processor.

Generator and load models

Generators and loads are not separate classes in the network graph — they are modeled as parameters and sub-objects within bus component classes. A bus component that represents a generator bus holds a collection of generator records, one per machine:
struct GeneratorRecord {
    double pg;          // active power output (MW)
    double qg;          // reactive power output (MVAR)
    double mbase;       // machine MVA base
    double ra, xd, xq; // machine reactances
    std::string id;     // machine identifier string
};

class MyBus : public gridpack::component::BaseBusComponent {
private:
    std::vector<GeneratorRecord> p_generators;
    // ...
};
For dynamic simulation, the framework supports BaseGeneratorDynamicsModel — a base class for generator dynamic models (classical, GENROU, GENSAL, etc.). These models are attached to bus components and integrated by the DAESolver during time-stepping.

Framework overview

How components fit into the four-layer GridPACK architecture

Network model

How buses and branches form the distributed network graph

Parallel computing

Ghost exchange, communicators, and task distribution

Build docs developers (and LLMs) love