From c2540331314f2213474d703ce6cc6f9d012a5148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=96stlund?= Date: Thu, 4 May 2023 17:01:11 +0200 Subject: [PATCH] Frontend support for partial derivatives of functions (#10649) - Add frontend support for partial derivatives of functions (`df = der(f, x)`) for use by the new backend. Only enabled when using the `--newBackend` flag since the old backend would handle them incorrectly. --- OMCompiler/Compiler/FrontEnd/DAE.mo | 5 + .../Compiler/NFFrontEnd/NFBuiltinFuncs.mo | 78 +++++++------- OMCompiler/Compiler/NFFrontEnd/NFClass.mo | 6 ++ .../Compiler/NFFrontEnd/NFConvertDAE.mo | 8 ++ .../Compiler/NFFrontEnd/NFEvalFunction.mo | 4 + OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo | 6 ++ OMCompiler/Compiler/NFFrontEnd/NFFunction.mo | 101 ++++++++++++++++-- OMCompiler/Compiler/NFFrontEnd/NFInst.mo | 9 ++ OMCompiler/Compiler/NFFrontEnd/NFInstNode.mo | 15 +++ OMCompiler/Compiler/NFFrontEnd/NFRecord.mo | 2 +- OMCompiler/Compiler/NFFrontEnd/NFTyping.mo | 4 +- OMCompiler/Compiler/Template/DAEDumpTV.mo | 5 + OMCompiler/Compiler/Template/DAEDumpTpl.tpl | 13 +++ OMCompiler/Compiler/Util/Error.mo | 4 + .../scodeinst/FunctionPartialDerivative1.mo | 24 +++++ .../scodeinst/FunctionPartialDerivative2.mo | 26 +++++ .../scodeinst/FunctionPartialDerivative3.mo | 26 +++++ .../flattening/modelica/scodeinst/Makefile | 3 + 18 files changed, 290 insertions(+), 49 deletions(-) create mode 100644 testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative1.mo create mode 100644 testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative2.mo create mode 100644 testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative3.mo diff --git a/OMCompiler/Compiler/FrontEnd/DAE.mo b/OMCompiler/Compiler/FrontEnd/DAE.mo index 5b37b544832..6cf4ad91227 100644 --- a/OMCompiler/Compiler/FrontEnd/DAE.mo +++ b/OMCompiler/Compiler/FrontEnd/DAE.mo @@ -470,6 +470,11 @@ public uniontype FunctionDefinition ComponentRef inputParam "The input parameter the inverse is for"; Exp inverseCall "The inverse function call"; end FUNCTION_INVERSE; + + record FUNCTION_PARTIAL_DERIVATIVE + Absyn.Path derivedFunction; + list derivedVars; + end FUNCTION_PARTIAL_DERIVATIVE; end FunctionDefinition; public diff --git a/OMCompiler/Compiler/NFFrontEnd/NFBuiltinFuncs.mo b/OMCompiler/Compiler/NFFrontEnd/NFBuiltinFuncs.mo index 0182b217e5d..333528b90d0 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFBuiltinFuncs.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFBuiltinFuncs.mo @@ -143,7 +143,7 @@ constant InstNode INTEGER_DUMMY_NODE = NFInstNode.CLASS_NODE("Integer", constant Function INTEGER_FUNCTION = Function.FUNCTION(Path.IDENT("Integer"), INTEGER_DUMMY_NODE, {ENUM_PARAM}, {}, {}, { Slot.SLOT(ENUM_PARAM, SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED) - }, Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); + }, Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant InstNode INTEGER_NODE = InstNode.CLASS_NODE("IntegerFunc", DUMMY_ELEMENT, Visibility.PUBLIC, @@ -185,7 +185,7 @@ constant Function STRING_REAL = Function.FUNCTION(Path.IDENT("String"), Slot.SLOT(SIGNIFICANT_DIGITS_PARAM, SlotType.NAMED, SOME(Expression.INTEGER(6)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(MINIMUM_LENGTH_PARAM, SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE(), 3, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(LEFT_JUSTIFIED_PARAM, SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE(), 4, SlotEvalStatus.NOT_EVALUATED) - }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // String(r, format="-0.6g") @@ -193,7 +193,7 @@ constant Function STRING_REAL_FORMAT = Function.FUNCTION(Path.IDENT("String"), STRING_DUMMY_NODE, {REAL_PARAM, STRING_PARAM}, {STRING_PARAM}, {}, { Slot.SLOT(R_PARAM, SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(FORMAT_PARAM, SlotType.NAMED, NONE(), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) - }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // String(i, minimumLength=0, leftJustified=true) @@ -202,7 +202,7 @@ constant Function STRING_INT = Function.FUNCTION(Path.IDENT("String"), Slot.SLOT(I_PARAM, SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(MINIMUM_LENGTH_PARAM, SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(LEFT_JUSTIFIED_PARAM, SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE(), 3, SlotEvalStatus.NOT_EVALUATED) - }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // String(b, minimumLength=0, leftJustified=true) @@ -211,7 +211,7 @@ constant Function STRING_BOOL = Function.FUNCTION(Path.IDENT("String"), Slot.SLOT(B_PARAM, SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(MINIMUM_LENGTH_PARAM, SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(LEFT_JUSTIFIED_PARAM, SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE(), 3, SlotEvalStatus.NOT_EVALUATED) - }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // String(e, minimumLength=0, leftJustified=true) @@ -220,7 +220,7 @@ constant Function STRING_ENUM = Function.FUNCTION(Path.IDENT("String"), Slot.SLOT(E_PARAM, SlotType.POSITIONAL, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(MINIMUM_LENGTH_PARAM, SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(LEFT_JUSTIFIED_PARAM, SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE(), 3, SlotEvalStatus.NOT_EVALUATED) - }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant InstNode STRING_NODE = InstNode.CLASS_NODE("String", @@ -246,142 +246,142 @@ constant ComponentRef STRING_CREF = // TODO: Sort these functions ... constant Function COS_REAL = Function.FUNCTION(Path.IDENT("cos"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function SIN_REAL = Function.FUNCTION(Path.IDENT("sin"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function TAN_REAL = Function.FUNCTION(Path.IDENT("tan"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function COSH_REAL = Function.FUNCTION(Path.IDENT("cosh"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function SINH_REAL = Function.FUNCTION(Path.IDENT("sinh"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function TANH_REAL = Function.FUNCTION(Path.IDENT("tanh"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function EXP_REAL = Function.FUNCTION(Path.IDENT("exp"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function LOG_REAL = Function.FUNCTION(Path.IDENT("log"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function LOG10_REAL = Function.FUNCTION(Path.IDENT("log10"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function ABS_REAL = Function.FUNCTION(Path.IDENT("abs"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function SIGN_REAL = Function.FUNCTION(Path.IDENT("sign"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function MAX_INT = Function.FUNCTION(Path.IDENT("max"), InstNode.EMPTY_NODE(), {INT_PARAM, INT_PARAM}, {INT_PARAM}, {}, {}, - Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function MAX_REAL = Function.FUNCTION(Path.IDENT("max"), InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function DIV_INT = Function.FUNCTION(Path.IDENT("div"), InstNode.EMPTY_NODE(), {INT_PARAM, INT_PARAM}, {INT_PARAM}, {}, {}, - Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function DIV_REAL = Function.FUNCTION(Path.IDENT("div"), InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function FLOOR = Function.FUNCTION(Path.IDENT("floor"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function INTEGER_REAL = Function.FUNCTION(Path.IDENT("integer"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {INT_PARAM}, {}, {}, - Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function INTEGER_ENUM = Function.FUNCTION(Path.IDENT("Integer"), InstNode.EMPTY_NODE(), {ENUM_PARAM}, {INT_PARAM}, {}, {}, - Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function POSITIVE_MAX_REAL = Function.FUNCTION(Path.IDENT("$OMC$PositiveMax"), InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function IN_STREAM = Function.FUNCTION(Path.IDENT("inStream"), InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function PROMOTE = Function.FUNCTION(Path.IDENT("promote"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function CAT = Function.FUNCTION(Path.IDENT("cat"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function ARRAY_FUNC = Function.FUNCTION(Path.IDENT("array"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function FILL_FUNC = Function.FUNCTION(Path.IDENT("fill"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function SMOOTH = Function.FUNCTION(Path.IDENT("smooth"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function NO_EVENT = Function.FUNCTION(Path.IDENT("noEvent"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function SUM = Function.FUNCTION(Path.IDENT("sum"), InstNode.EMPTY_NODE(), {}, {}, {}, {}, - Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Function SAMPLE = Function.FUNCTION(Path.QUALIFIED("OMC_NO_CLOCK", Path.IDENT("sample")), InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {}, - Type.BOOLEAN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN_IMPURE, {}, listArray({}), + Type.BOOLEAN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN_IMPURE, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant Component CLOCK_COMPONENT = Component.COMPONENT(NFInstNode.EMPTY_NODE(), @@ -400,7 +400,7 @@ constant InstNode CLOCK_DUMMY_NODE = NFInstNode.CLASS_NODE("Clock", // Clock() - inferred clock constant Function CLOCK_INFERRED = Function.FUNCTION(Path.IDENT("Clock"), CLOCK_DUMMY_NODE, {}, {CLOCK_PARAM}, {}, {}, Type.CLOCK(), - DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); constant InstNode INTERVAL_COUNTER_PARAM = InstNode.COMPONENT_NODE("intervalCounter", NONE(), @@ -423,14 +423,14 @@ constant Function CLOCK_INT = Function.FUNCTION(Path.IDENT("Clock"), CLOCK_DUMMY_NODE, {INT_PARAM, INT_PARAM}, {CLOCK_PARAM}, {}, { Slot.SLOT(INTERVAL_COUNTER_PARAM, SlotType.GENERIC, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(RESOLUTION_PARAM, SlotType.GENERIC, SOME(Expression.INTEGER(1)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) - }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // Clock(interval) - clock with Real interval constant Function CLOCK_REAL = Function.FUNCTION(Path.IDENT("Clock"), CLOCK_DUMMY_NODE, {REAL_PARAM}, {CLOCK_PARAM}, {}, { Slot.SLOT(INTERVAL_PARAM, SlotType.GENERIC, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED) - }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // Clock(condition, startInterval = 0.0) - Event clock, triggered by zero-crossing events @@ -438,7 +438,7 @@ constant Function CLOCK_BOOL = Function.FUNCTION(Path.IDENT("Clock"), CLOCK_DUMMY_NODE, {BOOL_PARAM, REAL_PARAM}, {CLOCK_PARAM}, {}, { Slot.SLOT(CONDITION_PARAM, SlotType.GENERIC, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(START_INTERVAL_PARAM, SlotType.GENERIC, SOME(Expression.REAL(0.0)), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) - }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); // Clock(c, solverMethod) - Solver clock @@ -446,7 +446,7 @@ constant Function CLOCK_SOLVER = Function.FUNCTION(Path.IDENT("Clock"), CLOCK_DUMMY_NODE, {CLOCK_PARAM, STRING_PARAM}, {CLOCK_PARAM}, {}, { Slot.SLOT(C_PARAM, SlotType.GENERIC, NONE(), NONE(), 1, SlotEvalStatus.NOT_EVALUATED), Slot.SLOT(SOLVER_METHOD_PARAM, SlotType.GENERIC, NONE(), NONE(), 2, SlotEvalStatus.NOT_EVALUATED) - }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, listArray({}), + }, Type.CLOCK(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, {}, {}, listArray({}), Pointer.createImmutable(FunctionStatus.BUILTIN), Pointer.createImmutable(0)); diff --git a/OMCompiler/Compiler/NFFrontEnd/NFClass.mo b/OMCompiler/Compiler/NFFrontEnd/NFClass.mo index f1e3380a3d2..2c99cc1b0ea 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFClass.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFClass.mo @@ -213,6 +213,12 @@ constant Prefixes DEFAULT_PREFIXES = Prefixes.PREFIXES( cls := match cls case INSTANCED_CLASS() then INSTANCED_CLASS(cls.ty, cls.elements, sections, cls.prefixes, cls.restriction); + + case TYPED_DERIVED() + algorithm + InstNode.classApply(cls.baseClass, setSections, sections); + then + cls; end match; end setSections; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFConvertDAE.mo b/OMCompiler/Compiler/NFFrontEnd/NFConvertDAE.mo index 9b25549dae6..ddfc4974db6 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFConvertDAE.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFConvertDAE.mo @@ -1091,6 +1091,14 @@ algorithm cls := InstNode.getClass(Function.instance(func)); dfunc := match cls + case Class.TYPED_DERIVED(restriction = Restriction.FUNCTION()) + guard Function.isPartialDerivative(func) + algorithm + def := DAE.FunctionDefinition.FUNCTION_PARTIAL_DERIVATIVE( + Function.getDerivedFunctionName(func), Function.getDerivedInputNames(func)); + then + Function.toDAE(func, def); + case Class.INSTANCED_CLASS(sections = sections, restriction = Restriction.FUNCTION()) algorithm elems := convertFunctionParams(func.inputs, {}); diff --git a/OMCompiler/Compiler/NFFrontEnd/NFEvalFunction.mo b/OMCompiler/Compiler/NFFrontEnd/NFEvalFunction.mo index 37feee55a42..dfc34f1b1ac 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFEvalFunction.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFEvalFunction.mo @@ -81,6 +81,10 @@ function evaluate algorithm if Function.isExternal(fn) then result := evaluateExternal(fn, args, target); + elseif Function.isPartialDerivative(fn) then + // Partial derivatives of functions are differentiated by the backend, so + // make sure we don't try to evaluate the non-differentiated function body. + fail(); else result := evaluateNormal(fn, args); end if; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo index 92432a8435f..6062c096a25 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFlatten.mo @@ -2533,6 +2533,12 @@ algorithm for fn_inv in fn.inverses loop funcs := collectExpFuncs(fn_inv.inverseCall, funcs); end for; + + if Function.isPartialDerivative(fn) then + for f in Function.getCachedFuncs(Class.lastBaseClass(fn.node)) loop + flattenFunction(f, funcs); + end for; + end if; end if; end if; end flattenFunction; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo b/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo index c261b172930..f20e143a279 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFFunction.mo @@ -270,6 +270,7 @@ uniontype Function Type returnType; DAE.FunctionAttributes attributes; list derivatives; + list derivedInputs; array inverses; Pointer status; Pointer callCounter "Used during function evaluation to limit recursion."; @@ -291,7 +292,7 @@ uniontype Function // Make sure builtin functions aren't added to the function tree. status := if isBuiltinAttr(attr) then FunctionStatus.COLLECTED else FunctionStatus.INITIAL; fn := FUNCTION(path, node, inputs, outputs, locals, {}, Type.UNKNOWN(), - attr, {}, listArray({}), Pointer.create(status), Pointer.create(0)); + attr, {}, {}, listArray({}), Pointer.create(status), Pointer.create(0)); end new; function lookupFunctionSimple @@ -467,6 +468,7 @@ uniontype Function specialBuiltin := isSpecialBuiltin(fn); fn.derivatives := FunctionDerivative.instDerivatives(fnNode, fn); fn.inverses := FunctionInverse.instInverses(fnNode, fn); + fn.derivedInputs := instPartialDerivedVars(def.classDef, fn.inputs, fn, context, info); fnNode := InstNode.cacheAddFunc(fnNode, fn, specialBuiltin); then (fnNode, specialBuiltin); @@ -728,15 +730,21 @@ uniontype Function algorithm if isDefaultRecordConstructor(fn) then s := IOStream.append(s, InstNode.toFlatString(fn.node)); + elseif isPartialDerivative(fn) then + fn_name := if stringEmpty(overrideName) then Util.makeQuotedIdentifier(AbsynUtil.pathString(fn.path)) else overrideName; + + s := IOStream.append(s, "function "); + s := IOStream.append(s, fn_name); + s := IOStream.append(s, " = der("); + s := IOStream.append(s, Util.makeQuotedIdentifier(AbsynUtil.pathString(getDerivedFunctionName(fn)))); + s := IOStream.append(s, ", "); + s := IOStream.append(s, stringDelimitList(getDerivedInputNames(fn), ", ")); + s := FlatModelicaUtil.appendComment(SCodeUtil.getElementComment(InstNode.definition(fn.node)), s); + s := IOStream.append(s, ")"); else cmt := Util.getOptionOrDefault(SCodeUtil.getElementComment(InstNode.definition(fn.node)), SCode.COMMENT(NONE(), NONE())); + fn_name := if stringEmpty(overrideName) then Util.makeQuotedIdentifier(AbsynUtil.pathString(fn.path)) else overrideName; - fn_name := AbsynUtil.pathString(fn.path); - if stringEmpty(overrideName) then - fn_name := Util.makeQuotedIdentifier(fn_name); - else - fn_name := overrideName; - end if; s := IOStream.append(s, "function "); s := IOStream.append(s, fn_name); s := FlatModelicaUtil.appendCommentString(SOME(cmt), s); @@ -1394,7 +1402,7 @@ uniontype Function if not isTyped(fn) then // Type all the components in the function. Typing.typeClassType(node, NFBinding.EMPTY_BINDING, context, node); - Typing.typeComponents(node, context); + Typing.typeComponents(node, context, preserveDerived = isPartialDerivative(fn)); if InstNode.isPartial(node) then ClassTree.applyComponents(Class.classTree(InstNode.getClass(node)), boxFunctionParameter); @@ -1403,6 +1411,7 @@ uniontype Function // Make the slots and return type for the function. fn.slots := makeSlots(fn.inputs); checkParamTypes(fn); + checkPartialDerivativeTypes(fn); fn.returnType := makeReturnType(fn); end if; end typeFunctionSignature; @@ -1759,6 +1768,31 @@ uniontype Function end if; end isExternalObjectConstructorOrDestructor; + function isPartialDerivative + "Returns true if the function is a partial derivative of a function, df = der(f, x)." + input Function fn; + output Boolean res = not listEmpty(fn.derivedInputs); + end isPartialDerivative; + + function getDerivedInputNames + "Returns the names of the differentiated inputs in a partial derivative, + df = der(f, x, y, z) => {\"x\", \"y\", \"z\"}" + input Function fn; + output list names = {}; + algorithm + for i in fn.derivedInputs loop + names := InstNode.name(listGet(fn.inputs, i)) :: names; + end for; + + names := listReverseInPlace(names); + end getDerivedInputNames; + + function getDerivedFunctionName + "Returns the name of the derived function in a partial derivative, df = der(f, x) => f" + input Function fn; + output Absyn.Path name = InstNode.fullPath(Class.lastBaseClass(fn.node), ignoreBaseClass = true); + end getDerivedFunctionName; + function inlineBuiltin input Function fn; output DAE.InlineType inlineType; @@ -2379,6 +2413,24 @@ protected end match; end isValidParamState; + function checkPartialDerivativeTypes + input Function fn; + protected + InstNode node; + Type ty; + algorithm + for i in fn.derivedInputs loop + node := listGet(fn.inputs, i); + ty := InstNode.getType(node); + + if not (Type.isReal(ty) and Type.isScalar(ty)) then + Error.addSourceMessage(Error.PARTIAL_DERIVATIVE_INPUT_INVALID_TYPE, + {InstNode.name(node), AbsynUtil.pathString(getDerivedFunctionName(fn))}, InstNode.info(fn.node)); + fail(); + end if; + end for; + end checkPartialDerivativeTypes; + public function makeReturnType input Function fn; output Type returnType; @@ -2818,6 +2870,39 @@ protected else (); end match; end checkUseBeforeAssignExp_traverse; + + function instPartialDerivedVars + input SCode.ClassDef classDef; + input list inputs; + input Function fn; + input InstContext.Type context; + input SourceInfo info; + output list derivedVars = {}; + protected + Integer index; + algorithm + () := match classDef + case SCode.ClassDef.PDER() + algorithm + for var in classDef.derivedVariables loop + index := List.positionOnTrue(inputs, function InstNode.isNamed(name = var)); + + if index < 1 then + Error.addSourceMessage(Error.PARTIAL_DERIVATIVE_INPUT_NOT_FOUND, + {var, AbsynUtil.pathString(getDerivedFunctionName(fn))}, info); + fail(); + end if; + + derivedVars := index :: derivedVars; + end for; + + derivedVars := listReverseInPlace(derivedVars); + then + (); + + else (); + end match; + end instPartialDerivedVars; end Function; annotation(__OpenModelica_Interface="frontend"); diff --git a/OMCompiler/Compiler/NFFrontEnd/NFInst.mo b/OMCompiler/Compiler/NFFrontEnd/NFInst.mo index decf756fcfb..2b963d671dd 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFInst.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFInst.mo @@ -547,6 +547,15 @@ algorithm // get here through e.g. the interactive API. In that case just ignore them. case SCode.OVERLOAD() then node; + // A partial derivative of a function, function df = der(f, x). + // Treat it as a short class definition here, + case SCode.PDER() + guard Flags.getConfigBool(Flags.NEW_BACKEND) + then expandClassDerived(def, + SCode.ClassDef.DERIVED(Absyn.TypeSpec.TPATH(cdef.functionPath, NONE()), + SCode.NOMOD(), SCode.defaultVarAttr), + node, info); + else algorithm Error.assertion(false, getInstanceName() + " got unknown class:\n" + SCodeDump.unparseElementStr(def), sourceInfo()); diff --git a/OMCompiler/Compiler/NFFrontEnd/NFInstNode.mo b/OMCompiler/Compiler/NFFrontEnd/NFInstNode.mo index c739afbe3a3..e78cf76096d 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFInstNode.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFInstNode.mo @@ -526,6 +526,21 @@ uniontype InstNode end match; end name; + function isNamed + input InstNode node; + input String name; + output Boolean res; + algorithm + res := match node + case CLASS_NODE() then node.name == name; + case COMPONENT_NODE() then node.name == name; + case INNER_OUTER_NODE() then isNamed(node.innerNode, name); + case VAR_NODE() then node.name == name; + case NAME_NODE() then node.name == name; + else false; + end match; + end isNamed; + function className input InstNode node; output String name; diff --git a/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo b/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo index 48a15d05b2c..d7f988661a4 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFRecord.mo @@ -163,7 +163,7 @@ algorithm attr := DAE.FUNCTION_ATTRIBUTES_DEFAULT; status := Pointer.create(FunctionStatus.INITIAL); InstNode.cacheAddFunc(node, Function.FUNCTION(path, ctor_node, inputs, - {out_rec}, locals, {}, Type.UNKNOWN(), attr, {}, listArray({}), status, Pointer.create(0)), false); + {out_rec}, locals, {}, Type.UNKNOWN(), attr, {}, {}, listArray({}), status, Pointer.create(0)), false); end instDefaultConstructor; function checkLocalFieldOrder diff --git a/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo b/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo index 3a781ec4abf..53a4fd191a4 100644 --- a/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo +++ b/OMCompiler/Compiler/NFFrontEnd/NFTyping.mo @@ -130,6 +130,7 @@ end typeClass; function typeComponents input InstNode cls; input InstContext.Type context; + input Boolean preserveDerived = false; protected Class c = InstNode.getClass(cls), c2; ClassTree cls_tree; @@ -158,7 +159,8 @@ algorithm // For derived types with dimensions we keep them as they are, because we // need to preserve the dimensions. - case Class.TYPED_DERIVED(ty = Type.ARRAY()) + case Class.TYPED_DERIVED() + guard preserveDerived or Type.isArray(c.ty) algorithm typeComponents(c.baseClass, context); then diff --git a/OMCompiler/Compiler/Template/DAEDumpTV.mo b/OMCompiler/Compiler/Template/DAEDumpTV.mo index 22dd1b69763..d4bc0b6eb7b 100644 --- a/OMCompiler/Compiler/Template/DAEDumpTV.mo +++ b/OMCompiler/Compiler/Template/DAEDumpTV.mo @@ -998,6 +998,11 @@ package DAE ComponentRef inputParam "The input parameter the inverse is for"; Exp inverseCall "The inverse function call"; end FUNCTION_INVERSE; + + record FUNCTION_PARTIAL_DERIVATIVE + Absyn.Path derivedFunction; + list derivedVars; + end FUNCTION_PARTIAL_DERIVATIVE; end FunctionDefinition; uniontype derivativeCond "Different conditions on derivatives" diff --git a/OMCompiler/Compiler/Template/DAEDumpTpl.tpl b/OMCompiler/Compiler/Template/DAEDumpTpl.tpl index 73f3876242b..45fd1c0a2fa 100644 --- a/OMCompiler/Compiler/Template/DAEDumpTpl.tpl +++ b/OMCompiler/Compiler/Template/DAEDumpTpl.tpl @@ -67,6 +67,14 @@ end dumpFunctions; template dumpFunction(DAE.Function function) ::= match function + case FUNCTION(functions = {FUNCTION_PARTIAL_DERIVATIVE(__)}) then + let fn_name = AbsynDumpTpl.dumpPathNoQual(path) + let cmt_str = dumpCommentOpt(comment) + let ann_str = dumpClassAnnotation(comment) + let impure_str = if isImpure then 'impure ' + << + <%impure_str%>function <%fn_name%> = <%dumpFunctionDefinitions(functions)%><%cmt_str%><%if ann_str then " "%><%ann_str%>; + >> case FUNCTION(__) then let cmt_str = dumpCommentOpt(comment) let ann_str = dumpClassAnnotation(comment) @@ -111,6 +119,11 @@ match functions >> case FUNCTION_DER_MAPPER(__) then '' case FUNCTION_INVERSE(__) then '' + case FUNCTION_PARTIAL_DERIVATIVE(__) then + let vars = (derivedVars |> var => var ;separator=", ") + << + der(<%AbsynDumpTpl.dumpPathNoQual(derivedFunction)%>, <%vars%>) + >> end dumpFunctionDefinition; template dumpExternalDecl(ExternalDecl externalDecl) diff --git a/OMCompiler/Compiler/Util/Error.mo b/OMCompiler/Compiler/Util/Error.mo index dc7068f7458..16c35e29049 100644 --- a/OMCompiler/Compiler/Util/Error.mo +++ b/OMCompiler/Compiler/Util/Error.mo @@ -881,6 +881,10 @@ public constant ErrorTypes.Message NF_PDE_NOT_IMPLEMENTED = ErrorTypes.MESSAGE(4 Gettext.gettext("PDEModelica is not yet supported by the new front-end, using the old front-end instead.")); public constant ErrorTypes.Message NON_CONSTANT_IN_ENCLOSING_SCOPE = ErrorTypes.MESSAGE(403, ErrorTypes.TRANSLATION(), ErrorTypes.ERROR(), Gettext.gettext("Component ‘%s‘ was found in an enclosing scope but is not a constant.")); +public constant ErrorTypes.Message PARTIAL_DERIVATIVE_INPUT_NOT_FOUND = ErrorTypes.MESSAGE(404, ErrorTypes.TRANSLATION(), ErrorTypes.ERROR(), + Gettext.gettext("‘%s‘ in partial derivative of ‘%s‘ does not name an input parameter of the function.")); +public constant ErrorTypes.Message PARTIAL_DERIVATIVE_INPUT_INVALID_TYPE = ErrorTypes.MESSAGE(405, ErrorTypes.TRANSLATION(), ErrorTypes.ERROR(), + Gettext.gettext("‘%s‘ in partial derivative of ‘%s‘ is not a scalar Real input parameter of the function.")); public constant ErrorTypes.Message INITIALIZATION_NOT_FULLY_SPECIFIED = ErrorTypes.MESSAGE(496, ErrorTypes.TRANSLATION(), ErrorTypes.WARNING(), Gettext.gettext("The initial conditions are not fully specified. %s.")); diff --git a/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative1.mo b/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative1.mo new file mode 100644 index 00000000000..51a0c909206 --- /dev/null +++ b/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative1.mo @@ -0,0 +1,24 @@ +// name: FunctionPartialDerivative1 +// keywords: +// status: correct +// cflags: -d=newInst, --newBackend +// + +model FunctionPartialDerivative1 + function f + input Real x; + output Real y = x^2; + end f; + + function df = der(f, x); + + Real y = df(0); +end FunctionPartialDerivative1; + +// Result: +// function FunctionPartialDerivative1.df = der(FunctionPartialDerivative1.f, x); +// +// class FunctionPartialDerivative1 +// Real y = FunctionPartialDerivative1.df(0.0); +// end FunctionPartialDerivative1; +// endResult diff --git a/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative2.mo b/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative2.mo new file mode 100644 index 00000000000..3a5dd0893a0 --- /dev/null +++ b/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative2.mo @@ -0,0 +1,26 @@ +// name: FunctionPartialDerivative2 +// keywords: +// status: incorrect +// cflags: -d=newInst, --newBackend +// + +model FunctionPartialDerivative2 + function f + input Real x; + output Real y = x^2; + end f; + + function df = der(f, y); + + Real y = df(0); +end FunctionPartialDerivative2; + +// Result: +// Error processing file: FunctionPartialDerivative2.mo +// [flattening/modelica/scodeinst/FunctionPartialDerivative2.mo:15:3-15:17:writable] Error: ‘y‘ in partial derivative of ‘FunctionPartialDerivative2.f‘ does not name an input parameter of the function. +// +// # Error encountered! Exiting... +// # Please check the error message and the flags. +// +// Execution failed! +// endResult diff --git a/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative3.mo b/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative3.mo new file mode 100644 index 00000000000..b91068e2195 --- /dev/null +++ b/testsuite/flattening/modelica/scodeinst/FunctionPartialDerivative3.mo @@ -0,0 +1,26 @@ +// name: FunctionPartialDerivative3 +// keywords: +// status: incorrect +// cflags: -d=newInst, --newBackend +// + +model FunctionPartialDerivative3 + function f + input Integer x; + output Real y = x^2; + end f; + + function df = der(f, x); + + Real y = df(0); +end FunctionPartialDerivative3; + +// Result: +// Error processing file: FunctionPartialDerivative3.mo +// [flattening/modelica/scodeinst/FunctionPartialDerivative3.mo:13:3-13:26:writable] Error: ‘x‘ in partial derivative of ‘FunctionPartialDerivative3.f‘ is not a scalar Real input parameter of the function. +// +// # Error encountered! Exiting... +// # Please check the error message and the flags. +// +// Execution failed! +// endResult diff --git a/testsuite/flattening/modelica/scodeinst/Makefile b/testsuite/flattening/modelica/scodeinst/Makefile index 637f87d865e..3b7a1fd2fca 100644 --- a/testsuite/flattening/modelica/scodeinst/Makefile +++ b/testsuite/flattening/modelica/scodeinst/Makefile @@ -662,6 +662,9 @@ FunctionMultiOutput4.mo \ FunctionMultiOutput5.mo \ FunctionNoOutput1.mo \ FunctionNonInputOutputParameter.mo \ +FunctionPartialDerivative1.mo \ +FunctionPartialDerivative2.mo \ +FunctionPartialDerivative3.mo \ FunctionRecordArg1.mo \ FunctionRecordArg2.mo \ FunctionRecordArg3.mo \