Skip to content

Commit da7fd93

Browse files
authored
add support for fmi2GetDirectionalDerivative (#1109)
1 parent 8f5daff commit da7fd93

27 files changed

+2025
-0
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#CAPTION#
2+
getDirectionalDerivative
3+
------------------------
4+
This function computes the directional derivatives of an FMU.
5+
#END#
6+
7+
#LUA#
8+
.. code-block:: lua
9+
10+
value, status = oms_getDirectionalDerivative(cref)
11+
12+
#END#
13+
14+
#PYTHON#
15+
.. code-block:: python
16+
17+
value, status = oms.getDirectionalDerivative(cref)
18+
19+
#END#
20+
21+
#CAPI#
22+
.. code-block:: c
23+
24+
oms_status_enu_t oms_getDirectionalDerivative(const char* cref, double* value);
25+
26+
#END#
27+
28+
#END#
29+
30+
#DESCRIPTION#
31+
#END#

src/OMSimulatorLib/Component.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ namespace oms
8383
virtual oms_status_enu_t getInteger(const ComRef& cref, int& value) { return logError_NotImplemented; }
8484
virtual oms_status_enu_t getReal(const ComRef& cref, double& value) { return logError_NotImplemented; }
8585
virtual oms_status_enu_t getRealOutputDerivative(const ComRef& cref, SignalDerivative& der) { return logError_NotImplemented; }
86+
virtual oms_status_enu_t getDirectionalDerivative(const ComRef& cref, double& value) { return logError_NotImplemented; }
8687
virtual oms_status_enu_t restoreState() { return logError_NotImplemented; }
8788
virtual oms_status_enu_t saveState() { return logError_NotImplemented; }
8889
virtual oms_status_enu_t setBoolean(const ComRef& cref, bool value) { return logError_NotImplemented; }

src/OMSimulatorLib/ComponentFMUCS.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1146,6 +1146,110 @@ oms_status_enu_t oms::ComponentFMUCS::getReal(const ComRef& cref, double& value)
11461146
return getReal(vr, value);
11471147
}
11481148

