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 
736 Dict FmuInternal::compile_fmu(const std::string& name, const Dict& files, const Dict& opts) {
737  // Options
738  Dict compiler_opts;
739  std::string compiler_plugin = "shell";
740  std::vector<std::string> include_dirs;
741  for (auto&& op : opts) {
742  if (op.first == "compiler") {
743  compiler_plugin = op.second.to_string();
744  } else if (op.first == "compiler_options") {
745  compiler_opts = op.second;
746  } else if (op.first == "include_dirs") {
747  include_dirs = op.second.to_string_vector();
748  } else {
749  casadi_error("No such option: " + op.first);
750  }
751  }
752  // The C sources to compile are the .c entries of the export_fmu map (flat in CWD)
753  std::vector<std::string> csources;
754  for (auto&& kv : files) {
755  const std::string& local = kv.first;
756  if (local.size() > 2 && local.substr(local.size() - 2) == ".c") csources.push_back(local);
757  }
758  // Amalgamation translation unit: a single .c that #includes every generated source,
759  // because the shell Importer compiles exactly one source file. The compile runs in
760  // the working directory, so quoted includes resolve against the loose files there.
761  // This is a build scratch file, NOT FMU content, so it is removed below.
762  std::string amalg = name + "_all.c";
763  {
764  auto f = Filesystem::ofstream_ptr(amalg);
765  for (const std::string& c : csources) *f << "#include \"" << c << "\"\n";
766  }
767  // Compile the amalgamation into a shared library via the Importer plugin.
768  // Pass include dirs through the OS-agnostic 'include_dirs' option (the plugin
769  // prefixes each with the compiler's own include flag: -I on gcc/clang, /I on MSVC).
770  Dict cop = compiler_opts;
771  if (!include_dirs.empty()) cop["include_dirs"] = include_dirs;
772  Importer compiler(amalg, compiler_plugin, cop);
773  // Lift the binary to a stable path before the Importer destructor removes it, then
774  // discard the amalgamation scratch file (compilation is done once the Importer exists)
775  std::string dll = name + dll_suffix();
776  Filesystem::copy_file(compiler.library(), dll);
777  Filesystem::remove(amalg);
778  // Augment the file map with the compiled binary
779  // (FMI-3 layout: binaries/<dll_infix>/<modelIdentifier><suffix>)
780  Dict ret = files;
781  ret[dll] = "binaries/" + Fmu3::dll_infix() + "/" + name + dll_suffix();
782  return ret;
783 }
784 
785 std::string FmuInternal::pack_fmu(const Dict& files, const std::string& path) {
786  casadi_assert(Archiver::has_plugin("libzip"),
787  "pack_fmu requires libzip. Compile CasADi with WITH_LIBZIP=ON.");
788  // The {local_file -> archive path} map is exactly the set of zip entries: no staging
789  // directory or copies required.
790  std::vector<std::pair<std::string, std::string>> entries;
791  for (auto&& kv : files) {
792  std::string arc = kv.second.to_string();
793  if (arc.substr(0, 2) == "./") arc = arc.substr(2); // zip entries are root-relative
794  entries.push_back({kv.first, arc});
795  }
796  std::string out = path;
797  if (out.size() < 4 || out.substr(out.size() - 4) != ".fmu") out += ".fmu";
798  casadi_assert(Archiver::getPlugin("libzip").exposed.pack_entries(entries, out),
799  "Packing FMU '" + out + "' failed.");
800  // Clean up the loose files
801  for (auto&& e : entries) Filesystem::remove(e.first);
802  return out;
803 }
804 
805 std::string FmuInternal::desc_in(FmuMemory* m, size_t id, bool more) const {
806  // Create description
807  if (more) {
808  // Detailed description
809  std::stringstream ss;
810  ss << vn_in_[id] << " = " << m->ibuf_[id] << " (nominal " << nominal_in_[id]
811  << ", min " << min_in_[id] << ", max " << max_in_[id] << ")";
812  return ss.str();
813  } else {
814  return vn_in_[id];
815  }
816 }
817 
818 int FmuInternal::eval_fwd(FmuMemory* m, bool independent_seeds) const {
819  // Gather input and output indices
820  gather_fwd(m);
821  // Calculate derivatives using FMU directional derivative support
823  // Evaluate using AD
824  if (eval_ad(m)) return 1;
825  }
826  // Calculate derivatives using finite differences
828  // Evaluate using FD
829  if (eval_fd(m, independent_seeds)) return 1;
830  }
831  return 0;
832 }
833 
835  // Gather input and output indices
836  gather_adj(m);
837  // Quick return if nothing to be calculated
838  if (m->id_in_.size() == 0) return 0;
839  // Check if no seeds
840  if (m->id_out_.size() == 0) {
841  // Sensitivities are zero, trivially
842  std::fill(m->d_in_.begin(), m->d_in_.end(), 0);
843  } else {
844  // Evaluate adjoint derivatives
846  get_ptr(m->vr_out_), m->id_out_.size(),
847  get_ptr(m->vr_in_), m->id_in_.size(),
848  get_ptr(m->d_out_), m->id_out_.size(),
849  get_ptr(m->d_in_), m->id_in_.size())) {
850  casadi_warning("FMU adjoint derivative failed");
851  return 1;
852  }
853  }
854  // Collect requested variables
855  auto it = m->d_in_.begin();
856  for (size_t id : m->id_in_) {
857  m->isens_[id] = *it++;
858  }
859  // Successful return
860  return 0;
861 }
862 
864  // Number of inputs and outputs
865  size_t n_known = m->id_in_.size();
866  size_t n_unknown = m->id_out_.size();
867  // Quick return if nothing to be calculated
868  if (n_unknown == 0) return 0;
869  // Quick return if no seeds
870  if (n_known == 0) {
871  std::fill(m->d_out_.begin(), m->d_out_.end(), 0);
872  return 0;
873  }
874  // Evalute (should not be necessary)
875  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, get_ptr(m->v_out_), n_unknown, m)) {
876  casadi_warning("FMU evaluation failed");
877  return 1;
878  }
879  // Evaluate directional derivatives
881  get_ptr(m->vr_out_), n_unknown,
882  get_ptr(m->vr_in_), n_known,
883  get_ptr(m->d_in_), n_known,
884  get_ptr(m->d_out_), n_unknown)) {
885  casadi_warning("FMU directional derivative failed");
886  return 1;
887  }
888  // Collect requested variables
889  auto it = m->d_out_.begin();
890  for (size_t id : m->id_out_) {
891  m->osens_[id] = *it++;
892  }
893  // Successful return
894  return 0;
895 }
896 
897 int FmuInternal::eval_fd(FmuMemory* m, bool independent_seeds) const {
898  // Number of inputs and outputs
899  size_t n_known = m->id_in_.size();
900  size_t n_unknown = m->id_out_.size();
901  // Quick return if nothing to be calculated
902  if (n_unknown == 0) return 0;
903  // Quick return if no seeds
904  if (n_known == 0) {
905  std::fill(m->d_out_.begin(), m->d_out_.end(), 0);
906  return 0;
907  }
908  // Evalute (should not be necessary)
909  if (get_real(m->instance, get_ptr(m->vr_out_), n_unknown, get_ptr(m->v_out_), n_unknown, m)) {
910  casadi_warning("Evaluating FMU failed");
911  return 1;
912  }
913  // Make outputs dimensionless
914  for (size_t k = 0; k < n_unknown; ++k) m->v_out_[k] /= nominal_out_[m->id_out_[k]];
915  // Number of points in FD stencil
916  casadi_int n_points = n_fd_points(m->self.fd_);
917  // Offset for points
918  casadi_int offset = fd_offset(m->self.fd_);
919  // Memory for perturbed outputs
920  m->fd_out_.resize(n_points * n_unknown);
921  // Which inputs are in bounds
922  m->in_bounds_.resize(n_known);
923  // Memory for perturbed inputs
924  m->v_pert_.resize(n_known);
925  // Do any any inputs need flipping?
926  m->flip_.resize(n_known);
927  size_t first_flip = -1;
928  for (size_t i = 0; i < n_known; ++i) {
929  // Try to take step
930  double test = m->v_in_[i] + m->self.step_ * m->d_in_[i];
931  // Check if in bounds
932  size_t id = m->id_in_[i];
933  if (test >= min_in_[id] && test <= max_in_[id]) {
934  // Positive perturbation is fine
935  m->flip_[i] = false;
936  } else {
937  // Try negative direction instead
938  test = m->v_in_[i] - m->self.step_ * m->d_in_[i];
939  casadi_assert(test >= min_in_[id] && test <= max_in_[id],
940  "Cannot perturb " + vn_in_[id] + " at " + str(m->v_in_[i]) + ", min " + str(min_in_[id])
941  + ", max " + str(max_in_[id]) + ", nominal " + str(nominal_in_[id]));
942  m->flip_[i] = true;
943  if (first_flip == size_t(-1)) first_flip = i;
944  }
945  }
946  // If seeds are not independent, we have to flip the sign for all of the seeds or none
947  if (first_flip != size_t(-1) && !independent_seeds) {
948  // Flip the rest of the seeds
949  for (size_t i = 0; i < n_known; ++i) {
950  if (!m->flip_[i]) {
951  // Test negative direction
952  double test = m->v_in_[i] - m->self.step_ * m->d_in_[i];
953  size_t id = m->id_in_[i];
954  casadi_assert(test >= min_in_[id] && test <= max_in_[id],
955  "Cannot perturb both " + vn_in_[id] + " and " + vn_in_[first_flip]);
956  // Flip it too
957  m->flip_[i] = true;
958  }
959  }
960  }
961  // All perturbed outputs
962  const double* yk_all[5] = {nullptr};
963 
964  // Calculate all perturbed outputs
965  for (casadi_int k = 0; k < n_points; ++k) {
966  // Where to save the perturbed outputs
967  double* yk = &m->fd_out_[n_unknown * k];
968  casadi_assert_dev(k < 5);
969  yk_all[k] = yk;
970  // If unperturbed output, quick return
971  if (k == offset) {
972  casadi_copy(get_ptr(m->v_out_), n_unknown, yk);
973  continue;
974  }
975  // Perturbation size
976  double pert = (k - offset) * m->self.step_;
977  // Perturb inputs, if allowed
978  for (size_t i = 0; i < n_known; ++i) {
979  // Try to take step
980  double sign = m->flip_[i] ? -1 : 1;
981  double test = m->v_in_[i] + pert * sign * m->d_in_[i];
982  // Check if in bounds
983  size_t id = m->id_in_[i];
984  m->in_bounds_[i] = test >= min_in_[id] && test <= max_in_[id];
985  // Take step, if allowed
986  m->v_pert_[i] = m->in_bounds_[i] ? test : m->v_in_[i];
987  }
988  // Pass perturbed inputs to FMU
989  if (set_all(m, get_ptr(m->v_pert_), m->v_pert_.size())) return 1;
990  // Evaluate perturbed FMU
991  if (get_all(m, yk, n_unknown)) return 1;
992  // Post-process yk if there was any scaling
993  if (independent_seeds) {
994  for (size_t i = 0; i < n_unknown; ++i) {
995  // Variable id
996  size_t id = m->id_out_[i];
997  // Differentiation with respect to what variable
998  size_t wrt_id = m->wrt_.at(id);
999  // Find the corresponding input variable
1000  size_t wrt_i;
1001  for (wrt_i = 0; wrt_i < n_known; ++wrt_i) {
1002  if (m->id_in_[wrt_i] == wrt_id) break;
1003  }
1004  // Check if in bounds
1005  if (m->in_bounds_.at(wrt_i) && (m->self.fd_flip_ || !m->flip_[i])) {
1006  // Input was in bounds: Keep output, make dimensionless
1007  yk[i] /= nominal_out_[m->id_out_[i]];
1008  } else {
1009  // Input was out of bounds: Discard output
1010  yk[i] = nan;
1011  }
1012  }
1013  }
1014  }
1015  // Restore FMU inputs
1016  if (set_all(m, get_ptr(m->v_in_), m->v_in_.size())) return 1;
1017  // Step size
1018  double h = m->self.step_;
1019 
1020  // Calculate FD approximation
1021  finite_diff(m->self.fd_, yk_all, get_ptr(m->d_out_), h, n_unknown, eps);
1022 
1023  // If seeds are dependent, quick return
1024  if (!independent_seeds) {
1025  // Simpy copy the results to output (no validation)
1026  for (size_t ind = 0; ind < m->id_out_.size(); ++ind) {
1027  m->osens_[m->id_out_[ind]] = m->d_out_[ind];
1028  }
1029  return 0;
1030  }
1031 
1032  // Collect requested variables
1033  for (size_t ind = 0; ind < m->id_out_.size(); ++ind) {
1034  // Variable id
1035  size_t id = m->id_out_[ind];
1036  // With respect to what variable
1037  size_t wrt = m->wrt_[id];
1038  // Find the corresponding input variable
1039  size_t wrt_i;
1040  for (wrt_i = 0; wrt_i < n_known; ++wrt_i) {
1041  if (m->id_in_[wrt_i] == wrt) break;
1042  }
1043  // Nominal value
1044  double n = nominal_out_[id];
1045  // Get the value
1046  double d_fd = m->d_out_[ind] * n;
1047  // Correct sign, if necessary
1048  if (m->flip_[wrt_i]) d_fd = -d_fd;
1049  // Use FD instead of AD or to compare with AD
1050  if (m->self.validate_forward_) {
1051  // Value to compare with
1052  double d_ad = m->osens_[id];
1053  // Nominal value used as seed
1054  d_ad /= nominal_in_[wrt];
1055  d_fd /= nominal_in_[wrt];
1056  // Is it a not a number?
1057  bool d_is_nan = d_ad != d_ad;
1058  // Magnitude of derivatives
1059  double d_max = std::fmax(std::fabs(d_fd), std::fabs(d_ad));
1060  // Check if NaN or error exceeds thresholds
1061  if (d_is_nan || (d_max > n * m->self.abstol_
1062  && std::fabs(d_ad - d_fd) > d_max * m->self.reltol_)) {
1063  // Offset for printing the stencil
1064  double off = m->fd_out_.at(ind + offset * n_unknown);
1065  // Warning or add to file
1066  std::stringstream ss;
1067  if (m->self.validate_ad_file_.empty()) {
1068  // Issue warning
1069  ss << (d_is_nan ? "NaN" : "Inconsistent") << " derivatives of " << vn_out_[id]
1070  << " w.r.t. " << desc_in(m, wrt) << ", got " << d_ad
1071  << " for AD vs. " << d_fd << " for FD[" << to_string(m->self.fd_) << "].";
1072  // Print the stencil:
1073  ss << "\nValues for step size " << h << ": " << (n * off) << " + [";
1074  for (casadi_int k = 0; k < n_points; ++k) {
1075  if (k > 0) ss << ", ";
1076  ss << (n * (m->fd_out_.at(ind + k * n_unknown) - off));
1077  }
1078  ss << "]";
1079  // Issue warning
1080  casadi_warning(ss.str());
1081  } else {
1082  // Output
1083  ss << vn_out_[id] << " ";
1084  // Input
1085  ss << vn_in_[wrt] << " ";
1086  // Value
1087  ss << m->ibuf_[wrt] << " ";
1088  // Noninal
1089  ss << nominal_in_[wrt] << " ";
1090  // Min
1091  ss << min_in_[wrt] << " ";
1092  // Max
1093  ss << max_in_[wrt] << " ";
1094  // AD
1095  ss << d_ad << " ";
1096  // FD
1097  ss << d_fd << " ";
1098  // Step
1099  ss << h << " ";
1100  // Offset
1101  ss << off << " ";
1102  // Stencil
1103  ss << "[";
1104  for (casadi_int k = 0; k < n_points; ++k) {
1105  if (k > 0) ss << ",";
1106  ss << (n * (m->fd_out_.at(ind + k * n_unknown) - off));
1107  }
1108  ss << "]" << std::endl;
1109  // Append to file
1110  auto valfile_ptr = Filesystem::ofstream_ptr(m->self.validate_ad_file_,
1111  std::ios_base::app);
1112  std::ostream& valfile = *valfile_ptr;
1113  valfile << ss.str();
1114  }
1115  }
1116  } else {
1117  // Use instead of AD
1118  m->osens_[id] = d_fd;
1119  }
1120  }
1121  // Successful return
1122  return 0;
1123 }
1124 
1125 void FmuInternal::get_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
1126  for (casadi_int i = 0; i < nsens; ++i) {
1127  *v++ = m->osens_.at(*id++);
1128  }
1129 }
1130 
1131 void FmuInternal::get_fwd(FmuMemory* m, size_t ind, double* v) const {
1132  // Quick return if not needed
1133  if (!v) return;
1134  // Retrieve all sensitivities FIXME(@jaeandersson): should use compatible types
1135  for (size_t id : ored_[ind]) {
1136  casadi_int id2 = id;
1137  get_fwd(m, 1, &id2, v++);
1138  }
1139 }
1140 
1141 void FmuInternal::set_adj(FmuMemory* m, casadi_int nseed,
1142  const casadi_int* id, const double* v) const {
1143  for (casadi_int i = 0; i < nseed; ++i) {
1144  if (*v != 0.) {
1145  m->osens_.at(*id) = *v;
1146  m->omarked_.at(*id) = true;
1147  }
1148  id++;
1149  v++;
1150  }
1151 }
1152 
1153 void FmuInternal::set_adj(FmuMemory* m, size_t ind, const double* v) const {
1154  // If seeds are zero, no need to add to seed buffers
1155  if (!v) return;
1156  // Pass all seeds FIXME(@jaeandersson): should use compatible types
1157  for (size_t id : ored_[ind]) {
1158  casadi_int id2 = id;
1159  set_adj(m, 1, &id2, v++);
1160  }
1161 }
1162 
1163 void FmuInternal::request_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id,
1164  const casadi_int* wrt_id) const {
1165  for (casadi_int i = 0; i < nsens; ++i) {
1166  m->imarked_.at(*id) = true;
1167  m->wrt_.at(*id) = wrt_id ? *wrt_id++ : -1;
1168  id++;
1169  }
1170 }
1171 
1172 void FmuInternal::request_adj(FmuMemory* m, casadi_int ind) const {
1173  // Request all sensitivities FIXME(@jaeandersson): should use compatible types
1174  casadi_int wrt_id = -1;
1175  for (size_t id : ired_[ind]) {
1176  casadi_int id2 = id;
1177  request_adj(m, 1, &id2, &wrt_id);
1178  }
1179 }
1180 
1181 void FmuInternal::get_adj(FmuMemory* m, casadi_int nsens, const casadi_int* id, double* v) const {
1182  for (casadi_int i = 0; i < nsens; ++i) {
1183  *v++ = m->isens_.at(*id++);
1184  }
1185 }
1186 
1187 void FmuInternal::get_adj(FmuMemory* m, size_t ind, double* v) const {
1188  // Quick return if not needed
1189  if (!v) return;
1190  // Retrieve all sensitivities FIXME(@jaeandersson): should use compatible types
1191  for (size_t id : ired_[ind]) {
1192  casadi_int id2 = id;
1193  get_adj(m, 1, &id2, v++);
1194  }
1195 }
1196 
1197 int FmuInternal::discrete_states_iter(void* instance) const {
1198  // Helper function: update_discrete_states
1199  EventMemory eventmem;
1200  const size_t max_update_iter = 10;
1201  for (size_t update_iter = 0; update_iter < max_update_iter; ++update_iter) {
1202  if (update_discrete_states(instance, &eventmem)) {
1203  casadi_warning("update_discrete_states");
1204  return 1;
1205  }
1206  // Not implemented
1207  if (eventmem.discrete_states_need_update) {
1210  casadi_warning("Discrete state update not implemented");
1211  }
1212  }
1213  if (eventmem.terminate_simulation) {
1216  casadi_warning("Terminate simulation not implemented");
1217  }
1218  }
1222  casadi_warning("Nominals of continuous states not implemented");
1223  }
1224  }
1225  if (eventmem.values_of_continuous_states_changed) {
1228  casadi_warning("Values of continuous states not implemented");
1229  }
1230  }
1231  if (eventmem.next_event_time_defined) {
1234  casadi_warning("Next event time not implemented");
1235  }
1236  }
1237  // Successful return
1238  if (!eventmem.discrete_states_need_update) {
1239  return 0;
1240  }
1241  }
1242  // Too many iterations
1243  casadi_warning("Discrete state update failed");
1244  return 1;
1245 }
1246 
1248  // Ensure not already instantiated
1249  casadi_assert(m->instance == nullptr, "Already instantiated");
1250  // Create instance
1251  m->instance = instantiate();
1252  // Set all values
1253  if (set_values(m->instance)) {
1254  casadi_warning("FmuInternal::set_values failed");
1255  return 1;
1256  }
1257  // Initialization mode begins
1258  if (enter_initialization_mode(m->instance)) return 1;
1259  // Initialization mode ends
1260  if (exit_initialization_mode(m->instance)) return 1;
1261  // Initial event iteration
1262  if (discrete_states_iter(m->instance)) return 1;
1263  // Continuous-time mode
1264  if (enter_continuous_time_mode(m->instance)) return 1;
1265  // Allocate/reset input buffer
1266  m->ibuf_.resize(iind_.size());
1267  std::fill(m->ibuf_.begin(), m->ibuf_.end(), casadi::nan);
1268  // Allocate/reset output buffer
1269  m->obuf_.resize(oind_.size());
1270  std::fill(m->obuf_.begin(), m->obuf_.end(), casadi::nan);
1271  // Maximum input or output
1272  size_t max_io = std::max(iind_.size(), oind_.size());
1273  // Allocate/reset seeds
1274  m->isens_.resize(max_io);
1275  std::fill(m->isens_.begin(), m->isens_.end(), 0);
1276  // Allocate/reset sensitivities
1277  m->osens_.resize(max_io);
1278  std::fill(m->osens_.begin(), m->osens_.end(), 0);
1279  // Allocate/reset changed
1280  m->imarked_.resize(max_io);
1281  std::fill(m->imarked_.begin(), m->imarked_.end(), false);
1282  // Allocate/reset requested
1283  m->omarked_.resize(max_io);
1284  std::fill(m->omarked_.begin(), m->omarked_.end(), false);
1285  // Also allocate memory for corresponding Jacobian entry (for debugging)
1286  m->wrt_.resize(max_io);
1287  // Successful return
1288  return 0;
1289 }
1290 
1291 void FmuInternal::set(FmuMemory* m, size_t ind, const double* value) const {
1292  if (value) {
1293  // Argument is given
1294  for (size_t id : ired_[ind]) {
1295  if (*value != m->ibuf_.at(id)) {
1296  m->ibuf_.at(id) = *value;
1297  m->imarked_.at(id) = true;
1298  }
1299  value++;
1300  }
1301  } else {
1302  // Argument is null - all zeros
1303  for (size_t id : ired_[ind]) {
1304  if (0 != m->ibuf_.at(id)) {
1305  m->ibuf_.at(id) = 0;
1306  m->imarked_.at(id) = true;
1307  }
1308  }
1309  }
1310 }
1311 
1312 void FmuInternal::request(FmuMemory* m, size_t ind) const {
1313  for (size_t id : ored_[ind]) {
1314  // Mark as requested
1315  m->omarked_.at(id) = true;
1316  // Also log corresponding input index
1317  m->wrt_.at(id) = -1;
1318  }
1319 }
1320 
1321 int FmuInternal::set_all(FmuMemory* m, const double* values, size_t n_values) const {
1322  // Quick return if nothing to set
1323  if (n_values == 0) return 0;
1324  // Value references
1325  const unsigned int* vr = get_ptr(m->vr_in_);
1326  size_t n_vr = m->vr_in_.size();
1327  // Set time variable, if any
1328  if (has_independent_ && *vr == independent_vr_) {
1329  // Update FMU time
1330  if (set_time(m->instance, *values)) return 1;
1331  // Skip when setting remaining variables
1332  vr++;
1333  n_vr--;
1334  values++;
1335  n_values--;
1336  // Quick return if nothing left to set
1337  if (n_vr == 0) return 0;
1338  }
1339 
1340  // Set remaining variables
1341  if (set_real(m->instance, vr, n_vr, values, n_values)) {
1342  casadi_warning("Setting FMU variables failed");
1343  return 1;
1344  }
1345 
1346  return 0;
1347 }
1348 
1349 int FmuInternal::get_all(FmuMemory* m, double* values, size_t n_values) const {
1350  // Quick return if nothing to get
1351  if (n_values == 0) return 0;
1352  // Retrieve from FMU
1353  if (get_real(m->instance, get_ptr(m->vr_out_), m->vr_out_.size(), values, n_values, m)) {
1354  casadi_warning("Evaluation failed");
1355  return 1;
1356  }
1357  // Successful return
1358  return 0;
1359 }
1360 
1362  // Gather inputs and outputs
1363  gather_io(m);
1364  // Pass inputs to FMU
1365  if (set_all(m, get_ptr(m->v_in_), m->v_in_.size())) return 1;
1366  // Get outputs from FMU
1367  if (get_all(m, get_ptr(m->v_out_), m->v_out_.size())) return 1;
1368  // Collect requested variables
1369  auto it = m->v_out_.begin();
1370  for (size_t id : m->id_out_) {
1371  m->obuf_[id] = *it++;
1372  }
1373  // Successful return
1374  return 0;
1375 }
1376 
1377 void FmuInternal::get(FmuMemory* m, size_t ind, double* value) const {
1378  // Save to return
1379  for (size_t id : ored_[ind]) {
1380  *value++ = m->obuf_.at(id);
1381  }
1382 }
1383 
1384 void FmuInternal::set_fwd(FmuMemory* m, casadi_int nseed,
1385  const casadi_int* id, const double* v) const {
1386  for (casadi_int i = 0; i < nseed; ++i) {
1387  if (*v != 0.) {
1388  m->isens_.at(*id) = *v;
1389  m->imarked_.at(*id) = true;
1390  }
1391  id++;
1392  v++;
1393  }
1394 }
1395 
1396 void FmuInternal::set_fwd(FmuMemory* m, size_t ind, const double* v) const {
1397  // If seeds are zero, no need to add to seed buffers
1398  if (!v) return;
1399  // Pass all seeds FIXME(@jaeandersson): should use compatible types
1400  for (size_t id : ired_[ind]) {
1401  casadi_int id2 = id;
1402  set_fwd(m, 1, &id2, v++);
1403  }
1404 }
1405 
1406 void FmuInternal::request_fwd(FmuMemory* m, casadi_int nsens, const casadi_int* id,
1407  const casadi_int* wrt_id) const {
1408  for (casadi_int i = 0; i < nsens; ++i) {
1409  m->omarked_.at(*id) = true;
1410  m->wrt_.at(*id) = *wrt_id++;
1411  id++;
1412  }
1413 }
1414 
1415 void FmuInternal::request_fwd(FmuMemory* m, casadi_int ind) const {
1416  // Request all sensitivities FIXME(@jaeandersson): should use compatible types
1417  casadi_int wrt_id = -1;
1418  for (size_t id : ored_[ind]) {
1419  casadi_int id2 = id;
1420  request_fwd(m, 1, &id2, &wrt_id);
1421  }
1422 }
1423 
1425  // Collect input indices and corresponding value references and values
1426  m->id_in_.clear();
1427  m->vr_in_.clear();
1428  m->v_in_.clear();
1429  for (size_t id = 0; id < m->imarked_.size(); ++id) {
1430  if (m->imarked_[id]) {
1431  m->id_in_.push_back(id);
1432  m->vr_in_.push_back(vr_in_[id]);
1433  m->v_in_.push_back(m->ibuf_[id]);
1434  m->imarked_[id] = false;
1435  }
1436  }
1437  // Collect output indices, corresponding value references
1438  m->id_out_.clear();
1439  m->vr_out_.clear();
1440  m->v_out_.clear();
1441  for (size_t id = 0; id < m->omarked_.size(); ++id) {
1442  if (m->omarked_[id]) {
1443  m->id_out_.push_back(id);
1444  m->vr_out_.push_back(vr_out_[id]);
1445  m->v_out_.push_back(nan);
1446  m->omarked_[id] = false;
1447  }
1448  }
1449 }
1450 
1452  // Gather input and output indices
1453  gather_io(m);
1454  // Number of outputs
1455  size_t n_unknown = m->id_out_.size();
1456  // Get/clear seeds
1457  m->d_in_.clear();
1458  for (size_t id : m->id_in_) {
1459  m->d_in_.push_back(m->isens_[id]);
1460  m->isens_[id] = 0;
1461  }
1462  // Allocate result vectors
1463  m->v_out_.resize(n_unknown);
1464  m->d_out_.resize(n_unknown);
1465 }
1466 
1468  // Gather input and output indices
1469  gather_io(m);
1470  // Number of inputs and outputs
1471  size_t n_known = m->id_in_.size();
1472  // Get/clear seeds
1473  m->d_out_.clear();
1474  for (size_t id : m->id_out_) {
1475  m->d_out_.push_back(m->osens_[id]);
1476  m->osens_[id] = 0;
1477  }
1478  // Allocate result vectors
1479  m->v_in_.resize(n_known);
1480  m->d_in_.resize(n_known);
1481 }
1482 
1484  (*this)->serialize(s);
1485 }
1486 
1489 }
1490 
1492  Fmu ret;
1493  ret.own(node);
1494  return ret;
1495 }
1496 
1498  serialize_type(s);
1499  serialize_body(s);
1500 }
1501 
1503  s.pack("FmuInternal::type", class_name());
1504 }
1505 
1507  s.version("FmuInternal", 4);
1508  s.pack("FmuInternal::name", name_);
1509  s.pack("FmuInternal::scheme_in", scheme_in_);
1510  s.pack("FmuInternal::scheme_out", scheme_out_);
1511  s.pack("FmuInternal::scheme", scheme_);
1512  s.pack("FmuInternal::aux", aux_);
1513  s.pack("FmuInternal::iind", iind_);
1514  s.pack("FmuInternal::iind_map", iind_map_);
1515  s.pack("FmuInternal::oind", oind_);
1516  s.pack("FmuInternal::oind_map", oind_map_);
1517  s.pack("FmuInternal::has_independent", has_independent_);
1518  s.pack("FmuInternal::nominal_in", nominal_in_);
1519  s.pack("FmuInternal::nominal_out", nominal_out_);
1520  s.pack("FmuInternal::min_in", min_in_);
1521  s.pack("FmuInternal::min_out", min_out_);
1522  s.pack("FmuInternal::max_in", max_in_);
1523  s.pack("FmuInternal::max_out", max_out_);
1524  s.pack("FmuInternal::vn_in", vn_in_);
1525  s.pack("FmuInternal::vn_out", vn_out_);
1526  s.pack("FmuInternal::vr_in", vr_in_);
1527  s.pack("FmuInternal::vr_out", vr_out_);
1528 
1529  s.pack("FmuInternal::value_in", value_in_);
1530  s.pack("FmuInternal::ired", ired_);
1531  s.pack("FmuInternal::ored", ored_);
1532  s.pack("FmuInternal::jac_sp", jac_sp_);
1533  s.pack("FmuInternal::hess_sp", hess_sp_);
1534 
1535  s.pack("FmuInternal::resource", resource_);
1536  s.pack("FmuInternal::fmutol", fmutol_);
1537  s.pack("FmuInternal::instance_name", instance_name_);
1538  s.pack("FmuInternal::instantiation_token", instantiation_token_);
1539  s.pack("FmuInternal::logging_on", logging_on_);
1540  s.pack("FmuInternal::number_of_event_indicators", number_of_event_indicators_);
1541  s.pack("FmuInternal::provides_directional_derivatives", provides_directional_derivatives_);
1542  s.pack("FmuInternal::provides_adjoint_derivatives", provides_adjoint_derivatives_);
1543  s.pack("FmuInternal::can_be_instantiated_only_once_per_process",
1545  s.pack("FmuInternal::start_time", start_time_);
1546  s.pack("FmuInternal::nx", nx_);
1547  s.pack("FmuInternal::do_evaluation_dance", do_evaluation_dance_);
1548 }
1549 
1551  s.version("FmuInternal", 4);
1552  s.unpack("FmuInternal::name", name_);
1553  s.unpack("FmuInternal::scheme_in", scheme_in_);
1554  s.unpack("FmuInternal::scheme_out", scheme_out_);
1555  s.unpack("FmuInternal::scheme", scheme_);
1556  s.unpack("FmuInternal::aux", aux_);
1557  s.unpack("FmuInternal::iind", iind_);
1558  s.unpack("FmuInternal::iind_map", iind_map_);
1559  s.unpack("FmuInternal::oind", oind_);
1560  s.unpack("FmuInternal::oind_map", oind_map_);
1561  s.unpack("FmuInternal::has_independent", has_independent_);
1562  s.unpack("FmuInternal::nominal_in", nominal_in_);
1563  s.unpack("FmuInternal::nominal_out", nominal_out_);
1564  s.unpack("FmuInternal::min_in", min_in_);
1565  s.unpack("FmuInternal::min_out", min_out_);
1566  s.unpack("FmuInternal::max_in", max_in_);
1567  s.unpack("FmuInternal::max_out", max_out_);
1568  s.unpack("FmuInternal::vn_in", vn_in_);
1569  s.unpack("FmuInternal::vn_out", vn_out_);
1570  s.unpack("FmuInternal::vr_in", vr_in_);
1571  s.unpack("FmuInternal::vr_out", vr_out_);
1572 
1573  s.unpack("FmuInternal::value_in", value_in_);
1574  s.unpack("FmuInternal::ired", ired_);
1575  s.unpack("FmuInternal::ored", ored_);
1576  s.unpack("FmuInternal::jac_sp", jac_sp_);
1577  s.unpack("FmuInternal::hess_sp", hess_sp_);
1578 
1579  s.unpack("FmuInternal::resource", resource_);
1580  s.unpack("FmuInternal::fmutol", fmutol_);
1581  s.unpack("FmuInternal::instance_name", instance_name_);
1582  s.unpack("FmuInternal::instantiation_token", instantiation_token_);
1583  s.unpack("FmuInternal::logging_on", logging_on_);
1584  s.unpack("FmuInternal::number_of_event_indicators", number_of_event_indicators_);
1585  s.unpack("FmuInternal::provides_directional_derivatives", provides_directional_derivatives_);
1586  s.unpack("FmuInternal::provides_adjoint_derivatives", provides_adjoint_derivatives_);
1587  s.unpack("FmuInternal::can_be_instantiated_only_once_per_process",
1589  s.unpack("FmuInternal::start_time", start_time_);
1590  s.unpack("FmuInternal::nx", nx_);
1591  s.unpack("FmuInternal::do_evaluation_dance", do_evaluation_dance_);
1592 }
1593 
1595  std::string class_name;
1596  s.unpack("FmuInternal::type", class_name);
1597  if (class_name=="Fmu2") {
1598 #ifdef WITH_FMI2
1599  return Fmu2::deserialize(s);
1600 #else
1601  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
1602 #endif // WITH_FMI2
1603  } else if (class_name=="Fmu3") {
1604 #ifdef WITH_FMI3
1605 return Fmu3::deserialize(s);
1606 #else
1607  casadi_error("CasADi was not compiled with WITH_FMI2=ON.");
1608 #endif // WITH_FMI3
1609  } else {
1610  casadi_error("Cannot deserialize type '" + class_name + "'");
1611  }
1612 }
1613 
1614 } // 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:533
static std::string dll_infix()
Definition: fmu3.cpp:61
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:372
std::vector< std::string > scheme_out_
Definition: fmu_impl.hpp:308
std::string instantiation_token_
Definition: fmu_impl.hpp:324
std::vector< double > max_in_
Definition: fmu_impl.hpp:356
bool warning_fired_next_event_time_defined_
Definition: fmu_impl.hpp:373
std::string name_
Instance name.
Definition: fmu_impl.hpp:305
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:333
virtual int set_time(void *instance, double t) const =0
bool warning_fired_nominals_of_continuous_states_changed_
Definition: fmu_impl.hpp:371
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:358
std::string desc_in(FmuMemory *m, size_t id, bool more=true) const
Definition: fmu.cpp:805
virtual void free_instance(void *c) const =0
std::vector< std::string > vn_out_
Definition: fmu_impl.hpp:357
void set(FmuMemory *m, size_t ind, const double *value) const
Definition: fmu.cpp:1291
std::vector< size_t > iind_
Definition: fmu_impl.hpp:345
void serialize(SerializingStream &s) const
Definition: fmu.cpp:1497
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:364
std::vector< std::string > aux_
Definition: fmu_impl.hpp:312
std::vector< std::vector< size_t > > ored_
Definition: fmu_impl.hpp:364
std::map< std::string, std::vector< size_t > > scheme_
Definition: fmu_impl.hpp:309
unsigned int independent_vr_
Definition: fmu_impl.hpp:351
int discrete_states_iter(void *instance) const
Definition: fmu.cpp:1197
virtual void serialize_body(SerializingStream &s) const
Definition: fmu.cpp:1506
virtual int get_aux(void *instance)=0
bool warning_fired_terminate_simulation_
Definition: fmu_impl.hpp:370
bool warning_fired_discrete_states_need_update_
Definition: fmu_impl.hpp:369
void get_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, double *v) const
Definition: fmu.cpp:1181
void gather_fwd(FmuMemory *m) const
Definition: fmu.cpp:1451
std::vector< double > nominal_out_
Definition: fmu_impl.hpp:354
void request(FmuMemory *m, size_t ind) const
Definition: fmu.cpp:1312
int get_all(FmuMemory *m, double *values, size_t n_values) const
Definition: fmu.cpp:1349
void gather_io(FmuMemory *m) const
Definition: fmu.cpp:1424
int eval_fd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:897
std::vector< std::string > vn_in_
Definition: fmu_impl.hpp:357
std::vector< size_t > oind_
Definition: fmu_impl.hpp:345
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:1594
void set_fwd(FmuMemory *m, casadi_int nseed, const casadi_int *id, const double *v) const
Definition: fmu.cpp:1384
virtual void serialize_type(SerializingStream &s) const
Definition: fmu.cpp:1502
void request_adj(FmuMemory *m, casadi_int nsens, const casadi_int *id, const casadi_int *wrt_id) const
Definition: fmu.cpp:1163
std::vector< unsigned int > vr_in_
Definition: fmu_impl.hpp:358
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:355
bool can_be_instantiated_only_once_per_process_
Definition: fmu_impl.hpp:336
int set_all(FmuMemory *m, const double *values, size_t n_values) const
Definition: fmu.cpp:1321
int eval_ad(FmuMemory *m) const
Definition: fmu.cpp:863
std::vector< double > nominal_in_
Definition: fmu_impl.hpp:354
std::vector< double > max_out_
Definition: fmu_impl.hpp:356
static std::string pack_fmu(const Dict &files, const std::string &path)
Definition: fmu.cpp:785
size_t index_out(const std::string &n) const
Definition: fmu.cpp:675
std::string resource_loc_
Definition: fmu_impl.hpp:315
std::vector< double > min_in_
Definition: fmu_impl.hpp:355
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:1141
std::vector< double > value_in_
Definition: fmu_impl.hpp:361
void get(FmuMemory *m, size_t id, double *value) const
Definition: fmu.cpp:1377
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:330
std::vector< double > all_nominal_out(size_t i) const
Retreive nominal values.
Definition: fmu.cpp:715
Importer li_
DLL.
Definition: fmu_impl.hpp:342
int eval_fwd(FmuMemory *m, bool independent_seeds) const
Definition: fmu.cpp:818
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:1125
void gather_adj(FmuMemory *m) const
Definition: fmu.cpp:1467
virtual int init_mem(FmuMemory *m) const
Initalize memory block.
Definition: fmu.cpp:1247
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:1406
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:345
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:308
std::string instance_name_
Definition: fmu_impl.hpp:321
bool provides_directional_derivatives_
Definition: fmu_impl.hpp:333
static Dict compile_fmu(const std::string &name, const Dict &files, const Dict &opts)
Definition: fmu.cpp:736
virtual std::string system_infix() const =0
int eval_adj(FmuMemory *m) const
Definition: fmu.cpp:834
int eval(FmuMemory *m) const
Definition: fmu.cpp:1361
std::vector< size_t > iind_map_
Definition: fmu_impl.hpp:345
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:1487
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:1491
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:1483
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.