ct_wrappers.hpp
Go to the documentation of this file.
1 /**********************************************************************
2  * ct_wrappers.hpp -- Co-simulation wrappers for the CT MOC *
3  * *
4  * Author: Hosein Attarzadeh (shan2@kth.se) *
5  * FMI code adopted from QTronic GmbH's FMI 2.0 SDK *
6  * *
7  * Purpose: Providing co-simulation wrappers for integration of *
8  * foreign models into ForSyDe *
9  * *
10  * Usage: This file is included automatically *
11  * *
12  * License: BSD3 *
13  *******************************************************************/
14 
15 #ifndef CT_WRAPPERS_HPP
16 #define CT_WRAPPERS_HPP
17 
26 #include "fmi2/fmi2.h"
27 #include "fmi2/sim_support.h"
28 
29 #include "sub_signal.hpp"
30 #include "ct_process.hpp"
31 
32 namespace ForSyDe
33 {
34 
35 namespace CT
36 {
37 
38 using namespace sc_core;
39 
41 
46 class fmi2cswrap : public ct_process
47 {
48 public:
51 
53 
57  fmi2cswrap(sc_module_name _name,
58  const std::string& fmu_file,
59  const unsigned int& input_index,
60  const unsigned int& output_index,
61  const sc_time& sample_period
62  ) : ct_process(_name), iport1("iport1"), oport1("oport1"),
63  fmuFileName(fmu_file), input_index(input_index),
64  output_index(output_index), h(sample_period)
65  {
66 #ifdef FORSYDE_INTROSPECTION
67  arg_vec.push_back(std::make_tuple("fmuFileName",fmuFileName));
68  std::stringstream ss;
69  ss << input_index;
70  arg_vec.push_back(std::make_tuple("input_index", ss.str()));
71  ss.str("");
72  ss << output_index;
73  arg_vec.push_back(std::make_tuple("output_index", ss.str()));
74  ss.str("");
75  ss << sample_period;
76  arg_vec.push_back(std::make_tuple("sample_period", ss.str()));
77 #endif
78  }
79 
81  std::string forsyde_kind() const {return "CT::fmi2cswrap";}
82 
83 private:
84  // Inputs and output variables
85  sub_signal oval;
86  sub_signal ival1;
87 
89  std::string fmuFileName;
90  unsigned int input_index, output_index;
91  sc_time h;
92 
93  sc_time time;
94  FMU fmu; // the fmu to simulate
95  const char *guid; // global unique id of the fmu
96  const char *instanceName; // instance name
97  fmi2Component c; // instance of the fmu
98  fmi2Status fmi2Flag; // return code of the fmu functions
99  char *fmuResourceLocation; // path to the fmu resources as URL
100  fmi2Boolean visible; // no simulator user interface
101  fmi2CallbackFunctions callbacks = {fmuLogger, calloc, free, NULL, &fmu};// called by the model during simulation
102  ModelDescription* md; // handle to the parsed XML file
103  fmi2Boolean toleranceDefined; // true if model description define tolerance
104  fmi2Real tolerance; // used in setting up the experiment
105  ValueStatus vs;
106  Element *defaultExp;
107 
108  //Implementing the abstract semantics
109  void init()
110  {
111  time = SC_ZERO_TIME;
112  fmuResourceLocation = getTempResourcesLocation();
113  visible = fmi2False;
114  //~ callbacks = {fmuLogger, calloc, free, NULL, fmu};
115  toleranceDefined = fmi2False;
116  tolerance = 0;
117  //~ vs = 0;
118 
119  // load the FMU
120  loadFMU(fmuFileName.c_str(), &fmu);
121 
122  // run the simulation
123  // instantiate the fmu
124  md = fmu.modelDescription;
125  guid = getAttributeValue((Element *)md, att_guid);
126  instanceName = getAttributeValue((Element *)getCoSimulation(md),
127  att_modelIdentifier);
128  c = fmu.instantiate(instanceName, fmi2CoSimulation, guid,
129  fmuResourceLocation, &callbacks, visible, fmi2False/*logging off*/);
130  free(fmuResourceLocation);
131  if (!c) return SC_REPORT_ERROR(name(),"could not instantiate model");
132 
133  defaultExp = getDefaultExperiment(md);
134  if (defaultExp) tolerance = getAttributeDouble(defaultExp, att_tolerance, &vs);
135  if (vs == valueDefined) {
136  toleranceDefined = fmi2True;
137  }
138 
139  fmi2Flag = fmu.setupExperiment(c, toleranceDefined, tolerance, 0, fmi2True, 1000/* FIXME */);
140  if (fmi2Flag > fmi2Warning) {
141  return SC_REPORT_ERROR(name(),"could not initialize model; failed FMI setup experiment");
142  }
143 
144  fmi2Flag = fmu.enterInitializationMode(c);
145  if (fmi2Flag > fmi2Warning) {
146  return SC_REPORT_ERROR(name(),"could not initialize model; failed FMI enter initialization mode");
147  }
148 
149  fmi2Flag = fmu.exitInitializationMode(c);
150  if (fmi2Flag > fmi2Warning) {
151  return SC_REPORT_ERROR(name(),"could not initialize model; failed FMI exit initialization mode");
152  }
153 
154  // output solution for time t0
155  // FIXME: outputRow(fmu, c, tStart, file, separator, fmi2False); // output values
156  //~ auto res = getRealOutput(fmu, c, 0);
157  //~ oval = sub_signal(time, time+h,
158  //~ [this,res](const sc_time& t)
159  //~ {
160  //~ return res;
161  //~ }
162  //~ );
163  //~ WRITE_MULTIPORT(oport1, oval)
164  //~ time += h;
165  //~ wait(time - sc_time_stamp());
166  ival1 = iport1.read();
167  }
168 
169  void prep()
170  {
171  while (time >= get_end_time(ival1)) ival1 = iport1.read();
172  setRealInput(&fmu, c, input_index, ival1(time));
173  }
174 
175  void exec()
176  {
177  fmi2Flag = fmu.doStep(c, time.to_seconds(), h.to_seconds(), fmi2True);
178  if (fmi2Flag == fmi2Discard) {
179  fmi2Boolean b;
180  // check if model requests to end simulation
181  if (fmi2OK != fmu.getBooleanStatus(c, fmi2Terminated, &b)) {
182  return SC_REPORT_ERROR(name(),"could not complete simulation of the model. getBooleanStatus return other than fmi2OK");
183  }
184  if (b == fmi2True) {
185  return SC_REPORT_ERROR(name(),"the model requested to end the simulation");
186  }
187  return SC_REPORT_ERROR(name(),"could not complete simulation of the model");
188  }
189  if (fmi2Flag != fmi2OK)
190  return SC_REPORT_ERROR(name(),"could not complete simulation of the model");
191 
192  // FIXME: res = outputRow(fmu, c, time, file, separator, fmi2False); // output values for this step
193  auto res = getRealOutput(&fmu, c, output_index);
194  oval = sub_signal(time, time+h,
195  [this,res](const sc_time& t)
196  {
197  return res;
198  }
199  );
200  }
201 
202  void prod()
203  {
204  WRITE_MULTIPORT(oport1, oval)
205  time += h;
206  wait(time - sc_time_stamp());
207  }
208 
209  void clean()
210  {
211  // end simulation
212  fmu.terminate(c);
213  fmu.freeInstance(c);
214 
215  #ifdef _MSC_VER
216  FreeLibrary(fmu.dllHandle);
217  #else
218  dlclose(fmu.dllHandle);
219  #endif
220  freeModelDescription(fmu.modelDescription);
221  deleteUnzippedFiles();
222  }
223 
224 #ifdef FORSYDE_INTROSPECTION
225  void bindInfo()
226  {
227  boundInChans.resize(1); // only one input port
228  boundInChans[0].port = &iport1;
229  boundOutChans.resize(1); // only one output port
230  boundOutChans[0].port = &oport1;
231  }
232 #endif
233 };
234 
236 
242 template <class OIf, class I1If>
243 inline fmi2cswrap* make_fmi2cswrap(const std::string& pName,
244  const std::string& fmu_file,
245  const unsigned& input_index,
246  const unsigned& output_index,
247  const sc_time& sample_period,
248  OIf& outS,
249  I1If& inp1S
250  )
251 {
252  auto p = new fmi2cswrap(pName.c_str(), fmu_file, input_index, output_index, sample_period);
253 
254  (*p).iport1(inp1S);
255  (*p).oport1(outS);
256 
257  return p;
258 }
259 
260 }
261 }
262 
263 #endif
The sub-signal type used to construct a CT signal.
Definition: sub_signal.hpp:38
The namespace for ForSyDe.
Definition: abssemantics.hpp:30
The CT_out port is used for output ports of CT processes.
Definition: ct_process.hpp:64
fmi2cswrap * make_fmi2cswrap(const std::string &pName, const std::string &fmu_file, const unsigned &input_index, const unsigned &output_index, const sc_time &sample_period, OIf &outS, I1If &inp1S)
Helper function to construct a pipewrap process.
Definition: ct_wrappers.hpp:243
Implements the abstract process in the CT Model of Computation.
The process constructor which defines the abstract semantics of execution.
Definition: abssemantics.hpp:212
Process constructor for a co-simulation FMU wrapper with one input and one output.
Definition: ct_wrappers.hpp:46
CT_out oport1
port for the output channel
Definition: ct_wrappers.hpp:50
The CT_in port is used for input ports of CT processes.
Definition: ct_process.hpp:53
fmi2cswrap(sc_module_name _name, const std::string &fmu_file, const unsigned int &input_index, const unsigned int &output_index, const sc_time &sample_period)
The constructor requires the module name.
Definition: ct_wrappers.hpp:57
std::string forsyde_kind() const
Specifying from which process constructor is the module built.
Definition: ct_wrappers.hpp:81
Implements the sub-components of a CT signal.
CT_in iport1
port for the input channel
Definition: ct_wrappers.hpp:49