Hybrid Symbolic-Numeric Framework#
ANDES uses a unique hybrid symbolic-numeric framework that combines the expressiveness of symbolic mathematics with the efficiency of numerical computation.
Key Concept#
Instead of writing numerical code directly, you describe models using equations and building blocks. ANDES then:
Parses symbolic equation strings
Computes partial derivatives automatically
Generates optimized numerical code
Executes vectorized calculations
Benefits#
For Model Developers#
Write equations, not code: Define differential equations as strings like
'omega - 1'Automatic Jacobians: No need to derive and code partial derivatives
Modular blocks: Reuse transfer functions (Lag, LeadLag, PIController)
Built-in validation: Framework catches common modeling errors
For Users#
Identical models: PSS/E parameters work directly without conversion
Fast simulation: Generated code is optimized and vectorized
Extensible: Add new models without modifying core solver
Framework Components#
┌─────────────────────────────────────────────────┐
│ Model Definition │
│ Parameters Variables Equations Blocks │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Symbolic Processing │
│ Parse → Derive → Optimize → Generate │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Numerical Simulation │
│ Initialize → Solve → Iterate → Output │
└─────────────────────────────────────────────────┘
Code Generation#
When you first run ANDES or modify models, code generation occurs:
# Triggered automatically, or manually with:
andes prepare
This creates optimized Python code stored in ~/.andes/pycode/. Generation runs once unless models change.
What Gets Generated#
Equation evaluation functions
Jacobian matrix builders
Initialization routines
Variable indexing maps
Example: Model Definition#
A simplified turbine governor in ANDES:
class TGOV1(TGOVData, Model):
def __init__(self, system, config):
TGOVData.__init__(self)
Model.__init__(self, system, config)
# Services (intermediate constants)
self.gain = ConstService(v_str='u/R')
# Variables with equation strings
self.pout = Algeb(
v_str='tm0',
e_str='(paux + pref + gain * (omega - 1) - pout)'
)
# Transfer function block
self.LG = Lag(u=self.pout, T=self.T1, K=1)
Key observations:
v_strdefines initial value calculatione_strdefines the algebraic equation (set to zero)Lagblock encapsulates first-order dynamicsNo numerical code for derivatives—handled automatically
Symbolic Variables#
Within equation strings, you can reference:
Type |
Example |
Description |
|---|---|---|
Parameters |
|
Model parameters |
Variables |
|
State/algebraic variables |
External |
|
Variables from other models |
Services |
|
Intermediate calculations |
Block outputs |
|
Output of transfer blocks |
Integration with Solver#
During simulation:
System collects all model equations
Equations are evaluated using generated code
Jacobians are built incrementally by model
Solver finds the solution iteratively
Results are distributed back to models
See Also#
Atomic Types - v-provider and e-provider concepts
System Architecture - System class internals
DAE Formulation - DAE mathematical background
Parameters - Parameter types
Variables - Variable types