From ec7f7412e80051a025e2b9db5cab4b793a6f448a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BCdiger=20Franke?= Date: Sat, 6 Oct 2018 07:16:32 +0200 Subject: [PATCH] Make inline integration for synchronous models work with arrays - synchronousFeatures generates for-equation with integration formula - SimCodeUtil.createEquation solves for-equations for states - (CodegenUtilSimulation.dumpEqs uses Modelica instead of C syntax) Belonging to [master]: - OpenModelica/OMCompiler#2698 - OpenModelica/OpenModelica-testsuite#1045 --- Compiler/BackEnd/SynchronousFeatures.mo | 56 +++++++++++++++++---- Compiler/FrontEnd/DAEUtil.mo | 18 +++++++ Compiler/SimCode/SimCodeUtil.mo | 14 ++++-- Compiler/Template/CodegenUtilSimulation.tpl | 9 ++-- 4 files changed, 77 insertions(+), 20 deletions(-) diff --git a/Compiler/BackEnd/SynchronousFeatures.mo b/Compiler/BackEnd/SynchronousFeatures.mo index c134ab8631..10d5ac42d2 100644 --- a/Compiler/BackEnd/SynchronousFeatures.mo +++ b/Compiler/BackEnd/SynchronousFeatures.mo @@ -213,6 +213,7 @@ algorithm list derVars = {}; BackendDAE.Var var; DAE.Exp exp, exp2; + DAE.Type ty; case syst as BackendDAE.EQSYSTEM(orderedEqs = eqs) algorithm BackendDAE.CLOCKED_PARTITION(idx) := syst.partitionKind; @@ -232,7 +233,7 @@ algorithm // replace der(x) with $DER.x and collect derVars x for i in 1:BackendEquation.getNumberOfEquations(eqs) loop eq := BackendEquation.get(eqs, i); - (eq, derVars) := BackendEquation.traverseExpsOfEquation(eq, getDerVars1, derVars); + (eq, (derVars, _)) := BackendEquation.traverseExpsOfEquation(eq, getDerVars1, (derVars, BackendEquation.getForEquationIterIdent(eq))); lstEqs := eq :: lstEqs; end for; // add all $DER.x as additional variables @@ -244,9 +245,16 @@ algorithm // add defining equations for $DER.x, depending on solverMethod for derVar in derVars loop var := listGet(BackendVariable.getVar(derVar, syst.orderedVars), 1); - exp := DAE.CALL(Absyn.IDENT(name = "der"), {DAE.CREF(derVar, var.varType)}, DAE.callAttrBuiltinImpureReal); + ty := var.varType; + // add forIter subscript and use element type if var is array + derVar := match var.varType + case DAE.T_ARRAY(ty = ty) + then ComponentReference.crefSetLastSubs(derVar, {DAE.INDEX(DAE.CREF(DAE.CREF_IDENT("i", DAE.T_INTEGER_DEFAULT, {}), DAE.T_INTEGER_DEFAULT))}); + else derVar; + end match; + exp := DAE.CALL(Absyn.IDENT(name = "der"), {DAE.CREF(derVar, ty)}, DAE.callAttrBuiltinImpureReal); exp := substituteFiniteDifference(exp); - exp2 := DAE.CREF(ComponentReference.crefPrefixDer(derVar), var.varType); + exp2 := DAE.CREF(ComponentReference.crefPrefixDer(derVar), ty); if solverMethod == "ExplicitEuler" then // introduce states to delay derivatives; see MLS 3.3, section 16.8.2 Solver Methods exp2 := DAE.CALL(Absyn.IDENT(name = "previous"), {exp2}, DAE.callAttrBuiltinImpureReal); @@ -259,7 +267,17 @@ algorithm // clocked continuous states are fixed at first tick exp2 := DAE.IFEXP(DAE.CALL(Absyn.IDENT(name = "firstTick"), {}, DAE.callAttrBuiltinImpureBool), DAE.RCONST(0), exp2); - eq := BackendDAE.EQUATION(exp, exp2, var.source, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC); + // create for-equation or regular equation + eq := match var.varType + local + DAE.Dimension dim; + case DAE.T_ARRAY(dims = {dim}) + then BackendDAE.FOR_EQUATION( + DAE.CREF(DAE.CREF_IDENT("i", DAE.T_INTEGER_DEFAULT, {}), DAE.T_INTEGER_DEFAULT), + DAE.ICONST(1), DAEUtil.dimExp(dim), + exp, exp2, var.source, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC); + else BackendDAE.EQUATION(exp, exp2, var.source, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC); + end match; lstEqs := eq :: lstEqs; end for; syst.orderedEqs := BackendEquation.listEquation(listReverse(lstEqs)); @@ -281,9 +299,9 @@ end treatClockedStates; protected function getDerVars1 "helper to getDerVars" input DAE.Exp inExp; - input list inDerVars; + input tuple, Option> inDerVars; output DAE.Exp outExp; - output list outDerVars; + output tuple, Option> outDerVars; algorithm (outExp, outDerVars) := Expression.traverseExpBottomUp(inExp, getDerVars, inDerVars); end getDerVars1; @@ -292,21 +310,37 @@ protected function getDerVars "Get all crefs that appear in a der() operator and replace der(x) with $DER.x. author: rfranke" input DAE.Exp inExp; - input list inDerVars; + input tuple, Option> inDerVars; output DAE.Exp outExp; - output list outDerVars = inDerVars; + output tuple, Option> outDerVars = inDerVars; algorithm outExp := match inExp local + list derVars; + Option optForIter; + DAE.Ident forIter; DAE.ComponentRef x; DAE.Type ty; + DAE.Exp der_x; case DAE.CALL(path = Absyn.IDENT(name = "der"), expLst = {DAE.CREF(componentRef = x, ty = ty)}) algorithm - if not ComponentReference.crefInLst(x, outDerVars) then - outDerVars := x :: outDerVars; + // build $DER.x + der_x := DAE.CREF(ComponentReference.crefPrefixDer(x), ty); + // strip optional forIter and append x to derVars + (derVars, optForIter) := inDerVars; + _ := match optForIter + case SOME(forIter) + algorithm + x := ComponentReference.crefStripIterSub(x, forIter); + then (); + else (); + end match; + if not ComponentReference.crefInLst(x, derVars) then + derVars := x :: derVars; end if; - then DAE.CREF(ComponentReference.crefPrefixDer(x), ty); + outDerVars := (derVars, optForIter); + then der_x; else inExp; end match; end getDerVars; diff --git a/Compiler/FrontEnd/DAEUtil.mo b/Compiler/FrontEnd/DAEUtil.mo index 28e7669bef..0c6865ae84 100644 --- a/Compiler/FrontEnd/DAEUtil.mo +++ b/Compiler/FrontEnd/DAEUtil.mo @@ -235,6 +235,24 @@ algorithm end match; end expTypeArrayDimensions; +public function dimExp + "Converts a dimension to an expression, covering constants and paramters." + input DAE.Dimension dim; + output DAE.Exp exp; +algorithm + exp := match dim + local + Integer iconst; + case DAE.DIM_INTEGER(iconst) then + DAE.ICONST(iconst); + case DAE.DIM_EXP(exp) then + exp; + else algorithm + Error.addMessage(Error.DIMENSION_NOT_KNOWN, {anyString(dim)}); + then fail(); + end match; +end dimExp; + public function derivativeOrder " Function to sort derivatives. Used for Util.sort" diff --git a/Compiler/SimCode/SimCodeUtil.mo b/Compiler/SimCode/SimCodeUtil.mo index fa5cf5d949..5598f7a71d 100644 --- a/Compiler/SimCode/SimCodeUtil.mo +++ b/Compiler/SimCode/SimCodeUtil.mo @@ -2084,7 +2084,8 @@ algorithm list conditions, solveCr; list resEqs; DAE.ComponentRef left, varOutput; - DAE.Exp e1, e2, varexp, exp_, right, cond, prevarexp; + DAE.Exp e1, e2, varexp, exp_, start, cond, prevarexp; + DAE.Ident iter; BackendDAE.WhenEquation whenEquation, elseWhen; Option oelseWhen; String algStr, message, eqStr; @@ -2109,10 +2110,15 @@ algorithm then ({SimCode.SES_SIMPLE_ASSIGN(iuniqueEqIndex, cr, e2, source, eqAttr)}, iuniqueEqIndex + 1, itempvars); - // for equation that may result from -d=-nfScalarize and is assumed solved - case BackendDAE.FOR_EQUATION(iter = varexp, start = e1, stop = e2, left = DAE.CREF(componentRef = cr), right = right, source = source, attr = eqAttr) + // for equation that may result from -d=-nfScalarize + case BackendDAE.FOR_EQUATION(iter = varexp, start = start, stop = cond, left = e1, right = e2, source = source, attr = eqAttr) + algorithm + DAE.CREF(componentRef = DAE.CREF_IDENT(ident = iter)) := varexp; + cr := ComponentReference.crefSetLastSubs(v.varName, {DAE.INDEX(DAE.CREF(DAE.CREF_IDENT(iter, DAE.T_INTEGER_DEFAULT, {}), DAE.T_INTEGER_DEFAULT))}); + BackendDAE.SHARED(functionTree = funcs) := shared; + (exp_, asserts, solveEqns, solveCr) := ExpressionSolve.solve2(e1, e2, Expression.crefExp(cr), SOME(funcs), SOME(iuniqueEqIndex), true, BackendDAEUtil.isSimulationDAE(shared)); then - ({SimCode.SES_FOR_LOOP(iuniqueEqIndex, varexp, e1, e2, cr, right, source, eqAttr)}, iuniqueEqIndex + 1, itempvars); + ({SimCode.SES_FOR_LOOP(iuniqueEqIndex, varexp, start, cond, cr, exp_, source, eqAttr)}, iuniqueEqIndex + 1, itempvars); // solved equation case BackendDAE.SOLVED_EQUATION(exp=e2, source=source, attr=eqAttr) diff --git a/Compiler/Template/CodegenUtilSimulation.tpl b/Compiler/Template/CodegenUtilSimulation.tpl index cb77a425bf..865681bb28 100644 --- a/Compiler/Template/CodegenUtilSimulation.tpl +++ b/Compiler/Template/CodegenUtilSimulation.tpl @@ -215,11 +215,10 @@ template dumpEqs(list eqs) >> case e as SES_FOR_LOOP(__) then let &forstatement = buffer "" - let &forstatement += 'for(size_t ' + escapeCComments(dumpExp(e.iter,"\"")) + ' = ' + escapeCComments(dumpExp(e.startIt,"\"")) + '; ' - let &forstatement += escapeCComments(dumpExp(e.iter,"\"")) + ' != ' + escapeCComments(dumpExp(e.endIt,"\"")) + '+1; ' - let &forstatement += escapeCComments(dumpExp(e.iter,"\"")) + '++) {<%\n%>' - let &forstatement += ' <%crefStr(e.cref)%> = <%escapeCComments(dumpExp(e.exp,"\""))%><%\n%>' - let &forstatement += '}' + let &forstatement += 'for ' + escapeCComments(dumpExp(e.iter,"\"")) + ' in ' + escapeCComments(dumpExp(e.startIt,"\"")) + let &forstatement += ' : ' + escapeCComments(dumpExp(e.endIt,"\"")) + ' loop<%\n%>' + let &forstatement += ' <%crefStr(e.cref)%> = <%escapeCComments(dumpExp(e.exp,"\""))%>; ' + let &forstatement += 'end for' << equation index: <%equationIndex(e)%> type: FOR_LOOP