4343import numpy as np
4444import importlib
4545import pathlib
46+ from dataclasses import dataclass
47+ from typing import Optional
4648
4749from OMPython .OMCSession import OMCSessionBase , OMCSessionZMQ
4850
@@ -54,6 +56,57 @@ class ModelicaSystemError(Exception):
5456 pass
5557
5658
59+ @dataclass
60+ class LinearizationResult :
61+ """Modelica model linearization results.
62+
63+ Attributes:
64+ n: number of states
65+ m: number of inputs
66+ p: number of outputs
67+ A: state matrix (n x n)
68+ B: input matrix (n x m)
69+ C: output matrix (p x n)
70+ D: feedthrough matrix (p x m)
71+ x0: fixed point
72+ u0: input corresponding to the fixed point
73+ stateVars: names of state variables
74+ inputVars: names of inputs
75+ outputVars: names of outputs
76+ """
77+
78+ n : int
79+ m : int
80+ p : int
81+
82+ A : list
83+ B : list
84+ C : list
85+ D : list
86+
87+ x0 : list [float ]
88+ u0 : list [float ]
89+
90+ stateVars : list [str ]
91+ inputVars : list [str ]
92+ outputVars : list [str ]
93+
94+ def __iter__ (self ):
95+ """Allow unpacking A, B, C, D = result."""
96+ yield self .A
97+ yield self .B
98+ yield self .C
99+ yield self .D
100+
101+ def __getitem__ (self , index : int ):
102+ """Allow accessing A, B, C, D via result[0] through result[3].
103+
104+ This is needed for backwards compatibility, because
105+ ModelicaSystem.linearize() used to return [A, B, C, D].
106+ """
107+ return {0 : self .A , 1 : self .B , 2 : self .C , 3 : self .D }[index ]
108+
109+
57110class ModelicaSystem :
58111 def __init__ (self , fileName = None , modelName = None , lmodel = None , commandLineOptions = None ,
59112 variableFilter = None , customBuildDirectory = None , verbose = True , raiseerrors = False ,
@@ -967,13 +1020,22 @@ def optimize(self): # 21
9671020
9681021 return optimizeResult
9691022
970- # to linearize model
971- def linearize (self , lintime = None , simflags = None ): # 22
972- """
973- This method linearizes model according to the linearized options. This will generate a linear model that consists of matrices A, B, C and D. It can be called:
974- only without any arguments
975- usage
976- >>> linearize()
1023+ def linearize (self , lintime : Optional [float ] = None , simflags : Optional [str ] = None ) -> LinearizationResult :
1024+ """Linearize the model according to linearOptions.
1025+
1026+ Args:
1027+ lintime: Override linearOptions["stopTime"] value.
1028+ simflags: A string of extra command line flags for the model
1029+ binary.
1030+
1031+ Returns:
1032+ A LinearizationResult object is returned. This allows several
1033+ uses:
1034+ * `(A, B, C, D) = linearize()` to get just the matrices,
1035+ * `result = linearize(); result.A` to get everything and access the
1036+ attributes one by one,
1037+ * `result = linearize(); A = result[0]` mostly just for backwards
1038+ compatibility, because linearize() used to return `[A, B, C, D]`.
9771039 """
9781040
9791041 if self .xmlFile is None :
@@ -1043,7 +1105,8 @@ def linearize(self, lintime=None, simflags=None): # 22
10431105 self .linearinputs = inputVars
10441106 self .linearoutputs = outputVars
10451107 self .linearstates = stateVars
1046- return [A , B , C , D ]
1108+ return LinearizationResult (n , m , p , A , B , C , D , x0 , u0 , stateVars ,
1109+ inputVars , outputVars )
10471110 except ModuleNotFoundError :
10481111 raise Exception ("ModuleNotFoundError: No module named 'linearized_model'" )
10491112
0 commit comments