fmu.cpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #include "fmu_impl.hpp"
27 #include "fmu_function.hpp"
28 #include "dae_builder_internal.hpp"
29 #include "filesystem_impl.hpp"
30 
31 #ifdef WITH_FMI2
32 #include "fmu2.hpp"
33 #endif // WITH_FMI2
34 
35 #ifdef WITH_FMI3
36 #include "fmu3.hpp"
37 #endif // WITH_FMI3
38 
39 namespace casadi {
40 
41 // Throw informative error message
42 #define THROW_ERROR(FNAME, WHAT) \
43 throw CasadiException("Error in Fmu::" FNAME " for '" + this->name() + "' "\
44  "[" + this->class_name() + "] at " + CASADI_WHERE + ":\n"\
45  + std::string(WHAT));
46 
47 
49 }
50 
51 Fmu::Fmu(const std::string& name, FmuApi api, const DaeBuilderInternal* dae,
52  const std::vector<std::string>& scheme_in,
53  const std::vector<std::string>& scheme_out,
54  const std::map<std::string, std::vector<size_t>>& scheme,
55  const std::vector<std::string>& aux) {
56  if (api == FmuApi::FMI2) {
57 #ifdef WITH_FMI2
58  // Create
59  own(new Fmu2(name, scheme_in, scheme_out, scheme, aux));
60 #else // WITH_FMI2
61  // No compilation support
62  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
63 #endif // WITH_FMI2
64  } else if (api == FmuApi::FMI3) {
65 #ifdef WITH_FMI3
66  // Create
67  own(new Fmu3(name, scheme_in, scheme_out, scheme, aux));
68 #else // WITH_FMI3
69  // No compilation support
70  casadi_error("CasADi was not compiled with WITH_FMI3=ON.");
71 #endif // WITH_FMI3
72  } else {
73  // Not supported
74  casadi_error("Unsupported FMU API: " + to_string(api));
75  }
76  // Initialize
77  try {
78  (*this)->init(dae);
79  (*this)->finalize();
80  } catch(std::exception& e) {
81  THROW_ERROR("init", e.what());
82  }
83 }
84 
86  return static_cast<FmuInternal*>(SharedObject::operator->());
87 }
88 
89 const FmuInternal* Fmu::operator->() const {
90  return static_cast<const FmuInternal*>(SharedObject::operator->());
91 }
92 
94  return (*this)->alloc_mem(f);
95 }
96 
97 void Fmu::free_mem(void *mem) const {
98  return (*this)->free_mem(mem);
99 }
100 
102  return static_cast<FmuInternal*>(SharedObject::get());
103 }
104 
105 const std::string& Fmu::name() const {
106  if (is_null()) {
107  static std::string null = "null";
108  return null;
109  } else {
110  return (*this)->name_;
111  }
112 }
113 
114 const std::string& Fmu::instance_name() const {
115  if (is_null()) {
116  static std::string null = "null";
117  return null;
118  } else {
119  return (*this)->instance_name_;
120  }
121 }
122 
123 size_t Fmu::n_in() const {
124  try {
125  return (*this)->n_in();
126  } catch(std::exception& e) {
127  THROW_ERROR("n_in", e.what());
128  }
129 }
130 
131 size_t Fmu::n_out() const {
132  try {
133  return (*this)->n_out();
134  } catch(std::exception& e) {
135  THROW_ERROR("n_out", e.what());
136  }
137 }
138 
139 size_t Fmu::index_in(const std::string& n) const {
140  try {
141  return (*this)->index_in(n);
142  } catch(std::exception& e) {
143  THROW_ERROR("index_in", e.what());
144  }
145 }
146 
147 size_t Fmu::index_out(const std::string& n) const {
148  try {
149  return (*this)->index_out(n);
150  } catch(std::exception& e) {
151  THROW_ERROR("index_out", e.what());
152  }
153 }
154 
155 const std::vector<size_t>& Fmu::ired(size_t ind) const {
156  try {
157  return (*this)->ired_.at(ind);
158  } catch(std::exception& e) {
159  THROW_ERROR("ired", e.what());
160  }
161 }
162 
163 const std::vector<size_t>& Fmu::ored(size_t ind) const {
164  try {
165  return (*this)->ored_.at(ind);
166  } catch(std::exception& e) {
167  THROW_ERROR("ored", e.what());
168  }
169 }
170 
171 double Fmu::nominal_in(size_t ind) const {
172  try {
173  return (*this)->nominal_in_.at(ind);
174  } catch(std::exception& e) {
175  THROW_ERROR("nominal_in", e.what());
176  }
177 }
178 
179 double Fmu::nominal_out(size_t ind) const {
180  try {
181  return (*this)->nominal_out_.at(ind);
182  } catch(std::exception& e) {
183  THROW_ERROR("nominal_out", e.what());
184  }
185 }
186 
187 double Fmu::min_in(size_t ind) const {
188  try {
189  return (*this)->min_in_.at(ind);
190  } catch(std::exception& e) {
191  THROW_ERROR("min_in", e.what());
192  }
193 }
194 
195 double Fmu::max_in(size_t ind) const {
196  try {
197  return (*this)->max_in_.at(ind);
198  } catch(std::exception& e) {
199  THROW_ERROR("max_in", e.what());
200  }
201 }
202 
203 std::vector<double> Fmu::all_nominal_in(size_t ind) const {
204  try {
205  return (*this)->all_nominal_in(ind);
206  } catch(std::exception& e) {
207  THROW_ERROR("all_nominal_in", e.what());
208  }
209 }
210 
211 std::vector<double> Fmu::all_nominal_out(size_t ind) const {
212  try {
213  return (*this)->all_nominal_out(ind);
214  } catch(std::exception& e) {
215  THROW_ERROR("all_nominal_out", e.what());
216  }
217 }
218 
219 std::string Fmu::desc_in(FmuMemory* m, size_t id, bool more) const {
220  try {
221  return (*this)->desc_in(m, id, more);
222  } catch(std::exception& e) {
223  THROW_ERROR("desc_in", e.what());
224  }
225 }
226 
228  try {
229  return (*this)->provides_directional_derivatives_;
230  } catch(std::exception& e) {
231  THROW_ERROR("provides_directional_derivatives", e.what());
232  }
233 }
234 
236  try {
237  return (*this)->provides_adjoint_derivatives_;
238  } catch(std::exception& e) {
239  THROW_ERROR("provides_adjoint_derivatives", e.what());
240  }
241 }
242 
244  try {
245  return (*this)->can_be_instantiated_only_once_per_process_;
246  } catch(std::exception& e) {
247  THROW_ERROR("can_be_instantiated_only_once_per_process", e.what());
248  }
249 }
250 
251 Sparsity Fmu::jac_sparsity(const std::vector<size_t>& osub,
252  const std::vector<size_t>& isub) const {
253  try {
254  return (*this)->jac_sparsity(osub, isub);
255  } catch(std::exception& e) {
256  THROW_ERROR("jac_sparsity", e.what());
257  }
258 }
259 
260 Sparsity Fmu::hess_sparsity(const std::vector<size_t>& r, const std::vector<size_t>& c) const {
261  try {
262  return (*this)->hess_sparsity(r, c);
263  } catch(std::exception& e) {
264  THROW_ERROR("hess_sparsity", e.what());
265  }
266 }
267 
268 int Fmu::init_mem(FmuMemory* m) const {
269  try {
270  return (*this)->init_mem(m);
271  } catch(std::exception& e) {
272  THROW_ERROR("init_mem", e.what());
273  return 1;
274  }
275 }
276 
277 void Fmu::free_instance(void* instance) const {
278  try {
279  return (*this)->free_instance(instance);
280  } catch(std::exception& e) {
281  THROW_ERROR("free_instance", e.what());
282  }
283 }
284 
285 void Fmu::set(FmuMemory* m, size_t ind, const double* value) const {
286  try {
287  return (*this)->set(m, ind, value);
288  } catch(std::exception& e) {
289  THROW_ERROR("set", e.what());
290  }
291 }
292 
293 void Fmu::request(FmuMemory* m, size_t ind) const {
294  try {
295  return (*this)->request(m, ind);
296  } catch(std::exception& e) {
297  THROW_ERROR("request", e.what());
298  }
299 }
300 
301 int Fmu::eval(FmuMemory* m) const {
302  try {
303  return (*this)->eval(m);
304  } catch(std::exception& e) {
305  THROW_ERROR("eval", e.what());
306  }
307 }
308 
309 void Fmu::get(FmuMemory* m, size_t id, double* value) const {
310  try {
311  return (*this)->get(m, id, value);
312  } catch(std::exception& e) {
313  THROW_ERROR("get", e.what());
314  }
315 }
316 
317 void Fmu::set_fwd(FmuMemory* m, casadi_int nseed, const casadi_int* id, const double* v) const {
318  try {
319  return (*this)->set_fwd(m, nseed, id, v);
320  } catch(std::exception& e) {
321  THROW_ERROR("set_fwd", e.what());
322  }
323 }
324 
325 void Fmu::set_fwd(FmuMemory* m, size_t ind, const double* v) const {
326  try {
327  return (*this)->set_fwd(m, ind, v);
328  } catch(std::exception& e) {
329  THROW_ERROR("set_fwd", e.what());
330  }
331 }
332 
333 void Fmu::request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
334  const casadi_int* wrt_id) const {
335  try {
336  return (*this)->request_fwd(m, nsens, id, wrt_id);
337  } catch(std::exception& e) {
338  THROW_ERROR("request_fwd", e.what());
339  }
340 }
341 
342 void Fmu::request_fwd(FmuMemory* m, casadi_int ind) const {
343  try {
344  return (*this)->request_fwd(m, ind);
345  } catch(std::exception& e) {
346  THROW_ERROR("request_fwd", e.what());
347  }
348 }
349 
350 int Fmu::eval_fwd(FmuMemory* m, bool independent_seeds) const {
351  try {
352  return (*this)->eval_fwd(m, independent_seeds);
353  } catch(std::exception& e) {
354  THROW_ERROR("eval_fwd", e.what());
355  }
356 }
357 
358 void Fmu::get_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
359  try {
360  return (*this)->get_fwd(m, nsens, id, v);
361  } catch(std::exception& e) {
362  THROW_ERROR("get_fwd", e.what());
363  }
364 }
365 
366 void Fmu::get_fwd(FmuMemory* m, size_t ind, double* v) const {
367  try {
368  return (*this)->get_fwd(m, ind, v);
369  } catch(std::exception& e) {
370  THROW_ERROR("get_fwd", e.what());
371  }
372 }
373 
374 void Fmu::set_adj(FmuMemory* m, casadi_int nseed, const casadi_int* id, const double* v) const {
375  try {
376  return (*this)->set_adj(m, nseed, id, v);
377  } catch(std::exception& e) {
378  THROW_ERROR("set_adj", e.what());
379  }
380 }
381 
382 void Fmu::set_adj(FmuMemory* m, size_t ind, const double* v) const {
383  try {
384  return (*this)->set_adj(m, ind, v);
385  } catch(std::exception& e) {
386  THROW_ERROR("set_adj", e.what());
387  }
388 }
389 
390 void Fmu::request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
391  const casadi_int* wrt_id) const {
392  try {
393  return (*this)->request_adj(m, nsens, id, wrt_id);
394  } catch(std::exception& e) {
395  THROW_ERROR("request_adj", e.what());
396  }
397 }
398 
399 void Fmu::request_adj(FmuMemory* m, casadi_int ind) const {
400  try {
401  return (*this)->request_adj(m, ind);
402  } catch(std::exception& e) {
403  THROW_ERROR("request_adj", e.what());
404  }
405 }
406 
407 int Fmu::eval_adj(FmuMemory* m) const {
408  try {
409  return (*this)->eval_adj(m);
410  } catch(std::exception& e) {
411  THROW_ERROR("eval_adj", e.what());
412  }
413 }
414 
415 void Fmu::get_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
416  try {
417  return (*this)->get_adj(m, nsens, id, v);
418  } catch(std::exception& e) {
419  THROW_ERROR("get_adj", e.what());
420  }
421 }
422 
423 void Fmu::get_adj(FmuMemory* m, size_t ind, double* v) const {
424  try {
425  return (*this)->get_adj(m, ind, v);
426  } catch(std::exception& e) {
427  THROW_ERROR("get_adj", e.what());
428  }
429 }
430 
431 void Fmu::get_stats(FmuMemory* m, Dict* stats,
432  const std::vector<std::string>& name_in, const InputStruct* in) const {
433  try {
434  return (*this)->get_stats(m, stats, name_in, in);
435  } catch(std::exception& e) {
436  THROW_ERROR("get_stats", e.what());
437  }
438 }
439 
440 FmuInternal::FmuInternal(const std::string& name,
441  const std::vector<std::string>& scheme_in,
442  const std::vector<std::string>& scheme_out,
443  const std::map<std::string, std::vector<size_t>>& scheme,
444  const std::vector<std::string>& aux)
445  : name_(name), scheme_in_(scheme_in), scheme_out_(scheme_out), scheme_(scheme), aux_(aux) {
446 }
447 
449 }
450 
452  // Copy info from DaeBuilder
453  resource_ = dae->resource_;
454  fmutol_ = dae->fmutol_;
457  logging_on_ = dae->debug_;
462  nx_ = dae->size(Category::X);
463  do_evaluation_dance_ = dae->generation_tool_.rfind("Simulink", 0) == 0;
464 
465  // Mark input indices
466  size_t numel = 0;
467  std::vector<bool> lookup(dae->n_variables(), false);
468  for (auto&& n : scheme_in_) {
469  for (size_t i : scheme_.at(n)) {
470  casadi_assert(!lookup.at(i), "Duplicate variable: " + dae->variable(i).name);
471  lookup.at(i) = true;
472  numel++;
473  }
474  }
475  // Input mappings
476  iind_.reserve(numel);
477  iind_map_.reserve(lookup.size());
478  for (size_t k = 0; k < lookup.size(); ++k) {
479  if (lookup[k]) {
480  iind_map_.push_back(iind_.size());
481  iind_.push_back(k);
482  } else {
483  iind_map_.push_back(-1);
484  }
485  }
486  // Mark output indices
487  numel = 0;
488  std::fill(lookup.begin(), lookup.end(), false);
489  for (auto&& n : scheme_out_) {
490  for (size_t i : scheme_.at(n)) {
491  casadi_assert(!lookup.at(i), "Duplicate variable: " + dae->variable(i).name);
492  lookup.at(i) = true;
493  numel++;
494  }
495  }
496  // Construct mappings
497  oind_.reserve(numel);
498  oind_map_.reserve(lookup.size());
499  for (size_t k = 0; k < lookup.size(); ++k) {
500  if (lookup[k]) {
501  oind_map_.push_back(oind_.size());
502  oind_.push_back(k);
503  } else {
504  oind_map_.push_back(-1);
505  }
506  }
507  // Inputs
508  ired_.resize(scheme_in_.size());
509  for (size_t i = 0; i < ired_.size(); ++i) {
510  auto&& s = scheme_.at(scheme_in_[i]);
511  ired_[i].resize(s.size());
512  for (size_t k = 0; k < s.size(); ++k) {
513  ired_[i][k] = iind_map_.at(s[k]);
514  }
515  }
516  // Outputs
517  ored_.resize(scheme_out_.size());
518  for (size_t i = 0; i < ored_.size(); ++i) {
519  auto&& s = scheme_.at(scheme_out_[i]);
520  ored_[i].resize(s.size());
521  for (size_t k = 0; k < s.size(); ++k) {
522  ored_[i][k] = oind_map_.at(s[k]);
523  }
524  }
525 
526  // Is there an independent variable?
527  has_independent_ = false;
528 
529  // Collect meta information for inputs
530  nominal_in_.reserve(iind_.size());
531  min_in_.reserve(iind_.size());
532  max_in_.reserve(iind_.size());
533  vn_in_.reserve(iind_.size());
534  vr_in_.reserve(iind_.size());
535  for (size_t i : iind_) {
536  const Variable& v = dae->variable(i);
537  nominal_in_.push_back(v.nominal);
538  min_in_.push_back(v.min);
539  max_in_.push_back(v.max);
540  vn_in_.push_back(v.name);
541  vr_in_.push_back(v.value_reference);
543  if (i != 0) casadi_error("Independent variable must be first input of FMU");
544  has_independent_ = true;
545  }
546  }
547  // Collect meta information for outputs
548  nominal_out_.reserve(oind_.size());
549  min_out_.reserve(oind_.size());
550  max_out_.reserve(oind_.size());
551  vn_out_.reserve(oind_.size());
552  vr_out_.reserve(oind_.size());
553  for (size_t i : oind_) {
554  const Variable& v = dae->variable(i);
555  nominal_out_.push_back(v.nominal);
556  min_out_.push_back(v.min);
557  max_out_.push_back(v.max);
558  vn_out_.push_back(v.name);
559  vr_out_.push_back(v.value_reference);
560  }
561 
562  // Numerical values for inputs
563  value_in_.resize(iind_.size());
564 
565  // Get Jacobian sparsity information
566  jac_sp_ = dae->jac_sparsity(oind_, iind_);
567 
568  // Get Hessian sparsity information
570 }
571 
572 int FmuInternal::get_adjoint_derivative(void* instance, const unsigned int* vr_out, size_t n_out,
573  const unsigned int* vr_in, size_t n_in, const double* seed, size_t n_seed,
574  double* sensitivity, size_t n_sensitivity) const {
575  casadi_error("Adjoint derivatives not supported for " + class_name());
576  return 1;
577 }
578 
585  // Load DLL
586  std::string instance_name_no_dot = instance_name_;
587  std::replace(instance_name_no_dot.begin(), instance_name_no_dot.end(), '.', '_');
588  std::string dll_path = resource_.path() + "/binaries/" + system_infix()
589  + "/" + instance_name_no_dot + dll_suffix();
590  li_ = Importer(dll_path, "dll");
591 
592  // Get FMI C functions
593  load_functions();
594 
595  // Path to resource directory
596  std::string url = "";
597  if (Filesystem::is_enabled()) {
598  url = "file://" + Filesystem::absolute(resource_.path()) + "/resources";
599  } else {
600  url = "file://" + resource_.path() + "/resources";
601  }
602  // Forward slashes
603  std::replace(url.begin(), url.end(), '\\', '/');
604 
605  resource_loc_ = url;
606 
607  // Create a temporary instance
608  void* c = instantiate();
609  // Set all values
610  if (set_values(c)) {
611  casadi_error("FmuInternal::set_values failed");
612  }
613  // Initialization mode begins
614  if (enter_initialization_mode(c)) {
615  casadi_error("FmuInternal::enter_initialization_mode failed");
616  }
617  // Get input values
618  if (!value_in_.empty()) {
619  if (get_real(c, get_ptr(vr_in_), vr_in_.size(), get_ptr(value_in_), value_in_.size())) {
620  casadi_error("FmuInternal::get_in failed");
621  }
622  }
623  // Get auxilliary variables
624  if (get_aux(c)) {
625  casadi_error("FmuInternal::get_aux failed");
626  }
627  // Free memory
628  free_instance(c);
629 }
630 
631 void FmuInternal::disp(std::ostream& stream, bool more) const {
632  (void)more; // unused
633  stream << name_ << " " << class_name();
634 }
635 
636 std::string to_string(FmuApi v) {
637  switch (v) {
638  case FmuApi::FMI2: return "fmi2";
639  case FmuApi::FMI3: return "fmi3";
640  default: break;
641  }
642  return "";
643 }
644 
645 size_t FmuInternal::index_in(const std::string& n) const {
646  // Linear search for the input
647  for (size_t i = 0; i < scheme_in_.size(); ++i) {
648  if (scheme_in_[i] == n) return i;
649  }
650  // Not found
651  casadi_error("No such input: " + n);
652  return -1;
653 }
654 
655 size_t FmuInternal::index_out(const std::string& n) const {
656  // Linear search for the input
657  for (size_t i = 0; i < scheme_out_.size(); ++i) {
658  if (scheme_out_[i] == n) return i;
659  }
660  // Not found
661  casadi_error("No such output: " + n);
662  return -1;
663 }
664 
665 Sparsity FmuInternal::jac_sparsity(const std::vector<size_t>& osub,
666  const std::vector<size_t>& isub) const {
667  // Convert to casadi_int type
668  std::vector<casadi_int> osub1(osub.begin(), osub.end());
669  std::vector<casadi_int> isub1(isub.begin(), isub.end());
670  // Index mapping (not used)
671  std::vector<casadi_int> mapping;
672  // Get selection
673  return jac_sp_.sub(osub1, isub1, mapping);
674 }
675 
676 Sparsity FmuInternal::hess_sparsity(const std::vector<size_t>& r,
677  const std::vector<size_t>& c) const {
678  // Convert to casadi_int type
679  std::vector<casadi_int> r1(r.begin(), r.end());
680  std::vector<casadi_int> c1(c.begin(), c.end());
681  // Index mapping (not used)
682  std::vector<casadi_int> mapping;
683  // Get selection
684  return hess_sp_.sub(r1, c1, mapping);
685 }
686 
687 std::vector<double> FmuInternal::all_nominal_in(size_t i) const {
688  auto&& ind = ired_.at(i);
689  std::vector<double> n;
690  n.reserve(ind.size());
691  for (size_t k : ind) n.push_back(nominal_in_.at(k));
692  return n;
693 }
694 
695 std::vector<double> FmuInternal::all_nominal_out(size_t i) const {
696  auto&& ind = ored_.at(i);
697  std::vector<double> n;
698  n.reserve(ind.size());
699  for (size_t k : ind) n.push_back(nominal_out_.at(k));
700  return n;
701 }
702 
703 std::string FmuInternal::dll_suffix() {
704 #if defined(_WIN32)
705  // Windows system
706  return ".dll";
707 #elif defined(__APPLE__)
708  // OSX
709  return ".dylib";
710 #else
711  // Linux
712  return ".so";
713 #endif
714 }
715 
716 std::string FmuInternal::desc_in(FmuMemory* m, size_t id, bool more) const {
717  // Create description
718  if (more) {
719  // Detailed description
720  std::stringstream ss;
721  ss << vn_in_[id] << " = " << m->ibuf_[id] << " (nominal " << nominal_in_[id]
722  << ", min " << min_in_[id] << ", max " << max_in_[id] << ")";
723  return ss.str();
724  } else {
725  return vn_in_[id];
726  }
727 }
728 
729 int FmuInternal::eval_fwd(FmuMemory* m, bool independent_seeds) const {
730  // Gather input and output indices
731  gather_fwd(m);
732  // Calculate derivatives using FMU directional derivative support
734  // Evaluate using AD
735  if (eval_ad(m)) return 1;
736  }
737  // Calculate derivatives using finite differences
739  // Evaluate using FD
740  if (eval_fd(m, independent_seeds)) return 1;
741  }
742  return 0;
743 }
744 
746  // Gather input and output indices
747  gather_adj(m);
748  // Quick return if nothing to be calculated
749  if (m->id_in_.size() == 0) return 0;
750  // Evaluate adjoint derivatives
752  get_ptr(m->vr_out_), m->id_out_.size(),
753  get_ptr(m->vr_in_), m->id_in_.size(),
754  get_ptr(m->d_out_), m->id_out_.size(),
755  get_ptr(m->d_in_), m->id_in_.size())) {
756  casadi_warning("FMU adjoint derivative failed");
757  return 1;
758  }
759  // Collect requested variables
760  auto it = m->d_in_.begin();
761  for (size_t id : m->id_in_) {
762  m->isens_[id] = *it++;
763  }
764  // Successful return
765  return 0;
766 }
767 
769  // Number of inputs and outputs
770  size_t n_known = m->id_in_.size();
771  size_t n_unknown = m->id_out_.size();
772  // Quick return if nothing to be calculated
773  if (n_unknown == 0) return 0;
774  // Evalute (should not be necessary)
775  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, get_ptr(m->v_out_), n_unknown)) {
776  casadi_warning("FMU evaluation failed");
777  return 1;
778  }
779  // Evaluate directional derivatives
781  get_ptr(m->vr_out_), n_unknown,
782  get_ptr(m->vr_in_), n_known,
783  get_ptr(m->d_in_), n_known,
784  get_ptr(m->d_out_), n_unknown)) {
785  casadi_warning("FMU directional derivative failed");
786  return 1;
787  }
788  // Collect requested variables
789  auto it = m->d_out_.begin();
790  for (size_t id : m->id_out_) {
791  m->osens_[id] = *it++;
792  }
793  // Successful return
794  return 0;
795 }
796 
797 int FmuInternal::eval_fd(FmuMemory* m, bool independent_seeds) const {
798  // Number of inputs and outputs
799  size_t n_known = m->id_in_.size();
800  size_t n_unknown = m->id_out_.size();
801  // Quick return if nothing to be calculated
802  if (n_unknown == 0) return 0;
803  // Evalute (should not be necessary)
804  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, get_ptr(m->v_out_), n_unknown)) {
805  casadi_warning("Evaluating FMU failed");
806  return 1;
807  }
808  // Make outputs dimensionless
809  for (size_t k = 0; k < n_unknown; ++k) m->v_out_[k] /= nominal_out_[m->id_out_[k]];
810  // Number of points in FD stencil
811  casadi_int n_points = n_fd_points(m->self.fd_);
812  // Offset for points
813  casadi_int offset = fd_offset(m->self.fd_);
814  // Memory for perturbed outputs
815  m->fd_out_.resize(n_points * n_unknown);
816  // Which inputs are in bounds
817  m->in_bounds_.resize(n_known);
818  // Memory for perturbed inputs
819  m->v_pert_.resize(n_known);
820  // Do any any inputs need flipping?
821  m->flip_.resize(n_known);
822  size_t first_flip = -1;
823  for (size_t i = 0; i < n_known; ++i) {
824  // Try to take step
825  double test = m->v_in_[i] + m->self.step_ * m->d_in_[i];
826  // Check if in bounds
827  size_t id = m->id_in_[i];
828  if (test >= min_in_[id] && test <= max_in_[id]) {
829  // Positive perturbation is fine
830  m->flip_[i] = false;
831  } else {
832  // Try negative direction instead
833  test = m->v_in_[i] - m->self.step_ * m->d_in_[i];
834  casadi_assert(test >= min_in_[id] && test <= max_in_[id],
835  "Cannot perturb " + vn_in_[id] + " at " + str(m->v_in_[i]) + ", min " + str(min_in_[id])
836  + ", max " + str(max_in_[id]) + ", nominal " + str(nominal_in_[id]));
837  m->flip_[i] = true;
838  if (first_flip == size_t(-1)) first_flip = i;
839  }
840  }
841  // If seeds are not independent, we have to flip the sign for all of the seeds or none
842  if (first_flip != size_t(-1) && !independent_seeds) {
843  // Flip the rest of the seeds
844  for (size_t i = 0; i < n_known; ++i) {
845  if (!m->flip_[i]) {
846  // Test negative direction
847  double test = m->v_in_[i] - m->self.step_ * m->d_in_[i];
848  size_t id = m->id_in_[i];
849  casadi_assert(test >= min_in_[id] && test <= max_in_[id],
850  "Cannot perturb both " + vn_in_[id] + " and " + vn_in_[first_flip]);
851  // Flip it too
852  m->flip_[i] = true;
853  }
854  }
855  }
856  // All perturbed outputs
857  const double* yk_all[5] = {0};
858 
859  // Calculate all perturbed outputs
860  for (casadi_int k = 0; k < n_points; ++k) {
861  // Where to save the perturbed outputs
862  double* yk = &m->fd_out_[n_unknown * k];
863  casadi_assert_dev(k < 5);
864  yk_all[k] = yk;
865  // If unperturbed output, quick return
866  if (k == offset) {
867  casadi_copy(get_ptr(m->v_out_), n_unknown, yk);
868  continue;
869  }
870  // Perturbation size
871  double pert = (k - offset) * m->self.step_;
872  // Perturb inputs, if allowed
873  for (size_t i = 0; i < n_known; ++i) {
874  // Try to take step
875  double sign = m->flip_[i] ? -1 : 1;
876  double test = m->v_in_[i] + pert * sign * m->d_in_[i];
877  // Check if in bounds
878  size_t id = m->id_in_[i];
879  m->in_bounds_[i] = test >= min_in_[id] && test <= max_in_[id];
880  // Take step, if allowed
881  m->v_pert_[i] = m->in_bounds_[i] ? test : m->v_in_[i];
882  }
883  // Pass perturbed inputs to FMU
884  if (set_real(m->instance, get_ptr(m->vr_in_), n_known, get_ptr(m->v_pert_), n_known)) {
885  casadi_warning("Setting FMU variables failed");
886  return 1;
887  }
888  // Evaluate perturbed FMU
889  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, yk, n_unknown)) {
890  casadi_warning("Evaluation failed");
891  return 1;
892  }
893  // Post-process yk if there was any scaling
894  if (independent_seeds) {
895  for (size_t i = 0; i < n_unknown; ++i) {
896  // Variable id
897  size_t id = m->id_out_[i];
898  // Differentiation with respect to what variable
899  size_t wrt_id = m->wrt_.at(id);
900  // Find the corresponding input variable
901  size_t wrt_i;
902  for (wrt_i = 0; wrt_i < n_known; ++wrt_i) {
903  if (m->id_in_[wrt_i] == wrt_id) break;
904  }
905  // Check if in bounds
906  if (m->in_bounds_.at(wrt_i)) {
907  // Input was in bounds: Keep output, make dimensionless
908  yk[i] /= nominal_out_[m->id_out_[i]];
909  } else {
910  // Input was out of bounds: Discard output
911  yk[i] = nan;
912  }
913  }
914  }
915  }
916  // Restore FMU inputs
917  if (set_real(m->instance, get_ptr(m->vr_in_), n_known, get_ptr(m->v_in_), n_known)) {
918  casadi_warning("Setting FMU variables failed");
919  return 1;
920  }
921  // Step size
922  double h = m->self.step_;
923 
924  // Calculate FD approximation
925  finite_diff(m->self.fd_, yk_all, get_ptr(m->d_out_), h, n_unknown, eps);
926 
927  // If seeds are dependent, quick return
928  if (!independent_seeds) {
929  // Simpy copy the results to output (no validation)
930  for (size_t ind = 0; ind < m->id_out_.size(); ++ind) {
931  m->osens_[m->id_out_[ind]] = m->d_out_[ind];
932  }
933  return 0;
934  }
935 
936  // Collect requested variables
937  for (size_t ind = 0; ind < m->id_out_.size(); ++ind) {
938  // Variable id
939  size_t id = m->id_out_[ind];
940  // With respect to what variable
941  size_t wrt = m->wrt_[id];
942  // Find the corresponding input variable
943  size_t wrt_i;
944  for (wrt_i = 0; wrt_i < n_known; ++wrt_i) {
945  if (m->id_in_[wrt_i] == wrt) break;
946  }
947  // Nominal value
948  double n = nominal_out_[id];
949  // Get the value
950  double d_fd = m->d_out_[ind] * n;
951  // Correct sign, if necessary
952  if (m->flip_[wrt_i]) d_fd = -d_fd;
953  // Use FD instead of AD or to compare with AD
954  if (m->self.validate_forward_) {
955  // Value to compare with
956  double d_ad = m->osens_[id];
957  // Nominal value used as seed
958  d_ad /= nominal_in_[wrt];
959  d_fd /= nominal_in_[wrt];
960  // Is it a not a number?
961  bool d_is_nan = d_ad != d_ad;
962  // Magnitude of derivatives
963  double d_max = std::fmax(std::fabs(d_fd), std::fabs(d_ad));
964  // Check if NaN or error exceeds thresholds
965  if (d_is_nan || (d_max > n * m->self.abstol_
966  && std::fabs(d_ad - d_fd) > d_max * m->self.reltol_)) {
967  // Offset for printing the stencil
968  double off = m->fd_out_.at(ind + offset * n_unknown);
969  // Warning or add to file
970  std::stringstream ss;
971  if (m->self.validate_ad_file_.empty()) {
972  // Issue warning
973  ss << (d_is_nan ? "NaN" : "Inconsistent") << " derivatives of " << vn_out_[id]
974  << " w.r.t. " << desc_in(m, wrt) << ", got " << d_ad
975  << " for AD vs. " << d_fd << " for FD[" << to_string(m->self.fd_) << "].";
976  // Print the stencil:
977  ss << "\nValues for step size " << h << ": " << (n * off) << " + [";
978  for (casadi_int k = 0; k < n_points; ++k) {
979  if (k > 0) ss << ", ";
980  ss << (n * (m->fd_out_.at(ind + k * n_unknown) - off));
981  }
982  ss << "]";
983  // Issue warning
984  casadi_warning(ss.str());
985  } else {
986  // Output
987  ss << vn_out_[id] << " ";
988  // Input
989  ss << vn_in_[wrt] << " ";
990  // Value
991  ss << m->ibuf_[wrt] << " ";
992  // Noninal
993  ss << nominal_in_[wrt] << " ";
994  // Min
995  ss << min_in_[wrt] << " ";
996  // Max
997  ss << max_in_[wrt] << " ";
998  // AD
999  ss << d_ad << " ";
1000  // FD
1001  ss << d_fd << " ";
1002  // Step
1003  ss << h << " ";
1004  // Offset
1005  ss << off << " ";
1006  // Stencil
1007  ss << "[";
1008  for (casadi_int k = 0; k < n_points; ++k) {
1009  if (k > 0) ss << ",";
1010  ss << (n * (m->fd_out_.at(ind + k * n_unknown) - off));
1011  }
1012  ss << "]" << std::endl;
1013  // Append to file
1014  auto valfile_ptr = Filesystem::ofstream_ptr(m->self.validate_ad_file_,
1015  std::ios_base::app);
1016  std::ostream& valfile = *valfile_ptr;
1017  valfile << ss.str();
1018  }
1019  }
1020  } else {
1021  // Use instead of AD
1022  m->osens_[id] = d_fd;
1023  }
1024  }
1025  // Successful return
1026  return 0;
1027 }
1028 
1029 void FmuInternal::get_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
1030  for (casadi_int i = 0; i < nsens; ++i) {
1031  *v++ = m->osens_.at(*id++);
1032  }
1033 }
1034 
1035 void FmuInternal::get_fwd(FmuMemory* m, size_t ind, double* v) const {
1036  // Quick return if not needed
1037  if (!v) return;
1038  // Retrieve all sensitivities FIXME(@jaeandersson): should use compatible types
1039  for (size_t id : ored_[ind]) {
1040  casadi_int id2 = id;
1041  get_fwd(m, 1, &id2, v++);
1042  }
1043 }
1044 
1045 void FmuInternal::set_adj(FmuMemory* m, casadi_int nseed,
1046  const casadi_int* id, const double* v) const {
1047  for (casadi_int i = 0; i < nseed; ++i) {
1048  m->osens_.at(*id) = *v++;
1049  m->omarked_.at(*id) = true;
1050  id++;
1051  }
1052 }
1053 
1054 void FmuInternal::set_adj(FmuMemory* m, size_t ind, const double* v) const {
1055  // If seeds are zero, no need to add to seed buffers
1056  if (!v) return;
1057  // Pass all seeds FIXME(@jaeandersson): should use compatible types
1058  for (size_t id : ored_[ind]) {
1059  casadi_int id2 = id;
1060  set_adj(m, 1, &id2, v++);
1061  }
1062 }
1063 
1064 void FmuInternal::request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
1065  const casadi_int* wrt_id) const {
1066  for (casadi_int i = 0; i < nsens; ++i) {
1067  m->imarked_.at(*id) = true;
1068  m->wrt_.at(*id) = *wrt_id++;
1069  id++;
1070  }
1071 }
1072 
1073 void FmuInternal::request_adj(FmuMemory* m, casadi_int ind) const {
1074  // Request all sensitivities FIXME(@jaeandersson): should use compatible types
1075  casadi_int wrt_id = -1;
1076  for (size_t id : ired_[ind]) {
1077  casadi_int id2 = id;
1078  request_adj(m, 1, &id2, &wrt_id);
1079  }
1080 }
1081 
1082 void FmuInternal::get_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
1083  for (casadi_int i = 0; i < nsens; ++i) {
1084  *v++ = m->isens_.at(*id++);
1085  }
1086 }
1087 
1088 void FmuInternal::get_adj(FmuMemory* m, size_t ind, double* v) const {
1089  // Quick return if not needed
1090  if (!v) return;
1091  // Retrieve all sensitivities FIXME(@jaeandersson): should use compatible types
1092  for (size_t id : ired_[ind]) {
1093  casadi_int id2 = id;
1094  get_adj(m, 1, &id2, v++);
1095  }
1096 }
1097 
1098 int FmuInternal::discrete_states_iter(void* instance) const {
1099  // Helper function: update_discrete_states
1100  EventMemory eventmem;
1101  const size_t max_update_iter = 10;
1102  for (size_t update_iter = 0; update_iter < max_update_iter; ++update_iter) {
1103  if (update_discrete_states(instance, &eventmem)) {
1104  casadi_warning("update_discrete_states");
1105  return 1;
1106  }
1107  // Not implemented
1108  if (eventmem.discrete_states_need_update) {
1111  casadi_warning("Discrete state update not implemented");
1112  }
1113  }
1114  if (eventmem.terminate_simulation) {
1117  casadi_warning("Terminate simulation not implemented");
1118  }
1119  }
1123  casadi_warning("Nominals of continuous states not implemented");
1124  }
1125  }
1126  if (eventmem.values_of_continuous_states_changed) {
1129  casadi_warning("Values of continuous states not implemented");
1130  }
1131  }
1132  if (eventmem.next_event_time_defined) {
1135  casadi_warning("Next event time not implemented");
1136  }
1137  }
1138  // Successful return
1139  if (!eventmem.discrete_states_need_update) {
1140  return 0;
1141  }
1142  }
1143  // Too many iterations
1144  casadi_warning("Discrete state update failed");
1145  return 1;
1146 }
1147 
1149  // Ensure not already instantiated
1150  casadi_assert(m->instance == 0, "Already instantiated");
1151  // Create instance
1152  m->instance = instantiate();
1153  // Set all values
1154  if (set_values(m->instance)) {
1155  casadi_warning("FmuInternal::set_values failed");
1156  return 1;
1157  }
1158  // Initialization mode begins
1159  if (enter_initialization_mode(m->instance)) return 1;
1160  // Initialization mode ends
1161  if (exit_initialization_mode(m->instance)) return 1;
1162  // Initial event iteration
1163  if (discrete_states_iter(m->instance)) return 1;
1164  // Continuous-time mode
1165  if (enter_continuous_time_mode(m->instance)) return 1;
1166  // Allocate/reset input buffer
1167  m->ibuf_.resize(iind_.size());
1168  std::fill(m->ibuf_.begin(), m->ibuf_.end(), casadi::nan);
1169  // Allocate/reset output buffer
1170  m->obuf_.resize(oind_.size());
1171  std::fill(m->obuf_.begin(), m->obuf_.end(), casadi::nan);
1172  // Maximum input or output
1173  size_t max_io = std::max(iind_.size(), oind_.size());
1174  // Allocate/reset seeds
1175  m->isens_.resize(max_io);
1176  std::fill(m->isens_.begin(), m->isens_.end(), 0);
1177  // Allocate/reset sensitivities
1178  m->osens_.resize(max_io);
1179  std::fill(m->osens_.begin(), m->osens_.end(), 0);
1180  // Allocate/reset changed
1181  m->imarked_.resize(max_io);
1182  std::fill(m->imarked_.begin(), m->imarked_.end(), false);
1183  // Allocate/reset requested
1184  m->omarked_.resize(max_io);
1185  std::fill(m->omarked_.begin(), m->omarked_.end(), false);
1186  // Also allocate memory for corresponding Jacobian entry (for debugging)
1187  m->wrt_.resize(max_io);
1188  // Successful return
1189  return 0;
1190 }
1191 
1192 void FmuInternal::set(FmuMemory* m, size_t ind, const double* value) const {
1193  if (value) {
1194  // Argument is given
1195  for (size_t id : ired_[ind]) {
1196  if (*value != m->ibuf_.at(id)) {
1197  m->ibuf_.at(id) = *value;
1198  m->imarked_.at(id) = true;
1199  }
1200  value++;
1201  }
1202  } else {
1203  // Argument is null - all zeros
1204  for (size_t id : ired_[ind]) {
1205  if (0 != m->ibuf_.at(id)) {
1206  m->ibuf_.at(id) = 0;
1207  m->imarked_.at(id) = true;
1208  }
1209  }
1210  }
1211 }
1212 
1213 void FmuInternal::request(FmuMemory* m, size_t ind) const {
1214  for (size_t id : ored_[ind]) {
1215  // Mark as requested
1216  m->omarked_.at(id) = true;
1217  // Also log corresponding input index
1218  m->wrt_.at(id) = -1;
1219  }
1220 }
1221 
1223  // Gather inputs and outputs
1224  gather_io(m);
1225  // Number of inputs and outputs
1226  size_t n_set = m->id_in_.size();
1227  size_t n_out = m->id_out_.size();
1228  // Set all variables
1229  if (set_real(m->instance, get_ptr(m->vr_in_), n_set, get_ptr(m->v_in_), n_set)) {
1230  casadi_warning("Setting FMU variables failed");
1231  return 1;
1232  }
1233  // Quick return if nothing requested
1234  if (n_out == 0) return 0;
1235  // Calculate all variables
1236  m->v_out_.resize(n_out);
1237  if (get_real(m->instance, get_ptr(m->vr_out_), n_out, get_ptr(m->v_out_), n_out)) {
1238  casadi_warning("Evaluation failed");
1239  return 1;
1240  }
1241  // Collect requested variables
1242  auto it = m->v_out_.begin();
1243  for (size_t id : m->id_out_) {
1244  m->obuf_[id] = *it++;
1245  }
1246  // Successful return
1247  return 0;
1248 }
1249 
1250 void FmuInternal::get(FmuMemory* m, size_t ind, double* value) const {
1251  // Save to return
1252  for (size_t id : ored_[ind]) {
1253  *value++ = m->obuf_.at(id);
1254  }
1255 }
1256 
1257 void FmuInternal::set_fwd(FmuMemory* m, casadi_int nseed,
1258  const casadi_int* id, const double* v) const {
1259  for (casadi_int i = 0; i < nseed; ++i) {
1260  m->isens_.at(*id) = *v++;
1261  m->imarked_.at(*id) = true;
1262  id++;
1263  }
1264 }
1265 
1266 void FmuInternal::set_fwd(FmuMemory* m, size_t ind, const double* v) const {
1267  // If seeds are zero, no need to add to seed buffers
1268  if (!v) return;
1269  // Pass all seeds FIXME(@jaeandersson): should use compatible types
1270  for (size_t id : ired_[ind]) {
1271  casadi_int id2 = id;
1272  set_fwd(m, 1, &id2, v++);
1273  }
1274 }
1275 
1276 void FmuInternal::request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
1277  const casadi_int* wrt_id) const {
1278  for (casadi_int i = 0; i < nsens; ++i) {
1279  m->omarked_.at(*id) = true;
1280  m->wrt_.at(*id) = *wrt_id++;
1281  id++;
1282  }
1283 }
1284 
1285 void FmuInternal::request_fwd(FmuMemory* m, casadi_int ind) const {
1286  // Request all sensitivities FIXME(@jaeandersson): should use compatible types
1287  casadi_int wrt_id = -1;
1288  for (size_t id : ored_[ind]) {
1289  casadi_int id2 = id;
1290  request_fwd(m, 1, &id2, &wrt_id);
1291  }
1292 }
1293 
1295  // Collect input indices and corresponding value references and values
1296  m->id_in_.clear();
1297  m->vr_in_.clear();
1298  m->v_in_.clear();
1299  for (size_t id = 0; id < m->imarked_.size(); ++id) {
1300  if (m->imarked_[id]) {
1301  m->id_in_.push_back(id);
1302  m->vr_in_.push_back(vr_in_[id]);
1303  m->v_in_.push_back(m->ibuf_[id]);
1304  m->imarked_[id] = false;
1305  }
1306  }
1307  // Collect output indices, corresponding value references
1308  m->id_out_.clear();
1309  m->vr_out_.clear();
1310  for (size_t id = 0; id < m->omarked_.size(); ++id) {
1311  if (m->omarked_[id]) {
1312  m->id_out_.push_back(id);
1313  m->vr_out_.push_back(vr_out_[id]);
1314  m->omarked_[id] = false;
1315  }
1316  }
1317 }
1318 
1320  // Gather input and output indices
1321  gather_io(m);
1322  // Number of inputs and outputs
1323  size_t n_known = m->id_in_.size();
1324  size_t n_unknown = m->id_out_.size();
1325  // Get/clear seeds
1326  m->d_in_.clear();
1327  for (size_t id : m->id_in_) {
1328  m->d_in_.push_back(m->isens_[id]);
1329  m->isens_[id] = 0;
1330  }
1331  // Ensure at least one seed
1332  casadi_assert(n_known != 0, "No seeds");
1333  // Allocate result vectors
1334  m->v_out_.resize(n_unknown);
1335  m->d_out_.resize(n_unknown);
1336 }
1337 
1339  // Gather input and output indices
1340  gather_io(m);
1341  // Number of inputs and outputs
1342  size_t n_known = m->id_in_.size();
1343  size_t n_unknown = m->id_out_.size();
1344  // Get/clear seeds
1345  m->d_out_.clear();
1346  for (size_t id : m->id_out_) {
1347  m->d_out_.push_back(m->osens_[id]);
1348  m->osens_[id] = 0;
1349  }
1350  // Ensure at least one seed
1351  casadi_assert(n_unknown != 0, "No seeds");
1352  // Allocate result vectors
1353  m->v_in_.resize(n_known);
1354  m->d_in_.resize(n_known);
1355 }
1356 
1358  return (*this)->serialize(s);
1359 }
1360 
1363 }
1364 
1366  Fmu ret;
1367  ret.own(node);
1368  return ret;
1369 }
1370 
1372  serialize_type(s);
1373  serialize_body(s);
1374 }
1375 
1377  s.pack("FmuInternal::type", class_name());
1378 }
1379 
1381  s.version("FmuInternal", 4);
1382  s.pack("FmuInternal::name", name_);
1383  s.pack("FmuInternal::scheme_in", scheme_in_);
1384  s.pack("FmuInternal::scheme_out", scheme_out_);
1385  s.pack("FmuInternal::scheme", scheme_);
1386  s.pack("FmuInternal::aux", aux_);
1387  s.pack("FmuInternal::iind", iind_);
1388  s.pack("FmuInternal::iind_map", iind_map_);
1389  s.pack("FmuInternal::oind", oind_);
1390  s.pack("FmuInternal::oind_map", oind_map_);
1391  s.pack("FmuInternal::has_independent", has_independent_);
1392  s.pack("FmuInternal::nominal_in", nominal_in_);
1393  s.pack("FmuInternal::nominal_out", nominal_out_);
1394  s.pack("FmuInternal::min_in", min_in_);
1395  s.pack("FmuInternal::min_out", min_out_);
1396  s.pack("FmuInternal::max_in", max_in_);
1397  s.pack("FmuInternal::max_out", max_out_);
1398  s.pack("FmuInternal::vn_in", vn_in_);
1399  s.pack("FmuInternal::vn_out", vn_out_);
1400  s.pack("FmuInternal::vr_in", vr_in_);
1401  s.pack("FmuInternal::vr_out", vr_out_);
1402 
1403  s.pack("FmuInternal::value_in", value_in_);
1404  s.pack("FmuInternal::ired", ired_);
1405  s.pack("FmuInternal::ored", ored_);
1406  s.pack("FmuInternal::jac_sp", jac_sp_);
1407  s.pack("FmuInternal::hess_sp", hess_sp_);
1408 
1409  s.pack("FmuInternal::resource", resource_);
1410  s.pack("FmuInternal::fmutol", fmutol_);
1411  s.pack("FmuInternal::instance_name", instance_name_);
1412  s.pack("FmuInternal::instantiation_token", instantiation_token_);
1413  s.pack("FmuInternal::logging_on", logging_on_);
1414  s.pack("FmuInternal::number_of_event_indicators", number_of_event_indicators_);
1415  s.pack("FmuInternal::provides_directional_derivatives", provides_directional_derivatives_);
1416  s.pack("FmuInternal::provides_adjoint_derivatives", provides_adjoint_derivatives_);
1417  s.pack("FmuInternal::can_be_instantiated_only_once_per_process",
1419  s.pack("FmuInternal::nx", nx_);
1420  s.pack("FmuInternal::do_evaluation_dance", do_evaluation_dance_);
1421 }
1422 
1424  s.version("FmuInternal", 4);
1425  s.unpack("FmuInternal::name", name_);
1426  s.unpack("FmuInternal::scheme_in", scheme_in_);
1427  s.unpack("FmuInternal::scheme_out", scheme_out_);
1428  s.unpack("FmuInternal::scheme", scheme_);
1429  s.unpack("FmuInternal::aux", aux_);
1430  s.unpack("FmuInternal::iind", iind_);
1431  s.unpack("FmuInternal::iind_map", iind_map_);
1432  s.unpack("FmuInternal::oind", oind_);
1433  s.unpack("FmuInternal::oind_map", oind_map_);
1434  s.unpack("FmuInternal::has_independent", has_independent_);
1435  s.unpack("FmuInternal::nominal_in", nominal_in_);
1436  s.unpack("FmuInternal::nominal_out", nominal_out_);
1437  s.unpack("FmuInternal::min_in", min_in_);
1438  s.unpack("FmuInternal::min_out", min_out_);
1439  s.unpack("FmuInternal::max_in", max_in_);
1440  s.unpack("FmuInternal::max_out", max_out_);
1441  s.unpack("FmuInternal::vn_in", vn_in_);
1442  s.unpack("FmuInternal::vn_out", vn_out_);
1443  s.unpack("FmuInternal::vr_in", vr_in_);
1444  s.unpack("FmuInternal::vr_out", vr_out_);
1445 
1446  s.unpack("FmuInternal::value_in", value_in_);
1447  s.unpack("FmuInternal::ired", ired_);
1448  s.unpack("FmuInternal::ored", ored_);
1449  s.unpack("FmuInternal::jac_sp", jac_sp_);
1450  s.unpack("FmuInternal::hess_sp", hess_sp_);
1451 
1452  s.unpack("FmuInternal::resource", resource_);
1453  s.unpack("FmuInternal::fmutol", fmutol_);
1454  s.unpack("FmuInternal::instance_name", instance_name_);
1455  s.unpack("FmuInternal::instantiation_token", instantiation_token_);
1456  s.unpack("FmuInternal::logging_on", logging_on_);
1457  s.unpack("FmuInternal::number_of_event_indicators", number_of_event_indicators_);
1458  s.unpack("FmuInternal::provides_directional_derivatives", provides_directional_derivatives_);
1459  s.unpack("FmuInternal::provides_adjoint_derivatives", provides_adjoint_derivatives_);
1460  s.unpack("FmuInternal::can_be_instantiated_only_once_per_process",
1462  s.unpack("FmuInternal::nx", nx_);
1463  s.unpack("FmuInternal::do_evaluation_dance", do_evaluation_dance_);
1464 }
1465 
1467  std::string class_name;
1468  s.unpack("FmuInternal::type", class_name);
1469  if (class_name=="Fmu2") {
1470 #ifdef WITH_FMI2
1471  return Fmu2::deserialize(s);
1472 #else
1473  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
1474 #endif // WITH_FMI2
1475  } else if (class_name=="Fmu3") {
1476 #ifdef WITH_FMI3
1477 return Fmu3::deserialize(s);
1478 #else
1479  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
1480 #endif // WITH_FMI3
1481  } else {
1482  casadi_error("Cannot deserialize type '" + class_name + "'");
1483  }
1484 }
1485 
1486 } // namespace casadi
Sparsity jac_sparsity(const std::vector< size_t > &oind, const std::vector< size_t > &iind) const
Get Jacobian sparsity.
size_t n_variables() const
Length of variables array.
Variable & variable(size_t ind)
size_t size(Category cat) const
Number of indices with a particular category.
Sparsity hess_sparsity(const std::vector< size_t > &oind, const std::vector< size_t > &iind) const
Get what is known of the Hessian sparsity.
Helper class for Serialization.
void unpack(Sparsity &e)
Reconstruct an object from the input stream.
void version(const std::string &name, int v)
static std::string absolute(const std::string &path)
Definition: filesystem.cpp:78
static bool is_enabled()
Definition: filesystem.cpp:83
static std::unique_ptr< std::ostream > ofstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::out)
Definition: filesystem.cpp:115
Interface to a binary FMU, adhering to FMI version 2.0.
Definition: fmu2.hpp:42
static Fmu2 * deserialize(DeserializingStream &s)
Definition: fmu2.cpp:538
Interface to a binary FMU, adhering to FMI version 2.0.
Definition: fmu3.hpp:42
static Fmu3 * deserialize(DeserializingStream &s)
Definition: fmu3.cpp:522
std::string validate_ad_file_
Interface to binary FMU.
Definition: fmu_impl.hpp:61
bool warning_fired_values_of_continuous_states_changed_
Definition: fmu_impl.hpp:348
std::vector< std::string > scheme_out_
Definition: fmu_impl.hpp:290
std::string instantiation_token_
Definition: fmu_impl.hpp:306
std::vector< double > max_in_
Definition: fmu_impl.hpp:332
bool warning_fired_next_event_time_defined_
Definition: fmu_impl.hpp:349
std::string name_
Instance name.
Definition: fmu_impl.hpp:287
virtual int get_directional_derivative(void *instance, const unsigned int *vr_out, size_t n_out, const unsigned int *vr_in, size_t n_in, const double *seed, size_t n_seed, double *sensitivity, size_t n_sensitivity) const =0
bool provides_adjoint_derivatives_
Definition: fmu_impl.hpp:315
bool warning_fired_nominals_of_continuous_states_changed_
Definition: fmu_impl.hpp:347
std::vector< double > all_nominal_in(size_t i) const
Retreive nominal values.
Definition: fmu.cpp:687
std::vector< unsigned int > vr_out_
Definition: fmu_impl.hpp:334
std::string desc_in(FmuMemory *m, size_t id, bool more=true) const
Definition: fmu.cpp:716
virtual void free_instance(void *c) const =0
std::vector< std::string > vn_out_
Definition: fmu_impl.hpp:333
void set(FmuMemory *m, size_t ind, const double *value) const
Definition: fmu.cpp:1192
std::vector< size_t > iind_
Definition: fmu_impl.hpp:324
void serialize(SerializingStream &s) const
Definition: fmu.cpp:1371
virtual void finalize()
Definition: fmu.cpp:579
void disp(std::ostream &stream, bool more) const override
Print.
Definition: fmu.cpp:631
FmuInternal(const std::string &name, const std::vector< std::string > &scheme_in, const std::vector< std::string > &scheme_out, const std::map< std::string, std::vector< size_t >> &scheme, const std::vector< std::string > &aux)
Definition: fmu.cpp:440
std::vector< std::vector< size_t > > ired_
Definition: fmu_impl.hpp:340
std::vector< std::string > aux_
Definition: fmu_impl.hpp:294
std::vector< std::vector< size_t > > ored_
Definition: fmu_impl.hpp:340
std::map< std::string, std::vector< size_t > > scheme_
Definition: fmu_impl.hpp:291
int discrete_states_iter(void *instance) const
Definition: fmu.cpp:1098
virtual void serialize_body(SerializingStream &s) const
Definition: fmu.cpp:1380
virtual int get_aux(void *instance)=0
bool warning_fired_terminate_simulation_
Definition: fmu_impl.hpp:346
bool warning_fired_discrete_states_need_update_
Definition: fmu_impl.hpp:345
virtual int get_real(void *instance, const unsigned int *vr, size_t n_vr, double *values, size_t n_values) const =0
void get_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:1082
void gather_fwd(FmuMemory *m) const
Definition: fmu.cpp:1319
std::vector< double > nominal_out_
Definition: fmu_impl.hpp:330
void request(FmuMemory *m, size_t ind) const
Definition: fmu.cpp:1213
void gather_io(FmuMemory *m) const
Definition: fmu.cpp:1294
int eval_fd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:797
std::vector< std::string > vn_in_
Definition: fmu_impl.hpp:333
std::vector< size_t > oind_
Definition: fmu_impl.hpp:324
virtual void load_functions()=0
~FmuInternal() override
Destructor.
Definition: fmu.cpp:448
virtual int update_discrete_states(void *instance, EventMemory *eventmem) const =0
static FmuInternal * deserialize(DeserializingStream &s)
Definition: fmu.cpp:1466
void set_fwd(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:1257
virtual void serialize_type(SerializingStream &s) const
Definition: fmu.cpp:1376
void request_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:1064
std::vector< unsigned int > vr_in_
Definition: fmu_impl.hpp:334
virtual void * instantiate() const =0
virtual int exit_initialization_mode(void *instance) const =0
virtual int get_adjoint_derivative(void *instance, const unsigned int *vr_out, size_t n_out, const unsigned int *vr_in, size_t n_in, const double *seed, size_t n_seed, double *sensitivity, size_t n_sensitivity) const
Definition: fmu.cpp:572
virtual int set_values(void *instance) const =0
std::vector< double > min_out_
Definition: fmu_impl.hpp:331
bool can_be_instantiated_only_once_per_process_
Definition: fmu_impl.hpp:318
int eval_ad(FmuMemory *m) const
Definition: fmu.cpp:768
std::vector< double > nominal_in_
Definition: fmu_impl.hpp:330
std::vector< double > max_out_
Definition: fmu_impl.hpp:332
size_t index_out(const std::string &n) const
Definition: fmu.cpp:655
std::string resource_loc_
Definition: fmu_impl.hpp:297
std::vector< double > min_in_
Definition: fmu_impl.hpp:331
static std::string dll_suffix()
Definition: fmu.cpp:703
void set_adj(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:1045
std::vector< double > value_in_
Definition: fmu_impl.hpp:337
void get(FmuMemory *m, size_t id, double *value) const
Definition: fmu.cpp:1250
virtual int set_real(void *instance, const unsigned int *vr, size_t n_vr, const double *values, size_t n_values) const =0
casadi_int number_of_event_indicators_
Definition: fmu_impl.hpp:312
std::vector< double > all_nominal_out(size_t i) const
Retreive nominal values.
Definition: fmu.cpp:695
Importer li_
DLL.
Definition: fmu_impl.hpp:321
int eval_fwd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:729
virtual void init(const DaeBuilderInternal *dae)
Definition: fmu.cpp:451
size_t n_out() const
Get the number of scheme outputs.
Definition: fmu_impl.hpp:132
void get_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:1029
void gather_adj(FmuMemory *m) const
Definition: fmu.cpp:1338
virtual int init_mem(FmuMemory *m) const
Initalize memory block.
Definition: fmu.cpp:1148
virtual int enter_continuous_time_mode(void *instance) const =0
size_t index_in(const std::string &n) const
Definition: fmu.cpp:645
void request_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:1276
virtual int enter_initialization_mode(void *instance) const =0
Sparsity hess_sparsity(const std::vector< size_t > &r, const std::vector< size_t > &c) const
Definition: fmu.cpp:676
std::vector< size_t > oind_map_
Definition: fmu_impl.hpp:324
Sparsity jac_sparsity(const std::vector< size_t > &osub, const std::vector< size_t > &isub) const
Definition: fmu.cpp:665
std::vector< std::string > scheme_in_
Definition: fmu_impl.hpp:290
std::string instance_name_
Definition: fmu_impl.hpp:303
bool provides_directional_derivatives_
Definition: fmu_impl.hpp:315
virtual std::string system_infix() const =0
int eval_adj(FmuMemory *m) const
Definition: fmu.cpp:745
int eval(FmuMemory *m) const
Definition: fmu.cpp:1222
std::vector< size_t > iind_map_
Definition: fmu_impl.hpp:324
Interface to binary FMU.
Definition: fmu.hpp:62
void set(FmuMemory *m, size_t ind, const double *value) const
Definition: fmu.cpp:285
void get_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:358
const std::vector< size_t > & ored(size_t ind) const
Definition: fmu.cpp:163
static Fmu deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: fmu.cpp:1361
size_t index_out(const std::string &n) const
Definition: fmu.cpp:147
int eval_adj(FmuMemory *m) const
Definition: fmu.cpp:407
Fmu()
Default constructor.
Definition: fmu.cpp:48
double nominal_out(size_t ind) const
Definition: fmu.cpp:179
void get_stats(FmuMemory *m, Dict *stats, const std::vector< std::string > &name_in, const InputStruct *in) const
Get stats.
Definition: fmu.cpp:431
Sparsity hess_sparsity(const std::vector< size_t > &r, const std::vector< size_t > &c) const
Definition: fmu.cpp:260
bool can_be_instantiated_only_once_per_process() const
Does the FMU declare restrictions on instantiation?
Definition: fmu.cpp:243
std::vector< double > all_nominal_out(size_t ind) const
Definition: fmu.cpp:211
bool provides_adjoint_derivatives() const
Does the FMU provide support for adjoint directional derivatives.
Definition: fmu.cpp:235
Sparsity jac_sparsity(const std::vector< size_t > &osub, const std::vector< size_t > &isub) const
Definition: fmu.cpp:251
int eval_fwd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:350
double nominal_in(size_t ind) const
Definition: fmu.cpp:171
size_t index_in(const std::string &n) const
Definition: fmu.cpp:139
FmuMemory * alloc_mem(const FmuFunction &f) const
Create memory block.
Definition: fmu.cpp:93
void get_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:415
double max_in(size_t ind) const
Definition: fmu.cpp:195
const std::string & name() const
Name of the instance.
Definition: fmu.cpp:105
void set_fwd(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:317
static Fmu create(FmuInternal *node)
Create from node.
Definition: fmu.cpp:1365
size_t n_out() const
Get the number of scheme outputs.
Definition: fmu.cpp:131
const std::string & instance_name() const
Name of the FMU.
Definition: fmu.cpp:114
std::vector< double > all_nominal_in(size_t ind) const
Definition: fmu.cpp:203
double min_in(size_t ind) const
Definition: fmu.cpp:187
void free_mem(void *mem) const
Free memory block.
Definition: fmu.cpp:97
FmuInternal * get() const
Definition: fmu.cpp:101
FmuInternal * operator->()
Definition: fmu.cpp:85
void set_adj(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:374
int init_mem(FmuMemory *m) const
Initalize memory block.
Definition: fmu.cpp:268
bool provides_directional_derivatives() const
Does the FMU provide support for forward directional derivatives.
Definition: fmu.cpp:227
int eval(FmuMemory *m) const
Definition: fmu.cpp:301
const std::vector< size_t > & ired(size_t ind) const
Definition: fmu.cpp:155
void request_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:390
size_t n_in() const
Get the number of scheme inputs.
Definition: fmu.cpp:123
void free_instance(void *instance) const
Definition: fmu.cpp:277
void request(FmuMemory *m, size_t ind) const
Definition: fmu.cpp:293
void request_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:333
std::string desc_in(FmuMemory *m, size_t id, bool more=true) const
Definition: fmu.cpp:219
void serialize(SerializingStream &s) const
Serialize an object.
Definition: fmu.cpp:1357
SharedObjectInternal * get() const
Get a const pointer to the node.
SharedObjectInternal * operator->() const
Access a member function or object.
Importer.
Definition: importer.hpp:86
const std::string & path() const
Get path for a consumer.
Definition: resource.cpp:70
Helper class for Serialization.
void version(const std::string &name, int v)
void pack(const Sparsity &e)
Serializes an object to the output stream.
virtual std::string class_name() const =0
Readable name of the internal class.
General sparsity class.
Definition: sparsity.hpp:106
Sparsity sub(const std::vector< casadi_int > &rr, const std::vector< casadi_int > &cc, std::vector< casadi_int > &mapping, bool ind1=false) const
Get a submatrix.
Definition: sparsity.cpp:334
The casadi namespace.
Definition: archiver.cpp:28
const double eps
Machine epsilon.
Definition: calculus.hpp:56
FmuApi
Which C API.
Definition: fmu.hpp:47
casadi_int n_fd_points(FdMode v)
Length of FD stencil, including unperturbed input.
casadi_int fd_offset(FdMode v)
Offset for FD stencil, i.e. index of unperturbed input.
double sign(double x)
Sign function, note that sign(nan) == nan.
Definition: calculus.hpp:264
void casadi_copy(const T1 *x, casadi_int n, T1 *y)
COPY: y <-x.
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
std::string to_string(TypeFmi2 v)
const double nan
Not a number.
Definition: calculus.hpp:53
T * get_ptr(std::vector< T > &v)
Get a pointer to the data contained in the vector.
CASADI_EXPORT void finite_diff(FdMode v, const T1 **yk, T1 *J, T1 h, casadi_int n_y, T1 smoothing)
Calculate FD estimate.
bool discrete_states_need_update
Definition: fmu_impl.hpp:39
bool next_event_time_defined
Definition: fmu_impl.hpp:43
bool nominals_of_continuous_states_changed
Definition: fmu_impl.hpp:41
bool values_of_continuous_states_changed
Definition: fmu_impl.hpp:42
std::vector< double > d_in_
std::vector< size_t > id_in_
std::vector< double > obuf_
std::vector< double > isens_
std::vector< bool > in_bounds_
const FmuFunction & self
std::vector< double > osens_
std::vector< size_t > wrt_
std::vector< double > d_out_
std::vector< unsigned int > vr_in_
std::vector< double > v_out_
std::vector< bool > flip_
std::vector< double > v_pert_
std::vector< size_t > id_out_
std::vector< double > fd_out_
std::vector< bool > omarked_
std::vector< double > v_in_
std::vector< double > ibuf_
std::vector< bool > imarked_
std::vector< unsigned int > vr_out_
Holds expressions and meta-data corresponding to a physical quantity evolving in time.
std::string name
Name of the variable.