1149+
1150+
oms_status_enu_t oms::ComponentFMUCS::getDirectionalDerivative(const ComRef& cref, double& value)
1151+
{
1152+
if (!getModel().validState(oms_modelState_instantiated|oms_modelState_initialization|oms_modelState_simulation))
1153+
return logError_ModelInWrongState(getModel().getCref());
1154+
1155+
if (!getFMUInfo()->getProvidesDirectionalDerivative())
1156+
return logError("It is not possible to compute directionalDerivative for signal \"" + std::string(getFullCref() + cref) + "\" as providesDirectionalDerivative is false or not provieded in modelDescription.xml");
1157+
1158+
int j = -1;
1159+
for (size_t i = 0; i < allVariables.size(); i++)
1160+
{
1161+
if (allVariables[i].getCref() == cref && allVariables[i].isTypeReal())
1162+
{
1163+
j = i;
1164+
break;
1165+
}
1166+
}
1167+
1168+
if (!fmu || j < 0)
1169+
return logError_UnknownSignal(getFullCref() + cref);
1170+
1171+
if (oms_modelState_instantiated == getModel().getModelState())
1172+
{
1173+
if (getFMUInfo()->getGenerationTool().substr(0, 12) == "OpenModelica")
1174+
logWarning("It is not possible to get partial derivatives of OpenModelica generated fmus during initialization mode, getting directional derivative after intialization is possible");
1175+
1176+
// check index exist in ModelStructure inititalUnknowns
1177+
auto index = values.modelStructureInitialUnknowns.find(j+1);
1178+
if (index == values.modelStructureInitialUnknowns.end())
1179+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an <InitialUnknowns> index in <ModelStructure>");
1180+
1181+
//get dependencylist from <InitialUnknowns> in <ModelStructure>
1182+
std::vector<int> dependencyList = values.modelStructureInitialUnknowns[j+1];
1183+
getDirectionalDerivativeHeper(j, dependencyList, value);
1184+
}
1185+
1186+
if (oms_modelState_simulation == getModel().getModelState())
1187+
{
1188+
if (!allVariables[j].isOutput() && !allVariables[j].isState() && !allVariables[j].isDer())
1189+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an output or state or derivates after initalization");
1190+
1191+
// <Outputs>
1192+
if (allVariables[j].isOutput())
1193+
{
1194+
// check index exist in ModelStructure inititalUnknowns
1195+
auto index = values.modelStructureOutputs.find(j + 1);
1196+
if (index == values.modelStructureOutputs.end())
1197+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an <Outputs> index in <ModelStructure>");
1198+
1199+
// get dependencylist from <Outputs> in <ModelStructure>
1200+
std::vector<int> dependencyList = values.modelStructureOutputs[j + 1];
1201+
getDirectionalDerivativeHeper(j, dependencyList, value);
1202+
}
1203+
1204+
// <Derivatives>
1205+
if (allVariables[j].isState() || allVariables[j].isDer())
1206+
{
1207+
// check index exist in ModelStructure inititalUnknowns
1208+
auto index = values.modelStructureDerivatives.find(j + 1);
1209+
if (index == values.modelStructureDerivatives.end())
1210+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an <Derivatives> index in <ModelStructure>");
1211+
1212+
// get dependencylist from <Derivatives> in <ModelStructure>
1213+
std::vector<int> dependencyList = values.modelStructureDerivatives[j + 1];
1214+
getDirectionalDerivativeHeper(j, dependencyList, value);
1215+
}
1216+
}
1217+
1218+
// fmi2_value_reference_t vr_unknown[1] = {5};
1219+
// fmi2_value_reference_t vr_known[4] = {0, 2, 3, 4};
1220+
// fmi2_real_t dvknown[4] = {1.0, 1.0, 1.0, 1.0};
1221+
// fmi2_real_t val;
1222+
// std::cout << "Get directional derivative_static_1: " << val << std::endl;
1223+
// fmi2_import_get_directional_derivative(fmu, vr_unknown, 1, vr_known, 4, dvknown, &val);
1224+
// std::cout << "\nGet directional derivative_static_2: " << val << std::endl;
1225+
1226+
return oms_status_ok;
1227+
}
1228+
1229+
oms_status_enu_t oms::ComponentFMUCS::getDirectionalDerivativeHeper(const int &index, const std::vector<int> &dependencyList, double &value)
1230+
{
1231+
fmi2_value_reference_t vr_unknown = allVariables[index].getValueReference();
1232+
1233+
fmi2_value_reference_t *vr_known = 0;
1234+
vr_known = (fmi2_value_reference_t *)calloc(dependencyList.size(), sizeof(fmi2_value_reference_t *));
1235+
1236+
fmi2_real_t *dvknown = 0;
1237+
dvknown = (fmi2_real_t *)calloc(dependencyList.size(), sizeof(fmi2_real_t *));
1238+
1239+
for (int i = 0; i < dependencyList.size(); i++)
1240+
{
1241+
vr_known[i] = allVariables[dependencyList[i] - 1].getValueReference();
1242+
dvknown[i] = 1.0;
1243+
}
1244+
1245+
fmi2_import_get_directional_derivative(fmu, &vr_unknown, 1, vr_known, dependencyList.size(), dvknown, &value);
1246+
1247+
free(vr_known);
1248+
free(dvknown);
1249+
1250+
return oms_status_ok;
1251+
}
1252+
11491253
oms_status_enu_t oms::ComponentFMUCS::getRealOutputDerivative(const ComRef& cref, SignalDerivative& der)
11501254
{
11511255
CallClock callClock(clock);

src/OMSimulatorLib/ComponentFMUCS.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ namespace oms
8686
oms_status_enu_t setInteger(const ComRef& cref, int value);
8787
oms_status_enu_t setReal(const ComRef& cref, double value);
8888

89+
oms_status_enu_t getDirectionalDerivative(const ComRef& cref, double& value);
90+
oms_status_enu_t getDirectionalDerivativeHeper(const int& index, const std::vector<int>& dependencyList, double& value);
91+
8992
oms_status_enu_t deleteStartValue(const ComRef& cref);
9093

9194
oms_status_enu_t setFmuTime(double time) {this->time = time; return oms_status_ok;}

src/OMSimulatorLib/ComponentFMUME.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,102 @@ oms_status_enu_t oms::ComponentFMUME::getReal(const ComRef& cref, double& value)
11411141
return getReal(vr, value);
11421142
}
11431143

