dae_builder.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 "dae_builder_internal.hpp"
27 
28 #include <cctype>
29 #include <ctime>
30 #include <map>
31 #include <set>
32 #include <sstream>
33 #include <string>
34 #include <algorithm>
35 
36 #include "casadi_misc.hpp"
37 #include "exception.hpp"
38 #include "code_generator.hpp"
39 #include "calculus.hpp"
40 #include "xml_file.hpp"
41 #include "external.hpp"
42 #include "integrator.hpp"
43 
44 namespace casadi {
45 
46 // Throw informative error message
47 #define THROW_ERROR(FNAME, WHAT) \
48 throw CasadiException("Error in DaeBuilder::" FNAME " for '" + this->name() \
49  + "' at " + CASADI_WHERE + ":\n" + std::string(WHAT));
50 
52 }
53 
54 DaeBuilder::DaeBuilder(const std::string& name, const std::string& path, const Dict& opts) {
55  own(new DaeBuilderInternal(name, path, opts));
56  if (!path.empty()) load_fmi_description((*this)->resource_.path() + "/modelDescription.xml");
57 }
58 
59 const std::string& DaeBuilder::name() const {
60  return (*this)->name_;
61 }
62 
63 const MX& DaeBuilder::time() const {
64  try {
65  return (*this)->time();
66  } catch (std::exception& e) {
67  THROW_ERROR("time", e.what());
68  static const MX t;
69  return t; // never reached
70  }
71 }
72 
73 std::vector<MX> DaeBuilder::inputs(const std::string& cat) const {
74  try {
75  return (*this)->inputs(to_enum<Category>(cat));
76  } catch (std::exception& e) {
77  THROW_ERROR("inputs", e.what());
78  return {}; // never reached
79  }
80 }
81 
82 std::vector<MX> DaeBuilder::outputs(const std::string& cat) const {
83  try {
84  return (*this)->outputs(to_enum<Category>(cat));
85  } catch (std::exception& e) {
86  THROW_ERROR("outputs", e.what());
87  return {}; // never reached
88  }
89 }
90 
91 std::vector<MX> DaeBuilder::cdef() const {
92  try {
93  return (*this)->cdef();
94  } catch (std::exception& e) {
95  THROW_ERROR("cdef", e.what());
96  return {}; // never reached
97  }
98 }
99 
100 std::vector<MX> DaeBuilder::ddef() const {
101  try {
102  return (*this)->outputs(Category::DDEF);
103  } catch (std::exception& e) {
104  THROW_ERROR("ddef", e.what());
105  return {}; // never reached
106  }
107 }
108 
109 std::vector<MX> DaeBuilder::wdef() const {
110  try {
111  return (*this)->outputs(Category::WDEF);
112  } catch (std::exception& e) {
113  THROW_ERROR("wdef", e.what());
114  return {}; // never reached
115  }
116 }
117 
118 std::vector<MX> DaeBuilder::init_lhs() const {
119  return (*this)->init_lhs();
120 }
121 
122 std::vector<MX> DaeBuilder::init_rhs() const {
123  return (*this)->init_rhs();
124 }
125 
126 std::vector<std::string> DaeBuilder::der() const {
127  try {
128  return (*this)->name((*this)->der_);
129  } catch (std::exception& e) {
130  THROW_ERROR("der", e.what());
131  return {}; // never reached
132  }
133 }
134 
135 std::vector<std::string> DaeBuilder::initial_unknowns() const {
136  try {
137  return (*this)->name((*this)->initial_unknowns_);
138  } catch (std::exception& e) {
139  THROW_ERROR("initial_unknowns", e.what());
140  return {}; // never reached
141  }
142 }
143 
144 bool DaeBuilder::has_t() const {
145  try {
146  return (*this)->has_t();
147  } catch (std::exception& e) {
148  THROW_ERROR("has_t", e.what());
149  return false; // never reached
150  }
151 }
152 
153 casadi_int DaeBuilder::nx() const {
154  return (*this)->size(Category::X);
155 }
156 
157 casadi_int DaeBuilder::nz() const {
158  return (*this)->size(Category::Z);
159 }
160 
161 casadi_int DaeBuilder::nq() const {
162  return (*this)->size(Category::Q);
163 }
164 
165 casadi_int DaeBuilder::nzero() const {
166  return (*this)->size(Category::ZERO);
167 }
168 
169 casadi_int DaeBuilder::ny() const {
170  return (*this)->size(Category::Y);
171 }
172 
173 casadi_int DaeBuilder::nu() const {
174  return (*this)->size(Category::U);
175 }
176 
177 casadi_int DaeBuilder::np() const {
178  return (*this)->size(Category::P);
179 }
180 
181 casadi_int DaeBuilder::nc() const {
182  return (*this)->size(Category::C);
183 }
184 
185 casadi_int DaeBuilder::nd() const {
186  return (*this)->size(Category::D);
187 }
188 
189 casadi_int DaeBuilder::nw() const {
190  return (*this)->size(Category::W);
191 }
192 
193 void DaeBuilder::load_fmi_description(const std::string& filename) {
194  try {
195  (*this)->load_fmi_description(filename);
196  } catch (std::exception& e) {
197  THROW_ERROR("load_fmi_description", e.what());
198  }
199 }
200 
202  try {
203  casadi_assert(!symbolic(), "Functionality only applies to imported standard FMUs");
204  return (*this)->provides_directional_derivatives_;
205  } catch (std::exception& e) {
206  THROW_ERROR("provides_directional_derivatives", e.what());
207  return false;
208  }
209 }
210 
212  try {
213  return (*this)->export_fmu(opts);
214  } catch (std::exception& e) {
215  THROW_ERROR("export_fmu", e.what());
216  return Dict(); // never reached
217  }
218 }
219 
220 Dict DaeBuilder::compile_fmu(const Dict& files, const Dict& opts) {
221  try {
222  return (*this)->compile_fmu(files, opts);
223  } catch (std::exception& e) {
224  THROW_ERROR("compile_fmu", e.what());
225  return Dict(); // never reached
226  }
227 }
228 
229 std::string DaeBuilder::pack_fmu(const Dict& files, const Dict& opts) {
230  try {
231  return (*this)->pack_fmu(files, opts);
232  } catch (std::exception& e) {
233  THROW_ERROR("pack_fmu", e.what());
234  return std::string(); // never reached
235  }
236 }
237 
238 void DaeBuilder::prune(bool prune_p, bool prune_u) {
239  try {
240  (*this)->prune(prune_p, prune_u);
241  } catch (std::exception& e) {
242  THROW_ERROR("prune", e.what());
243  }
244 }
245 
247  try {
248  (*this)->tear();
249  } catch (std::exception& e) {
250  THROW_ERROR("tear", e.what());
251  }
252 }
253 
254 bool DaeBuilder::has(const std::string& name) const {
255  try {
256  return (*this)->has(name);
257  } catch (std::exception& e) {
258  THROW_ERROR("has", e.what());
259  return false; // never reached
260  }
261 }
262 
263 std::vector<std::string> DaeBuilder::all() const {
264  try {
265  return (*this)->all();
266  } catch (std::exception& e) {
267  THROW_ERROR("all", e.what());
268  return {}; // never reached
269  }
270 }
271 
272 std::vector<std::string> DaeBuilder::all(const std::string& cat) const {
273  try {
274  return (*this)->all(to_enum<Category>(cat));
275  } catch (std::exception& e) {
276  THROW_ERROR("all", e.what());
277  return {}; // never reached
278  }
279 }
280 
281 void DaeBuilder::set_all(const std::string& v, const std::vector<std::string>& name) {
282  try {
283  // Get category enum
284  auto cat = to_enum<Category>(v);
285 
286  // Make sure no duplicate names
287  std::set<std::string> name_set(name.begin(), name.end());
288  casadi_assert(name_set.size() == name.size(), "Duplicate names");
289 
290  // For outputs, update causality
291  if (is_output_category(cat)) {
292  if (cat == Category::Y) {
293  for (auto&& n : name) set_causality(n, "output");
294  if (ny() != name.size()) {
295  for (auto&& n : y()) {
296  if (name_set.find(n) == name_set.end()) set_causality(n, "local");
297  }
298  }
299  } else {
300  casadi_error("Setting category '" + v + "' not supported");
301  }
302  } else if (is_input_category(cat)) {
303  // Update category
304  for (auto&& n : name) set_category(n, v);
305  // Remove any variables not in name from the category
306  auto all_in_cat = all(v);
307  if (all_in_cat.size() != name.size()) {
308  std::set<std::string> name_set(name.begin(), name.end());
309  for (auto&& n : all_in_cat) {
310  if (name_set.find(n) == name_set.end()) {
311  if (v == "x" || v == "q") {
312  // Move to unused derivatives
313  set_category(n, "");
314  } else if (v == "u" || v == "p") {
315  // Make constant
316  set_category(n, "c");
317  } else {
318  casadi_error("Cannot automatically remove '" + n + "' from category '" + v + "'");
319  }
320  }
321  }
322  }
323  } else {
324  casadi_error("Cannot set variables of category '" + v + "'");
325  }
326  // Make sure ordering is correct
327  reorder(v, name);
328  } catch (std::exception& e) {
329  THROW_ERROR("set_all", e.what());
330  }
331 }
332 
333 void DaeBuilder::reorder(const std::string& cat, const std::vector<std::string>& v) {
334  try {
335  (*this)->reorder(to_enum<Category>(cat), (*this)->find(v));
336  } catch (std::exception& e) {
337  THROW_ERROR("reorder", e.what());
338  }
339 }
340 
341 MX DaeBuilder::add(const std::string& name, const std::string& causality,
342  const std::string& variability, const Dict& opts) {
343  try {
344  return (*this)->add(name, to_enum<Causality>(causality),
345  to_enum<Variability>(variability), opts).v;
346  } catch (std::exception& e) {
347  THROW_ERROR("add", e.what());
348  return MX();
349  }
350 }
351 
352 MX DaeBuilder::add(const std::string& name, const std::string& causality, const Dict& opts) {
353  try {
354  return (*this)->add(name, to_enum<Causality>(causality), opts).v;
355  } catch (std::exception& e) {
356  THROW_ERROR("add", e.what());
357  return MX();
358  }
359 }
360 
361 MX DaeBuilder::add(const std::string& name, const Dict& opts) {
362  try {
363  return (*this)->add(name, opts).v;
364  } catch (std::exception& e) {
365  THROW_ERROR("add", e.what());
366  return MX();
367  }
368 }
369 
370 void DaeBuilder::add(const std::string& name, const std::string& causality,
371  const std::string& variability, const MX& expr, const Dict& opts) {
372  try {
373  // Ensure pure symbolic expression
374  casadi_assert(expr.is_symbolic(), "Expression must be symbolic");
375  // Make sure name matches expression
376  casadi_assert(name == expr.name(), "Name must match expression");
377  // Add variable
378  (*this)->add(name, to_enum<Causality>(causality), to_enum<Variability>(variability),
379  expr, opts);
380  } catch (std::exception& e) {
381  THROW_ERROR("add", e.what());
382  }
383 }
384 
385 void DaeBuilder::eq(const MX& lhs, const MX& rhs, const Dict& opts) {
386  try {
387  (*this)->eq(lhs, rhs, opts);
388  } catch (std::exception& e) {
389  THROW_ERROR("eq", e.what());
390  }
391 }
392 
393 void DaeBuilder::when(const MX& cond, const std::vector<std::string>& eqs, const Dict& opts) {
394  try {
395  (*this)->when(cond, eqs, opts);
396  } catch (std::exception& e) {
397  THROW_ERROR("when", e.what());
398  }
399 }
400 
401 std::string DaeBuilder::assign(const std::string& name, const MX& val) {
402  try {
403  return (*this)->assign(name, val).name;
404  } catch (std::exception& e) {
405  THROW_ERROR("assign", e.what());
406  return std::string(); // never reached
407  }
408 }
409 
410 std::string DaeBuilder::reinit(const std::string& name, const MX& val) {
411  try {
412  return (*this)->reinit(name, val).name;
413  } catch (std::exception& e) {
414  THROW_ERROR("reinit", e.what());
415  return std::string(); // never reached
416  }
417 }
418 
419 void DaeBuilder::set_init(const std::string& name, const MX& init_rhs) {
420  try {
421  (*this)->set_init(name, init_rhs);
422  } catch (std::exception& e) {
423  THROW_ERROR("set_init", e.what());
424  }
425 }
426 
428  try {
429  (*this)->sanity_check();
430  } catch (std::exception& e) {
431  THROW_ERROR("sanity_check", e.what());
432  }
433 }
434 
435 MX DaeBuilder::var(const std::string& name) const {
436  try {
437  return (*this)->variable(name).v;
438  } catch (std::exception& e) {
439  THROW_ERROR("var", e.what());
440  return MX(); // never reached
441  }
442 }
443 
444 std::string DaeBuilder::der(const std::string& name) const {
445  try {
446  // Get variable index
447  size_t ind = (*this)->find(name);
448  // Differentiate
449  ind = (*this)->variable(ind).der;
450  casadi_assert(ind != size_t(-1), "No derivative expression for " + name);
451  // Return name
452  return (*this)->variable(ind).name;
453  } catch (std::exception& e) {
454  THROW_ERROR("der", e.what());
455  return std::string(); // never reached
456  }
457 }
458 
459 std::string DaeBuilder::pre(const std::string& name) const {
460  try {
461  // Not implemented
462  static bool warned = false;
463  if (!warned) {
464  casadi_warning("DaeBuilder::pre has not been implemented: Returning identity mapping");
465  warned = true;
466  }
467  return name;
468  } catch (std::exception& e) {
469  THROW_ERROR("pre", e.what());
470  return std::string(); // never reached
471  }
472 }
473 
474 MX DaeBuilder::pre(const MX& v) const {
475  try {
476  // Not implemented
477  static bool warned = false;
478  if (!warned) {
479  casadi_warning("DaeBuilder::pre has not been implemented: Returning identity mapping");
480  warned = true;
481  }
482  return v;
483  } catch (std::exception& e) {
484  THROW_ERROR("pre", e.what());
485  return MX(); // never reached
486  }
487 }
488 
489 std::vector<std::string> DaeBuilder::der(const std::vector<std::string>& name) const {
490  try {
491  std::vector<std::string> r(name.size());
492  for (size_t i = 0; i < r.size(); ++i) r[i] = der(name[i]);
493  return r;
494  } catch (std::exception& e) {
495  THROW_ERROR("der", e.what());
496  return {}; // never reached
497  }
498 }
499 
500 std::vector<std::string> DaeBuilder::pre(const std::vector<std::string>& name) const {
501  try {
502  std::vector<std::string> r(name.size());
503  for (size_t i = 0; i < r.size(); ++i) r[i] = pre(name[i]);
504  return r;
505  } catch (std::exception& e) {
506  THROW_ERROR("pre", e.what());
507  return {}; // never reached
508  }
509 }
510 
511 bool DaeBuilder::has_beq(const std::string& name) const {
512  try {
513  return !(*this)->variable(name).has_beq();
514  } catch (std::exception& e) {
515  THROW_ERROR("has_beq", e.what());
516  return false; // never reached
517  }
518 }
519 
520 MX DaeBuilder::beq(const std::string& name) const {
521  try {
522  const Variable& v = (*this)->variable(name);
523  return (*this)->variable(v.bind).v;
524  } catch (std::exception& e) {
525  THROW_ERROR("beq", e.what());
526  return MX(); // never reached
527  }
528 }
529 
530 void DaeBuilder::eliminate(const std::string& cat) {
531  try {
532  (*this)->eliminate(to_enum<Category>(cat));
533  } catch (std::exception& e) {
534  THROW_ERROR("eliminate", e.what());
535  }
536 }
537 
538 void DaeBuilder::sort(const std::string& cat) {
539  try {
540  (*this)->sort(to_enum<Category>(cat));
541  } catch (std::exception& e) {
542  THROW_ERROR("sort", e.what());
543  }
544 }
545 
546 void DaeBuilder::lift(bool lift_shared, bool lift_calls) {
547  try {
548  (*this)->lift(lift_shared, lift_calls);
549  } catch (std::exception& e) {
550  THROW_ERROR("lift", e.what());
551  }
552 }
553 
554 casadi_int DaeBuilder::value_reference(const std::string& name) const {
555  return (*this)->variable(name).value_reference;
556 }
557 
558 void DaeBuilder::set_value_reference(const std::string& name, casadi_int val) {
559  (*this)->variable(name).value_reference = val;
560 }
561 
562 std::string DaeBuilder::description(const std::string& name) const {
563  return (*this)->variable(name).description;
564 }
565 
566 void DaeBuilder::set_description(const std::string& name, const std::string& val) {
567  (*this)->variable(name).description = val;
568 }
569 
570 std::string DaeBuilder::type(const std::string& name, casadi_int fmi_version) const {
571  // Check version
572  casadi_assert(fmi_version == 2 || fmi_version == 3, "Only FMI version 2 or 3 supported");
573  // Handle FMI 2
574  if (fmi_version == 2) {
575  return to_string(to_fmi2((*this)->variable(name).type));
576  }
577  // Assume FMI 3
578  return to_string((*this)->variable(name).type);
579 }
580 
581 void DaeBuilder::set_type(const std::string& name, const std::string& val) {
582  // Fallback to FMI 2, if necessary
583  if (has_enum<TypeFmi2>(val) && !has_enum<Type>(val)) {
584  (*this)->variable(name).type = from_fmi2(to_enum<TypeFmi2>(val));
585  }
586  // Assume FMI 3
587  (*this)->variable(name).type = to_enum<Type>(val);
588 }
589 
590 std::string DaeBuilder::causality(const std::string& name) const {
591  try {
592  return to_string((*this)->causality((*this)->find(name)));
593  } catch (std::exception& e) {
594  THROW_ERROR("causality", e.what());
595  return std::string(); // never reached
596  }
597 }
598 
599 std::vector<std::string> DaeBuilder::categories(const std::string& name) const {
600  try {
601  std::vector<std::string> ret;
602  for (auto&& cat : (*this)->variable(name).categories()) {
603  ret.push_back(to_string(cat));
604  }
605  return ret;
606  } catch (std::exception& e) {
607  THROW_ERROR("categories", e.what());
608  return {}; // never reached
609  }
610 }
611 
612 void DaeBuilder::set_causality(const std::string& name, const std::string& val) {
613  try {
614  (*this)->set_causality((*this)->find(name), to_enum<Causality>(val));
615  } catch (std::exception& e) {
616  THROW_ERROR("set_causality", e.what());
617  }
618 }
619 
620 std::string DaeBuilder::variability(const std::string& name) const {
621  try {
622  return to_string((*this)->variability((*this)->find(name)));
623  } catch (std::exception& e) {
624  THROW_ERROR("variability", e.what());
625  return std::string(); // never reached
626  }
627 }
628 
629 void DaeBuilder::set_variability(const std::string& name, const std::string& val) {
630  try {
631  (*this)->set_variability((*this)->find(name), to_enum<Variability>(val));
632  } catch (std::exception& e) {
633  THROW_ERROR("set_variability", e.what());
634  }
635 }
636 
637 std::string DaeBuilder::category(const std::string& name) const {
638  try {
639  return to_string((*this)->category((*this)->find(name)));
640  } catch (std::exception& e) {
641  THROW_ERROR("category", e.what());
642  return std::string(); // never reached
643  }
644 }
645 
646 void DaeBuilder::set_category(const std::string& name, const std::string& val) {
647  try {
648  (*this)->set_category((*this)->find(name),
649  val.empty() ? Category::NUMEL : to_enum<Category>(val));
650  } catch (std::exception& e) {
651  THROW_ERROR("set_category", e.what());
652  }
653 }
654 
655 std::string DaeBuilder::initial(const std::string& name) const {
656  return to_string((*this)->variable(name).initial);
657 }
658 
659 void DaeBuilder::set_initial(const std::string& name, const std::string& val) {
660  (*this)->variable(name).initial = to_enum<Initial>(val);
661 }
662 
663 std::string DaeBuilder::unit(const std::string& name) const {
664  return (*this)->variable(name).unit;
665 }
666 
667 void DaeBuilder::set_unit(const std::string& name, const std::string& val) {
668  (*this)->variable(name).unit = val;
669 }
670 
671 std::string DaeBuilder::display_unit(const std::string& name) const {
672  return (*this)->variable(name).display_unit;
673 }
674 
675 void DaeBuilder::set_display_unit(const std::string& name, const std::string& val) {
676  (*this)->variable(name).display_unit = val;
677 }
678 
679 casadi_int DaeBuilder::numel(const std::string& name) const {
680  return (*this)->variable(name).numel;
681 }
682 
683 std::vector<casadi_int> DaeBuilder::dimension(const std::string& name) const {
684  return (*this)->variable(name).dimension;
685 }
686 
687 double DaeBuilder::start_time() const {
688  try {
689  return (*this)->start_time_;
690  } catch (std::exception& e) {
691  THROW_ERROR("start_time", e.what());
692  return nan;
693  }
694 }
695 
696 void DaeBuilder::set_start_time(double val) {
697  try {
698  (*this)->start_time_ = val;
699  } catch (std::exception& e) {
700  THROW_ERROR("set_start_time", e.what());
701  }
702 }
703 
704 double DaeBuilder::stop_time() const {
705  try {
706  return (*this)->stop_time_;
707  } catch (std::exception& e) {
708  THROW_ERROR("stop_time", e.what());
709  return nan;
710  }
711 }
712 
713 void DaeBuilder::set_stop_time(double val) {
714  try {
715  (*this)->stop_time_ = val;
716  } catch (std::exception& e) {
717  THROW_ERROR("set_stop_time", e.what());
718  }
719 }
720 
721 double DaeBuilder::tolerance() const {
722  try {
723  return (*this)->tolerance_;
724  } catch (std::exception& e) {
725  THROW_ERROR("tolerance", e.what());
726  return nan;
727  }
728 }
729 
730 void DaeBuilder::set_tolerance(double val) {
731  try {
732  (*this)->tolerance_ = val;
733  } catch (std::exception& e) {
734  THROW_ERROR("set_tolerance", e.what());
735  }
736 }
737 
738 double DaeBuilder::step_size() const {
739  try {
740  return (*this)->step_size_;
741  } catch (std::exception& e) {
742  THROW_ERROR("step_size", e.what());
743  return nan;
744  }
745 }
746 
747 void DaeBuilder::set_step_size(double val) {
748  try {
749  (*this)->step_size_ = val;
750  } catch (std::exception& e) {
751  THROW_ERROR("set_step_size", e.what());
752  }
753 }
754 
755 void DaeBuilder::add_lc(const std::string& name,
756  const std::vector<std::string>& f_out) {
757  try {
758  (*this)->add_lc(name, f_out);
759  } catch (std::exception& e) {
760  THROW_ERROR("add_lc", e.what());
761  }
762 }
763 
764 Function DaeBuilder::create(const std::string& fname,
765  const std::vector<std::string>& name_in,
766  const std::vector<std::string>& name_out, bool sx, bool lifted_calls) const {
767  try {
768  return (*this)->create(fname, name_in, name_out, Dict(), sx, lifted_calls);
769  } catch (std::exception& e) {
770  THROW_ERROR("create", e.what());
771  return Function(); // never reached
772  }
773 }
774 
775 Function DaeBuilder::create(const std::string& fname,
776  const std::vector<std::string>& name_in,
777  const std::vector<std::string>& name_out, const Dict& opts) const {
778  try {
779  return (*this)->create(fname, name_in, name_out, opts, false, false);
780  } catch (std::exception& e) {
781  THROW_ERROR("create", e.what());
782  return Function(); // never reached
783  }
784 }
785 
786 Function DaeBuilder::create(const std::string& name, const Dict& opts) const {
787  try {
788  return (*this)->create(name, dyn_in(), dyn_out(), opts, false, false);
789  } catch (std::exception& e) {
790  THROW_ERROR("create", e.what());
791  return Function(); // never reached
792  }
793 }
794 
796  try {
797  return (*this)->add_fun(f);
798  } catch (std::exception& e) {
799  THROW_ERROR("add_fun", e.what());
800  return Function(); // never reached
801  }
802 }
803 
804 Function DaeBuilder::add_fun(const std::string& name, const std::vector<std::string>& arg,
805  const std::vector<std::string>& res, const Dict& opts) {
806  try {
807  return (*this)->add_fun(name, arg, res, opts);
808  } catch (std::exception& e) {
809  THROW_ERROR("add_fun", e.what());
810  return Function(); // never reached
811  }
812 }
813 
814 Function DaeBuilder::add_fun(const std::string& name, const Importer& compiler, const Dict& opts) {
815  casadi_assert(!has_fun(name), "Function '" + name + "' already exists");
816  return add_fun(external(name, compiler, opts));
817 }
818 
819 bool DaeBuilder::has_fun(const std::string& name) const {
820  try {
821  return (*this)->has_fun(name);
822  } catch (std::exception& e) {
823  THROW_ERROR("has_fun", e.what());
824  return false; // never reached
825  }
826 }
827 
828 Function DaeBuilder::fun(const std::string& name) const {
829  try {
830  return (*this)->fun(name);
831  } catch (std::exception& e) {
832  THROW_ERROR("fun", e.what());
833  return Function(); // never reached
834  }
835 }
836 
837 void DaeBuilder::gather_fun(casadi_int max_depth) {
838  try {
839  // Get a function corresponding to all equations (no inputs)
840  Function all_eq = (*this)->gather_eq();
841  // Gather all functions
842  std::vector<Function> allfun = all_eq.find_functions(max_depth);
843  // Add to list of functions
844  for (const Function& f : allfun) {
845  if (has_fun(f.name())) {
846  // Skip functions with duplicate names
847  casadi_warning("Duplicate function: '" + f.name() + "', ignored");
848  } else {
849  // Add to list of functions
850  add_fun(f);
851  }
852  }
853  } catch (std::exception& e) {
854  THROW_ERROR("gather_fun", e.what());
855  }
856 }
857 
858 std::vector<Function> DaeBuilder::fun() const {
859  return (*this)->fun_;
860 }
861 
862 Function DaeBuilder::oracle(bool sx, bool elim_w, bool lifted_calls) const {
863  try {
864  return (*this)->oracle(sx, elim_w, lifted_calls);
865  } catch (std::exception& e) {
866  THROW_ERROR("oracle", e.what());
867  return Function(); // never reached
868  }
869 }
870 
871 Function DaeBuilder::dependent_fun(const std::string& fname,
872  const std::vector<std::string>& s_in,
873  const std::vector<std::string>& s_out) const {
874  try {
875  return (*this)->dependent_fun(fname, s_in, s_out);
876  } catch (std::exception& e) {
877  THROW_ERROR("dependent_fun", e.what());
878  return Function(); // never reached
879  }
880 }
881 
882 Function DaeBuilder::transition(const std::string& fname, casadi_int index) const {
883  try {
884  return (*this)->transition(fname, index);
885  } catch (std::exception& e) {
886  THROW_ERROR("transition", e.what());
887  return Function(); // never reached
888  }
889 }
890 
891 Function DaeBuilder::transition(const std::string& fname) const {
892  try {
893  return (*this)->transition(fname);
894  } catch (std::exception& e) {
895  THROW_ERROR("transition", e.what());
896  return Function(); // never reached
897  }
898 }
899 
901  return dynamic_cast<const DaeBuilderInternal*>(ptr) != nullptr;
902 }
903 
905  return static_cast<DaeBuilderInternal*>(SharedObject::operator->());
906 }
907 
909  return static_cast<const DaeBuilderInternal*>(SharedObject::operator->());
910 }
911 
912 MX DaeBuilder::der(const MX& v) const {
913  try {
914  return (*this)->der(v);
915  } catch (std::exception& e) {
916  THROW_ERROR("der", e.what());
917  return MX(); // never reached
918  }
919 }
920 
921 MX DaeBuilder::der(const MX& v) {
922  try {
923  return (*this)->der(v);
924  } catch (std::exception& e) {
925  THROW_ERROR("der", e.what());
926  return MX(); // never reached
927  }
928 }
929 
930 double DaeBuilder::attribute(const std::string& a, const std::string& name) const {
931  try {
932  return (*this)->attribute(to_enum<Attribute>(a), name);
933  } catch (std::exception& e) {
934  THROW_ERROR("attribute", e.what());
935  return 0; // never reached
936  }
937 }
938 
939 std::vector<double> DaeBuilder::attribute(const std::string& a,
940  const std::vector<std::string>& name) const {
941  try {
942  return (*this)->attribute(to_enum<Attribute>(a), name);
943  } catch (std::exception& e) {
944  THROW_ERROR("attribute", e.what());
945  return {}; // never reached
946  }
947 }
948 
949 void DaeBuilder::set_attribute(const std::string& a, const std::string& name, double val) {
950  try {
951  (*this)->set_attribute(to_enum<Attribute>(a), name, val);
952  } catch (std::exception& e) {
953  THROW_ERROR("set_attribute", e.what());
954  }
955 }
956 
957 void DaeBuilder::set_attribute(const std::string& a, const std::vector<std::string>& name,
958  const std::vector<double>& val) {
959  try {
960  (*this)->set_attribute(to_enum<Attribute>(a), name, val);
961  } catch (std::exception& e) {
962  THROW_ERROR("set_attribute", e.what());
963  }
964 }
965 
966 double DaeBuilder::min(const std::string& name) const {
967  try {
968  return (*this)->variable(name).min;
969  } catch (std::exception& e) {
970  THROW_ERROR("min", e.what());
971  return 0; // never reached
972  }
973 }
974 
975 std::vector<double> DaeBuilder::min(const std::vector<std::string>& name) const {
976  try {
977  return (*this)->attribute(Attribute::MIN, name);
978  } catch (std::exception& e) {
979  THROW_ERROR("min", e.what());
980  return {}; // never reached
981  }
982 }
983 
984 void DaeBuilder::set_min(const std::string& name, double val) {
985  try {
986  (*this)->variable(name).min = val;
987  } catch (std::exception& e) {
988  THROW_ERROR("set_min", e.what());
989  }
990 }
991 
992 void DaeBuilder::set_min(const std::vector<std::string>& name, const std::vector<double>& val) {
993  try {
994  (*this)->set_attribute(Attribute::MIN, name, val);
995  } catch (std::exception& e) {
996  THROW_ERROR("set_min", e.what());
997  }
998 }
999 
1000 double DaeBuilder::max(const std::string& name) const {
1001  try {
1002  return (*this)->variable(name).max;
1003  } catch (std::exception& e) {
1004  THROW_ERROR("max", e.what());
1005  return 0; // never reached
1006  }
1007 }
1008 
1009 std::vector<double> DaeBuilder::max(const std::vector<std::string>& name) const {
1010  try {
1011  return (*this)->attribute(Attribute::MAX, name);
1012  } catch (std::exception& e) {
1013  THROW_ERROR("max", e.what());
1014  return {}; // never reached
1015  }
1016 }
1017 
1018 void DaeBuilder::set_max(const std::string& name, double val) {
1019  try {
1020  (*this)->variable(name).max = val;
1021  } catch (std::exception& e) {
1022  THROW_ERROR("set_max", e.what());
1023  }
1024 }
1025 
1026 void DaeBuilder::set_max(const std::vector<std::string>& name, const std::vector<double>& val) {
1027  try {
1028  (*this)->set_attribute(Attribute::MAX, name, val);
1029  } catch (std::exception& e) {
1030  THROW_ERROR("set_max", e.what());
1031  }
1032 }
1033 
1034 double DaeBuilder::nominal(const std::string& name) const {
1035  try {
1036  return (*this)->variable(name).nominal;
1037  } catch (std::exception& e) {
1038  THROW_ERROR("nominal", e.what());
1039  return 0; // never reached
1040  }
1041 }
1042 
1043 std::vector<double> DaeBuilder::nominal(const std::vector<std::string>& name) const {
1044  try {
1045  return (*this)->attribute(Attribute::NOMINAL, name);
1046  } catch (std::exception& e) {
1047  THROW_ERROR("nominal", e.what());
1048  return {}; // never reached
1049  }
1050 }
1051 
1052 void DaeBuilder::set_nominal(const std::string& name, double val) {
1053  try {
1054  (*this)->variable(name).nominal = val;
1055  } catch (std::exception& e) {
1056  THROW_ERROR("set_nominal", e.what());
1057  }
1058 }
1059 
1060 void DaeBuilder::set_nominal(const std::vector<std::string>& name, const std::vector<double>& val) {
1061  try {
1062  (*this)->set_attribute(Attribute::NOMINAL, name, val);
1063  } catch (std::exception& e) {
1064  THROW_ERROR("set_mininal", e.what());
1065  }
1066 }
1067 
1068 std::vector<double> DaeBuilder::start(const std::string& name) const {
1069  try {
1070  return (*this)->attribute(Attribute::START, std::vector<std::string>{name});
1071  } catch (std::exception& e) {
1072  THROW_ERROR("start", e.what());
1073  return {}; // never reached
1074  }
1075 }
1076 
1077 std::vector<double> DaeBuilder::start(const std::vector<std::string>& name) const {
1078  try {
1079  return (*this)->attribute(Attribute::START, name);
1080  } catch (std::exception& e) {
1081  THROW_ERROR("start", e.what());
1082  return {}; // never reached
1083  }
1084 }
1085 
1086 void DaeBuilder::set_start(const std::string& name, double val) {
1087  try {
1088  (*this)->set_attribute(Attribute::START, name, val);
1089  } catch (std::exception& e) {
1090  THROW_ERROR("set_start", e.what());
1091  }
1092 }
1093 
1094 void DaeBuilder::set_start(const std::string& name, const std::vector<double>& val) {
1095  try {
1096  (*this)->set_attribute(Attribute::START, std::vector<std::string>{name}, val);
1097  } catch (std::exception& e) {
1098  THROW_ERROR("set_start", e.what());
1099  }
1100 }
1101 
1102 void DaeBuilder::set_start(const std::vector<std::string>& name, const std::vector<double>& val) {
1103  try {
1104  (*this)->set_attribute(Attribute::START, name, val);
1105  } catch (std::exception& e) {
1106  THROW_ERROR("set_start", e.what());
1107  }
1108 }
1109 
1111  try {
1112  (*this)->reset();
1113  } catch (std::exception& e) {
1114  THROW_ERROR("reset", e.what());
1115  }
1116 }
1117 
1118 void DaeBuilder::set(const std::string& name, double val) {
1119  try {
1120  (*this)->set_attribute(Attribute::VALUE, name, val);
1121  } catch (std::exception& e) {
1122  THROW_ERROR("set", e.what());
1123  }
1124 }
1125 
1126 void DaeBuilder::set(const std::string& name, const std::string& val) {
1127  try {
1128  (*this)->set_string_attribute(Attribute::STRINGVALUE, name, val);
1129  } catch (std::exception& e) {
1130  THROW_ERROR("set", e.what());
1131  }
1132 }
1133 
1134 void DaeBuilder::set(const std::vector<std::string>& name, const std::vector<double>& val) {
1135  try {
1136  (*this)->set_attribute(Attribute::VALUE, name, val);
1137  } catch (std::exception& e) {
1138  THROW_ERROR("set", e.what());
1139  }
1140 }
1141 
1142 void DaeBuilder::set(const std::vector<std::string>& name,
1143  const std::vector<std::string>& val) {
1144  try {
1145  (*this)->set_string_attribute(Attribute::STRINGVALUE, name, val);
1146  } catch (std::exception& e) {
1147  THROW_ERROR("set", e.what());
1148  }
1149 }
1150 
1151 GenericType DaeBuilder::get(const std::string& name) const {
1152  return get(std::vector<std::string>{name}).front();
1153 }
1154 
1155 std::vector<GenericType> DaeBuilder::get(const std::vector<std::string>& name) const {
1156  try {
1157  // Allocate return value
1158  std::vector<GenericType> ret;
1159  ret.reserve(name.size());
1160  // For symbolic FMUs, we can just retrieve the values
1161  if (symbolic()) {
1162  // Retrieve the attributes
1163  for (const auto& n : name) {
1164  // Get the variable
1165  const Variable& v = (*this)->variable(n);
1166  if (v.type == Type::STRING) {
1167  // Attribute is a string
1168  std::string val;
1170  ret.push_back(val);
1171  } else if (v.numel == 1) {
1172  // Attribute is numerical scalar
1173  double val;
1175  ret.push_back(val);
1176  } else {
1177  // Attribute is a vector
1178  std::vector<double> val;
1180  ret.push_back(val);
1181  }
1182  }
1183  } else {
1184  // Create a temporary FmuFunction instance
1185  Function f = create(this->name() + "_get", {}, {}, Dict{{"aux", name}});
1186  // Get the stats
1187  Dict stats = f.stats().at("aux");
1188  // Return in the same order as inputs
1189  for (const std::string& n : name) ret.push_back(stats.at(n));
1190  }
1191  return ret;
1192  } catch (std::exception& e) {
1193  THROW_ERROR("get", e.what());
1194  return {};
1195  }
1196 }
1197 
1198 bool DaeBuilder::symbolic() const {
1199  try {
1200  return (*this)->symbolic_;
1201  } catch (std::exception& e) {
1202  THROW_ERROR("symbolic", e.what());
1203  return false; // never reached
1204  }
1205 }
1206 
1207 Sparsity DaeBuilder::jac_sparsity(const std::vector<std::string>& onames,
1208  const std::vector<std::string>& inames) const {
1209  try {
1210  return (*this)->jac_sparsity((*this)->find(onames), (*this)->find(inames));
1211  } catch (std::exception& e) {
1212  THROW_ERROR("jac_sparsity", e.what());
1213  return Sparsity(); // never reached
1214  }
1215 }
1216 
1217 } // namespace casadi
double start_time() const
Get the start time.
void when(const MX &cond, const std::vector< std::string > &eqs, const Dict &opts=Dict())
Add when equations.
bool has_fun(const std::string &name) const
Does a particular function already exist?
std::vector< Function > fun() const
Get all functions.
void set_stop_time(double val)
Set the stop time.
casadi_int nu() const
Free controls.
double nominal(const std::string &name) const
Get the nominal value, single variable.
void sanity_check() const
Check if dimensions match.
Function add_fun(const std::string &name, const std::vector< std::string > &arg, const std::vector< std::string > &res, const Dict &opts=Dict())
Add a function from loaded expressions.
bool has(const std::string &name) const
Check if a particular variable exists.
const std::string & name() const
Name of instance.
Definition: dae_builder.cpp:59
std::string variability(const std::string &name) const
Get the variability.
void set_value_reference(const std::string &name, casadi_int val)
casadi_int nx() const
Differential states.
void set_start(const std::string &name, double val)
Set the start attribute, single variable.
static bool test_cast(const SharedObjectInternal *ptr)
Check if a particular cast is allowed.
double tolerance() const
Get the tolerance.
std::string initial(const std::string &name) const
std::vector< casadi_int > dimension(const std::string &name) const
Get the dimensions of a variable.
Function dependent_fun(const std::string &fname, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out) const
Construct a function for evaluating dependent parameters.
std::vector< std::string > der() const
Model structure: All time derivatives.
double max(const std::string &name) const
Get the upper bound, single variable.
std::string unit(const std::string &name) const
std::vector< std::string > all() const
Get a list of all variables.
void set_max(const std::string &name, double val)
Set the upper bound, single variable.
Function oracle(bool sx=false, bool elim_w=false, bool lifted_calls=false) const
Get the (cached) oracle, SX or MX.
std::string category(const std::string &name) const
Get the variable category.
casadi_int nd() const
Dependent parameters.
void set_attribute(const std::string &a, const std::string &name, double val)
Set an attribute, single variable.
std::vector< MX > init_lhs() const
Initial conditions, left-hand-side.
void reorder(const std::string &cat, const std::vector< std::string > &v)
Reorder variables in a category.
double step_size() const
Get the step size.
void gather_fun(casadi_int max_depth=-1)
Collect embedded functions from the expression graph.
const MX & time() const
Expression for independent variable (usually time)
Definition: dae_builder.cpp:63
std::string causality(const std::string &name) const
Get the causality.
casadi_int nc() const
Named constants.
bool provides_directional_derivatives() const
Does the FMU provide support for analytic derivatives.
void set_tolerance(double val)
Set the tolerance.
void set_min(const std::string &name, double val)
Set the lower bound, single variable.
std::string assign(const std::string &name, const MX &val)
Assignment inside a when-equation or if-else equation.
void tear()
Identify iteration variables and residual equations using naming convention.
Function transition() const
Construct an event transition function, default naming.
std::vector< double > start(const std::string &name) const
Get the start attribute, single variable.
void set_type(const std::string &name, const std::string &val)
double attribute(const std::string &a, const std::string &name) const
Get an attribute, single variable.
void set_unit(const std::string &name, const std::string &val)
void sort(const std::string &cat)
Sort dependent parameters.
double stop_time() const
Get the stop time.
Function create() const
Create a function with standard integrator DAE signature, default naming.
double min(const std::string &name) const
Get the lower bound, single variable.
void set_display_unit(const std::string &name, const std::string &val)
std::string reinit(const std::string &name, const MX &val)
Reinitialize a state inside when-equations.
std::vector< std::string > categories(const std::string &name) const
Which categories are possible for a variable?
void set_init(const std::string &name, const MX &init_rhs)
Specify the initial equation for a variable.
void add_lc(const std::string &name, const std::vector< std::string > &f_out)
Add a named linear combination of output expressions.
void eq(const MX &lhs, const MX &rhs, const Dict &opts=Dict())
Add a simple equation.
void set_category(const std::string &name, const std::string &val)
Set the variable category, if permitted.
casadi_int nz() const
Algebraic variables.
std::vector< std::string > y() const
Outputs.
bool has_beq(const std::string &name) const
Does a variable have a binding equation?
std::string display_unit(const std::string &name) const
void set_nominal(const std::string &name, double val)
Set the nominal value, single variable.
void set_causality(const std::string &name, const std::string &val)
Set the causality, if permitted.
void prune(bool prune_p=true, bool prune_u=true)
Prune unused controls.
casadi_int nq() const
Quadrature states.
std::string pack_fmu(const Dict &files, const Dict &opts=Dict())
Pack files from export_fmu / compile_fmu into a single .fmu archive.
std::vector< std::string > pre(const std::vector< std::string > &name) const
Get the pre-variables of model variables.
std::vector< MX > init_rhs() const
Initial conditions, right-hand-side.
void set_variability(const std::string &name, const std::string &val)
Set the variability, if permitted.
MX add(const std::string &name, const std::string &causality, const std::string &variability, const Dict &opts=Dict())
Add a new model variable.
bool has_t() const
Is there a time variable?
void set_start_time(double val)
Set the start time.
DaeBuilder()
Default constructor.
Definition: dae_builder.cpp:51
void set(const std::string &name, double val)
void eliminate(const std::string &cat)
Eliminate all dependent parameters.
casadi_int value_reference(const std::string &name) const
Sparsity jac_sparsity(const std::vector< std::string > &onames, const std::vector< std::string > &inames) const
Get Jacobian sparsity.
casadi_int np() const
Parameters.
std::vector< MX > inputs(const std::string &cat) const
Input expressions for a specific category.
Definition: dae_builder.cpp:73
void lift(bool lift_shared=true, bool lift_calls=true)
Lift problem formulation by extracting shared subexpressions.
MX var(const std::string &name) const
casadi_int ny() const
Output variables.
const DaeBuilderInternal * operator->() const
Access a member function or object.
Dict compile_fmu(const Dict &files, const Dict &opts=Dict())
Compile the sources produced by export_fmu.
std::vector< MX > cdef() const
Definitions of named constants.
Definition: dae_builder.cpp:91
void set_all(const std::string &v, const std::vector< std::string > &name)
Set all variables within a a category.
std::vector< std::string > outputs() const
[DEPRECATED] Renamed "y"
void load_fmi_description(const std::string &filename)
Import problem description from FMI or XML.
casadi_int numel(const std::string &name) const
Get the number of elements of a variable.
Dict export_fmu(const Dict &opts=Dict())
Export instance into an FMU.
casadi_int nw() const
Dependent variables.
bool symbolic() const
Symbolic DAE instance?
void set_step_size(double val)
Set the step size.
std::vector< MX > ddef() const
Definitions of dependent parameters.
std::vector< std::string > initial_unknowns() const
Model structure: initial unknowns.
casadi_int nzero() const
Zero-crossing functions.
std::string description(const std::string &name) const
void set_initial(const std::string &name, const std::string &val)
MX beq(const std::string &name) const
Get the binding equation for a variable.
std::string type(const std::string &name, casadi_int fmi_version=3) const
std::vector< MX > wdef() const
Dependent variables and corresponding definitions.
void set_description(const std::string &name, const std::string &val)
virtual const Function & oracle() const
Get oracle.
Function object.
Definition: function.hpp:60
std::vector< Function > find_functions(casadi_int max_depth=-1) const
Get all functions embedded in the expression graphs.
Definition: function.cpp:2067
Dict stats(int mem=0) const
Get all statistics obtained at the end of the last evaluate call.
Definition: function.cpp:1080
SharedObjectInternal * get() const
Get a const pointer to the node.
SharedObjectInternal * operator->() const
Access a member function or object.
Generic data type, can hold different types such as bool, casadi_int, std::string etc.
Importer.
Definition: importer.hpp:86
MX - Matrix expression.
Definition: mx.hpp:92
std::string name() const
Get the name.
Definition: mx.cpp:791
bool is_symbolic() const
Check if symbolic.
Definition: mx.cpp:795
General sparsity class.
Definition: sparsity.hpp:106
std::vector< std::string > dyn_out()
Get output scheme of a DAE function.
Definition: integrator.cpp:236
std::vector< std::string > dyn_in()
Get input scheme of a DAE function.
Definition: integrator.cpp:232
The casadi namespace.
Definition: archiver.cpp:28
bool is_input_category(Category cat)
Type from_fmi2(TypeFmi2 v)
bool is_output_category(Category cat)
TypeFmi2 to_fmi2(Type v)
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
std::vector< casadi_int > path(const std::vector< casadi_int > &map, casadi_int i_start)
Function external(const std::string &name, const Importer &li, const Dict &opts)
Load a just-in-time compiled external function.
Definition: external.cpp:42
std::string filename(const std::string &path)
Definition: ghc.cpp:55
Holds expressions and meta-data corresponding to a physical quantity evolving in time.
void get_attribute(Attribute a, double *val) const
casadi_int numel
Number of elements - product of all dimensions.
MX v
Variable expression (always a vector)