Skip to content

Commit 93565e9

Browse files
committed
[NF] Move some bindings of vectorized components into equations (#12951)
This applies if -d=-nfScalarize and if the binding contains variables of the vectorized component itself. See the new testVectorizedBinding.mos and VectorizedPowerSystemTotal.mo that does not rely on manual conversion to an equation anymore.
1 parent 9024c16 commit 93565e9

File tree

4 files changed

+194
-17
lines changed

4 files changed

+194
-17
lines changed

OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ protected
675675
Boolean unfix;
676676
Prefix pre;
677677
Variable v;
678+
Boolean fillVectorizedBindingFails = false;
678679
algorithm
679680
Component.COMPONENT(ty = ty, binding = binding, attributes = comp_attr, comment = cmt, info = info) := comp;
680681
checkUnspecifiedEnumType(ty, node, info);
@@ -688,12 +689,20 @@ algorithm
688689
unfix := false;
689690
end if;
690691

692+
// If the component is vectorized and the binding uses variables of the component,
693+
// move the binding into an equation as fillVectorizedBinding is insufficient.
694+
if not settings.scalarize and not settings.vectorizeBindings and Binding.isBound(binding)
695+
and not Prefix.isEmpty(prefix) and Type.isArray(ComponentRef.nodeType(Prefix.prefix(prefix))) then
696+
fillVectorizedBindingFails := containsPrefix(Binding.getExp(binding), prefix);
697+
end if;
698+
691699
// If the component is an array component with a binding and at least discrete
692700
// variability, and scalarization is enabled, move the binding into an equation.
693701
// This avoids having to scalarize the binding.
694-
if not settings.nfAPI and settings.scalarize then
702+
if not settings.nfAPI and settings.scalarize or fillVectorizedBindingFails then
695703
if var >= Variability.DISCRETE and Type.isArray(ty) and
696-
not Type.isExternalObject(Type.arrayElementType(ty)) and Binding.isBound(binding) then
704+
not Type.isExternalObject(Type.arrayElementType(ty)) and Binding.isBound(binding)
705+
or fillVectorizedBindingFails then
697706
name := ComponentRef.prefixCref(comp_node, ty, {}, Prefix.prefix(prefix));
698707
eq := Equation.ARRAY_EQUALITY(Expression.CREF(ty, name), Binding.getTypedExp(binding), ty,
699708
InstNode.EMPTY_NODE(), ElementSource.createElementSource(info));
@@ -1461,6 +1470,36 @@ algorithm
14611470
end match;
14621471
end addIterator_traverse;
14631472

1473+
function containsPrefix
1474+
input Expression exp;
1475+
input Prefix prefix;
1476+
output Boolean contains;
1477+
algorithm
1478+
contains := Expression.fold(exp, function containsPrefix_traverse(prefix = prefix), false);
1479+
end containsPrefix;
1480+
1481+
function containsPrefix_traverse
1482+
input Expression exp;
1483+
input output Boolean contains;
1484+
input Prefix prefix;
1485+
protected
1486+
String restString, prefixString = ComponentRef.toString(Prefix.prefix(prefix));
1487+
algorithm
1488+
() := match exp
1489+
local
1490+
ComponentRef restCref;
1491+
case Expression.CREF(cref = ComponentRef.CREF(restCref = restCref))
1492+
algorithm
1493+
restString := ComponentRef.toString(restCref);
1494+
if StringUtil.startsWith(restString, prefixString) then
1495+
contains := true;
1496+
end if;
1497+
then
1498+
();
1499+
else ();
1500+
end match;
1501+
end containsPrefix_traverse;
1502+
14641503
function subscriptBindingOpt
14651504
input list<Subscript> subscripts;
14661505
input output Option<Binding> binding;

testsuite/openmodelica/cppruntime/VectorizedPowerSystemTotal.mo

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,7 @@ package PowerSystems "Library for electrical power systems"
325325
package PS = PhaseSystem;
326326
parameter PS.Voltage[PhaseSystem.n] v_start = ones(PhaseSystem.n) "Start value for voltage drop";
327327
PowerSystems.Generic.Ports.Terminal_p terminal(redeclare package PhaseSystem = PhaseSystem, v(start = v_start));
328-
SI.Power[PhaseSystem.n] p "ToDo: move below equation back to binding; broken since commit 28c5b6f (#9907)";
329-
equation
330-
p = PhaseSystem.phasePowers_vi(terminal.v, terminal.i);
328+
SI.Power[PhaseSystem.n] p = PhaseSystem.phasePowers_vi(terminal.v, terminal.i);
331329
end PartialLoad;
332330
end Ports;
333331
end Generic;
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// name: testVectorizedBinding
2+
// keywords: vectorized components, array equations, for loops
3+
// status: correct
4+
// teardown_command: rm -f *VectorizedBindingTest*
5+
// cflags: -d=-nfScalarize
6+
7+
setCommandLineOptions("-d=-nfScalarize"); getErrorString();
8+
setCommandLineOptions("--preOptModules+=dumpDAE"); getErrorString();
9+
setCommandLineOptions("--postOptModules+=dumpDAE"); getErrorString();
10+
setCommandLineOptions("--simCodeTarget=Cpp"); getErrorString();
11+
12+
loadString("
13+
model VectorizedBindingTest
14+
function f
15+
input Real u, i;
16+
output Real p = u * i;
17+
end f;
18+
model M
19+
input Real u = 1;
20+
input Real i = 2;
21+
output Real p = f(u, i);
22+
end M;
23+
parameter Integer n = 10;
24+
M[n] m(u = 1:1:n);
25+
end VectorizedBindingTest;
26+
"); getErrorString();
27+
28+
simulate(VectorizedBindingTest); getErrorString();
29+
30+
val(m.p[1], 1.0);
31+
val(m.p[4], 1.0);
32+
val(m.p[7], 1.0);
33+
val(m.p[10], 1.0);
34+
35+
// Result:
36+
// true
37+
// ""
38+
// true
39+
// ""
40+
// true
41+
// ""
42+
// true
43+
// ""
44+
// true
45+
// ""
46+
//
47+
// ########################################
48+
// dumpDAE
49+
// ########################################
50+
//
51+
//
52+
// unspecified partition
53+
// ========================================
54+
//
55+
// Variables (3)
56+
// ========================================
57+
// 1: m.p:VARIABLE() type: Real[10] [10]
58+
// 2: m.i:VARIABLE() type: Real[10] [10]
59+
// 3: m.u:VARIABLE() type: Real[10] [10]
60+
//
61+
//
62+
// Equations (3, 3)
63+
// ========================================
64+
// 1/1 (10): for $i1 in 1 : 10 loop
65+
// m[$i1].p = VectorizedBindingTest.f(m[$i1].u, m[$i1].i); end for; [dynamic |0|0|0|0|]
66+
// 2/11 (10): m.u = 1.0:1.0:10.0 [binding |0|0|0|0|]
67+
// 3/21 (10): m.i = 2.0 [binding |0|0|0|0|]
68+
//
69+
//
70+
// no matching
71+
//
72+
//
73+
//
74+
// BackendDAEType: simulation
75+
//
76+
//
77+
// Known variables only depending on parameters and constants - globalKnownVars (1)
78+
// ========================================
79+
// 1: n:PARAM(final = true ) = 10 type: Integer
80+
//
81+
//
82+
//
83+
// ########################################
84+
// dumpDAE
85+
// ########################################
86+
//
87+
//
88+
// unspecified partition
89+
// ========================================
90+
//
91+
// Variables (3)
92+
// ========================================
93+
// 1: m.p:VARIABLE() type: Real[10] [10]
94+
// 2: m.i:VARIABLE() type: Real[10] [10]
95+
// 3: m.u:VARIABLE() type: Real[10] [10]
96+
//
97+
//
98+
// Equations (3, 3)
99+
// ========================================
100+
// 1/1 (10): for $i1 in 1 : 10 loop
101+
// m[$i1].p = VectorizedBindingTest.f(m[$i1].u, m[$i1].i); end for; [dynamic |0|0|0|0|]
102+
// 2/11 (10): m.u = 1.0:1.0:10.0 [binding |0|0|0|0|]
103+
// 3/21 (10): m.i = 2.0 [binding |0|0|0|0|]
104+
//
105+
//
106+
// Matching
107+
// ========================================
108+
// 3 variables and equations
109+
// var 1 is solved in eqn 1
110+
// var 2 is solved in eqn 3
111+
// var 3 is solved in eqn 2
112+
//
113+
//
114+
// StrongComponents
115+
// ========================================
116+
// Array {{3:2}}
117+
// Array {{2:3}}
118+
// {1:1}
119+
//
120+
//
121+
//
122+
// BackendDAEType: simulation
123+
//
124+
//
125+
// Known variables only depending on parameters and constants - globalKnownVars (1)
126+
// ========================================
127+
// 1: n:PARAM(final = true ) = 10 type: Integer
128+
//
129+
//
130+
// record SimulationResult
131+
// resultFile = "VectorizedBindingTest_res.mat",
132+
// simulationOptions = "startTime = 0.0, stopTime = 1.0, numberOfIntervals = 500, tolerance = 1e-6, method = 'dassl', fileNamePrefix = 'VectorizedBindingTest', options = '', outputFormat = 'mat', variableFilter = '.*', cflags = '', simflags = ''",
133+
// messages = ""
134+
// end SimulationResult;
135+
// ""
136+
// 2.0
137+
// 8.0
138+
// 14.0
139+
// 20.0
140+
// endResult

testsuite/openmodelica/cppruntime/testVectorizedPowerSystem.mos

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
// keywords: vectorized components, array equations, for loops
33
// status: correct
44
// teardown_command: rm -f *VectorizedPowerSystemTest*
5-
// cflags: -d=-newInst
5+
// cflags: -d=-nfScalarize
66

77
setCommandLineOptions("--std=3.3"); getErrorString();
8-
setCommandLineOptions("-d=newInst,-nfScalarize"); getErrorString();
8+
setCommandLineOptions("-d=-nfScalarize"); getErrorString();
99
setCommandLineOptions("--preOptModules-=removeSimpleEquations"); getErrorString();
1010
setCommandLineOptions("--postOptModules-=removeSimpleEquations"); getErrorString();
1111
setCommandLineOptions("--preOptModules+=dumpDAE"); getErrorString();
@@ -120,7 +120,7 @@ val(fixedVoltageSource1.p[1], 1.0);
120120
// 5: busBar1.terminal_n.v:VARIABLE(flow=false unit = fill("V", 1) nominal = fill(1000.0, 1) ) "voltage vector" type: Real[3, 1] [3,1]
121121
// 6: busBar1.terminal_p.i:VARIABLE(flow=true unit = "A" nominal = 1.0 ) "current vector" type: Real[1] [1]
122122
// 7: busBar1.terminal_p.v:VARIABLE(flow=false unit = "V" nominal = 1000.0 ) "voltage vector" type: Real[1] [1]
123-
// 8: fixedLoad1.p:VARIABLE(unit = fill("W", 1) ) "ToDo: move below equation back to binding; broken since commit 28c5b6f (#9907)" type: Real[3, 1] [3,1]
123+
// 8: fixedLoad1.p:VARIABLE(unit = fill("W", 1) ) type: Real[3, 1] [3,1]
124124
// 9: fixedLoad1.terminal.i:VARIABLE(flow=true unit = fill("A", 1) nominal = fill(1.0, 1) ) "current vector" type: Real[3, 1] [3,1]
125125
// 10: fixedLoad1.terminal.v:VARIABLE(flow=false start = fixedLoad1.v_start unit = fill("V", 1) nominal = fill(1000.0, 1) ) "voltage vector" type: Real[3, 1] [3,1]
126126
// 11: fixedVoltageSource1.p:VARIABLE(unit = "W" ) type: Real[1] [1]
@@ -139,9 +139,9 @@ val(fixedVoltageSource1.p[1], 1.0);
139139
// fixedVoltageSource1.terminal.i[$i1] + busBar1.terminal_p.i[$i1] = 0.0; end for; [dynamic |0|0|0|0|]
140140
// 5/9 (1): fixedVoltageSource1.terminal.v = {fixedVoltageSource1.V} [dynamic |0|0|0|0|]
141141
// 6/10 (3): for $i1 in 1 : 3 loop
142-
// fixedLoad1[$i1].terminal.v * fixedLoad1[$i1].terminal.i = fixedLoad1[$i1].P; end for; [dynamic |0|0|0|0|]
143-
// 7/13 (3): for $i1 in 1 : 3 loop
144142
// fixedLoad1[$i1].p = {fixedLoad1[$i1].terminal.v * fixedLoad1[$i1].terminal.i}; end for; [dynamic |0|0|0|0|]
143+
// 7/13 (3): for $i1 in 1 : 3 loop
144+
// fixedLoad1[$i1].terminal.v * fixedLoad1[$i1].terminal.i = fixedLoad1[$i1].P; end for; [dynamic |0|0|0|0|]
145145
// 8/16 (1): for i in 1 : 1 loop
146146
// busBar1.terminal_p.i[i] = -sum(busBar1.terminal_n[:].i[i]); end for; [dynamic |0|0|0|0|]
147147
// 9/17 (3): for i in 1 : 3 loop
@@ -465,7 +465,7 @@ val(fixedVoltageSource1.p[1], 1.0);
465465
// 5: busBar1.terminal_n.v:VARIABLE(flow=false unit = {"V"} nominal = {1000.0} ) "voltage vector" type: Real[3, 1] [3,1]
466466
// 6: busBar1.terminal_p.i:VARIABLE(flow=true unit = "A" nominal = 1.0 ) "current vector" type: Real[1] [1]
467467
// 7: busBar1.terminal_p.v:VARIABLE(flow=false unit = "V" nominal = 1000.0 ) "voltage vector" type: Real[1] [1]
468-
// 8: fixedLoad1.p:VARIABLE(unit = {"W"} ) "ToDo: move below equation back to binding; broken since commit 28c5b6f (#9907)" type: Real[3, 1] [3,1]
468+
// 8: fixedLoad1.p:VARIABLE(unit = {"W"} ) type: Real[3, 1] [3,1]
469469
// 9: fixedLoad1.terminal.i:VARIABLE(flow=true unit = {"A"} nominal = {1.0} ) "current vector" type: Real[3, 1] [3,1]
470470
// 10: fixedLoad1.terminal.v:VARIABLE(flow=false start = fixedLoad1.v_start unit = {"V"} nominal = {1000.0} ) "voltage vector" type: Real[3, 1] [3,1]
471471
// 11: fixedVoltageSource1.p:VARIABLE(unit = "W" ) type: Real[1] [1]
@@ -484,9 +484,9 @@ val(fixedVoltageSource1.p[1], 1.0);
484484
// fixedVoltageSource1.terminal.i[$i1] + busBar1.terminal_p.i[$i1] = 0.0; end for; [dynamic |0|0|0|0|]
485485
// 5/9 (1): fixedVoltageSource1.terminal.v = {fixedVoltageSource1.V} [dynamic |0|0|0|0|]
486486
// 6/10 (3): for $i1 in 1 : 3 loop
487-
// fixedLoad1[$i1].terminal.v * fixedLoad1[$i1].terminal.i = fixedLoad1[$i1].P; end for; [dynamic |0|0|0|0|]
488-
// 7/13 (3): for $i1 in 1 : 3 loop
489487
// fixedLoad1[$i1].p = {fixedLoad1[$i1].terminal.v * fixedLoad1[$i1].terminal.i}; end for; [dynamic |0|0|0|0|]
488+
// 7/13 (3): for $i1 in 1 : 3 loop
489+
// fixedLoad1[$i1].terminal.v * fixedLoad1[$i1].terminal.i = fixedLoad1[$i1].P; end for; [dynamic |0|0|0|0|]
490490
// 8/16 (1): for i in 1 : 1 loop
491491
// busBar1.terminal_p.i[i] = -sum(busBar1.terminal_n[:].i[i]); end for; [dynamic |0|0|0|0|]
492492
// 9/17 (3): for i in 1 : 3 loop
@@ -507,8 +507,8 @@ val(fixedVoltageSource1.p[1], 1.0);
507507
// var 5 is solved in eqn 9
508508
// var 6 is solved in eqn 8
509509
// var 7 is solved in eqn 3
510-
// var 8 is solved in eqn 7
511-
// var 9 is solved in eqn 6
510+
// var 8 is solved in eqn 6
511+
// var 9 is solved in eqn 7
512512
// var 10 is solved in eqn 1
513513
// var 11 is solved in eqn 10
514514
// var 12 is solved in eqn 4
@@ -527,9 +527,9 @@ val(fixedVoltageSource1.p[1], 1.0);
527527
// Array {{11:3}}
528528
// Array {{13:1}}
529529
// Array {{1:10}}
530-
// {6:9}
530+
// {7:9}
531531
// {2:4}
532-
// {7:8}
532+
// {6:8}
533533
//
534534
//
535535
// unspecified partition

0 commit comments

Comments
 (0)