1144+
oms_status_enu_t oms::ComponentFMUME::getDirectionalDerivative(const ComRef &cref, double &value)
1145+
{
1146+
// TODO implement the getDirectionalDerivative table
1147+
if (!getModel().validState(oms_modelState_instantiated | oms_modelState_initialization | oms_modelState_simulation))
1148+
return logError_ModelInWrongState(getModel().getCref());
1149+
1150+
if (!getFMUInfo()->getProvidesDirectionalDerivative())
1151+
return logError("It is not possible to compute directionalDerivative for signal \"" + std::string(getFullCref() + cref) + "\" as providesDirectionalDerivative is false or not provieded in modelDescription.xml");
1152+
1153+
int j = -1;
1154+
for (size_t i = 0; i < allVariables.size(); i++)
1155+
{
1156+
if (allVariables[i].getCref() == cref && allVariables[i].isTypeReal())
1157+
{
1158+
j = i;
1159+
break;
1160+
}
1161+
}
1162+
1163+
if (!fmu || j < 0)
1164+
return logError_UnknownSignal(getFullCref() + cref);
1165+
1166+
if (oms_modelState_instantiated == getModel().getModelState())
1167+
{
1168+
if (getFMUInfo()->getGenerationTool().substr(0, 12) == "OpenModelica")
1169+
logWarning("It is not possible to get partial derivatives of OpenModelica generated fmus during initialization mode, getting directional derivative after intialization is possible");
1170+
1171+
// check index exist in ModelStructure inititalUnknowns
1172+
auto index = values.modelStructureInitialUnknowns.find(j + 1);
1173+
if (index == values.modelStructureInitialUnknowns.end())
1174+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an <InitialUnknowns> index in <ModelStructure>");
1175+
1176+
// get dependencylist from <InitialUnknowns> in <ModelStructure>
1177+
std::vector<int> dependencyList = values.modelStructureInitialUnknowns[j + 1];
1178+
getDirectionalDerivativeHeper(j, dependencyList, value);
1179+
}
1180+
1181+
if (oms_modelState_simulation == getModel().getModelState())
1182+
{
1183+
if (!allVariables[j].isOutput() && !allVariables[j].isState() && !allVariables[j].isDer())
1184+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an output or state or derivates after initalization");
1185+
1186+
// <Outputs>
1187+
if (allVariables[j].isOutput())
1188+
{
1189+
// check index exist in ModelStructure inititalUnknowns
1190+
auto index = values.modelStructureOutputs.find(j + 1);
1191+
if (index == values.modelStructureOutputs.end())
1192+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an <Outputs> index in <ModelStructure>");
1193+
1194+
// get dependencylist from <Outputs> in <ModelStructure>
1195+
std::vector<int> dependencyList = values.modelStructureOutputs[j + 1];
1196+
getDirectionalDerivativeHeper(j, dependencyList, value);
1197+
}
1198+
1199+
// <Derivatives>
1200+
if (allVariables[j].isState() || allVariables[j].isDer())
1201+
{
1202+
// check index exist in ModelStructure inititalUnknowns
1203+
auto index = values.modelStructureDerivatives.find(j + 1);
1204+
if (index == values.modelStructureDerivatives.end())
1205+
return logError("Signal \"" + std::string(getFullCref() + cref) + "\" could not be resolved to an <Derivatives> index in <ModelStructure>");
1206+
1207+
// get dependencylist from <Derivatives> in <ModelStructure>
1208+
std::vector<int> dependencyList = values.modelStructureDerivatives[j + 1];
1209+
getDirectionalDerivativeHeper(j, dependencyList, value);
1210+
}
1211+
}
1212+
1213+
return oms_status_ok;
1214+
}
1215+
1216+
oms_status_enu_t oms::ComponentFMUME::getDirectionalDerivativeHeper(const int &index, const std::vector<int> &dependencyList, double &value)
1217+
{
1218+
fmi2_value_reference_t vr_unknown = allVariables[index].getValueReference();
1219+
1220+
fmi2_value_reference_t *vr_known = 0;
1221+
vr_known = (fmi2_value_reference_t *)calloc(dependencyList.size(), sizeof(fmi2_value_reference_t *));
1222+
1223+
fmi2_real_t *dvknown = 0;
1224+
dvknown = (fmi2_real_t *)calloc(dependencyList.size(), sizeof(fmi2_real_t *));
1225+
1226+
for (int i = 0; i < dependencyList.size(); i++)
1227+
{
1228+
vr_known[i] = allVariables[dependencyList[i] - 1].getValueReference();
1229+
dvknown[i] = 1.0;
1230+
}
1231+
1232+
fmi2_import_get_directional_derivative(fmu, &vr_unknown, 1, vr_known, dependencyList.size(), dvknown, &value);
1233+
1234+
free(vr_known);
1235+
free(dvknown);
1236+
1237+
return oms_status_ok;
1238+
}
1239+
11441240
oms_status_enu_t oms::ComponentFMUME::setBoolean(const ComRef& cref, bool value)
11451241
{
11461242
CallClock callClock(clock);

src/OMSimulatorLib/ComponentFMUME.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ namespace oms
8181
oms_status_enu_t setInteger(const ComRef& cref, int value);
8282
oms_status_enu_t setReal(const ComRef& cref, double value);
8383

84+
oms_status_enu_t getDirectionalDerivative(const ComRef& cref, double& value);
85+
oms_status_enu_t getDirectionalDerivativeHeper(const int& index, const std::vector<int>& dependencyList, double& value);
86+
8487
oms_status_enu_t deleteStartValue(const ComRef& cref);
8588

8689
oms_status_enu_t registerSignalsForResultFile(ResultWriter& resultFile);

src/OMSimulatorLib/FMUInfo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ namespace oms
5656
bool getCanInterpolateInputs() const {return canInterpolateInputs;}
5757
bool getCanGetAndSetFMUstate() const {return canGetAndSetFMUstate;}
5858
unsigned int getMaxOutputDerivativeOrder() const {return maxOutputDerivativeOrder;}
59+
bool getProvidesDirectionalDerivative() const {return providesDirectionalDerivative;}
60+
std::string getGenerationTool() const {return std::string(generationTool);}
5961

6062
private:
6163
// methods to copy the object

src/OMSimulatorLib/OMSimulator.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,23 @@ oms_status_enu_t oms_getReal(const char* cref, double* value)
12981298
return system->getReal(tail, *value);
12991299
}
13001300

