Opened 8 years ago
Last modified 6 years ago
#4354 closed defect
Inefficient handling of Complex equations by the back-end — at Initial Version
Reported by: | Francesco Casella | Owned by: | Lennart Ochel |
---|---|---|---|
Priority: | high | Milestone: | 1.14.0 |
Component: | Backend | Version: | |
Keywords: | Cc: | Volker Waurich, Mahder Alemseged Gebremedhin, Willi Braun, Adrian Pop, Per Östlund |
Description
Please consider the following test case (also attached)
loadString(" model M1 parameter Real P = 1000; parameter Real Q = 2000; parameter Real V_re = 100; parameter Real V_im = 100; parameter Real I_re(fixed = false); parameter Real I_im(fixed = false); initial equation P = V_re*I_re + V_im*I_im; Q = V_re*I_im - V_im*I_re; end M1; model M2 import CM = Modelica.ComplexMath; parameter Real P = 1000; parameter Real Q = 2000; parameter Real V_re = 100; parameter Real V_im = 100; parameter Complex I(re(fixed=false), im(fixed=false)); initial equation Complex(P,Q) = Complex(V_re, V_im) * CM.conj(I); end M2; ");getErrorString(); setCommandLineOptions("-d=dumpSimCode"); loadModel(Modelica); buildModel(M1);getErrorString(); buildModel(M2);getErrorString();
M2 is completely equivalent to M1, only written down in a more compact and convenient way, by exploiting Complex records and function overloading. There should be no performance penalty when M2 is simulated instead of M1, otherwise one would prefer writing M1 instead of M2, which is against the whole concept of high-level declarative modelling.
This is the output from the back-end for M1
5: (LINEAR) index:0 jacobian: true variables: index: -1: I_im (no alias) initial: no arrCref index:() [] b-vector: 1: I_re=DIVISION(P - V_im * I_im, V_re) [Real ] 2: V_re * I_im + (-V_im) * I_re - Q (RESIDUAL) Jacobian idx: 0 3: I_re.$pDERLSJac0.dummyVarLSJac0=DIVISION((-V_im) * I_imSeedLSJac0, V_re) [Real ] 4: $res.1.$pDERLSJac0.dummyVarLSJac0=V_re * I_imSeedLSJac0 - V_im * I_re.$pDERLSJac0.dummyVarLSJac0 [Real ]
this is the output of the back-end for M2:
1: $TMP_Complex1 := Complex(V_re * I.re + V_im * I.im, V_im * I.re - V_re * I.im); 2: P=$TMP_Complex1.re [Real ] 3: Q=$TMP_Complex1.im [Real ]
With M1, OMC recognizes the intial equations as a linear system, and solves it via tearing. In fact, the way this is done is a bit questionable, because the solution would become unnecessarily singular when V_re = 0, which is perfectly legitimate, but that's another story.
With M2, OMC does not recognize this fact, and eventually a nonlinear iterative solver would be used. Of course I understand that in this specific case this is no big deal, as the Newton algorithm will converge in just one step.
My point is that with the current handling of Complex equations, in more complicated cases OMC may miss opportunities for useful symbolic handling, which could instead be critical.
I would recommend that Complex equations are symbolically transformed into Real equations, so that all kind of optimizations can be performed in the same way as with the flat formulation of the problem with Real variables. In this specific case, M1 and M2 would eventually be handled exactly in the same way by the solver.
One way to do so could be that in the special case of equations involving records with only two Real components r1
and r2
<lhs> = <rhs>
they are transformed into a pair of Real equations
instead of introducing auxiliary variables of any kind.
I reckon this can be trivially implemented in MetaModelica.