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 #include "archiver_impl.hpp"
31 #include "importer.hpp"
32 
33 #ifdef WITH_FMI2
34 #include "fmu2.hpp"
35 #endif // WITH_FMI2
36 
37 #ifdef WITH_FMI3
38 #include "fmu3.hpp"
39 #endif // WITH_FMI3
40 
41 namespace casadi {
42 
43 // Throw informative error message
44 #define THROW_ERROR(FNAME, WHAT) \
45 throw CasadiException("Error in Fmu::" FNAME " for '" + this->name() + "' "\
46  "[" + this->class_name() + "] at " + CASADI_WHERE + ":\n"\
47  + std::string(WHAT));
48 
49 
51 }
52 
53 Fmu::Fmu(const std::string& name, FmuApi api, const DaeBuilderInternal* dae,
54  const std::vector<std::string>& scheme_in,
55  const std::vector<std::string>& scheme_out,
56  const std::map<std::string, std::vector<size_t>>& scheme,
57  const std::vector<std::string>& aux) {
58  if (api == FmuApi::FMI2) {
59 #ifdef WITH_FMI2
60  // Create
61  own(new Fmu2(name, scheme_in, scheme_out, scheme, aux));
62 #else // WITH_FMI2
63  // No compilation support
64  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
65 #endif // WITH_FMI2
66  } else if (api == FmuApi::FMI3) {
67 #ifdef WITH_FMI3
68  // Create
69  own(new Fmu3(name, scheme_in, scheme_out, scheme, aux));
70 #else // WITH_FMI3
71  // No compilation support
72  casadi_error("CasADi was not compiled with WITH_FMI3=ON.");
73 #endif // WITH_FMI3
74  } else {
75  // Not supported
76  casadi_error("Unsupported FMU API: " + to_string(api));
77  }
78  // Initialize
79  try {
80  (*this)->init(dae);
81  (*this)->finalize();
82  } catch(std::exception& e) {
83  THROW_ERROR("init", e.what());
84  }
85 }
86 
88  return static_cast<FmuInternal*>(SharedObject::operator->());
89 }
90 
91 const FmuInternal* Fmu::operator->() const {
92  return static_cast<const FmuInternal*>(SharedObject::operator->());
93 }
94 
96  return (*this)->alloc_mem(f);
97 }
98 
99 void Fmu::free_mem(void *mem) const {
100  (*this)->free_mem(mem);
101 }
102 
104  return static_cast<FmuInternal*>(SharedObject::get());
105 }
106 
107 const std::string& Fmu::name() const {
108  if (is_null()) {
109  static std::string null = "null";
110  return null;
111  } else {
112  return (*this)->name_;
113  }
114 }
115 
116 const std::string& Fmu::instance_name() const {
117  if (is_null()) {
118  static std::string null = "null";
119  return null;
120  } else {
121  return (*this)->instance_name_;
122  }
123 }
124 
125 size_t Fmu::n_in() const {
126  try {
127  return (*this)->n_in();
128  } catch(std::exception& e) {
129  THROW_ERROR("n_in", e.what());
130  }
131 }
132 
133 size_t Fmu::n_out() const {
134  try {
135  return (*this)->n_out();
136  } catch(std::exception& e) {
137  THROW_ERROR("n_out", e.what());
138  }
139 }
140 
141 size_t Fmu::index_in(const std::string& n) const {
142  try {
143  return (*this)->index_in(n);
144  } catch(std::exception& e) {
145  THROW_ERROR("index_in", e.what());
146  }
147 }
148 
149 size_t Fmu::index_out(const std::string& n) const {
150  try {
151  return (*this)->index_out(n);
152  } catch(std::exception& e) {
153  THROW_ERROR("index_out", e.what());
154  }
155 }
156 
157 const std::vector<size_t>& Fmu::ired(size_t ind) const {
158  try {
159  return (*this)->ired_.at(ind);
160  } catch(std::exception& e) {
161  THROW_ERROR("ired", e.what());
162  }
163 }
164 
165 const std::vector<size_t>& Fmu::ored(size_t ind) const {
166  try {
167  return (*this)->ored_.at(ind);
168  } catch(std::exception& e) {
169  THROW_ERROR("ored", e.what());
170  }
171 }
172 
173 double Fmu::nominal_in(size_t ind) const {
174  try {
175  return (*this)->nominal_in_.at(ind);
176  } catch(std::exception& e) {
177  THROW_ERROR("nominal_in", e.what());
178  }
179 }
180 
181 double Fmu::nominal_out(size_t ind) const {
182  try {
183  return (*this)->nominal_out_.at(ind);
184  } catch(std::exception& e) {
185  THROW_ERROR("nominal_out", e.what());
186  }
187 }
188 
189 double Fmu::min_in(size_t ind) const {
190  try {
191  return (*this)->min_in_.at(ind);
192  } catch(std::exception& e) {
193  THROW_ERROR("min_in", e.what());
194  }
195 }
196 
197 double Fmu::max_in(size_t ind) const {
198  try {
199  return (*this)->max_in_.at(ind);
200  } catch(std::exception& e) {
201  THROW_ERROR("max_in", e.what());
202  }
203 }
204 
205 std::vector<double> Fmu::all_nominal_in(size_t ind) const {
206  try {
207  return (*this)->all_nominal_in(ind);
208  } catch(std::exception& e) {
209  THROW_ERROR("all_nominal_in", e.what());
210  }
211 }
212 
213 std::vector<double> Fmu::all_nominal_out(size_t ind) const {
214  try {
215  return (*this)->all_nominal_out(ind);
216  } catch(std::exception& e) {
217  THROW_ERROR("all_nominal_out", e.what());
218  }
219 }
220 
221 std::string Fmu::desc_in(FmuMemory* m, size_t id, bool more) const {
222  try {
223  return (*this)->desc_in(m, id, more);
224  } catch(std::exception& e) {
225  THROW_ERROR("desc_in", e.what());
226  }
227 }
228 
230  try {
231  return (*this)->provides_directional_derivatives_;
232  } catch(std::exception& e) {
233  THROW_ERROR("provides_directional_derivatives", e.what());
234  }
235 }
236 
238  try {
239  return (*this)->provides_adjoint_derivatives_;
240  } catch(std::exception& e) {
241  THROW_ERROR("provides_adjoint_derivatives", e.what());
242  }
243 }
244 
246  try {
247  return (*this)->can_be_instantiated_only_once_per_process_;
248  } catch(std::exception& e) {
249  THROW_ERROR("can_be_instantiated_only_once_per_process", e.what());
250  }
251 }
252 
253 Sparsity Fmu::jac_sparsity(const std::vector<size_t>& osub,
254  const std::vector<size_t>& isub) const {
255  try {
256  return (*this)->jac_sparsity(osub, isub);
257  } catch(std::exception& e) {
258  THROW_ERROR("jac_sparsity", e.what());
259  }
260 }
261 
262 Sparsity Fmu::hess_sparsity(const std::vector<size_t>& r, const std::vector<size_t>& c) const {
263  try {
264  return (*this)->hess_sparsity(r, c);
265  } catch(std::exception& e) {
266  THROW_ERROR("hess_sparsity", e.what());
267  }
268 }
269 
270 int Fmu::init_mem(FmuMemory* m) const {
271  try {
272  return (*this)->init_mem(m);
273  } catch(std::exception& e) {
274  THROW_ERROR("init_mem", e.what());
275  return 1;
276  }
277 }
278 
279 void Fmu::free_instance(void* instance) const {
280  try {
281  (*this)->free_instance(instance);
282  } catch(std::exception& e) {
283  THROW_ERROR("free_instance", e.what());
284  }
285 }
286 
287 void Fmu::set(FmuMemory* m, size_t ind, const double* value) const {
288  try {
289  (*this)->set(m, ind, value);
290  } catch(std::exception& e) {
291  THROW_ERROR("set", e.what());
292  }
293 }
294 
295 void Fmu::request(FmuMemory* m, size_t ind) const {
296  try {
297  (*this)->request(m, ind);
298  } catch(std::exception& e) {
299  THROW_ERROR("request", e.what());
300  }
301 }
302 
303 int Fmu::eval(FmuMemory* m) const {
304  try {
305  return (*this)->eval(m);
306  } catch(std::exception& e) {
307  THROW_ERROR("eval", e.what());
308  }
309 }
310 
311 void Fmu::get(FmuMemory* m, size_t id, double* value) const {
312  try {
313  (*this)->get(m, id, value);
314  } catch(std::exception& e) {
315  THROW_ERROR("get", e.what());
316  }
317 }
318 
319 void Fmu::set_fwd(FmuMemory* m, casadi_int nseed, const casadi_int* id, const double* v) const {
320  try {
321  (*this)->set_fwd(m, nseed, id, v);
322  } catch(std::exception& e) {
323  THROW_ERROR("set_fwd", e.what());
324  }
325 }
326 
327 void Fmu::set_fwd(FmuMemory* m, size_t ind, const double* v) const {
328  try {
329  (*this)->set_fwd(m, ind, v);
330  } catch(std::exception& e) {
331  THROW_ERROR("set_fwd", e.what());
332  }
333 }
334 
335 void Fmu::request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
336  const casadi_int* wrt_id) const {
337  try {
338  (*this)->request_fwd(m, nsens, id, wrt_id);
339  } catch(std::exception& e) {
340  THROW_ERROR("request_fwd", e.what());
341  }
342 }
343 
344 void Fmu::request_fwd(FmuMemory* m, casadi_int ind) const {
345  try {
346  (*this)->request_fwd(m, ind);
347  } catch(std::exception& e) {
348  THROW_ERROR("request_fwd", e.what());
349  }
350 }
351 
352 int Fmu::eval_fwd(FmuMemory* m, bool independent_seeds) const {
353  try {
354  return (*this)->eval_fwd(m, independent_seeds);
355  } catch(std::exception& e) {
356  THROW_ERROR("eval_fwd", e.what());
357  }
358 }
359 
360 void Fmu::get_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
361  try {
362  (*this)->get_fwd(m, nsens, id, v);
363  } catch(std::exception& e) {
364  THROW_ERROR("get_fwd", e.what());
365  }
366 }
367 
368 void Fmu::get_fwd(FmuMemory* m, size_t ind, double* v) const {
369  try {
370  (*this)->get_fwd(m, ind, v);
371  } catch(std::exception& e) {
372  THROW_ERROR("get_fwd", e.what());
373  }
374 }
375 
376 void Fmu::set_adj(FmuMemory* m, casadi_int nseed, const casadi_int* id, const double* v) const {
377  try {
378  (*this)->set_adj(m, nseed, id, v);
379  } catch(std::exception& e) {
380  THROW_ERROR("set_adj", e.what());
381  }
382 }
383 
384 void Fmu::set_adj(FmuMemory* m, size_t ind, const double* v) const {
385  try {
386  (*this)->set_adj(m, ind, v);
387  } catch(std::exception& e) {
388  THROW_ERROR("set_adj", e.what());
389  }
390 }
391 
392 void Fmu::request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
393  const casadi_int* wrt_id) const {
394  try {
395  (*this)->request_adj(m, nsens, id, wrt_id);
396  } catch(std::exception& e) {
397  THROW_ERROR("request_adj", e.what());
398  }
399 }
400 
401 void Fmu::request_adj(FmuMemory* m, casadi_int ind) const {
402  try {
403  (*this)->request_adj(m, ind);
404  } catch(std::exception& e) {
405  THROW_ERROR("request_adj", e.what());
406  }
407 }
408 
409 int Fmu::eval_adj(FmuMemory* m) const {
410  try {
411  return (*this)->eval_adj(m);
412  } catch(std::exception& e) {
413  THROW_ERROR("eval_adj", e.what());
414  }
415 }
416 
417 void Fmu::get_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
418  try {
419  (*this)->get_adj(m, nsens, id, v);
420  } catch(std::exception& e) {
421  THROW_ERROR("get_adj", e.what());
422  }
423 }
424 
425 void Fmu::get_adj(FmuMemory* m, size_t ind, double* v) const {
426  try {
427  (*this)->get_adj(m, ind, v);
428  } catch(std::exception& e) {
429  THROW_ERROR("get_adj", e.what());
430  }
431 }
432 
433 void Fmu::get_stats(FmuMemory* m, Dict* stats,
434  const std::vector<std::string>& name_in, const InputStruct* in) const {
435  try {
436  (*this)->get_stats(m, stats, name_in, in);
437  } catch(std::exception& e) {
438  THROW_ERROR("get_stats", e.what());
439  }
440 }
441 
442 FmuInternal::FmuInternal(const std::string& name,
443  const std::vector<std::string>& scheme_in,
444  const std::vector<std::string>& scheme_out,
445  const std::map<std::string, std::vector<size_t>>& scheme,
446  const std::vector<std::string>& aux)
447  : name_(name), scheme_in_(scheme_in), scheme_out_(scheme_out), scheme_(scheme), aux_(aux) {
448 }
449 
451 }
452 
454  // Copy info from DaeBuilder
455  resource_ = dae->resource_;
456  fmutol_ = dae->fmutol_;
459  logging_on_ = dae->debug_;
464  start_time_ = dae->start_time_;
465  nx_ = dae->size(Category::X);
466  do_evaluation_dance_ = dae->generation_tool_.rfind("Simulink", 0) == 0;
467 
468  // Mark input indices
469  size_t numel = 0;
470  std::vector<bool> lookup(dae->n_variables(), false);
471  for (auto&& n : scheme_in_) {
472  casadi_assert(scheme_.find(n) != scheme_.end(), "Unsupported input: '" + n + "'");
473  for (size_t i : scheme_.at(n)) {
474  casadi_assert(!lookup.at(i), "Duplicate variable: " + dae->variable(i).name);
475  lookup.at(i) = true;
476  numel++;
477  }
478  }
479  // Input mappings
480  iind_.reserve(numel);
481  iind_map_.reserve(lookup.size());
482  for (size_t k = 0; k < lookup.size(); ++k) {
483  if (lookup[k]) {
484  iind_map_.push_back(iind_.size());
485  iind_.push_back(k);
486  } else {
487  iind_map_.push_back(-1);
488  }
489  }
490  // Mark output indices
491  numel = 0;
492  std::fill(lookup.begin(), lookup.end(), false);
493  for (auto&& n : scheme_out_) {
494  casadi_assert(scheme_.find(n) != scheme_.end(), "Unsupported output: '" + n + "'");
495  for (size_t i : scheme_.at(n)) {
496  casadi_assert(!lookup.at(i), "Duplicate variable: " + dae->variable(i).name);
497  lookup.at(i) = true;
498  numel++;
499  }
500  }
501  // Construct mappings
502  oind_.reserve(numel);
503  oind_map_.reserve(lookup.size());
504  for (size_t k = 0; k < lookup.size(); ++k) {
505  if (lookup[k]) {
506  oind_map_.push_back(oind_.size());
507  oind_.push_back(k);
508  } else {
509  oind_map_.push_back(-1);
510  }
511  }
512  // Inputs
513  ired_.resize(scheme_in_.size());
514  for (size_t i = 0; i < ired_.size(); ++i) {
515  auto&& s = scheme_.at(scheme_in_[i]);
516  ired_[i].resize(s.size());
517  for (size_t k = 0; k < s.size(); ++k) {
518  ired_[i][k] = iind_map_.at(s[k]);
519  }
520  }
521  // Outputs
522  ored_.resize(scheme_out_.size());
523  for (size_t i = 0; i < ored_.size(); ++i) {
524  auto&& s = scheme_.at(scheme_out_[i]);
525  ored_[i].resize(s.size());
526  for (size_t k = 0; k < s.size(); ++k) {
527  ored_[i][k] = oind_map_.at(s[k]);
528  }
529  }
530 
531  // Is there an independent variable?
532  has_independent_ = false;
533 
534  // Collect meta information for inputs
535  nominal_in_.reserve(iind_.size());
536  min_in_.reserve(iind_.size());
537  max_in_.reserve(iind_.size());
538  vn_in_.reserve(iind_.size());
539  vr_in_.reserve(iind_.size());
540  for (size_t i : iind_) {
541  const Variable& v = dae->variable(i);
542  nominal_in_.push_back(v.nominal);
543  min_in_.push_back(v.min);
544  max_in_.push_back(v.max);
545  vn_in_.push_back(v.name);
546  vr_in_.push_back(v.value_reference);
548  if (i != 0) casadi_error("Independent variable must be the first model variable");
549  has_independent_ = true;
550  independent_vr_ = vr_in_.back();
551  }
552  }
553  // Collect meta information for outputs
554  nominal_out_.reserve(oind_.size());
555  min_out_.reserve(oind_.size());
556  max_out_.reserve(oind_.size());
557  vn_out_.reserve(oind_.size());
558  vr_out_.reserve(oind_.size());
559  for (size_t i : oind_) {
560  const Variable& v = dae->variable(i);
561  nominal_out_.push_back(v.nominal);
562  min_out_.push_back(v.min);
563  max_out_.push_back(v.max);
564  vn_out_.push_back(v.name);
565  vr_out_.push_back(v.value_reference);
566  }
567 
568  // Numerical values for inputs
569  value_in_.resize(iind_.size());
570 
571  // Get Jacobian sparsity information
572  jac_sp_ = dae->jac_sparsity(oind_, iind_);
573 
574  // Get Hessian sparsity information
576 
577  // Path to resource directory
580  resource_loc_ += "/resources";
581 
582  // Use forward slashes (supported by all file systems)
583  std::replace(resource_loc_.begin(), resource_loc_.end(), '\\', '/');
584 }
585 
586 int FmuInternal::get_adjoint_derivative(void* instance, const unsigned int* vr_out, size_t n_out,
587  const unsigned int* vr_in, size_t n_in, const double* seed, size_t n_seed,
588  double* sensitivity, size_t n_sensitivity) const {
589  casadi_error("Adjoint derivatives not supported for " + class_name());
590  return 1;
591 }
592 
599  // Load DLL
600  std::string instance_name_no_dot = instance_name_;
601  std::replace(instance_name_no_dot.begin(), instance_name_no_dot.end(), '.', '_');
602  std::string dll_path = resource_.path() + "/binaries/" + system_infix()
603  + "/" + instance_name_no_dot + dll_suffix();
604  li_ = Importer(dll_path, "dll");
605 
606  // Get FMI C functions
607  load_functions();
608 
609  // Create a temporary instance
610  void* c = instantiate();
611  // Set all values
612  if (set_values(c)) {
613  casadi_error("FmuInternal::set_values failed");
614  }
615  // Initialization mode begins
616  if (enter_initialization_mode(c)) {
617  casadi_error("FmuInternal::enter_initialization_mode failed");
618  }
619  // Get input values
620  if (!value_in_.empty()) {
621  // Value references
622  const unsigned int* vr = get_ptr(vr_in_);
623  size_t n_vr = vr_in_.size();
624  // Values
625  double* value = get_ptr(value_in_);
626  size_t n_value = value_in_.size();
627  // Set time variable, if any
628  if (has_independent_) {
629  *value = start_time_;
630  // Skip when getting remaining inputs
631  vr++;
632  n_vr--;
633  value++;
634  n_value--;
635  }
636  // Set remaining
637  if (n_value > 0) {
638  if (get_real(c, vr, n_vr, value, n_value)) {
639  casadi_error("FmuInternal::get_in failed");
640  }
641  }
642  }
643  // Get auxilliary variables
644  if (get_aux(c)) {
645  casadi_error("FmuInternal::get_aux failed");
646  }
647  // Free memory
648  free_instance(c);
649 }
650 
651 void FmuInternal::disp(std::ostream& stream, bool more) const {
652  (void)more; // unused
653  stream << name_ << " " << class_name();
654 }
655 
656 std::string to_string(FmuApi v) {
657  switch (v) {
658  case FmuApi::FMI2: return "fmi2";
659  case FmuApi::FMI3: return "fmi3";
660  default: break;
661  }
662  return "";
663 }
664 
665 size_t FmuInternal::index_in(const std::string& n) const {
666  // Linear search for the input
667  for (size_t i = 0; i < scheme_in_.size(); ++i) {
668  if (scheme_in_[i] == n) return i;
669  }
670  // Not found
671  casadi_error("No such input: " + n);
672  return -1;
673 }
674 
675 size_t FmuInternal::index_out(const std::string& n) const {
676  // Linear search for the input
677  for (size_t i = 0; i < scheme_out_.size(); ++i) {
678  if (scheme_out_[i] == n) return i;
679  }
680  // Not found
681  casadi_error("No such output: " + n);
682  return -1;
683 }
684 
685 Sparsity FmuInternal::jac_sparsity(const std::vector<size_t>& osub,
686  const std::vector<size_t>& isub) const {
687  // Convert to casadi_int type
688  std::vector<casadi_int> osub1(osub.begin(), osub.end());
689  std::vector<casadi_int> isub1(isub.begin(), isub.end());
690  // Index mapping (not used)
691  std::vector<casadi_int> mapping;
692  // Get selection
693  return jac_sp_.sub(osub1, isub1, mapping);
694 }
695 
696 Sparsity FmuInternal::hess_sparsity(const std::vector<size_t>& r,
697  const std::vector<size_t>& c) const {
698  // Convert to casadi_int type
699  std::vector<casadi_int> r1(r.begin(), r.end());
700  std::vector<casadi_int> c1(c.begin(), c.end());
701  // Index mapping (not used)
702  std::vector<casadi_int> mapping;
703  // Get selection
704  return hess_sp_.sub(r1, c1, mapping);
705 }
706 
707 std::vector<double> FmuInternal::all_nominal_in(size_t i) const {
708  auto&& ind = ired_.at(i);
709  std::vector<double> n;
710  n.reserve(ind.size());
711  for (size_t k : ind) n.push_back(nominal_in_.at(k));
712  return n;
713 }
714 
715 std::vector<double> FmuInternal::all_nominal_out(size_t i) const {
716  auto&& ind = ored_.at(i);
717  std::vector<double> n;
718  n.reserve(ind.size());
719  for (size_t k : ind) n.push_back(nominal_out_.at(k));
720  return n;
721 }
722 
723 std::string FmuInternal::dll_suffix() {
724 #if defined(_WIN32)
725  // Windows system
726  return ".dll";
727 #elif defined(__APPLE__)
728  // OSX
729  return ".dylib";
730 #else
731  // Linux
732  return ".so";
733 #endif
734 }
735 
737  // Architecture
738  std::string arch;
739 #if defined(__arm64__) || defined(__aarch64__)
740  // ARM 64-bit Architecture
741  arch = "aarch64";
742 #elif __arm__
743  if (sizeof(void*) == 4) {
744  // ARM 32-bit Architecture
745  arch = "aarch32";
746  } else {
747  // ARM 64-bit Architecture
748  arch = "aarch64";
749  }
750 #elif defined(__ppc64__) || defined(__powerpc64__)
751  // PowerPC 64-bit Architecture
752  arch = "ppc64";
753 #elif defined(__ppc__) || defined(__powerpc__)
754  // PowerPC 32-bit Architecture
755  arch = "ppc";
756 #else
757  if (sizeof(void*) == 4) {
758  // Intel/AMD x86 32-bit
759  arch = "x86";
760  } else {
761  // Intel/AMD x86 64-bit
762  arch = "x86_64";
763  }
764 #endif
765  // Operating system
766  std::string sys;
767 #if defined(_WIN32)
768  // Microsoft Windows
769  sys = "windows";
770 #elif defined(__APPLE__)
771  // Darwin (macOS, iOS, watchOS, tvOS, audioOS)
772  sys = "darwin";
773 #else
774  // Linux
775  sys = "linux";
776 #endif
777  // Return platform tuple, according to Section 2.5.1.4.1. of the FMI 3 specification
778  return arch + "-" + sys;
779 }
780 
781 Dict FmuInternal::compile_fmu(const std::string& name, const Dict& files, const Dict& opts) {
782  // Options
783  Dict compiler_opts;
784  std::string compiler_plugin = "shell";
785  std::vector<std::string> include_dirs;
786  for (auto&& op : opts) {
787  if (op.first == "compiler") {
788  compiler_plugin = op.second.to_string();
789  } else if (op.first == "compiler_options") {
790  compiler_opts = op.second;
791  } else if (op.first == "include_dirs") {
792  include_dirs = op.second.to_string_vector();
793  } else {
794  casadi_error("No such option: " + op.first);
795  }
796  }
797  // The C sources to compile are the .c entries of the export_fmu map (flat in CWD)
798  std::vector<std::string> csources;
799  for (auto&& kv : files) {
800  const std::string& local = kv.first;
801  if (local.size() > 2 && local.substr(local.size() - 2) == ".c") csources.push_back(local);
802  }
803  // Amalgamation translation unit: a single .c that #includes every generated source,
804  // because the shell Importer compiles exactly one source file. The compile runs in
805  // the working directory, so quoted includes resolve against the loose files there.
806  // This is a build scratch file, NOT FMU content, so it is removed below.
807  std::string amalg = name + "_all.c";
808  {
809  auto f = Filesystem::ofstream_ptr(amalg);
810  for (const std::string& c : csources) *f << "#include \"" << c << "\"\n";
811  }
812  // Compile the amalgamation into a shared library via the Importer plugin.
813  // Pass include dirs through the OS-agnostic 'include_dirs' option (the plugin
814  // prefixes each with the compiler's own include flag: -I on gcc/clang, /I on MSVC).
815  Dict cop = compiler_opts;
816  if (!include_dirs.empty()) cop["include_dirs"] = include_dirs;
817  Importer compiler(amalg, compiler_plugin, cop);
818  // Lift the binary to a stable path before the Importer destructor removes it, then
819  // discard the amalgamation scratch file (compilation is done once the Importer exists)
820  std::string dll = name + dll_suffix();
821  Filesystem::copy_file(compiler.library(), dll);
822  Filesystem::remove(amalg);
823  // Augment the file map with the compiled binary
824  // (FMI-3 layout: binaries/<dll_infix>/<modelIdentifier><suffix>)
825  Dict ret = files;
826  ret[dll] = "binaries/" + fmi3_dll_infix() + "/" + name + dll_suffix();
827  return ret;
828 }
829 
830 std::string FmuInternal::pack_fmu(const Dict& files, const std::string& path) {
831  casadi_assert(Archiver::has_plugin("libzip"),
832  "pack_fmu requires libzip. Compile CasADi with WITH_LIBZIP=ON.");
833  // The {local_file -> archive path} map is exactly the set of zip entries: no staging
834  // directory or copies required.
835  std::vector<std::pair<std::string, std::string>> entries;
836  for (auto&& kv : files) {
837  std::string arc = kv.second.to_string();
838  if (arc.substr(0, 2) == "./") arc = arc.substr(2); // zip entries are root-relative
839  entries.push_back({kv.first, arc});
840  }
841  std::string out = path;
842  if (out.size() < 4 || out.substr(out.size() - 4) != ".fmu") out += ".fmu";
843  casadi_assert(Archiver::getPlugin("libzip").exposed.pack_entries(entries, out),
844  "Packing FMU '" + out + "' failed.");
845  // Clean up the loose files
846  for (auto&& e : entries) Filesystem::remove(e.first);
847  return out;
848 }
849 
850 std::string FmuInternal::desc_in(FmuMemory* m, size_t id, bool more) const {
851  // Create description
852  if (more) {
853  // Detailed description
854  std::stringstream ss;
855  ss << vn_in_[id] << " = " << m->ibuf_[id] << " (nominal " << nominal_in_[id]
856  << ", min " << min_in_[id] << ", max " << max_in_[id] << ")";
857  return ss.str();
858  } else {
859  return vn_in_[id];
860  }
861 }
862 
863 int FmuInternal::eval_fwd(FmuMemory* m, bool independent_seeds) const {
864  // Gather input and output indices
865  gather_fwd(m);
866  // Calculate derivatives using FMU directional derivative support
868  // Evaluate using AD
869  if (eval_ad(m)) return 1;
870  }
871  // Calculate derivatives using finite differences
873  // Evaluate using FD
874  if (eval_fd(m, independent_seeds)) return 1;
875  }
876  return 0;
877 }
878 
880  // Gather input and output indices
881  gather_adj(m);
882  // Quick return if nothing to be calculated
883  if (m->id_in_.size() == 0) return 0;
884  // Check if no seeds
885  int flag;
886  if (m->id_out_.size() == 0) {
887  // Sensitivities are zero, trivially
888  std::fill(m->d_in_.begin(), m->d_in_.end(), 0);
889  flag = 0;
890  } else {
891  // Evaluate adjoint derivatives
892  m->n_get_adjoint++;
893  auto start = std::chrono::high_resolution_clock::now();
895  get_ptr(m->vr_out_), m->id_out_.size(), get_ptr(m->vr_in_), m->id_in_.size(),
896  get_ptr(m->d_out_), m->id_out_.size(), get_ptr(m->d_in_), m->id_in_.size());
897  auto stop = std::chrono::high_resolution_clock::now();
898  m->t_get_adjoint += std::chrono::duration_cast<std::chrono::microseconds>(
899  stop - start).count() / 1e6;
900  }
901  // Collect requested variables
902  if (!flag) {
903  auto it = m->d_in_.begin();
904  for (size_t id : m->id_in_) {
905  m->isens_[id] = *it++;
906  }
907  }
908  // Return results of the evaluation
909  return flag;
910 }
911 
913  // Number of inputs and outputs
914  size_t n_known = m->id_in_.size();
915  size_t n_unknown = m->id_out_.size();
916  // Quick return if nothing to be calculated
917  if (n_unknown == 0) return 0;
918  // Quick return if no seeds
919  if (n_known == 0) {
920  std::fill(m->d_out_.begin(), m->d_out_.end(), 0);
921  return 0;
922  }
923  // Evalute (should not be necessary)
924  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, get_ptr(m->v_out_), n_unknown, m)) {
925  casadi_warning("FMU evaluation failed");
926  return 1;
927  }
928  // Evaluate directional derivatives
929  m->n_get_directional++;
930  auto start = std::chrono::high_resolution_clock::now();
931  int flag = get_directional_derivative(m->instance,
932  get_ptr(m->vr_out_), n_unknown, get_ptr(m->vr_in_), n_known,
933  get_ptr(m->d_in_), n_known, get_ptr(m->d_out_), n_unknown);
934  auto stop = std::chrono::high_resolution_clock::now();
935  m->t_get_directional += std::chrono::duration_cast<std::chrono::microseconds>(
936  stop - start).count() / 1e6;
937  // Collect requested variables
938  if (!flag) {
939  auto it = m->d_out_.begin();
940  for (size_t id : m->id_out_) {
941  m->osens_[id] = *it++;
942  }
943  }
944  // Return result of the evaluation
945  return flag;
946 }
947 
948 int FmuInternal::eval_fd(FmuMemory* m, bool independent_seeds) const {
949  // Number of inputs and outputs
950  size_t n_known = m->id_in_.size();
951  size_t n_unknown = m->id_out_.size();
952  // Quick return if nothing to be calculated
953  if (n_unknown == 0) return 0;
954  // Quick return if no seeds
955  if (n_known == 0) {
956  std::fill(m->d_out_.begin(), m->d_out_.end(), 0);
957  return 0;
958  }
959  // Evalute (should not be necessary)
960  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, get_ptr(m->v_out_), n_unknown, m)) {
961  casadi_warning("Evaluating FMU failed");
962  return 1;
963  }
964  // Make outputs dimensionless
965  for (size_t k = 0; k < n_unknown; ++k) m->v_out_[k] /= nominal_out_[m->id_out_[k]];
966  // Number of points in FD stencil
967  casadi_int n_points = n_fd_points(m->self.fd_);
968  // Offset for points
969  casadi_int offset = fd_offset(m->self.fd_);
970  // Memory for perturbed outputs
971  m->fd_out_.resize(n_points * n_unknown);
972  // Which inputs are in bounds
973  m->in_bounds_.resize(n_known);
974  // Memory for perturbed inputs
975  m->v_pert_.resize(n_known);
976  // Do any any inputs need flipping?
977  m->flip_.resize(n_known);
978  size_t first_flip = -1;
979  for (size_t i = 0; i < n_known; ++i) {
980  // Try to take step
981  double test = m->v_in_[i] + m->self.step_ * m->d_in_[i];
982  // Check if in bounds
983  size_t id = m->id_in_[i];
984  if (test >= min_in_[id] && test <= max_in_[id]) {
985  // Positive perturbation is fine
986  m->flip_[i] = false;
987  } else {
988  // Try negative direction instead
989  test = m->v_in_[i] - m->self.step_ * m->d_in_[i];
990  casadi_assert(test >= min_in_[id] && test <= max_in_[id],
991  "Cannot perturb " + vn_in_[id] + " at " + str(m->v_in_[i]) + ", min " + str(min_in_[id])
992  + ", max " + str(max_in_[id]) + ", nominal " + str(nominal_in_[id]));
993  m->flip_[i] = true;
994  if (first_flip == size_t(-1)) first_flip = i;
995  }
996  }
997  // If seeds are not independent, we have to flip the sign for all of the seeds or none
998  if (first_flip != size_t(-1) && !independent_seeds) {
999  // Flip the rest of the seeds
1000  for (size_t i = 0; i < n_known; ++i) {
1001  if (!m->flip_[i]) {
1002  // Test negative direction
1003  double test = m->v_in_[i] - m->self.step_ * m->d_in_[i];
1004  size_t id = m->id_in_[i];
1005  casadi_assert(test >= min_in_[id] && test <= max_in_[id],
1006  "Cannot perturb both " + vn_in_[id] + " and " + vn_in_[first_flip]);
1007  // Flip it too
1008  m->flip_[i] = true;
1009  }
1010  }
1011  }
1012  // All perturbed outputs
1013  const double* yk_all[5] = {nullptr};
1014 
1015  // Calculate all perturbed outputs
1016  for (casadi_int k = 0; k < n_points; ++k) {
1017  // Where to save the perturbed outputs
1018  double* yk = &m->fd_out_[n_unknown * k];
1019  casadi_assert_dev(k < 5);
1020  yk_all[k] = yk;
1021  // If unperturbed output, quick return
1022  if (k == offset) {
1023  casadi_copy(get_ptr(m->v_out_), n_unknown, yk);
1024  continue;
1025  }
1026  // Perturbation size
1027  double pert = (k - offset) * m->self.step_;
1028  // Perturb inputs, if allowed
1029  for (size_t i = 0; i < n_known; ++i) {
1030  // Try to take step
1031  double sign = m->flip_[i] ? -1 : 1;
1032  double test = m->v_in_[i] + pert * sign * m->d_in_[i];
1033  // Check if in bounds
1034  size_t id = m->id_in_[i];
1035  m->in_bounds_[i] = test >= min_in_[id] && test <= max_in_[id];
1036  // Take step, if allowed
1037  m->v_pert_[i] = m->in_bounds_[i] ? test : m->v_in_[i];
1038  }
1039  // Pass perturbed inputs to FMU
1040  if (set_all(m, get_ptr(m->v_pert_), m->v_pert_.size())) return 1;
1041  // Evaluate perturbed FMU
1042  if (get_all(m, yk, n_unknown)) return 1;
1043  // Post-process yk if there was any scaling
1044  if (independent_seeds) {
1045  for (size_t i = 0; i < n_unknown; ++i) {
1046  // Variable id
1047  size_t id = m->id_out_[i];
1048  // Differentiation with respect to what variable
1049  size_t wrt_id = m->wrt_.at(id);
1050  // Find the corresponding input variable
1051  size_t wrt_i;
1052  for (wrt_i = 0; wrt_i < n_known; ++wrt_i) {
1053  if (m->id_in_[wrt_i] == wrt_id) break;
1054  }
1055  // Check if in bounds
1056  if (m->in_bounds_.at(wrt_i) && (m->self.fd_flip_ || !m->flip_[wrt_i])) {
1057  // Input was in bounds: Keep output, make dimensionless
1058  yk[i] /= nominal_out_[m->id_out_[i]];
1059  } else {
1060  // Input was out of bounds: Discard output
1061  yk[i] = nan;
1062  }
1063  }
1064  }
1065  }
1066  // Restore FMU inputs
1067  if (set_all(m, get_ptr(m->v_in_), m->v_in_.size())) return 1;
1068  // Step size
1069  double h = m->self.step_;
1070 
1071  // Calculate FD approximation
1072  finite_diff(m->self.fd_, yk_all, get_ptr(m->d_out_), h, n_unknown, eps);
1073 
1074  // If seeds are dependent, quick return
1075  if (!independent_seeds) {
1076  // Simpy copy the results to output (no validation)
1077  for (size_t ind = 0; ind < m->id_out_.size(); ++ind) {
1078  m->osens_[m->id_out_[ind]] = m->d_out_[ind];
1079  }
1080  return 0;
1081  }
1082 
1083  // Collect requested variables
1084  for (size_t ind = 0; ind < m->id_out_.size(); ++ind) {
1085  // Variable id
1086  size_t id = m->id_out_[ind];
1087  // With respect to what variable
1088  size_t wrt = m->wrt_[id];
1089  // Find the corresponding input variable
1090  size_t wrt_i;
1091  for (wrt_i = 0; wrt_i < n_known; ++wrt_i) {
1092  if (m->id_in_[wrt_i] == wrt) break;
1093  }
1094  // Nominal value
1095  double n = nominal_out_[id];
1096  // Get the value
1097  double d_fd = m->d_out_[ind] * n;
1098  // Correct sign, if necessary
1099  if (m->flip_[wrt_i]) d_fd = -d_fd;
1100  // Use FD instead of AD or to compare with AD
1101  if (m->self.validate_forward_) {
1102  // Value to compare with
1103  double d_ad = m->osens_[id];
1104  // Nominal value used as seed
1105  d_ad /= nominal_in_[wrt];
1106  d_fd /= nominal_in_[wrt];
1107  // Is it a not a number?
1108  bool d_is_nan = d_ad != d_ad;
1109  // Magnitude of derivatives
1110  double d_max = std::fmax(std::fabs(d_fd), std::fabs(d_ad));
1111  // Check if NaN or error exceeds thresholds
1112  if (d_is_nan || (d_max > n * m->self.abstol_
1113  && std::fabs(d_ad - d_fd) > d_max * m->self.reltol_)) {
1114  // Offset for printing the stencil
1115  double off = m->fd_out_.at(ind + offset * n_unknown);
1116  // Warning or add to file
1117  std::stringstream ss;
1118  if (m->self.validate_ad_file_.empty()) {
1119  // Issue warning
1120  ss << (d_is_nan ? "NaN" : "Inconsistent") << " derivatives of " << vn_out_[id]
1121  << " w.r.t. " << desc_in(m, wrt) << ", got " << d_ad
1122  << " for AD vs. " << d_fd << " for FD[" << to_string(m->self.fd_) << "].";
1123  // Print the stencil:
1124  ss << "\nValues for step size " << h << ": " << (n * off) << " + [";
1125  for (casadi_int k = 0; k < n_points; ++k) {
1126  if (k > 0) ss << ", ";
1127  ss << (n * (m->fd_out_.at(ind + k * n_unknown) - off));
1128  }
1129  ss << "]";
1130  // Issue warning
1131  casadi_warning(ss.str());
1132  } else {
1133  // Output
1134  ss << vn_out_[id] << " ";
1135  // Input
1136  ss << vn_in_[wrt] << " ";
1137  // Value
1138  ss << m->ibuf_[wrt] << " ";
1139  // Noninal
1140  ss << nominal_in_[wrt] << " ";
1141  // Min
1142  ss << min_in_[wrt] << " ";
1143  // Max
1144  ss << max_in_[wrt] << " ";
1145  // AD
1146  ss << d_ad << " ";
1147  // FD
1148  ss << d_fd << " ";
1149  // Step
1150  ss << h << " ";
1151  // Offset
1152  ss << off << " ";
1153  // Stencil
1154  ss << "[";
1155  for (casadi_int k = 0; k < n_points; ++k) {
1156  if (k > 0) ss << ",";
1157  ss << (n * (m->fd_out_.at(ind + k * n_unknown) - off));
1158  }
1159  ss << "]" << std::endl;
1160  // Append to file
1161  auto valfile_ptr = Filesystem::ofstream_ptr(m->self.validate_ad_file_,
1162  std::ios_base::app);
1163  std::ostream& valfile = *valfile_ptr;
1164  valfile << ss.str();
1165  }
1166  }
1167  } else {
1168  // Use instead of AD
1169  m->osens_[id] = d_fd;
1170  }
1171  }
1172  // Successful return
1173  return 0;
1174 }
1175 
1176 void FmuInternal::get_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
1177  for (casadi_int i = 0; i < nsens; ++i) {
1178  *v++ = m->osens_.at(*id++);
1179  }
1180 }
1181 
1182 void FmuInternal::get_fwd(FmuMemory* m, size_t ind, double* v) const {
1183  // Quick return if not needed
1184  if (!v) return;
1185  // Retrieve all sensitivities FIXME(@jaeandersson): should use compatible types
1186  for (size_t id : ored_[ind]) {
1187  casadi_int id2 = id;
1188  get_fwd(m, 1, &id2, v++);
1189  }
1190 }
1191 
1192 void FmuInternal::set_adj(FmuMemory* m, casadi_int nseed,
1193  const casadi_int* id, const double* v) const {
1194  for (casadi_int i = 0; i < nseed; ++i) {
1195  if (*v != 0.) {
1196  m->osens_.at(*id) = *v;
1197  m->omarked_.at(*id) = true;
1198  }
1199  id++;
1200  v++;
1201  }
1202 }
1203 
1204 void FmuInternal::set_adj(FmuMemory* m, size_t ind, const double* v) const {
1205  // If seeds are zero, no need to add to seed buffers
1206  if (!v) return;
1207  // Pass all seeds FIXME(@jaeandersson): should use compatible types
1208  for (size_t id : ored_[ind]) {
1209  casadi_int id2 = id;
1210  set_adj(m, 1, &id2, v++);
1211  }
1212 }
1213 
1214 void FmuInternal::request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
1215  const casadi_int* wrt_id) const {
1216  for (casadi_int i = 0; i < nsens; ++i) {
1217  m->imarked_.at(*id) = true;
1218  m->wrt_.at(*id) = wrt_id ? *wrt_id++ : -1;
1219  id++;
1220  }
1221 }
1222 
1223 void FmuInternal::request_adj(FmuMemory* m, casadi_int ind) const {
1224  // Request all sensitivities FIXME(@jaeandersson): should use compatible types
1225  casadi_int wrt_id = -1;
1226  for (size_t id : ired_[ind]) {
1227  casadi_int id2 = id;
1228  request_adj(m, 1, &id2, &wrt_id);
1229  }
1230 }
1231 
1232 void FmuInternal::get_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
1233  for (casadi_int i = 0; i < nsens; ++i) {
1234  *v++ = m->isens_.at(*id++);
1235  }
1236 }
1237 
1238 void FmuInternal::get_adj(FmuMemory* m, size_t ind, double* v) const {
1239  // Quick return if not needed
1240  if (!v) return;
1241  // Retrieve all sensitivities FIXME(@jaeandersson): should use compatible types
1242  for (size_t id : ired_[ind]) {
1243  casadi_int id2 = id;
1244  get_adj(m, 1, &id2, v++);
1245  }
1246 }
1247 
1248 int FmuInternal::discrete_states_iter(void* instance) const {
1249  // Helper function: update_discrete_states
1250  EventMemory eventmem;
1251  const size_t max_update_iter = 10;
1252  for (size_t update_iter = 0; update_iter < max_update_iter; ++update_iter) {
1253  if (update_discrete_states(instance, &eventmem)) {
1254  casadi_warning("update_discrete_states");
1255  return 1;
1256  }
1257  // Not implemented
1258  if (eventmem.discrete_states_need_update) {
1261  casadi_warning("Discrete state update not implemented");
1262  }
1263  }
1264  if (eventmem.terminate_simulation) {
1267  casadi_warning("Terminate simulation not implemented");
1268  }
1269  }
1273  casadi_warning("Nominals of continuous states not implemented");
1274  }
1275  }
1276  if (eventmem.values_of_continuous_states_changed) {
1279  casadi_warning("Values of continuous states not implemented");
1280  }
1281  }
1282  if (eventmem.next_event_time_defined) {
1285  casadi_warning("Next event time not implemented");
1286  }
1287  }
1288  // Successful return
1289  if (!eventmem.discrete_states_need_update) {
1290  return 0;
1291  }
1292  }
1293  // Too many iterations
1294  casadi_warning("Discrete state update failed");
1295  return 1;
1296 }
1297 
1299  // Ensure not already instantiated
1300  casadi_assert(m->instance == nullptr, "Already instantiated");
1301  // Create instance
1302  m->instance = instantiate();
1303  // Set all values
1304  if (set_values(m->instance)) {
1305  casadi_warning("FmuInternal::set_values failed");
1306  return 1;
1307  }
1308  // Initialization mode begins
1309  if (enter_initialization_mode(m->instance)) return 1;
1310  // Initialization mode ends
1311  if (exit_initialization_mode(m->instance)) return 1;
1312  // Initial event iteration
1313  if (discrete_states_iter(m->instance)) return 1;
1314  // Continuous-time mode
1315  if (enter_continuous_time_mode(m->instance)) return 1;
1316  // Allocate/reset input buffer
1317  m->ibuf_.resize(iind_.size());
1318  std::fill(m->ibuf_.begin(), m->ibuf_.end(), casadi::nan);
1319  // Allocate/reset output buffer
1320  m->obuf_.resize(oind_.size());
1321  std::fill(m->obuf_.begin(), m->obuf_.end(), casadi::nan);
1322  // Maximum input or output
1323  size_t max_io = std::max(iind_.size(), oind_.size());
1324  // Allocate/reset seeds
1325  m->isens_.resize(max_io);
1326  std::fill(m->isens_.begin(), m->isens_.end(), 0);
1327  // Allocate/reset sensitivities
1328  m->osens_.resize(max_io);
1329  std::fill(m->osens_.begin(), m->osens_.end(), 0);
1330  // Allocate/reset changed
1331  m->imarked_.resize(max_io);
1332  std::fill(m->imarked_.begin(), m->imarked_.end(), false);
1333  // Allocate/reset requested
1334  m->omarked_.resize(max_io);
1335  std::fill(m->omarked_.begin(), m->omarked_.end(), false);
1336  // Also allocate memory for corresponding Jacobian entry (for debugging)
1337  m->wrt_.resize(max_io);
1338  // Successful return
1339  return 0;
1340 }
1341 
1342 void FmuInternal::set(FmuMemory* m, size_t ind, const double* value) const {
1343  if (value) {
1344  // Argument is given
1345  for (size_t id : ired_[ind]) {
1346  if (*value != m->ibuf_.at(id)) {
1347  m->ibuf_.at(id) = *value;
1348  m->imarked_.at(id) = true;
1349  }
1350  value++;
1351  }
1352  } else {
1353  // Argument is null - all zeros
1354  for (size_t id : ired_[ind]) {
1355  if (0 != m->ibuf_.at(id)) {
1356  m->ibuf_.at(id) = 0;
1357  m->imarked_.at(id) = true;
1358  }
1359  }
1360  }
1361 }
1362 
1363 void FmuInternal::request(FmuMemory* m, size_t ind) const {
1364  for (size_t id : ored_[ind]) {
1365  // Mark as requested
1366  m->omarked_.at(id) = true;
1367  // Also log corresponding input index
1368  m->wrt_.at(id) = -1;
1369  }
1370 }
1371 
1372 int FmuInternal::set_all(FmuMemory* m, const double* values, size_t n_values) const {
1373  // Quick return if nothing to set
1374  if (n_values == 0) return 0;
1375  // Value references
1376  const unsigned int* vr = get_ptr(m->vr_in_);
1377  size_t n_vr = m->vr_in_.size();
1378  // Set time variable, if any
1379  if (has_independent_ && *vr == independent_vr_) {
1380  // Update FMU time
1381  if (set_time(m->instance, *values)) return 1;
1382  // Skip when setting remaining variables
1383  vr++;
1384  n_vr--;
1385  values++;
1386  n_values--;
1387  // Quick return if nothing left to set
1388  if (n_vr == 0) return 0;
1389  }
1390 
1391  // Set remaining variables
1392  if (set_real(m->instance, vr, n_vr, values, n_values)) {
1393  casadi_warning("Setting FMU variables failed");
1394  return 1;
1395  }
1396 
1397  return 0;
1398 }
1399 
1400 int FmuInternal::get_all(FmuMemory* m, double* values, size_t n_values) const {
1401  // Quick return if nothing to get
1402  if (n_values == 0) return 0;
1403  // Retrieve from FMU
1404  m->n_get_all++;
1405  auto start = std::chrono::high_resolution_clock::now();
1406  int flag = get_real(m->instance, get_ptr(m->vr_out_), m->vr_out_.size(), values, n_values, m);
1407  auto stop = std::chrono::high_resolution_clock::now();
1408  m->t_get_all += std::chrono::duration_cast<std::chrono::microseconds>(
1409  stop - start).count() / 1e6;
1410  // Return result of the evaluation
1411  return flag;
1412 }
1413 
1415  // Gather inputs and outputs
1416  gather_io(m);
1417  // Pass inputs to FMU
1418  if (set_all(m, get_ptr(m->v_in_), m->v_in_.size())) return 1;
1419  // Get outputs from FMU
1420  if (get_all(m, get_ptr(m->v_out_), m->v_out_.size())) return 1;
1421  // Collect requested variables
1422  auto it = m->v_out_.begin();
1423  for (size_t id : m->id_out_) {
1424  m->obuf_[id] = *it++;
1425  }
1426  // Successful return
1427  return 0;
1428 }
1429 
1430 void FmuInternal::get(FmuMemory* m, size_t ind, double* value) const {
1431  // Save to return
1432  for (size_t id : ored_[ind]) {
1433  *value++ = m->obuf_.at(id);
1434  }
1435 }
1436 
1437 void FmuInternal::set_fwd(FmuMemory* m, casadi_int nseed,
1438  const casadi_int* id, const double* v) const {
1439  for (casadi_int i = 0; i < nseed; ++i) {
1440  if (*v != 0.) {
1441  m->isens_.at(*id) = *v;
1442  m->imarked_.at(*id) = true;
1443  }
1444  id++;
1445  v++;
1446  }
1447 }
1448 
1449 void FmuInternal::set_fwd(FmuMemory* m, size_t ind, const double* v) const {
1450  // If seeds are zero, no need to add to seed buffers
1451  if (!v) return;
1452  // Pass all seeds FIXME(@jaeandersson): should use compatible types
1453  for (size_t id : ired_[ind]) {
1454  casadi_int id2 = id;
1455  set_fwd(m, 1, &id2, v++);
1456  }
1457 }
1458 
1459 void FmuInternal::request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
1460  const casadi_int* wrt_id) const {
1461  for (casadi_int i = 0; i < nsens; ++i) {
1462  m->omarked_.at(*id) = true;
1463  m->wrt_.at(*id) = *wrt_id++;
1464  id++;
1465  }
1466 }
1467 
1468 void FmuInternal::request_fwd(FmuMemory* m, casadi_int ind) const {
1469  // Request all sensitivities FIXME(@jaeandersson): should use compatible types
1470  casadi_int wrt_id = -1;
1471  for (size_t id : ored_[ind]) {
1472  casadi_int id2 = id;
1473  request_fwd(m, 1, &id2, &wrt_id);
1474  }
1475 }
1476 
1478  // Collect input indices and corresponding value references and values
1479  m->id_in_.clear();
1480  m->vr_in_.clear();
1481  m->v_in_.clear();
1482  for (size_t id = 0; id < m->imarked_.size(); ++id) {
1483  if (m->imarked_[id]) {
1484  m->id_in_.push_back(id);
1485  m->vr_in_.push_back(vr_in_[id]);
1486  m->v_in_.push_back(m->ibuf_[id]);
1487  m->imarked_[id] = false;
1488  }
1489  }
1490  // Collect output indices, corresponding value references
1491  m->id_out_.clear();
1492  m->vr_out_.clear();
1493  m->v_out_.clear();
1494  for (size_t id = 0; id < m->omarked_.size(); ++id) {
1495  if (m->omarked_[id]) {
1496  m->id_out_.push_back(id);
1497  m->vr_out_.push_back(vr_out_[id]);
1498  m->v_out_.push_back(nan);
1499  m->omarked_[id] = false;
1500  }
1501  }
1502 }
1503 
1505  // Gather input and output indices
1506  gather_io(m);
1507  // Number of outputs
1508  size_t n_unknown = m->id_out_.size();
1509  // Get/clear seeds
1510  m->d_in_.clear();
1511  for (size_t id : m->id_in_) {
1512  m->d_in_.push_back(m->isens_[id]);
1513  m->isens_[id] = 0;
1514  }
1515  // Allocate result vectors
1516  m->v_out_.resize(n_unknown);
1517  m->d_out_.resize(n_unknown);
1518 }
1519 
1521  // Gather input and output indices
1522  gather_io(m);
1523  // Number of inputs and outputs
1524  size_t n_known = m->id_in_.size();
1525  // Get/clear seeds
1526  m->d_out_.clear();
1527  for (size_t id : m->id_out_) {
1528  m->d_out_.push_back(m->osens_[id]);
1529  m->osens_[id] = 0;
1530  }
1531  // Allocate result vectors
1532  m->v_in_.resize(n_known);
1533  m->d_in_.resize(n_known);
1534 }
1535 
1537  (*this)->serialize(s);
1538 }
1539 
1542 }
1543 
1545  Fmu ret;
1546  ret.own(node);
1547  return ret;
1548 }
1549 
1551  serialize_type(s);
1552  serialize_body(s);
1553 }
1554 
1556  s.pack("FmuInternal::type", class_name());
1557 }
1558 
1560  s.version("FmuInternal", 4);
1561  s.pack("FmuInternal::name", name_);
1562  s.pack("FmuInternal::scheme_in", scheme_in_);
1563  s.pack("FmuInternal::scheme_out", scheme_out_);
1564  s.pack("FmuInternal::scheme", scheme_);
1565  s.pack("FmuInternal::aux", aux_);
1566  s.pack("FmuInternal::iind", iind_);
1567  s.pack("FmuInternal::iind_map", iind_map_);
1568  s.pack("FmuInternal::oind", oind_);
1569  s.pack("FmuInternal::oind_map", oind_map_);
1570  s.pack("FmuInternal::has_independent", has_independent_);
1571  s.pack("FmuInternal::nominal_in", nominal_in_);
1572  s.pack("FmuInternal::nominal_out", nominal_out_);
1573  s.pack("FmuInternal::min_in", min_in_);
1574  s.pack("FmuInternal::min_out", min_out_);
1575  s.pack("FmuInternal::max_in", max_in_);
1576  s.pack("FmuInternal::max_out", max_out_);
1577  s.pack("FmuInternal::vn_in", vn_in_);
1578  s.pack("FmuInternal::vn_out", vn_out_);
1579  s.pack("FmuInternal::vr_in", vr_in_);
1580  s.pack("FmuInternal::vr_out", vr_out_);
1581 
1582  s.pack("FmuInternal::value_in", value_in_);
1583  s.pack("FmuInternal::ired", ired_);
1584  s.pack("FmuInternal::ored", ored_);
1585  s.pack("FmuInternal::jac_sp", jac_sp_);
1586  s.pack("FmuInternal::hess_sp", hess_sp_);
1587 
1588  s.pack("FmuInternal::resource", resource_);
1589  s.pack("FmuInternal::fmutol", fmutol_);
1590  s.pack("FmuInternal::instance_name", instance_name_);
1591  s.pack("FmuInternal::instantiation_token", instantiation_token_);
1592  s.pack("FmuInternal::logging_on", logging_on_);
1593  s.pack("FmuInternal::number_of_event_indicators", number_of_event_indicators_);
1594  s.pack("FmuInternal::provides_directional_derivatives", provides_directional_derivatives_);
1595  s.pack("FmuInternal::provides_adjoint_derivatives", provides_adjoint_derivatives_);
1596  s.pack("FmuInternal::can_be_instantiated_only_once_per_process",
1598  s.pack("FmuInternal::start_time", start_time_);
1599  s.pack("FmuInternal::nx", nx_);
1600  s.pack("FmuInternal::do_evaluation_dance", do_evaluation_dance_);
1601 }
1602 
1604  s.version("FmuInternal", 4);
1605  s.unpack("FmuInternal::name", name_);
1606  s.unpack("FmuInternal::scheme_in", scheme_in_);
1607  s.unpack("FmuInternal::scheme_out", scheme_out_);
1608  s.unpack("FmuInternal::scheme", scheme_);
1609  s.unpack("FmuInternal::aux", aux_);
1610  s.unpack("FmuInternal::iind", iind_);
1611  s.unpack("FmuInternal::iind_map", iind_map_);
1612  s.unpack("FmuInternal::oind", oind_);
1613  s.unpack("FmuInternal::oind_map", oind_map_);
1614  s.unpack("FmuInternal::has_independent", has_independent_);
1615  s.unpack("FmuInternal::nominal_in", nominal_in_);
1616  s.unpack("FmuInternal::nominal_out", nominal_out_);
1617  s.unpack("FmuInternal::min_in", min_in_);
1618  s.unpack("FmuInternal::min_out", min_out_);
1619  s.unpack("FmuInternal::max_in", max_in_);
1620  s.unpack("FmuInternal::max_out", max_out_);
1621  s.unpack("FmuInternal::vn_in", vn_in_);
1622  s.unpack("FmuInternal::vn_out", vn_out_);
1623  s.unpack("FmuInternal::vr_in", vr_in_);
1624  s.unpack("FmuInternal::vr_out", vr_out_);
1625 
1626  s.unpack("FmuInternal::value_in", value_in_);
1627  s.unpack("FmuInternal::ired", ired_);
1628  s.unpack("FmuInternal::ored", ored_);
1629  s.unpack("FmuInternal::jac_sp", jac_sp_);
1630  s.unpack("FmuInternal::hess_sp", hess_sp_);
1631 
1632  s.unpack("FmuInternal::resource", resource_);
1633  s.unpack("FmuInternal::fmutol", fmutol_);
1634  s.unpack("FmuInternal::instance_name", instance_name_);
1635  s.unpack("FmuInternal::instantiation_token", instantiation_token_);
1636  s.unpack("FmuInternal::logging_on", logging_on_);
1637  s.unpack("FmuInternal::number_of_event_indicators", number_of_event_indicators_);
1638  s.unpack("FmuInternal::provides_directional_derivatives", provides_directional_derivatives_);
1639  s.unpack("FmuInternal::provides_adjoint_derivatives", provides_adjoint_derivatives_);
1640  s.unpack("FmuInternal::can_be_instantiated_only_once_per_process",
1642  s.unpack("FmuInternal::start_time", start_time_);
1643  s.unpack("FmuInternal::nx", nx_);
1644  s.unpack("FmuInternal::do_evaluation_dance", do_evaluation_dance_);
1645 }
1646 
1648  std::string class_name;
1649  s.unpack("FmuInternal::type", class_name);
1650  if (class_name=="Fmu2") {
1651 #ifdef WITH_FMI2
1652  return Fmu2::deserialize(s);
1653 #else
1654  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
1655 #endif // WITH_FMI2
1656  } else if (class_name=="Fmu3") {
1657 #ifdef WITH_FMI3
1658  return Fmu3::deserialize(s);
1659 #else
1660  casadi_error("CasADi was not compiled with WITH_FMI3=ON.");
1661 #endif // WITH_FMI3
1662  } else {
1663  casadi_error("Cannot deserialize type '" + class_name + "'");
1664  }
1665 }
1666 
1667 } // 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 void copy_file(const std::string &src, const std::string &dest)
Definition: filesystem.cpp:144
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
static bool remove(const std::string &path)
Definition: filesystem.cpp:43
Interface to a binary FMU, adhering to FMI version 2.0.
Definition: fmu2.hpp:42
static Fmu2 * deserialize(DeserializingStream &s)
Definition: fmu2.cpp:553
Interface to a binary FMU, adhering to FMI version 2.0.
Definition: fmu3.hpp:42
static Fmu3 * deserialize(DeserializingStream &s)
Definition: fmu3.cpp:492
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:377
std::vector< std::string > scheme_out_
Definition: fmu_impl.hpp:313
std::string instantiation_token_
Definition: fmu_impl.hpp:329
std::vector< double > max_in_
Definition: fmu_impl.hpp:361
bool warning_fired_next_event_time_defined_
Definition: fmu_impl.hpp:378
std::string name_
Instance name.
Definition: fmu_impl.hpp:310
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:338
virtual int set_time(void *instance, double t) const =0
bool warning_fired_nominals_of_continuous_states_changed_
Definition: fmu_impl.hpp:376
std::vector< double > all_nominal_in(size_t i) const
Retreive nominal values.
Definition: fmu.cpp:707
std::vector< unsigned int > vr_out_
Definition: fmu_impl.hpp:363
std::string desc_in(FmuMemory *m, size_t id, bool more=true) const
Definition: fmu.cpp:850
virtual void free_instance(void *c) const =0
std::vector< std::string > vn_out_
Definition: fmu_impl.hpp:362
void set(FmuMemory *m, size_t ind, const double *value) const
Definition: fmu.cpp:1342
std::vector< size_t > iind_
Definition: fmu_impl.hpp:350
void serialize(SerializingStream &s) const
Definition: fmu.cpp:1550
virtual void finalize()
Definition: fmu.cpp:593
void disp(std::ostream &stream, bool more) const override
Print.
Definition: fmu.cpp:651
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:442
std::vector< std::vector< size_t > > ired_
Definition: fmu_impl.hpp:369
std::vector< std::string > aux_
Definition: fmu_impl.hpp:317
std::vector< std::vector< size_t > > ored_
Definition: fmu_impl.hpp:369
std::map< std::string, std::vector< size_t > > scheme_
Definition: fmu_impl.hpp:314
unsigned int independent_vr_
Definition: fmu_impl.hpp:356
int discrete_states_iter(void *instance) const
Definition: fmu.cpp:1248
virtual void serialize_body(SerializingStream &s) const
Definition: fmu.cpp:1559
virtual int get_aux(void *instance)=0
bool warning_fired_terminate_simulation_
Definition: fmu_impl.hpp:375
bool warning_fired_discrete_states_need_update_
Definition: fmu_impl.hpp:374
void get_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:1232
void gather_fwd(FmuMemory *m) const
Definition: fmu.cpp:1504
std::vector< double > nominal_out_
Definition: fmu_impl.hpp:359
void request(FmuMemory *m, size_t ind) const
Definition: fmu.cpp:1363
int get_all(FmuMemory *m, double *values, size_t n_values) const
Definition: fmu.cpp:1400
void gather_io(FmuMemory *m) const
Definition: fmu.cpp:1477
int eval_fd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:948
std::vector< std::string > vn_in_
Definition: fmu_impl.hpp:362
std::vector< size_t > oind_
Definition: fmu_impl.hpp:350
virtual void load_functions()=0
~FmuInternal() override
Destructor.
Definition: fmu.cpp:450
virtual int update_discrete_states(void *instance, EventMemory *eventmem) const =0
static FmuInternal * deserialize(DeserializingStream &s)
Definition: fmu.cpp:1647
void set_fwd(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:1437
virtual void serialize_type(SerializingStream &s) const
Definition: fmu.cpp:1555
void request_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:1214
std::vector< unsigned int > vr_in_
Definition: fmu_impl.hpp:363
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:586
virtual int set_values(void *instance) const =0
std::vector< double > min_out_
Definition: fmu_impl.hpp:360
bool can_be_instantiated_only_once_per_process_
Definition: fmu_impl.hpp:341
int set_all(FmuMemory *m, const double *values, size_t n_values) const
Definition: fmu.cpp:1372
static std::string fmi3_dll_infix()
Definition: fmu.cpp:736
int eval_ad(FmuMemory *m) const
Definition: fmu.cpp:912
std::vector< double > nominal_in_
Definition: fmu_impl.hpp:359
std::vector< double > max_out_
Definition: fmu_impl.hpp:361
static std::string pack_fmu(const Dict &files, const std::string &path)
Definition: fmu.cpp:830
size_t index_out(const std::string &n) const
Definition: fmu.cpp:675
std::string resource_loc_
Definition: fmu_impl.hpp:320
std::vector< double > min_in_
Definition: fmu_impl.hpp:360
static std::string dll_suffix()
Definition: fmu.cpp:723
void set_adj(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:1192
std::vector< double > value_in_
Definition: fmu_impl.hpp:366
void get(FmuMemory *m, size_t id, double *value) const
Definition: fmu.cpp:1430
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:335
std::vector< double > all_nominal_out(size_t i) const
Retreive nominal values.
Definition: fmu.cpp:715
Importer li_
DLL.
Definition: fmu_impl.hpp:347
int eval_fwd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:863
virtual void init(const DaeBuilderInternal *dae)
Definition: fmu.cpp:453
void get_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:1176
void gather_adj(FmuMemory *m) const
Definition: fmu.cpp:1520
virtual int init_mem(FmuMemory *m) const
Initalize memory block.
Definition: fmu.cpp:1298
virtual int get_real(void *instance, const unsigned int *vr, size_t n_vr, double *values, size_t n_values, FmuMemory *m=nullptr) const =0
virtual int enter_continuous_time_mode(void *instance) const =0
size_t index_in(const std::string &n) const
Definition: fmu.cpp:665
void request_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:1459
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:696
std::vector< size_t > oind_map_
Definition: fmu_impl.hpp:350
Sparsity jac_sparsity(const std::vector< size_t > &osub, const std::vector< size_t > &isub) const
Definition: fmu.cpp:685
std::vector< std::string > scheme_in_
Definition: fmu_impl.hpp:313
std::string instance_name_
Definition: fmu_impl.hpp:326
bool provides_directional_derivatives_
Definition: fmu_impl.hpp:338
static Dict compile_fmu(const std::string &name, const Dict &files, const Dict &opts)
Definition: fmu.cpp:781
virtual std::string system_infix() const =0
int eval_adj(FmuMemory *m) const
Definition: fmu.cpp:879
int eval(FmuMemory *m) const
Definition: fmu.cpp:1414
std::vector< size_t > iind_map_
Definition: fmu_impl.hpp:350
Interface to binary FMU.
Definition: fmu.hpp:62
void set(FmuMemory *m, size_t ind, const double *value) const
Definition: fmu.cpp:287
void get_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:360
const std::vector< size_t > & ored(size_t ind) const
Definition: fmu.cpp:165
static Fmu deserialize(DeserializingStream &s)
Deserialize with type disambiguation.
Definition: fmu.cpp:1540
size_t index_out(const std::string &n) const
Definition: fmu.cpp:149
int eval_adj(FmuMemory *m) const
Definition: fmu.cpp:409
Fmu()
Default constructor.
Definition: fmu.cpp:50
double nominal_out(size_t ind) const
Definition: fmu.cpp:181
void get_stats(FmuMemory *m, Dict *stats, const std::vector< std::string > &name_in, const InputStruct *in) const
Get stats.
Definition: fmu.cpp:433
Sparsity hess_sparsity(const std::vector< size_t > &r, const std::vector< size_t > &c) const
Definition: fmu.cpp:262
bool can_be_instantiated_only_once_per_process() const
Does the FMU declare restrictions on instantiation?
Definition: fmu.cpp:245
std::vector< double > all_nominal_out(size_t ind) const
Definition: fmu.cpp:213
bool provides_adjoint_derivatives() const
Does the FMU provide support for adjoint directional derivatives.
Definition: fmu.cpp:237
Sparsity jac_sparsity(const std::vector< size_t > &osub, const std::vector< size_t > &isub) const
Definition: fmu.cpp:253
int eval_fwd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:352
double nominal_in(size_t ind) const
Definition: fmu.cpp:173
size_t index_in(const std::string &n) const
Definition: fmu.cpp:141
FmuMemory * alloc_mem(const FmuFunction &f) const
Create memory block.
Definition: fmu.cpp:95
void get_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:417
double max_in(size_t ind) const
Definition: fmu.cpp:197
const std::string & name() const
Name of the instance.
Definition: fmu.cpp:107
void set_fwd(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:319
static Fmu create(FmuInternal *node)
Create from node.
Definition: fmu.cpp:1544
size_t n_out() const
Get the number of scheme outputs.
Definition: fmu.cpp:133
const std::string & instance_name() const
Name of the FMU.
Definition: fmu.cpp:116
std::vector< double > all_nominal_in(size_t ind) const
Definition: fmu.cpp:205
double min_in(size_t ind) const
Definition: fmu.cpp:189
void free_mem(void *mem) const
Free memory block.
Definition: fmu.cpp:99
FmuInternal * get() const
Definition: fmu.cpp:103
FmuInternal * operator->()
Definition: fmu.cpp:87
void set_adj(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:376
int init_mem(FmuMemory *m) const
Initalize memory block.
Definition: fmu.cpp:270
bool provides_directional_derivatives() const
Does the FMU provide support for forward directional derivatives.
Definition: fmu.cpp:229
int eval(FmuMemory *m) const
Definition: fmu.cpp:303
const std::vector< size_t > & ired(size_t ind) const
Definition: fmu.cpp:157
void request_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:392
size_t n_in() const
Get the number of scheme inputs.
Definition: fmu.cpp:125
void free_instance(void *instance) const
Definition: fmu.cpp:279
void request(FmuMemory *m, size_t ind) const
Definition: fmu.cpp:295
void request_fwd(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:335
std::string desc_in(FmuMemory *m, size_t id, bool more=true) const
Definition: fmu.cpp:221
void serialize(SerializingStream &s) const
Serialize an object.
Definition: fmu.cpp:1536
SharedObjectInternal * get() const
Get a const pointer to the node.
SharedObjectInternal * operator->() const
Access a member function or object.
Importer.
Definition: importer.hpp:86
std::string library() const
Get library name.
Definition: importer.cpp:104
static bool has_plugin(const std::string &pname, bool verbose=false)
Check if a plugin is available or can be loaded.
static Plugin & getPlugin(const std::string &pname)
Load and get the creator function.
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:270
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.
std::vector< casadi_int > path(const std::vector< casadi_int > &map, casadi_int i_start)
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.