Docs Andes App en Stable
Docs Andes App en Stable
Docs Andes App en Stable
Release 1.8.10
Hantao Cui
1 Getting started 3
1.1 Package Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1 New to Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.2 Extra support package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.3 Develop Install . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.4 Updating ANDES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.5 Uninstall Multiple Copies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.3 Tutorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3.1 Command line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3.2 Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.3.3 Cheatsheet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.3.4 Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.4 Config . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.4.1 Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
1.4.2 Adjusting on the fly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.4.3 Config reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
1.5 Input formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.5.1 ANDES xlsx . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
1.5.2 PSS/E RAW and DYR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
1.5.3 MATPOWER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.5.4 ANDES JSON . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
1.5.5 Disturbances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.6 Test Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.6.1 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
1.6.2 Example data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.6.3 MATPOWER cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.6.4 How to contribute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.7 Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.7.1 Numba compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
1.7.2 MATPOWER cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.8 Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.8.1 IEEE 14-Bus Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1.8.2 CURENT NPCC Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
i
1.8.3 CURENT WECC Verification . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
1.9 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
1.9.1 Per Unit System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
1.9.2 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
1.9.3 Profiling Import . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
1.9.4 What won't not work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
1.10 Frequently Asked Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
1.10.1 Program Startup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
1.10.2 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
1.10.3 Modeling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
1.11 License . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
1.11.1 GNU Public License v3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
1.12 Quick install . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
2 Examples 135
2.1 Simulate and Plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
2.1.1 Import and Setting the Verbosity Level . . . . . . . . . . . . . . . . . . . . . . . . 135
2.1.2 Run Time-Domain Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
2.1.3 Export and Plot Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
2.1.4 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
2.2 Working with Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
2.2.1 Load System from an ANDES XLSX File . . . . . . . . . . . . . . . . . . . . . . 149
2.2.2 Load System from PSS/E RAW and DYR Files . . . . . . . . . . . . . . . . . . . 151
2.2.3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
2.2.4 Altering Fault duration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
2.2.5 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
2.3 Inspecting Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
2.3.1 Inspect Model Equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
2.3.2 Check model documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
2.4 Eigenvalue Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
2.4.1 Run Eigenvalue Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
2.4.2 Plotting in S-Domain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
2.4.3 Report . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
2.4.4 Parameter Sweep and Root Loci Plot . . . . . . . . . . . . . . . . . . . . . . . . . 189
2.4.5 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
2.5 Using CLI from Notebook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
2.5.1 The ! magic in iPython . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
2.5.2 Set up on Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
2.5.3 Running Shell Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
2.5.4 Run a simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
2.5.5 Check the output lst file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
2.5.6 Plot and save to file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
2.5.7 Display image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
2.5.8 Using xargs for index lookup . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
2.5.9 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
2.6 Batch Processing - Generate Cases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
2.6.1 Create Cases in Batch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
2.6.2 Parallel Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
ii
2.7 Batch Processing - in Memory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
2.7.1 Batch Power Flow Calculation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
2.7.2 Batch Time-Domain Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
2.8 Changing Setpoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
2.8.1 Step 1: Case Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
2.8.2 Step 2: Set the First Stop Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.8.3 Step 3: Run Simulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
2.8.4 Step 4. Apply the auxiliary power setpoints to TGOV1.paux0.v . . . . . . . . . . 219
2.8.5 Step 5: Set Another New Setpoints and New Ending TIme. . . . . . . . . . . . . . 224
2.9 Load Frequency Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226
2.9.1 Tripping a Generator in the IEEE 14-Bus System . . . . . . . . . . . . . . . . . . . 227
2.9.2 Adjusting Load to Compensate for the Generation Loss . . . . . . . . . . . . . . . 230
2.10 Profile in Notebook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
2.10.1 Profiling with Python CProfiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
2.10.2 Profiling with line_profiler. . . . . . . . . . . . . . . . . . . . . . . . . . . 238
2.10.3 Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
2.11 MATPOWER Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
2.11.1 Create an Octave/MATLAB instance . . . . . . . . . . . . . . . . . . . . . . . . . 241
2.11.2 Convert to MATPOWER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
2.11.3 Convert from MATPOWER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
2.11.4 Add dynamic data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
2.12 pandapower Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
2.12.1 Load case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
2.12.2 Convert to pandapower net . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 247
2.12.3 Comapre Power Flow Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
2.12.4 Generator dispatch based on OPF from pandapower . . . . . . . . . . . . . . . . . 250
2.13 pypowsybl Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
2.13.1 Imports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
2.13.2 Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
2.13.3 Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254
3 Development 257
3.1 System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257
3.1.2 DAE Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
3.1.3 Model and DAE Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
3.1.4 Calling Model Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
3.1.5 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
3.2 Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
3.2.1 andes.models.group.GroupBase . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
3.3 Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
3.3.1 andes.core.model.ModelData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269
3.3.2 andes.core.model.Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
3.3.3 andes.core.model.ModelCache . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
3.3.4 andes.core.model.ModelCall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
3.3.5 Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
3.3.6 Define Voltage Ratings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
3.3.7 Commonly Used Attributes in Models . . . . . . . . . . . . . . . . . . . . . . . . 290
iii
3.3.8 Attributes in Model.cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
3.3.9 Abstract Jacobian Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
3.3.10 Concrete Jacobian Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
3.4 Atomic Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
3.4.1 Value Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
3.4.2 Equation Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
3.5 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.5.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
3.6 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
3.6.1 andes.core.var.BaseVar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316
3.6.2 andes.core.var.ExtVar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
3.6.3 andes.core.var.State . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
3.6.4 andes.core.var.Algeb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324
3.6.5 andes.core.var.ExtState . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
3.6.6 andes.core.var.ExtAlgeb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329
3.6.7 andes.core.var.AliasState . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
3.6.8 andes.core.var.AliasAlgeb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334
3.6.9 Variable, Equation and Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
3.6.10 Value and Equation Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
3.6.11 Values Between DAE and Models . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
3.6.12 Flags for Value Overwriting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
3.6.13 A v_setter Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
3.7 Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
3.7.1 andes.core.service.BaseService . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
3.7.2 andes.core.service.OperationService . . . . . . . . . . . . . . . . . . . . . . . . . 341
3.7.3 Internal Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343
3.7.4 External Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345
3.7.5 Shape Manipulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
3.7.6 Value Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
3.7.7 Idx and References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
3.7.8 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
3.7.9 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354
3.7.10 Data Select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
3.7.11 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356
3.8 Discrete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
3.8.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
3.8.2 Limiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
3.8.3 Comparers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
3.8.4 Deadband . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366
3.8.5 Others . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
3.9 Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
3.9.1 Background . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369
3.9.2 Transfer Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
3.9.3 Saturation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389
3.9.4 Naming Convention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
3.10 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
3.10.1 TGOV1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
3.10.2 IEEEST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
iv
4 Release notes 399
4.1 v1.8 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
4.1.1 v1.8.10 (2023-08-10) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
4.1.2 v1.8.9 (2023-06-22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
4.1.3 v1.8.8 (2023-04-24) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399
4.1.4 v1.8.7 (2023-03-10) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.5 v1.8.6 (2023-02-13) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.6 v1.8.5 (2022-12-22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.7 v1.8.4 (2022-11-23) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.8 v1.8.3 (2022-11-15) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.9 v1.8.2 (2022-10-30) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400
4.1.10 v1.8.1 (2022-09-24) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
4.1.11 v1.8.0 (2022-08-30) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
4.2 v1.7 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
4.2.1 v1.7.8 (2022-08-24) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
4.2.2 v1.7.7 (2022-08-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
4.2.3 v1.7.6 (2022-07-11) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
4.2.4 v1.7.5 (2022-07-05) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
4.2.5 v1.7.4 (2022-07-01) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
4.2.6 v1.7.3 (2022-06-25) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
4.2.7 v1.7.2 (2022-06-07) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402
4.2.8 v1.7.1 (2022-05-31) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
4.2.9 v1.7.0 (2022-05-22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
4.3 v1.6 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
4.3.1 v1.6.6 (2022-04-30) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
4.3.2 v1.6.5 (2022-04-19) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
4.3.3 v1.6.4 (2022-04-17) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404
4.3.4 v1.6.3 (2022-04-06) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
4.3.5 v1.6.2 (2022-03-27) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
4.3.6 v1.6.1 (2022-03-13) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
4.3.7 v1.6.0 (2022-03-11) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
4.4 v1.5 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
4.4.1 v1.5.12 (2022-03-05) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
4.4.2 v1.5.11 (2022-02-23) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
4.4.3 v1.5.10 (2022-02-01) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
4.4.4 v1.5.9 (2022-01-31) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406
4.4.5 v1.5.8 (2021-12-21) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
4.4.6 v1.5.7 (2021-12-11) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
4.4.7 v1.5.6 (2021-11-25) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.4.8 v1.5.5 (2021-11-13) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.4.9 v1.5.4 (2021-11-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.4.10 v1.5.3 (2021-10-31) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.4.11 v1.5.2 (2021-10-27) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
4.4.12 v1.5.1 (2021-10-23) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
4.4.13 v1.5.0 (2021-10-13) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
4.5 v1.4 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
4.5.1 v1.4.4 (2021-10-05) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409
4.5.2 v1.4.3 (2021-09-25) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
v
4.5.3 v1.4.2 (2021-09-12) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
4.5.4 v1.4.1 (2021-09-12) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
4.5.5 v1.4.0 (2021-09-08) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
4.6 v1.3 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
4.6.1 v1.3.12 (2021-08-22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
4.6.2 v1.3.11 (2021-07-27) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
4.6.3 v1.3.10 (2021-06-08) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
4.6.4 v1.3.9 (2021-06-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
4.6.5 v1.3.8 (2021-06-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
4.6.6 v1.3.7 (2021-05-03) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411
4.6.7 v1.3.6 (2021-04-23) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.6.8 v1.3.5 (2021-03-20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.6.9 v1.3.4 (2021-03-13) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.6.10 v1.3.2 (2021-03-08) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.6.11 v1.3.1 (2021-03-07) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.6.12 v1.3.0 (2021-02-20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
4.7 v1.2 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
4.7.1 v1.2.9 (2021-01-16) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
4.7.2 v1.2.7 (2020-12-08) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
4.7.3 v1.2.6 (2020-12-01) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
4.7.4 v1.2.5 (2020-11-19) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
4.7.5 v1.2.4 (2020-11-13) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
4.7.6 v1.2.3 (2020-11-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
4.7.7 v1.2.2 (2020-11-01) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
4.7.8 v1.2.1 (2020-10-11) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
4.7.9 v1.2.0 (2020-10-10) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
4.8 v1.1 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.8.1 v1.1.5 (2020-10-08) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.8.2 v1.1.4 (2020-09-22) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.8.3 v1.1.3 (2020-09-05) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.8.4 v1.1.2 (2020-09-03) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415
4.8.5 v1.1.1 (2020-09-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
4.8.6 v1.1.0 (2020-09-01) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
4.9 v1.0 Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
4.9.1 v1.0.8 (2020-07-29) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
4.9.2 v1.0.7 (2020-07-18) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
4.9.3 v1.0.6 (2020-07-08) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
4.9.4 v1.0.5 (2020-07-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
4.9.5 v1.0.4 (2020-06-26) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
4.9.6 v1.0.3 (2020-06-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.9.7 v1.0.2 (2020-06-01) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.9.8 v1.0.1 (2020-05-27) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.9.9 v1.0.0 (2020-05-25) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.10 Pre-v1.0.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.10.1 v0.9.4 (2020-05-20) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418
4.10.2 v0.9.3 (2020-05-05) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
4.10.3 v0.9.1 (2020-05-02) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
4.10.4 v0.8.8 (2020-04-28) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
vi
4.10.5 v0.8.7 (2020-04-28) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
4.10.6 v0.8.6 (2020-04-21) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
4.10.7 v0.8.5 (2020-04-17) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
4.10.8 v0.8.4 (2020-04-07) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
4.10.9 v0.8.3 (2020-03-25) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
4.10.10 v0.8.0 (2020-02-12) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
4.10.11 v0.6.9 (2020-02-12) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
vii
5.12.2 IEEEX1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501
5.12.3 ESDC1A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
5.12.4 ESDC2A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
5.12.5 EXST1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
5.12.6 ESST3A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520
5.12.7 SEXS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527
5.12.8 IEEET1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
5.12.9 EXAC1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534
5.12.10 EXAC2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
5.12.11 EXAC4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547
5.12.12 ESST4B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551
5.12.13 AC8B . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
5.12.14 IEEET3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563
5.12.15 ESAC1A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 567
5.12.16 ESST1A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 574
5.12.17 ESAC5A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
5.13 Experimental . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
5.14 FreqMeasurement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
5.14.1 BusFreq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
5.14.2 BusROCOF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 589
5.15 Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
5.15.1 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
5.16 Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
5.16.1 Fortescue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
5.17 Motor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
5.17.1 Motor3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 595
5.17.2 Motor5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 598
5.18 OutputSelect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
5.18.1 Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
5.19 PLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
5.19.1 PLL1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
5.19.2 PLL2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 604
5.20 PSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
5.20.1 IEEEST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
5.20.2 ST2CUT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 612
5.21 PhasorMeasurement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
5.21.1 PMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 617
5.22 RenAerodynamics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
5.22.1 WTARA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
5.22.2 WTARV1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 619
5.23 RenExciter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
5.23.1 REECA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 621
5.23.2 REECA1E . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 629
5.23.3 REECA1G . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637
5.24 RenGen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
5.24.1 REGCA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
5.24.2 REGCP1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 650
5.24.3 REGCV1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 656
viii
5.24.4 REGCV2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 661
5.24.5 REGF1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 666
5.24.6 REGF2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
5.24.7 REGF3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 677
5.25 RenGovernor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684
5.25.1 WTDTA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 684
5.25.2 WTDS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 687
5.26 RenPitch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
5.26.1 WTPTA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 689
5.27 RenPlant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692
5.27.1 REPCA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 693
5.28 RenTorque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
5.28.1 WTTQA1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 699
5.29 StaticACDC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
5.29.1 VSCShunt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 704
5.30 StaticGen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 707
5.30.1 PV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 708
5.30.2 Slack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
5.31 StaticLoad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
5.31.1 PQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 712
5.32 StaticShunt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
5.32.1 Shunt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
5.32.2 ShuntTD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 716
5.32.3 ShuntSw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 718
5.33 SynGen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
5.33.1 GENCLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 720
5.33.2 GENROU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 724
5.33.3 PLBVFU1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 730
5.34 TimedEvent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
5.34.1 Toggle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 733
5.34.2 Fault . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 734
5.34.3 Alter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 736
5.35 TurbineGov . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737
5.35.1 TG2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 737
5.35.2 TGOV1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 740
5.35.3 TGOV1DB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 743
5.35.4 TGOV1N . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 745
5.35.5 TGOV1NDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 749
5.35.6 IEEEG1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 751
5.35.7 IEESGO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 756
5.35.8 GAST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 759
5.35.9 HYGOV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 762
5.35.10 HYGOVDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 766
5.35.11 HYGOV4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 770
5.36 Undefined . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774
5.37 VoltComp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 774
5.37.1 IEEEVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 775
ix
6 API reference 777
6.1 System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 777
6.1.1 andes.system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 777
6.1.2 andes.variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 794
6.2 Routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 807
6.2.1 andes.routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 808
6.3 Plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 828
6.3.1 andes.plot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 829
6.4 I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
6.4.1 andes.io . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 839
6.5 Interoperability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850
6.5.1 andes.interop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 850
6.6 Others . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 858
6.6.1 andes.cli . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859
6.6.2 andes.main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 859
6.6.3 andes.utils.paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 865
6.6.4 andes.utils.snapshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 870
6.6.5 andes.utils.widgets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 871
Bibliography 873
Index 877
x
ANDES Manual, Release 1.8.10
Download documentation: PDF for stable version | PDF for development version
Useful Links: Binary Installer | Source Repository | Report Issues | Q&A | Try in Jupyter Notebooks | LTB
Repository
LTB ANDES is an open-source Python library for power system modeling, computation, analysis, and control,
serving as the core simulation engine for the CURENT Large scale Testbed (LTB). It supports power flows
calculation, transient stability simulation, and small-signal stability analysis for transmission systems. ANDES
implements a symbolic-numeric framework for rapid prototyping of differential-algebraic equation-based mod-
els. In this framework, a comprehensive library of models is developed, including the full second-generation
renewable models. Models in ANDES have been verified with commercial software.
Getting started
New to ANDES? Check out the getting started guides. They contain tutorials to the ANDES command-line
interface, scripting usages, as well as guides to configure ANDES and work with case files.
To the getting started guides
Examples
The examples provide in-depth usage of ANDES in a Python scripting environment. Advanced usage and and
power system studies are shown with explanation.
To the examples
Model development guide
Looking to implement new models, algorithms and functionalities in ANDES? The development guide provides
in-depth information on the design philosophy, data structure, and implementation of the hybrid symbolic-
numeric framework.
To the development guide
API reference
The API reference contains a detailed description of the ANDES package. The reference describes how the
methods work and which parameters can be used. It assumes that you have an understanding of the key con-
cepts.
To the API reference
Using ANDES for Research?
Please cite our paper [Cui2021] if ANDES is used in your research for publication.
ANDES MANUAL 1
ANDES Manual, Release 1.8.10
2 ANDES MANUAL
CHAPTER
ONE
GETTING STARTED
ANDES is an open-source Python package for power system modeling, computation, analysis and control.
It establishes a unique hybrid symbolic-numeric framework for modeling differential algebraic equations
(DAEs) for numerical analysis. Main features of ANDES include
• a unique hybrid symbolic-numeric approach to modeling and simulation that enables descriptive DAE
modeling and automatic numerical code generation
• a rich library of transfer functions and discontinuous components (including limiters, dead-bands, and
saturation) available for prototyping models, which can be readily instantiated as multiple devices for
system analysis
• industry-grade second-generation renewable models (solar PV, type 3 and type 4 wind), distributed PV
and energy storage model
• comes with the Newton method for power flow calculation, the implicit trapezoidal method for time-
domain simulation, and full eigenvalue calculation
• rigorously verified models with commercial software. ANDES obtains identical time-domain simulation
results for IEEE 14-bus and NPCC system with GENROU and multiple controller models. See the
verification link for details.
• developed with performance in mind. While written in Python, ANDES comes with a performance
package and can finish a 20-second transient simulation of a 2000-bus system in a few seconds on a
typical desktop computer
• out-of-the-box PSS/E raw and dyr file support for available models. Once a model is developed, inputs
from a dyr file can be readily supported
• an always up-to-date equation documentation of implemented models
ANDES is currently under active development. To get involved,
• Follow the tutorial at https://andes.readthedocs.io
• Checkout the Notebook examples in the examples folder
• Try ANDES in Jupyter Notebook with Binder
• Download the PDF manual at download
3
ANDES Manual, Release 1.8.10
1.2 Installation
Setting Up Mambaforge
If you are new to Python and want to get started quickly, you can use Mambaforge, which is a conda-like
package manager configured with conda-forge.
Step 1:
Downloaded the latest Mambaforge for your platform from https://github.com/conda-forge/miniforge#
mambaforge. Most users will use x86_64(amd64) for Intel and AMD processors. Mac users with Ap-
ple Silicon should use arm64(Apple Silicon) for best performance.
Next, complete the Mambaforge installation on your system.
Note: Mambaforge is a drop-in replacement for conda. If you have an existing conda installation, you can
replace all following mamba commands with conda and achieve the same functionality.
If you are using Anaconda or Miniconda on Windows, you should open Anaconda Prompt instead of
Miniforge Prompt.
Step 2:
Open Terminal (on Linux or maxOS) or Miniforge Prompt (on Windows, not cmd!!). Make sure you are in
a conda environment - you should see (base) prepended to the command-line prompt, such as (base)
C:\Users\username>.
Create an environment for ANDES (recommended)
Note: You will need to activate the andes environment every time in a new Miniforge Prompt or shell.
If these steps complete without error, you now have a working Python environment. See the commands at the
top to Getting started ANDES.
Some ANDES features require extra support packages, which are not installed by default. For example, to
build the documentation, one will need to install development packages. Other packages will be required for
interoperability.
The extra support packages are specified in groups. The following group names are supported, with descriptions
given below:
• dev: packages to support development such as testing and documentation
• interop: packages to support interoperability of ANDES and other power systems tools.
Note: Extra support packages are not supported by conda/mamba installation. One needs to install ANDES
with pip.
One can also inspect the requirements-extra.txt to identify the packages for manual installation.
The development mode installation is for users who want to modify the code and, for example, develop new
models or routines. The benefit of development mode installation is that changes to source code will be reflected
immediately without re-installation.
Step 1: Get ANDES source code
As a developer, you are strongly encouraged to clone the source code using git from either your fork or the
original repository. Clone the repository with
1.2. Installation 5
ANDES Manual, Release 1.8.10
Note: Replace the URL with yours to use your fork. With git, you can later easily update the source code
and perform version control.
Alternatively, you can download the ANDES source code from https://github.com/cuihantao/andes and extract
all files to the path of your choice. Although works, this method is discouraged because tracking changes and
pushing back code edits will require significant manual efforts.
Step 2: Install dependencies
In the Mambaforge environment, use cd to change directory to the ANDES root folder. The folder should
contain the setup.py file.
Install dependencies with
Note the dot at the end. Pip will take care of the rest.
Note: The ANDES version number shown in pip list will stuck at the version that was intalled, unless
ANDES is develop-installed again. It will not update automatically with git pull.
To check the latest version number, check the preamble by running the andes command or chek the output
of python -c "import andes; print(andes.__version__)"
Note: ANDES updates may infrequently introduce new package requirements. If you see an ImportError
after updating ANDES, you can manually install the missing dependencies or redo Step 2.
Note: To install extra support packages, one can append [NAME_OF_EXTRA] to pip install -e
.. For example, pip install -e .[interop] will install packages to support interoperability when
installing ANDES in the development, editable mode.
Warning: If ANDES has been installed in the development mode using source code, you will need to use
git or the manual approach to update the source code. In this case, Do not proceed with the following
steps, as they will install a separate site-package installation on top of the development one.
Regular ANDES updates will be pushed to both conda-forge and Python package index. It is recom-
mended to use the latest version for bug fixes and new features. We also recommended you to check the
Release notes before updating to stay informed of changes that might break your downstream code.
Depending you how you installed ANDES, you will use one of the following ways to upgrade.
If you installed it from mamba or conda, run
A common mistake new users make is to have multiple copies of ANDES installed in the same environment.
This can happen when one previously installed ANDES in the development mode but later ran conda in-
stall or python3 -m pip install to install the latest version. As a result, only the most recently
installed version will be accessible.
In this case, we recommend that you uninstall all version and reinstall only one copy using your preferred
mode. Uninstalling all copies can be done by calling conda remove andes and python3 -m pip
uninstall andes. The prompted path will indicate the copy to be removed. One may need to run the two
commands for a couple of time until the package managers indicate that the andes package can no longer be
found.
1.2.6 Troubleshooting
ImportError: DLL load failed: The specified module could not be found.
It is a path issue of your Python. In fact, Python on Windows is so broken that many people are resorting to
WSL2 just for Python. Fixes can be convoluted, but the easiest one is to install ANDES in a Conda/Mambaforge
environment.
1.2. Installation 7
ANDES Manual, Release 1.8.10
1.3 Tutorial
ANDES can be used as a command-line tool or a library. The command-line interface (CLI) comes handy to
run studies. As a library, it can be used interactively in the IPython shell or the Jupyter Notebook. This chapter
describes the most common usages.
Please see the CLI cheatsheet if you are looking for quick help.
Basics
ANDES is invoked from the command line using the command andes. Running andes without any input is
equal to andes -h or andes --help. It prints out a preamble with version and environment information,
followed by and help commands
_ _ | Version 1.6.0
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 03/12/2022 10:30:44 AM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
positional arguments:
{run,plot,doc,misc,prepare,prep,selftest,st,demo}
[run] run simulation routine; [plot] plot
results; [doc] quick documentation; [misc] misc.
functions; [prepare] prepare the numerical code;
[selftest] run self test;
optional arguments:
-h, --help show this help message and exit
-v {1,10,20,30,40}, --verbose {1,10,20,30,40}
Verbosity level in 10-DEBUG, 20-INFO, 30-WARNING,
or 40-ERROR.
andes accepts an optional arugment to control verbosity level. It is done through -v LEVEL or --verbose
LEVEL, where level is a number. Logging level by default is 20 (INFO) and can be chosen from:
• 1 (DEBUG with code location info)
• 10 (DEBUG)
• 20 (INFO)
• 30 (WARNING)
• 40 (ERROR)
• 50 (CRITICAL)
To show debugging outputs, use andes -v 10, followed by top-level commands. To only show warnings
and errors, use andes -v 30.
The top-level commands are {run,plot,doc,misc,prepare,selftest}. Each command contains
a group of subcommands, which can be looked up with -h. For example, use andes run -h to look up
the subcommands for andes run. Frequently used commands are explained below.
andes selftest
After the installation, please run andes selftest from the command line to test ANDES functionality. It
might take a minute to run the full self-test suite. An example output looks like
OK
There may be more test than what is shown above. Make sure that all tests have passed.
ANDES receives frequent updates. After each update, please run andes st to confirm the functionality. The
command also makes sure the generated code is up to date. See andes prepare for more details on automatic
code generation.
Note: There is a quick mode to test ANDES by skipping code generation. This should only be used when you
are certain that there is no modification to models between the last code generation and now.
The quick mode is invoked by andes st -q.
1.3. Tutorial 9
ANDES Manual, Release 1.8.10
andes prepare
The symbolically defined models in ANDES need to be generated into numerical code for simulation. The
code generation process is automatic the first time you use ANDES to run any case study. It takes 10 seconds
to one minute to generate the code depending on your platform. When done, no code generation is needed in
your future use untill you modify the models.
It is also possible to generate the code manually with andes prepare or andes prep. In addition,
andes selftest automatically calls the code generation.
Note: Generated code files are stored in Python code in $HOME/.andes/pycode. While being human-
readable, they are not human-friendly and should only be consulted during low-level debugging.
The default code generation mode is known as the "quick mode". It skips the generation of LATEX-formatted
equations, which are only useful in documentation and the interactive mode.
Option -i or --incremental can be used to speed up code generation during model development. andes
prepare -i only generates code for models that are detected with changes since the last code generation.
Warning: To developers:
andes prepare -i needs to be called following model changes, such as equation modification and
adding variables. Otherwise, due to mismatches in model and code, simulation results will not reflect the
new changes, at best, or even lead to unexpected errors
ANDES supports precompiling the generated Python code using Numba. See Numba compilation. Numba
needs to be installed separately. Check the version of installed numba and other dependencies with andes
misc --version.
andes run
andes run is the entry point for power system analysis routines. The full list of options can be printed
with andes run -h. andes run takes one positional argument, filename, along with other optional
keyword arguments. filename is the path to cases, either relative or absolute.
• Relative path: andes run kundur_full.xlsx, e.g., uses a relative path. It works only if
kundur_full.xlsx exists in the working directory of the command line.
• Absolute path: andes run /Users/hcui7/kundur_full.xlsx (on macOS) or andes
run C:/Users/hcui7/kundur_full.xlsx (on Windows) use absolute paths to the case files.
They do not depend on the command-line current directory.
Note: When working with the command line, use cd to change directory to the folder containing your test
case. Spaces in folder and file names need to be escaped properly, so it's generally advised to avoid spaces in
file and folder names.
To find out your current working directory, look for the line below the ANDES preamble that reads like
Input path
ANDES allows one to specify the path to look for the case file instead of the working directory. This is done
by using the -p or --input-path option. For example, if kundur_full.xlsx is in folder /home/
hacui/cases, one can do
The argument passed to -p or --input-path can also be a relative path. If you need further help under-
standing paths, please consult other online articles.
Multiprocessing
ANDES takes multiple files inputs or wildcard. Multiprocessing will be triggered if more than one valid input
files are passed to filename.
• Multiple files: to run the power flow for kundur_full.xlsx and kundur_motor.xlsx simul-
taneously, one can do
• Wildcard: to run power flow for files with a prefix of kundur_ and a suffix (file extension) of .xlsx,
run
Case files with such name pattern, including kundur_full.xlsx and kundur_motor.xlsx, among
others, will be processed.
Option --ncpu NCPU can be used to specify the maximum number of parallel processes. By default, all
cores will be used. A small number can be specified to increase operating system responsiveness.
1.3. Tutorial 11
ANDES Manual, Release 1.8.10
Routine
Option -r or -routine is used for specifying the analysis routine, followed by the routine name. Available
routine names include
• pflow for power flow calculation
• tds for time domain simulation
• eig for eigenvalue analysis
If -r is not given, the power flow calculation routine will be called. There are routine specific options that can
be passed to andes run and are discussed next.
Each routine has a list of configuration options (called "config") to control their behaviors. Config needs to be
distinguished from command-line options as not all config options are available in the command-line. Refer to
Config for details.
Power flow
Note: Examples in the following will utilize the kundur_full.xlsx test case. If you have cloned the
ANDES repository, it can be found in andes/cases/kundur in the source code folder. You can also
download it from here.
To run power flow, change to the directory containing kundur_full.xlsx, and execute the following in
the command line:
Alternatively, the full path to the case file is also recognizable, such as
The power flow report will be saved to the current directory where ANDES is invoked. The report contains
four sections:
1) system statistics,
2) ac bus and dc node data
3) ac line data, and
4) results of other algebraic variables and state variables.
By default, the power flow routine is configured to use full Newton Raphson method, and reactive power limits
are not checked. To change these config, edit the config file by referring to andes doc PFlow and andes
doc PV.
Following power flow, ANDES does not initialize dynamic models to save time. When developing dynamic
models, one can enable the initialization by setting in the config file
[PFlow]
init_tds = 1
Time-domain simulation
The output contains the key information for the simulation, such as solver name and step size. It prints out the
disturbance information, the trip of Line Line_8 at time t=2.0 sec.
There are a few places needing to be noted:
1.3. Tutorial 13
ANDES Manual, Release 1.8.10
1. Make sure the power flow calculation is successful. Otherwise, there is no good starting point for dynamic
simulation.
2. Make sure no suspect initialization error is found. Otherwise, the system will not be at steady state even
before disturbances.
TDS writes two output files: a variable list file kundur_full_out.lst, and a compressed NumPy data
file kundur_full_out.npz:
• List file: it is a plain-text file with three columns: variable indices, variable name in plain text, and
variable name in the LATEX format. The variable indices are needed to plot the needed variable.
• Data file: it is a zipped NumPy binary file. Although not directly editable, it can be used for plotting or
can be converted to a CSV file. See the subsection on andes plot.
There are TDS-specific options that can be passed to andes run:
• --tf TF: the final time of the simulation. TF should be a number in seconds. By default, it is set to
20.0.
• --addfile ADDFILE: specify an additional data file. This is currently used to supply PSS/E dyr file
in addition to a raw file.
• --flat: turn on "flat run" mode to ignore all disturbances. The simulation will be performed up to the
end time.
• --no-pbar: turn off progress bar.
• --from-csv FROM_CSV: use data from a CSV file to perform mock simulation. The CSV file should
be in the format of andes plot --to-csv.
Disable output
Output to files can be disabled with --no-output or -n. It is useful when computation is needed but results
can be discarded. It is also useful when results are processed in memory, combined with the --shell option
discussed next.
IPython shell
The ANDES CLI will exit to the system shell when finished running. It is sometimes useful to script in Python
to quickly process the simulation results in memory, such as plotting. ANDES can exit to the IPython shell
with --shell or -s. For example:
Note the -n is optional to disable file output. The terminal output will look like
In [1]:
A prompt will appear following In [1]: to indicate an IPython shell. If the test case file is parsed without
error, the system object will be stored in variable system, i.e.
In [1]: system
Out[1]: <andes.system.System at 0x7fc1cd992790>
Python commands can be executed thereafter. To exit, type exit and press enter.
Format converter
ANDES uses the Excel format to store power system data in the ANDES semantics. In addition, multiple input
formats are recognized and can be converted to the ANDES xlsx format. Converting data into the ANDES
has pros and cons:
• Pros: - The data can be readily edited with an Excel-like tool - Data for models unique to ANDES can
be readily added to the xlsx file
• Cons: - Conversion from ANDES xlsx back to the original format is not supported
Note: It is recommended to stay with the original data format to maximize compatibility when no ANDES-
specific models are used.
Format conversion is done through --convert FORMAT or -c FORMAT, where FORMAT is the output
format. For now, the following formats are supported:
• xlsx: an Excel spread sheet format with ANDES-specific data. It is not compatible with xlsx with
datafrom other tools such as Pandapower.
• json: a JSON plain-text file with ANDES-specific data. Likewise, it is unlikely to be compatible with
JSON from other power system tools. JSON is much faster to parse than xlsx but not as friendly to
edit.
To convert kundur_full.xlsx, for example, to the json format, run
1.3. Tutorial 15
ANDES Manual, Release 1.8.10
Note that --convert will only create sheets for existing models.
The converter works with any input formats that are currently supported. These include:
• .m: MATPOWER case file
• .raw and .dyr: PSS/E raw and dyr files
• .xlsx: Excel spreadsheet file with ANDES data
• .json: JSON plain-text file with ANDES data
PSS/E inputs
To work with PSS/E input files (.raw and .dyr), one need to provide the raw file through casefile and pass
the dyr file through --addfile. For example, in andes/cases/kundur, one can run the power flow
using
Note: If one wants to modify the parameters of models that are supported by both PSS/E and ANDES, one
can directly edit those dynamic parameters in the .raw and .dyr files to maintain interoperability with other
tools.
To create add a disturbance, there are two options. The recommended option is to convert the PSS/E data into
an ANDES xlsx file, edit it and run (see the previous subsection). The alternative approach is documented in
Creating disturbances.
Profiling
Profiling is useful for analyzing the computation time and code efficiency. Option --profile enables the
profiling of ANDES execution. The profiling output will be written in two files in the current folder, one ending
with _prof.txt and the other one with _prof.prof.
The text file can be opened with a text editor, and the .prof file can be visualized with snakeviz, which
can be installed with pip install snakeviz.
If the output is disabled, profiling results will be printed to stdio.
andes plot
andes plot is the command-line tool for plotting. It currently supports time-domain simulation data. Three
positional arguments are required, and a dozen of optional arguments are supported.
positional arguments:
Argu- Description
ment
filename simulation output file name, which should end with out. File extension can be
omitted.
x the X-axis variable index, typically 0 for Time
y Y-axis variable indices. Space-separated indices or a colon-separated range is
accepted
For the list of optional arguments, see the output of andes plot -h.
To plot the generator speed variable omega of GENROU_1 omega GENROU 1 versus time, one way is to
supply the variable indices found in the .lst output file. The index of the variable omega GENROU 1 is
found to be 5, and Time is found to be 0, so the plot command should be
where kundur_full_out.lst is list file name, 0 is the index of Time for the x-axis, and 5 is the
index of omega GENROU 1. Note that for the the file name, either kundur_full_out.lst or
kundur_full_out.npz works as the program will automatically extract the file name.
The y-axis variable indices can also be specified as a Python range. For example, andes plot
kundur_full_out.npz 0 2:21:6 will plot the variables with indices 2, 8, 14 and 20.
It can become tedious to look up the indices of variables in the .lst file. andes plot supports --xargs
or -a for searching for variable indices and passing them as arguments to andes plot. See Examples -
"Using CLI from Notebook".
LaTeX rendering
andes plot will attempt to render with LATEX if dvipng program is in the search path. Figures rendered
by LATEX has publication-quality aesthetics for symbols but takes considerably longer time. In case LATEX is
available but fails (frequently happens on Windows), the option -d can be used to disable LATEX rendering.
1.3. Tutorial 17
ANDES Manual, Release 1.8.10
andes doc
andes doc is a handy tool to look up model, routine and config documentation. Model documentation
include the descriptions of parameters, variables, and configs. A pretty-print version is available online in
Model reference.
The basic usage of andes doc is to provide a model name or a routine name as the positional argument. For
a model, it will print out model parameters, variables, and equations to the stdio. For a routine, it will print out
fields in the Config file.
Parameters
| status | | | |
Group | Models
-----------------+-------------------------------------------
ACLine | Line
ACTopology | Bus
Collection | Area
DCLink | Ground, R, L, C, RCp, RCs, RLs, RLCs, RLCp
DCTopology | Node
Exciter | EXDC2
Experimental | PI2
FreqMeasurement | BusFreq, BusROCOF
(continues on next page)
andes misc
andes misc contains miscellaneous functions, such as configuration and output cleaning.
Configuration
ANDES uses a configuration file to set runtime configs for the system routines, and models. andes misc
--save-config saves all configs to a file. By default, it saves to $HOME/.andes/andes.conf file,
where $HOME is the path to your home directory.
With andes misc --edit-config, you can edit ANDES configuration handy. The command will
automatically save the configuration to the default location if not exist. The shorter version --edit can be
used instead as Python matches it with --edit-config.
You can pass an editor name to --edit, such as --edit vim. If the editor name is not provided, it will use
the following defaults: - Microsoft Windows: notepad. - GNU/Linux: the $EDITOR environment variable, or
vim if not exist.
For macOS users, the default is vim. If not familiar with vim, you can use nano with --edit nano or
TextEdit with --edit "open -a TextEdit".
1.3. Tutorial 19
ANDES Manual, Release 1.8.10
Cleanup
Version
Check the version of ANDES and the core packages it uses, use
1.3.2 Scripting
This section is a tutorial for using ANDES in an interactive/scripting environment. All scripting shells are
supported, including Python shell, IPython, Jupyter Notebook and Jupyter Lab. The examples below uses
Jupyter Notebook.
Jupyter Notebook
Jupyter notebook is a convenient tool to run Python code and present results. Jupyter notebook can be installed
with
After the installation, change directory to the folder where you wish to store notebooks, then start the notebook
with
jupyter notebook
A browser window should open automatically with the notebook browser loaded. To create a new notebook,
use the "New" button near the upper-right corner.
Note: In the following, code that starts with >>> are Python code. and should be run inside Python, IPython,
or Jupyter Notebook. Python code should not be entered into Anaconda Prompt or Linux shell.
Import
Like other Python libraries, ANDES needs to be imported into an interactive scripting Python environment.
Verbosity
If you are debugging ANDES, you can enable debug messages with
>>> andes.config_logger(stream_level=10)
or simply
>>> andes.config_logger(10)
The stream_level uses the same verbosity levels as for the command-line. If not explicitly enabled, the
default level 20 (INFO) will apply.
To set a new logging level for the current session, call config_logger with the desired new levels.
Making a System
Before running studies, an andes.system.System object needs to be create to hold the system data. The
System object can be created by passing the path to the case file the entry-point function.
There are multiple ways to create such object, and andes.main.run is the most convenient way. For
example, to run the file kundur_full.xlsx in the same directory as the notebook, use
>>> ss = andes.run('kundur_full.xlsx')
This function will parse the input file, run the power flow, and return the system as an object. Outputs will look
like
In this example, ss is an instance of andes.System. It contains member attributes for models, routines,
and numerical DAE.
1.3. Tutorial 21
ANDES Manual, Release 1.8.10
Note: andes.main.run can accept multiple input files for multiprocessing. They can be passed as a list
of strings to the first positional argument.
Passing options
andes.run() can accept options that are available to the command-line andes run. Options need to be
passed as keyword arguments to andes.run() in addition to the positional argument for the test case. For
example, setting no_output to True will disable all file outputs. When scripting, one can do
Please note that the dash between no and output needs to be replaced with an underscore for scripting. This
is the convention in Python's argument parser.
Another example is to specify a folder for output files. By default, outputs will be saved to the folder where
Python is run (or where the notebook is run). In case you need to organize outputs, a path prefix can be passed
to andes.run() through output_path:
which will put outputs into folder outputs relative to the current path. You can also supply an absolute path
to output_path.
The next example is to specify the simulation time for a time-domain simulation. There are multiple ways to
implement it (see Examples), and one way is to pass the end time (in sec) through argument tf and set the
routine to tds:
Note: While andes run accepts single-letter alias for the option, such as andes run -n for andes
run --no-output, andes.run() can only work with the full option name (with hyphen replaced by
underscore)
Load Only
In many workflows, one will simulate many scenarios with largely identical system data. A base case can be
loaded and modified to create scenarios in memory. See Example "Working with Data" for details
Inspecting Parameter
DataFrame
Parameters for the loaded system can be readily inspected in Jupyter Notebook using Pandas.
Parameters for a model instance can be retrieved in a DataFrame using the as_df() method on the model
instance. For example, to view the parameters of Bus, use
>>> ss.Bus.as_df()
A table will be printed with the columns being parameters and the rows being Bus devices/instances. For a
system that has been setup, parameters have been converted to per unit values in the system base specified by
ss.config.mva. The per-unit values in the system base will be used in computation as all computation in
ANDES uses system-base per-unit data.
To view the original input values, use the as_df(vin=True) method. For example, to view the system-base
per unit value of GENROU, use
>>> ss.GENROU.as_df(vin=True)
Parameter in the table is the same as that in the input file without any conversion. Some input data, by conven-
tion, are given as per unit in the device base; see Per Unit System for details.
Note that andes.core.modeldata.ModelData.as_df() returns a view. Modifying the returned
dataframe will not affect the original data used for simulation. To modify the data, see Example "Working with
Data".
Running Studies
Three routines are currently supported: PFlow, TDS and EIG. Each routine provides a run() method to
execute. The System instance contains member attributes having the same names. For example, to run the
time-domain simulation for ss, use
>>> ss.TDS.run()
To change configuration for routines, one can set the attribute before calling run. For example, to change the
end time to 5 sec, one can do
1.3. Tutorial 23
ANDES Manual, Release 1.8.10
>>> ss.TDS.config.tf = 5
>>> ss.TDS.run()
Note that not all config changes are respected. Some config values are used while creating the routine instance.
For config changes that does not necessarily have to be done on-the-fly, it is recommended to edit the config
file.
andes.System contains field exit_code for checking if error occurred in run time. A normal completion
without error should always have exit_code == 0. One should read output messages carefully and check
the exit code, which is particularly useful for batch simulations.
Error may occur in any phase - data parsing, power flow, or simulation. To diagnose, split the simulation steps
and check the outputs from each one.
TDS comes with a plotting utility for scripting usage. After running the simulation, a plotter attributed will
be created for TDS. To use the plotter, provide the attribute instance of the variable to plot. For example, to
plot all the generator speed, use
>>> ss.TDS.plotter.plot(ss.GENROU.omega)
>>> ss.TDS.load_plotter()
Optional indices is accepted to choose the specific elements to plot. It can be passed as a tuple through the a
argument
In the above example, the speed of the "zero-th" generator will be plotted.
Scaling
A lambda function can be passed to argument ycalc to scale the values. This is useful to convert a per-unit
variable to nominal. For example, to plot generator speed in Hertz, use
Formatting
Extracting Data
One can extract data from ANDES for custom plotting. Variable names can be extracted from the following
fields of ss.dae:
Un-formatted names (non-LaTeX):
• x_name: state variable names
• y_name: algebraic variable names
• xy_name: state variable names followed by algebraic ones
LaTeX-formatted names:
• x_tex_name: state variable names
• y_tex_name: algebraic variable names
• xy_tex_name: state variable names followed by algebraic ones
These lists only contain the variable names used in the current analysis routine. If you only ran power flow,
ss.dae.y_name will only contain the power flow algebraic variables, and ss.dae.x_name will likely be
empty. After initializing time-domain simulation, these lists will be extended to include all variables used by
TDS.
In case you want to extract the discontinuous flags from TDS, you can set store_z to 1 in the config file
under section [TDS]. When enabled, discontinuous flag names will be populated at
• ss.dae.z_name: discontinuous flag names
• ss.dae.z_tex_name: LaTeX-formatted discontinuous flag names
If not enabled, both lists will be empty.
1.3. Tutorial 25
ANDES Manual, Release 1.8.10
The full power flow solutions are stored at ss.dae.xy after running power flow (and before initializing
dynamic models). You can extract values from ss.dae.xy, which corresponds to the names in ss.dae.
xy_name or ss.dae.xy_tex_name.
If you want to extract variables from a particular model, for example, bus voltages, you can directly access the
v field of that variable
which stores a copy of the bus voltage values. Note that the first v is the voltage variable of Bus, and the
second v stands for value. It is important to make a copy by using np.array() to avoid accidental changes
to the solutions.
If you want to extract bus voltage phase angles, do
Time-domain data
Time-domain simulation data will be ready when simulation completes. It is stored in ss.dae.ts, which
has the following fields:
• txyz: a two-dimensional array. The first column is time stamps, and the following are variables. Each
row contains all variables for that time step.
• t: all time stamps.
• x: all state variables (one column per variable).
• y: all algebraic variables (one column per variable).
• z: all discontinuous flags (if enabled, one column per flag).
If you want the output in pandas DataFrame, call
ss.dae.ts.unpack(df=True)
Note: Looking to extract data for a single variable? See Examples - "Working with Data".
Each ANDES models offers pretty print of LATEX-formatted equations in the jupyter notebook environment.
To use this feature, symbolic equations need to be generated in the current session using
This process may take a few minutes to complete. To save time, you can selectively generate it only for interested
models. For example, to generate for the classical generator model GENCLS, do
Note: Pretty print only works for the particular System instance whose prepare() method is called. In
the above example, pretty print only works for ss after calling prepare().
1.3. Tutorial 27
ANDES Manual, Release 1.8.10
Finding Help
docstring
To find out how a Python class, method, or function should be used, use the built-in help() function. This will
print out the docstring of the class/method/function. For example, to check how the get method of GENROU
should be called, do
help(ss.GENROU.get)
Model docs
Model docs can be shown by printing the return of doc(). For example, to check the docs of GENCLS, do
print(ss.GENCLS.doc())
It is the same as calling andes doc GENCLS from the command line. Likewise, a pretty-print version is
available online in Model reference.
1.3.3 Cheatsheet
1.3.4 Documentation
The documentation you are viewing can be made locally in a variety of formats. To make HTML documenta-
tion, change directory to docs, and do
make html
After a few minutes, HTML documentation will be saved to docs/build/html with the index page being
index.html. You can use Python to serve it locally. In the folder docs/build/html, run
python -m http.server
A list of supported formats is as follows. Note that some format require additional compiler or library
1.4 Config
ANDES uses a config file to store the various options for routines and models. As discussed in andes misc,
the config file is at $HOME/.andes/andes.rc. The reference for the config fields can be found in Config
reference.
1.4.1 Format
The ANDES config file uses the format provided by Python module configparser. The syntax is like the
following:
[System]
freq = 60
mva = 100
...
[PFlow]
sparselib = klu
linsolve = 0
tol = 1e-6
...
[TGOV1]
allow_adjust = 1
(continues on next page)
1.4. Config 29
ANDES Manual, Release 1.8.10
In the above, System, PFlow and TGOV1 are two sections. freq = 60, for example, is a pair of option
and value in the [System] section. Note the space before and after the equal sign.
The meaning of the fields in each section can be found in Config reference, which contains the default values
and acceptable values for each option. The values for config fields can be a string or a number. Fields with
acceptable values being (0, 1) can only accept 0 or 1 to indicate true or false. Non-binary values for such
options will cause unexpected errors in the program.
Limits in models
CLI
One can adjust config on the fly in command line without modifying or even storing the config file. This is useful
when the config change is one-time or ANDES CLI is stored in a read-only container. The config update is
done by andes run --config-option SECTION.OPTION=VALUE, where SECTION is the section
name, OPTION is the option name, and VALUE is the new value. No space is allowed around . and =.
For example, to solve kundur_full.json with reactive power limit enforced, one can do:
where -O is the shorhand command for --config-option, and the enabled pv2pq will allow PV to be
converted to PQ once reactive power limit is hit.
Multiple config updates can be passed simultaneously, separated by space. For example, to enable reactive
power limit and switch the power flow solver to UMFPACK, do:
Scripting
which directly calls the backend API for the CLI. To update multiple configs, one can do
>>> ss = andes.run("kundur_full.json",
config_option=["PV.pv2pq=1", "PFlow.sparselib=umfpack"])
When the System object gets created, the config values will be distributed to member attributes of the System
object. Therefore, the config for a System object ss is stored in ss.config, and the config for the power
flow routine is stored in ss.PFlow.config.
To update the config for an existing system, one can directly access the config attribute and set the new
value. To set a new simulation end time, one can overwrite the ss.TDS.config.tf field, such as:
Warning: Not all config options can be updated on the fly. Those config that are used for constructing
the system object can only be updated when creating a new System object.
1.4. Config 31
ANDES Manual, Release 1.8.10
System
PFlow
TDS
EIG
1.4. Config 33
ANDES Manual, Release 1.8.10
The ANDES xlsx format allows one to use Excel for convenient viewing and editing. If you do not use Excel,
there are alternatives such as the free and open-source LibreOffice.
Format definition
The ANDES xlsx format contains multiple workbooks (also known as "sheets") shown as tabs at the bottom.
The name of a workbook is a model name, and each workbook contains the parameters of all devices that are
instances of the model.
In each sheet, the first row contains the names of parameters of the model. Starting from the second row, each
row corresponds to a device instance with the parameters in the corresponding columns. An example of the
Bus sheet is shown in the following screenshot.
Common parameters
A few columns are used across all models. That includes uid, idx, name and u:
• uid is an unique index that is generated and used internally. This column can be left empty when the
sheet is being created manually. Exporting systems to xlsx with --convert (see Format converter)
will have the uid overwritten.
• idx is the unique index to identify a device of the model. An unique idx should be provided explicitly
for each instance for best consistency. Accepted types for idx include numbers and strings without
spaces.
Warning: ANDES will check the uniqueness of idx and assign new ones when duplication is detected.
Duplicate idx indicates data inconsistency and will likely cause simulations to fail.
• u is the connectivity status of the instance. Accepted values are 0 for disconnected (turned off) and 1 for
connected (turned on). Disconnected devices will still have the variables assigned in ANDES but will
not interact with the simulation. Unexpected behaviors may occur if numerical values other than 0 and
1 are assigned, as u is often used as a multiplier in equations.
• name is the name for the device instance. It is used for display purposes and can be left empty.
Connecting devices
Most importantly, idx is the unique index for referencing a device, so that it can be properly connected by
supported devices. In a system, a PQ (constant PQ load) device needs to connect to a Bus device to inject
power. That is, the PQ device needs to indicate the Bus device to which it is connected. Such connection is
done in the PQ sheet by setting the bus parameter to the idx of the connected bus.
Creating cases
It is often easier to modify from existing cases than creating from scratch. We recommend that you get familiar
with the cases available with ANDES, see Test Cases.
Adding devices
Adding devices to an existing workbook is straightforward. Navigate to the sheet corresponding to the model
and add a new line below the existing lines.
Almost all models have so-called mandatory parameters. They are essential to describe a complete and con-
sistent test case. For example, the PQ model has the bus parameter as mandatory to indicate the connected
bus. To look up mandatory parameters, see Model reference or use andes doc MODEL_NAME. Check for
"mandatory" in the last column called "Properties". This column also contains other data consistency require-
ments discussed in the following.
Non-mandatory parameters are optional, meaning that if not provided, ANDES will use the default parameters.
The default values can also be found in Model reference. This does not mean that such parameters should always
be left blank. For example, the p0 (active power load) of PQ is optional, but likely one wants to set it to a non-
zero value.
There are consistency requirements for parameters, such as non_zero, non_negative or
non_positive. If unmet, the default values will be used. See the class reference in andes.
core.param.NumParam.
Autofill data
When you finished adding devices but left some optional parameters empty, you can use ANDES to autofill
them. This is useful when you want to populate a large number of devices with the same parameters that can
be modified later.
The autofill is done through the data converter, namely, --convert or -c. ANDES will read in the Excel
file, fill the optional parameters with default values, fix the inconsistent values, and then export the data back
to Excel.
Warning: Please backup the spreadsheet if it contains customized edits. Inconsistent data will be re-
placed during the conversion. Formatting in the spreadsheet will be lost. Unrecognized sheets will also be
discarded.
To autofill kundur_full.xlsx, do
Adding workbooks
If one wants to add workbooks for models that does not exist in an xlsx file, one can use --add-book
ADD_BOOK (or -b ADD_BOOK), where ADD_BOOK can be a single model name or comma-separated model
names (without space). For example,
Warning: With --add-book, the xlsx file will be overwritten with the same parameter corrections as
in the autofill. Please make backups as needed.
Format conversion and workbook addition can be performed together. To convert a PSS/E raw file and a dyr
file into an xlsx file and add a workbook for Fault, do
The output will have the same name as the raw file.
Data Consistency
Input data needs to have consistent types for idx. Both string and numerical types are allowed for idx, but
the original type and the referencing type must be the same. Suppose we have a bus and a connected PQ. The
Bus device may use 1 or '1' as its idx, as long as the PQ device uses the same value for its bus parameter.
The ANDES xlsx reader will try to convert data into numerical types when possible. This is especially relevant
when the input idx is string literal of numbers, the exported file will have them converted to numbers. The
conversion does not affect the consistency of data.
Parameter Check
The following parameter checks are applied after converting input values to array:
• Any NaN values will raise a ValueError
• Any inf will be replaced with 108 , and -inf will be replaced with −108 .
The Siemens PSS/E data format is a widely used for power system simulation. PSS/E uses a variety of plain-text
files to store data for different actions. The RAW format (with file extension .raw) is used to store the steady-
state data for power flow analysis, and the DYR format (with extension .dyr) is used to store the parameters
of dynamic devices for transient simulation.
RAW Compatibility
ANDES supports PSS/E RAW in versions 32 and 33. Newer versions of raw files can store PSS/E settings
along with the system data, but such feature is not yet supported in ANDES. Also, manually edited raw files
can confuse the parser in ANDES. Following manual edits, it is strongly recommended to load the data into
PSS/E and save the case as a v33 RAW file.
ANDES supports most power flow models in PSS/E. It needs to be recognized that the power flow models in
PSS/E is is a larger set compared with those in ANDES. For example, switched shunts in PSS/E are converted
to fixed ones, not all three-winding transformer flags are supported, and HVDC devices are not yet converted.
This is not an exhaustive list, but all of them are advanced models.
We welcome contributions but please also reach out to us if you need to arrange the development of such
models.
DYR Compatibility
Fortunately, the DYR format does not have different versions yet. ANDES support reading parameters from
DYR files for models that have been implemented in ANDES. Owing to the descriptive modeling framework,
we implement the identical model so that parameters can be without conversion. If a dyr file contains models
that are not recognized by ANDES, an error will be thrown. One needs to manually remove those unsupported
models to load.
Like RAW files, manually edited DYR files can often be understood by PSS/E but may confuse the ANDES
parser. We also recommend to load and re-save the file using PSS/E.
Loading files
where --addfile or -a is used to specify the optional DYR file. For now, DYR files can only be added to
a RAW file. We will allow different formats to be mixed in the future.
Likewise, one can convert PSS/E files to ANDES xlsx:
This will convert all models in the RAW and DYR files. If only the RAW file is provided, only power flow
models will be converted. One cannot easily append those in a DYR file to an existing xlx file yet.
To load PSS/E files into a scripting environment, see Example - "Working with Data".
Creating disturbances
Instead of converting raw and dyr to xlsx before adding disturbances, one can edit the .dyr file with a
planin-text editor (such as Notepad) and append lines customized for ANDES models. This is for advanced
users after referring to andes/io/psse-dyr.yaml, at the end of which one can find the format of Tog-
gle:
To define two Toggles in the .dyr file, one can append lines to the end of the file using, for example,
which is separated by spaces and ended with a slash. The second parameter is fixed to the model name quoted
by a pair of single quotation marks, and the others correspond to the fields defined in the above inputs. Each
entry is properly terminated with a forward slash.
ANDES supporting parsing PSS/E dynamic files in the format of .dyr. Support new dynamic models can be
added by editing the input and output conversion definition file in andes/io/psse-dyr.yaml, which is
in the standard YAML format. To add support for a new dynamic model, it is recommended to start with an
existing model of similar functionality.
Consider a GENCLS entry in a dyr file. The entry looks like
where the fields are in the order of bus index, model name, generator index on the bus, inertia (H) and damping
coefficient (D).
The input-output conversion definition for GENCLS is as follows
GENCLS:
destination: GENCLS
inputs:
- BUS
- ID
- H
- D
find:
gen:
StaticGen:
bus: BUS
subidx: ID
get:
u:
StaticGen:
src: u
idx: gen
Sn:
StaticGen:
src: Sn
idx: gen
Vn:
Bus:
src: Vn
idx: BUS
ra:
StaticGen:
src: ra
idx: gen
xs:
StaticGen:
(continues on next page)
It begins with a base-level definition of the model name to be parsed from the dyr file, namely, GENCLS. Five
directives can be defined for each model: destination, inputs, outputs, find and get. Note that
find and get are optional, but the other three are mandatory.
• destination is ANDES model to which the original PSS/E model will be converted. In this case,
the ANDES model have the same name GENCLS.
• inputs is a list of the parameter names for the PSS/E data. Arbitrary names can be used, but it is
recommended to use the same notation following the PSS/E manual.
• outputs is a dictionary where the keys are the ANDES model parameter and the values are the input
parameter or lambda functions that processes the inputs (see notes below).
• find is a dictionary with the keys being the temporary parameter name to store the idx of external
devices and the values being the criteria to locate the devices. In the example above, GENCLS will try
to find the idx of StaticGen with bus == BUS and the subidx == ID, where BUS and ID
are from the dyr file.
• get is a dictionary with each key being a temporary parameter name for storing an external parameter
and each value being the criteria to find the external parameter. In the example above, a temporary
parameter u is the u parameter of StaticGen whose idx == gen. Note that gen is the idx of
StaticGen retrieved in the above find section.
For the inputs section, one will need to skip the model name because for any model, the second field is
always the model name. That is why for GENCLS below, we only list four input parameters.
For the outputs section, the order can be arbitrary, but it is recommended to follow the input order as much
as possible for maintainability. In particular, the right-hand-side of the outputs can be either an input parameter
name or an anonymous expression that processes the input parameters. For the example of GENCLS, since
ANDES internally uses the parameter of M = 2H, the input H needs to be multiplied by 2. It is done by the
following
where the left-hand-side is the output parameter name (destination ANDES model parameter name), and the
right-hand-side is arguments and the lambda function separated by semi-colon, all in a pair of double quotation
marks. Multiple arguments are accepted and should be separated by comma. Arguments can come from the
same model or another model. In the case of the same model, the model name can be neglected, namely, by
writing M: "H; lambda x: 2 * x".
1.5.3 MATPOWER
ANDES supports MATPOWER data in version 2 in part for power flow calculation. The following fields are
supported:
• mpc.busMVA
• mpc.bus
• mpc.gen
• mpc.branch
• mpc.area
• mpc.bus_name
Other fields are not supported, most notably, mpc.gencost.
Power flow calculation results for MATPOWER cases are typically identical to that from MATPOWER using
default settings. These settings include no reactive power limits and following all generator connectivity status.
Discrepencies in the power flow solution between ANDES and MATPOWER are typically due to configuration
issues or different interpretation of the data, rather than in the power flow models.
Overview
JSON is a portable format for storing data. It has been used in several other power system tools, including
PowerModels, Pandapower, NREL-SIIP, and GridCal. It must be noted that JSON files from these tools are
not interoperable because JSON only defines the data structure, not the meaning of data.
Compared with the xlsx file which is a zipped package, the ANDES JSON file is much faster to parse. We
recommend that you use JSON in the following scenarios:
• Your test case is stable and require no manual editing, or
• You will read/write a large number of cases
To convert kundur_full.xlsx to the ANDES JSON format, do
Data storage
The ANDES JSON format uses one large dictionary for all devices in the system. The keys of the dictionary
are the model names, and the values are lists of dictionaries. In each dictionary, the keys are the parameter
names and the values are the parameter values.
The following shows the structure of a JSON file:
{
"Toggle": [
{
"idx": 1,
"u": 1.0,
"name": "Toggle_1",
"model": "Line",
"dev": "Line_8",
"t": 2.0
} // <- Toggle_1 ends
], // <- Toggle model ends
"Bus": [
{
"idx": 1,
"u": 1.0,
"name": 1,
"Vn": 20.0,
"vmax": 1.1,
"vmin": 0.9,
... // <- other parameters are omitted
},
{
"idx": 2,
"u": 1.0,
"name": 2,
"Vn": 20.0,
"vmax": 1.1,
"vmin": 0.9,
... // <- other parameters are omitted
},
... // <- other buses
There are thirdparty tools for editing JSON files, but we still recommend to convert files to xlsx for editing.
The conversion can be readily done with
1.5.5 Disturbances
Disturbance Devices
Predefined disturbances at specified time can be created by adding the corresponding devices. Three types of
predefined disturbances are supported:
1. Three-phase-to-ground fault on buses. See Fault for details.
2. Connectivity status toggling. Disconnecting, connecting, or reconnecting any device, including lines,
generators and motors can be implemented by Toggle.
3. Alteration of values. See Alter for details.
To use these devices, the time of disturbance needs to be known ahead of the simulation. The simulation
program by default checks the network connectivity status after any disturbance.
Perturbation File
One can implement any custom disturbance using a perturbation file as discussed in [Milano2010]. The per-
turbation file is a Python script with a function named pert. The example for the perturbation file can be
found in andes/cases/ieee14/pert.py.
andes.cases.ieee14.pert.pert(t, system)
Perturbation function called at each step.
The function needs to be named pert and takes two positional arguments: t for the simulation time,
and system for the system object. Arbitrary logic and calculations can be applied in this function to
system.
If the perturbation event involves switching, such as disconnecting a line, one will need to set the
system.TDS.custom_event flag to True to trigger a system connectivity checking, and Jaco-
bian rebuilding and refactorization. To implement, add the following line to the scope where the event
is triggered:
system.TDS.custom_event = True
In other scopes of the code where events are not triggered, do not add the above line as it may cause
significant slow-down.
The perturbation file can be supplied to the CLI using the --pert argument or supplied to andes.
main.run() using the pert keyword.
Parameters
t [float] Simulation time.
system [andes.system.System] System object supplied by the simulator.
ANDES ships with with test cases in the andes/cases folder. The cases can be found in the online reposi-
tory.
1.6.1 Summary
Below is a summary of the folders and the corresponding test cases. Some folders contain a README file
with notes. When viewing the case folder on GitHub, one can conveniently read the README file below the
file listing.
• smib: single machine infinite bus (SMIB) system [Sauer].
• 5bus: a small PJM 5-bus test case for power flow study [PJM5].
• GBnetwork: a 2,000-bus system for the Great Britain network [GB]. Dynamic data is randomly gen-
erated.
• EI: the CURENT Eastern Interconnection network [EI].
• ieee14 and ieee39: the IEEE 14-bus and 39-bus test cases [IEEE].
• kundur: a modified Kundur's two area system from [RLGC]. The modified system is different in the
number of buses and lines from the textbook.
• matpower: a subset of test cases from [MATPOWER].
• nordic44: Nordpool 44-bus test case [Nordic]. Not all dynamic models are supported.
• npcc: the 140-bus Northeast Power Coordinating Council (NPCC) test case originated from Power
System Toolbox [PST].
• wecc: the 179-bus Western Electric Coordinating Council (WECC) test case [WECC].
• wscc: the 9-bus WSCC (succeeded by WECC) power flow data converted from [PSAT].
Note: Different systems exhibit different dynamics, thus the appropriate systems should be used to study
power system stability. For example:
• The Kundur's two-area system has under-damped modes and two coherent groups of generators. It is
suitable for oscillation study and transient stability studies.
• The WECC system is known for the inter-area oscillation.
• The IEEE 14-bus system and the 140-bus NPCC system is are frequently used for frequency control
studies. So is the Eastern Interconnection system.
Currently, the Kundur's 2-area system, IEEE 14-bus system, NPCC 140-bus system, and the WECC 179-bus
system has been verified against DSATools TSAT.
When developing models, we manually create cases with example data to verify the models. The Kundur's
system and the IEEE 14-bus system are used as the bases for adding specific models. One can find many cases
in the folder andes/cases/kundur. The case file names typically indicate the specific model added to the
file. These example cases with specific models are useful when one needs to find example parameters for the
model. For example:
• kundur_ieeeg1 indicates the use of IEEEG1 model in a Kundur's sytem
• ieee14_solar.xlsx contains the solar PV models (REGCA1, REECA1, and REPCA1)
• ieee14_plbvfu1.xlsx is the case for PLBVFU1 (playback of voltage and frequency). The case
provides an example of specifying plbvf.xlsx
• ieee14_timeseries.xlsx is an example for specifying timeseries for load data, which is provided
in pqts.xlsx
MATPOWER cases has been tested in ANDES for power flow calculation. All following cases are calculated
with the provided initial values using the full Newton-Raphson iterative approach.
Benchmark
Synthetic systems
The 70K and the USA synthetic systems have difficulties to converge using the provided initial values. One can
solve the case in MATPOWER and save it as a new case for ANDES. For example, the SyntheticUSA case
can be converted in MATLAB with
mpc = runpf(case_SyntheticUSA)
savecase('USA.m', mpc)
We welcome the contribution of test cases! You can make a pull request to contribute new test cases.
Please follow the structure in the cases folder and provide an example Jupyter notebook (see examples/
demonstration) to showcase the results of your system.
1.7 Performance
We discuss methods to improve the compuattional performance in ANDES using Numba. Performance bench-
marks are also presented.
In nearly all numerical simulation software, time is mostly spent on constructing the numerical system and
solving it. The construction of the DAE in ANDES involves the evaluation of functions from models that
implement the residuals and Jacobians.
Numba is a just-in-time compiler in Python that can turn numerical functions into compiled machine code.
In ANDES, it can speed up simulations by as much as 30%. The speedup is most effective in medium-sized
systems with multiple models. Such systems involve heavy function calls but rather moderate load for lin-
ear equation solvers. It is is less significant in large-scale systems where solving equations is the major time
consumer.
Note: Numba is supported since ANDES 1.5.0. One needs to manually install it with python -m pip
install numba from the Anaconda Prompt.
Numba needs to be enabled manually. In the ANDES config file: in section [System], set numba = 1, so
that it looks like
[System]
...
numba = 1
...
1.7. Performance 47
ANDES Manual, Release 1.8.10
where the ... are other options that are omitted here.
Just-in-time compilation will compile the code upon the first execution based on the input types. This is the
default mode of Numba. When compilation is triggered, ANDES may appear frozen due to the compilation
lag. To reuse the compiled code and save compilation time for future runs, the compiled binary code will be
automatically cached. The default cache folder is in $HOME/.andes/pydata/__pycache__ with file
extensions nbc and nbi
Numba compilation needs to be distinguished from the ANDES code generation by andes prepare. The AN-
DES code generation is to generate Python code from symbolically defined models and is relatively fast. The
Numba compilation further compiles the generated Python code to machine code. Whenever the ANDES code
generation produces new Python code, the cached Numba binary code will be invalidated.
when developing models, we recommend disabling numba to avoid spending time on compilation.
Ahead-of-time compilation
Just-in-time compilation can feel laggy. When ANDES is not being developed, one can compile the generated
Python code ahead of time to avoid just-in-time delays. We call it "precompilation".
Precompilation is invoked by
andes prep -c
It may take a minute for the first time. Owing to caching, future compilations will be incremental and much
faster.
The hardware platform is an AMD Ryzen 9 5950X with 64GB of 3200 MHz DDR4 RAM. The operating
system is WSL2 Ubunbu 20.04 on Windows 10. Software packages are:
• ANDES 1.5.3
• KVXOPT 1.2.7.1
• NumPy 1.20.3
• numba 0.54.1
• OpenBLAS 0.3.18.
Numba is enabled, and all generated code are precompiled. Network connectivity checking is turned off
([PFlow] check_conn=0). Time to read numba cache (~0.3s) is not included.
The table below shows the power flow time in ANDES. All the cases are original in MATPOWER 7.0, and cases
not listed below will not solve with ANDES 1.5.3. The computation time may vary depending on hardware,
operating system, and software.
1.7. Performance 49
ANDES Manual, Release 1.8.10
1.8 Verification
This section presents the verification of the models and algorithms implemented in ANDES by comparing the
time-domain simulation results with commercial tools.
ANDES produces identical results for the IEEE 14-bus and the NPCC systems with several models. For the
CURENT WECC system, ANDES, TSAT and PSS/E produce slightly different results. In fact, results from
different tools can hardly match for large systems with a variety of dynamic models.
Background
Two line trip scenarios are used to verify ANDES simulation results with DSATools TSAT.
Dynamic data is created to utilize the available models, including GENROU, TGOV1, IEEEG1, EXST2,
EXDC2, ESST3A, IEEEST and ST2CUT. Test case data can be found at the end of the notebook.
Simulation Parameters
Initialization
Power flow solutions are identical across all the two software.
GENROU initialization (EF D , ET ERM , P , Q, δ, Id and Iq ) is identical to that from PSS/E for all cases (with
and without generator saturation). Note that Id and Iq are in machine base in PSS/E but in system base in
ANDES.
GENROU initialization (including all the internal variables Ed′ , Eq′ , ψkd , ψkq , ψd′′ , and ψq′′ ) is identical to that
from OpenIPSL.
No controller limit violation occurs during initialization.
Conclusion
IEEE 14-bus system simulation results from ANDES are identical to that from TSAT.
import andes
import numpy as np
from andes.utils.tsat import tsat_to_df, plot_comparison, run_cmp
andes.config_logger(stream_level=30)
Scenario 1: Line 1-2 trips at 1 sec. and reconnects after 2.0 sec.
The reconnection delay is set to 2 seconds to trigger a large disturbance to the system to verify nonlinear models.
Simulation Setup
1.8. Verification 51
ANDES Manual, Release 1.8.10
Scenario 1 Plots
Scenario 2: Line 7-8 trips at 1 sec. and reconnects after 0.1 sec.
Line 7-8 is an equivalent branch in of the three-winding transformer. Tripping Line 7-8 will isolate Bus 8.
Simulation Setup
# line data
ss2.Line.cache.df.iloc[19]
idx Line_20
u 1
name Line_20
bus1 8
bus2 7
Sn 100
fn 60
Vn1 69
Vn2 138
(continues on next page)
1.8. Verification 53
ANDES Manual, Release 1.8.10
Scenario 2 Plots
1.8. Verification 55
ANDES Manual, Release 1.8.10
1.8. Verification 57
ANDES Manual, Release 1.8.10
1.8. Verification 59
ANDES Manual, Release 1.8.10
Background
The CURENT NPCC test system contains 140 buses, 233 branches, and 48 generators. Dynamic data uses
models GENROU, GENCLS, TGOV1 and IEEEX1.
One line trip scenario is used to verify ANDES simulation results with DSATools TSAT.
Simulation Parameters
Initialization
Power flow solutions are identical across all the two software.
GENROU initialization (EF D , ET ERM , P , Q, δ, Id and Iq ) is identical to that from PSS/E for all cases (with
and without generator saturation). Note that Id and Iq are in machine base in PSS/E but in system base in
ANDES.
GENROU initialization (including all the internal variables Ed′ , Eq′ , ψkd , ψkq , ψd′′ , and ψq′′ ) is identical to that
from OpenIPSL.
No controller limit violation occurs during initialization.
Conclusion
NPCC simulation results from ANDES are identical to that from TSAT.
import andes
import numpy as np
from andes.utils.tsat import tsat_to_df, plot_comparison, run_cmp
andes.config_logger(stream_level=30)
omega_lt2s = tsat_to_df('omega_lt2s.xls')
v_lt2s = tsat_to_df('v_lt2s.xls')
Scenario 1: Line 1-2 trips at 1 sec. and reconnects after 2.0 sec.
The reconnection delay is set to 2 seconds to trigger a large disturbance to the system to verify nonlinear models.
Simulation Setup
# line information
ss.Line.cache.df_in.iloc[0]
idx Line_1
u 1
name Line_1
bus1 1
bus2 2
Sn 100
fn 60
Vn1 345
Vn2 345
r 0.0004
x 0.0043
b 0.07
g 0
b1 0
g1 0
b2 0
g2 0
trans 0
tap 1
phi 0
owner None
xcoord None
ycoord None
Name: 0, dtype: object
1.8. Verification 61
ANDES Manual, Release 1.8.10
Scenario 1 Plots
1.8. Verification 63
ANDES Manual, Release 1.8.10
1.8. Verification 65
ANDES Manual, Release 1.8.10
1.8. Verification 67
ANDES Manual, Release 1.8.10
1.8. Verification 69
ANDES Manual, Release 1.8.10
1.8. Verification 73
ANDES Manual, Release 1.8.10
1.8. Verification 75
ANDES Manual, Release 1.8.10
1.8. Verification 77
ANDES Manual, Release 1.8.10
1.8. Verification 79
ANDES Manual, Release 1.8.10
1.8. Verification 81
ANDES Manual, Release 1.8.10
1.8. Verification 83
ANDES Manual, Release 1.8.10
1.8. Verification 85
ANDES Manual, Release 1.8.10
1.8. Verification 87
ANDES Manual, Release 1.8.10
Background
The CURENT WECC system contains 179 buses and 263 branches. Two line trip scenarios are created to
verify ANDES simulation results with DSATools TSAT and Siemens PTI PSS/E.
Dynamic data is based on the CURENT WECC 179-Bus test system, which uses models GENROU, TGOV1,
IEEEG1, EXST2, EXDC2, ESST3A, IEEEST, ST2CUT and ESDC2A, the saturation of which could be
implemented differently across software.
Simulation Parameters
Integretion method: Trapezidal Rule (ANDES and TSAT), the default second order Adams-Bashforth method
(AB-2) (PSS/E)
Time step size: 1/120 sec. (Note: step size between 1/30 to 1/120 has little impact on the ANDES results.
One can use tstep=1/30 to obtain almost the same results.)
Load conversion: static loads are converted to 100% constant impedances for both P and Q.
TSAT automatic parameter correction is disabled.
Initialization
Power flow solutions are identical across all the three software.
GENROU initialization (EF D , ET ERM , P , Q, δ, Id and Iq ) is identical to that from PSS/E for all cases (with
and without generator saturation). Note that Id and Iq are in machine base in PSS/E but in system base in
ANDES.
GENROU initialization (including all the internal variables Ed′ , Eq′ , ψkd , ψkq , ψd′′ , and ψq′′ ) is identical to that
from OpenIPSL.
1.8. Verification 89
ANDES Manual, Release 1.8.10
Conclusion
The finding is that, for particular disturbances in large systems, neither two of ANDES, TSAT and PSS/E
could match. Implementation details in commercial software are lacking. Thus, it could be futile to insist on
obtaining the same results for large systems, especially with several complex models.
Nevertheless, Scenario 2 shows that ANDES results are trustworthy. In fact, ANDES is open-source with all
the implemented equations clearly documented, which makes the results highly credible for research
and education purposes.
import andes
import numpy as np
from andes.utils.tsat import tsat_to_df, psse_to_df, plot_comparison, run_cmp
andes.config_logger(stream_level=30)
Line 38-39 is a transformer branch that connects generator #11 on Bus 39 to Bus 38. It is the only link to Bus
39.
# Line_221 information
ss.Line.cache.df_in.iloc[220]
idx Line_221
u 1
name Line_221
bus1 38
bus2 39
Sn 100
fn 60
Vn1 230
Vn2 18
r 0.0005
x 0.0238
b 0
g 0
b1 0
g1 0
(continues on next page)
omega2_psse = psse_to_df('omega2_psse.xlsx')
v2_psse = psse_to_df('v2_psse.xlsx')
omega2_psse.iloc[:, 1:] += 1
omega2_psse.iloc[:, 1:] *= 60
fname = ss.TDS.plt._fname
tsat_omega_headers = header_replace(fname, ss.GENROU.omega.a, 1, "GENROU",
,→"TSAT")
tsat_v_headers = header_replace(fname, ss.GENROU.v.a, 1 + ss.dae.n, "Bus",
,→"TSAT")
1.8. Verification 91
ANDES Manual, Release 1.8.10
Line 4-16 is in the eastern zone that connects two generator buses (CRAIG and SAN JUAN).
# Line 2 information
ss2.Line.cache.df_in.iloc[1]
idx Line_2
u 1
name Line_2
bus1 4
bus2 16
Sn 100
fn 60
Vn1 345
Vn2 345
r 0.00977
x 0.11
b 2
g 0
(continues on next page)
1.8. Verification 93
ANDES Manual, Release 1.8.10
# load data
omega = tsat_to_df('omega.xls')
v = tsat_to_df('v.xls')
omega_psse = psse_to_df('omega_psse.xlsx')
v_psse = psse_to_df('v_psse.xlsx')
omega_psse.iloc[:, 1:] += 1
omega_psse.iloc[:, 1:] *= 60
1.8. Verification 95
ANDES Manual, Release 1.8.10
1.8. Verification 97
ANDES Manual, Release 1.8.10
1.8. Verification 99
ANDES Manual, Release 1.8.10
1.9 Miscellaneous
1.9.2 Notes
Modeling Blocks
State Freeze
State freeze is used by converter controllers during fault transients to fix a variable at the pre-fault values. The
concept of state freeze is applicable to both state or algebraic variables. For example, in the renewable energy
electric control model (REECA), the proportional-integral controllers for reactive power error and voltage error
are subject to state freeze when voltage dip is observed. The internal and output states should be frozen when
the freeze signal turns one and freed when the signal turns back to zero.
Freezing a state variable can be easily implemented by multiplying the freeze signal with the right-hand side
(RHS) of the differential equation:
T ẋ = (1 − zf ) × f (x)
where f (x) is the original RHS of the differential equation, and zf is the freeze signal. When zf becomes zero
the differential equation will evaluate to zero, making the increment zero.
Freezing an algebraic variable is more complicate to implement. One might consider a similar solution to
freezing a differential variable by constructing a piecewise equation, for example,
0 = (1 − zf ) × g(y)
where g(y) is the original RHS of the algebraic equation. One might also need to add a small value to the
diagonals of dae.gy associated with the algebraic variable to avoid singularity. The rationale behind this
implementation is to zero out the algebraic equation mismatch and thus stop incremental correction: in the
frozen state, since zf switches to zero, the algebraic increment should be forced to zero. This method, however,
would not work when a dishonest Newton method is used.
If the Jacobian matrix is not updated after zf switches to one, in the row associated with the equation, the
derivatives will remain the same. For the algebraic equation of the PI controller given by
0 = (Kp u + xi ) − y
where Kp is the proportional gain, u is the input, xI is the integrator output, and y is the PI controller output,
the derivatives w.r.t u, xi and y are nonzero in the pre-frozen state. These derivative corrects y following the
changes of u and x. Although x has been frozen, if the Jacobian is not rebuilt, correction will still be made
due to the change of u. Since this equation is linear, only one iteration is needed to let y track the changes of
u. For nonlinear algebraic variables, this approach will likely give wrong results, since the residual is pegged at
zero.
To correctly freeze an algebraic variable, the freezing signal needs to be passed to an EventFlag, which will
set an custom_event flag if any input changes. EventFlag is a VarService that will be evaluated at
each iteration after discrete components and before equations.
To speed up the command-line program, import profiling is used to breakdown the program loading time.
With tool profimp, andes can be profiled with profimp "import andes" --html >
andes_import.htm. The report can be viewed in any web browser.
You might have heard that PyPy is faster than CPython due to a built-in JIT compiler. Before you spend an
hour compiling the dependencies, here is the fact: PyPy won't work for speeding up ANDES.
PyPy is often much slower than CPython when using CPython extension modules (see the PyPy_FAQ). Un-
fortunately, NumPy is one of the highly optimized libraries that heavily use CPython extension modules.
1.10.2 General
1.10.3 Modeling
Admittance matrix
1.11 License
ANDES is free software; you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any
later version.
ANDES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
Prefer pip?
ANDES can be installed via pip from PyPI.
New to Python?
Set up a Mambaforge environment following Setting Up Mambaforge. We recommend Mambaforge on Win-
dows and Apple Silicon for new users.
Are you a developer?
Installing from source? Looking to develop models? Check the guide in Develop Install.
TWO
EXAMPLES
A collection of examples are presented to supplement the tutorial. The examples below are identical to the
Jupyter Notebook in the examples folder of the repository here. You can run the examples in a live Jupyter
Notebook online using Binder.
We first import the andes library and the get_case function that for loading test cases shipped with AN-
DES.
import andes
We can configure the verbosity level for logging (output messages) by passing a verbosity level (10-DEBUG, 20-
INFO, 30-WARNING, 40-ERROR, 50-CRITICAL) to the stream_level argument of andes.main.
config_logger(). Verbose level 10 is useful for getting debug output.
The logging level can be altered (as of v1.4.3) by calling config_logger again with new stream_level
and file_level.
andes.config_logger(stream_level=20)
135
ANDES Manual, Release 1.8.10
get_case takes a relative path to ANDES_ROOT/andes/cases and returns the full path, where AN-
DES_ROOT is the root folder of ANDES.
andes.run is the entrypoint function for loading files and running routines. It runs power flow by default
and returns a System object.
Note: if default_config=True, the default concif will be used. To use your own config, remove de-
fault_config=True.
See the tutorial for saving and editing ANDES config.
ss = andes.run(get_case('kundur/kundur_full.xlsx'), default_config=True)
Run TDS by calling TDS.run() on the system. Note that the call must follow the power flow immediately.
The default simulation is for 20 seconds. To change if, change config.tf to the desired value.
ss.TDS.run()
True
To check if all operations completed successfully, check ss.exit_code. exit_code == 0 means that
all operations were successful.
If not zero, exit_code indicates the number of errors caught. One will need to check output messages for
errors.
ss.exit_code
If you are using ANDES interactively from Jupyter Notebook or IPython, at the end of a time-domain simu-
lation. a plotter object ss.TDS.plt will automatically be created.
To check if that has been created successfully (in case the detection of an interactive environment fails), check
the type of ss.TDS.plt.
ss.TDS.plt
<andes.plot.TDSData at 0x7fb229d9ff70>
ss.TDS.load_plotter()
To export simulation results to a CSV file, one can use ss.TDS.plt.export_csv(), which takes an
optional argument of the file name.
If not provided, a default file name will be assigned.
ss.TDS.plt.export_csv()
Index-based Plotting
plotter.plot() is the entry point for plotting. It is the backend of the command-line andes plot.
Before plotting, open the kundur_full_out.lst to find the indices (first column) for the variables to
plot.
For example, if we want to plot all generator speed, which is the omega variable of GENROU. By inspect, we
found the indices as 5, 6, 7, 8.
Pass them in a tuple or a list to ss.TDS.plt.plot.
ss.TDS.plt.find('omega')
([5, 6, 7, 8],
['omega GENROU 1', 'omega GENROU 2', 'omega GENROU 3', 'omega GENROU 4'])
fig, ax = ss.TDS.plotter.plot(ss.TDS.plotter.find('omega')[0])
Plotting by variable
fig, ax = ss.TDS.plt.plot(ss.GENROU.omega)
To plot a subset of the variables, pass the 0-indexed selection indices in a tuple through argument a of ss.
TDS.plt.plot. For example, to plot the 0-th and the 3-th GENROU.omega, do
Plotting curves into an existing figure allows easy comparison of results. It can be done by passing a figure and
an axis object of plot().
For example, to plot the speed of the second generator (a=1) on the figure above, do
Y-axis label
Note that the number of elements passed to yheader should match the number of variables. yheader only
Scaling
A lambda functino can be passed to ycalc to scale the value. To scale the frequency from per unit to 60 Hz
nominal values, use
Save figure
Additional arguments
plotter.plot takes addition arguments. To check additional arguments, please use help or refer to the
source code.
help(ss.TDS.plotter.plot)
This function retrieves the x and y values based on the `xidx` and
`yidx` inputs, applies scaling functions `ytimes` and `ycalc`␣
,→sequentially,
and delegates the plotting to the backend.
Parameters
----------
yidx : list or int
(continues on next page)
Other Parameters
----------------
ycalc: callable, optional
A callable to apply to all y values after scaling with `ytimes`.
xlabel : str
Text label for the x axis
xheader : list
A list containing the variable names for the x-axis variable
legend : bool
True to show legend and False otherwise
legend_ncol : int
Number of columns in legend
legend_bbox : tuple of two floats
legend box to anchor
grid : bool
True to show grid and False otherwise
latex : bool
True to enable latex and False to disable
greyscale : bool
True to use greyscale, False otherwise
savefig : bool or str
True to save to png figure file.
str is treated as the output file name.
save_format : str
File extension string (pdf, png or jpg) for the savefig format
dpi : int
(continues on next page)
Returns
-------
(fig, ax)
Figure and axis handles for matplotlib backend.
fig
Figure object for bqplot backend.
2.1.4 Cleanup
! andes misc -C
"/home/hacui/repos/andes/examples/kundur_full_out.npz" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.txt" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.lst" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.csv" removed.
!rm kundur_full_out_1.png
This example shows how to work with the data of a loaded test system, including parameters and variables.
import andes
from andes.utils.paths import get_case
andes.config_logger()
To show all the rows and columns, change the pandas configuration with
import pandas as pd
pd.options.display.max_columns = None
pd.options.display.max_rows = None
The ANDES xlsx file is the best supported format. Other formats can be converted to the xlsx format.
See the link below for more about format conversion. https://github.com/cuihantao/andes/blob/master/README.md#format-
converter
As previously shown, test cases can be loaded with andes.run():
ss = andes.run(get_case('kundur/kundur_full.xlsx'),
default_config=True) # one can remove `default_config=True`␣
,→to use custom config file
Alternatively, one can load a test case without setting up using andes.load(..., setup=False). Note
that setup=False option. It is useful to apply parameter changes to an existing test case.
ss = andes.load(get_case('kundur/kundur_full.xlsx'),
default_config=True,
setup=False)
ss.Line.alter('u', 'Line_3', 0)
When done, remember to set up the system before running calculation routines:
ss.setup()
ss.PFlow.run()
True
After setting up the system, adding or removing devices are not yet allowed.
ANDES supports loading systems from PSS/E RAW and DYR files.
The PSS/E v32 raw format is best supported.
Note that this feature is experimental. We try out best to support this format, but the compatibility is not
guaranteed.
raw_path = get_case('kundur/kundur.raw')
dyr_path = get_case('kundur/kundur_full.dyr')
The raw file is passed to the positional argument, whereas the dyr file is passed to addfile.
Parameters are stored as attributes of the model. For example, ss.GENROU.M, the machine starting time
constant (2H), is stored in ss.GENROU.M.
ss.GENROU.M
It is an instance of NumParam, which contains fields v for the values after converting to system-base per unit
values.
ss.GENROU.M.v
ss.GENROU.M.vin
Tabulated view
ANDES provides tabulated view of model parameters by using DataFrame. Each model object has an attribute
called cache for caching the parameter dataframes.
The original parameters from the input file are stored in cache.df_in of the model object. For GENROU,
do
ss.GENROU.cache.df_in
Parameters will be converted to per-unit in the system base after loading. This process have been done if
andes.run is used for loading the data file.
To inspect the converted parameters, check the cache.df parameter.
ss.GENROU.cache.df
One will notice the converted parameters such as M, xl, and all other impedances.
It is very important to notice that cache.df and cache.df_in are both views. Altering data in
these views will NOT alter the underlying parameter values.
To alter values, see the example below.
One may have noticed that ss.GENROU.cache.df and ss.GENROU.as_df() returns the same
dataframe. The difference is that the latter creates a new dataframe everytime it is called, but the former
caches the dataframe when it is initally accessed.
Altering parameters
13.0
The value set through alter is always the data before per-unit conversion - just like it should have been in an
input file. ANDES will perform the conversion and set vin and v correctly.
Parameters altered through Model.alter() can be saved as a new system using
True
In-place update
alter() can be used to change the value of ConstService to modify the equation that depend on such
ConstService. For example, the distributed PV model PVD1 implements a ConstService called
pref0 to store the initial value of the power reference. An equation associated with variable Pref enforces
that 0 = Pref - pref0.
If one needs to modify Pref, it has to be done through modifying pref0. Modifying Pref directly will not
take any effect since the variable will be overwritten by the solution of equations.
To update pref0 for a PVD1 device with idx = "PVD_1", one can do
ss.PVD1.alter('pref0', 'PVD_1', 0.005)
or, using keyword arguments in any order,
ss.PVD1.alter(src='pref0', idx='PVD_1', value=0.005)
If PVD_1 is the first (i.e., 0-th in the Python indexing) in the idx list, this modification is equivalent to setting
ss.PVD1.pref0.v[0] = 0.005.
Since index 0 is given, the array ss.PVD1.pref0.v is updated in-place.
When one needs to modify the pref0 of all PVD1 devices to 0.005, one can do
ss.PVD1.alter('pref0', ss.PVD1.idx.v, 0.005)
This is equivalent to
ss.PVD1.pref0.v[:] = 0.005
Note the [:] in the above line. This is a slice operation so that the assignment happens in-place.
One must never do out-of-place assignment, i.e.,
ss.PVD1.pref0.v = 0.005
or
ss.PVD1.pref0.v = 0.005 * np.ones_line(ss.PVD1.pref0.v)
because the assignment will point ss.PVD1.pref0.v to a new array. Internally, ANDES reuses the memory
for all arrays, meaning that their addresses are assumed to be constant. If one modifies ss.PVD1.pref0.v
out of place, the previous memory will no longer be accessible through ss.PVD1.pref0.v.
On the safe side, one should modify variables using alter() or, at least, always use in-place assignment to
internal arrays.
As mentioned, cache.df and cache.df_in are cached views and will not be automatically updated for
inspection.
This is generally not an issue if one performs the simulation after altering data. However, if one needs to inspect
the data again, cache.refresh() needs to be called manually.
ss.GENROU.cache.refresh()
ss.GENROU.cache.df_in
Alternatively, one can call the as_df() function to build a new dataframe without overwriting the cache:
ss.GENROU.as_df()
2.2.3 Variables
Snapshots
One might also want to check the variable values in a similar way to that for a parameter. Certainly, a variable
has a v attribute which stores values.
It is important to note that v only holds the values at the last program state. Such program state could be
the solution of power flow, the initialization of time-domain simulation, or the end of a simulation disturbances.
Since we have only ran power flow for ss, ss.Bus.v.v are the voltage magnitude solutions, where the first
v is for "voltage", and the second v is the first v's value attribute.
ss.Bus.v.v
array([1. , 1. , 1. , 1. , 0.98337472,
0.96908585, 0.9562181 , 0.95400018, 0.96856366, 0.98377143])
Variables hold more than values. They have an attribute a for the addresses indexing into the corresponding
type of array.
There are two system-level arrays, ss.dae.x and ss.dae.y for the right-hand-side of the differential and
algebraic equations, respectively.
type(ss.Bus.v)
andes.core.var.Algeb
ss.Bus.v is an algebraic variable, thus ss.Bus.v.a holds the indices into ss.dae.g.
ss.dae.y[ss.Bus.v.a]
array([1. , 1. , 1. , 1. , 0.98337472,
0.96908585, 0.9562181 , 0.95400018, 0.96856366, 0.98377143])
Time series
After a time-domain simulation, the time series of the variables can be retrieved through ss.dae.ts. Let's
first run a simulation.
ss.TDS.run()
True
ss.dae.ts
<andes.variables.dae.DAETimeSeries at 0x7f7bc75c1b50>
ss.dae.ts has four commonly used attributes: t for time stamps, xy for variables (differential and then
algebraic), z for discontinuous states, and df for the dataframe of all.
ss.dae.ts.t.shape
(603,)
(603, 201)
len(ss.dae.xy_name)
201
Let's extract the data for rotor speed (variable omega) of GENROU generators. The first step to extract variable
data is to determine the type of the variable: differential or algebraic. One can print the variable to see the
type:
ss.GENROU.omega
The output shows that omega is a state (differential variable), which should be looked up in ss.dae.x. For
algebraic variables such as ss.Bus.v, they should be looked up in ss.dae.y.
Therefore, all omega variables can be extracted as follows:
where the : in the first axis will access such data for all time stamps, and ss.GENROU.omega.a stores the
addresses of all omega into ss.dae.x.
To access all bus voltages (algebraic variable v) of the generators, one can use:
ss.dae.ts.y[:, ss.GENROU.v.a]
array([[1. , 1. , 1. , 1. ],
[1. , 1. , 1. , 1. ],
[1. , 1. , 1. , 1. ],
...,
[1.00240968, 1.00148908, 0.99526693, 1.00007159],
[1.00249935, 1.00159007, 0.99515528, 0.99997846],
[1.00259067, 1.0016924 , 0.99504062, 0.999883 ]])
These data correspond to the timestamps stored in ss.dae.ts.t. One can process such data as necessary.
To show verify the extracted data, we plot them with ss.TDS.plt.plot_data.
ss.TDS.plt.plot_data(ss.dae.ts.t, omega )
Alter can be used for updating any model parameter. We show another example of updating the duration of
a fault. Using the ieee14_fault.xlsx test case, we have
ss = andes.run(get_case("ieee14/ieee14_fault.xlsx"))
Again, if you need to add devices, you should use ss = andes.load(.., setup=False) and ss.
setup() instead of andes.run().
List the existing Fault devices:
ss.Fault.as_df()
One fault on Bus 9 is applied at t=1.0 sec and cleared at t=1.1 sec. Suppose that we want to clear the fault at t
= 1.05 sec, we can do
where tc is the parameter to alter, 1 is the idx of the Fault to find, and 1.05 is the new value. Inspect the
Fault devices to see the updated value. The simulation for the new system can be performed next.
ss.Fault.as_df()
2.2.5 Cleanup
!andes misc -C
"/home/hacui/repos/andes/examples/kundur_full_out.txt" removed.
"/home/hacui/repos/andes/examples/kundur_out.lst" removed.
"/home/hacui/repos/andes/examples/kundur_out.npz" removed.
"/home/hacui/repos/andes/examples/ieee14_fault_out.txt" removed.
"/home/hacui/repos/andes/examples/kundur_out.txt" removed.
!rm new_system.xlsx
First of all, import andes and configure the logger to the WARNING level (30).
import andes
andes.config_logger(30)
Create an empty andes.System object and call prepare(nomp=True) to generate equations and pretty
print, where nomp disables multiprocessing so that equations can be properly returned. This operation may
take a moment.
To only generate equations for a specific model, such as GENCLS, do:
ss = andes.System()
ss.GENCLS.prepare()
print(ss.supported_models())
Group | Models
-------------------+----------------------------------------------------------
ACLine | Line
ACShort | Jumper
ACTopology | Bus
Calculation | ACE, ACEc, COI
Collection | Area
DCLink | Ground, R, L, C, RCp, RCs, RLs, RLCs, RLCp
(continues on next page)
To check the documentation for the model, print the return of doc() for the model instance.
For example, the documentation for GENCLS can be printed with
print(ss.GENCLS.doc())
Parameters
Variables
Initialization Equations
Differential Equations
Algebraic Equations
Services
ss.GENCLS.syms.xy
δ
ω
Id
I
q
V
d
V
q
τ
m
τe
vf
Xad If d
Pe
Qe
ψd
ψq
θ
V
ss.GENCLS.states
ss.GENCLS.algebs
Formatted equations are stored in each model. The following attributes of Model.syms are available for
equation printing.
• f: differential equations
• g: algebraic equations
• df: df/dxy
• dg: dg/dxy
ss.GENCLS.syms.f
[ ]
2πf u (ω − 1)
u (−D (ω − 1) − τe + τm )
ss.GENCLS.syms.g
Id xq + ψd − vf
Iq xq + ψq
V u sin (δ − θ) − V
d
V u cos (δ − θ) − V
q
−τm + τm0
−τe + u (−Id ψq + Iq ψd )
uvf 0 − vf
−Xad If d + uvf 0
−Pe + u (Id Vd + Iq Vq )
−Qe + u (Id Vq − Iq Vd )
−ψd + u (Iq ra + Vq )
ψq + u (Id ra + Vd )
−u (Id Vd + Iq Vq )
−u (Id Vq − Iq Vd )
ss.GENCLS.syms.df
[ ]
0 2πf u 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 −Du 0 0 0 0 u −u 0 0 0 0 0 0 0 0
ss.GENCLS.syms.dg
0 0 xq 0 0 0 0 0 −1 0 0 0 1 0 0
0 0 0 xq 0 0 0 0 0 0 0 0 0 1 0
V u cos (δ − θ) −1 −V u cos (δ − θ) u
0 0 0 0 0 0 0 0 0 0 0 0
−V u sin (δ − θ) −1 V u sin (δ − θ) u
0 0 0 0 0 0 0 0 0 0 0 0
−1 0
0 0 0 0 0 0 0 0 0 0 0 0 0
0 −ψq u ψd u 0 −1 0 0 Iq u −Id u
0 0 0 0 0 0
0 0 0 0 0 0 0 0 −1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 −1 0 0 0 0 0
0 0 Vd u Vq u Id u Iq u 0 0 0 0 −1 0 0 0 0
0 0 Vq u −Vd u −Iq u Id u 0 0 0 0 0 −1 0 0 0
0 0 0 ra u 0 u 0 0 0 0 0 0 −1 0 0
0 0 ra u 0 u 0 0 0 0 0 0 0 0 1 0
0 0 −Vd u −Vq u −Id u −Iq u 0 0 0 0 0 0 0 0 0
0 0 −Vq u Vd u Iq u −Id u 0 0 0 0 0 0 0 0 0
ss.GENCLS.services
ss.GENCLS.syms.s
[P_{0s}*\gamma_P,
Q_{0s}*\gamma_Q,
V*exp(I*\theta),
P_0 - I*Q_0,
S/conj(V_c),
I_c*(r_a + I*xq) + V_c,
log(E/Abs(E)),
u*im(\delta_c),
V_c*u*exp(-\delta_c + 0.5*I*pi),
I_c*u*exp(-\delta_c + 0.5*I*pi),
re(I_{dq}),
im(I_{dq}),
re(V_{dq}),
im(V_{dq}),
u*(I_{d0}*(I_{d0}*r_a + V_{d0}) + I_{q0}*(I_{q0}*r_a + V_{q0})),
I_{q0}*r_a*u + V_{q0},
-I_{d0}*r_a*u - V_{d0},
I_{d0}*xq + I_{q0}*r_a + V_{q0}]
import numpy as np
import andes
from andes.utils.paths import list_cases, get_case
case_path = get_case('kundur/kundur_full.xlsx')
ss = andes.run(case_path, routine='eig')
ss.EIG.plot()
2.4.3 Report
Report is saved to the file and can be loaded into the notebook.
with open('kundur_full_eig.txt', 'r') as f:
print(f.read())
ANDES 1.7.5.post2.dev0+ga53a31fa
Copyright (C) 2015-2022 Hantao Cui
Positives 0
Zeros 1
Negatives 52
STATISTICS
Most Associated Real Imag. ␣
,→ Damped Freq. Frequency Damping [%]
#1 LL_x EXDC2 1 -1 0 ␣
,→ 0 0 0
#2 LL_x EXDC2 2 -1 0 ␣
,→ 0 0 0
#3 LL_x EXDC2 3 -1 0 ␣
,→ 0 0 0
#4 LL_x EXDC2 4 -1 0 ␣
,→ 0 0 0
#5 LS_y EXDC2 3 -49.191 0.64233 ␣
,→ 0.10223 7.8296 99.991
#6 LS_y EXDC2 3 -49.191 -0.64233 ␣
,→ 0.10223 7.8296 99.991
#7 LS_y EXDC2 1 -49.535 0 ␣
,→ 0 0 0
#8 LS_y EXDC2 4 -49.515 0 ␣
,→ 0 0 0
#9 LA_y EXDC2 2 -49.202 0.39349 ␣
,→ 0.062627 7.831 99.997
#10 LA_y EXDC2 2 -49.202 -0.39349 ␣
,→ 0.062627 7.831 99.997
#11 LA_y EXDC2 1 -48.885 0 ␣
,→ 0 0 0
#12 LA_y EXDC2 4 -48.905 0 ␣
,→ 0 0 0
#13 e2d GENROU 2 -36.896 0 ␣
,→ 0 0 0
#14 e2d GENROU 4 -36.75 0 ␣
,→ 0 0 0
#15 e2d GENROU 1 -34.732 0 ␣
,→ 0 0 0
#16 e2q GENROU 3 -33.89 0 ␣
,→ 0 0 0
#17 e2q GENROU 2 -33.526 0 ␣
,→ 0 0 0
#18 e2d GENROU 3 -31.242 0 ␣
,→ 0 0 0
#19 e2q GENROU 4 -27.613 0 ␣
,→ 0 0 0
#20 e2q GENROU 1 -24.954 0 ␣
,→ 0 0 0
(continues on next page)
EIGENVALUE DATA
#1 #2 #3 ␣
,→ #4 #5 #6 #7
delta GENROU 1 0 0 0 ␣
,→ 0 0 0 4e-05
delta GENROU 2 0 0 0 ␣
,→ 0 0 0 6e-05
delta GENROU 3 0 0 0 ␣
,→ 0 0 0 2e-05
delta GENROU 4 0 0 0 ␣
,→ 0 0 0 1e-05
omega GENROU 1 0 0 0 ␣
,→ 0 0 0 2e-05
omega GENROU 2 0 0 0 ␣
,→ 0 0 0 3e-05
omega GENROU 3 0 0 0 ␣
,→ 0 0 0 1e-05
omega GENROU 4 0 0 0 ␣
,→ 0 0 0 0
e1q GENROU 1 0 0 0 ␣
,→ 0 0.00084 0.00084 0.00306
e1q GENROU 2 0 0 0 ␣
,→ 0 0.0019 0.0019 0.00224
e1q GENROU 3 0 0 0 ␣
,→ 0 0.0026 0.0026 0.00069
e1q GENROU 4 0 0 0 ␣
,→ 0 0.00118 0.00118 0.00063
e1d GENROU 1 0 0 0 ␣
,→ 0 0 0 0
e1d GENROU 2 0 0 0 ␣
,→ 0 0 0 0
e1d GENROU 3 0 0 0 ␣
,→ 0 0 0 0
e1d GENROU 4 0 0 0 ␣
,→ 0 0 0 0
e2d GENROU 1 0 0 0 ␣
,→ 0 0.00839 0.00839 0.02012
e2d GENROU 2 0 0 0 ␣
,→ 0 0.01824 0.01824 (continues on next page)
0.01364
Parameter sweep allows automatically applying a set of parameters to compute the eigenvalues. It is useful to
plot the root loci of the system.
In this example, we will study the impact of EXDC2.KA of the device 1 on the system stability. Let its KA
vary evenly between 20 to 200 in 10 steps.
Plot the 30th to the 50-th eigenvalues (0-based index) on the s-plane:
Note that the marker size increases linearly as the parameters sweep from the first to the last. We recommend
sweeping the parameter in an ascending order so that the larger marker size correspond to a larger parameter.
2.4.5 Cleanup
!andes misc -C
"/home/hacui/repos/andes/examples/kundur_full_out.txt" removed.
"/home/hacui/repos/andes/examples/kundur_full_eig.txt" removed.
This example notebook is a supplement to the ANDES tutorial. Make sure you have read the tutorial on using
the CLI first.
A brief version can be found at https://github.com/cuihantao/andes/blob/master/README.md#run-
simulations
This example shows how to use the ANDES CLI from Jupyter Notebook.
It is based on the iPython magic !. To run a command from within IPython or Jupyter, place a ! immediately
before the command.
Conversely, all commands demonstrated in this notebook can be used in a terminal/shell by removing the
preceeding ! sign.
Windows users will need to install MSYS2 to support most of the Linux shell commands.
To install MSYS2-base, uncomment the following line and run it:
For example, to list the directory , use !ls. This is equivalent to executing ls from the terminal.
!ls
Likewise, to run andes, use !andes. Addition arguments can be passed as usual.
!andes
_ _ | Version 1.6.4.post10.dev0+gd1a4589d
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 04/19/2022 08:30:40 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
positional arguments:
{run,plot,doc,misc,prepare,prep,selftest,st,demo}
[run] run simulation routine; [plot] plot results;
[doc] quick documentation; [misc] misc. functions;
[prepare] prepare the numerical code; [selftest] run
self test;
optional arguments:
-h, --help show this help message and exit
-v {1,10,20,30,40}, --verbose {1,10,20,30,40}
Verbosity level in 10-DEBUG, 20-INFO, 30-WARNING, or
40-ERROR.
Pass the path to the case file and other arguments to andes from the command line as follows.
!andes run ../andes/cases/kundur/kundur_full.xlsx -r tds
_ _ | Version 1.6.4.post10.dev0+gd1a4589d
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 04/19/2022 08:30:41 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
Case file names can be separated from the path, which can be passed to -p. The above command is equivanent
to
_ _ | Version 1.6.4.post10.dev0+gd1a4589d
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 04/19/2022 08:30:43 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
!pwd
/home/hacui/repos/andes/examples
import os
os.path.isfile('../andes/cases/kundur/kundur_full.xlsx')
True
To run a simulation using PSS/E raw and dyr files, pass the dyr file to argument --addfile.
For example:
_ _ | Version 1.6.4.post10.dev0+gd1a4589d
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 04/19/2022 08:30:46 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
!cat kundur_full_out.lst
We found a limitation of using andes plot from within Notebook/iPython. The figure won't be displayed
correctly. The workaround is to save the image as a file and display it from the notebook.
Please let us know if you have better solutions.
A convenient tool in Linux/macOS is xargs, which turns the standard output of one program into arguments
for another.
andes plot --xargs accepts an input of search pattern for variable names and returns a list of arguments,
including the matched indices, that can be understood by andes plot.
To illustrate, let's look at an example output of andes plot --xargs.
kundur_full_out.lst 0 5 6 7 8
The output consists of the lst file name, the default x-axis index 0, and the indices for the found variables. The
full output can be passed to andes plot without modification.
We use the following command to pass the arguments:
Figure(640x480)
where | is the pipe operator in shell for piping the standard output of the left-hand side to the right-hand side,
xargs captures the pipe-in and appends it to andes plot.
The command is equivalent to manually running
Figure(640x480)
2.5.9 Cleanup
!rm -v *.png
removed 'kundur_full_out_1.png'
!andes misc -C
"/home/hacui/repos/andes/examples/kundur_full_out.npz" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.txt" removed.
"/home/hacui/repos/andes/examples/kundur_out.lst" removed.
"/home/hacui/repos/andes/examples/kundur_out.npz" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.lst" removed.
"/home/hacui/repos/andes/examples/kundur_out.txt" removed.
This notebook demonstrates creating cases in batch and running them in parallel.
import andes
import numpy as np
from andes.utils.paths import get_case
kundur = get_case('kundur/kundur_full.xlsx')
ss = andes.load(kundur)
Create 3 cases so that the load increases from p0_base to 1.2 * p0_base.
import os
!ls -la
total 56
drwxr-xr-x 2 hacui hacui 4096 Apr 19 20:31 .
drwxr-xr-x 6 hacui hacui 4096 Apr 19 20:31 ..
(continues on next page)
_ _ | Version 1.6.4.post10.dev0+gd1a4589d
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 04/19/2022 08:31:06 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
Number of CPUs
In some cases, you don't want the simulatino to use up all resources.
ANDES allows to control the number of processes to run in parallel through --ncpu NCPU, where NCPU is
the maximum number of processes (equivalent to the number of CPU cores) allowed.
_ _ | Version 1.6.4.post10.dev0+gd1a4589d
/_\ _ _ __| |___ ___ | Python 3.9.10 on Linux, 04/19/2022 08:31:09 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
systems[0]
<andes.system.System at 0x7fbaa050a070>
systems
[<andes.system.System at 0x7fbaa050a070>,
<andes.system.System at 0x7fba7bca2c70>,
<andes.system.System at 0x7fba7bc9db80>]
Example plots
ss = systems[0]
systems[0].TDS.plotter.plot(ss.GENROU.omega, latex=False)
systems[2].TDS.plotter.plot(ss.GENROU.omega, latex=False)
!andes misc -C
!rm -rf batch_cases
This notebook shows examples for batch power flow and time-domain calculations. Readers are supposed to
have read the previous examples, especially Example 7 for parallel simulations.
import andes
import numpy as np
Use the Kundur's system as the example. Suppose we want to calculate power flow for the same system structure
but for different load levels.
kundur = andes.utils.get_case('kundur/kundur_full.xlsx')
ss = andes.run(kundur,
no_output=True,
default_config=True,
verbose=30, # set logging level to WARNING
)
There are two PQ loads in the Kundur's system with idxes of PQ_0 and PQ_1.
ss.PQ.as_df(vin=True)
where there are 3 samples for PQ_0.p0 between [10, 12] and 3 samples for PQ_1.p0 between (12,
18).
We can use a for loop to set the load values and calculate power flow for each point.
Suppose we want to retrieve the voltage magnitude for each case, we use v_results the voltage results.
Results that are not saved will be discarded.
for ii in pq0_values:
ss.PQ.alter("p0", "PQ_0", ii)
for jj in pq1_values:
ss.PFlow.run()
v_results[:, idx] = ss.dae.y[ss.Bus.v.a]
idx += 1
lines = plt.plot(v_results)
xl = plt.xlabel('Bus Name')
yl = plt.ylabel('Voltage [p.u.]')
tk = plt.xticks(np.arange(ss.Bus.n), ss.Bus.name.v)
One should be aware that the for-loop based approach is single-threaded. It does not take advantage of multi-
core processors.
If the total number of scenarios are huge, one should refer to Example 7 to save all scenarios to excel files and
use multi-processing.
The next example shows how to run batch time-domain simulations for different events.
Suppose we want to create one scenario for each line trip event, which is actuated through Toggle. For the
same system, we want to add Toggles for each line, run the simulation, and save results.
kundur = andes.utils.get_case('kundur/kundur_full.xlsx')
ss = andes.load(kundur, setup=False)
idxes = ss.Line.idx.v
ss.Toggle.as_df()
We use ss.add() to add two Toggles for each line at 1 second and 1.1 seconds to simulate a line opening
and closing. ss.add() takes a model name, "Toggle", as the positional argument, and a dictionary for the
Toggle device parameters.
A note for this particular test case is that kundur_full.xlsx already comes with a Toggle with idx==1.
To not to interfere with our scenarios, we need to disable it using ss.Toggle.alter.
After adding Toggle devices, we need to manually call ss.setup() to finish the data structure setup. Then,
power flow and time-domain simulation can be performed.
We store the results in a dictionary where keys are the line names and values are the systems. Code is as follows.
results = dict()
ss.PFlow.run()
ss.TDS.config.tf = 5 # simulate for 5 seconds to save time
ss.TDS.config.no_tqdm = 1 # disable progres bar printing
ss.TDS.run()
results[idx] = ss
Not all cases will solve due to system instability. For the converged cases, one can export the data or plot results
following Example 1.
This notebook shows an example of changing the generator setpoints in a time-domain simulation. Data in this
example is trivial, but the example can be retrofitted for scenarios such as economic dispatch incorporation or
reinforcement learning.
Steps are the folllwing:
1. Initialize a system by running the power flow,
2. Set the first simulation stop time in TDS.config.tf,
3. Run the simulation,
4. Update the setpoints,
5. Set the new simulation stop time and repeat from 3 until the end.
import andes
from andes.utils import get_case
kundur = get_case('kundur/kundur_full.xlsx')
ss = andes.run(kundur)
ss.TDS.run()
True
First, let's check the equations of TGOV1. ss.TGOV1.paux0 is associated with equation 0 = paux -
paux0, in which paux is added to the power input equation.
print(ss.TGOV1.doc())
Parameters
Variables
Initialization Equations
Differential Equations
Algebraic Equations
Services
Discretes
Blocks
ss.TGOV1.paux0.v
# look up the original values of TGOV1 make sure they are as expected
ss.TGOV1.paux0.v
ss.TGOV1.paux0.v[0] = 0.05
# ss.TGOV1.alter('paux0', 1, 0.05)
ss.TGOV1.paux0.v
array([0.05, 0. , 0. , 0. ])
ss.TDS.config.tf = 2
ss.TDS.run()
True
ss.TDS.plotter.plot(ss.TGOV1.paux)
ss.TDS.plotter.plot(ss.TGOV1.pout)
ss.TDS.plotter.plot(ss.GENROU.omega)
2.8.5 Step 5: Set Another New Setpoints and New Ending TIme.
ss.TGOV1.paux0.v[0] = 0.
# ss.TGOV1.alter('paux0', 1, 0)
ss.TDS.run()
True
ss.TDS.plotter.plot(ss.TGOV1.paux)
ss.TDS.plotter.plot(ss.GENROU.omega)
!andes misc -C
"/home/hacui/repos/andes/examples/kundur_full_out.npz" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.txt" removed.
"/home/hacui/repos/andes/examples/kundur_full_out.lst" removed.
This examples shows (1) how to trip a generator, and (2) how to drive frequency back by load shedding.
import andes
import numpy as np
andes.config_logger(stream_level=20)
ieee14_raw = andes.get_case("ieee14/ieee14.raw")
ieee14_dyr = andes.get_case("ieee14/ieee14.dyr")
'Toggle_3'
ss.setup()
True
ss.Toggle.as_df()
ss.Toggle.u.v[[0, 1]] = 0
# use constant power model for PQ (we will come back to this later)
ss.PQ.config.p2p = 1
ss.PQ.config.q2q = 1
ss.PQ.config.p2z = 0
ss.PQ.config.q2z = 0
ss.PFlow.run()
True
ss.TDS.config.tf = 20
(continues on next page)
ss.TDS.run()
True
ss.TDS.plt.plot(ss.GENROU.omega,
a=(0, 2, 3, 4),
ytimes=60,
)
Check the power of the lost generator by inspecting the power flow inputs:
ss.PV.as_df()
The tripped GENROU_2 correspond to the first PV (GENROU_1 corresponds to Slack). Thus, the lost active
power is 0.40 pu.
Let's compensate for that by shedding 0.4 pu of active power load at t=2.0 s.
By checking the equation documentation of PQ (using print(ss.PQ.doc()), we can tell that the imposed
active power for time-domain simulation is from Ppf, because we used the constant power model with p2p
= 1.
Algebraic Equations
Ppf = np.array(ss.PQ.Ppf.v)
Ppf
ss.PQ.config.p2p = 1
ss.PQ.config.q2q = 1
ss.PQ.config.p2z = 0
ss.PQ.config.q2z = 0
ss.PQ.pq2z = 0
ss.PFlow.run()
True
ss.TDS.run()
True
shed_buses = [2, 3, 4, 5, 6, 9]
True
# double check
ss.PQ.Ppf.v
ss.TDS.config.tf = 10
ss.TDS.run()
ss.TDS.plt.plot(ss.GENROU.omega,
a=(0, 2, 3, 4),
ytimes=60,
)
!andes misc -C
"/home/hacui/repos/andes/examples/ieee14_out.txt" removed.
"/home/hacui/repos/andes/examples/ieee14_out.lst" removed.
"/home/hacui/repos/andes/examples/ieee14_out.npz" removed.
The result shows the generator speed (frequency) returns to 60 Hz after load shedding.
Before getting started, this example requires the config flag PFlow.init_tds to be 0, which is the default
value.
import andes
from andes.utils.paths import get_case
case_path = get_case('kundur/kundur_full.xlsx')
Passing profile=True, no_output = True to run will enable the profiler and have the results
printed.
,→dependency)
26 0.000 0.000 0.138 0.005 /home/hacui/mambaforge/envs/a/
,→lib/python3.9/site-packages/numba/core/dispatcher.py:864(compile)
1 0.000 0.000 0.138 0.138 /home/hacui/mambaforge/envs/a/
,→lib/python3.9/site-packages/openpyxl/__init__.py:4(<module>)
26 0.000 0.000 0.135 0.005 /home/hacui/mambaforge/envs/a/
,→lib/python3.9/site-packages/numba/core/caching.py:636(load_overload)
1 0.000 0.000 0.131 0.131 /home/hacui/mambaforge/envs/a/
,→lib/python3.9/site-packages/openpyxl/workbook/__init__.py:4(<module>)
import andes
from andes.utils.paths import get_case
case_path = get_case('kundur/kundur_full.xlsx')
Pass the function name to profile to the magic %lprun, followed by a call to the function itself or an upper-level
function.
Results will be shown in a popup window.
%load_ext line_profiler
Alternatively, do
ss.reset()
%lprun -f ss.PFlow.run ss.PFlow.run()
To dig into the Newton Raphson iteration steps, profile each step instead with:
ss.reset()
%lprun -f ss.PFlow.nr_step ss.PFlow.run()
2.10.3 Cleanup
!andes misc -C
_ _ | Version 1.5.7.post27.dev0+g9e0e253e
/_\ _ _ __| |___ ___ | Python 3.9.7 on Linux, 12/14/2021 02:51:15 PM
/ _ \| ' \/ _` / -_|_-< |
/_/ \_\_||_\__,_\___/__/ | This program comes with ABSOLUTELY NO WARRANTY.
import andes
m = start_instance()
m.eval("runpf(mpc)")
Minimum Maximum
------------------------- --------------------------------
Voltage Magnitude 1.010 p.u. @ bus 3 1.030 p.u. @ bus 2
Voltage Angle -9.48 deg @ bus 14 0.00 deg @ bus 1
P Losses (I^2*R) - 0.50 MW @ line 1-2
Q Losses (I^2*X) - 2.11 MVAr @ line 8-7
================================================================================
| Bus Data ␣
,→ |
================================================================================
Bus Voltage Generation Load
# Mag(pu) Ang(deg) P (MW) Q (MVAr) P (MW) Q (MVAr)
----- ------- -------- -------- -------- -------- --------
1 1.030 0.000* 81.43 -21.62 - -
2 1.030 -1.764 40.00 30.44 21.70 12.70
3 1.010 -3.537 40.00 12.60 50.00 25.00
4 1.011 -4.410 - - 47.80 10.00
5 1.017 -3.843 - - 7.60 1.60
6 1.030 -6.453 30.00 20.99 15.00 7.50
7 1.022 -4.885 - - - -
8 1.030 -1.540 35.00 7.40 - -
9 1.022 -7.246 - - 29.50 16.60
10 1.016 -7.415 - - 9.00 5.80
11 1.019 -7.080 - - 3.50 1.80
12 1.017 -7.473 - - 6.10 1.60
13 1.014 -7.721 - - 13.50 5.80
14 1.016 -9.481 - - 20.00 7.00
-------- -------- -------- --------
Total: 226.43 49.80 223.70 95.40
================================================================================
| Branch Data ␣
,→ |
================================================================================
Brnch From To From Bus Injection To Bus Injection Loss (I^2 * Z)
# Bus Bus P (MW) Q (MVAr) P (MW) Q (MVAr) P (MW) Q␣
,→(MVAr)
----- ----- ----- -------- -------- -------- -------- -------- -------
,→-
One can also save the case to a MATPOWER .m file from Octave/MATLAB. Comment in and run the fol-
lowing code:
# m.eval("savecase('case14_andes.m', mpc)")
m.pull() won't work if one has run OPF in Octave/MATLAB because Oct2Py does not support custom
class objects created by MATPOWER.
from _matpower() will read the individual fields to construct an mpc dict internally before creating a
system.
One can create an Excel file with dynamic data only and use the xlsx parser to load data into system:
xlsx.read(system, andes.get_case('ieee14/ieee14_dyn_only.xlsx'))
<andes.system.System at 0x7f8684043520>
system.setup()
system.PFlow.run()
(continues on next page)
system.TDS.run()
True
system.TDS.plt.plot(system.GENROU.omega)
ss = andes.run(andes.get_case("ieee14/ieee14_fault.xlsx"),
routine='tds', verbose=30,
no_output=True, default_config=True)
ss.TDS.plt.plot(ss.GENROU.omega)
This example (1) shows how to convert an ANDES system (ssa) to a pandapower network (ssp), (2) bench-
marks the powerflow results, (3) shows how to alter ssa active power setpoints according to ssp results.
The following clarafications you might need to know:
1. This interface tracks static power flow model in ANDES: Bus, Line, PQ, Shunt, PV, and Slack.
The dynamic model in ANDES is not tracked, including but not limited to TurbineGov, SynGen,
and Exciter.
2. The interface converts the Slack in ANDES to gen in pandapower rather than ext_gen.
3. MUST NOT verify power flow after initializing TDS in ANDES. ANDES does not allow running
PFlow for systems with initialized TDS as it will break variable addressing.
4. If you want to track dynamic model outputs in ANDES and feedback into pandapower, you might need
to manually transfer the results from ANDES to pandapower.
This interface is mainly developed by Jinning Wang.
import andes
andes.config_logger(20)
import pandapower as pp
import numpy as np
import pandas as pd
Here we use the same ANDES system ss0 to do the pandapower conversion, which leaves the ssa untouched.
This will be useful if you need to modify the ssa parametes or setpoints.
ssa = andes.load(andes.get_case('ieee14/ieee14_ieeet1.xlsx'),
setup=False,
no_output=True,
default_config=True)
ssa.Toggle.u.v = [0, 0]
ssa.setup()
ss0 = andes.load(andes.get_case('ieee14/ieee14_ieeet1.xlsx'),
setup=False,
no_output=True,
default_config=True)
ss0.Toggle.u.v = [0, 0]
ss0.setup()
True
add_gencost(ssp, gen_cost)
True
ssp
ssa.PFlow.run()
True
# ssa
ssa_res_gen = pd.DataFrame(columns=['name', 'p_mw', 'q_mvar', 'va_degree',
,→'vm_pu'])
# ssp
pp.runpp(ssp)
ssp_res_gen = pd.concat([ssp.gen['name'], ssp.res_gen], axis=1)
# ssa
ssa_pf_bus = ssa.Bus.as_df()[["name"]].copy()
ssa_pf_bus['v_andes'] = ssa.Bus.v.v
ssa_pf_bus['a_andes'] = ssa.Bus.a.v * 180 / pi
# ssp
ssp_pf_bus = ssa.Bus.as_df()[["name"]].copy()
ssp_pf_bus['v_pp'] = ssp.res_bus['vm_pu']
ssp_pf_bus['a_pp'] = ssp.res_bus['va_degree']
Generation
In the table below, the left half are ANDES results, and the right half are from pandapower
res_gen_concat.round(4)
vm_pu
0 1.03
1 1.01
2 1.03
(continues on next page)
Likewise, the left half are ANDES results, and the right half are from pandapower
pf_bus_concat.round(4)
# Asign the StaticGen with OPF, in this case, all the SynGen are GENROU
link_table = make_link_table(ssa)
link_table
Note: some Jupyter notebooks may not support inline plots. You can use the following command to enable it.
import matplotlib
%matplotlib inline
import matplotlib
%matplotlib inline
ssa.TDS.config.tf = 2
ssa.TDS.run()
ssa.TDS.plt.plot(ssa.GENROU.Pe)
Get the OPF results from pandapower. The ssp_res has been converted to p.u..
ACOPF is solved.
Now dispatch the resutls into ssa, where the active power setpoitns are updated to TurbinGov.pref0.
ssa_gov_idx = list(ssp_res['gov_idx'][~ssp_res['gov_idx'].isna()])
ssa.TurbineGov.set(src='pref0', idx=ssa_gov_idx, attr='v', value=ssp_res['p
,→'][~ssp_res['gov_idx'].isna()])
ssa.TurbineGov.get(src='pref0', idx=ssa_gov_idx, attr='v')
ssa.TDS.config.tf = 50
ssa.TDS.run()
True
We can see the outputs of GENROU are rearranged by the OPF results.
ssa.TDS.plt.plot(ssa.GENROU.Pe)
"PowSyBl (Power System Blocks) is an open source framework written in Java, dedicated to electrical grid
modelling and simulation, licensed under the Mozilla Public License version 2.0. It is part of LF Energy, an
open source foundation focused on the power systems sector, hosted within The Linux Foundation."
pypowsybl is the Python interface to PowSybl. For more information, please visit:
https://www.powsybl.org/pages/overview/
ANDES provides a simple interface to pypowsybl. The main goal is to leverage pypowsybl for drawing
single-line diagrams and area diagrams for systems loaded in ANDES.
2.13.1 Imports
import andes
import pypowsybl as pp
ss = andes.load(andes.get_case("ieee14/ieee14_linetrip.xlsx"))
2.13.2 Conversion
n = to_pypowsybl(ss)
results = pp.loadflow.run_ac(n)
2.13.3 Diagrams
n.get_network_area_diagram()
<pypowsybl.network.Svg at 0x7f1f905b33d0>
n.get_single_line_diagram("VL6")
<pypowsybl.network.Svg at 0x7f1e879e2760>
where VL6 is the voltage level container created for Bus 6. Voltage level container is named as VL + bus idx.
To find out how to work with pypowsybl, visit its documentation at https://pypowsybl.readthedocs.io
THREE
DEVELOPMENT
This chapter contains advanced topics on modeling and simulation and how they are implemented in ANDES.
It aims to provide an in-depth explanation of how the ANDES framework is set up for symbolic modeling and
numerical simulation. It also provides an example for interested users to implement customized DAE models.
3.1 System
3.1.1 Overview
System is the top-level class for organizing power system models and orchestrating calculations. The full API
reference of System is found at andes.system.System.
Dynamic Imports
System dynamically imports groups, models, and routines at creation. To add new models, groups or routines,
edit the corresponding file by adding entries following examples.
andes.system.System.import_models(self)
Import and instantiate models as System member attributes.
Models defined in models/__init__.py will be instantiated sequentially as attributes with the same
name as the class name. In addition, all models will be stored in dictionary System.models with
model names as keys and the corresponding instances as values.
Examples
system.Bus stores the Bus object, and system.GENCLS stores the classical generator object,
system.models['Bus'] points the same instance as system.Bus.
andes.system.System.import_groups(self)
Import all groups classes defined in models/group.py.
Groups will be stored as instances with the name as class names. All groups will be stored to dictionary
System.groups.
257
ANDES Manual, Release 1.8.10
andes.system.System.import_routines(self)
Import routines as defined in routines/__init__.py.
Routines will be stored as instances with the name as class names. All routines will be stored to dictionary
System.routines.
Examples
System.PFlow is the power flow routine instance, and System.TDS and System.EIG are time-
domain analysis and eigenvalue analysis routines, respectively.
Code Generation
Under the hood, all models whose equations are provided in strings need be processed to generate executable
functions for simulations. We call this process "code generation". Code generation utilizes SymPy, a symbolic
toolbox, and can take up to one minute.
Code generation is automatically triggered upon the first ANDES run or whenever model changes are detected.
Code generation only needs to run once unless the generated code is removed or model edits are detected. The
generated code is then stored and reused for speed up.
The generated Python code is called pycode. It is a Python package (folder) with each module (a .py file)
storing the executable Python code and metadata for numerical simulation. The default path to store pycode
is HOME_DIR/.andes, where HOME_DIR is one's home directory.
Note: Code generation has been done if one has executed andes, andes selftest, or andes pre-
pare.
Warning: For developers: when models are modified (such as adding new models or changing equation
strings), code generation needs to be executed again for consistency. ANDES can automatically detect
changes, and it can be manually triggered from command line using andes prepare -i.
Warning: Generated lambda functions will be serialized to file, but pretty prints (SymPy objects)
can only exist in the System instance on which prepare is called.
Notes
Option incremental compares the md5 checksum of all var and service strings, and only regenerate
for updated models.
Examples
If one needs to print out LaTeX-formatted equations in a Jupyter Notebook, one need to generate such
equations with
import andes
sys = andes.prepare()
Alternatively, one can explicitly create a System and generate the code
import andes
sys = andes.System()
sys.prepare()
andes.system.System.undill(self, autogen_stale=True)
Reload generated function functions, from either the $HOME/.andes/pycode folder.
If no change is made to models, future calls to prepare() can be replaced with undill() for
acceleration.
Parameters
autogen_stale: bool True to automatically call code generation if stale code is detected.
Regardless of this option, codegen is trigger if importing existing code fails.
Scalar Description
m The number of algebraic variables/equations
n The number of algebraic variables/equations
o The number of limiter state flags
The derivatives of f and g with respect to x and y are stored in four kvxopt.spmatrix sparse ma-
trices: fx, fy, gx, and gy, where the first letter is the equation name, and the second letter is the variable
name.
Notes
DAE does not keep track of the association of variable and address. Only a variable instance keeps track
of its addresses.
ANDES uses a decentralized architecture between models and DAE value arrays. In this architecture, variables
are initialized and equations are evaluated inside each model. Then, System provides methods for collecting
initial values and equation values into DAE, as well as copying solved values to each model.
The collection of values from models needs to follow protocols to avoid conflicts. Details are given in the
subsection Variables.
andes.system.System.vars_to_dae(self, model)
Copy variables values from models to System.dae.
This function clears DAE.x and DAE.y and collects values from models.
andes.system.System.vars_to_models(self)
Copy variable values from System.dae to models.
The largest overhead in building and solving nonlinear equations is the building of Jacobian matrices. This
is especially relevant when we use the implicit integration approach which algebraized the differential equa-
tions. Given the unique data structure of power system models, the sparse matrices for Jacobians are built
incrementally, model after model.
There are two common approaches to incrementally build a sparse matrix. The first one is to use simple in-place
add on sparse matrices, such as doing
Although the implementation is simple, it involves creating and discarding temporary objects on the right hand
side and, even worse, changing the sparse pattern of self.fx.
The second approach is to store the rows, columns and values in an array-like object and construct the Jacobians
at the end. This approach is very efficient but has one caveat: it does not allow accessing the sparse matrix while
building.
ANDES uses a pre-allocation approach to avoid the change of sparse patterns by filling values into a known
the sparse matrix pattern matrix. System collects the indices of rows and columns for each Jacobian matrix.
Before in-place additions, ANDES builds a temporary zero-filled spmatrix, to which the actual Jacobian values
are written later. Since these in-place add operations are only modifying existing values, it does not change
the pattern and thus avoids memory copying. In addition, updating sparse matrices can be done with the exact
same code as the first approach.
Still, this approach creates and discards temporary objects. It is however feasible to write a C function which
takes three array-likes and modify the sparse matrices in place. This is feature to be developed, and our
prototype shows a promising acceleration up to 50%.
andes.system.System.store_sparse_pattern(self, models: collections.OrderedDict)
Collect and store the sparsity pattern of Jacobian matrices.
This is a runtime function specific to cases.
Notes
For gy matrix, always make sure the diagonal is reserved. It is a safeguard if the modeling user omitted
the diagonal term in the equations.
System is an orchestrator for calling shared methods of models. These API methods are defined for initializa-
tion, equation update, Jacobian update, and discrete flags update.
The following methods take an argument models, which should be an OrderedDict of models with names as
keys and instances as values.
andes.system.System.init(self, models: collections.OrderedDict, routine: str)
Initialize the variables for each of the specified models.
For each model, the initialization procedure is:
• Get values for all ExtService.
• Call the model init() method, which initializes internal variables.
• Copy variables to DAE and then back to the model.
andes.system.System.e_clear(self, models: collections.OrderedDict)
Clear equation arrays in DAE and model variables.
This step must be called before calling f_update or g_update to flush existing values.
andes.system.System.l_update_var(self, models: collections.OrderedDict, niter=0, err=None)
Update variable-based limiter discrete states by calling l_update_var of models.
This function is must be called before any equation evaluation.
andes.system.System.f_update(self, models: collections.OrderedDict)
Call the differential equation update method for models in sequence.
Notes
Updated equation values remain in models and have not been collected into DAE at the end of this step.
andes.system.System.l_update_eq(self, models: collections.OrderedDict, init=False, niter=0)
Update equation-dependent limiter discrete components by calling l_check_eq of models. Force set
equations after evaluating equations.
This function is must be called after differential equation updates.
andes.system.System.g_update(self, models: collections.OrderedDict)
Call the algebraic equation update method for models in sequence.
Notes
Like f_update, updated values have not collected into DAE at the end of the step.
andes.system.System.j_update(self, models: collections.OrderedDict, info=None)
Call the Jacobian update method for models in sequence.
The procedure is - Restore the sparsity pattern with andes.variables.dae.DAE.
restore_sparse() - For each sparse matrix in (fx, fy, gx, gy), evaluate the Jacobian function calls
and add values.
Notes
Updated Jacobians are immediately reflected in the DAE sparse matrices (fx, fy, gx, gy).
3.1.5 Configuration
System, models and routines have a member attribute config for model-specific or routine-specific configura-
tions. System manages all configs, including saving to a config file and loading back.
andes.system.System.save_config(self, file_path=None, overwrite=False)
Save all system, model, and routine configurations to an rc-formatted file.
Parameters
file_path [str, optional] path to the configuration file default to ~/andes/andes.rc.
overwrite [bool, optional] If file exists, True to overwrite without confirmation. Oth-
erwise prompt for confirmation.
Warning: Saved config is loaded back and populated at system instance creation time. Configs from
the config file takes precedence over default config values.
Warning: It is important to note that configs from files is passed to model constructors during instantiation.
If one needs to modify config for a run, it needs to be done before instantiating System, or before running
andes from command line. Directly modifying Model.config may not take effect or have side effect
as for the current implementation.
3.2 Group
A group is a collection of similar functional models with common variables and parameters. It is manda-
tory to enforce the common variables and parameters when develop new models. The common variables and
parameters are typically the interface when connecting different group models.
For example, the Group RenGen has variables Pe and Qe, which are active power output and reactive power
output. Such common variables can be retrieved by other models, such as one in the Group RenExciter for
further calculation.
In such a way, the same variable interface is realized so that all model in the same group could carry out similar
function.
3.2.1 andes.models.group.GroupBase
class andes.models.group.GroupBase
Base class for groups.
__init__()
Methods
GroupBase.add
GroupBase.add(idx, model)
Register an idx from model_name to the group
Parameters
idx: Union[str, float, int] Register an element to a model
model: Model instance of the model
Returns
GroupBase.add_model
GroupBase.doc
GroupBase.doc(export='plain')
Return the documentation of the group in a string.
GroupBase.doc_all
GroupBase.doc_all(export='plain')
Return documentation of the group and its models.
Parameters
export ['plain' or 'rest'] Export format, plain-text or RestructuredText
Returns
str
GroupBase.find_idx
GroupBase.get
GroupBase.get_field
GroupBase.get_next_idx
GroupBase.get_next_idx(idx=None, model_name=None)
Get a no-conflict idx for a new device. Use the provided idx if no conflict. Generate a new one
otherwise.
Parameters
idx [str or None] Proposed idx. If None, assign a new one.
model_name [str or None] Model name. If not, prepend the group name.
Returns
GroupBase.idx2model
GroupBase.idx2model(idx, allow_none=False)
Find model name for the given idx.
Parameters
idx [float, int, str, array-like] idx or idx-es of devices.
allow_none [bool] If True, return None at the positions where idx is not found.
Returns
If idx is a list, return a list of model instances.
If idx is a single element, return a model instance.
GroupBase.idx2uid
GroupBase.idx2uid(idx)
Convert idx to the 0-indexed unique index.
Parameters
idx [array-like, numbers, or str] idx of devices
Returns
list A list containing the unique indices of the devices
GroupBase.set
GroupBase.set_backref
Attributes
class_name
GroupBase.class_name
property GroupBase.class_name
GroupBase.n
property GroupBase.n
Total number of devices.
3.3 Models
This section introduces the modeling of power system devices. The terminology "model" is used to describe
the mathematical representation of a type of device, such as synchronous generators or turbine governors. The
terminology "device" is used to describe a particular instance of a model, for example, a specific generator.
To define a model in ANDES, two classes, ModelData and Model need to be utilized. Class ModelData is
used for defining parameters that will be provided from input files. It provides API for adding data from devices
and managing the data. Class Model is used for defining other non-input parameters, service variables, and
DAE variables. It provides API for converting symbolic equations, storing Jacobian patterns, and updating
equations.
The following classes are related to models:
3.3.1 andes.core.model.ModelData
Notes
Three default parameters are pre-defined in ModelData and will be inherited by all models. They are
• idx, unique device idx of type andes.core.param.DataParam
• u, connection status of type andes.core.param.NumParam
• name, (device name of type andes.core.param.DataParam
In rare cases one does not want to define these three parameters, one can pass three_params=True to the
constructor of ModelData.
Examples
If we want to build a class PQData (for static PQ load) with three parameters, Vn, p0 and q0, we can
use the following
class PQData(ModelData):
super().__init__()
self.Vn = NumParam(default=110,
info="AC voltage rating",
unit='kV', non_zero=True,
tex_name=r'V_n')
self.p0 = NumParam(default=0,
info='active power load in system base',
tex_name=r'p_0', unit='p.u.')
self.q0 = NumParam(default=0,
info='reactive power load in system base',
tex_name=r'q_0', unit='p.u.')
In this example, all the three parameters are defined as andes.core.param.NumParam. In the
full PQData class, other types of parameters also exist. For example, to store the idx of owner, PQData
uses
Attributes
cache A cache instance for different views of the internal data.
flags [dict] Flags to control the routine and functions that get called. If the model is
using user-defined numerical calls, set f_num, g_num and j_num properly.
Methods
ModelData.add
ModelData.add(**kwargs)
Add a device (an instance) to this model.
Parameters
kwargs model parameters are collected into the kwargs dictionary
Warning: This function is not intended to be used directly. Use the add method from System
so that the index can be registered correctly.
ModelData.as_df
ModelData.as_df(vin=False)
Export all parameters as a pandas.DataFrame object. This function utilizes as_dict for preparing
data.
Returns
DataFrame A dataframe containing all model data. An uid column is added.
vin [bool] If True, export all parameters from original input (vin).
ModelData.as_df_local
ModelData.as_df_local()
Export local variable values and services to a DataFrame.
ModelData.as_dict
ModelData.as_dict(vin=False)
Export all parameters as a dict.
Returns
dict a dict with the keys being the ModelData parameter names and the values being
an array-like of data in the order of adding. An additional uid key is added with
the value default to range(n).
ModelData.find_idx
ModelData.find_param
ModelData.find_param(prop)
Find params with the given property and return in an OrderedDict.
Parameters
prop [str] Property name
Returns
OrderedDict
ModelData.update_from_df
ModelData.update_from_df(df, vin=False)
Update parameter values from a DataFrame.
Adding devices are not allowed.
3.3.2 andes.core.model.Model
Examples
Take the static PQ as an example, the subclass of Model, PQ, should look like
Since PQ is calling the base class constructors, it is meant to be the final class and not further derived.
It inherits from PQData and Model and must call constructors in the order of PQData and Model. If the
derived class of Model needs to be further derived, it should only derive from Model and use a name
ending with Base. See andes.models.synchronous.genbase.GENBase.
Next, in PQ.__init__, set proper flags to indicate the routines in which the model will be used
self.flags.update({'pflow': True})
Currently, flags pflow and tds are supported. Both are False by default, meaning the model is neither used
in power flow nor in time-domain simulation. A very common pitfall is forgetting to set the flag.
Next, the group name can be provided. A group is a collection of models with common parameters and
variables. Devices' idx of all models in the same group must be unique. To provide a group name, use
self.group = 'StaticLoad'
The group name must be an existing class name in andes.models.group. The model will be added
to the specified group and subject to the variable and parameter policy of the group. If not provided with
a group class name, the model will be placed in the Undefined group.
Next, additional configuration flags can be added. Configuration flags for models are load-time vari-
ables, specifying the behavior of a model. They can be exported to an andes.rc file and automatically
loaded when creating the System. Configuration flags can be used in equation strings, as long as they are
numerical values. To add config flags, use
It is recommended to use OrderedDict instead of dict, although the syntax is verbose. Note that booleans
should be provided as integers (1 or 0), since True or False is interpreted as a string when loaded from
the rc file and will cause an error.
Next, it's time for variables and equations! The PQ class does not have internal variables itself. It uses its
bus parameter to fetch the corresponding a and v variables of buses. Equation wise, it imposes an active
power and a reactive power load equation.
To define external variables from Bus, use
where the e_str attribute is the equation string attribute. u is the connectivity status. Any parameter,
config, service or variable can be used in equation strings.
Three additional scalars can be used in equations: - dae_t for the current simulation time (can be used if
the model has flag tds). - sys_f for system frequency (from system.config.freq). - sys_mva
for system base mva (from system.config.mva).
The above example is overly simplified. Our PQ model wants a feature to switch itself to a constant
impedance if the voltage is out of the range (vmin, vmax). To implement this, we need to introduce
a discrete component called Limiter, which yields three arrays of binary flags, zi, zl, and zu indicating
in-range, below lower-limit, and above upper-limit, respectively.
First, create an attribute vcmp as a Limiter instance
where self.config.pq2z is a flag to turn this feature on or off. After this line, we can use vcmp_zi, vcmp_zl,
and vcmp_zu in other equation strings.
Note that PQ.a.e_str can use the three variables from vcmp even before defining PQ.vcmp, as long as
PQ.vcmp is defined, because vcmp_zi is just a string literal in e_str.
The two equations above implement a piece-wise power injection equation. It selects the original power
demand if within range, and uses the calculated power when out of range.
Finally, to let ANDES pick up the model, the model name needs to be added to models/__init__.py.
Follow the examples in the OrderedDict, where the key is the file name, and the value is the class name.
Attributes
num_params [OrderedDict] {name: instance} of numerical parameters, including in-
ternal and external ones
__init__(system=None, config=None)
Methods
Model.a_reset
Model.a_reset()
Reset addresses to empty and reset flags.address to False.
Model.alter
Model.doc
Model.doc(max_width=78, export='plain')
Retrieve model documentation as a string.
Model.e_clear
Model.e_clear()
Clear equation value arrays associated with all internal variables.
Model.externalize
Model.externalize()
Externalize internal data as a snapshot.
Model.f_numeric
Model.f_numeric(**kwargs)
Custom fcall functions. Modify equations directly.
Model.f_update
Model.f_update()
Evaluate differential equations.
Notes
In-place equations: added to the corresponding DAE array. Non-in-place equations: in-place set
to internal array to overwrite old values (and avoid clearing).
Model.g_numeric
Model.g_numeric(**kwargs)
Custom gcall functions. Modify equations directly.
Model.g_update
Model.g_update()
Evaluate algebraic equations.
Model.get
Model.get_init_order
Model.get_init_order()
Get variable initialization order and send to logger.info.
Model.get_inputs
Model.get_inputs(refresh=False)
Get an OrderedDict of the inputs to the numerical function calls.
Parameters
refresh [bool] Refresh the values in the dictionary. This is only used when the mem-
ory addresses of arrays change. After initialization, all array assignments are in
place. To avoid overhead, refresh should not be used after initialization.
Returns
OrderedDict The input name and value array pairs in an OrderedDict
Notes
dae.t is now a numpy.ndarray which has stable memory. There is no need to refresh dat_t in this
version.
Model.get_md5
Model.get_md5()
Return the md5 hash of concatenated equation strings.
Model.get_times
Model.get_times()
Get event switch_times from TimerParam.
Returns
list A list containing all switching times defined in TimerParams
Model.idx2uid
Model.idx2uid(idx)
Convert idx to the 0-indexed unique index.
Parameters
idx [array-like, numbers, or str] idx of devices
Returns
list A list containing the unique indices of the devices
Model.init
Model.init(routine)
Numerical initialization of a model.
Initialization sequence: 1. Sequential initialization based on the order of definition 2. Use Newton-
Krylov method for iterative initialization 3. Custom init
Model.internalize
Model.internalize()
Internalize snapshot data.
Model.j_numeric
Model.j_numeric(**kwargs)
Custom numeric update functions.
This function should append indices to _ifx, _jfx, and append anonymous functions to _vfx. It is
only called once by store_sparse_pattern.
Model.j_update
Model.j_update()
Update Jacobian elements.
Values are stored to Model.triplets[jname], where jname is a jacobian name.
Returns
None
Model.l_check_eq
Model.l_update_var
Model.list2array
Model.list2array()
Convert all the value attributes v to NumPy arrays.
Value attribute arrays should remain in the same address afterwards. Namely, all assignments to
value array should be operated in place (e.g., with [:]).
Model.mock_refresh_inputs
Model.mock_refresh_inputs()
Use mock data to fill the inputs.
This function is used to generate input data of the desired type to trigger JIT compilation.
Model.numba_jitify
Model.post_init_check
Model.post_init_check()
Post init checking. Warns if values of InitChecker are not True.
Model.precompile
Model.precompile()
Trigger numba compilation for this model.
This function requires the system to be setup, i.e., memory allocated for storage.
Model.prepare
Model.refresh_inputs
Model.refresh_inputs()
This is the helper function to refresh inputs.
The functions collects object references into OrderedDict self._input and self._input_z.
Returns
None
Model.refresh_inputs_arg
Model.refresh_inputs_arg()
Refresh inputs for each function with individual argument list.
Model.register_debug_equation
Model.register_debug_equation(var_name)
Helper function to register a variable for debugging the initialization.
This function needs to be called before calling TDS.init(), and logging level needs to be set to
DEBUG.
Model.s_numeric
Model.s_numeric(**kwargs)
Custom service value functions. Modify Service.v directly.
Model.s_numeric_var
Model.s_numeric_var(**kwargs)
Custom variable service value functions. Modify VarService.v directly.
This custom numerical function is evaluated at each step/iteration before equation update.
Model.s_update
Model.s_update()
Update service equation values.
This function is only evaluated at initialization. Service values are updated sequentially. The v
attribute of services will be assigned at a new memory address.
Model.s_update_post
Model.s_update_post()
Update post-initialization services.
Model.s_update_var
Model.s_update_var()
Update values of andes.core.service.VarService.
Model.set
attr [str, optional, default='v'] The internal attribute of the property to get. v for
values, a for address, and e for equation value.
value [array-like] New values to be set
Returns
bool True when successful.
Model.set_backref
Model.set_in_use
Model.set_in_use()
Set the in_use attribute. Called at the end of System.collect_ref.
This function is overloaded by models with BackRef to disable calls when no model is referencing.
Models with no back references will have internal variable addresses assigned but external addresses
being empty.
For internal equations that have external variables, the row indices will be non-zeros, while the col
indices will be empty, which causes an error when updating Jacobians.
Setting self.in_use to False when len(back_ref_instance.v) == 0 avoids this error. See COI.
Model.solve_iter
Model.solve_iter(name, kwargs)
Solve iterative initialization.
Model.solve_iter_single
Model.store_sparse_pattern
Model.store_sparse_pattern()
Store rows and columns of the non-zeros in the Jacobians for building the sparsity pattern.
This function converts the internal 0-indexed equation/variable address to the numerical addresses
for the loaded system.
Calling sequence: For each Jacobian name, fx, fy, gx and gy, store by a) generated constant and
variable Jacobians c) user-provided constant and variable Jacobians, d) user-provided block con-
stant and variable Jacobians
Notes
If self.n == 0, skipping this function will avoid appending empty lists/arrays and non-empty values,
which, as a combination, is not accepted by kvxopt.spmatrix.
Model.switch_action
Model.switch_action(dae_t)
Call the switch actions.
Parameters
dae_t [float] Current simulation time
Returns
None
Warning: Timer exported from blocks are supposed to work but have not been tested.
Model.v_numeric
Model.v_numeric(**kwargs)
Custom variable initialization function.
Attributes
Model.class_name
property Model.class_name
Return the class name
3.3.3 andes.core.model.ModelCache
class andes.core.model.ModelCache
Class for caching the return value of callback functions.
Check ModelCache.__dict__.keys() for fields.
__init__()
Methods
ModelCache.add_callback
ModelCache.refresh
ModelCache.refresh(name=None)
Refresh the cached values
Parameters
name [str, list, optional] name or list of cached to refresh, by default None for re-
freshing all
3.3.4 andes.core.model.ModelCall
class andes.core.model.ModelCall
Class for storing generated function calls, Jacobian calls, and arguments.
__init__()
Methods
clear_ijv()
zip_ijv(j_full_name) Return a zipped iterator for the rows, cols and vals
for the specified matrix name.
ModelCall.append_ijv
ModelCall.clear_ijv
ModelCall.clear_ijv()
ModelCall.zip_ijv
ModelCall.zip_ijv(j_full_name)
Return a zipped iterator for the rows, cols and vals for the specified matrix name.
3.3.5 Cache
ModelData uses a lightweight class andes.core.model.ModelCache for caching its data as a dictionary
or a pandas DataFrame. Four attributes are defined in ModelData.cache:
• dict: all data in a dictionary with the parameter names as keys and v values as arrays.
• dict_in: the same as dict except that the values are from v_in, the original input.
• df: all data in a pandas DataFrame.
• df_in: the same as df except that the values are from v_in.
Other attributes can be added by registering with cache.add_callback.
If a model is connected to an AC Bus or a DC Node, namely, if bus, bus1, node or node1 exists as
parameter, it must provide the corresponding parameter, Vn, Vn1, Vdcn or Vdcn1, for rated voltages.
Controllers not connected to Bus or Node will have its rated voltages omitted and thus Vb = Vn = 1, unless
one uses andes.core.param.ExtParam to retrieve the bus/node values.
As a rule of thumb, controllers not directly connected to the network shall use system-base per unit for voltage
and current parameters. Controllers (such as a turbine governor) may inherit rated power from controlled
models and thus power parameters will be converted consistently.
Examples
Take the static PQ as an example, the subclass of Model, PQ, should look like
Since PQ is calling the base class constructors, it is meant to be the final class and not further derived.
It inherits from PQData and Model and must call constructors in the order of PQData and Model. If the
derived class of Model needs to be further derived, it should only derive from Model and use a name
ending with Base. See andes.models.synchronous.genbase.GENBase.
Next, in PQ.__init__, set proper flags to indicate the routines in which the model will be used
self.flags.update({'pflow': True})
Currently, flags pflow and tds are supported. Both are False by default, meaning the model is neither used
in power flow nor in time-domain simulation. A very common pitfall is forgetting to set the flag.
Next, the group name can be provided. A group is a collection of models with common parameters and
variables. Devices' idx of all models in the same group must be unique. To provide a group name, use
self.group = 'StaticLoad'
The group name must be an existing class name in andes.models.group. The model will be added
to the specified group and subject to the variable and parameter policy of the group. If not provided with
a group class name, the model will be placed in the Undefined group.
Next, additional configuration flags can be added. Configuration flags for models are load-time vari-
ables, specifying the behavior of a model. They can be exported to an andes.rc file and automatically
loaded when creating the System. Configuration flags can be used in equation strings, as long as they are
numerical values. To add config flags, use
It is recommended to use OrderedDict instead of dict, although the syntax is verbose. Note that booleans
should be provided as integers (1 or 0), since True or False is interpreted as a string when loaded from
the rc file and will cause an error.
Next, it's time for variables and equations! The PQ class does not have internal variables itself. It uses its
bus parameter to fetch the corresponding a and v variables of buses. Equation wise, it imposes an active
power and a reactive power load equation.
To define external variables from Bus, use
where the e_str attribute is the equation string attribute. u is the connectivity status. Any parameter,
config, service or variable can be used in equation strings.
Three additional scalars can be used in equations: - dae_t for the current simulation time (can be used if
the model has flag tds). - sys_f for system frequency (from system.config.freq). - sys_mva
for system base mva (from system.config.mva).
The above example is overly simplified. Our PQ model wants a feature to switch itself to a constant
impedance if the voltage is out of the range (vmin, vmax). To implement this, we need to introduce
a discrete component called Limiter, which yields three arrays of binary flags, zi, zl, and zu indicating
in-range, below lower-limit, and above upper-limit, respectively.
First, create an attribute vcmp as a Limiter instance
where self.config.pq2z is a flag to turn this feature on or off. After this line, we can use vcmp_zi, vcmp_zl,
and vcmp_zu in other equation strings.
Note that PQ.a.e_str can use the three variables from vcmp even before defining PQ.vcmp, as long as
PQ.vcmp is defined, because vcmp_zi is just a string literal in e_str.
The two equations above implement a piece-wise power injection equation. It selects the original power
demand if within range, and uses the calculated power when out of range.
Finally, to let ANDES pick up the model, the model name needs to be added to models/__init__.py.
Follow the examples in the OrderedDict, where the key is the file name, and the value is the class name.
Attributes
num_params [OrderedDict] {name: instance} of numerical parameters, including in-
ternal and external ones
The magic for automatic creation of variables are all hidden in andes.core.model.Model.
__setattr__(), and the code is incredible simple. It sets the name, tex_name, and owner model of the
attribute instance and, more importantly, does the book keeping. In particular, when the attribute is a andes.
core.block.Block subclass, __setattr__ captures the exported instances, recursively, and prepends
the block name to exported ones. All these convenience owe to the dynamic feature of Python.
During the code generation phase, the symbols are created by checking the book-keeping attributes, such as
states, algebs, and attributes in Model.cache.
In the numerical evaluation phase, Model provides a method, andes.core.model.get_inputs(), to
collect the variable value arrays in a dictionary, which can be effortlessly passed as arguments to numerical
functions.
The following Model attributes are commonly used for debugging. If the attribute is an OrderedDict, the keys
are attribute names in str, and corresponding values are the instances.
• params and params_ext, two OrderedDict for internal (both numerical and non-numerical) and
external parameters, respectively.
• num_params for numerical parameters, both internal and external.
• states and algebs, two OrderedDict for state variables and algebraic variables, respectively.
• states_ext and algebs_ext, two OrderedDict for external states and algebraics.
• discrete, an OrderedDict for discrete components.
• blocks, an OrderedDict for blocks.
• services, an OrderedDict for services with v_str.
• services_ext, an OrderedDict for externally retrieved services.
Attributes in Model.cache are additional book-keeping structures for variables, parameters and services. The
following attributes are defined.
• all_vars: all the variables.
• all_vars_names, a list of all variable names.
• all_params, all parameters.
• all_params_names, a list of all parameter names.
• algebs_and_ext, an OrderedDict of internal and external algebraic variables.
• states_and_ext, an OrderedDict of internal and external differential variables.
• services_and_ext, an OrderedDict of internal and external service variables.
• vars_int, an OrderedDict of all internal variables, states and then algebs.
• vars_ext, an OrderedDict of all external variables, states and then algebs.
Equation Generation
Model.syms, an instance of SymProcessor, handles the symbolic to numeric generation when called.
The equation generation is a multi-step process with symbol preparation, equation generation, Jacobian gener-
ation, initializer generation, and pretty print generation.
class andes.core.SymProcessor(parent)
A helper class for symbolic processing and code generation.
Parameters
Jacobian Storage
Using the .jacobian method on sympy.Matrix, the symbolic Jacobians can be easily obtained. The
complexity lies in the storage of the Jacobian elements. Observed that the Jacobian equation generation happens
before any system is loaded, thus only the variable indices in the variable array is available. For each non-zero
item in each Jacobian matrix, ANDES stores the equation index, variable index, and the Jacobian value (either
a constant number or a callable function returning an array).
Note that, again, a non-zero entry in a Jacobian matrix can be either a constant or an expression. For efficiency,
constant numbers and lambdified callables are stored separately. Constant numbers, therefore, can be loaded
into the sparse matrix pattern when a particular system is given.
Warning: Data structure for the Jacobian storage has changed. Pending documentation update. Please
check andes.core.common.JacTriplet class for more details.
The triplets, the equation (row) index, variable (column) index, and values (constant numbers or callable) are
stored in Model attributes with the name of _{i, j, v}{Jacobian Name}{c or None}, where
{i, j, v} is a single character for row, column or value, {Jacobian Name} is a two-character Jacobian
name chosen from fx, fy, gx, and gy, and {c or None} is either character c or no character,
indicating whether it corresponds to the constants or non-constants in the Jacobian.
For example, the triplets for the constants in Jacobian gy are stored in _igyc, _jgyc, and _vgyc.
In terms of the non-constant entries in Jacobians, the callable functions are stored in the corresponding
_v{Jacobian Name} array. Note the differences between, for example, _vgy an _vgyc: _vgy is a
list of callables, while _vgyc is a list of constant numbers.
When a specific system is loaded and the addresses are assigned to variables, the abstract Jacobian triplets, more
specifically, the rows and columns, are replaced with the array of addresses. The new addresses and values will
be stored in Model attributes with the names {i, j, v}{Jacobian Name}{c or None}. Note that
there is no underscore for the concrete Jacobian triplets.
For example, if model PV has a list of variables [p, q, a, v] . The equation associated with p is - u
* p0, and the equation associated with q is u * (v0 - v). Therefore, the derivative of equation v0 -
v over v is -u. Note that u is unknown at generation time, thus the value is NOT a constant and should to go
vgy.
The values in _igy, _jgy and _vgy contains, respectively, 1, 3, and a lambda function which returns -u.
When a specific system is loaded, for example, a 5-bus system, the addresses for the q and v are [11, 13,
15, and [5, 7, 9]. PV.igy and PV.jgy will thus query the corresponding address list based on PV.
_igy and PV._jgy and store [11, 13, 15, and [5, 7, 9].
Initialization
Value providers such as services and DAE variables need to be initialized. Services are initialized before any
DAE variable. Both Services and DAE Variables are initialized sequentially in the order of declaration.
Each Service, in addition to the standard v_str for symbolic initialization, provides a v_numeric hook for
specifying a custom function for initialization. Custom initialization functions for DAE variables, are lumped
in a single function in Model.v_numeric.
ANDES has an experimental Newton-Krylov method based iterative initialization. All DAE variables with
v_iter will be initialized using the iterative approach
Addition numerical equations are allowed to complete the "hybrid symbolic-numeric" framework. Numerical
function calls are useful when the model DAE is non-standard or hard to be generalized. Since the symbolic-
to-numeric generation is an additional layer on top of the numerical simulation, it is fundamentally the same as
user-provided numerical function calls.
ANDES provides the following hook functions in each Model subclass for custom numerical functions:
• v_numeric: custom initialization function
• s_numeric: custom service value function
• g_numeric: custom algebraic equations; update the e of the corresponding variable.
• f_numeric: custom differential equations; update the e of the corresponding variable.
• j_numeric: custom Jacobian equations; the function should append to _i, _j and _v structures.
For most models, numerical function calls are unnecessary and not recommended as it increases code com-
plexity. However, when the data structure or the DAE are difficult to generalize in the symbolic framework,
the numerical equations can be used.
For interested readers, see the COI symbolic implementation which calculated the center-of-inertia speed of
generators. The COI could have been implemented numerically with for loops instead of NumReduce, Num-
Repeat and external variables.
ANDES contains three types of atom classes for building DAE models. These types are parameter, variable
and service.
Before addressing specific atom classes, the terminology v-provider, and e-provider are discussed. A value
provider class (or v-provider for short) references any class with a member attribute named v, which should be
a list or a 1-dimensional array of values. For example, all parameter classes are v-providers, since a parameter
class should provide values for that parameter.
Note: In fact, all types of atom classes are v-providers, meaning that an instance of an atom class must contain
values.
The values in the v attribute of a particular instance are values that will substitute the instance for computation.
If in a model, one has a parameter
self.v0 = NumParam()
self.b = NumParam()
While computing v0 ** 2 * b, v0 and b will be substituted with the values in self.v0.v and self.b.v.
Sharing this interface v allows interoperability among parameters and variables and services. In the above
example, if one defines v0 as a ConstService instance, such as
self.v0 = ConstService(v_str='1.0')
Similarly, an equation provider class (or e-provider) references any class with a member attribute named e,
which should be a 1-dimensional array of values. The values in the e array are the results from the equation
and will be summed to the numerical DAE at the addresses specified by the attribute a.
The addresses of the corresponding voltage variables will be retrieved into self.v.a, and the equation evaluation
results will be stored in self.v.e
3.5 Parameters
3.5.1 Background
Parameter is a type of building atom for DAE models. Most parameters are read directly from an input file
and passed to equation, and other parameters can be calculated from existing parameters.
The base class for parameters in ANDES is BaseParam, which defines interfaces for adding values and checking
the number of values. BaseParam has its values stored in a plain list, the member attribute v. Subclasses such
as NumParam stores values using a NumPy ndarray.
An overview of supported parameters is given below.
andes.core.param.BaseParam
Warning: The most distinct feature of BaseParam, DataParam and IdxParam is that values are
stored in a list without conversion to array. BaseParam, DataParam or IdxParam are not allowed in
equations.
Attributes
v [list] A list holding all the values. The BaseParam class does not convert the v
attribute into NumPy arrays.
property [dict] A dict containing the truth values of the model properties.
Methods
BaseParam.add
BaseParam.add(value=None)
Add a new parameter value (from a new device of the owner model) to the v list.
Parameters
value [str or float, optional] Parameter value of the new element. If None, the default
will be used.
Notes
BaseParam.get_names
BaseParam.get_names()
Return self.name in a list.
This is a helper function to provide the same API as blocks or discrete components.
Returns
list A list only containing the name of the parameter
BaseParam.get_property
BaseParam.get_property(property_name: str)
Check the boolean value of the given property. If the property does not exist in the dictionary,
False will be returned.
Parameters
property_name [str] Property name
Returns
The truth value of the property.
BaseParam.set
BaseParam.set_all
BaseParam.set_all(attr, value)
Set attributes of the BaseParam class to new values for all positions.
Parameters
attr ['v', 'vin'] Name of the attribute to be set
value [list of str, float or int] New values
Attributes
BaseParam.class_name
property BaseParam.class_name
Return the class name.
BaseParam.n
property BaseParam.n
Return the count of elements in the value array.
andes.core.param.DataParam
Methods
DataParam.add
DataParam.add(value=None)
Add a new parameter value (from a new device of the owner model) to the v list.
Parameters
value [str or float, optional] Parameter value of the new element. If None, the default
will be used.
Notes
DataParam.get_names
DataParam.get_names()
Return self.name in a list.
This is a helper function to provide the same API as blocks or discrete components.
Returns
list A list only containing the name of the parameter
DataParam.get_property
DataParam.get_property(property_name: str)
Check the boolean value of the given property. If the property does not exist in the dictionary,
False will be returned.
Parameters
property_name [str] Property name
Returns
The truth value of the property.
DataParam.set
DataParam.set_all
DataParam.set_all(attr, value)
Set attributes of the BaseParam class to new values for all positions.
Parameters
attr ['v', 'vin'] Name of the attribute to be set
value [list of str, float or int] New values
Attributes
DataParam.class_name
property DataParam.class_name
Return the class name.
DataParam.n
property DataParam.n
Return the count of elements in the value array.
andes.core.param.IdxParam
Notes
This will be useful when, for example, one connects two TGs to one SynGen.
Examples
class PQModel(...):
def __init__(...):
...
self.bus = IdxParam(model='Bus')
Methods
IdxParam.add
IdxParam.add(value=None)
Add a new parameter value (from a new device of the owner model) to the v list.
Parameters
value [str or float, optional] Parameter value of the new element. If None, the default
will be used.
Notes
IdxParam.get_names
IdxParam.get_names()
Return self.name in a list.
This is a helper function to provide the same API as blocks or discrete components.
Returns
list A list only containing the name of the parameter
IdxParam.get_property
IdxParam.get_property(property_name: str)
Check the boolean value of the given property. If the property does not exist in the dictionary,
False will be returned.
Parameters
property_name [str] Property name
Returns
The truth value of the property.
IdxParam.set
IdxParam.set_all
IdxParam.set_all(attr, value)
Set attributes of the BaseParam class to new values for all positions.
Parameters
attr ['v', 'vin'] Name of the attribute to be set
value [list of str, float or int] New values
Attributes
IdxParam.class_name
property IdxParam.class_name
Return the class name.
IdxParam.n
property IdxParam.n
Return the count of elements in the value array.
andes.core.param.NumParam
non_zero [bool] True if this parameter must be non-zero. non_zero can be combined
with non_positive or non_negative.
non_positive [bool] True if this parameter must be non-positive.
non_negative [bool] True if this parameter must be non-negative.
mandatory [bool] True if this parameter must not be None.
power [bool] True if this parameter is a power per-unit quantity under the device base.
iconvert [callable] Callable to convert input data from excel or others to the internal v
field.
oconvert [callable] Callable to convert input data from internal type to a serializable
type.
ipower [bool] True if this parameter is an inverse-power per-unit quantity under the
device base.
voltage [bool] True if the parameter is a voltage pu quantity under the device base.
current [bool] True if the parameter is a current pu quantity under the device base.
z [bool] True if the parameter is an AC impedance pu quantity under the device base.
y [bool] True if the parameter is an AC admittance pu quantity under the device base.
r [bool] True if the parameter is a DC resistance pu quantity under the device base.
g [bool] True if the parameter is a DC conductance pu quantity under the device base.
dc_current [bool] True if the parameter is a DC current pu quantity under device base.
dc_voltage [bool] True if the parameter is a DC voltage pu quantity under device base.
__init__(default: typing.Optional[typing.Union[float, str, typing.Callable]] = None, name:
typing.Optional[str] = None, tex_name: typing.Optional[str] = None, info:
typing.Optional[str] = None, unit: typing.Optional[str] = None, vrange:
typing.Optional[typing.Union[typing.List, typing.Tuple]] = None, vtype:
typing.Optional[typing.Type] = <class 'float'>, iconvert: typing.Optional[typing.Callable]
= None, oconvert: typing.Optional[typing.Callable] = None, non_zero: bool = False,
non_positive: bool = False, non_negative: bool = False, mandatory: bool = False, power:
bool = False, ipower: bool = False, voltage: bool = False, current: bool = False, z: bool =
False, y: bool = False, r: bool = False, g: bool = False, dc_voltage: bool = False,
dc_current: bool = False, export: bool = True)
Methods
NumParam.add
NumParam.add(value=None)
Add a value to the parameter value list.
In addition to BaseParam.add, this method checks for non-zero property and reset to default
if is zero.
See also:
NumParam.get_names
NumParam.get_names()
Return self.name in a list.
This is a helper function to provide the same API as blocks or discrete components.
Returns
list A list only containing the name of the parameter
NumParam.get_property
NumParam.get_property(property_name: str)
Check the boolean value of the given property. If the property does not exist in the dictionary,
False will be returned.
Parameters
property_name [str] Property name
Returns
The truth value of the property.
NumParam.restore
NumParam.restore()
Restore parameter to the original input by copying self.vin to self.v.
pu_coeff will not be overwritten.
NumParam.set
NumParam.set_all
NumParam.set_all(attr, value)
Set attributes of the BaseParam class to new values for all positions.
Parameters
attr ['v', 'vin'] Name of the attribute to be set
value [list of str, float or int] New values
NumParam.set_pu_coeff
NumParam.set_pu_coeff(coeff)
Store p.u. conversion coefficient into self.pu_coeff and calculate the system-base per unit
with self.v = self.vin * self.pu_coeff.
This function must be called after self.to_array.
Parameters
coeff [np.ndarray] An array with the pu conversion coefficients
NumParam.to_array
NumParam.to_array()
Converts field v to the NumPy array type. to enable array-based calculation.
Must be called after adding all elements. Store a copy of original input values to field vin. Set
pu_coeff to all ones.
Warning: After this call, add will not be allowed to avoid unexpected issues.
Attributes
NumParam.class_name
property NumParam.class_name
Return the class name.
NumParam.n
property NumParam.n
Return the count of elements in the value array.
andes.core.param.ExtParam
Attributes
parent_model [Model] The parent model providing the original parameter.
__init__(model: str, src: str, indexer=None, vtype=<class 'float'>, allow_none=False, default=0.0,
**kwargs)
Methods
ExtParam.add
ExtParam.add(value=None)
ExtParam has an empty add method.
ExtParam.get_names
ExtParam.get_names()
Return self.name in a list.
This is a helper function to provide the same API as blocks or discrete components.
Returns
list A list only containing the name of the parameter
ExtParam.get_property
ExtParam.get_property(property_name: str)
Check the boolean value of the given property. If the property does not exist in the dictionary,
False will be returned.
Parameters
property_name [str] Property name
Returns
The truth value of the property.
ExtParam.link_external
ExtParam.link_external(ext_model)
Update parameter values provided by external models. This needs to be called before pu conversion.
Parameters
ext_model [Model, Group] Instance of the parent model or group, provided by the
System calling this method.
ExtParam.restore
ExtParam.restore()
ExtParam has an empty restore method
ExtParam.set
ExtParam.set_all
ExtParam.set_all(attr, value)
Set attributes of the BaseParam class to new values for all positions.
Parameters
attr ['v', 'vin'] Name of the attribute to be set
value [list of str, float or int] New values
ExtParam.set_pu_coeff
ExtParam.set_pu_coeff(coeff)
Store p.u. conversion coefficient into self.pu_coeff and calculate the system-base per unit
with self.v = self.vin * self.pu_coeff.
This function must be called after self.to_array.
Parameters
coeff [np.ndarray] An array with the pu conversion coefficients
ExtParam.to_array
ExtParam.to_array()
Convert to array when d_type is not str
Attributes
ExtParam.class_name
property ExtParam.class_name
Return the class name.
ExtParam.n
property ExtParam.n
Return the count of elements in the value array.
andes.core.param.TimerParam
Examples
A connectivity status toggle class Toggle takes a parameter t for the toggle time. Inside Toggle.
__init__, one would have
self.t = TimerParam()
The Toggle class also needs to define a method for togging the connectivity status
self.t.callback = self._u_switch
Methods
TimerParam.add
TimerParam.add(value=None)
Add a value to the parameter value list.
In addition to BaseParam.add, this method checks for non-zero property and reset to default
if is zero.
See also:
TimerParam.get_names
TimerParam.get_names()
Return self.name in a list.
This is a helper function to provide the same API as blocks or discrete components.
Returns
list A list only containing the name of the parameter
TimerParam.get_property
TimerParam.get_property(property_name: str)
Check the boolean value of the given property. If the property does not exist in the dictionary,
False will be returned.
Parameters
property_name [str] Property name
Returns
The truth value of the property.
TimerParam.is_time
TimerParam.is_time(dae_t)
Element-wise check if the DAE time is the same as the parameter value. The current implemen-
tation uses np.equal.
Parameters
dae_t [float] Current simulation time
Returns
np.ndarray The array containing the truth value of if the DAE time is close to the
parameter value.
Notes
The previous implementation with np.isclose with default rtol=1e-5 mistakes the immediate pre-
and post-event time as in-event when simulation time is greater than 10.
TimerParam.restore
TimerParam.restore()
Restore parameter to the original input by copying self.vin to self.v.
pu_coeff will not be overwritten.
TimerParam.set
TimerParam.set_all
TimerParam.set_all(attr, value)
Set attributes of the BaseParam class to new values for all positions.
Parameters
attr ['v', 'vin'] Name of the attribute to be set
value [list of str, float or int] New values
TimerParam.set_pu_coeff
TimerParam.set_pu_coeff(coeff)
Store p.u. conversion coefficient into self.pu_coeff and calculate the system-base per unit
with self.v = self.vin * self.pu_coeff.
This function must be called after self.to_array.
Parameters
coeff [np.ndarray] An array with the pu conversion coefficients
TimerParam.to_array
TimerParam.to_array()
Converts field v to the NumPy array type. to enable array-based calculation.
Must be called after adding all elements. Store a copy of original input values to field vin. Set
pu_coeff to all ones.
Warning: After this call, add will not be allowed to avoid unexpected issues.
Attributes
TimerParam.class_name
property TimerParam.class_name
Return the class name.
TimerParam.n
property TimerParam.n
Return the count of elements in the value array.
3.6 Variables
DAE Variables, or variables for short, are unknowns to be solved using numerical or analytical methods. A
variable stores values, equation values, and addresses in the DAE array. The base class for variables is BaseVar.
In this subsection, BaseVar is used to represent any subclass of VarBase list in the table below.
3.6.1 andes.core.var.BaseVar
Methods
get_names()
BaseVar.get_names
BaseVar.get_names()
BaseVar.reset
BaseVar.reset()
Reset the internal numpy arrays and flags.
BaseVar.set_address
BaseVar.set_arrays
Attributes
class_name
BaseVar.class_name
property BaseVar.class_name
3.6.2 andes.core.var.ExtVar
v_code [str] Variable code string; copied from the parent instance.
__init__(model: str, src: str, indexer: Optional[Union[List, numpy.ndarray,
andes.core.param.BaseParam, andes.core.service.BaseService]] = None, allow_none:
Optional[bool] = False, name: Optional[str] = None, tex_name: Optional[str] = None,
ename: Optional[str] = None, tex_ename: Optional[str] = None, info: Optional[str] =
None, unit: Optional[str] = None, v_str: Optional[Union[str, float]] = None, v_iter:
Optional[str] = None, e_str: Optional[str] = None, v_setter: Optional[bool] = False,
e_setter: Optional[bool] = False, addressable: Optional[bool] = True, export:
Optional[bool] = True, diag_eps: Optional[float] = 0.0, is_input: Optional[bool] = False)
Methods
get_names()
ExtVar.get_names
ExtVar.get_names()
ExtVar.link_external
ExtVar.link_external(ext_model)
Update variable addresses provided by external models
This method sets attributes including parent_model, parent_instance, uid, a, n, e_code and v_code.
It initializes the e and v to zero.
Parameters
ext_model [Model] Instance of the parent model
Returns
None
Warning: link_external does not check if the ExtVar type is the same as the original variable
to reduce performance overhead. It will be a silent error (a dimension too small error from
dae.build_pattern) if a model uses ExtAlgeb to access a State, or vice versa.
ExtVar.reset
ExtVar.reset()
Reset the internal numpy arrays and flags.
ExtVar.set_address
ExtVar.set_address(addr, contiguous=False)
Assigns address for equation RHS.
ExtVar.set_arrays
Attributes
class_name
ExtVar.class_name
property ExtVar.class_name
3.6.3 andes.core.var.State
t_const [BaseParam, DummyValue] Left-hand time constant for the differential equa-
tion. They will be collected to array dae.Tf. Time constants will not be used
when evaluating the right-hand side specified in e_str but will be applied to the
left-hand side.
check_init [bool] True to check if the equation right-hand-side is zero initially. Dis-
abling the checking can be used for integrators when the initial input may not be
zero.
Examples
M ω̇ = τm − τe − D(ω − 1)
Note that self.M, the inertia parameter is given through t_const and is not part of e_str.
Attributes
e_code [str] Equation code string, equals string literal f
v_code [str] Variable code string, equals string literal x
__init__(name: Optional[str] = None, tex_name: Optional[str] = None, info: Optional[str] = None,
unit: Optional[str] = None, v_str: Optional[Union[str, float]] = None, v_iter:
Optional[str] = None, e_str: Optional[str] = None, discrete:
Optional[andes.core.discrete.Discrete] = None, t_const:
Optional[Union[andes.core.param.BaseParam, andes.core.common.DummyValue,
andes.core.service.BaseService]] = None, check_init: Optional[bool] = True, v_setter:
Optional[bool] = False, e_setter: Optional[bool] = False, addressable: Optional[bool] =
True, export: Optional[bool] = True, diag_eps: Optional[float] = 0.0, deps:
Optional[List] = None)
Methods
get_names()
State.get_names
State.get_names()
State.reset
State.reset()
Reset the internal numpy arrays and flags.
State.set_address
State.set_arrays
Attributes
class_name
e_code
v_code
State.class_name
property State.class_name
State.e_code
State.e_code = 'f'
State.v_code
State.v_code = 'x'
3.6.4 andes.core.var.Algeb
Examples
Methods
get_names()
Algeb.get_names
Algeb.get_names()
Algeb.reset
Algeb.reset()
Reset the internal numpy arrays and flags.
Algeb.set_address
Algeb.set_arrays
Attributes
class_name
e_code
v_code
Algeb.class_name
property Algeb.class_name
Algeb.e_code
Algeb.e_code = 'g'
Algeb.v_code
Algeb.v_code = 'y'
3.6.5 andes.core.var.ExtState
Warning: ExtState is not allowed to set t_const, as it may conflict with the source State
variable.
Only in rare cases should one set e_str for ExtState. The t_const of the source State variable
is used.
Methods
get_names()
ExtState.get_names
ExtState.get_names()
ExtState.link_external
ExtState.link_external(ext_model)
Update variable addresses provided by external models
This method sets attributes including parent_model, parent_instance, uid, a, n, e_code and v_code.
It initializes the e and v to zero.
Parameters
ext_model [Model] Instance of the parent model
Returns
None
Warning: link_external does not check if the ExtVar type is the same as the original variable
to reduce performance overhead. It will be a silent error (a dimension too small error from
dae.build_pattern) if a model uses ExtAlgeb to access a State, or vice versa.
ExtState.reset
ExtState.reset()
Reset the internal numpy arrays and flags.
ExtState.set_address
ExtState.set_address(addr, contiguous=False)
Assigns address for equation RHS.
ExtState.set_arrays
Attributes
class_name
e_code
r_code
t_const
v_code
ExtState.class_name
property ExtState.class_name
ExtState.e_code
ExtState.e_code = 'f'
ExtState.r_code
ExtState.r_code = 'h'
ExtState.t_const
ExtState.t_const = None
ExtState.v_code
ExtState.v_code = 'x'
3.6.6 andes.core.var.ExtAlgeb
Methods
get_names()
ExtAlgeb.get_names
ExtAlgeb.get_names()
ExtAlgeb.link_external
ExtAlgeb.link_external(ext_model)
Update variable addresses provided by external models
This method sets attributes including parent_model, parent_instance, uid, a, n, e_code and v_code.
It initializes the e and v to zero.
Parameters
ext_model [Model] Instance of the parent model
Returns
None
Warning: link_external does not check if the ExtVar type is the same as the original variable
to reduce performance overhead. It will be a silent error (a dimension too small error from
dae.build_pattern) if a model uses ExtAlgeb to access a State, or vice versa.
ExtAlgeb.reset
ExtAlgeb.reset()
Reset the internal numpy arrays and flags.
ExtAlgeb.set_address
ExtAlgeb.set_address(addr, contiguous=False)
Assigns address for equation RHS.
ExtAlgeb.set_arrays
Attributes
class_name
e_code
r_code
v_code
ExtAlgeb.class_name
property ExtAlgeb.class_name
ExtAlgeb.e_code
ExtAlgeb.e_code = 'g'
ExtAlgeb.r_code
ExtAlgeb.r_code = 'i'
ExtAlgeb.v_code
ExtAlgeb.v_code = 'y'
3.6.7 andes.core.var.AliasState
Methods
get_names()
AliasState.get_names
AliasState.get_names()
AliasState.link_external
AliasState.link_external(ext_model)
Update variable addresses provided by external models
This method sets attributes including parent_model, parent_instance, uid, a, n, e_code and v_code.
It initializes the e and v to zero.
Parameters
ext_model [Model] Instance of the parent model
Returns
None
Warning: link_external does not check if the ExtVar type is the same as the original variable
to reduce performance overhead. It will be a silent error (a dimension too small error from
dae.build_pattern) if a model uses ExtAlgeb to access a State, or vice versa.
AliasState.reset
AliasState.reset()
Reset the internal numpy arrays and flags.
AliasState.set_address
AliasState.set_address(addr, contiguous=False)
Assigns address for equation RHS.
AliasState.set_arrays
Attributes
class_name
e_code
r_code
t_const
v_code
AliasState.class_name
property AliasState.class_name
AliasState.e_code
AliasState.e_code = 'f'
AliasState.r_code
AliasState.r_code = 'h'
AliasState.t_const
AliasState.t_const = None
AliasState.v_code
AliasState.v_code = 'x'
3.6.8 andes.core.var.AliasAlgeb
Methods
get_names()
AliasAlgeb.get_names
AliasAlgeb.get_names()
AliasAlgeb.link_external
AliasAlgeb.link_external(ext_model)
Update variable addresses provided by external models
This method sets attributes including parent_model, parent_instance, uid, a, n, e_code and v_code.
It initializes the e and v to zero.
Parameters
ext_model [Model] Instance of the parent model
Returns
None
Warning: link_external does not check if the ExtVar type is the same as the original variable
to reduce performance overhead. It will be a silent error (a dimension too small error from
dae.build_pattern) if a model uses ExtAlgeb to access a State, or vice versa.
AliasAlgeb.reset
AliasAlgeb.reset()
Reset the internal numpy arrays and flags.
AliasAlgeb.set_address
AliasAlgeb.set_address(addr, contiguous=False)
Assigns address for equation RHS.
AliasAlgeb.set_arrays
Attributes
class_name
e_code
r_code
v_code
AliasAlgeb.class_name
property AliasAlgeb.class_name
AliasAlgeb.e_code
AliasAlgeb.e_code = 'g'
AliasAlgeb.r_code
AliasAlgeb.r_code = 'i'
AliasAlgeb.v_code
AliasAlgeb.v_code = 'y'
Note that equations associated with state variables are in the form of Mẋ = f(x, y), where x are the differential
variables, y are the algebraic variables, and M is the mass matrix, and f are the right-hand side of differential
equations. Equations associated with algebraic variables take the form of 0 = g, where g are the equation
right-hand side
BaseVar has two types: the differential variable type State and the algebraic variable type Algeb. State variables
are described by differential equations, whereas algebraic variables are described by algebraic equations. State
variables can only change continuously, while algebraic variables can be discontinuous.
Based on the model the variable is defined, variables can be internal or external. Most variables are internal
and only appear in equations in the same model. Some models have "public" variables that can be accessed by
other models. For example, a Bus defines v for the voltage magnitude. Each device attached to a particular bus
needs to access the value and impose the reactive power injection. It can be done with ExtAlgeb or ExtState,
which links with an existing variable from a model or a group.
Subclasses of BaseVar are value providers and equation providers. Each BaseVar has member attributes v and
e for variable values and equation values, respectively. The initial value of v is set by the initialization routine,
and the initial value of e is set to zero. In the process of power flow calculation or time domain simulation, v
is not directly modifiable by models but rather updated after solving non-linear equations. e is updated by the
models and summed up before solving equations.
Each BaseVar also stores addresses of this variable, for all devices, in its member attribute a. The addresses
are 0-based indices into the numerical DAE array, f or g, based on the variable type.
For example, Bus has self.a = Algeb() as the voltage phase angle variable. For a 5-bus system, Bus.
a.a stores the addresses of the a variable for all the five Bus devices. Conventionally, Bus.a.a will be assigned
np.array([0, 1, 2, 3, 4]).
The most important feature of the symbolic framework is allowing to define equations using strings. There are
three types of strings for a variable, stored in the following member attributes, respectively:
• v_str: equation string for explicit initialization in the form of v = v_str(x, y).
• v_iter: equation string for implicit initialization in the form of v_iter(x, y) = 0
• e_str: equation string for (full or part of) the differential or algebraic equation.
The difference between v_str and v_iter should be clearly noted. v_str evaluates directly into the initial value,
while all v_iter equations are solved numerically using the Newton-Krylov iterative method.
ANDES adopts a decentralized architecture which provides each model a copy of variable values before equa-
tion evaluation. This architecture allows to parallelize the equation evaluation (in theory, or in practice if
one works round the Python GIL). However, this architecture requires a coherent protocol for updating the
DAE arrays and the BaseVar arrays. More specifically, how the variable and equations values from model
VarBase should be summed up or forcefully set at the DAE arrays needs to be defined.
The protocol is relevant when a model defines subclasses of BaseVar that are supposed to be "public". Other
models share this variable with ExtAlgeb or ExtState.
By default, all v and e at the same address are summed up. This is the most common case, such as a Bus
connected by multiple devices: power injections from devices should be summed up.
In addition, BaseVar provides two flags, v_setter and e_setter, for cases when one VarBase needs to overwrite
the variable or equation values.
BaseVar have special flags for handling value initialization and equation values. This is only relevant for public
or external variables. The v_setter is used to indicate whether a particular BaseVar instance sets the initial value.
The e_setter flag indicates whether the equation associated with a BaseVar sets the equation value.
The v_setter flag is checked when collecting data from models to the numerical DAE array. If v_setter is False,
variable values of the same address will be added. If one of the variable or external variable has v_setter is
True, it will, at the end, set the values in the DAE array to its value. Only one BaseVar of the same address is
allowed to have v_setter == True.
A Bus is allowed to default the initial voltage magnitude to 1 and the voltage phase angle to 0. If a PV device
is connected to a Bus device, the PV should be allowed to override the voltage initial value with the voltage set
point.
In Bus.__init__(), one has
self.v = Algeb(v_str='1')
self.v0 = Param()
self.bus = IdxParam(model='Bus')
self.v = ExtAlgeb(src='v',
model='Bus',
indexer=self.bus,
v_str='v0',
v_setter=True)
where an ExtAlgeb is defined to access Bus.v using indexer self.bus. The v_str line sets the initial value to v0.
In the variable initialization phase for PV, PV.v.v is set to v0.
During the value collection into DAE.y by the System class, PV.v, as a final v_setter, will overwrite the voltage
magnitude for Bus devices with the indices provided in PV.bus.
3.7 Services
Services are helper variables outside the DAE variable list. Services are most often used for storing intermediate
constants but can be used for special operations to work around restrictions in the symbolic framework. Services
are value providers, meaning each service has an attribute v for storing service values. The base class of services
is :py:mod`BaseService`, and the supported services are listed as follows.
3.7.1 andes.core.service.BaseService
Methods
BaseService.assign_memory
BaseService.assign_memory(n)
Assign memory for self.v and set the array to zero.
Parameters
n [int] Number of elements of the value array. Provided by caller (Model.list2array).
BaseService.get_names
BaseService.get_names()
Return name in a list
Returns
list A list only containing the name of the service variable
Attributes
BaseService.class_name
property BaseService.class_name
Return the class name
BaseService.n
property BaseService.n
Return the count of values in self.v.
Needs to be overloaded if v of subclasses is not a 1-dimensional array.
Returns
int The count of elements in this variable
3.7.2 andes.core.service.OperationService
NumReduce Service for Reducing linearly stored 2-D services into 1-D
NumRepeat Service for repeating 1-D NumParam/ v-array following a
sub-pattern
IdxRepeat Service for repeating 1-D IdxParam/ v-list following a
sub-pattern
Methods
OperationService.assign_memory
OperationService.assign_memory(n)
Assign memory for self.v and set the array to zero.
Parameters
n [int] Number of elements of the value array. Provided by caller (Model.list2array).
OperationService.get_names
OperationService.get_names()
Return name in a list
Returns
list A list only containing the name of the service variable
Attributes
OperationService.class_name
property OperationService.class_name
Return the class name
OperationService.n
property OperationService.n
Return the count of values in self.v.
Needs to be overloaded if v of subclasses is not a 1-dimensional array.
Returns
int The count of elements in this variable
OperationService.v
property OperationService.v
Return values stored in self._v. May be overloaded by subclasses.
Class Description
ConstService Internal service for constant values.
VarService Variable service updated at each iteration before equations.
ExtService External service for retrieving values from value providers.
PostInitService Constant service evaluated after TDS initialization
NumReduce The service type for reducing linear 2-D arrays into 1-D arrays
NumRepeat The service type for repeating a 1-D array to linear 2-D arrays
IdxRepeat The service type for repeating a 1-D list to linear 2-D list
EventFlag Service type for flagging changes in inputs as an event
VarHold Hold input value when a hold signal is active
ExtendedEvent Extend an event signal for a given period of time
DataSelect Select optional str data if provided or use the fallback
NumSelect Select optional numerical data if provided
DeviceFinder Finds or creates devices linked to the given devices
BackRef Collects idx-es for the backward references
RefFlatten Converts BackRef list of lists into a 1-D list
InitChecker Checks initial values against typical values
FlagValue Flags values that equals the given value
Replace Replace values that returns True for the given lambda func
The most commonly used service is ConstService. It is used to store an array of constants, whose value is
evaluated from a provided symbolic string. They are only evaluated once in the model initialization phase,
ahead of variable initialization. ConstService comes handy when one wants to calculate intermediate constants
from parameters.
For example, a turbine governor has a NumParam R for the droop. ConstService allows to calculate the inverse
of the droop, the gain, and use it in equations. The snippet from a turbine governor's __init__() may look
like
self.R = NumParam()
self.G = ConstService(v_str='u/R')
where u is the online status parameter. The model can thus use G in subsequent variable or equation strings.
class andes.core.service.ConstService(v_str: Optional[str] = None, v_numeric:
Optional[Callable] = None, vtype: Optional[type]
= None, name: Optional[str] = None, tex_name:
Optional[str] = None, info: Optional[str] = None,
unit: Optional[str] = None)
A type of Service that stays constant once initialized.
ConstService are usually constants calculated from parameters. They are only evaluated once in the
initialization phase before variables are initialized. Therefore, uninitialized variables must not be used
in v_str`.
ConstService are evaluated in sequence after getting external variables and parameters and before ini-
tializing internal variables.
Parameters
name [str] Name of the ConstService
v_str [str] An equation string to calculate the variable value.
v_numeric [Callable, optional] A callable which returns the value of the ConstService
v_type: type, optional, default to float Type of element in the value array in float or
complex
Attributes
v [array-like or a scalar] ConstService value
class andes.core.service.VarService(v_str: Optional[str] = None, v_numeric:
Optional[Callable] = None, vtype: Optional[type] =
None, name: Optional[str] = None, tex_name:
Optional[str] = None, info: Optional[str] = None, unit:
Optional[str] = None, sequential: Optional[bool] =
True)
Variable service that gets updated in each step/iteration before computing the residual equations. As
a results, variable values from the k-th step are used to compute a VarService that will be used to
compute the residual for the (k+1)-th step.
This class is useful when one has non-differentiable algebraic equations, which make use of abs(), re
and im. Instead of creating Algeb, one can put the equation in VarService, which will be updated before
solving algebraic equations.
Parameters
sequential [bool, optional, default to True] True if this VarService depends on previ-
ously defined VarService and should be evaluated in sequence. False if this VarSer-
vice only uses known variables.
Warning: VarService is not solved with other algebraic equations, meaning that there is one step
"delay" between the algebraic variables and VarService. Use an algebraic variable whenever possible.
Examples
In ESST3A model, the voltage and current sensors (vd + jvq), (Id + jIq) estimate the sensed VE using
equation
self.VE = VarService(
tex_name='V_E', info='VE', v_str='Abs(KPC*(vd + 1j*vq) + 1j*(KI +
KPC*XL)*(Id + 1j*Iq))', )
Examples
In ESST3A model, the vf variable is initialized followed by other variables. One can store the initial vf
into vf0 so that equation vf - vf0 = 0 will hold.
Since all ConstService are evaluated before equation evaluation, without using PostInitService, one will
need to create lots of ConstService to store values in the initialization path towards vf0, in order to cor-
rectly initialize vf.
Service constants whose value is retrieved from an external model or group. Using ExtService is similar to
using external variables. The values of ExtService will be retrieved once during the initialization phase before
ConstService evaluation.
For example, a synchronous generator needs to retrieve the p and q values from static generators for initial-
ization. ExtService is used for this purpose. In the __init__() of a synchronous generator model, one can
define the following to retrieve StaticGen.p as p0:
self.p0 = ExtService(src='p',
model='StaticGen',
indexer=self.gen,
tex_name='P_0')
Parameters
src [str] Variable or parameter name in the source model or group
model [str] A model name or a group name
indexer [IdxParam or BaseParam] An "Indexer" instance whose v field contains the
idx of devices in the model or group.
Examples
A synchronous generator needs to retrieve the p and q values from static generators for initialization.
ExtService is used for this purpose.
In a synchronous generator, one can define the following to retrieve StaticGen.p as p0:
class GENCLSModel(Model):
def __init__(...):
...
self.p0 = ExtService(src='p',
model='StaticGen',
indexer=self.gen,
tex_name='P_0')
Examples
A Bus device has an IdxParam of area, storing the idx of area to which the bus device belongs. In
Bus.__init__(), one has
self.area = IdxParam(model='Area')
idx area Vn
1 1 110
2 2 220
3 1 345
4 1 500
The Area model wants to collect the indices of Bus devices which points to the corresponding Area
device. In Area.__init__, one defines
self.Bus = BackRef()
where the member attribute name Bus needs to match exactly model name that Area wants to collect
idx for. Similarly, one can define self.ACTopology = BackRef() to collect devices in the
ACTopology group that references Area.
The collection of idx happens in andes.system.System._collect_ref_param(). It has to
be noted that the specific Area entry must exist to collect model idx-dx referencing it. For example, if
Area has the following data
idx 1
Then, only Bus 1, 3, and 4 will be collected into self.Bus.v, namely, self.Bus.v == [ [1, 3,
4] ].
If Area has data
idx 1 2
ref [BackRef] The BackRef whose 2-dimensional shapes are used for indexing
fun [Callable] The callable for converting a 1-D array-like to a scalar
Examples
Suppose one wants to calculate the mean value of the Vn in one Area. In the Area class, one defines
class AreaModel(...):
def __init__(...):
...
# backward reference from `Bus`
self.Bus = BackRef()
self.Vn_mean = NumReduce(u=self.Vn,
fun=np.mean,
ref=self.Bus)
Suppose we define two areas, 1 and 2, the Bus data looks like
idx area Vn
1 1 110
2 2 220
3 1 345
4 1 500
Then, self.Bus.v is a list of two lists [ [1, 3, 4], [2] ]. self.Vn.v will be retrieved and linearly
stored as [110, 345, 500, 220]. Based on the shape from self.Bus, numpy.mean() will be
called on [110, 345, 500] and [220] respectively. Thus, self.Vn_mean.v will become [318.
33, 220].
class andes.core.service.NumRepeat(u, ref, **kwargs)
A helper Service type which repeats a v-provider's value based on the shape from a BackRef
Examples
NumRepeat was originally designed for computing the inertia-weighted average rotor speed (center of
inertia speed). COI speed is computed with
∑
Mi ∗ ωi
ωCOI = ∑
Mi
The numerator can be calculated with a mix of BackRef, ExtParam and ExtState. The denominator
needs to be calculated with NumReduce and Service Repeat. That is, use NumReduce to calculate the
sum, and use NumRepeat to repeat the summed value for each device.
class COIModel(...):
def __init__(...):
...
self.SynGen = BackRef()
self.SynGenIdx = RefFlatten(ref=self.SynGen)
self.M = ExtParam(model='SynGen',
src='M',
indexer=self.SynGenIdx)
self.wgen = ExtState(model='SynGen',
src='omega',
indexer=self.SynGenIdx)
self.Mt = NumReduce(u=self.M,
fun=np.sum,
ref=self.SynGen)
self.Mtr = NumRepeat(u=self.Mt,
ref=self.SynGen)
self.pidx = IdxRepeat(u=self.idx,ref=self.SynGen)
self.wcoi_sub = ExtAlgeb(model='COI',
src='wcoi',
e_str='M * wgen / Mtr',
v_str='M / Mtr',
indexer=self.pidx,
)
It is very worth noting that the implementation uses∑a trick to separate the average weighted sum into
n sub-equations, each calculating the (Mi ∗ ωi )/( Mi ). Since all the variables are preserved in the
sub-equation, the derivatives can be calculated correctly.
class andes.core.service.IdxRepeat(u, ref, **kwargs)
Helper class to repeat IdxParam.
This class has the same functionality as andes.core.service.NumRepeat but only operates on
IdxParam, DataParam or NumParam.
class andes.core.service.RefFlatten(ref, **kwargs)
A service type for flattening andes.core.service.BackRef into a 1-D list.
Examples
This class is used when one wants to pass BackRef values as indexer.
andes.models.coi.COI collects referencing andes.models.group.SynGen with
After collecting BackRefs, self.SynGen.v will become a two-level list of indices, where the first level
correspond to each COI and the second level correspond to generators of the COI.
Convert self.SynGen into 1-d as self.SynGenIdx, which can be passed as indexer for retrieving other
parameters and variables
self.SynGenIdx = RefFlatten(ref=self.SynGen)
Examples
The IEEEST stabilizer takes an optional parameter busf of the type IdxParam for specifying the con-
nected bus frequency measurement device, which is needed for mode 6. To avoid reimplementing Bus-
Freq within IEEEST, one can do
self.busfreq = DeviceFinder(self.busf,
link=self.buss, idx_name='bus',
default_model='BusFreq')
where self.busf is for the optional parameter for the idx of bus frequency estimation devices
(e.g., BusFreq), self.buss is for the idx of buses that self.busf devices should measure, and
idx_name is the name of the BusFreq parameter through which the indices of measured buses are
given.
For each None or invalid values in self.busf, a BusFreq device will be created with its bus set to
the corresponding value in self.buss. That is, BusFreq.[idx_name].v = [link].
At the end, the DeviceFinder instance will contain the list of BusFreq that are are connected to self.buss,
respectively.
In the case of any valid value in self.busf, that is, the value is an existing BusFreq device, De-
viceFinder will return it as is without checking if the BusFreq device actually measures the bus specified
by self.buss. It allows to use the measurement at a different location, but the user have to perform
the data consistency check.
class andes.core.service.BackRef(**kwargs)
A special type of reference collector.
BackRef is used for collecting device indices of other models referencing the parent model of the Back-
Ref. The v``field will be a list of lists, each containing the `idx of other models referencing each device
of the parent model.
BackRef can be passed as indexer for params and vars, or shape for NumReduce and NumRepeat. See
examples for illustration.
See also:
Examples
A Bus device has an IdxParam of area, storing the idx of area to which the bus device belongs. In
Bus.__init__(), one has
self.area = IdxParam(model='Area')
idx area Vn
1 1 110
2 2 220
3 1 345
4 1 500
The Area model wants to collect the indices of Bus devices which points to the corresponding Area
device. In Area.__init__, one defines
self.Bus = BackRef()
where the member attribute name Bus needs to match exactly model name that Area wants to collect
idx for. Similarly, one can define self.ACTopology = BackRef() to collect devices in the
ACTopology group that references Area.
The collection of idx happens in andes.system.System._collect_ref_param(). It has to
be noted that the specific Area entry must exist to collect model idx-dx referencing it. For example, if
Area has the following data
idx 1
Then, only Bus 1, 3, and 4 will be collected into self.Bus.v, namely, self.Bus.v == [ [1, 3,
4] ].
If Area has data
idx 1 2
Examples
This class is used when one wants to pass BackRef values as indexer.
andes.models.coi.COI collects referencing andes.models.group.SynGen with
After collecting BackRefs, self.SynGen.v will become a two-level list of indices, where the first level
correspond to each COI and the second level correspond to generators of the COI.
Convert self.SynGen into 1-d as self.SynGenIdx, which can be passed as indexer for retrieving other
parameters and variables
self.SynGenIdx = RefFlatten(ref=self.SynGen)
3.7.8 Events
trig [str in ("rise", "fall")] Triggering edge for the beginning of an event. rise by default.
enable [bool or v-provider] If disabled, the output will be v_disabled
extend_only [bool] Only output during the extended period, not the event period.
3.7.9 Flags
Service for flagging parameters < or <= the given value element-wise.
Parameters that satisfy the comparison (u < or <= value) will flagged as flag (1 by default).
class andes.core.service.FlagValue(u, value, flag=0, name=None, tex_name=None,
info=None, cache=True)
Class for flagging values that equal to the given value.
By default, values that equal to value will be flagged as 0. Non-matching values will be flagged as 1.
Parameters
u Input parameter
value Value to flag. Can be None, string, or a number.
flag [0 by default, only 0 or 1 is accepted.] The flag for the matched ones
Warning: FlagNotNone can only be applied to BaseParam with cache=True. Applying to Service
will fail unless cache is False (at a performance cost).
Notes
self.Tn = NumParam(default=None)
self.Sg = ExtParam(...)
self.Sn = DataSelect(Tn, Sg)
Examples
3.7.11 Miscellaneous
Examples
Let's say generator excitation voltages are known to be in the range of 1.6 - 3.0 per unit. One can add
the following instance to GENBase
self._vfc = InitChecker(u=self.vf,
info='vf range',
lower=1.8,
upper=3.0,
)
lower and upper can also take v-providers instead of float values.
One can also pass float values from Config to make it adjustable as in our implementation of GENBase.
_vfc.
class andes.core.service.ApplyFunc(u, func, name=None, tex_name=None, info=None,
cache=True)
Class for applying a numerical function on a parameter..
Parameters
u Input parameter
func A condition function that returns True or False.
bus1 bus2
*------>>-----*
bus(+) bus(-)
Warning: The value will be randomized every time it is accessed. Do not use it if the value needs
to be stable for each simulation step.
3.8 Discrete
3.8.1 Background
The discrete component library contains a special type of block for modeling the discontinuity in power system
devices. Such continuities can be device-level physical constraints or algorithmic limits imposed on controllers.
The base class for discrete components is andes.core.discrete.Discrete.
andes.core.discrete.Discrete
Methods
Discrete.check_eq
Discrete.check_eq(**kwargs)
This function is called in l_check_eq after updating equations.
It updates internal flags, set differential equations, and record pegged variables.
Discrete.check_iter_err
Discrete.check_iter_err(niter=None, err=None)
Check if the minimum iteration or maximum error is reached so that this discrete block should be
enabled.
Only when both niter and err are given, (niter < min_iter) , and (err > err_tol) it will return False.
This logic will start checking the discrete states if called from an external solver that does not feed
niter or err at each step.
Returns
bool True if it should be enabled, False otherwise
Discrete.check_var
Discrete.check_var(*args, **kwargs)
This function is called in l_update_var before evaluating equations.
It should update internal flags only.
Parameters
adjust_upper [bool] True to adjust the upper limit to the value of the variable.
Supported by limiters.
adjust_lower [bool] True to adjust the lower limit to the value of the variable. Sup-
ported by limiters.
Discrete.get_names
Discrete.get_names()
Available symbols from this class
Returns
Discrete.get_tex_names
Discrete.get_tex_names()
Return tex_names of exported flags.
TODO: Fix the bug described in the warning below.
Returns
list A list of tex_names for all exported flags.
Warning: If underscore _ appears in both flag tex_name and self.tex_name (for example,
when this discrete is within a block), the exported tex_name will become invalid for SymPy.
Variable name substitution will fail.
Discrete.get_values
Discrete.get_values()
Discrete.list2array
Discrete.list2array(n)
Allocate memory for the discrete flags specified in self.export_flags.
Parameters
n [int] Number of elements in the array. Provided by the calling function.
Discrete.warn_init_limit
Discrete.warn_init_limit()
Warn if associated variables are initialized at limits.
Attributes
class_name
Discrete.class_name
property Discrete.class_name
The uniqueness of discrete components is the way it works. Discrete components take inputs, criteria, and
exports a set of flags with the component-defined meanings. These exported flags can be used in algebraic or
differential equations to build piece-wise equations.
For example, Limiter takes a v-provider as input, two v-providers as the upper and the lower bound. It exports
three flags: zi (within bound), zl (below lower bound), and zu (above upper bound). See the code example in
models/pv.py for an example voltage-based PQ-to-Z conversion.
It is important to note when the flags are updated. Discrete subclasses can use three methods to check and
update the value and equations. Among these methods, check_var is called before equation evaluation, but
check_eq and set_eq are called after equation update. In the current implementation, check_var updates flags
for variable-based discrete components (such as Limiter). check_eq updates flags for equation-involved discrete
components (such as AntiWindup). set_var` is currently only used by AntiWindup to store the pegged states.
ANDES includes the following types of discrete components.
3.8.2 Limiters
Notes
Parameters
n_select [int] the number of violations to be flagged, for each of over-limit and under-
limit cases. If n_select == 1, at most one over-limit and one under-limit inputs will
be flagged. If n_select is zero, heuristics will be used.
abs_violation [bool] True to use the absolute violation. False if the relative violation
abs(violation/limit) is used for sorting. Since most variables are in per unit, absolute
violation is recommended.
class andes.core.discrete.HardLimiter(u, lower, upper, enable=True, name: Optional[str]
= None, tex_name: Optional[str] = None, info:
Optional[str] = None, min_iter: int = 2, err_tol:
float = 0.01, allow_adjust: bool = True,
no_lower=False, no_upper=False, sign_lower=1,
sign_upper=1, equal=True, no_warn=False,
zu=0.0, zl=0.0, zi=1.0)
Hard limiter for algebraic or differential variable. This class is an alias of Limiter.
class andes.core.discrete.RateLimiter(u, lower, upper, enable=True, no_lower=False,
no_upper=False, lower_cond=1, upper_cond=1,
name=None, tex_name=None, info=None)
Rate limiter for a differential variable.
RateLimiter does not export any variable. It directly modifies the differential equation value.
Warning: RateLimiter cannot be applied to a state variable that already undergoes an AntiWindup
limiter. Use AntiWindupRate for a rate-limited anti-windup limiter.
Notes
RateLimiter inherits from Discrete to avoid internal naming conflicts with Limiter.
class andes.core.discrete.AntiWindup(u, lower, upper, enable=True, no_warn=False,
no_lower=False, no_upper=False, sign_lower=1,
sign_upper=1, name=None, tex_name=None,
info=None, state=None, allow_adjust: bool = True)
Anti-windup limiter.
Anti-windup limiter prevents the wind-up effect of a differential variable. The derivative of the differ-
ential variable is reset if it continues to increase in the same direction after exceeding the limits. During
the derivative return, the limiter will be inactive
This class takes one more optional parameter for specifying the equation.
Parameters
state [State, ExtState] A State (or ExtState) whose equation value will be checked and,
when condition satisfies, will be reset by the anti-windup-limiter.
class andes.core.discrete.AntiWindupRate(u, lower, upper, rate_lower, rate_upper,
no_lower=False, no_upper=False,
rate_no_lower=False, rate_no_upper=False,
rate_lower_cond=None,
rate_upper_cond=None, enable=True,
name=None, tex_name=None, info=None,
allow_adjust: bool = True)
Anti-windup limiter with rate limits
3.8.3 Comparers
Notes
The default z0 and z1, if not enabled, can be set through the constructor. By default, the model will not
adjust the limit.
class andes.core.discrete.Selector(*args, fun, tex_name=None, info=None)
Selection between two variables using the provided reduce function.
The reduce function should take the given number of arguments. An example function is
np.maximum.reduce which can be used to select the maximum.
Names are in s0, s1.
Warning: A potential bug when more than two inputs are provided, and values in different inputs
are equal. Only two inputs are allowed.
Deprecated since version 1.5.9: Use of this class for comparison-based output is discouraged. In-
stead, use LessThan and Limiter to construct piesewise equations.
See the new implementation of HVGate and LVGate.
See also:
Notes
A common pitfall is the 0-based indexing in the Selector flags. Note that exported flags start from 0.
Namely, s0 corresponds to the first variable provided for the Selector constructor.
Examples
Example 1: select the largest value between v0 and v1 and put it into vmax.
After the definitions of v0 and v1, define the algebraic variable vmax for the largest value, and a selector
vs
The initial value of vmax is calculated by maximum(v0, v1), which is the element-wise maximum
in SymPy and will be generated into np.maximum(v0, v1). The equation of vmax is to select the
values based on vs_s0 and vs_s1.
class andes.core.discrete.Switcher(u, options: Union[list, Tuple], info: Optional[str] =
None, name: Optional[str] = None, tex_name:
Optional[str] = None, cache=True)
Switcher based on an input parameter.
The switch class takes one v-provider, compares the input with each value in the option list, and exports
one flag array for each option. The flags are 0-indexed.
Exported flags are named with _s0, _s1, ..., with a total number of len(options). See the examples section.
Notes
Examples
The IEEEST model takes an input for selecting the signal. Options are 1 through 6. One can construct
where IC_s0 is used for padding so that following flags align with the options.
3.8.4 Deadband
Notes
Input changes within a deadband will incur no output changes. This component computes and exports
three flags.
Three flags computed from the current input:
• zl: True if the input is below the lower threshold
• zi: True if the input is within the deadband
• zu: True if is above the lower threshold
Initial condition:
All three flags are initialized to zero. All flags are updated during check_var when enabled. If the
deadband component is not enabled, all of them will remain zero.
Examples
Exported deadband flags need to be used in the algebraic equation corresponding to the post-deadband
variable. Assume the pre-deadband input variable is var_in and the post-deadband variable is var_out.
First, define a deadband instance db in the model using
To implement a no-memory deadband whose output returns to center when the input is within the band,
the equation for var can be written as
Notes
Input changes within a deadband will incur no output changes. This component computes and exports
five flags. The additional two flags on top of DeadBand indicate the direction of return:
• zur: True if the input is/has been within the deadband and was returned from the upper threshold
• zlr: True if the input is/has been within the deadband and was returned from the lower threshold
Initial condition:
All five flags are initialized to zero. All flags are updated during check_var when enabled. If the deadband
component is not enabled, all of them will remain zero.
Examples
To implement a deadband whose output is pegged at the nearest deadband bounds, the equation for var
can be provided as
3.8.5 Others
The output of the Derivative class is named <INSTANCE_NAME>_v just like Delay.
class andes.core.discrete.Sampling(u, interval=1.0, offset=0.0, name=None,
tex_name=None, info=None)
Sample and hold
Sample an input variable periodically at the given time interval and hold the value until the next sample
time.
For example, this class can be used to implement a 4-second sampling of the AGC signal.
The output of Sampling is named <INSTANCE_NAME>_v, where <INSTANCE_NAME> is the Sam-
pling instance name.
class andes.core.discrete.ShuntAdjust(*, v, lower, upper, bsw, gsw, dt, u, enable=True,
min_iter=2, err_tol=0.01, name=None,
tex_name=None, info=None, no_warn=False)
Class for adjusting switchable shunts.
Parameters
v [BaseVar] Voltage measurement
lower [BaseParam] Lower voltage bound
upper [BaseParam] Upper voltage bound
bsw [SwBlock] SwBlock instance for susceptance
gsw [SwBlock] SwBlock instance for conductance
dt [NumParam] Delay time
u [NumParam] Connection status
min_iter [int] Minimum iteration number to enable shunt switching
err_tol [float] Minimum iteration tolerance to enable switching
3.9 Blocks
3.9.1 Background
The block library contains commonly used blocks (such as transfer functions and nonlinear functions). Variables
and equations are pre-defined for blocks to be used as "lego pieces" for scripting DAE models. The base class
for blocks is andes.core.block.Block.
The supported blocks include Lag, LeadLag, Washout, LeadLagLimit, PIController. In ad-
dition, the base class for piece-wise nonlinear functions, Piecewise is provided. Piecewise is used
for implementing the quadratic saturation function MagneticQuadSat and exponential saturation function
MagneticExpSat.
All variables in a block must be defined as attributes in the constructor, just like variable definition in models.
The difference is that the variables are "exported" from a block to the capturing model. All exported variables
need to placed in a dictionary, self.vars at the end of the block constructor.
Blocks can be nested as advanced usage. See the following API documentation for more details.
class andes.core.block.Block(name: Optional[str] = None, tex_name: Optional[str] = None,
info: Optional[str] = None, namespace: str = 'local')
Base class for control blocks.
Blocks are meant to be instantiated as Model attributes to provide pre-defined equation sets. Subclasses
must overload the __init__ method to take custom inputs. Subclasses of Block must overload the define
method to provide initialization and equation strings. Exported variables, services and blocks must be
constructed into a dictionary self.vars at the end of the constructor.
Blocks can be nested. A block can have blocks but itself as attributes and therefore reuse equations.
When a block has sub-blocks, the outer block must be constructed with a``name``.
Nested block works in the following way: the parent block modifies the sub-block's name attribute by
prepending the parent block's name at the construction phase. The parent block then exports the sub-
block as a whole. When the parent Model class picks up the block, it will recursively import the variables
in the block and the sub-blocks correctly. See the example section for details.
Parameters
name [str, optional] Block name
tex_name [str, optional] Block LaTeX name
info [str, optional] Block description.
namespace [str, local or parent] Namespace of the exported elements. If 'local', the
block name will be prepended by the parent. If 'parent', the original element name
will be used when exporting.
Warning: It is a good practice to avoid more than one level of nesting, to avoid multi-underscore
variable names.
Examples
Example for two-level nested blocks. Suppose we have the following hierarchy
SomeModel instance M contains an instance of LeadLag block named A, which contains a Lag instance
named B. Both A and B exports two variables x and y.
In the code for SomeModel, the following code is used to instantiate LeadLag
class SomeModel:
def __init__(...)
... self.A = LeadLag(name='A',
u=self.foo1, T1=self.foo2, T2=self.foo3)
To use Lag in the LeadLag code, the following lines are found in the constructor of LeadLag
class LeadLag:
def __init__(name, ...)
... self.B = Lag(u=self.y, K=self.K, T=self.T)
When instantiating any block instance, its __setattr__ function assigns names to exported variables
and blocks. For the LeadLag instance with the name A, its member attribute B is assigned the name A_B
by convention. That is, A_B will be set to B.name.
When A is picked up by SomeModel.__setattr__, B is captured from A's exports with the name
A_B. Recursively, B's variables are exported, Recall that B.name is now A_B, following the naming rule
(parent block's name + variable name), B's internal variables become A_B_x and A_B_y.
Again, the LeadLag instance name (A.name in this example) must be given when instantiating in
SomeModel's constructor to ensure correct name propagation. If there is more than one level of nesting,
other than the terminal-level block, all names of the parent blocks must be provided at instantiation.
In such a way, B's define() needs no modification since the naming rule is the same. For example,
B's internal y is always {self.name}_y, although the nested B has gotten a new name A_B.
define()
Function for setting the initialization and equation strings for internal variables. This method must
be implemented by subclasses.
The equations should be written with the "final" variable names. Let's say the block instance is
named blk (kept at self.name of the block), and an internal variable v is defined. The internal
variable will be captured as blk_v by the parent model. Therefore, all equations should use
{self.name}_v to represent variable v, where {self.name} is the name of the block at
run time.
On the other hand, the names of externally provided parameters or variables are obtained by directly
accessing the name attribute. For example, if self.T is a parameter provided through the block
constructor, {self.T.name} should be used in the equation.
See also:
Examples
An internal variable v has a trivial equation T = v, where T is a parameter provided to the block
constructor.
In the model, one has
class SomeModel():
def __init__(...)
(continues on next page)
class ExampleBlock():
def __init__(...):
self.v = Algeb()
self.vars = {'v', self.v}
def define(self):
self.v.v_str = '{self.T.name}'
self.v.e_str = '{self.T.name} - {self.name}_v'
In the parent model, v from the block will be captured as blk_v, and the equation will evaluate
into
self.blk_v.v_str = 'T'
self.blk_v.e_str = 'T - blk_v'
The following transfer function blocks have been implemented. They can be imported to build new models.
Linear
┌───┐
u -> │ K │ -> y
└───┘
y = Ku
y (0) = Ku(0)
Parameters
u [str, BaseVar] Input variable, or an equation string for constructing an anonymous
variable
K [str, BaseParam, BaseService] Initial gain for u before limiter
R [str, BaseParam, BaseService] Post limiter gain
define()
TODO: write docstring
class andes.core.block.Piecewise(u, points: Union[List, Tuple], funs: Union[List, Tuple],
name=None, tex_name=None, info=None)
Piecewise block. Outputs an algebraic variable y.
This block takes a list of N points, [x0, x1, ...x_{n-1}] to define N+1 ranges, namely (-inf, x0), (x0, x1),
..., (x_{n-1}, +inf). and a list of N+1 function strings [fun0, ..., fun_n].
Inputs that fall within each range applies the corresponding function. The first range (-inf, x0) applies
fun_0, and the last range (x_{n-1}, +inf) applies the last function fun_n.
The function returns zero if no condition is met.
Parameters
points [list, tuple] A list of piecewise points. Need to be provided in the constructor
function.
funs [list, tuple] A list of strings for the piecewise functions. Need to be provided in
the overloaded define function.
define()
Build the equation string for the piecewise equations.
self.funs needs to be provided with the function strings corresponding to each range.
class andes.core.block.HVGate(u1, u2, name=None, tex_name=None, info=None)
High Value Gate. Outputs the maximum of two inputs.
┌─────────┐
u1 -> │ HV Gate │
│ │ -> y
u2 -> │ (MAX) │
└─────────┘
Notes
Block diagram
| /
______|__/___ -> Gain -> DeadBand1_y
/ |
/ |
First Order
define()
Implemented equation and the initial condition are
ẏ = Ku
y (0) = 0
upper
/¯¯¯¯¯
┌──────┐
u -> │ K/sT │ -> y
└──────┘
_____/
lower
Exports a differential variable y and an AntiWindup lim. The initial output must be specified through y0.
define()
Implemented equation and the initial condition are
ẏ = Ku
y (0) = 0
┌────────┐
│ K │
u -> │ ────── │ -> y
│ D + sT │
└────────┘
Notes
T ẏ = (Ku − Dy)
y (0) = Ku/D
upper
/¯¯¯¯¯¯
┌────────┐
│ K │
u -> │ ────── │ -> y
│ D + sT │
└────────┘
______/
lower
Exports one state variable y as the output and one AntiWindup instance lim.
Parameters
K Gain
T Time constant
D Constant
u Input variable
define()
Notes
T ẏ = (Ku − Dy)
y (0) = Ku/D
Notes
T ẏ = (1 − f reeze) ∗ (Ku − y)
y (0) = Ku
Notes
T ẏ = (1 − f reeze)(Ku − y)
y (0) = Ku
/ rate_upper
┌────────┐
│ K │
u -> │ ────── │ -> y
│ D + sT │
└────────┘
rate_lower /
Exports one state variable y as the output and one AntiWindupRate instance lim.
Parameters
K Gain
T Time constant
D Constant
u Input variable
define()
Notes
T ẏ = (Ku − y)
y (0) = Ku
upper
rate_upper /¯¯¯¯¯¯
┌────────┐
│ K │
u -> │ ────── │ -> y
│ D + sT │
└────────┘
______/ rate_lower
lower
Exports one state variable y as the output and one AntiWindupRate instance lim.
Parameters
K Gain
T Time constant
D Constant
u Input variable
define()
Notes
T ẏ = (Ku − Dy)
y (0) = Ku/D
┌────────┐
│ sK │
u -> │ ────── │ -> y
│ 1 + sT │
└────────┘
Notes
T ẋ′ = (u − x′ )
T y = K(u − x′ )
x′(0) = u
y (0) = 0
Notes
T ẋ′ = (u − x′ )
T y = z0 K(u − x′ ) + z1 T x
x′(0) = u
y (0) = 0
where z_0 is a flag array for the greater-than-zero elements, and z_1 is that for the less-than or
equal-to zero elements.
Notes
Notes
Exports four variables: state x, output before hard limiter ynl, output y, and AntiWindup lim.
define()
Notes
T2 ẋ′ = (u − x′ )
T2 y = T1 (u − x′ ) + T2 x′
x′(0) = y (0) = u
Second Order
┌──────────────────┐
│ K │
u -> │ ──────────────── │ -> y
│ 1 + sT1 + s^2 T2 │
└──────────────────┘
Exports one two state variables (x, y), where y is the output.
Parameters
u Input
K Gain
T1 First order time constant
T2 Second order time constant
define()
Notes
T2 ẋ = Ku − y − T1 x
ẏ = x
x(0) = 0
y (0) = Ku
┌──────────────────┐
│ 1 + sT3 + s^2 T4 │
u -> │ ──────────────── │ -> y
│ 1 + sT1 + s^2 T2 │
└──────────────────┘
Exports two internal states (x1 and x2) and output algebraic variable y.
The current implementation allows any or all parameters to be zero. Four LessThan blocks are used
to check if the parameter values are all zero. If yes, y = u will be imposed in the algebraic equation.
define()
Notes
T2 ẋ1 = u − x2 − T1 x1
ẋ2 = x1
T2 y = T2 x2 + T2 T3 x1 + T4 (u − x2 − T1 x1 ) + E2 , where
{
(y − x2 ) if T1 = T2 = T3 = T4 = 0&zero_out = T rue
E2 =
0 otherwise
(0)
x1 = 0
(0)
x2 = y (0) = u
PI Controllers
Notes
ẋi = ki ∗ (u − ref )
y = xi + kp ∗ (u − ref )
Notes
ẋi = ki ∗ (u − ref )
y = xi + kp ∗ (u − ref )
Examples
An internal variable v has a trivial equation T = v, where T is a parameter provided to the block
constructor.
In the model, one has
class SomeModel():
def __init__(...)
self.input = Algeb()
self.T = Param()
class ExampleBlock():
def __init__(...):
self.v = Algeb()
self.vars = {'v', self.v}
def define(self):
self.v.v_str = '{self.T.name}'
self.v.e_str = '{self.T.name} - {self.name}_v'
In the parent model, v from the block will be captured as blk_v, and the equation will evaluate
into
self.blk_v.v_str = 'T'
self.blk_v.e_str = 'T - blk_v'
Notes
Tested in experimental.TestPITrackAW.PIFreeze.
define()
Notes
ẋi = ki ∗ (u − ref )
y = (1 − f reeze) ∗ (xi + kp ∗ (u − ref )) + f reeze ∗ y
Examples
An internal variable v has a trivial equation T = v, where T is a parameter provided to the block
constructor.
In the model, one has
class SomeModel():
def __init__(...)
self.input = Algeb()
self.T = Param()
class ExampleBlock():
def __init__(...):
self.v = Algeb()
self.vars = {'v', self.v}
def define(self):
self.v.v_str = '{self.T.name}'
self.v.e_str = '{self.T.name} - {self.name}_v'
In the parent model, v from the block will be captured as blk_v, and the equation will evaluate
into
self.blk_v.v_str = 'T'
self.blk_v.e_str = 'T - blk_v'
┌────────────────────┐
│ ki skd │
u -> │kp + ─── + ─────── │ -> y
│ s 1 + sTd │
└────────────────────┘
The controller takes an error signal as the input. It takes an optional ref signal, which will be subtracted
from the input.
The name is suggessted to be specified the same as the instance name.
This block assembles a PIController and a Washout.
Parameters
u [BaseVar] The input variable instance
kp [BaseParam] The proportional gain parameter instance
ki [BaseParam] The integral gain parameter instance
kd [BaseParam] The derivative gain parameter instance
Td [BaseParam] The derivative time constant parameter instance
define()
Define equations for the PID Controller.
Notes
One PIController PIC, one Washout xd, and one algebraic variable y are added.
Equations implemented are
ẋi = ki ∗ (u − ref )
xd = W ashout(u − ref )y
= xi + kp ∗ (u − ref ) + xd
upper
/¯¯¯¯¯¯
┌────────────────────┐
│ ki skd │
u -> │kp + ─── + ─────── │ -> y
│ s 1 + sTd │
└────────────────────┘
______/
lower
Notes
ẋi = ki ∗ (u − ref )
y = xi + kp ∗ (u − ref )
class andes.core.block.PIDTrackAW(u, kp, ki, kd, Td, ks, lower, upper, no_lower=False,
no_upper=False, ref=0.0, x0=0.0, name=None,
tex_name=None, info=None)
PID with tracking anti-windup limiter
define()
Function for setting the initialization and equation strings for internal variables. This method must
be implemented by subclasses.
The equations should be written with the "final" variable names. Let's say the block instance is
named blk (kept at self.name of the block), and an internal variable v is defined. The internal
variable will be captured as blk_v by the parent model. Therefore, all equations should use
{self.name}_v to represent variable v, where {self.name} is the name of the block at
run time.
On the other hand, the names of externally provided parameters or variables are obtained by directly
accessing the name attribute. For example, if self.T is a parameter provided through the block
constructor, {self.T.name} should be used in the equation.
See also:
Examples
An internal variable v has a trivial equation T = v, where T is a parameter provided to the block
constructor.
In the model, one has
class SomeModel():
def __init__(...)
self.input = Algeb()
self.T = Param()
class ExampleBlock():
def __init__(...):
self.v = Algeb()
self.vars = {'v', self.v}
def define(self):
self.v.v_str = '{self.T.name}'
self.v.e_str = '{self.T.name} - {self.name}_v'
In the parent model, v from the block will be captured as blk_v, and the equation will evaluate
into
self.blk_v.v_str = 'T'
self.blk_v.e_str = 'T - blk_v'
3.9.3 Saturation
Notes
We loosely follow a naming convention when using modeling blocks. An instance of a modeling block is named
with a two-letter acronym, followed by a number or a meaningful but short variaiable name. The acronym and
the name are spelled in one word without underscore, as the output of the block already contains _y.
For example, two washout filters can be names WO1 and WO2. In another case, a first-order lag function for
voltage sensing can be called LGv, or even LG if there is only one Lag instance in the model.
Naming conventions are not strictly enforced. Expressiveness and concision are encouraged.
3.10 Examples
We show two examples to demonstrate modeling from equations and modeling from control block diagrams.
• The TGOV1 example shows code snippet for equation-based modeling and, as well as code for block-
based modeling.
• The IEEEST example walks through the source code and explains the complete setup, including optional
parameters, input selection, and manual per-unit conversion.
3.10.1 TGOV1
The TGOV1 turbine governor model is shown as a practical example using the library.
This model is composed of a lead-lag transfer function and a first-order lag transfer function with an anti-
windup limiter, which are sufficiently complex for demonstration. The corresponding differential equations
Another implementation of TGOV1 makes extensive use of the modeling blocks. The resulting code is more
readable as follows.
self.gain = ConstService(v_str='u/R')
self.LAG = LagAntiWindup(u=self.pd,
K=1,
T=self.T1,
lower=self.VMIN,
upper=self.VMAX,
)
self.LL = LeadLag(u=self.LAG_y,
T1=self.T2,
T2=self.T3,
)
(continues on next page)
3.10.2 IEEEST
In this example, we will explain step-by-step how IEEEST is programmed. The block diagram of IEEEST is
given as follows. We recommend you to open up the source code in andes/models/pss.py and then
continue reading.
PSSBase
PSSBase is defined for the common (external) parameters, services and variables shared by all PSSs. The
class and constructor signatures are
class PSSBase(Model):
def __init__(self, system, config):
super().__init__(system, config)
PSSBase inherits from Model and calls the base constructor. Note that the call to Model's constructor takes
two positional arguments, system and config of types System and ModelConfig. Next, the group is
specified, and the model flags are set.
Note: It is important to set the TDS flag to register the model. If not set, data for the model will be successfully
loaded, but the variables in the model will not receive any address, and the model equations will be skipped.
There is a similar flag self.flags.pflow for models to participate in power flow calculations. Most
dynamic models, however, are initialized after power flow.
self.group = 'PSS'
self.flags.tds = True
Next, Replace is used to replace input parameters that satisfy a lambda function with new values.
The value replacement happens when VCUr and VCLr is first accessed. Replace is executed in the model
initialization phase (at the end of services update).
Next, the indices of connected generators, buses, and bus frequency measurements are retrieved. Synchronous
generator idx is retrieved with
Using the retrieved self.syn, it retrieves the buses to which the generators are connected.
PSS models support an optional remote bus specified through parameter busr. When busr is None, the
generator-connected bus should be used. The following code uses DataSelect to select busr if available
but falls back to bus otherwise.
Each PSS links to a bus frequency measurement device. If the input data does not specify one or the specified
one does not exist, DeviceFinder can find the correct measurement device for the bus where frequency
measurements should be taken.
where busf is the optional frequency measurement device idx, buss is the bus idx for which measurement
device needs to be found or created.
Next, external parameters, variables and services are retrieved. Note that the PSS output vsout is pre-
allocated but the equation string is left to specific models.
IEEESTModel
IEEESTModel inherits from PSSBase and adds specific model components. After calling PSSBase's con-
structor, IEEESTModel adds config entries to allow specifying the model for frequency measurement, because
there may be multiple frequency measurement models in the future.
self.config.add(OrderedDict([('freq_model', 'BusFreq')]))
self.config.add_extra('_help', {'freq_model': 'default freq. measurement model
,→'})
We set the chosen measurement model to busf so that DeviceFinder knows which model to use if it
needs to create new devices.
self.busf.model = self.config.freq_model
Next, because bus voltage is an algebraic variable, we use Derivative to calculate the finite difference to
approximate its derivative.
Then, we retrieve the coefficient to convert power from machine base to system base using ConstService,
given by Sb / Sn. This is needed for input mode 3, electric power in machine base.
Note that the ExtService access the pu_coeff field of the M variables of synchronous generators. Since M
is a machine-base power quantity, M.pu_coeff stores the multiplication coefficient to convert each of them
from machine bases to the system base, which is Sb / Sn.
The input mode is parsed into boolean flags using Switcher:
self.SW = Switcher(u=self.MODE,
options=[0, 1, 2, 3, 4, 5, 6],
)
where the input u is the MODE parameter, and options is a list of accepted values. Switcher boolean
arrays s0, s1, ..., sN, where N = len(options) - 1. We added 0 to options for padding so that
SW_s1 corresponds to MODE 1. It improves the readability of the code as we will see next.
The input signal sig is an algebraic variable given by
self.sig = Algeb(tex_name='S_{ig}',
info='Input signal',
)
The v_str and e_str are separated from the constructor to improve readability. They construct piece-wise
functions to select the correct initial values and equations based on mode. For any variables in v_str, they
must be defined before sig so that they will be initialized ahead of sig. Clearly, omega, tm, and v are
defined in PSSBase and thus come before sig.
The following comes the most effective part: modeling using transfer function blocks. We utilized several
blocks to describe the model from the diagram. Note that the output of a block is always the block name
followed by _y. For example, the input of F2 is the output of F1, given by F1_y.
In the end, the output equation is assigned to vsout.e_str. It completes the equations of the IEEEST
model.
Finalize
Locate and edit the file andes/models/__init__.py. The variable file_classes is a list of tuples
that stores the source file and class names in strings. In each tuple, the first element is the .py file name in the
models folder, and the second element is a list of class names to be imported from that file.
Find the line with pss, then add IEEEST to the corresponding list of model names. The line will look like
file_classes = list([
...
('pss', ['IEEEST', 'ST2CUT']),
...
])
Note in the above that the string 'IEEEST' is used. The line above is valid as long as from andes.
models.pss import IEEEST is valid. If the source file name does not exist in any line of
file_classes, one may add it after all prerequisite models. For example, the pss line should be added
after exciters (and generators, of course).
Finally, locate andes/models/group.py, check if the class PSS exist. It needs to match the group name
of IEEEST. If not, create one by inheriting from GroupBase:
class PSS(GroupBase):
"""Power system stabilizer group."""
def __init__(self):
super().__init__()
self.common_vars.extend(('vsout',))
where we added vsout to the common_vars list. All models in the PSS group must have a variable named
vsout, which is defined in PSSBase.
This completes the IEEEST model. When developing new models, use andes prepare to generate nu-
merical code and start debugging.
FOUR
RELEASE NOTES
The APIs before v3.0.0 are in beta and may change without prior notice.
• An internal change to the xlsx parser option. Previously, the index column was set to 0, which assumes
the existence of uid as the header. Manually input sheets without uid will fail. This version unsets the
index column when using pandas to parse the xlsx file.
• Jumper is included for connectivity check.
• Add curly brackets for LaTeX symbols from sub-blocks. Nested symbols with subscripts and superscripts
now display properly.
• Fix Model.alter() for parameters that are time constants for differential equations. Altered time constants
are now properly updated in dae.Tf and will be correctly reflected in simulation results.
• Fix a bug in connectivity check.
• Support numba for Python 3.11.
399
ANDES Manual, Release 1.8.10
• Added IEEE 39-bus test case with dynamics in the ANDES xlsx format. Contributed by @jinningwang.
• In interop.pandapower, the _verify_pf function will not be called if TDS has been initialized. This
prevents the breaking of variable addresses.
• Fixed a bug in time stepping where step sizes were not properly reduced when the solver failed to con-
verge.
• New turbine governor model HYGOV4. Thanks to Zaid Mahmood for the contribution.
• Bug fixes to saving data to xlsx file.
• Internal change: drop the support for reloading generated code from calls.pkl. All generated code
are serialized into Python files and reloaded as a pycode module.
• Fix an issue where cases in multiprocessing fail to serialize due to not being able to find pycode.
pycode is now properly imported by the main process.
• When one needs to serialize a System object, such as during multiprocessing, one needs to manually
import pycode. This can be done by calling andes.system.import_pycode().
• Internal change: serializing with dill is not set to recursive by default.
• Support marking tests as extra so that they are not run by default. The function names for extra tests
should contain extra_test. To run all tests, use andes st -e or andes selftest --extra.
• Add the new_A flag for sparse solvers to trigger actions. Currently, only the spsolve solver will need
to rebuild and refactorize the sparse matrix.
• Implemented a chattering detection and stop algorithm by increasing the step size when chattering is
detected.
• TimeSeries.get_data() works for systems with Output.
• Allow freezing states associated with anti-windup limiters after a certain number of iterations to prevent
chattering.
Models:
• New exciter models: ESDC1A, EXAC2.
• New grid-forming inverter models: REGF1, REGF2, REGF3.
• For IEEEG1, normalize K1 through K8 if they do not sum up to 1.0
• In eigenvalue analysis, added parameter sweeping and scatter plot for root loci. See revised Example 4.
• Documentation improvements.
• Added Fortescue model to support symmetric component calculation. The model allows interfacing a
positive-sequence bus with three buses representing three phases. See the model description for details.
• Added PLL2 for the Synchronously-rotating Reference Frame (SRF)-based PLL.
• REGCP1 works identically to REGCA1 when the pll parameter is empty and works with a PLL.
• REECA1 is updated to work with vd of the converter. If using the REGCA1 model, vd = v.
• Reverted a change in Line parameter that caused SMIB case to crash.
Bug fix:
• Fix Ipcmd initialization equation of REGCA1.
Improved the interface to pandapower:
• Improved to_pandapower performance using vectorized conversion.
• Enhanced make_link_table to include group RenGen.
Allow incrementally offloading simulation data from memory to the output file:
• [TDS].limit_store is a boolean value to enable the limit for in-memory time-series storage. If
set to 1, data will be offloaded to the npz file every [TDS].max_store steps. Offloaded data will
then be erased from memory.
• If you need to interact with the time-series data in memory, you need to keep [TDS].limit_store
to 0.
Allow specifying models, variables, and/or devices to output:
• See Output. The model field is mandatory. Leaving varname or dev blank indicates the selection of all
applicable elements. For example, specifying model and varname without dev means that the variable
for all devices will be exported.
• Plot tool works with in-memory time-series data specified by Output.
Simulation output control:
• Allow controlling the save frequency for output data in [TDS].save_every. The default value is 1,
which means that every step will be saved. Setting it to 4, for example, will save data every four steps.
This setting applies to the in-memory storage and the output data file.
• Setting save_every = 0 will immediately discard all data after each simulation step.
• Added the option [TDS].save_mode to change the automatic simulation data dumping to manual.
Accepted values are auto and manual. This option shall only be adjusted to manual when one is
manually stepping the simulation and wants to avoid writing to the output file when the simulation reaches
TDS.config.tf. One will need to call TDS.save_output() when the full simulation concludes
to avoid losing unsaved data.
Other changes:
• Fix the initialization of offline synchronous generators.
• Allow styles to be set for plots using the argument style. To generate figures for IEEE publications,
use style=ieee (require package scienceplots).
• Moved the writing of the lst file to the first step of simulation.
• andes misc -C will not remove _out.csv file as it is considered data for post-processing just like
exported figures.
• Rename [System] call_stats to [System] save_stats for clarity. If turned on, one can
retrieve statistics of function calls in TDS.call_stats.
• Store routine execution time to routine member execution_time.
• Fix PSS/E parsing issues with GAST.
• Fix issues and update default parameters for REGCV1 and REGCV2.
• Allow adjusting limits for state variables during initialization. Like for algebraic variables, the default
setting automatically adjusts the upper limit but not the lower one.
• Added a TDS stop criteria based on rotor angle separation with reference to Power System Analysis
Toolbox.
• Fix a bug for snapshot save and load. It now supports writing to and reading from io.BytesIO().
Breaking change:
• PV model no longer has p as a variable in the DAE. p copies the value of p0. This change affects the
addresses of variables.
• Changed models.file_classes to a list to improve the control over the class initialization se-
quence in the same package.
Operator splitting for internal algebraic variables:
• VarService can be evaluated model-internal algebraic variables outside the DAE system. This ap-
proach is known as operator splitting and is commonly used in other simulation tools.
• Operator splitting reduces the size of the DAE system but introduces a one-iteration lag between the
internal algebraic variables and others in the DAE system.
• VarService shall be avoided for singular functions (non-continuous) and shall not be adopted to
circumvent initializing algebraic equations.
• VarService takes an argument sequential, which is True by default. Non-sequential VarSer-
vice shall not depend on other VarService calculated at the same step as they will be evaluated
simultaneously.
• andes.interop.pandapower.to_pandapower() set all generators as controllable by de-
fault. Generators in converted the pandapower case are named using the idx of StaticGen.
• Bug fixes in interop.pandapower.make_link_table().
Other changes:
• Added a new service type andes.core.service.SubsService for temporary symbols that will
be substituted at code generation time.
• TDS.plt.plot() now accepts a list of variable objects. For example, ss.TDS.plt.plot([ss.
GENROU.omega, ss.GENROU.delta], a=[0, 1]) will plot the rotor speed and angles of
the 0-th and the 1-st generator.
• Added REGCP1 model for generic converters with PLL support.
• Fixed PSS/E parser for HYGOV.
• Adjustments in the Pandapower interface. Added make_GSF() for the generation shift factor matrix.
• Reduced import overhead for the command-line tool.
Interoperability:
• Added interoperability modules for MATPOWER (through Oct2Py), pandapower and pypowsybl.
• Added Examples and API reference for the interoperability module.
• Improved the setup script to support extra dependencies. The following extras groups are supported:
dev and interop. See Extra support package for more information.
• Added tests for power flow calculation against MATPOWER.
Others:
• Added a shorthand command andes.system.example() to return a disposable system. It can be
useful for quick prototyping.
• Improved the formatting and navigation of Model references.
• Models store the base values for per-unit conversion in Model.bases.
• Improved PSS/E parsers for WTDTA1 model to follow PSS/E parameter definition.
• Included the Jupyter notebook examples in the documentation.
• Tweaks to the plot utility.
• Full initialization debug message will be printed only when -v 10 and run --init are both used.
• Improved warning of out-of-limit initialization. Variables initialized at limits will be shown only at the
debug level.
• Initialization improvements for models REGCA1 and REECA1.
• Added model HYGOV.
• Changed the default vout of offline exciters to zeros. All vout equations need to be multipled by ue.
will set the verbose level to 10 and run test.xlsx in the current folder, proceed to time-domain simulation
but only initialize the models. Outputs will be printed to the shell where the command is executed.
To save the output to a file, use the following in a UNIX shell:
where the first > pipes the output to a file named info.txt, and 2>&1 appends stderr (2) to stdout (1).
The other main improvement is allowing automatic limit adjustment during initialization. Due to parameter
errors, some variables will be initialized to values outside the given limits. Most commercial software does not
attempt to fix the parameter but rather adjust the limit in run time.
The same approach is followed in ANDES by automatically adjusting the upper limit, if exceeded, to variable
initial values. The lower limit, however, is kept unadjusted by default.
Discrete components now take an argument named allow_adjust so that the model developer can specify
if its limits can be adjusted or must be kept as is. Each model is allowed to specify three config flags to
customize runtime behaviors: allow_adjust, adjust_lower, and adjust_uppwer. By default,
allow_adjust=True, adjust_upper=True, and adjust_lower=False. One can modify the
config file to enable or disable the limit adjustments for specific models.
Other fixes include:
• Bug fixes for GAST parameter AT.
• Bug fixes for IEEET3, GAST, ESAC1A and ESST1A when device is off to avoid matrix singularity.
• Fixed a bug in generated select functions that omitted the coefficients of __ones.
This release features parallel processing that cuts the time for andes prepare by more than half.
• andes prepare supports multiprocessing and uses it by default.
• Added aliases andes st and andes prep for andes selftest and andes prepare.
• andes.config_logger supports setting new stream_level and file_level.
New exciter models are contributed by Jinning Wang.
• Added AC8B, IEEET3 and ESAC1A.
Other changes include disallowing numba's nopython mode.
• Bug fixes
• Dropped support for cvxoptklu.
• Bug fixes.
• Overhaul of the prepare and undill methods.
• andes prepare can be called for specific models through -m, which takes one or many model names
as arguments.
Plot enhancements:
• plot() takes an argument mark for masking y-axis data based on the left and right range pa-
rameters.
• TDS.plt provides a panoview method for plotting an panoramic view for selected variables and
devices of a model.
Models:
• Added WIP EV models and protection models.
Test case: - Added CURENT EI test system. - Added a number of IEEE 14 bus test systems for specific
models.
• Allow manually specifying variables needing initialization preceding a variable. Specify a list of variable
names through BaseVar.deps.
• Allow State variable set check_init=False to skip initialization test. One use case is for integrators with
non-zero inputs (such as state-of-charge integration).
• Solves power flow for systems with multiple areas, each with one Slack generator.
• Added Jumper for connecting two buses with zero impedance.
• REGCA1 and synchronous generators can take power ratio parameters gammap and gammaq.
• New models: IEESGO and IEEET1, EXAC4.
• Refactored exciters, turbine governors, and renewable models into modules.
• Time-domain integration now evaluates anti-windup limiter before algebraic residuals. It assures that
algebraic residuals are calculated with the new state values if pegged at limits.
• Fixed the conditions for Iq ramping in REGC; removed Iqmax and Iqmin.
• Added a new plot function plotn to allow multiple subplots in one figure.
• TDS.config.g_scale is now now used as a factor for scaling algebraic equations for better con-
vergence. Setting it to 1.0 functions the same as before.
• Added TGOV1N model which sums pref and paux after the 1/droop block.
• Added ZIP and FLoad for dynamic analysis. Need to be initialized after power flow.
• Added DAETimeSeries.get_data() method.
• Added IEEE 14-bus test cases with solar PV (ieee14_solar.xlsx) and Generic Type 3 wind
(ieee14_wt3.xlsx).
• Added Summary model to allow arbitrary information for a test case. Works in xlsx and json formats.
• PV reactive power limit works. Automatically determines the number of PVs to convert if npv2pq=0.
• Limiter and AntiWindup limiter can use sign_upper=-1 and sign_lower=-1 to negate the provided limits.
• Improved error messages for inconsistent data.
• DAETimeSeries functions refactored.
New Models:
• PVD1 model, WECC distributed PV model. Supports multiple PVD1 devices on the same bus.
• Added ACEc model, ACE calculation with continuous freq.
Changes and fixes:
• Renamed TDS._itm_step to TDS.itm_step as a public API.
• Allow variable sys_f (system frequency) in equation strings.
• Fixed ACE equation. measurement.
• Support kvxopt as a drop-in replacement for cvxopt to bring KLU to Windows (and other platforms).
• Added kvxopt as a dependency for PyPI installation.
• The Python code dump can be reformatted with yapf through the config option yapf_pycode. Re-
quires separate installation.
• The dumped Python code can be used for subsequent simulations through the config option
use_pycode.
• Improved documentation.
• Minor bug fixes.
• Added back quasi-real-time speed control through --qrt and --kqrt KQRT.
• Patched the time-domain routine for the final step.
• andes prepare now takes three mutually exclusive arguments, full, quick and incremental. The
command-line now defaults to the quick mode. andes.prepare() still uses the full mode.
• Model.s_update now evaluates the generated and the user-provided calls in sequence for each ser-
vice in order.
• Renamed model REGCAU1 to REGCA1.
• Implemented compressed NumPy format (npz) for time-domain simulation output data file.
• Implemented optional attribute vtype for specifying data type for Service.
• Patched COI speed initialization.
• Patched PSS/E parser for two-winding transformer winding and impedance modes.
• Patches PQ model equations where the "or" logic "|" is ignored in equation strings. To adjust PQ load in
time domain simulation, refer to the note in pq.py.
• Allow Model.alter to update service values.
• Patches the conda-forge script to use SymPy < 1.6. After SymPy version 1.5.1, comparison operations
cannot be sympified. Pip installations are not affected.
• Generate one lambda function for each of f and g, instead of generating one for each single f/g equation.
Requires to run andes prepare after updating.
4.10 Pre-v1.0.0
• Added exciter models EXST1, ESST3A, ESDC2A, SEXS, and IEEEX1, turbine governor model
IEEEG1 (dual-machine support), and stabilizer model ST2CUT.
• Added blocks HVGate and LVGate with a work-around for sympy.maximum/ minimum.
• Added services PostInitService (for storing initialized values), and VarService (variable services that get
updated) after limiters and before equations).
• Added service InitChecker for checking initialization values against typical values. Warnings will be
issued when out of bound or equality/ inequality conditions are not met.
• Allow internal variables to be associated with a discrete component which will be updated before ini-
tialization (through BaseVar.discrete).
• Allow turbine governors to specify an optional Tn (turbine rating). If not provided, turbine rating will
fall back to Sn (generator rating).
• Renamed OptionalSelect to DataSelect; Added NumSelect, the array-based version of DataSelect.
• Allow to regenerate code for updated models through andes prepare -qi.
• Various patches to allow zeroing out time constants in transfer functions.
This update contains a quick but significant fix to boost the simulation speed by avoiding calls to empty user-
defined numerical calls.
• In Model.flags and Block.flags, added f_num, g_num and j_num to indicate if user-defined numerical
calls exist.
• In Model.f_update, Model.g_update and Model.j_update, check the above flags to avoid unnecessary calls
to empty numeric functions.
• For the kundur_ieeest.xlsx case, simulation time was reduced from 3.5s to 2.7s.
This release contains important documentation fixes and two new blocks.
• Fixed documentations in andes doc to address a misplacement of symbols and equations.
• Converted all blocks to the division-free formulation (with dae.zf renamed to dae.Tf).
• Fixed equation errors in the block documentation.
• Implemented two new blocks: Lag2ndOrd and LeadLag2ndOrd.
• Added a prototype for IEEEST stabilizer with some fixes needed.
• Converted the differential equations to the form of T \dot{x} = f(x, y), where T is supplied to
t_const of State/ExtState.
• Added the support for Config fields in documentation (in andes doc and on readthedocs).
• Added Config consistency checking.
• Converted Model.idx from a list to DataParam.
• Added support for JSON case files. Convert existing case file to JSON with --convert json.
• Added support for PSS/E dyr files, loadable with -addfile ADDFILE.
• Added andes plot --xargs for searching variable name and plotting. See example 6.
• Various bug fixes: Fault power injection fix;
• Version 0.6.9 is the last version for the numeric-only modeling framework.
• This version will not be updated any more. But, models, routines and functions will be ported to the new
version.
FIVE
MODEL REFERENCE
Use the left navigation pane to locate the group and model and view details.
Supported Groups and Models
Group Models
ACLine Line
ACShort Jumper
ACTopology Bus
Calculation ACE, ACEc, COI
Collection Area
DCLink Ground, R, L, C, RCp, RCs, RLs, RLCs, RLCp
DCTopology Node
DG PVD1, ESD1, EV1, EV2
DGProtection DGPRCT1, DGPRCTExt
DataSeries TimeSeries
DynLoad ZIP, FLoad
Exciter EXDC2, IEEEX1, ESDC1A, ESDC2A, EXST1, ESST3A, SEXS, IEEET1, EXAC1, EXAC2, EXAC4, ESST
FreqMeasurement BusFreq, BusROCOF
Information Summary
Interface Fortescue
Motor Motor3, Motor5
OutputSelect Output
PLL PLL1, PLL2
PSS IEEEST, ST2CUT
PhasorMeasurement PMU
RenAerodynamics WTARA1, WTARV1
RenExciter REECA1, REECA1E, REECA1G
RenGen REGCA1, REGCP1, REGCV1, REGCV2, REGF1, REGF2, REGF3
RenGovernor WTDTA1, WTDS
RenPitch WTPTA1
RenPlant REPCA1
RenTorque WTTQA1
StaticACDC VSCShunt
StaticGen PV, Slack
423
ANDES Manual, Release 1.8.10
5.1 ACLine
5.1.1 Line
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.2 ACShort
5.2.1 Jumper
Jumper is a device to short two buses (merging two buses into one).
Jumper can connect two buses satisfying one of the following conditions:
• neither bus is voltage-controlled
• either bus is voltage-controlled
• both buses are voltage-controlled, and the voltages are the same.
If the buses are controlled in different voltages, power flow will not solve (as the power flow through the jumper
will be infinite).
In the solutions, the p and q are flowing out of bus1 and flowing into bus2.
Setting a Jumper's connectivity status u to zero will disconnect the two buses. In the case of a system split, one
will need to call System.connectivity() immediately following the split to detect islands.
Parameters
Variables
Initialization Equations
Algebraic Equations
5.3 ACTopology
5.3.1 Bus
AC Bus model.
Power balance equation have the form of load - injection = 0. Namely, load is positively summed,
while injections are negative.
Parameters
Variables
Initialization Equations
Algebraic Equations
5.4 Calculation
5.4.1 ACE
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
Discretes
5.4.2 ACEc
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.4.3 COI
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
wgen ωgen ExtState 0
agen δgen ExtState 0
Algebraic Equations
Services
5.5 Collection
5.5.1 Area
Area model.
Area collects back references from the Bus model and the ACTopology group.
Parameters
5.6 DCLink
Basic DC links
Common Parameters: u, name
Available models: Ground, R, L, C, RCp, RCs, RLs, RLCs, RLCp
5.6.1 Ground
Parameters
Variables
Initialization Equations
Algebraic Equations
5.6.2 R
Resistive dc line
Parameters
Variables
Initialization Equations
Algebraic Equations
5.6.3 L
Inductive dc line
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
IL IL State −u (v1 − v2 )
Algebraic Equations
5.6.4 C
Capacitive dc branch
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
vC vC State −Idc u
Algebraic Equations
5.6.5 RCp
Parameters
Variables
Initialization Equations
Differential Equations
Algebraic Equations
5.6.6 RCs
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
vC vC State −Idc u C
Algebraic Equations
5.6.7 RLs
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
IL IL State u (−IL R + v1 − v2 ) L
Algebraic Equations
5.6.8 RLCs
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
IL IL State u (−IL R + v1 − v2 − vC ) L
vC vC State IL u C
Algebraic Equations
5.6.9 RLCp
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
IL IL State uvC( ) L
vC vC State −u −IL + Idc − vRC C
Algebraic Equations
5.7 DCTopology
5.7.1 Node
DC Node model.
A DC Node is like an AC Bus. DC devices need to be connected to Nodes to inject power flow.
Parameters
Variables
Initialization Equations
Algebraic Equations
5.8 DG
5.8.1 PVD1
5.8. DG 449
ANDES Manual, Release 1.8.10
Parameters
Variables
5.8. DG 451
ANDES Manual, Release 1.8.10
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Ipout_y yIpout State 1.0yI pcmd − yIpout Tip
Iqout_y yIqout State 1.0yI qcmd − yIqout Tiq
Algebraic Equations
Services
maxsq0 (( ) ( vice
))
Iqmaxsq 2
Iqmax FixPiecewise 0, I 2 − (yI pcmd )2 ≤ 0 , Ialim
2 − (yI pcmd )2 , TrueVarService
(( alim 2 2
) ( 2 2
))
Pref 0u Pref 0u
Iq- 2
Iqmax0 FixPiecewise 0, Ialim − V 2 ≤ 0 , Ialim − V 2 , True ConstSer-
2 2
maxsq0 vice
Discretes
Blocks
5.8. DG 457
ANDES Manual, Release 1.8.10
5.8.2 ESD1
Parameters
Variables
5.8. DG 459
ANDES Manual, Release 1.8.10
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Ipout_y yIpout State 1.0yI pcmd − yIpout Tip
Iqout_y yIqout State 1.0yI qcmd − yIqout Tiq
( LT N )
Vy z0
Sb,sys −HC V yIpout z1LT N − Ipout
HD
pIG_y ypIG State 3600En Tf
SOC SOC AliasState 0
5.8. DG 461
ANDES Manual, Release 1.8.10
Algebraic Equations
Services
maxsq0 (( ) ( vice
))
Iqmaxsq 2
Iqmax FixPiecewise 0, I 2 − (yI pcmd )2 ≤ 0 , Ialim
2 − (yI pcmd )2 , TrueVarService
(( alim 2 2
) ( 2 2
))
Pref 0u Pref 0u
Iq- 2
Iqmax0 FixPiecewise 0, Ialim − V 2 ≤ 0 , Ialim − V 2 , True ConstSer-
2 2
maxsq0 vice
5.8. DG 463
ANDES Manual, Release 1.8.10
Discretes
Blocks
5.8.3 EV1
Parameters
5.8. DG 465
ANDES Manual, Release 1.8.10
Variables
Initialization Equations
5.8. DG 467
ANDES Manual, Release 1.8.10
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Ipout_y yIpout State 1.0yI pcmd − yIpout Tip
Iqout_y yIqout State 1.0yI qcmd − yIqout Tiq
( LT N )
Vy z0
Sb,sys −HC V yIpout z1LT N − Ipout
HD
pIG_y ypIG State 3600En Tf
SOC SOC AliasState 0
Algebraic Equations
Services
maxsq0 (( ) ( vice
))
Iqmaxsq 2
Iqmax FixPiecewise 0, I 2 − (yI pcmd )2 ≤ 0 , Ialim
2 − (yI pcmd )2 , TrueVarService
(( alim 2 2
) ( 2 2
))
Pref 0u Pref 0u
Iq- 2
Iqmax0 FixPiecewise 0, Ialim − V 2 ≤ 0 , Ialim − V 2 , True ConstSer-
2 2
maxsq0 vice
Discretes
Blocks
5.8. DG 471
ANDES Manual, Release 1.8.10
5.8.4 EV2
Parameters
Variables
5.8. DG 473
ANDES Manual, Release 1.8.10
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Ipout_y yIpout State 1.0yI pcmd − yIpout Tip
Iqout_y yIqout State 1.0yI qcmd − yIqout Tiq
( LT N )
Vy z0
Sb,sys −HC V yIpout z1LT N − Ipout
HD
pIG_y ypIG State 3600En Tf
SOC SOC AliasState 0
5.8. DG 475
ANDES Manual, Release 1.8.10
Algebraic Equations
Services
maxsq0 (( ) ( vice
))
Iqmaxsq 2
Iqmax FixPiecewise 0, I 2 − (yI pcmd )2 ≤ 0 , Ialim
2 − (yI pcmd )2 , TrueVarService
(( alim 2 2
) ( 2 2
))
Pref 0u Pref 0u
Iq- 2
Iqmax0 FixPiecewise 0, Ialim − V 2 ≤ 0 , Ialim − V 2 , True ConstSer-
2 2
maxsq0 vice
5.8. DG 477
ANDES Manual, Release 1.8.10
Discretes
Blocks
5.9 DGProtection
5.9.1 DGPRCT1
NERC. Bulk Power System Reliability Perspectives on the Adoption of IEEE 1547-2018. March 2020. Avail-
able:
https://www.nerc.com/comm/PC_Reliability_Guidelines_DL/Guideline_IEEE_1547-2018_BPS_
Perspectives.pdf
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
T res
IAWfl1_y yIAW f l1 State − Tf l1res + ziLf l1 · (1 − res) 1
T res
IAWfl2_y yIAW f l2 State − Tf l2res + ziLf l2 · (1 − res) 1
T res
IAWfu1_y yIAW f u1 State − fTu1res + ziLf u1 · (1 − res) 1
T res
IAWfu2_y yIAW f u2 State − fTu2res + ziLf l2 · (1 − res) 1
IAWVl1_y yIAW V l1 State − TTvl1res
res
+ ziLV l1 · (1 − res) 1
IAWVl2_y yIAW V l2 State − TTvl2res
res
+ ziLV l2 · (1 − res) 1
IAWVl3_y yIAW V l3 State − T res + ziLV l2 · (1 − res)
Tvl3 res
1
IAWVu1_y yIAW V u1 State − Tvu1 res
T res + zi
LV u1 · (1 − res) 1
IAWVu2_y yIAW V u2 State − Tvu2 res
T res + zi
LV u2 · (1 − res) 1
Algebraic Equations
Services
Discretes
Blocks
5.9.2 DGPRCTExt
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
T res
IAWfl1_y yIAW f l1 State − Tf l1res + ziLf l1 · (1 − res) 1
T res
IAWfl2_y yIAW f l2 State − Tf l2res + ziLf l2 · (1 − res) 1
T res
IAWfu1_y yIAW f u1 State − fTu1res + ziLf u1 · (1 − res) 1
Tf u2 res
IAWfu2_y yIAW f u2 State − T res + ziLf l2 · (1 − res) 1
IAWVl1_y yIAW V l1 State − TTvl1res
res
+ ziLV l1 · (1 − res) 1
IAWVl2_y yIAW V l2 State − T res + ziLV l2 · (1 − res)
Tvl2 res
1
IAWVl3_y yIAW V l3 State − TTvl3res
res
+ ziLV l2 · (1 − res) 1
IAWVu1_y yIAW V u1 State − T res + ziLV u1 · (1 − res)
Tvu1 res
1
IAWVu2_y yIAW V u2 State − Tvu2 res
T res + zi
LV u2 · (1 − res) 1
Algebraic Equations
Services
Discretes
Blocks
5.10 DataSeries
5.10.1 TimeSeries
Parameters
Discretes
5.11 DynLoad
5.11.1 ZIP
ZIP load model (polynomial load). This model is initialized after power flow.
Please check the config of PQ to avoid double counting. If this ZIP model is in use, one should typically set
p2p=1.0 and q2q=1.0 while leaving the others (p2i, p2z, q2i, q2z, and pq2z) as zeros. This setting allows one
to impose the desired powers by the static PQ and to convert them based on the percentage specified in the
ZIP.
The percentages for active power, (kpp, kpi, and kpz) must sum up to 100. Otherwise, initialization will fail.
The same applies to the reactive power percentages.
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.11.2 FLoad
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.12 Exciter
5.12.1 EXDC2
EXDC2 model.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
vp Vp State ue (−KE Vp − Se (|Vout |)Vp + yLA ) TE
LS_y yLS State 1.0Eterm − yLS TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
W_x x′W State Vp − x′W TF 1
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.2 IEEEX1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
vp Vp State ue (−KE Vp − Se (|Vout |)Vp + yLA ) TE
LS_y yLS State 1.0Eterm − yLS TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
W_x x′W State Vp − x′W TF 1
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.3 ESDC1A
ESDC1A model.
This model derives from ESDC2A and changes the regular limits to "VRMAX" and "VRMIN".
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
INT_y yIN T State ue (−VF E + yLA ) TE
WF_x x′W F State −x′W F + yIN T TF 1
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.4 ESDC2A
ESDC2A model.
This model is implemented as described in the PSS/E manual, except that the HVGate is not in use. Due to
the HVGate and saturation function, the results are close to but different from TSAT.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
INT_y yIN T State ue (−VF E + yLA ) TE
WF_x x′W F State −x′W F + yIN T TF 1
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.5 EXST1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vl − x′LL TB
LR_y yLR State KA yLL − yLR TA
WF_x x′W F State −x′W F + yLR TF
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.6 ESST3A
Parameters
Variables
Initialization Equations
geb
vi Vi Al- −Eterm + Vref
geb
vil Vil Al- Vi ziHLI + VIM AX zuHLI + VIM IN zlHLI
geb
HG_y yHG Al- UEL z0N oneHG + Vil z1N oneHG
geb
LL_y yLL Al- yHG
geb
vf vf Ex-
tAl-
geb
Xad- Xad If d Ex-
Ifd tAl-
geb
a θ Ex-
tAl-
5.12. Exciter geb 523
vbus V Ex-
tAl-
ANDES Manual, Release 1.8.10
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State −x′LL + yHG TB
LAW1_y yLAW 1 State KA yLL − yLAW 1 TA
LAW2_y yLAW 2 State KM VRS − yLAW 2 KC
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.7 SEXS
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LL_x x′LL State Vi − x′LL TB
LAW_y yLAW State KyLL − yLAW TE
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.8 IEEET1
IEEET1 exciter.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LA_y yLA State KA ue (Vi − yW F ) − yLA TA
INT_y yIN T State ue (−VF E + yLA ) TE
WF_x x′W F State vout − x′W F TF
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.9 EXAC1
EXAC1 model.
Ref: https://www.powerworld.com/WebHelp/Content/TransientModels_HTML/Exciter%20EXAC1.htm
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
INT_y yIN T State ue (−VF E + yLA ) TE
WF_x x′W F State VF E − x′W F TF
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.10 EXAC2
EXAC2 model.
Ref: https://www.powerworld.com/WebHelp/Content/TransientModels_HTML/Exciter%20EXAC2.htm
Notes
VLR is an input parameter, but to initialize the LVGate, an internal VLRx will be computed as a contant upon
initialization. The constant VLRx will be used in the place of VLR in the block diagram.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
INT_y yIN T State ue (−VF E + yV R ) TE
WF_x x′W F State VF E − x′W F TF
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.11 EXAC4
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vi ziHLI + VIM AX zuHLI + VIM IN zlHLI − x′LL TB
LR_y yLR State KA yLL − yLR TA
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.12 ESST4B
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
PI1_xi xiP I1 State KIR (Vi + 2yP I1 − 2ysP I1 )
LA_y yLA State −yLA + 1.0yP I1 TA
PI2_xi xiP I2 State KIM (yLA + 2yP I2 − yV G − 2ysP I2 )
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.13 AC8B
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
PID_xi xiP ID State kI (Vi + 2yP ID − 2ysP ID )
PID_WO_x x′P ID W OP ID State uinP ID − x′P ID W OP ID Td
LA_y yLA State KA yP ID − yLA TA
INT_y yIN T State ue (−VF E + yLA ) TE
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.14 IEEET3
Exciter IEEET3.
Reference:
[1] PowerWorld, Exciter IEEET3, [Online],
[2] NEPLAN, Exciters Models, [Online],
Available:
https://www.powerworld.com/WebHelp/Content/TransientModels_HTML/Exciter%20IEEET3.htm
https://www.neplan.ch/wp-content/uploads/2015/08/Nep_EXCITERS1.pdf
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LA3_y yLA3 State KA ue (Vi − yW F() − yLA3 ) TA
LA1_y yLA1 State −KE yLA1 + ue VBM AX zuHL + yV B ziHL TE
WF_x x′W F State −x′W F + yLA1 TF
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.15 ESAC1A
Exciter ESAC1A.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State Vi − x′LL TB
LA_y yLA State KA yLL − yLA TA
INT_y yIN T State ue (−VF E + yLV G ) TE
WF_x x′W F State VF E − x′W F TF 1
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.12.16 ESST1A
Parameters
Variables
Initialization Equations
SG SG Algeb SG0
LR_x xLR Algeb KLR (−ILR + Xad If d )
limLR
LR_y yLR Algeb xLR
(zi + zllimLR zero )
vi Vi Algeb ue SGsSW
1
V OS
+ UEL sSW
1
U EL
+ Vref + Vs − yLG − yW F
vil_x xvil Algeb Vi
limvil
vil_y yvil Algeb VIM limvil + V
( AX zu IM IN z(
l + xvil zilim
))
vil
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Eterm − yLG TR
LL_x x′LL State −x′LL + yHV G1 TB
LL1_x x′LL1 State −x′LL1 + yLL TB1
LA_y yLA State KA yLL1 − yLA TA
WF_x x′W F State −x′W F + yLV G TF
omega ω ExtState 0
Algebraic Equations
HVG1_y yHV G1 Algeb U EL2 z0N oneHV G1 − yHV G1 + yvil z1N oneHV G1
( )2
LL_y yLL Algeb TB x′LL − TB yLL + TC (−x′LL + yHV G1 ) + z1LTLL (−x′LL + yLL )
LL1_y yLL1 Algeb TB1 x′LL1 − TB1 yLL1 + TC1 (−x′LL1 + yLL ) +
( )2
z1LTLL1 (−x′LL1 + yLL1 )
( )
vas VAs Algeb −VAs + ue SGsSW V OS
+ yLA − yLR
( 2 ( ))
UEL3 U EL3 Algeb −U EL3 + ue UEL sSW 3
U EL
+ llim 1 − sSWU EL
3
HVG_y yHV G Algeb U EL3 z0N oneHV G + VAs z1N oneHV G − yHV G
LVG_y yLV G Algeb OEL z0N oneLV G + yHV G z1N oneLV G − yLV G
vol_x xvol Algeb −xvol + yLV G
vol_y yvol Algeb ef dl zllimvol + ef du zulimvol + xvol zilimvol − yvol
WF_y yW F Algeb KF (−x′W F + yLV G ) − TF yW F
vf vf ExtAl- ue (−vf 0 + vout )
geb
XadIfd Xad If d ExtAl- 0
geb
a θ ExtAl- 0
geb
vbus V ExtAl- 0
geb
vd Vd ExtAl- 0
geb
vq Vq ExtAl- 0
geb
Services
Discretes
Blocks
5.12.17 ESAC5A
Exciter ESAC5A.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LP_y yLP State Eterm − yLP TR
VR_y yV R State KA vi − yV R TA
LL_x x′LL State −x′LL + yV R TF 2
WF_x x′W F State −x′W F + yLL TF 1
INT_y yIN T State ue (−VF E + yV R ) TE
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.13 Experimental
Experimental group
Common Parameters: u, name
5.14 FreqMeasurement
Frequency measurements.
Common Parameters: u, name
Common Variables: f
Available models: BusFreq, BusROCOF
5.14.1 BusFreq
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
L_y yL State θ − θ0 − yL Tf
WO_x x′W O State −x′W O + yL Tw
Algebraic Equations
Services
Blocks
5.14.2 BusROCOF
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
L_y yL State θ − θ0 − yL Tf
WO_x x′W O State −x′W O + yL Tw
Wf_x x′W f State f − x′W f Tr
Algebraic Equations
Services
Blocks
5.15 Information
5.15.1 Summary
Class for storing system summary. Can be used for random information or notes.
Parameters
5.16 Interface
5.16.1 Fortescue
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.17 Motor
5.17.1 Motor3
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
slip σ State u (−τ
( e + τm ) ) M
I (−x′ +x )+e′
e1d e′d State u ωb σe′q − q T0′
0 d
( )
−I (−x +x )+e′
′
e1q e′q State u −ωb σe′d − d T ′ 0 q
0
Algebraic Equations
Services
5.17.2 Motor5
Parameters
Variables
Initialization Equations
Differential Equations
Algebraic Equations
Services
5.18 OutputSelect
5.18.1 Output
Parameters
5.19 PLL
5.19.1 PLL1
Simple Phasor Lock Loop (PLL) using one PI controller. The PI controller minimizes the error between the
input and output angle.
Input bus angle signal -> Lag filter 1 with Tf -> Output angle af_y.
(af_y - am) -> PI Controller (Kp, Ki) -> PI_y
Estimated angle ae = (2 * pi * fn * PI_y) -> Lag filter 2 with Tp -> am.
The output signal is am, a state variable.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
af_y yaf State θ − yaf Tf
PI_xi xiP I State Ki u (−θm + yaf )
ae θest State 2πfn yP I
am θm State θest − θm Tp
Algebraic Equations
Blocks
5.19.2 PLL2
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
PI_xi xiP I State Ki V sin (θ − θm )
am θm State 2πfn yP I
Algebraic Equations
Blocks
5.20 PSS
5.20.1 IEEEST
IEEEST stabilizer model. Automatically adds frequency measurement devices if not provided.
Input signals (MODE):
1. Rotor speed deviation (p.u.),
2. Bus frequency deviation (p.u.) (*),
3. Generator P electrical in Gen MVABase (p.u.),
4. Generator accelerating power (p.u.),
5. Bus voltage (p.u.),
6. Derivative of p.u. bus voltage.
(*) Due to the frequency measurement implementation difference, mode 2 is likely to yield different results
across software.
Note: Blocks are named F1, F2, LL1, LL2 and WO in sequence. Two limiters are named VLIM and OLIM
in sequence.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
F1_x x′F 1 State −A1 x′F 1 + Sig − yF 1 A2
F1_y yF 1 State x′F 1
F2_x1 x′F 2 State −A3 x′F 2 − x′′F 2 + yF 1 A4
F2_x2 x′′F 2 State x′F 2
LL1_x x′LL1 State −x′LL1 + yF 2 T2
LL2_x x′LL2 State −x′LL2 + yLL1 T4
WO_x x′W O State −x′W O + yV ks T6
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.20.2 ST2CUT
ST2CUT stabilizer model. Automatically adds frequency measurement devices if not provided.
Input signals (MODE and MODE2):
0 - Disable input signal 1 (s1) - Rotor speed deviation (p.u.), 2 (s2) - Bus frequency deviation (*) (p.u.), 3 (s3)
- Generator P electrical in Gen MVABase (p.u.), 4 (s4) - Generator accelerating power (p.u.), 5 (s5) - Bus
voltage (p.u.), 6 (s6) - Derivative of p.u. bus voltage.
(*) Due to the frequency measurement implementation difference, mode 2 is likely to yield different results
across software.
Blocks are named LL1, LL2, LL3, LL4 in sequence. Two limiters are named VSS_lim and OLIM in sequence.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
L1_y yL1 State K1 Sig − yL1 T1
L2_y yL2 State K2 Sig2 − yL2 T2
WO_x x′W O State IN − x′W O T4
LL1_x x′LL1 State −x′LL1 + yW O T6
LL2_x x′LL2 State −x′LL2 + yLL1 T8
LL3_x x′LL3 State −x′LL3 + yLL2 T10
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.21 PhasorMeasurement
Phasor measurements
Common Parameters: u, name
Common Variables: am, vm
Available models: PMU
5.21.1 PMU
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
am θm State θ − θm Ta
vm Vm State V − Vm Tv
Algebraic Equations
5.22 RenAerodynamics
5.22.1 WTARA1
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.22.2 WTARV1
Parameters
Variables
Initialization Equations
Algebraic Equations
5.23 RenExciter
5.23.1 REECA1
Parameters
Variables
Initialization Equations
Qerr Qerr Algeb P F selziP F lim + Qmax zuP F lim + Qmin zlP F lim − Qe
PIQ_ys ysP IQ Algeb Kqp Qerr sSW1
V
Differential Equations
Algebraic Equations
Services
Discretes
Blocks
5.23.2 REECA1E
REGCA1 with inertia emulation and primary frequency droop. Measurements are based on frequency mea-
surement model.
Bus ROCOF obtained from BusROCOF devices.
Parameters
Variables
Initialization Equations
Qerr Qerr Algeb P F selzi P F lim + Qmax zuP F lim + Qmin zlP F lim − Qe
PIQ_ys ysP IQ Algeb Kqp Qerr sSW1
V
Differential Equations
Algebraic Equations
Services
Discretes
Blocks
5.23.3 REECA1G
Parameters
Variables
Initialization Equations
Qerr Qerr Algeb P F selzi P F lim + Qmax zuP F lim + Qmin zlP F lim − Qe
PIQ_ys ysP IQ Algeb Kqp Qerr sSW1
V
Differential Equations
Algebraic Equations
( − Qerr + Qmax zu
Qerr Qerr Algeb P F selziP F lim P F lim + Q P F lim − Qe
min z)l
PIQ_ys ysP IQ Algeb (1 − zV dip ) Kqp Qerr sSW V
+ xiP IQ − ysP IQ
( 1
)
lim lim lim
PIQ_y yP IQ Algeb (1 − zV dip ) Vmax zu P IQ + Vmin zl P IQ − yP IQ + ysP IQ zi P IQ
( )
Vsel_x xV sel Algeb sSW
0
V
Q s
cpf 1
SWP F
+ Q s
ref 0
SWP F
+ V SWV
ref 1 + s1 yP IQ − xV sel
Vsel_y yV sel Algeb Vmax zulimV sel + Vmin zllimV sel + xV sel zilimV sel − yV sel
Services
Discretes
Blocks
5.24 RenGen
5.24.1 REGCA1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
S1_y yS1 State −Iqcmd − yS1 Tg
S2_y yS2 State 1.0V − yS2 Tf ltr
S0_y yS0 State Ipcmd − yS0 Tg
Algebraic Equations
Services
Discretes
Blocks
5.24.2 REGCP1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
S1_y yS1 State −Iqcmd − yS1 Tg
S2_y yS2 State 1.0V − yS2 Tf ltr
S0_y yS0 State Ipcmd − yS0 Tg
am θm ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.24.3 REGCV1
Notes
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
dw ∆ω State −D∆ω − Pe + Pref 2 M
delta δ State 2π∆ωf
PIvd_xi xiP Ivd State kivd (Vd − vref 2 )
PIvq_xi xiP Ivq State Vq kivq
PIId_xi xiP IId State kidi (Id − yP Ivd )
PIIq_xi xiP IIq State kiqi (Iq − yP Ivq )
udLag_y yudLag State udref − yudLag Tc
uqLag_y yuqLag State uqref − yuqLag Tc
ud ud AliasState 0
uq uq AliasState 0
Algebraic Equations
Services
Blocks
5.24.4 REGCV2
Notes
To avoid small-signal stability issues, one take extreme care in setting the PI control gains Kpvd, Kivd, Kpvq,
and Kivq, and the emulated inertia M and damping D.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
dw ∆ω State −D∆ω − Pe + Pref 2 M
delta δ State 2π∆ωf
PIvd_xi xiP Ivd State kivd (Vd − vref 2 )
PIvq_xi xiP Ivq State Vq kivq
LGId_y yLGId State −yLGId + yP Ivd TId
LGIq_y yLGIq State −yLGIq + yP Ivq TIq
Algebraic Equations
Services
Blocks
5.24.5 REGF1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Psen_y yP sen State Pe − yP sen Tc
Qsen_y yQsen State Qe − yQsen Tc
Psig_y yP sig State P aux + yP sen − yP sig Tpm
Qsig_y yQsig State Qaux + yQsen − yQsig Tpm
PIplim_xi xiP Iplim State KIplim (−yP sen + yP sig )
PIqlim_xi xiP Iqlim State KIqlim (−yQsen + yQsig )
delta δ State ydw
PIvd_xi xiP Ivd State KIv (−Vd + vref 2 )
PIvq_xi xiP Ivq State −KIv Vq
PIId_xi xiP IId State KIi (−Id + yP Ivd )
PIIq_xi xiP IIq State KIi (−Iq + yP Ivq )
udLag_y yudLag State udref − yudLag Te
uqLag_y yuqLag State uqref − yuqLag Te
ud ud AliasState 0
uq uq AliasState 0
Algebraic Equations
Services
Discretes
Blocks
5.24.6 REGF2
Parameters
Variables
Initialization Equations
Differential Equations
Algebraic Equations
Services
Discretes
Blocks
5.24.7 REGF3
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Psen_y yP sen State Pe − yP sen Tc
Qsen_y yQsen State Qe − yQsen Tc
Psig_y yP sig State P aux + yP sen − yP sig Tpm
Qsig_y yQsig State Qaux + yQsen − yQsig Tpm
PIplim_xi xiP Iplim State KIplim (−yP sen + yP sig )
PIqlim_xi xiP Iqlim State KIqlim (−yQsen + yQsig )
delta δ State ydw
vref2 vref2 State dV w0
PIvd_xi xiP Ivd State KIv (−Vd + vref2 )
PIvq_xi xiP Ivq State −KIv Vq
PIId_xi xiP IId State KIi (−Id + yP Ivd )
PIIq_xi xiP IIq State KIi (−Iq + yP Ivq )
udLag_y yudLag State udref − yudLag Te
uqLag_y yuqLag State uqref − yuqLag Te
ud ud AliasState 0
uq uq AliasState 0
Algebraic Equations
Services
Discretes
Blocks
5.25 RenGovernor
5.25.1 WTDTA1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
s1_y ys1 State −1.0Pd + 1.0Pys1 − 1.0ys3
m
2Ht
s2_y ys2 State −1.0Damp (−ω0 + ys2 ) + 1.0Pd − 1.0P e
ys2 + 1.0ys3 2Hg
s3_y ys3 State Kshaf t (ys1 − ys2 ) 1.0
wt ωt AliasState 0
wg ωg AliasState 0
Algebraic Equations
Services
Blocks
5.25.2 WTDS
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
m −P e)
s1_y ys1 State −1.0Dshaf t (−ωr0 + ys1 ) + 1.0(Pwge 2H
s3_y ys3 State 0
wt ωt AliasState 0
wg ωg AliasState 0
Algebraic Equations
Services
Blocks
5.26 RenPitch
5.26.1 WTPTA1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
PIc_xi xiP Ic State Kic (P ord − P ref )
PIw_xi xiP Iw State Kiw (Kcc (P ord − P ref ) − ωref + wt)
LG_y yLG State −yLG + 1.0yP Ic + 1.0yP Iw Tθ
wt wt ExtState 0
Pord P ord ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.27 RenPlant
5.27.1 REPCA1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
s0_y ys0 State Vcomp sSW
1
VC
+ sSW
0
VC
(Kc Qline + V ) − ys0 Tf ltr
s1_y ys1 State Qline − ys1 Tf ltr
s2_xi xis2 State Ki (ehld + 2ys2 − 2yss2 )
s3_x x′s3 State −x′s3 + ys2 Tf v
s4_y ys4 State Pline(− ys4 ) Tp
s5_xi xis5 State Kig Perr zifeHL + femax zufeHL + femin zlfeHL + 2ys5 − 2yss5
s6_y ys6 State ys5 − ys6 Tg
Algebraic Equations
Services
Discretes
Blocks
5.28 RenTorque
5.28.1 WTTQA1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
s1_y ys1 State 1.0Pe − ys1 Tp
s2_y ys2 State 1.0yfP e − ys2 Twref
PI_xi xiP I State Kip Tsel
wg ωg ExtState 0
wt ωt ExtState 0
s3_y ys3 ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.29 StaticACDC
5.29.1 VSCShunt
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
Discretes
5.30 StaticGen
5.30.1 PV
Static PV generator with reactive power limit checking and PV-to-PQ conversion.
pv2pq = 1 turns on the conversion. It starts from iteration min_iter or when the convergence error drops below
err_tol.
The PV-to-PQ conversion first ranks the reactive violations. A maximum number of npv2pq PVs above the
upper limit, and a maximum of npv2pq PVs below the lower limit will be converted to PQ, which sets the
reactive power to pmax or pmin.
If pv2pq is 1 (enabled) and npv2pq is 0, heuristics will be used to determine the number of PVs to be converted
for each iteration.
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
Discretes
5.30.2 Slack
Slack generator.
Parameters
Variables
Initialization Equations
Algebraic Equations
Discretes
5.31 StaticLoad
5.31.1 PQ
PQ load model.
Implements an automatic pq2z conversion during power flow when the voltage is outside [vmin, vmax]. The
conversion can be turned off by setting pq2z to 0 in the Config file.
Before time-domain simulation, PQ load will be converted to impedance, current source, and power source
based on the weights in the Config file.
Weights (p2p, p2i, p2z) corresponds to the weights for constant power, constant current and constant
impedance. p2p, p2i and p2z must be in decimal numbers and sum up exactly to 1. The same rule applies to
(q2q, q2i, q2z).
To alter the PQ load in terms of power during simulation, one needs to set the conversion weights to preserve
the constant power portion. For example, the PQ can remain as constant power load by setting
ss.PQ.config.p2p = 1.0
ss.PQ.config.p2i = 0
ss.PQ.config.p2z = 0
ss.PQ.config.q2q = 1.0
ss.PQ.config.q2i = 0
ss.PQ.config.q2z = 0
Then, the constant power portion can be altered by changing the Ppf and Qpf constants for active power and
reactive power.
The equivalent constant current components are in constants Ipeq and Iqeq for active and reactive current,
and the equivalent impedances are in Req and Xeq.
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
Discretes
5.32 StaticShunt
5.32.1 Shunt
Parameters
Variables
Initialization Equations
Algebraic Equations
5.32.2 ShuntTD
Parameters
Variables
Initialization Equations
Algebraic Equations
5.32.3 ShuntSw
gs = [0, 0]
bs = [0.2, 0.2]
ns = [2, 4]
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
Discretes
5.33 SynGen
5.33.1 GENCLS
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
delta δ State 2πf u (ω − 1)
omega ω State u (−D (ω − 1) − τe + τm ) M
Algebraic Equations
Services
5.33.2 GENROU
Notes
Parameters:
• xd2 and xq2 must be equal to pass initialization.
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
delta δ State 2πf u (ω − 1)
omega ω State u (−D (ω − 1) − τe + τm ) M
e1q e′q State −Xad If d + vf ′
Td0
e1d e′d State −Xaq I1q ′
Tq0
e2d e′′d State −I(d (x′d − xl )) − e′′d + e′q ′′
Td0
e2q e′′q State Iq −xl + x′q − e′′q + e′d ′′
Tq0
Algebraic Equations
Services
Discretes
Blocks
5.33.3 PLBVFU1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
Vflt Vf lt State 1/Vscale V ts − Vf lt − Vof f s Tv
omega ω State 1/fscale f ts − ω − fof f s Tf
delta δ State 2πfn u (ω − 1)
Algebraic Equations
Services
5.34 TimedEvent
5.34.1 Toggle
Parameters
Services
5.34.2 Fault
Three-phase-to-ground fault.
A Fault device is used to apply and clear three-phase-to-ground fault to the given bus. One can set two time
parameters, tf and tc, for the fault-on and fault-clearance time, respectively, although only tf is mandatory.
A fault is implemented by a very small internal shunt impedance to be connected at the fault-on time. Its
reactance and resistance are specified by the parameters xf and rf.
To implement a fault and its clearance by tripping a line, one can combine Fault and Toggle. That is, clear
a fault in concurrence with a Toggle. The user needs to ensure data consistency so that the line trip actually
clears the fault.
Non-convergence can occur in the proximity of a fault due to various reasons, including network power transfer
capability limitation and parameter issues of controllers.
When a fault gets cleared, algebraic variables change drastically. E.g., voltages can go from nearly zero back
to 1.0. As we are using Newton's method for solving the DAE, the initial values are crucial for the immediate
step after fault clearance.
This Fault model restores the pre-fault values for algebraic variables Fault.config.scale is the scaling
factor to be multiplied to the pre-fault values for adjusting the initial values. Some trial and error are expected
for severe disturbances, combined with increasing the fault reactance xf.
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
5.34.3 Alter
Examples
To apply a PQ load change, according to PQ, one needs to set the load model to constant power and alter
Ppf and Qpf. Altering p0 and q0 will have no impact as they are not used in the equations for time-domain
simulation.
Parameters
Discretes
5.35 TurbineGov
5.35.1 TG2
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
ll_x x′ll State ωdmG − x′ll T2
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.2 TGOV1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LAG_y yLAG State Pd − yLAG T1
LL_x x′LL State −x′LL + yLAG T3
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.3 TGOV1DB
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LAG_y yLAG State Pd − yLAG T1
LL_x x′LL State −x′LL + yLAG T3
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.4 TGOV1N
Examples
To update all paux0 values to paux_new, which contains the new values, do
instead of
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LAG_y yLAG State Pd − yLAG T1
LL_x x′LL State −x′LL + yLAG T3
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.5 TGOV1NDB
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LAG_y yLAG State Pd − yLAG T1
LL_x x′LL State −x′LL + yLAG T3
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.6 IEEEG1
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LL_x x′LL State ωdev − x′LL T1
IAW_y yIAW State Vsl 1
L4_y yL4 State yIAW − yL4 T4
L5_y yL5 State yL4 − yL5 T5
L6_y yL6 State yL5 − yL6 T6
L7_y yL7 State yL6 − yL7 T7
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.7 IEESGO
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
F1_y yF 1 State K1 ue (ω − ωref ) − yF 1 T1
F2_x x′F 2 State −x′F 2 + yF 1 T3
F3_y yF 3 State −yF 3 + 1.0yHL T4
F4_y yF 4 State K2 yF 3 − yF 4 T5
F5_y yF 5 State K3 yF 4 − yF 5 T6
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.8 GAST
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LAG_y yLAG State −yLAG + yLV G T1
LG2_y yLG2 State yLAG − yLG2 T2
LG3_y yLG3 State yLG2 − yLG3 T3
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.9 HYGOV
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Pd − yLG Tf
gtpos δ State yLG
LAG_y yLAG State dg − yLAG Tg
yq2
q_y yq State 1− 2
yLAG
Tw
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.10 HYGOVDB
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
LG_y yLG State Pd − yLG Tf
gtpos δ State yLG
LAG_y yLAG State dg − yLAG Tg
yq2
q_y yq State 1− 2
yLAG
Tw
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.35.11 HYGOV4
Parameters
Variables
Initialization Equations
Differential Equations
Name Symbol Type RHS of Equation "T x' = f(x, y)" T (LHS)
GATE_y yGAT E State ySV 1
WO_x x′W O State −x′W O + yGAT E Tr
LAG_y yLAG State Psum − yLAG Tp
q_y yq State Hdam − trhead Tw
omega ω ExtState 0
Algebraic Equations
Services
Discretes
Blocks
5.36 Undefined
5.37 VoltComp
5.37.1 IEEEVC
Parameters
Variables
Initialization Equations
Algebraic Equations
Services
SIX
API REFERENCE
6.1 System
6.1.1 andes.system
Functions
example
777
ANDES Manual, Release 1.8.10
fix_view_arrays
andes.system.fix_view_arrays(system)
Point NumPy arrays without OWNDATA (termed "view arrays" here) to the source array.
This function properly sets v and e arrays of internal variables as views of the corresponding DAE arrays.
Inputs will be refreshed for each model.
Parameters
system [andes.system.System] System object to be fixed
import_pycode
andes.system.import_pycode(user_pycode_path=None)
Helper function to import generated pycode in the following priority:
1. a user-provided path from CLI. Currently, this is only for specifying the path to store the generated
pycode via andes prepare.
2. ~/.andes/pycode. This is where pycode is stored by default.
3. <andes_package_root>/pycode. One can store pycode in the ANDES package folder
and ship a full package, which does not require code generation.
load_config_rc
andes.system.load_config_rc(conf_path=None)
Load config from an rc-formatted file.
Parameters
conf_path [None or str] Path to the config file. If is None, the function body will not
run.
Returns
configparse.ConfigParser
reload_submodules
andes.system.reload_submodules(module_name)
Helper function for reloading an existing module and its submodules.
It is used to reload the pycode module after regenerating code.
Classes
andes.system.ExistingModels
class andes.system.ExistingModels
Storage class for existing models
__init__()
Methods
andes.system.System
Notes
System stores model and routine instances as attributes. Model and routine attribute names are the same
as their class names. For example, Bus is stored at system.Bus, the power flow calculation routine is
at system.PFlow, and the numerical DAE instance is at system.dae. See attributes for the list of
attributes.
Attributes
dae [andes.variables.dae.DAE] Numerical DAE storage
files [andes.variables.fileman.FileMan] File path storage
config [andes.core.Config] System config storage
models [OrderedDict] model name and instance pairs
groups [OrderedDict] group name and instance pairs
routines [OrderedDict] routine name and instance pairs
__init__(case: Optional[str] = None, name: Optional[str] = None, config: Optional[Dict] = None,
config_path: Optional[str] = None, default_config: Optional[bool] = False, options:
Optional[Dict] = None, no_undill: Optional[bool] = False, autogen_stale: Optional[bool]
= True, **kwargs)
Methods
System.add
System.as_dict
System.as_dict(vin=False, skip_empty=True)
Return system data as a dict where the keys are model names and values are dicts. Each dict has
parameter names as keys and corresponding data in an array as values.
Returns
OrderedDict
System.calc_pu_coeff
System.calc_pu_coeff()
Perform per unit value conversion.
This function calculates the per unit conversion factors, stores input parameters to vin, and perform
the conversion.
System.call_models
System.collect_config
System.collect_config()
Collect config data from models.
Returns
dict a dict containing the config from devices; class names are keys and configs in a
dict are values.
System.collect_ref
System.collect_ref()
Collect indices into BackRef for all models.
System.connectivity
System.connectivity(info=True)
Perform connectivity check for system.
Parameters
info [bool] True to log connectivity summary.
System.e_clear
System.e_clear(models: collections.OrderedDict)
Clear equation arrays in DAE and model variables.
This step must be called before calling f_update or g_update to flush existing values.
System.f_update
System.f_update(models: collections.OrderedDict)
Call the differential equation update method for models in sequence.
Notes
Updated equation values remain in models and have not been collected into DAE at the end of this
step.
System.fg_to_dae
System.fg_to_dae()
Collect equation values into the DAE arrays.
Additionally, the function resets the differential equations associated with variables pegged by anti-
windup limiters.
System.find_devices
System.find_devices()
Add dependent devices for all model based on DeviceFinder.
System.find_models
Warning: Checking the number of devices has been centralized into this function. models
passed to most System calls must be retrieved from here.
System.from_ipysheet
System.g_islands
System.g_islands()
Reset algebraic mismatches for islanded buses.
System.g_update
System.g_update(models: collections.OrderedDict)
Call the algebraic equation update method for models in sequence.
Notes
Like f_update, updated values have not collected into DAE at the end of the step.
System.get_z
System.get_z(models: collections.OrderedDict)
Get all discrete status flags in a numpy array. Values are written to dae.z in place.
Returns
numpy.array
System.import_groups
System.import_groups()
Import all groups classes defined in models/group.py.
Groups will be stored as instances with the name as class names. All groups will be stored to
dictionary System.groups.
System.import_models
System.import_models()
Import and instantiate models as System member attributes.
Models defined in models/__init__.py will be instantiated sequentially as attributes with
the same name as the class name. In addition, all models will be stored in dictionary System.
models with model names as keys and the corresponding instances as values.
Examples
system.Bus stores the Bus object, and system.GENCLS stores the classical generator object,
system.models['Bus'] points the same instance as system.Bus.
System.import_routines
System.import_routines()
Import routines as defined in routines/__init__.py.
Routines will be stored as instances with the name as class names. All routines will be stored to
dictionary System.routines.
Examples
System.PFlow is the power flow routine instance, and System.TDS and System.EIG are
time-domain analysis and eigenvalue analysis routines, respectively.
System.init
System.j_islands
System.j_islands()
Set gy diagonals to eps for a and v variables of islanded buses.
System.j_update
Notes
Updated Jacobians are immediately reflected in the DAE sparse matrices (fx, fy, gx, gy).
System.l_update_eq
System.l_update_var
System.link_ext_param
System.link_ext_param(model=None)
Retrieve values for ExtParam for the given models.
System.precompile
System.prepare
Warning: Generated lambda functions will be serialized to file, but pretty prints (SymPy
objects) can only exist in the System instance on which prepare is called.
Notes
Option incremental compares the md5 checksum of all var and service strings, and only re-
generate for updated models.
Examples
If one needs to print out LaTeX-formatted equations in a Jupyter Notebook, one need to generate
such equations with
import andes
sys = andes.prepare()
Alternatively, one can explicitly create a System and generate the code
import andes
sys = andes.System()
sys.prepare()
System.reload
System.reload(case, **kwargs)
Reload a new case in the same System object.
System.remove_pycapsule
System.remove_pycapsule()
Remove PyCapsule objects in solvers.
System.reset
System.reset(force=False)
Reset to the state after reading data and setup (before power flow).
System.s_update_post
System.s_update_post(models: collections.OrderedDict)
Update variable services by calling s_update_post of models.
This function is called at the end of System.init().
System.s_update_var
System.s_update_var(models: collections.OrderedDict)
Update variable services by calling s_update_var of models.
This function is must be called before any equation evaluation after limiter update function
l_update_var.
System.save_config
System.save_config(file_path=None, overwrite=False)
Save all system, model, and routine configurations to an rc-formatted file.
Parameters
file_path [str, optional] path to the configuration file default to ~/andes/andes.rc.
overwrite [bool, optional] If file exists, True to overwrite without confirmation.
Otherwise prompt for confirmation.
Warning: Saved config is loaded back and populated at system instance creation time. Configs
from the config file takes precedence over default config values.
System.set_address
System.set_address(models)
Set addresses for differential and algebraic variables.
System.set_config
System.set_config(config=None)
Set configuration for the System object.
Config for models are routines are passed directly to their constructors.
System.set_dae_names
System.set_dae_names(models)
Set variable names for differential and algebraic variables, right-hand side of external equations,
and discrete flags.
System.set_output_subidx
System.set_output_subidx(models)
Process andes.models.misc.Output data and store the sub-indices into dae.xy.
Parameters
models [OrderedDict] Models currently in use for the routine
System.set_var_arrays
System.setup
System.setup()
Set up system for studies.
This function is to be called after adding all device data.
System.store_adder_setter
System.store_adder_setter(models)
Store non-inplace adders and setters for variables and equations.
System.store_existing
System.store_existing()
Store existing models in System.existing.
TODO: Models with TimerParam will need to be stored anyway. This will allow adding switches
on the fly.
System.store_no_check_init
System.store_no_check_init(models)
Store differential variables with check_init == False.
System.store_sparse_pattern
System.store_sparse_pattern(models: collections.OrderedDict)
Collect and store the sparsity pattern of Jacobian matrices.
This is a runtime function specific to cases.
Notes
For gy matrix, always make sure the diagonal is reserved. It is a safeguard if the modeling user
omitted the diagonal term in the equations.
System.store_switch_times
System.store_switch_times(models, eps=0.0001)
Store event switching time in a sorted Numpy array in System.switch_times and an Or-
deredDict System.switch_dict.
System.switch_dict has keys as event times and values as the OrderedDict of model names
and instances associated with the event.
Parameters
models [OrderedDict] model name : model instance
eps [float] The small time step size to use immediately before and after the event
Returns
array-like self.switch_times
System.summary
System.summary()
Print out system summary.
System.supported_models
System.supported_models(export='plain')
Return the support group names and model names in a table.
Returns
str A table-formatted string for the groups and models
System.switch_action
System.switch_action(models: collections.OrderedDict)
Invoke the actions associated with switch times.
This function will not be called if flat=True is passed to system.
System.to_ipysheet
System.undill
System.undill(autogen_stale=True)
Reload generated function functions, from either the $HOME/.andes/pycode folder.
If no change is made to models, future calls to prepare() can be replaced with undill() for
acceleration.
Parameters
autogen_stale: bool True to automatically call code generation if stale code is de-
tected. Regardless of this option, codegen is trigger if importing existing code
fails.
System.vars_to_dae
System.vars_to_dae(model)
Copy variables values from models to System.dae.
This function clears DAE.x and DAE.y and collects values from models.
System.vars_to_models
System.vars_to_models()
Copy variable values from System.dae to models.
6.1.2 andes.variables
Modules
andes.variables.dae
andes.variables.fileman
andes.variables.report
andes.variables.dae
Classes
andes.variables.dae.DAE
class andes.variables.dae.DAE(system)
Class for storing numerical values of the DAE system, including variables, equations and first order
derivatives (Jacobian matrices).
Variable values and equation values are stored as numpy.ndarray, while Jacobians are stored as
kvxopt.spmatrix. The defined arrays and descriptions are as follows:
Scalar Description
m The number of algebraic variables/equations
n The number of algebraic variables/equations
o The number of limiter state flags
The derivatives of f and g with respect to x and y are stored in four kvxopt.spmatrix sparse ma-
trices: fx, fy, gx, and gy, where the first letter is the equation name, and the second letter is the variable
name.
Notes
DAE does not keep track of the association of variable and address. Only a variable instance keeps track
of its addresses.
__init__(system)
Methods
alloc_or_extend_names() Allocate empty lists for names for the given size.
build_pattern(name) Build sparse matrices with stored patterns.
clear_arrays() Reset equation and variable arrays to empty.
clear_fg() Resets equation arrays to empty.
clear_ijv() Clear stored triplets.
clear_ts() Drop the TimeSeries data and create a new one.
clear_xy() Reset variable arrays to empty.
clear_z() Reset status arrays to empty
get_name(arr) Helper function for geting the list of variable
names based on the array name.
get_size(name) Get the size of an array or sparse matrix based on
name.
print_array(name[, values, tol]) Debug helper to print array values and names.
request_address(array_name, ndevice, Interface for requesting addresses for a model.
nvar[, ...])
reset() Reset array sizes to zero and clear all arrays.
resize_arrays() Resize arrays to the new sizes m and n, and o.
restore_sparse([names]) Restore all sparse matrices to the sparsity pattern
filled with zeros (for variable Jacobian elements)
and non-zero constants.
set_t(t) Helper function for setting time in-place.
store() Store values for the current time step to the Time-
Series storage.
store_sparse_ijv(name, row, col, val) Store the sparse pattern triplets.
write_lst(lst_path) Dump the variable name lst file.
write_npy(file_path) Write TDS data into NumPy uncompressed for-
mat.
write_npz(file_path) Write TDS data into NumPy compressed format.
DAE.alloc_or_extend_names
DAE.alloc_or_extend_names()
Allocate empty lists for names for the given size.
DAE.build_pattern
DAE.build_pattern(name)
Build sparse matrices with stored patterns.
Call to store_row_col_idx should be made before this function.
Parameters
name [name] jac name
DAE.clear_arrays
DAE.clear_arrays()
Reset equation and variable arrays to empty.
DAE.clear_fg
DAE.clear_fg()
Resets equation arrays to empty.
DAE.clear_ijv
DAE.clear_ijv()
Clear stored triplets.
DAE.clear_ts
DAE.clear_ts()
Drop the TimeSeries data and create a new one.
DAE.clear_xy
DAE.clear_xy()
Reset variable arrays to empty.
DAE.clear_z
DAE.clear_z()
Reset status arrays to empty
DAE.get_name
DAE.get_name(arr)
Helper function for geting the list of variable names based on the array name.
Parameters
arr [str] Array name in 'f', 'g', 'x', 'y', 'z'.
DAE.get_size
DAE.get_size(name)
Get the size of an array or sparse matrix based on name.
Parameters
name [str (f, g, fx, gy, etc.)] array/sparse name
Returns
tuple sizes of each element in a tuple
DAE.print_array
DAE.request_address
DAE.reset
DAE.reset()
Reset array sizes to zero and clear all arrays.
DAE.resize_arrays
DAE.resize_arrays()
Resize arrays to the new sizes m and n, and o.
If m > len(self.y) or n > len(self.x, arrays will be extended. Otherwise, new empty
arrays will be sliced, starting from 0 to the given size.
Warning: This function should not be called directly. Instead, it is called in System.
set_address which re-points variables used in power flow to the new array for dynamic
analyses.
DAE.restore_sparse
DAE.restore_sparse(names=None)
Restore all sparse matrices to the sparsity pattern filled with zeros (for variable Jacobian elements)
and non-zero constants.
Parameters
names [None or list] List of Jacobian names to restore sparsity pattern
DAE.set_t
DAE.set_t(t)
Helper function for setting time in-place.
DAE.store
DAE.store()
Store values for the current time step to the TimeSeries storage. Values include variables, equation
RHS and discrete states.
DAE.store_sparse_ijv
DAE.write_lst
DAE.write_lst(lst_path)
Dump the variable name lst file.
Parameters
lst_path Path to the lst file.
Returns
bool succeed flag
DAE.write_npy
DAE.write_npy(file_path)
Write TDS data into NumPy uncompressed format.
DAE.write_npz
DAE.write_npz(file_path)
Write TDS data into NumPy compressed format.
The function supports writing out all values at once or writing them out incrementally.
Attributes
DAE.fg
property DAE.fg
Return a concatenated array of [f, g].
DAE.x_name_output
property DAE.x_name_output
Return a list of state var names selected by Output.
DAE.x_tex_name_output
property DAE.x_tex_name_output
Return a list of state var LaTeX names selected by Output.
DAE.xy
property DAE.xy
Return a concatenated array of [x, y].
DAE.xy_name
property DAE.xy_name
Return a concatenated list of all variable names without format.
DAE.xy_tex_name
property DAE.xy_tex_name
Return a concatenated list of all variable names in LaTeX format.
DAE.xyz
property DAE.xyz
Return a concatenated array of [x, y].
DAE.xyz_name
property DAE.xyz_name
Return a concatenated list of all variable names without format.
DAE.xyz_tex_name
property DAE.xyz_tex_name
Return a concatenated list of all variable names in LaTeX format.
DAE.y_name_output
property DAE.y_name_output
Return a list of algeb var names selected by Output.
DAE.y_tex_name_output
property DAE.y_tex_name_output
Return a list of algeb var LaTeX names selected by Output.
andes.variables.dae.DAETimeSeries
class andes.variables.dae.DAETimeSeries(dae=None)
DAE time series data.
__init__(dae=None)
Methods
get_data(base_vars, *[, a, rhs]) Get time-series data, either for a variable or for
the equation associated with the variable.
reset() Reset the internal storage and erase all data.
unpack([df, attr, warn_empty]) Unpack dict-stored data into arrays and/or
dataframes.
unpack_df(attr) Construct pandas dataframes.
unpack_np(attr[, warn_empty]) Unpack dict data into numpy arrays.
DAETimeSeries.get_data
DAETimeSeries.get_data(base_vars: Union[andes.core.var.BaseVar,
List[andes.core.var.BaseVar]], *, a=None, rhs: bool = False)
Get time-series data, either for a variable or for the equation associated with the variable.
Parameters
base_var [BaseVar or a sequence of BaseVar(s)] The variable types and internal
addresses are used for looking up the data.
a [an array/list of int or None] Sub-indices into the address of base_var. Applied to
each variable.
Returns
np.ndarray A two-dimensional array. Each row corresponds to one time step. Each
column corresponds to a different different variable.
DAETimeSeries.reset
DAETimeSeries.reset()
Reset the internal storage and erase all data.
DAETimeSeries.unpack
DAETimeSeries.unpack_df
DAETimeSeries.unpack_df(attr)
Construct pandas dataframes.
DAETimeSeries.unpack_np
DAETimeSeries.unpack_np(attr, warn_empty=True)
Unpack dict data into numpy arrays.
Attributes
DAETimeSeries.df
property DAETimeSeries.df
Short-hand for the xy dataframe.
andes.variables.fileman
Functions
add_suffix
andes.variables.fileman.add_suffix(fullname, suffix)
Add suffix to a full file name.
Classes
andes.variables.fileman.FileMan
Methods
FileMan.get_fullpath
FileMan.get_fullpath(fullname=None)
Return the original full path if full path is specified, otherwise search in the case file path.
Parameters
fullname [str, optional] Full name of the file. If relative, prepend input_path. Oth-
erwise, leave it as is.
FileMan.set
FileMan.set(case=None, **kwargs)
Perform the input and output set up.
andes.variables.report
Functions
report_info(system)
report_info
andes.variables.report.report_info(system)
Classes
andes.variables.report.Report
class andes.variables.report.Report(system)
Report class to store system static analysis reports
__init__(system)
Methods
Report.update
Report.update()
Update values based on the requested content
Report.write
Report.write()
Write report to file.
Attributes
info
Report.info
property Report.info
6.2 Routines
6.2.1 andes.routines
Modules
andes.routines.base
Classes
andes.routines.base.BaseRoutine
Methods
BaseRoutine.doc
BaseRoutine.doc(max_width=78, export='plain')
Routine documentation interface.
BaseRoutine.init
BaseRoutine.init()
Routine initialization interface.
BaseRoutine.report
BaseRoutine.report(**kwargs)
Report interface.
BaseRoutine.run
BaseRoutine.run(**kwargs)
Routine main entry point.
BaseRoutine.summary
BaseRoutine.summary(**kwargs)
Summary interface
Attributes
class_name
BaseRoutine.class_name
property BaseRoutine.class_name
andes.routines.criteria
Functions
deltadelta
andes.routines.criteria.deltadelta(delta, diff_limit)
Test if a system is stable by comparing the maximum rotor angle difference with a threshold.
Returns
bool True if the system is stable, False otherwise.
andes.routines.daeint
Classes
andes.routines.daeint.BackEuler
class andes.routines.daeint.BackEuler
Backward Euler's integration method.
__init__(*args, **kwargs)
Methods
BackEuler.calc_jac
BackEuler.calc_q
Notes
Numba jit somehow slows down this function for the 14-bus and the 2k-bus systems.
BackEuler.step
static BackEuler.step(tds)
Integrate with Implicit Trapezoidal Method (ITM) to the current time.
This function has an internal Newton-Raphson loop for algebraized semi-explicit DAE. The func-
tion returns the convergence status when done but does NOT progress simulation time.
Returns
bool Convergence status in tds.converged.
andes.routines.daeint.ImplicitIter
class andes.routines.daeint.ImplicitIter
Base class for implicit iterative methods.
__init__(*args, **kwargs)
Methods
ImplicitIter.calc_jac
ImplicitIter.calc_q
ImplicitIter.step
static ImplicitIter.step(tds)
Integrate with Implicit Trapezoidal Method (ITM) to the current time.
This function has an internal Newton-Raphson loop for algebraized semi-explicit DAE. The func-
tion returns the convergence status when done but does NOT progress simulation time.
Returns
bool Convergence status in tds.converged.
andes.routines.daeint.Trapezoid
class andes.routines.daeint.Trapezoid
Trapezoidal methods.
__init__(*args, **kwargs)
Methods
Trapezoid.calc_jac
Trapezoid.calc_q
Notes
Numba jit somehow slows down this function for the 14-bus and the 2k-bus systems.
Trapezoid.step
static Trapezoid.step(tds)
Integrate with Implicit Trapezoidal Method (ITM) to the current time.
This function has an internal Newton-Raphson loop for algebraized semi-explicit DAE. The func-
tion returns the convergence status when done but does NOT progress simulation time.
Returns
bool Convergence status in tds.converged.
andes.routines.eig
Classes
andes.routines.eig.EIG
Methods
EIG.calc_As
EIG.calc_As(dense=True)
Return state matrix and store to self.As.
Returns
kvxopt.matrix state matrix
Notes
T ẋ = f (x, y)
0 = g(x, y)
As = T −1 (fx − fy ∗ gy−1 ∗ gx )
EIG.calc_eig
EIG.calc_eig(As=None)
Calculate eigenvalues and right eigen vectors.
This function is a wrapper to np.linalg.eig. Results are returned but not stored to EIG.
Returns
np.array(dtype=complex) eigenvalues
np.array() right eigenvectors
EIG.calc_pfactor
EIG.calc_pfactor(As=None)
Compute participation factor of states in eigenvalues.
Each row in the participation factor correspond to one state, and each column correspond to one
mode.
Parameters
As [np.array or None] State matrix to process. If None, use self.As.
Returns
np.array(dtype=complex) eigenvalues
np.array participation factor matrix
EIG.doc
EIG.doc(max_width=78, export='plain')
Routine documentation interface.
EIG.export_mat
EIG.export_mat()
Export state matrix to a <CaseName>_As.mat file with the variable name As, where
<CaseName> is the test case name.
State variable names are stored in variables x_name and x_tex_name.
Returns
bool True if successful
EIG.find_zero_states
EIG.find_zero_states()
Find the indices of states associated with zero time constants in x.
EIG.init
EIG.init()
Routine initialization interface.
EIG.plot
EIG.plot_root_loci
Examples
EIG.post_process
EIG.post_process()
Post processing of eigenvalues.
EIG.report
EIG.report(x_name=None, **kwargs)
Save eigenvalue analysis reports.
Returns
None
EIG.run
EIG.run(**kwargs)
Run small-signal stability analysis.
EIG.stats
EIG.stats()
Return statistics of results in a string.
EIG.summary
EIG.summary()
Print out a summary to logger.info.
EIG.sweep
Examples
ret = ss.EIG.sweep([ss.GENCLS.M],
["GENCLS_1"],
[np.linspace(1, 2, 10)])
Attributes
class_name
EIG.class_name
property EIG.class_name
andes.routines.pflow
Classes
andes.routines.pflow.PFlow
Methods
PFlow.doc
PFlow.doc(max_width=78, export='plain')
Routine documentation interface.
PFlow.fg_update
PFlow.fg_update()
Evaluate the limiters and residual equations.
PFlow.init
PFlow.init()
Initialize variables for power flow.
PFlow.newton_krylov
PFlow.newton_krylov(verbose=True)
Full Newton-Krylov method from SciPy.
Parameters
verbose True if verbose.
Returns
bool Convergence status
PFlow.nr_solve
PFlow.nr_solve()
Solve the power flow problem using itertive Newton's method.
PFlow.nr_step
PFlow.nr_step()
Solve a single iteration step using the Newton-Raphson method.
Returns
float maximum absolute mismatch
PFlow.report
PFlow.report()
Write power flow report to a plain-text file.
Returns
bool True if report was written, False otherwise.
PFlow.run
PFlow.run(**kwargs)
Solve the power flow using the selected method.
Returns
bool convergence status
PFlow.summary
PFlow.summary()
Output a summary for the PFlow routine.
Attributes
class_name
PFlow.class_name
property PFlow.class_name
andes.routines.tds
Classes
andes.routines.tds.TDS
Methods
TDS.calc_h
TDS.calc_h(resume=False)
Calculate the time step size during the TDS.
Parameters
resume [bool] If True, calculate the initial step size.
Returns
float computed time step size stored in self.h
Notes
TDS.check_criteria
TDS.check_criteria()
Check stability criteria.
TDS.do_switch
TDS.do_switch()
Checks if is an event time and perform switch if true.
TDS.doc
TDS.doc(max_width=78, export='plain')
Routine documentation interface.
TDS.fg_update
TDS.fg_update(models, init=False)
Perform one round of evaluation for one iteration step. The following operations are performed in
order:
• variable service updating through s_update_var
• discrete flags updating through l_update_var
• evaluation of the right-hand-side of f
• equation-dependent discrete flags updating through l_update_eq
• evaluation of the right-hand-side of g
• collection of residuals into dae through fg_to_dae.
TDS.init
TDS.init()
Initialize the status, storage and values for TDS.
Returns
array-like The initial values of xy.
TDS.init_resume
TDS.init_resume()
Initialize a resumed simulation.
TDS.itm_step
TDS.itm_step()
Integrate for the step size of self.h using implicit trapezoid method.
Returns
bool Convergence status in self.converged.
TDS.load_plotter
TDS.load_plotter()
Manually load a plotter into TDS.plotter.
TDS.report
TDS.report(**kwargs)
Report interface.
TDS.reset
TDS.reset()
Reset internal states to pre-init condition.
TDS.rewind
TDS.rewind(t)
TODO: rewind to a past time.
TDS.run
TDS.run(no_summary=False, **kwargs)
Run time-domain simulation using numerical integration.
The default method is the Implicit Trapezoidal Method (ITM).
TDS.save_output
TDS.save_output(npz=True)
Save the simulation data into two files: a .lst file and a .npz file.
This function saves the output regardless of the files.no_output flag.
Parameters
npz [bool] True to save in npz format; False to save in npy format.
Returns
bool True if files are written. False otherwise.
TDS.set_method
TDS.streaming_init
TDS.streaming_init()
Send out initialization variables and process init from modules.
Returns
None
TDS.streaming_step
TDS.streaming_step()
Sync, handle and streaming for each integration step.
Returns
None
TDS.summary
TDS.summary()
Print out a summary of TDS options to logger.info.
Returns
None
TDS.test_init
TDS.test_init()
Test if the TDS initialization is successful.
This function update dae.f and dae.g and checks if the residuals are zeros.
Attributes
class_name
TDS.class_name
property TDS.class_name
6.3 Plot
6.3.1 andes.plot
Functions
eig_plot(name, args)
parse_y(y, upper[, lower]) Parse command-line input for Y indices and return
a list of indices
set_font([family, size, style, weight]) Sets the font for matplotlib.
set_latex() Enables LaTeX for matplotlib based on the
with_latex option and dvipng availability.
set_style([style]) Set matplotlib style.
tdsplot(filename, y[, x, to_csv, find, ...]) TDS plot main function based on the new TDSData
class.
eig_plot
andes.plot.eig_plot(name, args)
parse_y
set_font
set_latex
andes.plot.set_latex()
Enables LaTeX for matplotlib based on the with_latex option and dvipng availability.
Returns
bool True for LaTeX on, False for off
set_style
andes.plot.set_style(style='default')
Set matplotlib style.
Parameters
style [str] default, ieee (require scienceplots), or other available styles (see mat-
plotlib.pyplot.style.available).
tdsplot
xargs [str, optional] similar to find, but return the result indices with file name, x idx
name for xargs
exclude [str, optional] variable name pattern to exclude
Returns
TDSData object
Classes
TDSData([full_name, mode, dae, path]) A data container for loading and plotting results from
Andes time-domain simulation.
andes.plot.TDSData
Methods
TDSData.bqplot_data
TDSData.data_to_df
TDSData.data_to_df()
Convert to pandas.DataFrame
TDSData.export_csv
TDSData.find
TDSData.get_call
TDSData.get_call(backend=None)
Get the internal plot_data function for the specified backend.
TDSData.get_header
TDSData.get_header(idx, formatted=False)
Return a list of the variable names at the given indices.
Parameters
idx [list or int] The indices of the variables to retrieve
formatted [bool] True to retrieve latex-formatted names, False for unformatted
names
Returns
list A list of variable names (headers)
TDSData.get_values
TDSData.get_values(idx)
Return the variable values at the given indices.
Parameters
idx [list] The indicex of the variables to retrieve. idx=0 is for Time. Variable indices
start at 1.
Returns
np.ndarray Variable data
TDSData.guess_event_time
TDSData.guess_event_time()
Guess the event starting time from the input data by checking when the values start to change
TDSData.load_dae
TDSData.load_dae()
Load from DAE time series.
TDSData.load_lst
TDSData.load_lst()
Load the lst file into internal data structures _idx, _fname, _uname, and counts the number of
variables to nvars.
Returns
None
TDSData.load_npy_or_csv
TDSData.load_npy_or_csv(delimiter=',')
Load the npy, zpy or (the legacy) csv file into the internal data structure self._xy.
Parameters
delimiter [str, optional] The delimiter for the case file. Default to comma.
Returns
None
TDSData.panoview
Examples
system.TDS.plt.plot(system.GENROU,
vars=['omega', 'delta'],
idx=['GENROU_1', 'GENROU_2'])
TDSData.plot
TDSData.plot_data
Examples
To plot the results of arithmetic calculation of variables, retrieve the values, do the calculation, and
plot with plot_data.
TDSData.plotn
6.4 I/O
6.4.1 andes.io
Functions
dump(system, output_format[, full_path, ...]) Dump the System data into the requested output for-
mat.
get_output_ext(out_format) Helper function to get the output extension for the
given output format.
guess(system) Guess the input format based on extension and con-
tent.
parse(system) Parse input file with the given format in sys-
tem.files.input_format.
read_file_like(infile) Read a file-like object and return a list of splitted
lines.
dump
get_output_ext
andes.io.get_output_ext(out_format)
Helper function to get the output extension for the given output format.
Parameters
out_format [str] Output format name.
Returns
str [file extension without dot or empty if not supported]
guess
andes.io.guess(system)
Guess the input format based on extension and content.
Also stores the format name to system.files.input_format.
Parameters
system [System] System instance with the file name set to system.files
Returns
str format name
parse
andes.io.parse(system)
Parse input file with the given format in system.files.input_format.
Returns
bool True if successful; False otherwise.
read_file_like
Modules
andes.io.json
Functions
read(system, infile) Read JSON file with ANDES model data into an
empty system.
testlines(infile)
write(system, outfile[, skip_empty, overwrite]) Write loaded ANDES system data into a JSON file.
read
testlines
andes.io.json.testlines(infile)
write
andes.io.matpower
Functions
m2mpc
Parameters
infile [str] Path to the MATPOWER file.
Returns
dict mpc struct names : numpy arrays
mpc2system
read
andes.io.matpower.read(system, file)
Read a MATPOWER data file into mpc, and build andes device elements.
system2mpc
andes.io.matpower.system2mpc(system) → dict
Convert data from an ANDES system to an mpc dict.
In the gen section, slack generators preceeds PV generators.
testlines
andes.io.matpower.testlines(infile)
Test if this file is in the MATPOWER format.
NOT YET IMPLEMENTED.
andes.io.psse
Functions
get_block_lines(b, mdata) Return the number of lines based on the block index
in the RAW file.
read(system, file) Read PSS/E RAW file v32/v33 formats.
read_add(system, file) Read an addition PSS/E dyr file.
sort_psse_models(dyr_yaml, system) Sort supported models so that model names are or-
dered by dependency.
testlines(infile) Check the raw file for frequency base.
get_block_lines
andes.io.psse.get_block_lines(b, mdata)
Return the number of lines based on the block index in the RAW file.
read
andes.io.psse.read(system, file)
Read PSS/E RAW file v32/v33 formats.
read_add
andes.io.psse.read_add(system, file)
Read an addition PSS/E dyr file.
Parameters
system [System] System instance to which data will be loaded
file [str] Path to the additional dyr file
Returns
bool data parsing status
sort_psse_models
andes.io.psse.sort_psse_models(dyr_yaml, system)
Sort supported models so that model names are ordered by dependency.
Dependency is determined by checking the find key in psse-dyr.yaml for each model.
Returns
list The sequence of model names for loading parameters.
testlines
andes.io.psse.testlines(infile)
Check the raw file for frequency base.
andes.io.streaming
Classes
andes.io.streaming.Streaming
class andes.io.streaming.Streaming(system)
ANDES data streaming class to interface with CURENT LTB.
__init__(system)
Methods
Streaming.build_init
Streaming.build_init()
Build Varheader, Idxvgs and SysParam after power flow routine
Streaming.connect
Streaming.connect()
Connect to DiME 2 server.
If dime_address is specified from the command-line, streaming will be automatically enabled.
Otherwise, settings from the Config file will be used.
Streaming.finalize
Streaming.finalize()
Send DONE signal when simulation completes
Returns None
Streaming.handle_alter
Streaming.handle_alter(Alter)
Handle parameter altering
Streaming.handle_event
Streaming.handle_event(Event)
Handle Fault, Breaker, Syn and Load Events
Streaming.record_module_init
Streaming.record_module_init(name, init_var)
Record the variable requests from modules
Streaming.send_init
Streaming.send_init(recepient='all')
Broadcast Varheader, Idxvgs and SysParam to all DiME clients after power flow routine
Streaming.sync_and_handle
Streaming.sync_and_handle()
Sync until the queue is empty. Handle sync'ed commands.
Streaming.transpose_matlab_row
static Streaming.transpose_matlab_row(a)
Streaming.vars_to_modules
Streaming.vars_to_modules()
Stream the results from the last step to modules
Returns None
Streaming.vars_to_pmu
Streaming.vars_to_pmu()
Broadcast all PMU measurements and BusFreq measurements in the variable pmudata
andes.io.txt
Functions
dump_data
andes.io.xlsx
Functions
read(system, infile) Read an xlsx file with ANDES model data into an
empty system
testlines(infile)
write(system, outfile[, skip_empty, ...]) Write loaded ANDES system data into an xlsx file
read
andes.io.xlsx.read(system, infile)
Read an xlsx file with ANDES model data into an empty system
Parameters
system [System] Empty System instance
infile [str or file-like] Path to the input file, or a file-like object
Returns
System System instance after succeeded
testlines
andes.io.xlsx.testlines(infile)
write
overwrite [bool, optional] None to prompt for overwrite selection; True to overwrite;
False to not overwrite
add_book [str, optional] An optional model to be added to the output spreadsheet
Returns
bool True if file written; False otherwise
6.5 Interoperability
6.5.1 andes.interop
To install dependencies for development, in the ANDES source code folder, do:
Modules
andes.interop.gridcal
Basic GridCal (4.6.1) interface, based on the pandapower interface written by Jinning Wang
Author: Josep Fanals (@JosepFanals)
Functions
require_gridcal
andes.interop.gridcal.require_gridcal(f)
Decorator for functions that require GridCal.
to_gridcal
Notes
andes.interop.matpower
m = start_instance()
Functions
from_matpower
Examples
One can create an Excel file with dynamic data only and use the xlsx parser to load data into system:
xlsx.read(system, andes.get_case('ieee14/ieee14_dyn_only.xlsx'))
xlsx.write(system, 'system_static.xlsx')
require_matpower
andes.interop.matpower.require_matpower(f)
Decorator for functions that require matpower.
to_matpower
Examples
The code below will create an IEEE 14-bus example system in ANDES, convert it to MATPOWER's
case, and send to the MATLAB/Octave instance.
import andes
m = start_instance()
ss = andes.system.example()
mpc = to_matpower(m, 'mpc', ss)
m.eval("runpf(mpc)")
andes.interop.pandapower
Functions
add_gencost
andes.interop.pandapower.add_gencost(ssp, gen_cost)
Add cost function to converted pandapower net ssp.
The cost data follows the same format of pypower and matpower.
Now only poly_cost is supported.
Parameters
ssp The pandapower net
gen_cost [array] generator cost data
build_group_table
mdl_name [list of string] The list of models that to be included in the table. Default as
all models.
Returns
DataFrame The output Dataframe contains the columns from the device
make_GSF
make_link_table
andes.interop.pandapower.make_link_table(ssa)
Build the link table for generators and generator controllers in an ANDES System, including SynGen
and DG for now.
Parameters
ssa [andes.system.System] The ANDES system to link
Returns
DataFrame Each column in the output Dataframe contains the idx of linked Stat-
icGen, Bus, DG, RenGen, RenExciter, SynGen, Exciter, and Tur-
bineGov, gammap, gammaq.
require_pandapower
andes.interop.pandapower.require_pandapower(f)
Decorator for functions that require pandapower.
runopp_map
Notes
• The pandapower net and the ANDES system must have same base MVA.
• Multiple DG connected to the same StaticGen will be converted to one generator. The power
is dispatched to each DG by the power ratio gammap
to_pandapower
Notes
andes.interop.pypowsybl
Functions
require_pypowsybl
andes.interop.pypowsybl.require_pypowsybl(f)
Decorator for functions that require pypowsybl.
to_pypowsybl
andes.interop.pypowsybl.to_pypowsybl(ss)
Convert an ANDES system to a pypowsybl network.
Parameters
ss [andes.system.System] The ANDES system to be converted.
Returns
pypowsybl.network.Network
Warning:
• Power flow results are not verified.
Notes
Examples
ss = andes.system.example()
n = to_pypowsybl(ss)
results = pp.loadflow.run_ac(n)
6.6 Others
6.6.1 andes.cli
Functions
create_parser
andes.cli.create_parser()
Create a parser for the command-line interface.
Returns
argparse.ArgumentParser Parser with all ANDES options
main
andes.cli.main()
Entry point of the ANDES command-line interface.
preamble
andes.cli.preamble()
Log the ANDES command-line preamble at the logging.INFO level
6.6.2 andes.main
Main entry point for the ANDES CLI and scripting interfaces.
Functions
config_logger([stream_level, stream, file, ...]) Configure an ANDES logger with a FileHandler and
a StreamHandler.
demo(**kwargs) TODO: show some demonstrations from CLI.
doc([attribute, list_supported, config]) Quick documentation from command-line.
edit_conf([edit_config]) Edit the Andes config file which occurs first in the
search path.
find_log_path(lg) Find the file paths of the FileHandlers.
load(case[, codegen, setup, use_input_path]) Load a case and set up a system without running rou-
tine.
misc([edit_config, save_config, ...]) Miscellaneous commands.
plot(*args, **kwargs) Wrapper for the plot tool.
prepare([quick, incremental, models, ...]) Run code generation.
print_license() Print out Andes license to stdout.
remove_output([recursive]) Remove the outputs generated by Andes, including
power flow reports _out.txt, time-domain list
_out.lst and data _out.dat, eigenvalue anal-
ysis report _eig.txt.
run(filename[, input_path, verbose, ...]) Entry point to run ANDES routines.
run_case(case, *[, routine, profile, ...]) Run single simulation case for the given full path.
save_conf([config_path, overwrite]) Save the Andes config to a file at the path specified
by save_config.
selftest([quick, extra]) Run unit tests.
set_logger_level(lg, type_to_set, level) Set logging level for the given type of handler.
versioninfo() Print version info for ANDES and dependencies.
config_logger
stream_level [{10, 20, 30, 40, 50}, optional] StreamHandler verbosity level.
file_level [{10, 20, 30, 40, 50}, optional] FileHandler verbosity level.
Returns
-------
None
demo
andes.main.demo(**kwargs)
TODO: show some demonstrations from CLI.
doc
edit_conf
find_log_path
andes.main.find_log_path(lg)
Find the file paths of the FileHandlers.
load
Warning: If one need to add devices in addition to these from the case file, do setup=False
and call System.add() to add devices. When done, manually invoke setup() to set up the
system.
misc
plot
andes.main.plot(*args, **kwargs)
Wrapper for the plot tool.
prepare
precompile [bool] True to compile model function calls after code generation.
Returns
System object if cli is False; exit_code 0 otherwise.
Warning: The default behavior has changed since v1.0.8: when cli is True and full is not True,
quick code generation will be used.
print_license
andes.main.print_license()
Print out Andes license to stdout.
remove_output
andes.main.remove_output(recursive=False)
Remove the outputs generated by Andes, including power flow reports _out.txt, time-domain list
_out.lst and data _out.dat, eigenvalue analysis report _eig.txt.
Parameters
recursive [bool] Recursively clean all subfolders
Returns
bool True is the function body executes with success. False otherwise.
run
run_case
save_conf
selftest
set_logger_level
versioninfo
andes.main.versioninfo()
Print version info for ANDES and dependencies.
6.6.3 andes.utils.paths
Functions
andes_root
andes.utils.paths.andes_root()
Return the path to the folder of the ANDES package.
cases_root
andes.utils.paths.cases_root()
Return the root path to the stock cases
confirm_overwrite
andes.utils.paths.confirm_overwrite(outfile, overwrite=None)
Confirm overwriting a file.
get_case
andes.utils.paths.get_case(rpath, check=True)
Return the path to a stock case for a given path relative to andes/cases.
To list all cases, use andes.list_cases().
Parameters
check [bool] True to check if file exists
Examples
andes.get_case('kundur/kundur_full.xlsx')
get_config_path
andes.utils.paths.get_config_path(file_name='andes.rc')
Return the path of the config file to be loaded.
Search Priority: 1. current directory; 2. home directory.
Parameters
file_name [str, optional] Config file name with the default as andes.rc.
Returns
Config path in string if found; None otherwise.
get_dot_andes_path
andes.utils.paths.get_dot_andes_path()
Return the path to $HOME/.andes
get_log_dir
andes.utils.paths.get_log_dir()
Get the directory for log file.
The default is <tempdir>/andes, where <tempdir> is provided by tempfile.
gettempdir().
Returns
str The path to the temporary logging directory
get_pycode_path
andes.utils.paths.get_pycode_path(pycode_path=None, mkdir=False)
Get the path to the pycode folder.
list_cases
andes.utils.paths.list_cases(rpath='.', no_print=False)
List stock cases under a given folder relative to andes/cases
tests_root
andes.utils.paths.tests_root()
Return the root path to the stock cases
Classes
andes.utils.paths.DisplayablePath
Methods
displayable()
DisplayablePath.displayable
DisplayablePath.displayable()
DisplayablePath.make_tree
Attributes
display_filename_prefix_last
display_filename_prefix_middle
display_parent_prefix_last
display_parent_prefix_middle
displayname
DisplayablePath.display_filename_prefix_last
DisplayablePath.display_filename_prefix_last = '└──'
DisplayablePath.display_filename_prefix_middle
DisplayablePath.display_filename_prefix_middle = '├──'
DisplayablePath.display_parent_prefix_last
DisplayablePath.display_parent_prefix_middle
DisplayablePath.displayname
property DisplayablePath.displayname
6.6.4 andes.utils.snapshot
import andes
ss = andes.run(andes.get_case("ieee14/ieee14_linetrip.xlsx"))
ss.Toggle.u.v[:] = 0 # turn off line trips for the base case
xy = ss.TDS.init()
andes.utils.snapshot.save_ss("ieee14_snapshot.pkl", ss)
2. For every scenario afterwards, load the snapshot and apply disturbances:
import andes
ss = andes.utils.snapshot.load_ss("ieee14_snapshot.pkl")
ss.TDS.run()
Functions
load_ss
andes.utils.snapshot.load_ss(path)
Load an ANDES snapshot and return a System object.
Parameters
path [str] Path to the snapshot file.
Returns
andes.system.System The loaded system object
save_ss
andes.utils.snapshot.save_ss(path, system)
Save a system with all internal states as a snapshot.
Returns
Path to the saved snapshot.
Warning: One limitation of the current implementation is version dependency. The snapshots only
work with the specific ANDES version that created it.
6.6.5 andes.utils.widgets
Functions
edit_sheet
edit_system
andes.utils.widgets.edit_system(system)
Edit a loaded ANDES System with ipywidgets.
on_close
andes.utils.widgets.on_close(b)
Callback for the Close botton. Closes ipywidget objects.
on_update
andes.utils.widgets.on_update(b)
Callback for the Update button. Sets new parameters back to System.
[Cui2021] H. Cui, F. Li and K. Tomsovic, "Hybrid Symbolic-Numeric Framework for Power System Model-
ing and Analysis," in IEEE Transactions on Power Systems, vol. 36, no. 2, pp. 1373-1384, March
2021, doi: 10.1109/TPWRS.2020.3017019.
[Milano2010] F. Milano, “Power System Modelling and Scripting,” in Power Modelling and Scripting, F.
Milano, Ed. Berlin, Heidelberg: Springer, pp. 202-204, 2010.
[Sauer] P. W. Sauer, M. A. Pai, and J. H. Chow, Power system dynamics and stability: with synchrophasor
measurement and power system toolbox, Second edition. Hoboken, NJ, USA: IEEE Press, Wiley,
2017.
[PJM5] F. Li and R. Bo, "Small test systems for power system economic studies," IEEE PES General
Meeting, 2010, pp. 1-4, doi: 10.1109/PES.2010.5589973.
[GB] The University of Edinburgh, "Power Systems Test Case Archive", https://www.maths.ed.ac.uk/
optenergy/NetworkData/fullGB
[EI] D. Osipov and M. Arrieta-Paternina, "Reduced Eastern Interconnection System Model", [Online].
Available: https://curent.utk.edu/2016SiteVisit/EI_LTB_Report.pdf.
[IEEE] University of Washington, "Power Systems Test Case Archive", [Online]. Available: https://labs.
ece.uw.edu/pstca/
[RLGC] Qiuhua Huang, "RLGC repository", [Online]. Available: https://github.com/RLGC-Project/
RLGC
[MATPOWER] R. D. Zimmerman, "MATPOWER", [Online]. Available: https://matpower.org/
[Nordic] ALSETLab, "Nordpool test system", [Online]. Available: https://github.com/ALSETLab/
Nordic44-Nordpool/tree/master/nordic44/models
[PST] Power System Toolbox, [Online]. Available: https://sites.ecse.rpi.edu/~chowj/PSTMan.pdf
[WECC] K. Sun, "Test Cases Library of Power System Sustained Oscillations". Available: http://web.eecs.
utk.edu/~kaisun/Oscillation/basecase.html
[PSAT] F. Milano, "Power System Analysis Toolbox", [Online]. Available: http://faraday1.ucd.ie/psat.
html
873
ANDES Manual, Release 1.8.10
874 Bibliography
PYTHON MODULE INDEX
a
andes.cli, 859
andes.interop, 850
andes.interop.gridcal, 850
andes.interop.matpower, 852
andes.interop.pandapower, 854
andes.interop.pypowsybl, 857
andes.io, 839
andes.io.json, 841
andes.io.matpower, 842
andes.io.psse, 844
andes.io.streaming, 845
andes.io.txt, 848
andes.io.xlsx, 849
andes.main, 859
andes.plot, 829
andes.routines, 808
andes.routines.base, 808
andes.routines.criteria, 810
andes.routines.daeint, 810
andes.routines.eig, 814
andes.routines.pflow, 820
andes.routines.tds, 823
andes.system, 777
andes.utils.paths, 865
andes.utils.snapshot, 870
andes.utils.widgets, 871
andes.variables, 794
andes.variables.dae, 794
andes.variables.fileman, 805
andes.variables.report, 806
875
ANDES Manual, Release 1.8.10
877
ANDES Manual, Release 1.8.10
878 Index
ANDES Manual, Release 1.8.10
Index 879
ANDES Manual, Release 1.8.10
880 Index
ANDES Manual, Release 1.8.10
Index 881
ANDES Manual, Release 1.8.10
882 Index
ANDES Manual, Release 1.8.10
Index 883
ANDES Manual, Release 1.8.10
884 Index
ANDES Manual, Release 1.8.10
Index 885
ANDES Manual, Release 1.8.10
886 Index
ANDES Manual, Release 1.8.10
Index 887