25 #include "dae_builder_internal.hpp"
35 #include "casadi_misc.hpp"
36 #include "exception.hpp"
37 #include "code_generator.hpp"
38 #include "calculus.hpp"
39 #include "xml_file.hpp"
40 #include "external.hpp"
41 #include "fmu_function.hpp"
42 #include "integrator.hpp"
43 #include "filesystem_impl.hpp"
44 #include "fmu_impl.hpp"
45 #include "graph_builder.hpp"
46 #include "resource_internal.hpp"
47 #include "modelica_parser.hpp"
50 #define THROW_ERROR_NODE(FNAME, NODE, WHAT) \
51 throw CasadiException("Error in DaeBuilderInternal::" FNAME " for '" + this->name_ \
52 + "', node '" + (NODE).name + "' (line " + str((NODE).line) + ") at " \
53 + CASADI_WHERE + ":\n" + std::string(WHAT));
56 #define THROW_ERROR(FNAME, WHAT) \
57 throw CasadiException("Error in DaeBuilderInternal::" FNAME " for '" + this->name_ \
59 + CASADI_WHERE + ":\n" + std::string(WHAT));
92 casadi_error(
to_string(v) +
" cannot be converted to FMI 2");
289 casadi_error(
"No dependent definition category for: " +
to_string(cat));
293 std::vector<Category> ret;
295 auto cat =
static_cast<Category>(i);
302 std::vector<Category> ret;
304 auto cat =
static_cast<Category>(i);
324 casadi_assert(
numel == 1,
"Variable " +
name +
" is not scalar");
337 if (val) *val =
start.front();
340 if (val) *val =
value.front();
345 casadi_error(
"Cannot handle: " +
to_string(a));
350 if (val) val->resize(
size(a));
359 if (val) std::copy(
start.begin(),
start.end(), val->begin());
362 if (val) std::copy(
value.begin(),
value.end(), val->begin());
367 casadi_error(
"Cannot handle: " +
to_string(a));
378 casadi_error(
"Cannot handle: " +
to_string(a));
402 casadi_error(
"Cannot handle: " +
to_string(a));
407 if (val.size() == 1) {
412 casadi_assert(val.size() ==
numel,
"Wrong size for attribute " +
to_string(a));
416 std::copy(val.begin(), val.end(),
start.begin());
419 std::copy(val.begin(), val.end(),
value.begin());
424 casadi_error(
"Cannot handle: " +
to_string(a));
439 Variable::Variable(casadi_int index,
const std::string& name,
440 const std::vector<casadi_int>& dimension,
const MX& expr)
441 : index(index), name(name), dimension(dimension), v(expr) {
443 casadi_assert(
dimension.size() > 0,
"Variable must have at least one dimension");
444 for (casadi_int d :
dimension) casadi_assert(d > 0,
"Dimensions must be positive");
515 casadi_warning(
"Start attribute for String, Binary not implemented.");
518 std::stringstream ss;
519 for (
size_t i = 0; i <
start.size(); ++i) {
520 if (i > 0) ss <<
" ";
524 ss << static_cast<casadi_int>(
start.at(i));
601 if (c == cat)
return true;
611 casadi_assert(
der >= 0,
"Variable " +
name +
" has no time derivative");
613 return self.variable(
der).v;
629 self.der_.push_back(der_v.
index);
644 if (
path.size() >= 4 &&
path.substr(
path.size() - 4) ==
".bmo") {
680 for (
auto&& op : opts) {
681 if (op.first==
"debug") {
683 }
else if (op.first==
"fmutol") {
685 }
else if (op.first==
"ignore_time") {
687 }
else if (op.first==
"detect_quad") {
689 }
else if (op.first==
"resource_serialize_mode") {
691 }
else if (op.first==
"enable_ls_dae") {
693 }
else if (op.first==
"enable_ls_serialization") {
696 casadi_error(
"No such option: " + op.first);
706 casadi_error(
"Could not open file '" +
filename +
"'.");
708 casadi_error(
"Could not open file '" +
filename +
"'. "
709 "Note that, since CasADi was compiled without WITH_GHC_FILESYSTEM=ON, "
710 "passing fmu files to DaeBuilder is unsupported. "
711 "You could manually unzip the FMU file and "
712 "pass the path to the unzipped directory instead.");
717 casadi_assert(
n_variables() == 0,
"Instance already has variables");
741 fmi_major_ >= 3 ?
"instantiationToken" :
"guid");
756 if (fmi_desc.
has_child(
"DefaultExperiment")) {
761 bool has_model_exchange =
false;
762 if (fmi_desc.
has_child(
"ModelExchange")) {
763 has_model_exchange =
true;
768 casadi_assert(fmi_desc.
has_child(
"ModelVariables"),
"Missing 'ModelVariables'");
772 if (fmi_desc.
has_child(
"ModelStructure")) {
784 +
"/extra/org.casadi.fmi-ls-serialization/oracle.casadi");
787 auto oracle_out =
oracle(oracle_in);
789 std::vector<MX> v, vdef;
790 for (
auto& arg : oracle_in) {
792 for (
auto& vp : arg.primitives()) {
794 size_t ind =
find(vp.name());
797 vdef.push_back(
var(ind));
801 oracle_in = substitute(oracle_in, v, vdef);
802 oracle_out = substitute(oracle_out, v, vdef);
808 for (
size_t i = 0; i < w.size(); ++i) {
815 assign_w_i.
v = wdef[i];
828 MX alg_all = vertcat(alg);
830 auto alg_it = alg.begin();
841 }
catch (std::exception& e) {
849 +
"/extra/org.lacemodelica.ls-onnx-serialization/model.onnx";
857 auto oracle_out =
oracle(oracle_in);
860 std::vector<std::string> input_var_names;
861 for (casadi_int i = 0; i <
oracle.
n_in(); ++i) {
866 std::vector<MX> v, vdef;
867 for (
auto& arg : oracle_in) {
869 for (
auto& vp : arg.primitives()) {
871 size_t ind =
find(vp.name());
874 vdef.push_back(
var(ind));
879 oracle_out = substitute(oracle_out, v, vdef);
888 for (
size_t i = 0; i < oracle_out.size(); ++i) {
890 MX expr = oracle_out[i];
893 bool is_init_eq = out_name.substr(0, 8) ==
"init_eq[";
894 bool is_dyn_eq = out_name.substr(0, 3) ==
"eq[" && !is_init_eq;
896 if (is_dyn_eq || is_init_eq) {
899 if (expr.
n_dep() == 2) {
900 MX lhs = expr.
dep(0);
901 MX rhs = expr.
dep(1);
906 std::string var_name = lhs.
name();
913 std::string var_name = lhs.
name();
914 size_t var_ind =
find(var_name);
924 }
else if (out_name.substr(0, 6) ==
"start[") {
926 size_t bracket_pos = out_name.find(
'[');
927 size_t close_pos = out_name.find(
']');
928 if (bracket_pos != std::string::npos && close_pos != std::string::npos) {
929 casadi_int idx = std::stoi(out_name.substr(bracket_pos + 1, close_pos - bracket_pos - 1));
930 if (idx >= 0 && idx <
static_cast<casadi_int
>(input_var_names.size())) {
931 std::string var_name = input_var_names[idx];
935 DM dm_val =
static_cast<DM>(expr);
936 var_ref.
start = std::vector<double>(dm_val->begin(), dm_val->end());
941 }
else if (out_name.substr(0, 4) ==
"min[") {
943 size_t bracket_pos = out_name.find(
'[');
944 size_t close_pos = out_name.find(
']');
945 if (bracket_pos != std::string::npos && close_pos != std::string::npos) {
946 casadi_int idx = std::stoi(out_name.substr(bracket_pos + 1, close_pos - bracket_pos - 1));
947 if (idx >= 0 && idx <
static_cast<casadi_int
>(input_var_names.size())) {
948 std::string var_name = input_var_names[idx];
952 DM dm_val =
static_cast<DM>(expr);
953 var_ref.
min =
static_cast<double>(dm_val);
958 }
else if (out_name.substr(0, 4) ==
"max[") {
960 size_t bracket_pos = out_name.find(
'[');
961 size_t close_pos = out_name.find(
']');
962 if (bracket_pos != std::string::npos && close_pos != std::string::npos) {
963 casadi_int idx = std::stoi(out_name.substr(bracket_pos + 1, close_pos - bracket_pos - 1));
964 if (idx >= 0 && idx <
static_cast<casadi_int
>(input_var_names.size())) {
965 std::string var_name = input_var_names[idx];
969 DM dm_val =
static_cast<DM>(expr);
970 var_ref.
max =
static_cast<double>(dm_val);
982 if (fmi_desc.
has_child(
"equ:BindingEquations")) {
988 if (fmi_desc.
has_child(
"equ:InitialEquations")) {
994 if (fmi_desc.
has_child(
"equ:DynamicEquations")) {
1000 casadi_assert(
symbolic_ || has_model_exchange,
1001 "FMU must be of ModelExchange type or be symbolic (FMUX)");
1005 const std::vector<std::string>& cfiles)
const {
1009 std::string model_name =
name_;
1013 r.
name =
"fmiBuildDescription";
1014 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
1017 source_file_set.
name =
"SourceFileSet";
1018 for (
auto&& f : cfiles) {
1020 source_file.
name =
"SourceFile";
1022 source_file_set.
children.push_back(source_file);
1026 bc.
name =
"BuildConfiguration";
1028 bc.
children.push_back(source_file_set);
1031 std::string xml_filename =
"buildDescription.xml";
1034 build_description.
children.push_back(r);
1037 xml_file.
dump(xml_filename, build_description);
1038 return xml_filename;
1045 std::string model_name =
name_;
1048 std::string version;
1049 std::string copyright;
1050 std::string license;
1054 r.
name =
"fmiModelDescription";
1055 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
1057 r.
set_attribute(fmi_major >= 3 ?
"instantiationToken" :
"guid", guid);
1061 if (!copyright.empty()) r.
set_attribute(
"copyright", copyright);
1066 if (fmi_major < 3) r.
set_attribute(
"numberOfEventIndicators",
"0");
1070 me.
name =
"ModelExchange";
1078 def_exp.
name =
"DefaultExperiment";
1090 std::string xml_filename =
"modelDescription.xml";
1093 model_description.
children.push_back(r);
1096 xml_file.
dump(xml_filename, model_description);
1097 return xml_filename;
1103 r.
name =
"ModelVariables";
1105 r.
children.push_back(v->export_xml(*
this));
1112 r.
name =
"ModelStructure";
1126 c.
name =
"ContinuousStateDerivative";
1134 f.
name =
"Formulation";
1139 c.
name =
"Residual";
1148 c.
name =
"InitialUnknown";
1157 c.
name =
"InitialUnknown";
1166 c.
name =
"EventIndicator";
1188 for (casadi_int k = dode_dxT.
colind(i); k < dode_dxT.
colind(i + 1); ++k) {
1189 casadi_int j = dode_dxT.
row(k);
1193 for (casadi_int k = dode_dzT.
colind(i); k < dode_dzT.
colind(i + 1); ++k) {
1194 casadi_int j = dode_dzT.
row(k);
1198 for (casadi_int k = dode_duT.
colind(i); k < dode_duT.
colind(i + 1); ++k) {
1199 casadi_int j = dode_duT.
row(k);
1206 const std::vector<size_t>& oind =
indices(cat);
1210 for (casadi_int i = 0; i < oind.size(); ++i) {
1216 for (casadi_int k = dy_dxT.
colind(i); k < dy_dxT.
colind(i + 1); ++k) {
1217 casadi_int j = dy_dxT.
row(k);
1221 for (casadi_int k = dy_dzT.
colind(i); k < dy_dzT.
colind(i + 1); ++k) {
1222 casadi_int j = dy_dzT.
row(k);
1226 for (casadi_int k = dy_duT.
colind(i); k < dy_duT.
colind(i + 1); ++k) {
1227 casadi_int j = dy_duT.
row(k);
1236 bool no_warning =
false;
1237 bool with_serialization =
true;
1238 for (
auto&& op : opts) {
1239 if (op.first ==
"no_warning") {
1240 no_warning = op.second;
1241 }
else if (op.first ==
"with_serialization") {
1242 with_serialization = op.second;
1244 casadi_error(
"No such option: " + op.first);
1248 if (!no_warning) casadi_warning(
"FMU generation is experimental and incomplete")
1252 std::string dae_filename =
name_;
1254 Function dae = shared_from_this<DaeBuilder>().
create(dae_filename,
1255 {
"t",
"x",
"z",
"p",
"u"}, {
"ode",
"alg",
"y",
"zero"});
1261 codegen_opts[
"with_header"] =
true;
1268 std::vector<std::string> sources;
1270 sources.push_back(dae_filename +
".h");
1279 for (
const std::string& s : sources) ret[s] =
"sources/" + s;
1284 if (with_serialization) {
1286 std::string serialization_ls =
"org.casadi.fmi-ls-serialization";
1288 std::string oracle_filename =
"oracle.casadi";
1289 shared_from_this<DaeBuilder>().oracle().save(oracle_filename);
1290 ret[oracle_filename] =
"extra/" + serialization_ls +
"/" + oracle_filename;
1293 r.
name =
"fmiLayeredStandardManifest";
1297 "Layered standard for serialized CasADi expressions in FMU");
1302 std::string manifest_filename = serialization_ls +
".fmi-ls-manifest.xml";
1303 xml_file.
dump(manifest_filename, manifest);
1304 ret[manifest_filename] =
"extra/" + serialization_ls +
"/fmi-ls-manifest.xml";
1309 std::string dae_ls =
"org.fmi-standard.fmi-ls-dae";
1312 r.
name =
"fmiLayeredStandardManifest";
1316 "Layered standard for DAE support in FMU");
1319 a.
name =
"AlgebraicVariables";
1322 v.
name =
"AlgebraicVariable";
1324 static_cast<casadi_int
>(
variable(i).value_reference));
1335 std::string manifest_filename = dae_ls +
".fmi-ls-manifest.xml";
1336 xml_file.
dump(manifest_filename, manifest);
1337 ret[manifest_filename] =
"extra/" + dae_ls +
"/fmi-ls-manifest.xml";
1349 for (
auto&& op : opts) {
1350 if (op.first ==
"path") {
1351 path = op.second.to_string();
1353 casadi_error(
"No such option: " + op.first);
1360 std::stringstream ss;
1363 for (
double e : v) {
1365 if (!first) ss <<
", ";
1375 std::stringstream ss;
1378 for (
double e : v) {
1380 if (!first) ss <<
", ";
1383 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << e;
1390 std::vector<double> r;
1392 for (
double s : v->start) r.push_back(s);
1400 std::string wrapper_filename =
name_ +
"_wrap.c";
1403 std::ostream& f = *f_ptr;
1407 f <<
"#include <fmi3Functions.h>\n"
1408 <<
"#include \"" <<
name_ <<
".h\"\n"
1415 f <<
"#define SZ_MEM " <<
n_mem() <<
"\n";
1418 size_t sz_arg, sz_res, sz_iw, sz_w;
1419 gen.
sz_work(sz_arg, sz_res, sz_iw, sz_w);
1420 f <<
"#define SZ_ARG " << sz_arg <<
"\n"
1421 <<
"#define SZ_RES " << sz_res <<
"\n"
1422 <<
"#define SZ_IW " << sz_iw <<
"\n"
1423 <<
"#define SZ_W " << sz_w <<
"\n";
1426 f <<
"const size_t var_offset[N_VAR + 1] = {0";
1429 mem_ind += v->numel;
1430 f <<
", " << mem_ind;
1458 std::vector<size_t> xdot;
1460 f <<
"fmi3ValueReference xdot_vr[N_X] = " <<
generate(xdot) <<
";\n"
1482 return wrapper_filename;
1491 }
catch (std::exception& e) {
1492 THROW_ERROR_NODE(
"read_variable", node, e.what());
1505 casadi_error(
"Cannot read attribute " +
to_string(att));
1512 const std::string& fullname = node.
name;
1514 if (fullname ==
"fun:If") {
1516 const XmlNode& cond = node[
"fun:Condition"];
1517 const XmlNode& then_stmt = node[
"fun:Statements"];
1518 const XmlNode& else_stmt = node[
"fun:Else"];
1520 casadi_assert(cond.
size() == 1,
"Only one condition in if expression supported");
1521 casadi_assert(then_stmt.
size() == 1,
"Only one then statement in if expression supported");
1522 casadi_assert(else_stmt.
size() == 1,
"Only one else statement in if expression supported");
1526 if (fullname.find(
"exp:")== std::string::npos) {
1527 casadi_error(
"DaeBuilderInternal::read_expr: unknown - expression is supposed to "
1528 "start with 'exp:' , got " + fullname);
1532 std::string
name = fullname.substr(4);
1539 }
else if (
name==
"Acos") {
1541 }
else if (
name==
"Asin") {
1543 }
else if (
name==
"Atan") {
1545 }
else if (
name==
"Cos") {
1547 }
else if (
name==
"Der") {
1549 }
else if (
name==
"Div") {
1551 }
else if (
name==
"Exp") {
1553 }
else if (
name==
"Identifier") {
1555 }
else if (
name==
"IntegerLiteral" ||
name==
"BooleanLiteral") {
1559 }
else if (
name==
"Instant") {
1563 }
else if (
name==
"Log") {
1565 }
else if (
name==
"Not") {
1567 }
else if (
name==
"LogLeq") {
1569 }
else if (
name==
"LogGeq") {
1571 }
else if (
name==
"LogLt") {
1573 }
else if (
name==
"LogGt") {
1575 }
else if (
name==
"Max") {
1577 }
else if (
name==
"Min") {
1579 }
else if (
name==
"Mul") {
1581 }
else if (
name==
"Neg") {
1583 }
else if (
name==
"NoEvent") {
1586 casadi_int n = node.
size();
1592 for (casadi_int i=n-3; i>=0; i -= 2) {
1597 }
else if (
name==
"Pow") {
1599 }
else if (
name==
"Pre") {
1600 casadi_warning(
"Ignoring pre attribute");
1602 }
else if (
name==
"RealLiteral") {
1606 }
else if (
name==
"Sin") {
1608 }
else if (
name==
"Sqrt") {
1610 }
else if (
name==
"StringLiteral") {
1611 casadi_error(node.
text);
1612 }
else if (
name==
"Sub") {
1614 }
else if (
name==
"Tan") {
1616 }
else if (
name==
"Time") {
1618 }
else if (
name==
"TimedVariable") {
1620 }
else if (
name==
"FunctionCall") {
1623 casadi_warning(
"Function call to '" + fname +
"' incomplete");
1625 const XmlNode& args = node[
"exp:Arguments"];
1626 std::vector<MX> farg(args.
size());
1627 for (casadi_int i = 0; i < args.
size(); ++i) {
1644 }
else if (
name==
"Array") {
1646 std::vector<MX> v(node.
size());
1647 for (casadi_int i = 0; i < v.size(); ++i) v[i] =
read_expr(node[i]);
1652 casadi_error(
"Unknown node: " +
name);
1653 }
catch (std::exception& e) {
1654 THROW_ERROR_NODE(
"read_expr", node, e.what());
1677 stream << std::endl;
1680 if (!
fun_.empty()) {
1681 stream <<
"Functions:" << std::endl;
1683 stream <<
" " << f << std::endl;
1688 stream <<
"Model variables:" << std::endl;
1691 if (
size(cat) > 0) {
1698 if (
size(cat) > 0) {
1700 for (
size_t c :
indices(cat)) {
1702 stream <<
" " << v.
name;
1704 stream << std::endl;
1711 if (
size(cat) > 0) {
1715 for (
size_t k :
indices(cat)) {
1717 stream <<
" " << v.
name <<
": " <<
der(v.
v) << std::endl;
1724 stream <<
"Outputs (y):" << std::endl;
1727 stream <<
" " << v.
name <<
": " << v.
v << std::endl;
1732 stream <<
"Algebraic equations:" << std::endl;
1734 stream <<
" 0 == " <<
variable(k).
v << std::endl;
1738 if (!
init_.empty()) {
1739 stream <<
"Initial equations:" << std::endl;
1740 for (
size_t k :
init_) {
1742 stream <<
" " << v.
name;
1744 stream << std::endl;
1748 if (!
when_.empty()) {
1749 stream <<
"When equations:" << std::endl;
1750 for (
auto weq :
when_) {
1751 stream <<
" when " <<
variable(weq.first).
v <<
" < 0 : " << std::endl;
1752 for (
size_t eq : weq.second) {
1766 std::vector<size_t> new_order;
1767 for (
const MX& e : v) new_order.push_back(
find(e.name()));
1768 std::copy(new_order.begin(), new_order.end(),
indices(cat).begin());
1773 casadi_assert(z_order.size() ==
size(
Category::Z),
"Dimension mismatch");
1778 std::vector<size_t> new_z;
1779 new_z.reserve(z_order.size());
1780 for (
const std::string& s : z_order) {
1782 casadi_assert(old_z.at(i),
"Variable \"" + s +
"\" is not an algebraic variable.");
1790 return indices_.at(
static_cast<size_t>(cat));
1802 const std::vector<size_t>& v)
const {
1804 casadi_assert(ind.size() == v.size(),
"Cannot reorder " + n +
": "
1805 +
str(v.size()) +
" elements provided for " +
str(ind.size()) +
" components.");
1808 for (
size_t i : v) set.at(i) =
true;
1810 for (
size_t i : ind) casadi_assert(set.at(i),
"Cannot reorder " + n +
": "
1813 std::copy(v.begin(), v.end(), ind.begin());
1818 std::vector<MX> f_in, f_out, v;
1819 std::vector<std::string> f_in_name, f_out_name;
1826 f_in.push_back(vertcat(v));
1834 f_out.push_back(vertcat(v));
1839 Function f(
"prune_fcn", f_in, f_out, f_in_name, f_out_name);
1841 std::vector<bool> free_variables(
n_variables(),
false);
1842 for (
const std::string& s : f.
get_free()) {
1844 casadi_assert(it !=
varind_.end(),
"No such variable: \"" + s +
"\".");
1845 free_variables.at(it->second) =
true;
1861 for (
size_t i = 0; i < u.size(); ++i) {
1862 if (!free_variables.at(u.at(i))) u.at(nu++) = u.at(i);
1870 std::vector<std::string> res, iv, iv_on_hold;
1873 std::set<std::string> iv_set;
1874 for (
auto& e : iv) iv_set.insert(e);
1875 for (
auto& e : iv_on_hold) iv_set.insert(e);
1902 std::vector<std::string>* iv, std::vector<std::string>* iv_on_hold)
const {
1904 if (res) res->clear();
1905 if (iv) iv->clear();
1906 if (iv_on_hold) iv_on_hold->clear();
1908 const std::string res_prefix =
"res__";
1910 std::vector<MX> r_hold, iv_hold;
1912 bool any_hold =
false;
1916 if (v->name.rfind(res_prefix, 0) == 0) {
1918 std::string iv_name, res_hold_name, iv_hold_name;
1921 size_t pos = res_prefix.size();
1923 size_t end = v->name.find(
"__", pos);
1924 if (end == std::string::npos) end = v->name.size();
1926 iv_name = v->name.substr(pos, end - pos);
1928 casadi_assert(
has(iv_name),
"No such variable: " + iv_name);
1930 if (end != v->name.size()) {
1933 end = v->name.find(
"__", pos);
1934 if (end == std::string::npos) end = v->name.size();
1935 res_hold_name = v->name.substr(pos, end - pos);
1937 casadi_assert(
has(res_hold_name),
"No such variable: " + res_hold_name);
1939 if (end != v->name.size()) {
1940 iv_hold_name = v->name.substr(end + 2);
1941 casadi_assert(
has(iv_hold_name),
"No such variable: " + iv_hold_name);
1944 }
catch (std::exception& e) {
1946 casadi_warning(
"Cannot process residual variable: " + v->name +
":" +
1947 std::string(e.what()));
1951 if (res_hold_name.empty()) {
1952 r_hold.push_back(
false);
1955 r_hold.push_back(
variable(res_hold_name).v);
1956 casadi_assert(r_hold.back().is_scalar(),
"Non-scalar hold variable for " + res_hold_name);
1958 if (res) res->push_back(v->name);
1960 if (iv_hold_name.empty()) {
1961 iv_hold.push_back(
false);
1964 iv_hold.push_back(
variable(iv_hold_name).v);
1965 casadi_assert(iv_hold.back().is_scalar(),
"Non-scalar hold variable for " + iv_hold_name);
1967 if (iv) iv->push_back(iv_name);
1974 casadi_error(
"not implemented");
1977 Function startfun_p = attribute_fun(
"startfun_p", {}, {
"start_p"});
1979 casadi_error(
"startfun has free variables: " +
str(startfun_p.
get_free()));
1981 DM p0 = startfun_p(std::vector<DM>{}).at(0);
1984 {vertcat(r_hold), vertcat(iv_hold)}, {
"p"}, {
"r_hold",
"iv_hold"});
1985 if (holdfun.has_free()) {
1986 casadi_error(
"holdfun has free variables: " +
str(holdfun.get_free()));
1989 std::vector<DM> hold0 = holdfun(std::vector<DM>{p0});
1990 std::vector<double> r_hold0 = hold0.at(0).nonzeros();
1991 std::vector<double> iv_hold0 = hold0.at(1).nonzeros();
1992 casadi_assert_dev(r_hold0.size() == res->size());
1993 casadi_assert_dev(iv_hold0.size() == iv->size());
1997 for (
size_t k = 0; k < res->size(); ++k) {
1998 if (!
static_cast<bool>(r_hold0.at(k))) {
1999 res->at(sz++) = res->at(k);
2006 for (
size_t k = 0; k < iv->size(); ++k) {
2007 if (!
static_cast<bool>(iv_hold0.at(k))) {
2008 if (iv) iv->at(sz++) = iv->at(k);
2010 if (iv_on_hold) iv_on_hold->push_back(iv->at(k));
2013 if (iv) iv->resize(sz);
2015 }
catch (std::exception& e) {
2017 casadi_warning(
"Failed to evaluate hold variables: " + std::string(e.what()));
2027 std::vector<std::string> r;
2044 const std::vector<casadi_int>& dimension,
const MX& expr) {
2046 casadi_assert(!
name.empty(),
"Name is empty string");
2048 casadi_assert(!
has(
name),
"Variable \"" +
name +
"\" already exists.");
2063 casadi_assert(
size(
Category::T) == 1,
"At most one time variable allowed");
2070 std::stringstream qn;
2071 bool first_part =
true;
2075 for (casadi_int i=0; i<nn.
size(); ++i) {
2077 std::string np = nn[i].
attribute<std::string>(
"name");
2080 if (np ==
"$START") {
2084 casadi_error(
"Ignoring attribute " + np);
2087 }
else if (np ==
"$PRE") {
2088 casadi_warning(
"$PRE attribute has not been implemented, ignoring");
2093 if (!first_part) qn <<
".";
2097 if (nn[i].
size()>0) {
2099 nn[i][
"exp:ArraySubscripts"][
"exp:IndexExpression"][
"exp:IntegerLiteral"].
get(&ind);
2100 qn <<
"[" << ind <<
"]";
2121 casadi_assert(
var.
is_column(),
"Input expression must be a vector");
2128 for (
MX& s : var_split) s =
der(s, may_allocate);
2133 std::vector<MX> dep = symvar(
var);
2135 std::vector<MX> dep_der;
2136 for (
size_t ind :
find(dep)) dep_der.push_back(
get_der(ind, may_allocate));
2139 std::vector<std::vector<MX>> r = {dep_der};
2140 r = forward(std::vector<MX>{
var}, dep, r);
2141 casadi_assert_dev(r.size() == 1);
2142 return vertcat(r.at(0));
2146 bool allow_no_prefix)
const {
2148 if (allow_no_prefix && !
has(prefix))
return prefix;
2151 while (
has(prefix +
str(i))) i++;
2153 return prefix +
str(i);
2164 casadi_assert(
is_acyclic(cat),
"Elimination not supported for category " +
to_string(cat));
2167 if (
size(cat) == 0)
return;
2175 if (!v->v.is_constant()) ex.push_back(v->v);
2178 std::vector<size_t> ind =
indices(cat);
2179 std::vector<MX> v =
var(ind);
2181 substitute_inplace(v, vdef, ex);
2183 auto it = ex.begin();
2185 if (!v->v.is_constant()) v->v = *it++;
2188 casadi_assert_dev(it == ex.end());
2190 for (
size_t k : ind) {
2204 std::vector<MX> new_w, new_wdef;
2205 Dict opts{{
"lift_shared", lift_shared}, {
"lift_calls", lift_calls},
2206 {
"prefix",
"w_"}, {
"suffix",
""}, {
"offset",
static_cast<casadi_int
>(
size(
Category::W))}};
2207 extract(ex, new_w, new_wdef, opts);
2209 for (
size_t i = 0; i < new_w.size(); ++i) {
2217 auto it = ex.begin();
2222 casadi_assert_dev(it == ex.end());
2233 casadi_error(
"No input category for " +
to_string(cat));
2239 to_string(ind) +
" is not an input category");
2245 std::vector<MX> ret(ind.size());
2246 for (casadi_int i=0; i<ind.size(); ++i) {
2247 ret[i] = vertcat(
inputs(ind[i]));
2265 std::vector<MX> ret;
2266 ret.reserve(
size(cat));
2272 for (
size_t v :
indices(cat)) {
2282 casadi_error(
"Missing derivative for " +
str(x.
name));
2297 std::vector<MX> ret(ind.size());
2298 for (casadi_int i=0; i<ind.size(); ++i) {
2299 ret[i] = vertcat(
outputs(ind[i]));
2309 casadi_assert(!
name.empty(),
"DaeBuilderInternal::add_lc: \"name\" is empty");
2310 for (std::string::const_iterator i=
name.begin(); i!=
name.end(); ++i) {
2311 casadi_assert(isalnum(*i),
2312 "DaeBuilderInternal::add_lc: \"name\" must be alphanumeric");
2316 casadi_assert(!f_out.empty(),
"DaeBuilderInternal::add_lc: Linear combination is empty");
2318 for (casadi_int i=0; i < f_out.size(); ++i) {
2319 auto oind =
static_cast<size_t>(to_enum<Category>(f_out[i]));
2320 casadi_assert(!in_use[oind],
"DaeBuilderInternal::add_lc: Duplicate expression " + f_out[i]);
2321 in_use[oind] =
true;
2324 std::vector<std::string>& ret1 =
lc_[
name];
2325 if (!ret1.empty()) casadi_warning(
"DaeBuilderInternal::add_lc: Overwriting " <<
name);
2330 const std::vector<std::string>& s_in,
2331 const std::vector<std::string>& s_out,
const Dict& opts,
bool sx,
bool lifted_calls)
const {
2333 bool with_underscore =
false;
2334 for (
const auto *s_io : {&s_in, &s_out}) {
2335 for (
const std::string& s : *s_io) {
2336 with_underscore = with_underscore || std::count(s.begin(), s.end(),
'_');
2342 casadi_assert(!lifted_calls,
"Lifting requires a symbolic representation");
2344 casadi_assert(!sx,
"SX expansion requires a symbolic representation");
2346 return fmu_fun(fname, s_in, s_out, opts);
2349 if (with_underscore) {
2350 std::vector<std::string> s_in_mod(s_in), s_out_mod(s_out);
2351 for (
auto *s_io : {&s_in_mod, &s_out_mod}) {
2352 for (std::string& s : *s_io) std::replace(s.begin(), s.end(),
'_',
':');
2355 return create(fname, s_in_mod, s_out_mod, opts, sx, lifted_calls);
2358 bool elim_w =
false;
2362 for (
const std::string& s : s_in) {
2373 casadi_assert(!elim_w,
"Lifted calls cannot be used if dependent variables are eliminated");
2375 lifted_calls =
false;
2377 if (vdef_comp.is_output()) {
2379 lifted_calls =
true;
2385 std::string fname_nocalls = lifted_calls ? fname +
"_nocalls" : fname;
2388 if (!lifted_calls)
return ret;
2390 std::vector<MX> ret_in = ret.
mx_in();
2391 std::vector<MX> ret_out = ret(ret_in);
2395 std::vector<MX> v_in, lam_vdef_in;
2396 for (
size_t i = 0; i < s_in.size(); ++i) {
2398 v_in = vertsplit(ret_in[i], h_offsets);
2399 }
else if (ret.
name_in(i) ==
"lam_wdef") {
2400 lam_vdef_in = vertsplit(ret_in[i], h_offsets);
2404 std::map<MXNode*, size_t> v_map;
2411 std::map<MXNode*, CallIO> call_nodes;
2412 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2414 const MX& vdefref = wdef.at(vdefind);
2418 MX c = vdefref.
dep(0);
2420 auto call_it = call_nodes.
find(c.
get());
2422 if (call_it == call_nodes.end()) {
2428 cio.
v.resize(c.
n_dep(), -1);
2429 cio.
arg.resize(cio.
v.size());
2430 for (casadi_int i = 0; i < cio.
v.size(); ++i) {
2432 cio.
arg.at(i) = c.
dep(i);
2434 size_t v_ind = v_map.at(c.
dep(i).
get());
2435 cio.
v.at(i) = v_ind;
2436 cio.
arg.at(i) = v_in.at(v_ind);
2441 cio.
res.resize(cio.
vdef.size());
2445 call_it = call_nodes.insert(std::make_pair(c.
get(), cio)).first;
2450 call_it->second.vdef.at(oind) = vdefind;
2451 call_it->second.res.at(oind) = v_in.at(vdefind);
2453 if (!lam_vdef_in.empty()) call_it->second.adj1_arg.at(oind) = lam_vdef_in.at(vdefind);
2457 for (
size_t i = 0; i < ret_out.size(); ++i) {
2458 if (ret.
name_out(i) ==
"jac_wdef_w") {
2464 for (
auto&& e :
lc_) {
2466 bool has_vdef =
false;
2467 for (
const std::string& r : e.second) {
2474 if (!has_vdef)
continue;
2476 for (
size_t i = 0; i < ret_out.size(); ++i) {
2477 if (ret.
name_out(i) ==
"hess_" + e.first +
"_w_w") {
2482 ret_out.at(i) += extra_hess_v_v;
2492 const std::vector<casadi_int>& h_offsets)
const {
2494 for (
auto call_it = call_nodes.begin(); call_it != call_nodes.end(); ++call_it) {
2495 call_it->second.calc_jac();
2498 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2500 std::vector<MX> vblocks, hblocks;
2502 std::map<size_t, MX> jac_brow;
2506 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2508 const MX& vdefref = wdef.at(vdefind);
2510 voffset_begin = voffset_end;
2511 voffset_end += vdefref.
numel();
2517 MX c = vdefref.
dep(0);
2519 auto call_it = call_nodes.
find(c.
get());
2520 casadi_assert_dev(call_it != call_nodes.end());
2523 for (casadi_int iind = 0; iind < call_it->second.arg.size(); ++iind) {
2524 size_t vind = call_it->second.v.at(iind);
2525 if (vind !=
size_t(-1)) {
2526 jac_brow[vind] = call_it->second.jac(oind, iind);
2530 if (voffset_last != voffset_begin) {
2531 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2535 casadi_int hoffset = 0;
2536 for (
auto e : jac_brow) {
2538 if (hoffset < h_offsets.at(e.first))
2539 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.at(e.first) - hoffset));
2541 hblocks.push_back(e.second);
2543 hoffset = h_offsets.at(e.first + 1);
2546 if (hoffset < h_offsets.back())
2547 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.back() - hoffset));
2549 vblocks.push_back(horzcat(hblocks));
2551 voffset_last = voffset_end;
2555 if (voffset_last != voffset_end) {
2556 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2559 return vertcat(vblocks);
2563 const std::vector<casadi_int>& h_offsets)
const {
2565 for (
auto&& call_ref : call_nodes) call_ref.second.calc_hess();
2567 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2569 std::vector<MX> vblocks, hblocks;
2571 std::map<size_t, MX> hess_brow;
2577 voffset_begin = voffset_end;
2578 voffset_end += vref.
numel();
2581 for (
auto&& call_ref : call_nodes) {
2583 for (
size_t iind1 = 0; iind1 < call_ref.second.v.size(); ++iind1) {
2584 if (call_ref.second.v.at(iind1) == vind1) {
2586 for (
size_t iind2 = 0; iind2 < call_ref.second.v.size(); ++iind2) {
2588 size_t vind2 = call_ref.second.v[iind2];
2589 if (vind2 ==
size_t(-1))
continue;
2591 MX H_contr = call_ref.second.hess(iind1, iind2);
2593 auto it = hess_brow.
find(vind2);
2594 if (it != hess_brow.end()) {
2595 it->second += H_contr;
2597 hess_brow[vind2] = H_contr;
2606 if (hess_brow.empty())
continue;
2608 if (voffset_last != voffset_begin) {
2609 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2613 casadi_int hoffset = 0;
2614 for (
auto e : hess_brow) {
2616 if (hoffset < h_offsets.at(e.first))
2617 hblocks.push_back(
MX(vref.
numel(), h_offsets.at(e.first) - hoffset));
2619 hblocks.push_back(e.second);
2621 hoffset = h_offsets.at(e.first + 1);
2624 if (hoffset < h_offsets.back())
2625 hblocks.push_back(
MX(vref.
numel(), h_offsets.back() - hoffset));
2627 vblocks.push_back(horzcat(hblocks));
2629 voffset_last = voffset_end;
2632 if (voffset_last != voffset_end) {
2633 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2636 return vertcat(vblocks);
2640 for (
bool sx : {
false,
true}) {
2641 for (
bool elim_w : {
false,
true}) {
2642 for (
bool lifted_calls : {
false,
true}) {
2652 casadi_assert(
symbolic_,
"DaeBuilder oracle only available if symbolic representation");
2657 if (
oracle_[
false][elim_w][lifted_calls].is_null()) {
2659 std::vector<MX> f_in, f_out, v;
2660 std::vector<std::string> f_in_name, f_out_name;
2662 casadi_int wdef_ind = -1;
2664 casadi_assert(!(elim_w && lifted_calls),
"Incompatible options");
2666 bool subst_v =
false;
2668 bool subst_c =
false;
2673 if (!v.empty()) subst_v =
true;
2675 if (!v.empty()) subst_c =
true;
2678 f_in.push_back(
MX(0, 1));
2680 f_in.push_back(vertcat(v));
2691 f_out.push_back(
MX(0, 1));
2694 f_out.push_back(vertcat(v));
2703 }
else if (lifted_calls && wdef_ind >= 0) {
2707 for (
MX& wdefref : wdef) {
2708 if (wdefref.is_output()) wdefref =
MX::zeros(wdefref.sparsity());
2711 f_out.at(wdef_ind) = vertcat(wdef);
2717 std::vector<casadi::MX>
cdef;
2718 for (
size_t i = 0; i < c.size(); ++i) {
2722 f_out = substitute(f_out, c,
cdef);
2726 oracle_[
false][elim_w][lifted_calls]
2727 =
Function(
"mx_oracle", f_in, f_out, f_in_name, f_out_name);
2730 if (!sx)
return oracle_[
false][elim_w][lifted_calls];
2740 for (casadi_int i = 0; i < this->
f.
n_in(); ++i) {
2741 casadi_assert(this->
f.
size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2743 for (casadi_int i = 0; i < this->
f.
n_out(); ++i) {
2744 casadi_assert(this->
f.
size_out(i) == this->res.at(i).size(),
"Call output not provided");
2751 std::vector<MX> call_in = this->
arg;
2752 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2759 for (casadi_int i = 0; i < this->f.n_in(); ++i) {
2760 casadi_assert(this->f.size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2762 casadi_assert(this->adj1_arg.size() == this->res.size(),
"Input 'lam_vdef' not provided");
2763 for (casadi_int i = 0; i < this->f.n_out(); ++i) {
2764 casadi_assert(this->f.size_out(i) == this->res.at(i).size(),
"Call output not provided");
2765 casadi_assert(this->adj1_arg.at(i).size() == this->res.at(i).size(),
2766 "Call adjoint seed not provided");
2769 if (!this->jac_res.empty())
2770 casadi_warning(
"Jacobian blocks currently not reused for gradient calculation");
2773 this->adj1_f = this->f.reverse(1);
2776 std::vector<MX> call_in = this->arg;
2777 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2778 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2780 this->adj1_res = this->adj1_f(call_in);
2785 if (this->adj1_f.is_null()) calc_grad();
2788 this->H = this->adj1_f.jacobian();
2791 std::vector<MX> call_in = this->arg;
2792 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2793 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2794 call_in.insert(call_in.end(), this->adj1_res.begin(), this->adj1_res.end());
2796 this->hess_res = this->H(call_in);
2801 casadi_int ind = iind + oind * this->arg.
size();
2803 return this->jac_res.at(ind);
2808 casadi_int ind = iind1 + iind1 * this->adj1_arg.
size();
2810 return this->hess_res.at(ind);
2815 Function vfcn(
"vfcn", {vertcat(v)}, {vertcat(vdef)}, {
"v"}, {
"vdef"},
2816 Dict{{
"allow_free",
true}});
2818 bool any_vector_valued =
false;
2819 for (
const MX& v_i : v) {
2820 casadi_assert(!v_i.is_empty(),
"Cannot have zero-dimension dependent variables");
2821 if (!v_i.is_scalar()) {
2822 any_vector_valued =
true;
2827 if (any_vector_valued) {
2829 std::vector<MX> vfcn_in(v), vfcn_arg(v);
2830 for (
size_t i = 0; i < v.size(); ++i) {
2831 if (!v.at(i).is_scalar()) {
2832 vfcn_in.at(i) =
MX::sym(v.at(i).name());
2833 vfcn_arg.at(i) = repmat(vfcn_in.at(i), v.at(i).size1());
2837 std::vector<MX> vfcn_out = vfcn(vertcat(vfcn_arg));
2838 vfcn_out = vertsplit(vfcn_out.at(0), offset(v));
2840 for (
size_t i = 0; i < v.size(); ++i) {
2841 if (!v.at(i).is_scalar()) {
2842 vfcn_out.at(i) =
dot(vfcn_out.at(i), vfcn_out.at(i));
2846 vfcn =
Function(vfcn.name(), {vertcat(vfcn_in)}, {vertcat(vfcn_out)},
2847 vfcn.name_in(), vfcn.name_out(), {{
"allow_free", true}});
2850 Sparsity Jv = vfcn.jac_sparsity(0, 0);
2856 std::vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
2857 (void)Jv.
btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
2859 std::vector<MX> tmp(v.size());
2860 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = v.at(colperm.at(k));
2861 std::copy(tmp.begin(), tmp.end(), v.begin());
2863 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = vdef.at(rowperm.at(k));
2864 std::copy(tmp.begin(), tmp.end(), vdef.begin());
2868 const std::vector<std::string>& s_in,
2869 const std::vector<std::string>& s_out)
const {
2871 bool calc_d =
false, calc_w =
false;
2873 std::vector<Category> v_out;
2874 v_out.reserve(v_out.size());
2875 for (
const std::string& s : s_out) {
2882 casadi_error(
"Can only calculate d and/or w");
2887 casadi_assert(calc_d || calc_w,
"Nothing to calculate");
2889 std::vector<Category> v_in;
2890 v_in.reserve(v_in.size());
2891 for (
const std::string& s : s_in) {
2893 if (calc_d && e ==
Category::D) casadi_error(
"'d' cannot be both input and output");
2894 if (calc_w && e ==
Category::W) casadi_error(
"'w' cannot be both input and output");
2898 std::vector<MX> f_in;
2899 f_in.reserve(s_in.size());
2902 std::vector<MX> f_out;
2903 f_out.reserve(s_out.size());
2906 std::vector<MX> dw, dwdef;
2909 dw.insert(dw.end(), d.begin(), d.end());
2911 dwdef.insert(dwdef.end(), ddef.begin(), ddef.end());
2915 dw.insert(dw.end(), w.begin(), w.end());
2917 dwdef.insert(dwdef.end(), wdef.begin(), wdef.end());
2920 substitute_inplace(dw, dwdef, f_out);
2922 return Function(fname, f_in, f_out, s_in, s_out);
2926 bool dummy_index_input)
const {
2929 casadi_assert(index >= 0 && index <
when_.size(),
"Illegal event index");
2944 std::vector<MX> when_lhs, when_rhs;
2945 for (
size_t eq :
when_.at(index).second) {
2952 std::vector<MX> ret_out = {ret_in[
DYN_X], ret_in[
DYN_Z]};
2964 if (dummy_index_input) {
2966 ret_in.insert(ret_in.begin(),
MX());
2982 std::vector<Function> f_all;
2983 for (casadi_int i = 0; i <
when_.size(); ++i) {
2997 const std::vector<std::string>& name_in,
2998 const std::vector<std::string>& name_out,
2999 const Dict& opts)
const {
3001 Dict::const_iterator it;
3003 std::vector<std::string> scheme_in;
3004 bool has_in =
false;
3005 it = opts.find(
"scheme_in");
3006 if (it != opts.end()) {
3008 scheme_in = it->second;
3009 }
catch (std::exception& e) {
3010 casadi_error(std::string(
"Cannot read 'scheme_in': ") + e.what());
3016 std::vector<std::string> scheme_out;
3017 bool has_out =
false;
3018 it = opts.find(
"scheme_out");
3019 if (it != opts.end()) {
3021 scheme_out = it->second;
3023 }
catch (std::exception& e) {
3024 casadi_error(std::string(
"Cannot read 'scheme_out': ") + e.what());
3028 if (!has_in || !has_out) {
3030 has_out ?
nullptr : &scheme_out, name_in, name_out);
3033 std::map<std::string, std::vector<size_t>> scheme;
3034 it = opts.find(
"scheme");
3035 if (it != opts.end()) {
3038 Dict scheme_dict = it->second;
3040 for (
auto&& e : scheme_dict) {
3041 std::vector<std::string> v = e.second;
3042 scheme[e.first] =
find(v);
3044 }
catch (std::exception& e) {
3045 casadi_error(std::string(
"Cannot read 'scheme': ") + e.what());
3049 for (
auto&& s :
dyn_in()) scheme[s] = std::vector<size_t>();
3050 for (
auto&& s :
dyn_out()) scheme[s] = std::vector<size_t>();
3058 for (
size_t& i : scheme[
"ode"]) i =
variable(i).
der;
3060 for (
size_t& i : scheme[
"quad"]) i =
variable(i).
der;
3065 std::vector<std::string> aux;
3066 it = opts.find(
"aux");
3067 if (it != opts.end()) {
3070 }
catch (std::exception& e) {
3071 casadi_error(std::string(
"Cannot read 'aux': ") + e.what());
3076 scheme_in, scheme_out, scheme, aux);
3084 std::vector<MX> f_out;
3086 std::vector<std::string> f_out_name;
3089 std::vector<MX> v =
outputs(cat);
3091 f_out.push_back(vertcat(v));
3096 return Function(
"all_eq", {}, f_out, {}, f_out_name, {{
"allow_free",
true}});
3100 casadi_assert(
has_t(),
"No explicit time variable");
3132 std::vector<MX> ret;
3139 std::vector<MX> ret;
3140 ret.reserve(
init_.size());
3141 for (
size_t ind :
init_) {
3148 std::vector<MX> ret;
3149 ret.reserve(
init_.size());
3150 for (
size_t ind :
init_) {
3220 std::string
description, type, initial, unit, display_unit;
3221 std::vector<casadi_int> dimension = {1};
3223 std::vector<double> start;
3225 for (
auto&& op : opts) {
3226 if (op.first==
"dimension") {
3227 dimension = op.second.to_int_vector();
3228 }
else if (op.first==
"description") {
3230 }
else if (op.first==
"unit") {
3231 unit = op.second.to_string();
3232 }
else if (op.first==
"display_unit") {
3233 display_unit = op.second.to_string();
3234 }
else if (op.first==
"min") {
3235 min = op.second.to_double();
3236 }
else if (op.first==
"max") {
3237 max = op.second.to_double();
3238 }
else if (op.first==
"nominal") {
3239 nominal = op.second.to_double();
3240 }
else if (op.first==
"start") {
3242 start.resize(1, op.second.to_double());
3244 start = op.second.to_double_vector();
3246 }
else if (op.first==
"type") {
3247 type = op.second.to_string();
3248 }
else if (op.first==
"initial") {
3249 initial = op.second.to_string();
3251 casadi_error(
"No such option: " + op.first);
3263 casadi_assert(
orig_time_index_ == -1,
"Only one independent variable is permitted");
3285 if (!type.empty()) v.
type = to_enum<Type>(type);
3288 if (!start.empty()) v.
value = v.
start = start;
3289 if (!initial.empty()) {
3290 v.
initial = to_enum<Initial>(initial);
3294 if (!unit.empty()) v.
unit = unit;
3295 if (!display_unit.empty()) v.
display_unit = display_unit;
3308 casadi_error(
"'parameter' causality requires 'fixed' or 'tunable' variability");
3313 "'calculatedParameter' causality requires 'fixed' or 'tunable' variability");
3320 "'input' causality requires 'continuous' or 'discrete' variability");
3335 casadi_error(
"'output' causality requires 'constant', 'continuous' or "
3336 "'discrete' variability");
3354 casadi_error(
"'output' causality requires 'constant', 'fixed', 'tunable', 'discrete' or "
3355 "'continuous' variability");
3361 "Independent variable must be continuous");
3378 if (opts.find(
"type") != opts.end()) {
3379 type = to_enum<Type>(opts.at(
"type").to_string());
3410 size_t loc = v.size();
3411 for (
size_t i = 0; i < v.size(); ++i) {
3417 v.insert(v.begin() + loc, ind);
3421 for (
auto it = v.begin(); it != v.end(); ++it) {
3427 casadi_error(
"Variable not found");
3448 casadi_error(
"Cannot change causality of " + v.
name +
" which is of category '"
3479 casadi_error(
"The variability of " + v.
name +
", which is of category 'u', can only be "
3480 "changed to 'fixed' (for no category) or 'tunable' (for category 'p')");
3494 casadi_error(
"The variability of " + v.
name +
", which is of category 'p', can only be "
3495 "changed to 'continuous' (for category 'u') or 'fixed' (for no category)");
3509 casadi_error(
"The variability of " + v.
name +
", which is of type 'c', can only be "
3510 "changed to 'continuous' (for category 'u') or 'tunable' (for category 'p')");
3514 casadi_error(
"Cannot change variability of " + v.
name +
", which is of category '"
3593 casadi_error(
"Cannot change category of " + v.
name +
" from '"
3599 for (
auto&& op : opts) {
3600 casadi_error(
"No such option: " + op.first);
3603 casadi_assert(lhs.
is_column(),
"Left-hand-side must be a column vector");
3604 casadi_assert(rhs.
is_column(),
"Right-hand-side must be a column vector");
3607 eq(densify(lhs), rhs, opts);
3611 eq(lhs, densify(rhs), opts);
3618 eq(repmat(lhs, rhs.
size1()), rhs, opts);
3620 }
else if (lhs.
size1() > 1 && rhs.
size1() == 1) {
3621 eq(lhs, repmat(rhs, lhs.
size1()), opts);
3624 casadi_error(
"Mismatched dimensions: " +
str(lhs.
size1()) +
" vs " +
str(rhs.
size1()));
3628 std::vector<size_t> rhs_vars =
find(symvar(rhs));
3632 for (
size_t rhs : rhs_vars) {
3638 casadi_assert(x.
der == v.
index,
"Cannot handle right-hand-side variable: " + v.
name);
3642 {{
"dimension", {x.dimension}}});
3644 eq(x.get_der(*
this), der_x.v,
Dict());
3648 if (lhs.is_valid_input()) {
3650 if (lhs.is_symbolic()) {
3656 eq(
MX::zeros(lhs.sparsity()), lhs - rhs, opts);
3660 Variable& beq = assign(v.
name, rhs);
3668 casadi_assert(x.der == v.
index,
"Cannot handle left-hand-side: " +
str(lhs));
3677 Variable& def_x = add(unique_name(
"def_" + x.name,
true),
3679 {{
"dimension", {x.dimension}}});
3681 def_x.bind = x.bind;
3688 x.v - def_x.v, {{
"dimension", x.dimension}});
3692 casadi_error(
"Unexpected category for " + x.name +
": " +
to_string(x.category));
3698 casadi_error(
"Cannot handle left-hand-side: " +
str(lhs) +
" of category '"
3703 auto lhs_split = lhs.primitives();
3704 std::vector<MX> rhs_split = lhs.split_primitives(rhs);
3706 for (
size_t k = 0; k < lhs_split.size(); ++k) {
3707 eq(lhs_split.at(k), rhs_split.at(k), opts);
3714 lhs - rhs, {{
"dimension", std::vector<casadi_int>{lhs.size1()}}});
3719 for (
size_t rhs : rhs_vars) {
3731 for (
auto&& op : opts) {
3732 casadi_error(
"No such option: " + op.first);
3737 zero = cond.
dep(0) - cond.
dep(1);
3739 casadi_error(
"Only strict inequality in zero-crossing conditions permitted, got: "
3742 casadi_error(
"Cannot parse zero-crossing condition: " +
str(cond));
3750 std::vector<MX> all_lhs, all_rhs;
3751 std::vector<size_t> all_eqs;
3752 for (
auto&&
eq : eqs) {
3756 all_rhs.push_back(ee.
v);
3757 all_eqs.push_back(ee.
index);
3759 when_.push_back(std::make_pair(e.
index, all_eqs));
3764 std::string assign_name =
unique_name(
"__assign__" +
name +
"__",
true);
3794 if (old_loc ==
init_.end()) casadi_error(
"Corrupted list of initial equations");
3795 init_.erase(old_loc);
3803 casadi_error(
"Initial equation for " +
name +
" has already been set");
3810 template<
typename T>
3813 size_t sz = n.
size();
3817 for (
size_t i = 0; i < sz; ++i) {
3818 r.push_back(
T(n[i]));
3833 fmi_major_ >= 3 ?
"providesDirectionalDerivatives" :
"providesDirectionalDerivative",
false);
3835 = n.
attribute<
bool>(
"providesAdjointDerivatives",
false);
3838 n.
attribute<
bool>(
"canBeInstantiatedOnlyOncePerProcess",
false);
3841 for (
const XmlNode& sf : n[
"SourceFiles"].children) {
3849 std::vector<std::pair<std::string, std::string>> fmi1_der;
3852 for (casadi_int i = 0; i < modvars.
size(); ++i) {
3854 const XmlNode& vnode = modvars[i];
3861 std::string variable_category = vnode[
"VariableCategory"].
text;
3862 if (variable_category ==
"derivative") {
3864 std::string x_name = vnode[
"QualifiedName"][0].
attribute<std::string>(
"name");
3865 fmi1_der.push_back(std::make_pair(x_name,
name));
3870 if (
fmi_major_ == 1 &&
name.rfind(
"$whenCondition", 0) == 0)
continue;
3874 casadi_warning(
"Duplicate variable '" +
name +
"' ignored");
3881 casadi_int derivative = -1;
3884 type = to_enum<Type>(vnode.
name);
3889 opts[
"unit"] = vnode.
attribute<std::string>(
"unit",
"");
3890 opts[
"display_unit"] = vnode.
attribute<std::string>(
"displayUnit",
"");
3893 opts[
"nominal"] = vnode.
attribute<
double>(
"nominal", 1.);
3894 opts[
"start"] = vnode.
attribute<
double>(
"start", 0.);
3895 derivative = vnode.
attribute<casadi_int>(
"derivative", -1);
3916 const XmlNode& props = vnode[
"Real"];
3917 opts[
"unit"] = props.
attribute<std::string>(
"unit",
"");
3918 opts[
"display_unit"] = props.
attribute<std::string>(
"displayUnit",
"");
3921 opts[
"nominal"] = props.
attribute<
double>(
"nominal", 1.);
3922 opts[
"start"] = props.
attribute<
double>(
"start", 0.);
3923 derivative = props.
attribute<casadi_int>(
"derivative", -1);
3924 }
else if (vnode.
has_child(
"Integer")) {
3926 const XmlNode& props = vnode[
"Integer"];
3929 }
else if (vnode.
has_child(
"Boolean")) {
3933 }
else if (vnode.
has_child(
"Enumeration")) {
3936 casadi_warning(
"Unknown type for " +
name);
3944 std::string causality_str = vnode.
attribute<std::string>(
"causality",
"local");
3945 if (
fmi_major_ == 1 && causality_str ==
"internal") causality_str =
"local";
3949 std::string variability_str = vnode.
attribute<std::string>(
"variability",
3951 if (
fmi_major_ == 1 && variability_str ==
"parameter") variability_str =
"fixed";
3956 std::string initial_str = vnode.
attribute<std::string>(
"initial",
"");
3957 if (!initial_str.empty()) {
3961 "initial = '" + initial_str +
"' is not allowed per the FMI specification.");
3962 initial = to_enum<Initial>(initial_str);
3991 var.der_of = derivative;
3996 var.value_reference =
static_cast<unsigned int>(vnode.
attribute<casadi_int>(
"valueReference"));
4019 for (
auto& p : fmi1_der) {
4033 "Default 'dependencies' not implemented");
4035 std::vector<casadi_int> r = n.
attribute<std::vector<casadi_int>>(
"dependencies", {});
4037 for (casadi_int& e : r) {
4040 e =
vrmap_.at(
static_cast<unsigned int>(e));
4051 const XmlNode& n,
size_t ndep) {
4058 auto dk_str = n.
attribute<std::vector<std::string>>(
"dependenciesKind");
4060 casadi_assert(dk_str.size() == ndep,
"Mismatching 'dependenciesKind'");
4062 std::vector<DependenciesKind> r(ndep);
4063 for (
size_t i = 0; i < ndep; ++i) {
4064 r[i] = to_enum<DependenciesKind>(dk_str[i]);
4086 bool has_lsdae =
false;
4087 std::string lsdae =
resource_.
path() +
"/extra/org.fmi-standard.fmi-ls-dae/fmi-ls-manifest.xml";
4094 for (casadi_int i = 0; i < n.
size(); ++i) {
4096 if (e.
name !=
"ContinuousStateDerivative" && e.
name !=
"Output") {
4102 }
catch (
const std::exception& e) {
4103 casadi_warning(
"Failed to load LS-DAE manifest: " + std::string(e.what()));
4108 const XmlNode& ms = has_lsdae ? lsdae_ms : n;
4109 for (casadi_int i = 0; i < ms.
size(); ++i) {
4113 if (e.
name ==
"Output") {
4124 }
else if (e.
name ==
"ContinuousStateDerivative") {
4130 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
4141 }
else if (e.
name ==
"ClockedState") {
4143 casadi_message(
"ClockedState not implemented, ignoring");
4144 }
else if (e.
name ==
"InitialUnknown") {
4149 }
else if (e.
name ==
"EventIndicator") {
4153 }
else if (e.
name ==
"Residual") {
4156 for (casadi_int form = 0; form < e.
size(); ++form) {
4158 auto form_index = f.
attribute<
size_t>(
"index");
4159 if (form_index == 1) {
4161 casadi_assert(!found,
"Duplicate index-1 formulations");
4165 f.
attribute<
size_t>(
"valueReference")));
4173 casadi_assert(found,
"Missing index-1 formulation");
4176 casadi_error(
"Unknown ModelStructure element: " + e.
name);
4178 }
catch (
const std::exception& ex) {
4179 casadi_error(
"Error processing ModelStructure element: " + e.
name +
": " + ex.what());
4185 for (
const auto& e : n[
"Derivatives"].children) {
4191 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
4201 std::vector<casadi_int> default_dependencies;
4202 default_dependencies.insert(default_dependencies.begin(),
4204 default_dependencies.insert(default_dependencies.begin(),
4206 default_dependencies.insert(default_dependencies.begin(),
4208 std::sort(default_dependencies.begin(), default_dependencies.end());
4217 std::vector<casadi_int> additional_dependencies;
4218 additional_dependencies.insert(additional_dependencies.begin(),
4220 std::vector<DependenciesKind> additional_dependencies_kind(
size(
Category::P),
4226 for (
const auto& e : n[
"Derivatives"].children) {
4227 casadi_int index =
convert_index(e.attribute<casadi_int>(
"index", 0));
4233 if (e.has_attribute(
"dependencies")) {
4241 additional_dependencies.begin(), additional_dependencies.end());
4243 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
4252 for (
const auto& e : n[
"Outputs"].children) {
4259 if (e.has_attribute(
"dependencies")) {
4267 additional_dependencies.begin(), additional_dependencies.end());
4269 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
4278 default_dependencies.clear();
4279 default_dependencies.insert(default_dependencies.begin(),
4282 if (v->initial ==
Initial::EXACT) default_dependencies.push_back(v->index);
4284 default_dependencies.insert(default_dependencies.begin(),
4286 std::sort(default_dependencies.begin(), default_dependencies.end());
4290 for (
const auto& e : n[
"InitialUnknowns"].children) {
4294 std::vector<casadi_int> dependencies;
4296 if (e.has_attribute(
"dependencies")) {
4299 dependencies = default_dependencies;
4302 dependencies.insert(dependencies.end(),
4303 additional_dependencies.begin(), additional_dependencies.end());
4313 for (
size_t i :
der_) {
4326 auto ls_version = ls_manifest.
attribute<std::string>(
"fmi-ls:fmi-ls-version",
"");
4327 casadi_assert(ls_version.empty() || ls_version ==
"1.0",
4328 "Unsupported LS-DAE version: " + ls_version);
4331 casadi_assert(ls_manifest.
has_child(
"AlgebraicVariables"),
"Missing 'AlgebraicVariables'");
4332 for (
const XmlNode& e : ls_manifest[
"AlgebraicVariables"].children) {
4333 auto vr =
static_cast<unsigned int>(e.attribute<casadi_int>(
"valueReference"));
4338 casadi_assert(ls_manifest.
has_child(
"ModelStructure"),
"Missing 'ModelStructure'");
4339 return ls_manifest[
"ModelStructure"];
4344 uout() <<
"== Structure before importing binding equations ==" << std::endl;
4349 for (casadi_int i = 0; i < eqs.
size(); ++i) {
4351 std::string eq_name =
"beq_" +
str(i);
4361 casadi_assert(
eq[1].
size() == 0,
"Not implemented");
4364 casadi_warning(
var.
name +
" has binding equation without type specifier: " +
str(val));
4370 }
catch (std::exception& e) {
4371 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
4378 uout() <<
"== Structure before importing dynamic equations ==" << std::endl;
4389 for (casadi_int i = 0; i < eqs.
size(); ++i) {
4391 std::string eq_name =
"dyneq_" +
str(i);
4394 if (
eq.name ==
"equ:When") {
4396 const XmlNode& n_cond =
eq[
"equ:Condition"];
4397 const XmlNode& n_equ =
eq[
"equ:Equation"];
4399 casadi_assert(n_cond.
size() == 1,
"Only one condition in when equation supported");
4400 casadi_assert(n_equ.
size() == 1,
"Only one equation in when equation supported");
4402 std::string cond_name = n_cond[0][0].
attribute<std::string>(
"name");
4403 std::string when_prefix =
"$whenCondition";
4404 cond_name = cond_name.substr(when_prefix.size());
4405 casadi_int ind = std::stoi(cond_name) - 1;
4409 if (n_equ[0].
name ==
"exp:Sub") {
4414 }
else if (n_equ[0].
name ==
"exp:Reinit") {
4421 casadi_error(n_equ[0].
name +
" in when equation not supported");
4423 }
else if (
eq.name ==
"equ:Equation") {
4425 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
4428 casadi_warning(eq_name +
" is empty, ignored.");
4437 std::string when_prefix =
"$whenCondition";
4438 if (lhs.
name ==
"exp:Der") {
4442 }
else if (lhs.
size() > 0
4443 && lhs[0].
attribute<std::string>(
"name").rfind(when_prefix, 0) == 0) {
4445 std::string cond_name = lhs[0].
attribute<std::string>(
"name");
4447 uout() <<
"Reading event indicator: " << cond_name <<
" := " << beq << std::endl;
4449 cond_name = cond_name.substr(when_prefix.size());
4450 casadi_int ind = std::stoi(cond_name) - 1;
4452 casadi_assert(ind ==
when_.size(),
"Non-consequitive when conditions");
4458 if (
debug_)
uout() <<
"Reading equation: " << v.
name <<
" == " << beq << std::endl;
4462 casadi_error(
"Unknown dynamic equation type, got:" +
eq.name);
4464 }
catch (std::exception& e) {
4465 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
4472 uout() <<
"== Structure before importing initial equations ==" << std::endl;
4477 std::set<std::string> already_added;
4479 for (casadi_int i = 0; i < eqs.
size(); ++i) {
4482 std::string eq_name =
"initeq_" +
str(i);
4484 if (
eq.name ==
"equ:Equation") {
4486 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
4489 casadi_warning(eq_name +
" is empty, ignored.");
4498 && lhs[0].
attribute<std::string>(
"name").rfind(
"$whenCondition", 0) == 0) {
4503 if (lhs.
size() > 0 && lhs[0].
attribute<std::string>(
"name") ==
"$PRE") {
4504 casadi_warning(eq_name +
" defines a pre-variable, ignored");
4513 casadi_warning(eq_name +
" defines a tunable parameter, ignored")
4517 std::string eq_str =
str(v.
v) +
" == " +
str(beq);
4518 auto it = already_added.insert(eq_str);
4520 casadi_warning(eq_name +
" duplicate of previous equation " + eq_str +
", ignored")
4526 casadi_error(
"Unknown initial equation type, got:" +
eq.name);
4528 }
catch (std::exception& e) {
4529 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
4539 std::vector<MX> ret;
4540 ret.reserve(ind.size());
4541 for (
size_t i : ind) ret.push_back(
var(i));
4547 casadi_assert(it !=
varind_.end(),
"No such variable: \"" +
name +
"\".");
4553 casadi_assert(v.
is_symbolic(),
"Variable must be symbolic");
4558 "Variable \"" + v.
name() +
"\" has mismatching symbolic expression");
4564 std::vector<size_t> r(
name.size());
4565 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(
name[i]);
4570 std::vector<size_t> r(v.size());
4571 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(v[i]);
4580 std::vector<std::string> r(ind.size());
4581 for (
size_t i = 0; i < r.size(); ++i) r[i] =
name(ind[i]);
4586 casadi_assert(!
has_fun(f.
name()),
"Function '" + f.
name() +
"' already exists");
4592 const std::vector<std::string>& arg,
4593 const std::vector<std::string>& res,
const Dict& opts) {
4594 casadi_assert(!
has_fun(
name),
"Function '" +
name +
"' already exists");
4599 std::vector<MX> arg_ex, res_ex;
4600 for (
auto&& s : arg) arg_ex.push_back(
var(s));
4601 for (
auto&& s : res) {
4606 res_ex.push_back(wdef.at(v_ind));
4610 casadi_assert(v_ind <
size(
Category::W),
"Cannot find dependent '" + s +
"'");
4618 if (f.name()==
name)
return true;
4626 if (f.name()==
name)
return f;
4633 std::fill(v->value.begin(), v->value.end(),
nan);
4634 v->stringvalue = std::string();
4645 const std::vector<std::string>& name)
const {
4647 std::vector<double> r;
4650 std::vector<double> r1;
4651 for (
const auto& n :
name) {
4653 r.insert(r.end(), r1.begin(), r1.end());
4663 const std::vector<double>& val) {
4664 if (
name.size() == val.size()) {
4667 }
else if (val.size() ==
size(a,
name)) {
4669 auto val_it = val.begin();
4670 for (
size_t k = 0; k <
name.size(); ++k) {
4672 auto val_next = val_it + v.
size(a);
4677 casadi_error(
"Cannot set attribute " +
to_string(a) +
": Argument is of length " +
4678 str(val.size()) +
", expected number of elements (" +
str(
size(a,
name))
4679 +
") or number of variables (" +
str(
name.size()) +
")");
4684 const std::string& name)
const {
4691 const std::vector<std::string>& name)
const {
4693 std::vector<std::string> r;
4697 for (
const auto& n :
name) {
4705 const std::string& val) {
4710 const std::vector<std::string>& name,
const std::vector<std::string>& val) {
4711 casadi_assert(
name.size() == val.size(),
"Dimension mismatch");
4722 const std::vector<size_t>& iind)
const {
4724 std::vector<casadi_int> lookup(
n_variables(), -1);
4725 for (
size_t i = 0; i < iind.size(); ++i)
4726 lookup.at(iind[i]) = i;
4728 std::vector<casadi_int> row, col;
4730 for (casadi_int j = 0; j < oind.size(); ++j) {
4731 for (casadi_int d :
variable(oind[j]).dependencies) {
4732 casadi_int i = lookup.at(d);
4744 const std::vector<size_t>& iind)
const {
4746 std::vector<casadi_int> lookup(
n_variables(), -1);
4747 for (
size_t i = 0; i < iind.size(); ++i) lookup.at(iind[i]) = i;
4749 std::vector<bool> nonlin(iind.size(),
false);
4751 std::vector<casadi_int> nonlin_list;
4753 std::vector<casadi_int> row, col;
4755 for (casadi_int j = 0; j < oind.size(); ++j) {
4761 if (i >= 0 && !nonlin.at(i)) {
4763 nonlin_list.push_back(i);
4764 nonlin.at(i) =
true;
4769 for (casadi_int k1 : nonlin_list) {
4770 for (casadi_int k2 : nonlin_list) {
4776 if (col.size() > 2 * iind.size() * iind.size()) {
4782 for (casadi_int k : nonlin_list) nonlin[k] =
false;
4783 nonlin_list.clear();
4791 auto now = std::chrono::system_clock::now();
4792 std::time_t tt = std::chrono::system_clock::to_time_t(now);
4793 auto local_tm = *std::localtime(&tt);
4795 std::stringstream ss;
4796 ss << local_tm.tm_year + 1900 <<
'-';
4797 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mon + 1 <<
'-';
4798 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mday <<
'T';
4799 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_hour <<
':';
4800 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_min <<
':';
4801 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_sec <<
'Z';
4807 static bool initialized =
false;
4809 srand(::
time(
nullptr));
4813 const char h[] =
"0123456789abcdef";
4815 const size_t len = 32;
4817 std::vector<char> buf(len);
4818 for (
size_t i = 0; i < len; ++i)
4819 buf[i] = h[rand() % 16];
4820 return std::string(&buf.front(), len);
Helper class for C code generation.
static std::string fmu_helpers(const std::string &modelname)
FMU helper functions.
void add(const Function &f, bool with_jac_sparsity=false)
Add a function (name generated)
static void stream_open(std::ostream &f, bool cpp)
Print file header.
static void stream_close(std::ostream &f, bool cpp)
Print file header.
std::string generate(const std::string &prefix="")
Generate file(s)
void sz_work(size_t &sz_arg, size_t &sz_res, size_t &sz_iw, size_t &sz_w) const
Get number of temporary variables needed for all functions.
Sparsity jac_sparsity(const std::vector< size_t > &oind, const std::vector< size_t > &iind) const
Get Jacobian sparsity.
Function create(const std::string &fname, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out, const Dict &opts, bool sx, bool lifted_calls) const
Construct a function object.
bool enable_ls_serialization_
size_t n_variables() const
Length of variables array.
bool provides_directional_derivatives_
XmlNode generate_model_variables() const
Generate FMU ModelVariables.
void insert(std::vector< size_t > &v, size_t ind) const
Insert into list of variables, keeping it ordered.
const Function & oracle(bool sx=false, bool elim_w=false, bool lifted_calls=false) const
Get the (cached) oracle, SX or MX.
Variability variability(size_t ind) const
Get variability.
Dict compile_fmu(const Dict &files, const Dict &opts) const
Compile the sources produced by export_fmu, returning the augmented file map.
void reorder(Category cat, const std::vector< size_t > &v)
Reorder variables in a category.
std::vector< std::string > all() const
Get a list of all variables.
std::string generation_date_and_time_
Function transition(const std::string &fname, casadi_int index, bool dummy_index_input=false) const
Construct a function describing transition at a specific event.
std::vector< size_t > & indices(Category cat)
Classified variable indices (mutable)
void sanity_check() const
Check if dimensions match.
Causality causality(size_t ind) const
Get causality.
bool clear_cache_
Should the cache be cleared?
std::string instantiation_token_
std::vector< std::pair< size_t, std::vector< size_t > > > when_
void when(const MX &cond, const std::vector< std::string > &eqs, const Dict &opts)
Add when equations.
void import_model_structure(const XmlNode &n)
void tear()
Identify free variables and residual equations.
Function fun(const std::string &name) const
Get function by name.
Dict export_fmu(const Dict &opts) const
Export instance into an FMU (experimental)
std::vector< MX > init_lhs() const
Initial conditions, left-hand-side.
bool has_fun(const std::string &name) const
Does a particular function already exist?
MX read_identifier(const XmlNode &node)
Read an identifier expression.
Variable & reinit(const std::string &name, const MX &val)
Reinitialize a state inside when-equations.
void import_dynamic_equations(const XmlNode &eqs)
MX get_der(size_t ind) const
Get a derivative expression by variable index (const, never create)
Function gather_eq() const
Function corresponding to all equations.
static void sort_dependent(std::vector< MX > &v, std::vector< MX > &vdef)
void import_model_variables(const XmlNode &modvars)
Read ModelVariables.
void import_model_exchange(const XmlNode &n)
std::vector< MX > cdef() const
Definitions of dependent constants.
void set_init(const std::string &name, const MX &init_rhs)
Set a initial equation.
void update_dependencies() const
Update model variable dependencies.
~DaeBuilderInternal() override
Destructor.
void eliminate(Category cat)
Eliminate all variables of a category.
std::string generate_wrapper(const std::string &guid, const CodeGenerator &gen) const
Generate FMU wrapper file (fmi3Functions.c)
static std::string generate_guid()
void lift(bool lift_shared, bool lift_calls)
Lift problem formulation by extracting shared subexpressions.
std::string unique_name(const std::string &prefix, bool allow_no_prefix=false) const
Find a unique name, with a specific prefix.
std::string generation_tool_
void sort(Category cat)
Sort all variables of a category.
MX hess_v_v_from_calls(std::map< MXNode *, CallIO > &call_nodes, const std::vector< casadi_int > &h_offsets) const
Calculate contribution to hess_?_v_v from lifted calls.
void tearing_variables(std::vector< std::string > *res, std::vector< std::string > *iv, std::vector< std::string > *iv_on_hold) const
Identify free variables and residual equations.
std::vector< size_t > initial_unknowns_
std::vector< Function > fun_
Functions.
Function fmu_fun(const std::string &fname, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out, const Dict &opts) const
Construct function from an FMU DLL.
XmlNode generate_model_structure(bool dae=false) const
Generate FMU ModelStructure.
void add_lc(const std::string &name, const std::vector< std::string > &f_out)
Add a named linear combination of output expressions.
void import_initial_equations(const XmlNode &eqs)
void import_default_experiment(const XmlNode &n)
size_t find(const std::string &name) const
Get index of variable, given name.
bool has(const std::string &name) const
Check if a particular variable exists.
MX der(const MX &var) const
Get a derivative expression by non-differentiated expression (const, never create)
std::unordered_map< std::string, size_t > varind_
Find of variable by name.
size_t n_mem() const
Length of memory for all variables.
casadi_int orig_time_index_
void set_variability(size_t ind, Variability variability)
Set variability.
std::vector< MX > inputs(Category ind) const
std::string model_identifier_
std::vector< std::vector< size_t > > indices_
Ordered variables.
std::unordered_map< unsigned int, size_t > vrmap_
Find of variable by value reference.
Function::AuxOut lc_
Linear combinations of output expressions.
const std::string & name(size_t ind) const
Get variable name by index.
void set_attribute(Attribute a, const std::string &name, double val)
std::vector< DependenciesKind > read_dependencies_kind(const XmlNode &n, size_t ndep)
void sort_z(const std::vector< std::string > &z_order)
Sort algebraic variables.
void set_causality(size_t ind, Causality causality)
Set causality.
std::string string_attribute(Attribute a, const std::string &name) const
void remove(std::vector< size_t > &v, size_t ind) const
Remove from list of variables.
Function oracle_[2][2][2]
Function oracles (cached)
std::string generate_build_description(const std::vector< std::string > &cfiles) const
Generate buildDescription.xml.
bool has_t() const
Is there a time variable?
Variable & variable(size_t ind)
static Initial default_initial(Causality causality, Variability variability)
std::string generate_model_description(const std::string &guid) const
Generate modelDescription.xml.
std::vector< Variable * > variables_
All variables.
Variable & new_variable(const std::string &name, const std::vector< casadi_int > &dimension={1}, const MX &expr=MX())
Create a new variable.
bool can_be_instantiated_only_once_per_process_
casadi_int convert_index(casadi_int index) const
std::string name_
Name of instance.
bool provides_adjoint_derivatives_
void clear_cache() const
Problem structure has changed: Clear cache.
MX jac_vdef_v_from_calls(std::map< MXNode *, CallIO > &call_nodes, const std::vector< casadi_int > &h_offsets) const
Calculate contribution to jac_vdef_v from lifted calls.
static std::string generate(const std::vector< size_t > &v)
void set_string_attribute(Attribute a, const std::string &name, const std::string &val)
std::vector< double > start_all() const
Start values for all variables.
std::vector< casadi_int > read_dependencies(const XmlNode &n)
std::vector< size_t > der_
Variable & assign(const std::string &name, const MX &val)
Assignment inside when-equations or if-else equations.
std::string pack_fmu(const Dict &files, const Dict &opts) const
Pack files (from export_fmu / compile_fmu) into a single .fmu archive (experimental)
std::vector< std::string > source_files_
void set_category(size_t ind, Category cat)
Set category.
void eq(const MX &lhs, const MX &rhs, const Dict &opts)
Add a simple equation.
void import_binding_equations(const XmlNode &eqs)
Variable & read_variable(const XmlNode &node, Attribute *att=nullptr)
Read a variable.
double attribute(Attribute a, const std::string &name) const
DaeBuilderInternal(const std::string &name, const std::string &path, const Dict &opts)
Constructor.
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.
Category category(size_t ind) const
Get category.
void load_fmi_description(const std::string &filename)
static std::string qualified_name(const XmlNode &nn, Attribute *att=nullptr)
Get the qualified name.
std::vector< size_t > init_
size_t size(Category cat) const
Number of indices with a particular category.
const MX & var(const std::string &name) const
Get variable expression by name.
std::string variable_naming_convention_
XmlNode import_ls_dae(const std::string &lsdae)
Sparsity hess_sparsity(const std::vector< size_t > &oind, const std::vector< size_t > &iind) const
Get what is known of the Hessian sparsity.
void disp(std::ostream &stream, bool more) const override
Print description.
std::vector< MX > outputs(Category ind) const
void prune(bool prune_p, bool prune_u)
Prune unused controls.
std::vector< MX > init_rhs() const
Initial conditions, right-hand-side.
MX read_expr(const XmlNode &node)
Read an equation.
static std::string iso_8601_time()
Get current date and time in the ISO 8601 format.
static Variability default_variability(Causality causality, Type type)
Default variability attribute, per the FMI specification.
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.
void categorize(size_t ind, Category cat)
Set or change the category for a variable.
Variable & add(const std::string &name, Causality causality, Variability variability, const Dict &opts)
Add a new variable.
static std::string filename(const std::string &path)
static std::unique_ptr< std::ostream > ofstream_ptr(const std::string &path, std::ios_base::openmode mode=std::ios_base::out)
static bool exists(const std::string &path)
static void identify_io(std::vector< std::string > *scheme_in, std::vector< std::string > *scheme_out, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out)
static std::string pack_fmu(const Dict &files, const std::string &path)
static Dict compile_fmu(const std::string &name, const Dict &files, const Dict &opts)
Function forward(casadi_int nfwd) const
Get a function that calculates nfwd forward derivatives.
static Function conditional(const std::string &name, const std::vector< Function > &f, const Function &f_def, const Dict &opts=Dict())
Constuct a switch function.
const MX mx_in(casadi_int ind) const
Get symbolic primitives equivalent to the input expressions.
Function expand() const
Expand a function to SX.
const std::vector< std::string > & name_in() const
Get input scheme.
const std::string & name() const
Name of the function.
Function reverse(casadi_int nadj) const
Get a function that calculates nadj adjoint derivatives.
Function jacobian() const
Calculate all Jacobian blocks.
casadi_int index_in(const std::string &name) const
Find the index for a string describing a particular entry of an input scheme.
static Function create(FunctionInternal *node)
Create from node.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Get output dimension.
casadi_int n_out() const
Get the number of function outputs.
casadi_int n_in() const
Get the number of function inputs.
std::vector< std::string > get_free() const
Get free variables as a string.
bool has_free() const
Does the function have free variables.
static Function load(const std::string &filename)
Build function from serialization.
std::pair< casadi_int, casadi_int > size_in(casadi_int ind) const
Get input dimension.
casadi_int index_out(const std::string &name) const
Find the index for a string describing a particular entry of an output scheme.
const std::vector< Sparsity > & jac_sparsity(bool compact=false) const
Get, if necessary generate, the sparsity of all Jacobian blocks.
Function factory(const std::string &name, const std::vector< std::string > &s_in, const std::vector< std::string > &s_out, const AuxOut &aux=AuxOut(), const Dict &opts=Dict()) const
const std::vector< std::string > & name_out() const
Get output scheme.
casadi_int numel() const
Get the number of elements.
bool is_dense() const
Check if the matrix expression is dense.
bool is_column() const
Check if the matrix is a column vector (i.e. size2()==1)
bool is_empty(bool both=false) const
Check if the sparsity is empty, i.e. if one of the dimensions is zero.
std::pair< casadi_int, casadi_int > size() const
Get the shape.
casadi_int size1() const
Get the first dimension (i.e. number of rows)
static MX sym(const std::string &name, casadi_int nrow=1, casadi_int ncol=1)
Create an nrow-by-ncol symbolic primitive.
static MX zeros(casadi_int nrow=1, casadi_int ncol=1)
Create a dense matrix or a matrix with specified sparsity with all entries zero.
bool is_null() const
Is a null pointer?
A mutable, format-neutral interface to a computational-graph model.
Function create(const std::string &name, const std::vector< std::string > &name_in, const std::vector< std::string > &name_out, const Dict &opts=Dict()) const
Freeze into an evaluable Function.
bool is_valid_input() const
Check if matrix can be used to define function inputs.
static MX substitute(const MX &ex, const MX &v, const MX &vdef)
const Sparsity & sparsity() const
Get the sparsity pattern.
bool is_output() const
Check if evaluation output.
casadi_int n_out() const
Number of outputs.
casadi_int n_dep() const
Get the number of dependencies of a binary SXElem.
std::string name() const
Get the name.
static MX find(const MX &x)
bool is_constant() const
Check if constant.
MXNode * get() const
Get a const pointer to the node.
std::vector< MX > split_primitives(const MX &x) const
Split up an expression along symbolic primitives.
Function which_function() const
Get function - only valid when is_call() is true.
bool is_op(casadi_int op) const
Is it a certain operation.
std::vector< MX > primitives() const
Get primitives.
casadi_int which_output() const
Get the index of evaluation output - only valid when is_output() is true.
MX join_primitives(const std::vector< MX > &v) const
Join an expression along symbolic primitives.
MX dep(casadi_int ch=0) const
Get the nth dependency as MX.
bool is_symbolic() const
Check if symbolic.
void parse(const std::string &filename, const std::string &output_dir)
RAII class for reading from a zip file.
const std::string & path() const
Get path for a consumer.
void change_option(const std::string &option_name, const GenericType &option_value)
Change option after object creation for debugging.
static Resource create(ResourceInternal *node)
Create from node.
casadi_int size1() const
Get the number of rows.
static Sparsity diag(casadi_int nrow)
Create diagonal sparsity pattern *.
std::vector< casadi_int > get_col() const
Get the column for each non-zero entry.
const casadi_int * row() const
Get a reference to row-vector,.
casadi_int btf(std::vector< casadi_int > &rowperm, std::vector< casadi_int > &colperm, std::vector< casadi_int > &rowblock, std::vector< casadi_int > &colblock, std::vector< casadi_int > &coarse_rowblock, std::vector< casadi_int > &coarse_colblock) const
Calculate the block triangular form (BTF)
std::vector< casadi_int > get_row() const
Get the row for each non-zero entry.
const casadi_int * colind() const
Get a reference to the colindex of all column element (see class description)
static Sparsity triplet(casadi_int nrow, casadi_int ncol, const std::vector< casadi_int > &row, const std::vector< casadi_int > &col, std::vector< casadi_int > &mapping, bool invert_mapping)
Create a sparsity pattern given the nonzeros in sparse triplet form *.
bool is_triu(bool strictly=false) const
Is upper triangular?
Base class for resources that use a temporary directory.
const std::string & path() const override
Get path for a consumer.
void dump(const std::string &filename, const XmlNode &node)
XmlNode parse(const std::string &filename)
std::vector< std::string > dyn_out()
Get output scheme of a DAE function.
std::vector< std::string > event_in()
Get input scheme of an event transition function.
std::vector< std::string > dyn_in()
Get input scheme of a DAE function.
std::vector< std::string > event_out()
Get output scheme of an event transition functions.
struct VariableStruct Variable
bool is_equal(double x, double y, casadi_int depth=0)
Variability
Variability: FMI 2.0 specification, section 2.2.7 or FMI 3.0 specification, section 2....
std::string description(Category v)
Category input_category(Category cat)
bool is_input_category(Category cat)
double if_else(double x, double y, double z)
Type from_fmi2(TypeFmi2 v)
std::vector< T > read_list(const XmlNode &n)
std::vector< Category > input_categories()
bool is_output_category(Category cat)
static Resource open_resource(const std::string &path)
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
std::vector< Category > output_categories()
Initial
Initial: FMI 2.0 specification, section 2.2.7 or FMI 3.0 specification, section 2....
T dot(const std::vector< T > &a, const std::vector< T > &b)
std::string to_string(TypeFmi2 v)
const double nan
Not a number.
Category dependent_definition(Category cat)
bool is_acyclic(Category cat)
Causality
Causality: FMI 2.0 specification, section 2.2.7 or FMI 3.0 specification, section 2....
Type
Variable type (FMI 3)
std::vector< casadi_int > path(const std::vector< casadi_int > &map, casadi_int i_start)
std::string filename(const std::string &path)
TypeFmi2
Variable type (FMI 2)
Helper class, represents inputs and outputs for a function call node.
std::vector< MX > adj1_arg
const MX & hess(casadi_int iind1, casadi_int iind2) const
const MX & jac(casadi_int oind, casadi_int iind) const
std::vector< MX > jac_res
std::vector< size_t > vdef
Holds expressions and meta-data corresponding to a physical quantity evolving in time.
Category category
CasADi's classification of the variable.
bool dependency
Do other expressions depend on this variable.
void set_attribute(Attribute a, double val)
std::vector< double > value
Numerical value (also for booleans, integers, enums)
MX get_der(DaeBuilderInternal &self, bool may_allocate=true)
std::vector< Category > categories() const
casadi_int size(Attribute a) const
Total number of elements for a particular attribute.
void get_attribute(Attribute a, double *val) const
std::vector< double > start
casadi_int index
Location in variable vector.
std::string stringvalue
String value (if string-valued)
casadi_int numel
Number of elements - product of all dimensions.
std::string name
Name of the variable.
unsigned int value_reference
MX v
Variable expression (always a vector)
XmlNode export_xml(const DaeBuilderInternal &self) const
std::vector< casadi_int > dependencies
Dependencies.
bool permitted(Category cat) const
std::vector< DependenciesKind > dependenciesKind
Dependencies.
std::vector< casadi_int > dimension
Dimensions.
MX ieq
Initial equation (to be removed and moved to a separate dependent variable)
void set_attribute(const std::string &att_name, const std::string &att)
Add an attribute.
std::vector< XmlNode > children
T attribute(const std::string &att_name) const
Get an attribute by its name.
bool has_child(const std::string &childname) const
Check if a child is present.
void get(T *val) const
Get value of text field.
bool has_attribute(const std::string &att_name) const
Check if an attribute is present.
std::map< std::string, std::string > attributes
size_t size() const
Get the number of children.
Helper class: Specify number of entries in an enum.