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 ,
@@ -907,13 +960,22 @@ def optimize(self): # 21
907960
908961 return optimizeResult
909962
910- # to linearize model
911- def linearize (self , lintime = None , simflags = None ): # 22
912- """
913- 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:
914- only without any arguments
915- usage
916- >>> linearize()
963+ def linearize (self , lintime : Optional [float ] = None , simflags : Optional [str ] = None ) -> LinearizationResult :
964+ """Linearize the model according to linearOptions.
965+
966+ Args:
967+ lintime: Override linearOptions["stopTime"] value.
968+ simflags: A string of extra command line flags for the model
969+ binary.
970+
971+ Returns:
972+ A LinearizationResult object is returned. This allows several
973+ uses:
974+ * `(A, B, C, D) = linearize()` to get just the matrices,
975+ * `result = linearize(); result.A` to get everything and access the
976+ attributes one by one,
977+ * `result = linearize(); A = result[0]` mostly just for backwards
978+ compatibility, because linearize() used to return `[A, B, C, D]`.
917979 """
918980
919981 if self .xmlFile is None :
@@ -983,7 +1045,8 @@ def linearize(self, lintime=None, simflags=None): # 22
9831045 self .linearinputs = inputVars
9841046 self .linearoutputs = outputVars
9851047 self .linearstates = stateVars
986- return [A , B , C , D ]
1048+ return LinearizationResult (n , m , p , A , B , C , D , x0 , u0 , stateVars ,
1049+ inputVars , outputVars )
9871050 except ModuleNotFoundError :
9881051 raise Exception ("ModuleNotFoundError: No module named 'linearized_model'" )
9891052
0 commit comments