1301+
oms_status_enu_t oms_getDirectionalDerivative(const char* cref, double* value)
1302+
{
1303+
oms::ComRef tail(cref);
1304+
oms::ComRef front = tail.pop_front();
1305+
1306+
oms::Model* model = oms::Scope::GetInstance().getModel(front);
1307+
if (!model)
1308+
return logError_ModelNotInScope(front);
1309+
1310+
front = tail.pop_front();
1311+
oms::System* system = model->getSystem(front);
1312+
if (!system)
1313+
return logError_SystemNotInModel(model->getCref(), front);
1314+
1315+
return system->getDirectionalDerivative(tail, *value);
1316+
}
1317+
13011318
oms_status_enu_t oms_getResultFile(const char* cref_, char** filename, int* bufferSize)
13021319
{
13031320
oms::ComRef cref(cref_);

src/OMSimulatorLib/OMSimulator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ OMSAPI oms_status_enu_t OMSCALL oms_getBus(const char* cref, oms_busconnector_t*
9595
OMSAPI oms_status_enu_t OMSCALL oms_getComponentType(const char* cref, oms_component_enu_t* type);
9696
OMSAPI oms_status_enu_t OMSCALL oms_getConnections(const char* cref, oms_connection_t*** connections);
9797
OMSAPI oms_status_enu_t OMSCALL oms_getConnector(const char* cref, oms_connector_t** connector);
98+
OMSAPI oms_status_enu_t OMSCALL oms_getDirectionalDerivative(const char* cref, double* value);
9899
OMSAPI oms_status_enu_t OMSCALL oms_getElement(const char* cref, oms_element_t** element);
99100
OMSAPI oms_status_enu_t OMSCALL oms_getElements(const char* cref, oms_element_t*** elements);
100101
OMSAPI oms_status_enu_t OMSCALL oms_getExternalModelInfo(const char* cref, const oms_external_tlm_model_info_t** externalModelInfo);

src/OMSimulatorLib/System.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,6 +2134,24 @@ oms_status_enu_t oms::System::getReal(const ComRef& cref, double& value)
21342134
return logError_UnknownSignal(getFullCref() + cref);
21352135
}
21362136

2137+
oms_status_enu_t oms::System::getDirectionalDerivative(const ComRef& cref, double& value)
2138+
{
2139+
if (!getModel().validState(oms_modelState_virgin|oms_modelState_instantiated|oms_modelState_initialization|oms_modelState_simulation))
2140+
return logError_ModelInWrongState(getModel().getCref());
2141+
2142+
oms::ComRef tail(cref);
2143+
oms::ComRef head = tail.pop_front();
2144+
2145+
auto subsystem = subsystems.find(head);
2146+
if (subsystem != subsystems.end())
2147+
return logError("getDirectionalDerivative is computed only for fmu signals");
2148+
2149+
auto component = components.find(head);
2150+
if (component != components.end())
2151+
return component->second->getDirectionalDerivative(tail, value);
2152+
2153+
return logError_UnknownSignal(getFullCref() + cref);
2154+
}
21372155

21382156
oms_status_enu_t oms::System::setBoolean(const ComRef& cref, bool value)
21392157
{

0 commit comments

Comments
 (0)