From 901e52a8177c8fac5cb8db6c6be0645079db8e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=96stlund?= Date: Thu, 7 Dec 2023 13:13:57 +0100 Subject: [PATCH] Improve handling of if/for containing connections (#11694) - Mark if-conditions/for-ranges as structural if they are parameter expressions and the if/for contains connections. Fixes #11606 --- OMCompiler/Compiler/NFFrontEnd/NFComponent.mo | 18 +++++++ OMCompiler/Compiler/NFFrontEnd/NFEquation.mo | 17 +++++++ OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo | 17 +------ .../Compiler/NFFrontEnd/NFStructural.mo | 13 +++-- OMCompiler/Compiler/NFFrontEnd/NFTyping.mo | 7 ++- .../modelica/scodeinst/ForConnect2.mo | 51 +++++++++++++++++++ .../modelica/scodeinst/IfConnect4.mo | 35 +++++++++++++ .../flattening/modelica/scodeinst/Makefile | 2 + 8 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 testsuite/flattening/modelica/scodeinst/ForConnect2.mo create mode 100644 testsuite/flattening/modelica/scodeinst/IfConnect4.mo diff --git a/OMCompiler/Compiler/NFFrontEnd/NFComponent.mo b/OMCompiler/Compiler/NFFrontEnd/NFComponent.mo index 175500b0362..743e14c85e1 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFComponent.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFComponent.mo @@ -357,6 +357,24 @@ public end if; end getImplicitBinding; + function getTypeAttributeBinding + input Component component; + input String attrName; + output Binding binding; + protected + InstNode start_node; + Component start_comp; + algorithm + try + start_node := Class.lookupElement(attrName, InstNode.getClass(classInstance(component))); + start_comp := InstNode.component(start_node); + true := Component.isTypeAttribute(start_comp); + binding := Component.getBinding(start_comp); + else + binding := NFBinding.EMPTY_BINDING; + end try; + end getTypeAttributeBinding; + function setBinding input Binding binding; input output Component component; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFEquation.mo b/OMCompiler/Compiler/NFFrontEnd/NFEquation.mo index 56ad922ca84..36d6e8b87cc 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFEquation.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFEquation.mo @@ -45,6 +45,7 @@ protected import FlatModelicaUtil = NFFlatModelicaUtil; import IOStream; import Util; + import Call = NFCall; public uniontype Branch @@ -1180,6 +1181,7 @@ public end replaceIteratorList; function isConnect + "Checks if an equation is a connect equation." input Equation eq; output Boolean isConnect; algorithm @@ -1189,6 +1191,21 @@ public end match; end isConnect; + function isConnection + "Checks if an equation is a connect equation or a Connections.* call." + input Equation eq; + output Boolean res; + protected + Call call; + algorithm + res := match eq + case Equation.CONNECT() then true; + case Equation.NORETCALL(exp = Expression.CALL(call = call)) + then Call.functionNameFirst(call) == "Connections"; + else false; + end match; + end isConnection; + function sizeOfList input list eqs; output Integer size = 0; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo index 2e19d0e75e4..4ad8e85b080 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo @@ -1708,7 +1708,7 @@ protected InstNode scope; algorithm Equation.IF(branches = branches, scope = scope, source = src) := eq; - has_connect := Equation.contains(eq, isConnectEq); + has_connect := Equation.contains(eq, Equation.isConnection); // Print errors for unbound constants/parameters if the if-equation contains // connects, since we must select a branch in that case. @@ -1792,21 +1792,6 @@ algorithm end if; end flattenIfEquation; -function isConnectEq - input Equation eq; - output Boolean isConnect; -algorithm - isConnect := match eq - local - Function fn; - - case Equation.CONNECT() then true; - case Equation.NORETCALL(exp = Expression.CALL(call = Call.TYPED_CALL(fn = fn))) - then AbsynUtil.pathFirstIdent(Function.name(fn)) == "Connections"; - else false; - end match; -end isConnectEq; - function flattenEqBranch input output Equation.Branch branch; input Prefix prefix; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFStructural.mo b/OMCompiler/Compiler/NFFrontEnd/NFStructural.mo index ef6d48055d5..3317daca7a6 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFStructural.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFStructural.mo @@ -58,11 +58,15 @@ public output Boolean isStructural; protected Boolean is_fixed; + Binding binding; algorithm if compAttrs.variability <> Variability.PARAMETER then // Only parameters can be structural. isStructural := false; elseif compEval or parentEval then + binding := if Binding.isBound(compBinding) then + compBinding else Component.getTypeAttributeBinding(component, "start"); + // If the component or any of its parents has an Evaluate=true annotation // we should probably evaluate the parameter, which we do by marking it as // structural. @@ -72,7 +76,7 @@ public elseif Component.isExternalObject(component) then // Except external objects. isStructural := false; - elseif not InstNode.hasBinding(compNode) then + elseif not (Binding.isBound(binding) or InstNode.hasBinding(compNode)) then // Except parameters with no bindings. if not parentEval and not Flags.getConfigBool(Flags.CHECK_MODEL) then // Print a warning if a parameter has an Evaluate=true annotation but no binding. @@ -81,7 +85,7 @@ public end if; isStructural := false; - elseif isBindingNotFixed(compBinding, requireFinal = false) then + elseif isBindingNotFixed(binding, requireFinal = false) then // Except parameters that depend on non-fixed parameters. isStructural := false; else @@ -92,7 +96,7 @@ public // // If a parameter is fixed and final we might also want to evaluate it, // // since its binding can't be modified. But only if all parameters it // // depends on are also fixed and final. - // if Binding.isUnbound(compBinding) or isBindingNotFixed(compBinding, requireFinal = true) then + // if Binding.isUnbound(binding) or isBindingNotFixed(binding, requireFinal = true) then // isStructural := false; // else // isStructural := true; @@ -143,7 +147,8 @@ public if InstNode.isComponent(parent) and InstNode.isRecord(parent) then isNotFixed := isComponentBindingNotFixed(InstNode.component(parent), parent, requireFinal, maxDepth, true); else - isNotFixed := true; + binding := Component.getTypeAttributeBinding(component, "start"); + isNotFixed := isBindingNotFixed(binding, requireFinal, maxDepth); end if; end if; else diff --git a/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo b/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo index 81f8f0b0bf4..321163296bb 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo @@ -2988,6 +2988,10 @@ algorithm e1 := typeIterator(eq.iterator, e1, context, structural = true); next_context := InstContext.set(context, NFInstContext.FOR); body := list(typeEquation(e, next_context) for e in eq.body); + + if Equation.containsList(body, Equation.isConnection) then + Structural.markExp(e1); + end if; then Equation.FOR(eq.iterator, SOME(e1), body, eq.scope, eq.source); @@ -3497,7 +3501,8 @@ algorithm // connections in the branch, mark the context so we can check that when // typing the body of the branch. next_context := InstContext.set(next_context, NFInstContext.NONEXPANDABLE); - elseif var == Variability.PARAMETER and accum_var <= Variability.PARAMETER then + elseif var == Variability.PARAMETER and + (accum_var <= Variability.PARAMETER or Equation.containsList(eql, Equation.isConnection)) then // If all conditions up to and including this one are parameter // expressions, consider the condition to be structural. var := Variability.STRUCTURAL_PARAMETER; diff --git a/testsuite/flattening/modelica/scodeinst/ForConnect2.mo b/testsuite/flattening/modelica/scodeinst/ForConnect2.mo new file mode 100644 index 00000000000..048d1ced31c --- /dev/null +++ b/testsuite/flattening/modelica/scodeinst/ForConnect2.mo @@ -0,0 +1,51 @@ +// name: ForConnect2 +// keywords: +// status: correct +// cflags: -d=newInst +// +// + +connector C + Real e; + flow Real f; +end C; + +model ForConnect2 + C c1[3], c2[3]; + parameter Integer n(start = 3); +equation + for i in 1:n loop + connect(c1[i], c2[i]); + end for; +end ForConnect2; + +// Result: +// class ForConnect2 +// Real c1[1].e; +// Real c1[1].f; +// Real c1[2].e; +// Real c1[2].f; +// Real c1[3].e; +// Real c1[3].f; +// Real c2[1].e; +// Real c2[1].f; +// Real c2[2].e; +// Real c2[2].f; +// Real c2[3].e; +// Real c2[3].f; +// final parameter Integer n(start = 3); +// equation +// c1[1].e = c2[1].e; +// (-c1[1].f) - c2[1].f = 0.0; +// c1[2].e = c2[2].e; +// (-c1[2].f) - c2[2].f = 0.0; +// c1[3].e = c2[3].e; +// (-c1[3].f) - c2[3].f = 0.0; +// c1[1].f = 0.0; +// c1[2].f = 0.0; +// c1[3].f = 0.0; +// c2[1].f = 0.0; +// c2[2].f = 0.0; +// c2[3].f = 0.0; +// end ForConnect2; +// endResult diff --git a/testsuite/flattening/modelica/scodeinst/IfConnect4.mo b/testsuite/flattening/modelica/scodeinst/IfConnect4.mo new file mode 100644 index 00000000000..c7f82452f67 --- /dev/null +++ b/testsuite/flattening/modelica/scodeinst/IfConnect4.mo @@ -0,0 +1,35 @@ +// name: IfConnect4 +// keywords: +// status: correct +// cflags: -d=newInst +// +// + +connector C + Real e; + flow Real f; +end C; + +model IfConnect4 + parameter Boolean b(start = true); + C c1, c2; +equation + if b then + connect(c1, c2); + end if; +end IfConnect4; + +// Result: +// class IfConnect4 +// final parameter Boolean b(start = true); +// Real c1.e; +// Real c1.f; +// Real c2.e; +// Real c2.f; +// equation +// c1.e = c2.e; +// (-c1.f) - c2.f = 0.0; +// c1.f = 0.0; +// c2.f = 0.0; +// end IfConnect4; +// endResult diff --git a/testsuite/flattening/modelica/scodeinst/Makefile b/testsuite/flattening/modelica/scodeinst/Makefile index 76d7f54db43..b1ce9d5f5fa 100644 --- a/testsuite/flattening/modelica/scodeinst/Makefile +++ b/testsuite/flattening/modelica/scodeinst/Makefile @@ -514,6 +514,7 @@ Final5.mo \ Final6.mo \ Final7.mo \ ForConnect1.mo \ +ForConnect2.mo \ ForEquation1.mo \ ForEquation2.mo \ ForEquation3.mo \ @@ -705,6 +706,7 @@ FunctionUnitialized4.mo \ IfConnect1.mo \ IfConnect2.mo \ IfConnect3.mo \ +IfConnect4.mo \ IfEquation1.mo \ IfEquation2.mo \ IfEquation3.mo \