From 7a4ad0e6349ba6ef3f1c74323dc7fc5e73dda865 Mon Sep 17 00:00:00 2001 From: rfranke Date: Fri, 18 Jun 2021 10:55:31 +0200 Subject: [PATCH] Add support for pre of arrays to Cpp runtime (#7574) * Add support for pre of arrays to Cpp runtime DiscreteEvents/SimVars: - add pre of arrays Array: - add new WrapArray for array return value from pre FactoryConfig: - remove interface includes to avoid additional include of Array.h CodegenCppCommon: - move $PRE qualifier for lhs from contextCref to cref1 - make BaseArray function call arguments const * Distinguish lhs from rhs daeExpCref and add test This is needed for the appropriate treatment of ArraySlice/Const after the introduction of const qualifiers for BaseArray refs in d3085da56b999bee979cd0ad844b207715710ed3. --- .../Compiler/Template/CodegenCppCommonOld.tpl | 26 +-- .../Compiler/Template/CodegenCppOld.tpl | 4 +- .../cpp/Core/System/SimVars.cpp | 24 +++ .../cpp/Include/Core/Math/Array.h | 178 ++++++++++++++++++ .../cpp/Include/Core/System/DiscreteEvents.h | 4 + .../cpp/Include/Core/System/ISimVars.h | 21 ++- .../cpp/Include/Core/System/SimVars.h | 4 + .../SimCoreFactory/Policies/FactoryConfig.h | 28 --- testsuite/openmodelica/cppruntime/Makefile | 1 + .../cppruntime/distributionsTest.mos | 28 +++ 10 files changed, 267 insertions(+), 51 deletions(-) create mode 100644 testsuite/openmodelica/cppruntime/distributionsTest.mos diff --git a/OMCompiler/Compiler/Template/CodegenCppCommonOld.tpl b/OMCompiler/Compiler/Template/CodegenCppCommonOld.tpl index 82e88c3b6aa..68d2ba211c2 100644 --- a/OMCompiler/Compiler/Template/CodegenCppCommonOld.tpl +++ b/OMCompiler/Compiler/Template/CodegenCppCommonOld.tpl @@ -148,10 +148,6 @@ end subscriptStr; template contextCref(ComponentRef cr, Context context,SimCode simCode ,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, Text stateDerVectorName /*=__zDot*/, Boolean useFlatArrayNotation) "Generates code for a component reference depending on which context we're in." ::= -match cr -case CREF_QUAL(ident = "$PRE") then - '_discrete_events->pre(<%contextCref(componentRef,context,simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation)%>)' - else let &varDeclsCref = buffer "" /*BUFD*/ match context case FUNCTION_CONTEXT(__) then crefStr(cr) @@ -212,7 +208,10 @@ end crefToCStrWithIndex; template cref1(ComponentRef cr, SimCode simCode ,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, Context context, Text &varDecls, Text stateDerVectorName /*=__zDot*/, Boolean useFlatArrayNotation) ::= match cr - case CREF_IDENT(ident = "xloc") then '<%representationCref(cr, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, context, varDecls, stateDerVectorName, useFlatArrayNotation)%>' + case CREF_QUAL(ident = "$PRE") then + '_discrete_events->pre(<%cref1(componentRef, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, context, varDecls, stateDerVectorName, useFlatArrayNotation)%>)' + case CREF_IDENT(ident = "xloc") then + '<%representationCref(cr, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, context, varDecls, stateDerVectorName, useFlatArrayNotation)%>' case CREF_IDENT(ident = "time") then match context case ALGLOOP_CONTEXT(genInitialisation=false) @@ -350,7 +349,7 @@ template daeExpCrefRhs(Exp exp, Context context, Text &preExp, Text &varDecls, S // by daeExpRecordCrefRhs only in a simulation context, not in a function. case CREF(componentRef = cr, ty = t as T_COMPLEX(complexClassType = RECORD(path = _))) then match context case FUNCTION_CONTEXT(__) then - '<%daeExpCrefRhs2(exp, context, &preExp, &varDecls,simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation)%>' + '<%daeExpCref(false, exp, context, &preExp, &varDecls,simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation)%>' else daeExpRecordCrefRhs(t, cr, context, &preExp, &varDecls, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) case CREF(ty = T_FUNCTION_REFERENCE_FUNC(functionType=t)) then @@ -358,12 +357,12 @@ template daeExpCrefRhs(Exp exp, Context context, Text &preExp, Text &varDecls, S case CREF(componentRef = CREF_IDENT(ident=ident), ty = T_FUNCTION_REFERENCE_VAR(__)) then contextFunName(ident, context) else - daeExpCrefRhs2(exp, context, &preExp, &varDecls, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) + daeExpCref(false, exp, context, &preExp, &varDecls, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) end daeExpCrefRhs; -template daeExpCrefRhs2(Exp ecr, Context context, Text &preExp, Text &varDecls, SimCode simCode, Text& extraFuncs, - Text& extraFuncsDecl, Text extraFuncsNamespace, Text stateDerVectorName /*=__zDot*/, Boolean useFlatArrayNotation) +template daeExpCref(Boolean isLhs, Exp ecr, Context context, Text &preExp, Text &varDecls, SimCode simCode, Text& extraFuncs, + Text& extraFuncsDecl, Text extraFuncsNamespace, Text stateDerVectorName /*=__zDot*/, Boolean useFlatArrayNotation) "Generates code for a component reference." ::= match ecr @@ -391,13 +390,14 @@ case component as CREF(componentRef=cr, ty=ty) then else // The array subscript denotes a slice let arrName = contextArrayCref(cr, context) - let typeStr = expTypeShort(ty) + let arrTypeStr = if isLhs then 'ArraySlice' else 'ArraySliceConst' + let elTypeStr = expTypeShort(ty) let slice = daeExpCrefIndexSpec(crefSubs(cr), context, &preExp, &varDecls, simCode, &extraFuncs, &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) - let &preExp += 'ArraySlice<<%typeStr%>> <%slice%>_as(<%arrName%>, <%slice%>);<%\n%>' + let &preExp += '<%arrTypeStr%><<%elTypeStr%>> <%slice%>_as(<%arrName%>, <%slice%>);<%\n%>' '<%slice%>_as' -end daeExpCrefRhs2; +end daeExpCref; template daeExpCrefIndexSpec(list subs, Context context, @@ -745,7 +745,7 @@ template expTypeFlag(DAE.Type ty, Integer flag) case 8 then match ty - case T_ARRAY(dims=dims) then'BaseArray<<%expTypeShort(ty)%>>&' + case T_ARRAY(dims=dims) then 'const BaseArray<<%expTypeShort(ty)%>>&' else expTypeFlag(ty, 9) end match diff --git a/OMCompiler/Compiler/Template/CodegenCppOld.tpl b/OMCompiler/Compiler/Template/CodegenCppOld.tpl index cf218e1f101..ca6ac6ca150 100644 --- a/OMCompiler/Compiler/Template/CodegenCppOld.tpl +++ b/OMCompiler/Compiler/Template/CodegenCppOld.tpl @@ -11557,7 +11557,7 @@ template equationForLoop(SimEqSystem eq, Context context, Text &varDecls, SimCod let startExp = daeExp(startIt, context, preExp, varDecls, simCode, extraFuncs, extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, false) let endExp = daeExp(endIt, context, preExp, varDecls, simCode, extraFuncs, extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, false) let expPart = daeExp(exp, context, preExp, varDecls, simCode, extraFuncs, extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, false) - let crefPart = daeExp(crefExp(cref), context, preExp, varDecls, simCode, extraFuncs, extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, false) + let crefPart = daeExpCref(true, crefExp(cref), context, preExp, varDecls, simCode, extraFuncs, extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, false) << <%if not assignToStartValues then '<%startFixedExp%>'%> for (int <%iterExp%> = <%startExp%>; <%iterExp%> <= <%endExp%>; <%iterExp%>++) { @@ -13650,7 +13650,7 @@ match stmt case STMT_ASSIGN_ARR(exp=e, lhs=lhsexp as CREF(componentRef=cr), type_=t) then let &preExp = buffer "" /*BUFD*/ let expPart = daeExp(e, context, &preExp /*BUFC*/, &varDecls /*BUFD*/, simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) - let dest = daeExp(lhsexp, context, &preExp /*BUFC*/, &varDecls /*BUFD*/, simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) + let dest = daeExpCref(true, lhsexp, context, &preExp /*BUFC*/, &varDecls /*BUFD*/, simCode , &extraFuncs , &extraFuncsDecl, extraFuncsNamespace, stateDerVectorName, useFlatArrayNotation) << <%preExp%> <%dest%>.assign(<%expPart%>); diff --git a/OMCompiler/SimulationRuntime/cpp/Core/System/SimVars.cpp b/OMCompiler/SimulationRuntime/cpp/Core/System/SimVars.cpp index 13f0c18aa11..1f4f5b79133 100644 --- a/OMCompiler/SimulationRuntime/cpp/Core/System/SimVars.cpp +++ b/OMCompiler/SimulationRuntime/cpp/Core/System/SimVars.cpp @@ -492,6 +492,30 @@ std::string& SimVars::getPreVar(const std::string& var) return _pre_string_vars[i]; } +WrapArray SimVars::getPreArr(const BaseArray& arr) +{ + size_t i = arr.getData() - _real_vars; + return WrapArray(_pre_real_vars + i, arr.getNumElems()); +} + +WrapArray SimVars::getPreArr(const BaseArray& arr) +{ + size_t i = arr.getData() - _int_vars; + return WrapArray(_pre_int_vars + i, arr.getNumElems()); +} + +WrapArray SimVars::getPreArr(const BaseArray& arr) +{ + size_t i = arr.getData() - _bool_vars; + return WrapArray(_pre_bool_vars + i, arr.getNumElems()); +} + +WrapArray SimVars::getPreArr(const BaseArray& arr) +{ + size_t i = arr.getData() - _string_vars; + return WrapArray(_pre_string_vars + i, arr.getNumElems()); +} + /**\brief returns a pointer to a real simvar variable in simvar array * \param [in] i index of simvar in simvar array * \return pointer to simvar diff --git a/OMCompiler/SimulationRuntime/cpp/Include/Core/Math/Array.h b/OMCompiler/SimulationRuntime/cpp/Include/Core/Math/Array.h index 588841ff10d..5269ecccc9c 100644 --- a/OMCompiler/SimulationRuntime/cpp/Include/Core/Math/Array.h +++ b/OMCompiler/SimulationRuntime/cpp/Include/Core/Math/Array.h @@ -629,6 +629,184 @@ class RefArrayDim3 : public RefArray } }; +/** + * Wrap external data with nelems unknown at compile time into array, implements BaseArray interface methods + * @param T type of the array elements + */ +template +class WrapArray : public BaseArray +{ + public: + /** + * Constuctor for wrapper array storing a pointer + */ + WrapArray(T* data, size_t nelems) + :BaseArray(true, false) + { + _data = data; + _nelems = nelems; + } + + /** + * Constuctor for wrapper array that + * holds a pointer to otherarray's data + */ + WrapArray(const WrapArray& otherarray) + :BaseArray(true, false) + { + _data = otherarray._data; + _nelems = otherarray.getNumElems(); + } + + /** + * Default constuctor for wrapper array + */ + WrapArray() + :BaseArray(true, false) + { + _data = NULL; // no data assigned yet + _nelems = 0; + } + + virtual ~WrapArray() {} + + /** + * Index operator to read array element + * @param idx vector of indices + */ + virtual const T& operator()(const vector& idx) const + { + throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION, "Wrong WrapArray const operator() call"); + } + + /** + * Index operator to write array element + * @param idx vector of indices + */ + virtual T& operator()(const vector& idx) + { + throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION, "Wrong WrapArray operator() call"); + } + + /** + * Return sizes of dimensions + */ + virtual std::vector getDims() const + { + throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION, "Wrong WrapArray getDims call"); + } + + /** + * Return sizes of one dimension + */ + virtual int getDim(size_t dim) const + { + throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION, "Wrong WrapArray getDim call"); + } + + /** + * Returns number of dimensions + */ + virtual size_t getNumDims() const + { + throw ModelicaSimulationError(MODEL_ARRAY_FUNCTION, "Wrong WrapArray getNumDims call"); + } + + /** + * Resize array method + * @param dims vector with new dimension sizes + * wrapper array could not be resized + */ + virtual void resize(const std::vector& dims) + { + if (dims != this->getDims()) + throw std::runtime_error("Cannot resize wrapper array!"); + } + + /** + * Assigns data to array + * @param data new array data + * a.assign(data) + */ + virtual void assign(const T* data) + { + if (_nelems > 0) { + if (_data == NULL) + throw std::runtime_error("Cannot assign data to uninitialized WrapArray!"); + std::copy(data, data + _nelems, _data); + } + } + + /** + * Assigns array data to array + * @param b any array of type BaseArray + * a.assign(b) + */ + virtual void assign(const BaseArray& b) + { + if (_nelems > 0) { + if (_data == NULL) + throw std::runtime_error("Cannot assign to uninitialized WrapArray!"); + assert(b.getNumElems() == _nelems); + b.getDataCopy(_data, _nelems); + } + } + + /** + * Assigns value to each array element + * @param value new array value + * a.assign(value) + */ + virtual void assign(const T& value) + { + if (_nelems > 0) { + if (_data == NULL) + throw std::runtime_error("Cannot assign value to uninitialized WrapArray!"); + std::fill(_data, _data + _nelems, value); + } + } + + /** + * Access to data + */ + virtual T* getData() + { + return _data; + } + + /** + * Access to data (read-only) + */ + virtual const T* getData() const + { + return _data; + } + + /** + * Copies the array data of size n in the data array + * data has to be allocated before getDataCopy is called + */ + virtual void getDataCopy(T data[], size_t n) const + { + if (n > 0) + std::copy(_data, _data + n, data); + } + + /** + * Returns number of elements + */ + virtual size_t getNumElems() const + { + return _nelems; + } + + virtual void setDims(const std::vector& v) {} + + protected: + T *_data; // array data + size_t _nelems; // number of elements +}; + /** * Static array, implements BaseArray interface methods * @param T type of the array diff --git a/OMCompiler/SimulationRuntime/cpp/Include/Core/System/DiscreteEvents.h b/OMCompiler/SimulationRuntime/cpp/Include/Core/System/DiscreteEvents.h index 0c19e380ae4..104bc79a229 100644 --- a/OMCompiler/SimulationRuntime/cpp/Include/Core/System/DiscreteEvents.h +++ b/OMCompiler/SimulationRuntime/cpp/Include/Core/System/DiscreteEvents.h @@ -30,6 +30,10 @@ class BOOST_EXTENSION_EVENTHANDLING_DECL DiscreteEvents int& pre(const int& var); bool& pre(const bool& var); std::string& pre(const std::string& var); + template + WrapArray pre(const BaseArray& arr) { + return _sim_vars->getPreArr(arr); + } //Implementation of the Modelica edge operator bool edge(double& var); bool edge(int& var); diff --git a/OMCompiler/SimulationRuntime/cpp/Include/Core/System/ISimVars.h b/OMCompiler/SimulationRuntime/cpp/Include/Core/System/ISimVars.h index fe8502ab94d..a1de7c1aa9a 100644 --- a/OMCompiler/SimulationRuntime/cpp/Include/Core/System/ISimVars.h +++ b/OMCompiler/SimulationRuntime/cpp/Include/Core/System/ISimVars.h @@ -61,13 +61,18 @@ class ISimVars virtual bool& initBoolVar(size_t i)= 0; virtual string& initStringVar(size_t i)= 0; - /*Methods for pre- variables*/ - virtual void savePreVariables() = 0; - virtual void initPreVariables()= 0; - /*access methods for pre-variable*/ - virtual double& getPreVar(const double& var)=0; - virtual int& getPreVar(const int& var)=0; - virtual bool& getPreVar(const bool& var)=0; - virtual std::string& getPreVar(const std::string& var)=0; + /*Methods for pre- variables*/ + virtual void savePreVariables() = 0; + virtual void initPreVariables() = 0; + /*access methods for pre-variable*/ + virtual double& getPreVar(const double& var) = 0; + virtual int& getPreVar(const int& var) = 0; + virtual bool& getPreVar(const bool& var) = 0; + virtual std::string& getPreVar(const std::string& var) = 0; + /*access methods for pre-array*/ + virtual WrapArray getPreArr(const BaseArray& arr) = 0; + virtual WrapArray getPreArr(const BaseArray& arr) = 0; + virtual WrapArray getPreArr(const BaseArray& arr) = 0; + virtual WrapArray getPreArr(const BaseArray& arr) = 0; }; /** @} */ // end of coreSystem diff --git a/OMCompiler/SimulationRuntime/cpp/Include/Core/System/SimVars.h b/OMCompiler/SimulationRuntime/cpp/Include/Core/System/SimVars.h index fe9c33081c5..9114bef8a2d 100644 --- a/OMCompiler/SimulationRuntime/cpp/Include/Core/System/SimVars.h +++ b/OMCompiler/SimulationRuntime/cpp/Include/Core/System/SimVars.h @@ -112,6 +112,10 @@ class BOOST_EXTENSION_SIMVARS_DECL SimVars: public ISimVars virtual int& getPreVar(const int& var); virtual bool& getPreVar(const bool& var); virtual std::string& getPreVar(const std::string& var); + virtual WrapArray getPreArr(const BaseArray& arr); + virtual WrapArray getPreArr(const BaseArray& arr); + virtual WrapArray getPreArr(const BaseArray& arr); + virtual WrapArray getPreArr(const BaseArray& arr); virtual size_t getDimString() const; virtual size_t getDimBool() const; diff --git a/OMCompiler/SimulationRuntime/cpp/Include/SimCoreFactory/Policies/FactoryConfig.h b/OMCompiler/SimulationRuntime/cpp/Include/SimCoreFactory/Policies/FactoryConfig.h index 46a35e7bca3..032f9fba354 100644 --- a/OMCompiler/SimulationRuntime/cpp/Include/SimCoreFactory/Policies/FactoryConfig.h +++ b/OMCompiler/SimulationRuntime/cpp/Include/SimCoreFactory/Policies/FactoryConfig.h @@ -78,34 +78,6 @@ /*Defines*/ #define PATH string #include "LibrariesConfig.h" - /*interface includes*/ - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - #else #error "operating system not supported" diff --git a/testsuite/openmodelica/cppruntime/Makefile b/testsuite/openmodelica/cppruntime/Makefile index 46ad9febb45..1bfb3a07969 100644 --- a/testsuite/openmodelica/cppruntime/Makefile +++ b/testsuite/openmodelica/cppruntime/Makefile @@ -11,6 +11,7 @@ clockedEventTest.mos \ clockedSolverTest.mos \ clockedTypesTest.mos \ clockedTest.mos \ +distributionsTest.mos \ externalArrayInputTest.mos \ mathFunctionsTest.mos \ nameClashTest.mos \ diff --git a/testsuite/openmodelica/cppruntime/distributionsTest.mos b/testsuite/openmodelica/cppruntime/distributionsTest.mos new file mode 100644 index 00000000000..0ebc86ffb1c --- /dev/null +++ b/testsuite/openmodelica/cppruntime/distributionsTest.mos @@ -0,0 +1,28 @@ +// name: distribustionsTest +// keywords: pre array const +// status: correct +// teardown_command: rm -f *NoiseExamples* +// cflags: -d=newInst + +setCommandLineOptions("+simCodeTarget=Cpp"); + +loadModel(Modelica, {"3.2.3"}); getErrorString(); + +simulate(Modelica.Blocks.Examples.NoiseExamples.Distributions); +val(truncatedNormalNoise_y, 2.0); +val(uniformNoise_y, 2.0); +getErrorString(); + +// Result: +// true +// true +// "" +// record SimulationResult +// resultFile = "Modelica.Blocks.Examples.NoiseExamples.Distributions_res.mat", +// simulationOptions = "startTime = 0.0, stopTime = 2.0, numberOfIntervals = 500, tolerance = 1e-06, method = 'dassl', fileNamePrefix = 'Modelica.Blocks.Examples.NoiseExamples.Distributions', options = '', outputFormat = 'mat', variableFilter = '.*', cflags = '', simflags = ''", +// messages = "" +// end SimulationResult; +// 0.7428113041992174 +// 0.3976885904512169 +// "" +// endResult