From 8a91ca6675238f494e0d6c3257909f3d2fd0585f Mon Sep 17 00:00:00 2001 From: pelesh Date: Thu, 2 Apr 2026 14:02:57 -0400 Subject: [PATCH 1/4] [skip ci] Add component model developer checklist. --- GridKit/Model/PhasorDynamics/README.md | 63 ++++++++++++++++++- .../PhasorDynamics/GenClassicalTests.hpp | 4 +- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/GridKit/Model/PhasorDynamics/README.md b/GridKit/Model/PhasorDynamics/README.md index ec38c25a2..0f839bf82 100644 --- a/GridKit/Model/PhasorDynamics/README.md +++ b/GridKit/Model/PhasorDynamics/README.md @@ -1,7 +1,68 @@ # Phasor dynamics This directory contains an implementation of a system model using phasor -dynamics. Aside from all of the modeling aspects, one additional part of +dynamics. + +## Modeling checklist + +In current GridKit architecture each component model is implemented in six +files: +- `MyModel.cpp`: Basic compilation unit for the case when model does not + provide Jacobian. +- `MyModel.hpp`: Component model declaration. +- `MyModelData.hpp`: Definitions of model data including model parameters, + model connection ports and model outputs (monitored + variables). +- `MyModelDependencyTracking.cpp`: Compilation unit for Jacobian evaluation + using dependency tracking data type (a.k.a + tapeless automatic differentiation). +- `MyModelEnzyme.cpp`: Compilation unit for Jacobian evaluation with Enzyme. +- `MyModelimpl.hpp`: Actual model implementation. + +In essence, a component model developer needs to implement model data +structures in `MyModelData.hpp` file and model equations in `MyModelImpl.hpp` +file. The remaining four files are just supporting infrastructure for +compilation and testing. + +We recommend developers follow these steps when adding new component models: +1. Create a subdirectory within appropriate model family directory. +2. Create a README file in markdown format that contains all information + needed to implement the model. This should include: + 1. List of model parameters in a table format. + 2. List of _derived_ model parameters with mathematical expression + describing how they are obtained from instantiation parameters. + 3. Model internal variables. Use separate tables for differential and + algebraic variables. + 4. Model external variables (always algebraic in phasor dynamics). + 5. Model differential and algebraic equations (in separate subsections). + 6. Model initialization procedure with equations in order in which + initialization computations are performed. + 7. List of model outputs with equations for computing those outputs + where applicable. +3. Create all six `MyModel*.*pp` implementation files and `CMakeLists.txt` + file, which specifies build requirements (files to compile, files to + include, libraries to link and location to install to). Ensure the code + builds correctly. + - You may want to start with a "dummy" implementation first to make sure + the build and installation works correctly before proceeding to the + implementation. +4. Create unit tests in `tests/UnitTesting/PhasorDynamics` directory. Unit + test should include: + 1. Constructor tests (smoke tests). + 2. Residual evaluation test (pick input variables to get easy to verify + residual values). + 3. Jacobian evaluation test (Enzyme generated Jacobian must match Jacobian + created using dependency tracking variables). + 4. Initialization test (initialize to arbitrary, easy to verify values). + 5. Initialize and evaluate residual test (initialization should ensure + residual evaluates to zero within prescribed tolerance). +5. Recommended: Create an example using the new component. + + + +## Input file parser + +Aside from all of the modeling aspects, one additional part of note is the experimental JSON parsing functionality which can take in a JSON object (described in `INPUT_FORMAT.md`) and yields a system model. This is implemented with the [nlohmann/json](https://github.com/nlohmann/json) diff --git a/tests/UnitTests/PhasorDynamics/GenClassicalTests.hpp b/tests/UnitTests/PhasorDynamics/GenClassicalTests.hpp index 83b19640f..2938816ac 100644 --- a/tests/UnitTests/PhasorDynamics/GenClassicalTests.hpp +++ b/tests/UnitTests/PhasorDynamics/GenClassicalTests.hpp @@ -180,8 +180,8 @@ namespace GridKit return success.report(__func__); } - /* - *Verifies the residual evaluates to zero for the initial conditions + /** + * Verifies the residual evaluates to zero for the initial conditions */ TestOutcome zeroInitialResidual() { From 07e3343dd08ed421dcce2cac65a7db840d9346ef Mon Sep 17 00:00:00 2001 From: pelesh Date: Mon, 6 Apr 2026 10:59:00 -0400 Subject: [PATCH 2/4] [skip ci] Update GridKit/Model/PhasorDynamics/README.md Co-authored-by: Steven Roberts --- GridKit/Model/PhasorDynamics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GridKit/Model/PhasorDynamics/README.md b/GridKit/Model/PhasorDynamics/README.md index 0f839bf82..25ec0813d 100644 --- a/GridKit/Model/PhasorDynamics/README.md +++ b/GridKit/Model/PhasorDynamics/README.md @@ -56,7 +56,7 @@ We recommend developers follow these steps when adding new component models: 4. Initialization test (initialize to arbitrary, easy to verify values). 5. Initialize and evaluate residual test (initialization should ensure residual evaluates to zero within prescribed tolerance). -5. Recommended: Create an example using the new component. +5. Recommended: Create an example in `examples/PhasorDynamics` using the new component. From 6ca8a09e848d59698b6da6a12cad3a16f16ce979 Mon Sep 17 00:00:00 2001 From: pelesh Date: Mon, 6 Apr 2026 11:18:10 -0400 Subject: [PATCH 3/4] Update changelog and model readme files. --- CHANGELOG.md | 2 ++ GridKit/Model/PhasorDynamics/README.md | 12 ++++++----- .../PowerElectronics/MicrogridBusDQ/README.md | 11 +++++----- GridKit/Model/PowerElectronics/README.md | 20 +++++++++---------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d17bf9a9..03ed87b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ - Added `Node` class to the PowerElectronics module to separate nodes from circuit components. - Refactored Jacobian assembly in `PowerElectronics` module to reuse the CSR pattern. - Refactored Jacobian assembly in `PhasorDyanmcics` module to reuse the CSR pattern. +- Added component model developer checklist to a README file. + ## v0.1 - Refactored code to support adding different model families. diff --git a/GridKit/Model/PhasorDynamics/README.md b/GridKit/Model/PhasorDynamics/README.md index 25ec0813d..bce07b991 100644 --- a/GridKit/Model/PhasorDynamics/README.md +++ b/GridKit/Model/PhasorDynamics/README.md @@ -49,13 +49,15 @@ We recommend developers follow these steps when adding new component models: 4. Create unit tests in `tests/UnitTesting/PhasorDynamics` directory. Unit test should include: 1. Constructor tests (smoke tests). - 2. Residual evaluation test (pick input variables to get easy to verify - residual values). + 2. Residual evaluation test (substitute variables in the residual that + check all computations in the residual function; avoid zeros and ones + as inputs). 3. Jacobian evaluation test (Enzyme generated Jacobian must match Jacobian created using dependency tracking variables). - 4. Initialization test (initialize to arbitrary, easy to verify values). - 5. Initialize and evaluate residual test (initialization should ensure - residual evaluates to zero within prescribed tolerance). + 4. Initialization test (verify that component correctly sets initial + values). + 5. Combined initialization and residual evaluation test (initialization + should ensure residual evaluates to zero within prescribed tolerance). 5. Recommended: Create an example in `examples/PhasorDynamics` using the new component. diff --git a/GridKit/Model/PowerElectronics/MicrogridBusDQ/README.md b/GridKit/Model/PowerElectronics/MicrogridBusDQ/README.md index 79432b0f1..076f4eaf7 100644 --- a/GridKit/Model/PowerElectronics/MicrogridBusDQ/README.md +++ b/GridKit/Model/PowerElectronics/MicrogridBusDQ/README.md @@ -1,12 +1,12 @@ -The Bus used for the Microgrid found in references 1 and 2. +The bus model used for the microgrid found in Pogaku et al.[^1] and Bidram et al.[^2] Parameters: + $RN$ - Virtual Resistance Variables (External): - + $v_{D}$ - Incoming Bus Voltage (D) - + $v_{Q}$ - Incoming Bus Voltage (Q) + + $v_{D}$ - Bus voltage along direct axis + + $v_{Q}$ - Bus voltage along quadrature axis Equations (External, Residuals): + $\frac{-v_D}{RN}$ @@ -15,5 +15,6 @@ Equations (External, Residuals): There are no internal variables to this system. Only residuals to be added from existing externals. As $RN \rightarrow \infty$ then the bus represent Kirchhoff's current law. -1. Pogaku, Nagaraju, Milan Prodanovic, and Timothy C. Green. "Modeling, analysis and testing of autonomous operation of an inverter-based microgrid." IEEE Transactions on power electronics 22.2 (2007): 613-625. -2. Bidram, Ali, Frank L. Lewis, and Ali Davoudi. "Distributed control systems for small-scale power networks: Using multiagent cooperative control theory." IEEE Control systems magazine 34.6 (2014): 56-77. +[^1]: Pogaku, Nagaraju, Milan Prodanovic, and Timothy C. Green. "Modeling, analysis and testing of autonomous operation of an inverter-based microgrid." IEEE Transactions on power electronics 22.2 (2007): 613-625. + +[^2]: Bidram, Ali, Frank L. Lewis, and Ali Davoudi. "Distributed control systems for small-scale power networks: Using multiagent cooperative control theory." IEEE Control systems magazine 34.6 (2014): 56-77. diff --git a/GridKit/Model/PowerElectronics/README.md b/GridKit/Model/PowerElectronics/README.md index efe08996c..669e82172 100644 --- a/GridKit/Model/PowerElectronics/README.md +++ b/GridKit/Model/PowerElectronics/README.md @@ -1,7 +1,7 @@ This sub-directory provides components utilized within the PowerElectronicsModel composer. All components are treated equally and only the composer can view and distribute data to components. Components have no knowledge nor require the existence of any other component. Each component evaluates a set of equations to form residuals. There are two types of variables. - + Internal Variables. Variables only need by the component. - + External Variables. Variables shared between multiple components. + + Internal Variables $y$. Variables only need by the component. + + External Variables $w$. Variables shared between multiple components. Each equation is associated to a variable. The residuals generated by external components are assumed to add together to form the final system. Arbitrary amounts of components can be handle and residuals evaluated. @@ -16,25 +16,25 @@ Example with two components is as follows. Component 1: ```math \begin{align} - 0 = f_1(\frac{dy_{1}}{dt}, y_1 ,z) & \qquad \text{(Internal Equations)}\\ - c_1(y_1,z) & \qquad \text{(External Residuals)}\\ + 0 = f_1\left(\frac{dy_{1}}{dt}, y_1 , w \right) & \qquad \text{(Internal Equations Residual)}\\ + c_1(y_1, w) & \qquad \text{(External Coupling Term)}\\ \end{align} ``` Component 2: ```math \begin{align} - 0 = f_2(\frac{dy_{2}}{dt}, y_2 ,z) & \qquad \text{(Internal Equations)}\\ - c_2(y_2,z) & \qquad \text{(External Residuals)}\\ + 0 = f_2\left(\frac{dy_{2}}{dt}, y_2 ,w\right) & \qquad \text{(Internal Equations Residual)}\\ + c_2(y_2,w) & \qquad \text{(External Coupling Term)}\\ \end{align} ``` The composition of components 1 and 2: ```math \begin{align} - 0 = f_1(\frac{dy_{1}}{dt}, y_1 ,z) & \qquad \text{(Internal Equations)}\\ - 0 = f_2(\frac{dy_{2}}{dt}, y_2 ,z) &\\ - 0 = c_1(y_1, z) + c_2(y_2,z) & \qquad \text{(Composed External Residuals)}\\ + 0 = f_1\left(\frac{dy_{1}}{dt}, y_1 ,w\right) & \qquad \text{(Internal Equations Residuals)}\\ + 0 = f_2\left(\frac{dy_{2}}{dt}, y_2 ,w\right) &\\ + 0 = c_1(y_1, w) + c_2(y_2,w) & \qquad \text{(External Coupling Residuals)}\\ \end{align} ``` -Note the dimensions of \(y\) can be \(0\) if there are no internal equations (an example seen in Resistors and MicrogridBus). +Note the dimensions of $y$ can be $0$ if there are no internal equations (an example seen in Resistors and MicrogridBus). From 568b75801cee81cce673b8d5c05b7b1d035738a1 Mon Sep 17 00:00:00 2001 From: pelesh Date: Mon, 6 Apr 2026 18:20:51 -0400 Subject: [PATCH 4/4] [skip ci] Update component model developer checklist --- GridKit/Model/PhasorDynamics/README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/GridKit/Model/PhasorDynamics/README.md b/GridKit/Model/PhasorDynamics/README.md index bce07b991..ddd7d6001 100644 --- a/GridKit/Model/PhasorDynamics/README.md +++ b/GridKit/Model/PhasorDynamics/README.md @@ -17,7 +17,7 @@ files: using dependency tracking data type (a.k.a tapeless automatic differentiation). - `MyModelEnzyme.cpp`: Compilation unit for Jacobian evaluation with Enzyme. -- `MyModelimpl.hpp`: Actual model implementation. +- `MyModelImpl.hpp`: Actual model implementation. In essence, a component model developer needs to implement model data structures in `MyModelData.hpp` file and model equations in `MyModelImpl.hpp` @@ -45,9 +45,12 @@ We recommend developers follow these steps when adding new component models: builds correctly. - You may want to start with a "dummy" implementation first to make sure the build and installation works correctly before proceeding to the - implementation. -4. Create unit tests in `tests/UnitTesting/PhasorDynamics` directory. Unit - test should include: + implementation. +4. Create unit tests in `tests/UnitTesting/PhasorDynamics` directory. The + implementation consists of `MyModelTests.hpp` with implementation of + individual unit tests, the test driver in `runMyModelTests.cpp`, and + `CMakeLists.txt` with build and installation configuration of tests. Unit + test should be include: 1. Constructor tests (smoke tests). 2. Residual evaluation test (substitute variables in the residual that check all computations in the residual function; avoid zeros and ones @@ -58,7 +61,16 @@ We recommend developers follow these steps when adding new component models: values). 5. Combined initialization and residual evaluation test (initialization should ensure residual evaluates to zero within prescribed tolerance). -5. Recommended: Create an example in `examples/PhasorDynamics` using the new component. +5. Once model is tested, add it to the system composer. This requires following steps: + 1. Add header file `MyModel.hpp` to `ComponentLibrary.hpp`, so that + `MyModel` declaration is visible to the `SystemModel` class. + 3. Modify `SystemModelJsonParser.hpp` so that `MyModel` is recognized by the + parser. + 4. Modify `SystemModelData.hpp` so that `MyModelData` is visible to the system + model. + 5. Modify `SystemModel.hpp` so that `MyModel` components can be connected by the + system composer. +7. Recommended: Create an example in `examples/PhasorDynamics` using the new component.