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

<lhs.r1> = <rhs.r2>
<lhs.r1> = <rhs.r2>

instead of introducing auxiliary variables of any kind.

I reckon this can be trivially implemented in MetaModelica.

Change History (0)

Note: See TracTickets for help on using tickets.