Skip to content

Commit

Permalink
FMI2 Cpp: introduce new getters and setters
Browse files Browse the repository at this point in the history
git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@25337 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
rfranke committed Mar 31, 2015
1 parent 80a062f commit 9160007
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 45 deletions.
183 changes: 170 additions & 13 deletions Compiler/Template/CodegenFMUCpp.tpl
Expand Up @@ -64,7 +64,8 @@ case SIMCODE(modelInfo=modelInfo as MODELINFO(__)) then
let &extraFuncs = buffer "" /*BUFD*/
let &extraFuncsDecl = buffer "" /*BUFD*/
let cpp = CodegenCpp.translateModel(simCode)
let()= textFile(fmuModelWrapperFile(simCode, extraFuncs, extraFuncsDecl, "",guid, FMUVersion), 'OMCpp<%fileNamePrefix%>FMU.cpp')
let()= textFile(fmuModelHeaderFile(simCode, extraFuncs, extraFuncsDecl, "",guid, FMUVersion), 'OMCpp<%fileNamePrefix%>FMU.h')
let()= textFile(fmuModelCppFile(simCode, extraFuncs, extraFuncsDecl, "",guid, FMUVersion), 'OMCpp<%fileNamePrefix%>FMU.cpp')
let()= textFile(fmuModelDescriptionFileCpp(simCode, extraFuncs, extraFuncsDecl, "", guid, FMUVersion, FMUType), 'modelDescription.xml')
let()= textFile(fmudeffile(simCode, FMUVersion), '<%fileNamePrefix%>.def')
let()= textFile(fmuMakefile(target,simCode, extraFuncs, extraFuncsDecl, "", FMUVersion), '<%fileNamePrefix%>_FMU.makefile')
Expand Down Expand Up @@ -135,17 +136,51 @@ case SIMCODE(modelInfo = MODELINFO(varInfo = vi as VARINFO(__), vars = SIMVARS(s
>>
end fmiModelDescriptionAttributesCpp;

template fmuModelWrapperFile(SimCode simCode,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, String guid, String FMUVersion)
"Generates code for ModelDescription file for FMU target."
template fmuModelHeaderFile(SimCode simCode,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, String guid, String FMUVersion)
"Generates declaration for FMU target."
::=
match simCode
case SIMCODE(modelInfo=MODELINFO(__)) then
let modelIdentifier = lastIdentOfPath(modelInfo.name)
//let modelIdentifier = System.stringReplace(dotPath(modelInfo.name), ".", "_")
<<
// declaration for Cpp FMU target
#include "OMCpp<%fileNamePrefix%>Extension.h"

class <%modelIdentifier%>FMU: public <%modelIdentifier%>Extension {
public:
// constructor
<%modelIdentifier%>FMU(IGlobalSettings* globalSettings,
boost::shared_ptr<IAlgLoopSolverFactory> nonLinSolverFactory,
boost::shared_ptr<ISimData> simData);
// getters for given value references
virtual void getReal(const unsigned int vr[], int nvr, double value[]);
virtual void getInteger(const unsigned int vr[], int nvr, int value[]);
virtual void getBoolean(const unsigned int vr[], int nvr, int value[]);
virtual void getString(const unsigned int vr[], int nvr, string value[]);
// setters for given value references
virtual void setReal(const unsigned int vr[], int nvr, const double value[]);
virtual void setInteger(const unsigned int vr[], int nvr, const int value[]);
virtual void setBoolean(const unsigned int vr[], int nvr, const int value[]);
virtual void setString(const unsigned int vr[], int nvr, const string value[]);
};
>>
end fmuModelHeaderFile;

template fmuModelCppFile(SimCode simCode,Text& extraFuncs,Text& extraFuncsDecl,Text extraFuncsNamespace, String guid, String FMUVersion)
"Generates code for FMU target."
::=
match simCode
case SIMCODE(modelInfo=MODELINFO(__)) then
let modelName = dotPath(modelInfo.name)
let modelShortName = lastIdentOfPath(modelInfo.name)
let modelIdentifier = System.stringReplace(modelName, ".", "_")
//let modelIdentifier = System.stringReplace(modelName, ".", "_")
let modelIdentifier = modelShortName
<<
// define model identifier and unique id
#define MODEL_IDENTIFIER <%modelShortName%>
#define MODEL_IDENTIFIER <%modelIdentifier%>
#define MODEL_GUID "{<%guid%>}"

#include <Core/Modelica.h>
Expand All @@ -158,7 +193,7 @@ case SIMCODE(modelInfo=MODELINFO(__)) then
#include <Solver/IAlgLoopSolver.h>
#include <System/IAlgLoopSolverFactory.h>
#include <SimController/ISimData.h>
#include "OMCpp<%fileNamePrefix%>Extension.h"
#include "OMCpp<%fileNamePrefix%>FMU.h"

<%ModelDefineData(modelInfo)%>
#define NUMBER_OF_EVENT_INDICATORS <%zerocrosslength(simCode, extraFuncs ,extraFuncsDecl, extraFuncsNamespace)%>
Expand All @@ -167,20 +202,30 @@ case SIMCODE(modelInfo=MODELINFO(__)) then
'#include "FMU2/FMU2Wrapper.cpp"'
else
'#include "FMU/FMUWrapper.cpp"'%>

<%if isFMIVersion20(FMUVersion) then
'#include "FMU2/FMU2Interface.cpp"'
else
'#include "FMU/FMULibInterface.cpp"'%>

#if 0
<%setDefaultStartValues(modelInfo)%>
<%setStartValues(modelInfo)%>
<%setExternalFunction(modelInfo)%>
#endif
// constructor
<%modelIdentifier%>FMU::<%modelIdentifier%>FMU(IGlobalSettings* globalSettings,
boost::shared_ptr<IAlgLoopSolverFactory> nonLinSolverFactory,
boost::shared_ptr<ISimData> simData):
PreVariables(<%getPreVarsCount(simCode)%>),
<%modelIdentifier%>(globalSettings, nonLinSolverFactory, simData),
<%modelIdentifier%>Extension(globalSettings, nonLinSolverFactory, simData) {
}

// getters
<%accessFunctions(simCode, "get", modelIdentifier, modelInfo)%>
// setters
<%accessFunctions(simCode, "set", modelIdentifier, modelInfo)%>
>>
end fmuModelWrapperFile;
// TODO:
// <%setDefaultStartValues(modelInfo)%>
// <%setStartValues(modelInfo)%>
// <%setExternalFunction(modelInfo)%>
end fmuModelCppFile;

template ModelDefineData(ModelInfo modelInfo)
"Generates global data in simulation file."
Expand Down Expand Up @@ -371,6 +416,118 @@ template setExternalFunctionSwitch(Function fn)
>>
end setExternalFunctionSwitch;

template accessFunctions(SimCode simCode, String direction, String modelIdentifier, ModelInfo modelInfo)
"Generates getters and setters for Real, Integer, Boolean, and String."
::=
match modelInfo
case MODELINFO(vars=SIMVARS(__)) then
<<
<%accessRealFunction(simCode, direction, modelIdentifier, modelInfo)%>
<%accessVarsFunction(simCode, direction, modelIdentifier, "Integer", "int", vars.intAlgVars, vars.intParamVars, vars.intAliasVars)%>
<%accessVarsFunction(simCode, direction, modelIdentifier, "Boolean", "int", vars.boolAlgVars, vars.boolParamVars, vars.boolAliasVars)%>
<%accessVarsFunction(simCode, direction, modelIdentifier, "String", "string", vars.stringAlgVars, vars.stringParamVars, vars.stringAliasVars)%>
>>
end accessFunctions;

template accessRealFunction(SimCode simCode, String direction, String modelIdentifier, ModelInfo modelInfo)
"Generates getReal and setReal functions."
::=
match modelInfo
case MODELINFO(vars=SIMVARS(__), varInfo=VARINFO(numStateVars=numStateVars, numAlgVars=numAlgVars, numDiscreteReal=numDiscreteReal, numParams=numParams)) then
let qualifier = if stringEq(direction, "set") then "const"
let statesOffset = intMul(2, stringInt(numFMUStateVars(vars.stateVars)))
<<
void <%modelIdentifier%>FMU::<%direction%>Real(const unsigned int vr[], int nvr, <%qualifier%> double value[]) {
for (int i = 0; i < nvr; i++)
switch (vr[i]) {
<%vars.stateVars |> var => accessVecVar(direction, var, 0, "__z"); separator="\n"%>
<%vars.derivativeVars |> var => accessVecVar(direction, var, numStateVars, "__zDot"); separator="\n"%>
<%accessVars(simCode, direction, vars.algVars, stringInt(statesOffset))%>
<%accessVars(simCode, direction, vars.discreteAlgVars, intAdd(stringInt(statesOffset), numAlgVars))%>
<%accessVars(simCode, direction, vars.paramVars, intAdd(intAdd(stringInt(statesOffset), numAlgVars), numDiscreteReal))%>
<%accessVars(simCode, direction, vars.aliasVars, intAdd(intAdd(intAdd(stringInt(statesOffset), numAlgVars), numDiscreteReal), numParams))%>
default:
std::ostringstream message;
message << "<%direction%>Real with wrong value reference " << vr[i];
throw std::invalid_argument(message.str());
}
}

>>
end accessRealFunction;

template numFMUStateVars(list<SimVar> stateVars)
"Return number of states without dummy state"
::=
if intGt(listLength(stateVars), 1) then listLength(stateVars) else (stateVars |> var => match var case SIMVAR(__) then if stringEq(crefStr(name), "$dummy") then 0 else 1)
end numFMUStateVars;

template accessVarsFunction(SimCode simCode, String direction, String modelIdentifier, String typeName, String typeImpl, list<SimVar> algVars, list<SimVar> paramVars, list<SimVar> aliasVars)
"Generates get<%typeName%> and set<%typeName%> functions."
::=
let qualifier = if stringEq(direction, "set") then "const"
<<
void <%modelIdentifier%>FMU::<%direction%><%typeName%>(const unsigned int vr[], int nvr, <%qualifier%> <%typeImpl%> value[]) {
for (int i = 0; i < nvr; i++)
switch (vr[i]) {
<%accessVars(simCode, direction, algVars, 0)%>
<%accessVars(simCode, direction, paramVars, listLength(algVars))%>
<%accessVars(simCode, direction, aliasVars, intAdd(listLength(algVars), listLength(paramVars)))%>
default:
std::ostringstream message;
message << "<%direction%><%typeName%> with wrong value reference " << vr[i];
throw std::invalid_argument(message.str());
}
}

>>
end accessVarsFunction;

template accessVars(SimCode simCode, String direction, list<SimVar> varsList, Integer offset)
"Generates list of case statements in get functions of Cpp file."
::=
<<
<%varsList |> var => accessVar(simCode, direction, var, offset); separator="\n"%>
>>
end accessVars;

template accessVar(SimCode simCode, String direction, SimVar simVar, Integer offset)
"Generates code for accessing variables in Cpp file for FMU target."
::=
match simVar
case SIMVAR(__) then
let description = if comment then '// <%comment%>'
let varname = cref1(name, simCode, "", "", "", contextOther, "", "", false)
if stringEq(direction, "get") then
<<
case <%intAdd(offset, index)%>: value[i] = <%varname%>; break; <%description%>
>>
else
<<
case <%intAdd(offset, index)%>: <%varname%> = value[i]; break; <%description%>
>>
end accessVar;

template accessVecVar(String direction, SimVar simVar, Integer offset, String vecName)
"Generates code for accessing vector variables, neglecting $dummy states."
::=
match simVar
case SIMVAR(__) then
let description = if comment then '// <%comment%>'
if stringEq(crefStr(name), "$dummy") then
<<>>
else if stringEq(crefStr(name), "der($dummy)") then
<<>>
else if stringEq(direction, "get") then
<<
case <%intAdd(offset, index)%>: value[i] = <%vecName%>[<%index%>]; break; <%description%>
>>
else
<<
case <%intAdd(offset, index)%>: <%vecName%>[<%index%>] = value[i]; break; <%description%>
>>
end accessVecVar;

template getPlatformString2(String platform, String fileNamePrefix, String dirExtra, String libsPos1, String libsPos2, String omhome)
"returns compilation commands for the platform. "
::=
Expand Down
54 changes: 26 additions & 28 deletions SimulationRuntime/cpp/Include/FMU2/FMU2Wrapper.cpp
Expand Up @@ -79,9 +79,7 @@ FMU2Wrapper::FMU2Wrapper(fmi2String instanceName, fmi2String GUID,
boost::shared_ptr<ISimData>(new SimData())));
_model->setInitial(true);
_model->initialize(); // set default start values
_tmp_real_buffer.resize(_model->getDimReal());
_tmp_int_buffer.resize(_model->getDimInteger());
_tmp_bool_buffer.resize(_model->getDimBoolean());
_string_buffer.resize(_model->getDimString());
}

FMU2Wrapper::~FMU2Wrapper()
Expand Down Expand Up @@ -189,40 +187,39 @@ fmi2Status FMU2Wrapper::completedIntegratorStep(fmi2Boolean noSetFMUStatePriorTo
fmi2Status FMU2Wrapper::setReal(const fmi2ValueReference vr[], size_t nvr,
const fmi2Real value[])
{
_model->getReal(&_tmp_real_buffer[0]);
for(size_t i = 0; i < nvr; ++i)
_tmp_real_buffer[vr[i]] = value[i];
_model->setReal(&_tmp_real_buffer[0]);
_model->setReal(vr, nvr, value);
_need_update = true;
return fmi2OK;
}

fmi2Status FMU2Wrapper::setInteger(const fmi2ValueReference vr[], size_t nvr,
const fmi2Integer value[])
{
_model->getInteger(&_tmp_int_buffer[0]);
for(size_t i = 0; i < nvr; ++i)
_tmp_int_buffer[vr[i]] = value[i];
_model->setInteger(&_tmp_int_buffer[0]);
_model->setInteger(vr, nvr, value);
_need_update = true;
return fmi2OK;
}

fmi2Status FMU2Wrapper::setBoolean(const fmi2ValueReference vr[], size_t nvr,
const fmi2Boolean value[])
{
_model->getBoolean((bool*) &_tmp_bool_buffer[0]);
for(size_t i = 0; i < nvr; ++i)
_tmp_bool_buffer[vr[i]] = value[i];
_model->setBoolean((bool*) &_tmp_bool_buffer[0]);
_model->setBoolean(vr, nvr, value);
_need_update = true;
return fmi2OK;
}

fmi2Status FMU2Wrapper::setString(const fmi2ValueReference vr[], size_t nvr,
const fmi2String value[])
{
// TODO implement strings
if (nvr > _string_buffer.size()) {
FMU2_LOG(this, fmi2Error, logStatusError,
"Attempt to set %d fmi2String; FMU only has %d",
nvr, _string_buffer.size());
return fmi2Error;
}
for (size_t i = 0; i < nvr; i++)
_string_buffer[i] = string(value[i]); // convert to string
_model->setString(vr, nvr, &_string_buffer[0]);
_need_update = true;
return fmi2OK;
}
Expand Down Expand Up @@ -264,43 +261,44 @@ fmi2Status FMU2Wrapper::getEventIndicators(fmi2Real eventIndicators[], size_t ni
return fmi2OK;
}

// Funktions for reading the values of variables that have a reference by the modelDescription.xml
// Functions for reading the values of variables
fmi2Status FMU2Wrapper::getReal(const fmi2ValueReference vr[], size_t nvr,
fmi2Real value[])
{
updateModel();
_model->getReal(&_tmp_real_buffer[0]);
for(size_t i = 0; i < nvr; ++i)
value[i] = _tmp_real_buffer[vr[i]];
_model->getReal(vr, nvr, value);
return fmi2OK;
}

fmi2Status FMU2Wrapper::getInteger(const fmi2ValueReference vr[], size_t nvr,
fmi2Integer value[])
{
updateModel();
_model->getInteger(&_tmp_int_buffer[0]);
for(size_t i = 0; i < nvr; ++i)
value[i] = _tmp_int_buffer[vr[i]];
_model->getInteger(vr, nvr, value);
return fmi2OK;
}

fmi2Status FMU2Wrapper::getBoolean(const fmi2ValueReference vr[], size_t nvr,
fmi2Boolean value[])
{
updateModel();
_model->getBoolean((bool*) &_tmp_bool_buffer[0]);
for(size_t i = 0; i < nvr; ++i)
value[i] = _tmp_bool_buffer[vr[i]];
_model->getBoolean(vr, nvr, value);
return fmi2OK;
}

fmi2Status FMU2Wrapper::getString(const fmi2ValueReference vr[], size_t nvr,
fmi2String value[])
{
if (nvr > _string_buffer.size()) {
FMU2_LOG(this, fmi2Error, logStatusError,
"Attempt to get %d fmi2String; FMU only has %d",
nvr, _string_buffer.size());
return fmi2Error;
}
updateModel();
// for(size_t i = 0; i < nvr; ++i)
//TODO _model->getString(vr[i], value[i]);
_model->getString(vr, nvr, &_string_buffer[0]);
for (size_t i = 0; i < nvr; i++)
value[i] = _string_buffer[i].c_str(); // convert to fmi2String
return fmi2OK;
}

Expand Down
6 changes: 2 additions & 4 deletions SimulationRuntime/cpp/Include/FMU2/FMU2Wrapper.h
Expand Up @@ -43,7 +43,7 @@
// build MODEL_CLASS from MODEL_IDENTIFIER
#define FMU2_PASTER(a, b) a ## b
#define FMU2_CONCAT(a, b) FMU2_PASTER(a, b)
#define MODEL_CLASS FMU2_CONCAT(MODEL_IDENTIFIER, Extension)
#define MODEL_CLASS FMU2_CONCAT(MODEL_IDENTIFIER, FMU)

// define logger as macro that passes through variadic args
#define FMU2_LOG(w, status, category, ...) \
Expand Down Expand Up @@ -130,9 +130,7 @@ class FMU2Wrapper
private:
FMU2GlobalSettings _global_settings;
boost::shared_ptr<MODEL_CLASS> _model;
std::vector<fmi2Real> _tmp_real_buffer;
std::vector<fmi2Integer> _tmp_int_buffer;
std::vector<fmi2Boolean> _tmp_bool_buffer;
std::vector<string> _string_buffer;
double _need_update;
void updateModel();

Expand Down

0 comments on commit 9160007

Please sign in to comment.