diff --git a/runtime/sfmi_runtime.cpp b/runtime/sfmi_runtime.cpp new file mode 100644 index 0000000..7ff7db2 --- /dev/null +++ b/runtime/sfmi_runtime.cpp @@ -0,0 +1,87 @@ +#include "sfmi_runtime.h" +#include +using namespace std; +using namespace sfmi; + +model_data::model_data( + int num_reals, + int num_ints, + int num_strs, + int num_bools): + Time(0), + real_vars(new fmi2Real[num_reals]), + int_vars(new fmi2Integer[num_ints]), + bool_vars(new fmi2Boolean[num_bools]), + str_vars(new string[num_strs]) +{ +} + +void model_data::link(void* var, void(*func)(model_data*)) +{ + _input_info[var].push_back(func); +} + +void model_data::link(void(*func)(model_data*),void* var) +{ + _output_info[func].push_back(var); +} + +void model_data::modify(void* var) +{ + _modified_vars.insert(var); +} + +model_data::~model_data() +{ + delete [] real_vars; + delete [] int_vars; + delete [] bool_vars; + delete [] str_vars; +} + +void model_data::update() +{ + while (!(_modified_vars.empty())) + { + // Get the variable that was modified + set::iterator next_var = _modified_vars.begin(); + void* var = *next_var; + // Remove it from the list of modified variables + _modified_vars.erase(next_var); + // Get the list of equations that have this variable as input + map >::iterator map_iter = + _input_info.find(var); + // If there are any such equations, recalculate them + if (map_iter != _input_info.end()) + { + // Get the list of equations + list& eqns = (*map_iter).second; + // Calculate each one + list::iterator eqns_iter = eqns.begin(); + for (; eqns_iter != eqns.end(); eqns_iter++) + { + (*eqns_iter)(this); + // Get the variables that are modified by this eqn and put them into the modified list + map >::iterator map_iter_2 = + _output_info.find(*eqns_iter); + if (map_iter_2 != _output_info.end()) + { + list& vars = (*map_iter_2).second; + list::iterator var_iter = vars.begin(); + for (; var_iter != vars.end(); var_iter++) + _modified_vars.insert(*var_iter); + } + } + } + } +} + +double sfmi::DIVISION_SIM(double num, double den, const char* den_name, int eq) +{ + double result = num/den; + if (!isfinite(result)) + { + cerr << "DIVISION BY ZERO! " << den_name << " = 0 in Eqn. " << eq << endl; + } + return result; +} diff --git a/runtime/sfmi_runtime.h b/runtime/sfmi_runtime.h new file mode 100644 index 0000000..a8a7a52 --- /dev/null +++ b/runtime/sfmi_runtime.h @@ -0,0 +1,54 @@ +#ifndef __sfmi_runtime_h_ +#define __sfmi_runtime_h_ +#include +#include +#include +#include +#include +#include "fmi2TypesPlatform.h" + +namespace sfmi +{ + + class model_data + { + public: + // Allocate data arrays and change management structures + model_data( + int num_reals, + int num_ints, + int num_strs, + int num_bools); + + // Link an input variable to its function + void link(void* var, void(*func)(model_data*)); + // Link a function its output variable + void link(void(*func)(model_data*),void* var); + // Indicate that a variable has been modified by a call to SetXXX + void modify(void* var); + // Perform updates for all modified variables + void update(); + // Destroy data arrays and change management structures + ~model_data(); + + // Data arrays + fmi2Real Time; + fmi2Real* real_vars; + fmi2Integer* int_vars; + fmi2Boolean* bool_vars; + std::string* str_vars; + + private: + // Map from variable addresses to addresses of functions that have the variable for input + std::map > _input_info; + // Map from addresses of functions to variables they modify + std::map > _output_info; + // List of variables that have been modified + std::set _modified_vars; + }; + + double DIVISION_SIM(double,double,const char* divisor,int); + +}; + +#endif diff --git a/test/.Linsys_FMI.cpp.swp b/test/.Linsys_FMI.cpp.swp new file mode 100644 index 0000000..1dd7702 Binary files /dev/null and b/test/.Linsys_FMI.cpp.swp differ diff --git a/test/Influenza.mo b/test/Influenza.mo new file mode 100644 index 0000000..e3cbec9 --- /dev/null +++ b/test/Influenza.mo @@ -0,0 +1,28 @@ +model Influenza + // Parameters + parameter Real MortalityProb = 0.01; + parameter Real RecoveryTime = 3.0; + // In days + parameter Real MortalityTime = 1.0; + // In days + parameter Real TransmissionProb = 0.15; + parameter Real EncounterRate = 4; + // In days + // Start variables + Real Deceased(start = 0); + Real Recovered(start = 0); + Real Removed(start = 0); + Real Infectious(start = 0); + Real Susceptible(start = 499000); + Real Population; + Real R; +equation + Population = Recovered + Infectious + Susceptible; + R = (TransmissionProb * EncounterRate * Susceptible) / Population; + der(Removed) = (MortalityProb / MortalityTime + (1 - MortalityProb) / RecoveryTime) * Infectious; + der(Deceased) = MortalityProb * der(Removed); + der(Recovered) = (1 - MortalityProb) * der(Removed); + der(Susceptible) = -R * Infectious; + der(Infectious) = -der(Removed) + R * Infectious + (1+sin(4*time/365)); +end Influenza; + diff --git a/test/Linsys.fmu b/test/Linsys.fmu new file mode 100644 index 0000000..1c6bed1 Binary files /dev/null and b/test/Linsys.fmu differ diff --git a/test/Linsys.mo b/test/Linsys.mo new file mode 100644 index 0000000..d8cb72d --- /dev/null +++ b/test/Linsys.mo @@ -0,0 +1,9 @@ +model Linsys + parameter Real [2,2] A = { { -0.5, 0.0 }, { 0.0, -1.0 } }; + Real [2] x; +equation + der(x) = A*x; +initial equation + x[1] = 1.0; + x[2] = 2.0; +end Linsys; diff --git a/test/Test1.mo b/test/Test1.mo new file mode 100644 index 0000000..36c6ea1 --- /dev/null +++ b/test/Test1.mo @@ -0,0 +1,6 @@ +model Test1 + Real x (start = 1.0); + parameter Real a = -1.0; +equation + der(x) = a*x; +end Test1; diff --git a/test/all_tests.sh b/test/all_tests.sh new file mode 100644 index 0000000..eca6f1e --- /dev/null +++ b/test/all_tests.sh @@ -0,0 +1,10 @@ +filenames=" +/home/nutarojj/Code/openmodelica/trunk/testsuite/openmodelica/fmi/ModelExchange/HelloFMIWorld.mo +Test1.mo +Linsys.mo +" +for f in $filenames; +do + bash fmu_check.sh $f +done + diff --git a/test/fmu_check.sh b/test/fmu_check.sh new file mode 100644 index 0000000..fea3655 --- /dev/null +++ b/test/fmu_check.sh @@ -0,0 +1,13 @@ +rm -rf binaries +rm -f *.fmu +export MODELICAPATH="${HOME}/Code/openmodelica/libraries/Modelica 3.2.1" +omc +s +simCodeTarget=sfmi $1 Modelica +modelFile=$(exec basename $1 | sed 's/\.mo//') +g++ -Wall -g -c -fPIC -I../FMI_for_ModelExchange_and_CoSimulation_v2.0 -o sfmi_runtime.o ../runtime/sfmi_runtime.cpp +g++ -Wall -g -c -fPIC -I../FMI_for_ModelExchange_and_CoSimulation_v2.0 -I../runtime -o ${modelFile}_FMI.o ${modelFile}_FMI.cpp +g++ -shared -Wl,-soname,${modelFile}.so -o ${modelFile}.so sfmi_runtime.o ${modelFile}_FMI.o +mkdir binaries +mkdir binaries/linux64 +mv ${modelFile}.so binaries/linux64 +zip -r ${modelFile}.fmu modelDescription.xml binaries +fmuCheck.linux64 -l 5 -f ${modelFile}.fmu > ${modelFile}.dat