GridPACK bus and branch components: implementing grid physics, loading DataCollection parameters, and contributing matrix elements through MatVecInterface.
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.
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:
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 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 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;};
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.
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.
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 entrydata->setValue(BUS_VOLTAGE_ANG, updated_angle); // overwrite existing
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-busbool 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;}
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:
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.
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 exchangedint MyBus::getXCBufSize(void) { return 2 * sizeof(double); // voltage magnitude + angle}// Store pointer to the buffer for later usevoid 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.
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