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'");
775 if (fmi_desc.
has_child(
"ModelStructure")) {
787 +
"/extra/org.casadi.fmi-ls-serialization/oracle.casadi");
790 auto oracle_out =
oracle(oracle_in);
792 std::vector<MX> v, vdef;
793 for (
auto& arg : oracle_in) {
795 for (
auto& vp : arg.primitives()) {
797 size_t ind =
find(vp.name());
800 vdef.push_back(
var(ind));
804 oracle_in = substitute(oracle_in, v, vdef);
805 oracle_out = substitute(oracle_out, v, vdef);
811 for (
size_t i = 0; i < w.size(); ++i) {
818 assign_w_i.
v = wdef[i];
831 MX alg_all = vertcat(alg);
833 auto alg_it = alg.begin();
844 }
catch (std::exception& e) {
852 +
"/extra/org.lacemodelica.ls-onnx-serialization/model.onnx";
860 auto oracle_out =
oracle(oracle_in);
863 std::vector<std::string> input_var_names;
864 for (casadi_int i = 0; i <
oracle.
n_in(); ++i) {
869 std::vector<MX> v, vdef;
870 for (
auto& arg : oracle_in) {
872 for (
auto& vp : arg.primitives()) {
874 size_t ind =
find(vp.name());
877 vdef.push_back(
var(ind));
882 oracle_out = substitute(oracle_out, v, vdef);
891 for (
size_t i = 0; i < oracle_out.size(); ++i) {
893 MX expr = oracle_out[i];
896 bool is_init_eq = out_name.substr(0, 8) ==
"init_eq[";
897 bool is_dyn_eq = out_name.substr(0, 3) ==
"eq[" && !is_init_eq;
899 if (is_dyn_eq || is_init_eq) {
902 if (expr.
n_dep() == 2) {
903 MX lhs = expr.
dep(0);
904 MX rhs = expr.
dep(1);
909 std::string var_name = lhs.
name();
916 std::string var_name = lhs.
name();
917 size_t var_ind =
find(var_name);
927 }
else if (out_name.substr(0, 6) ==
"start[") {
929 size_t bracket_pos = out_name.find(
'[');
930 size_t close_pos = out_name.find(
']');
931 if (bracket_pos != std::string::npos && close_pos != std::string::npos) {
932 casadi_int idx = std::stoi(out_name.substr(bracket_pos + 1, close_pos - bracket_pos - 1));
933 if (idx >= 0 && idx <
static_cast<casadi_int
>(input_var_names.size())) {
934 std::string var_name = input_var_names[idx];
938 DM dm_val =
static_cast<DM>(expr);
939 var_ref.
start = std::vector<double>(dm_val->begin(), dm_val->end());
944 }
else if (out_name.substr(0, 4) ==
"min[") {
946 size_t bracket_pos = out_name.find(
'[');
947 size_t close_pos = out_name.find(
']');
948 if (bracket_pos != std::string::npos && close_pos != std::string::npos) {
949 casadi_int idx = std::stoi(out_name.substr(bracket_pos + 1, close_pos - bracket_pos - 1));
950 if (idx >= 0 && idx <
static_cast<casadi_int
>(input_var_names.size())) {
951 std::string var_name = input_var_names[idx];
955 DM dm_val =
static_cast<DM>(expr);
956 var_ref.
min =
static_cast<double>(dm_val);
961 }
else if (out_name.substr(0, 4) ==
"max[") {
963 size_t bracket_pos = out_name.find(
'[');
964 size_t close_pos = out_name.find(
']');
965 if (bracket_pos != std::string::npos && close_pos != std::string::npos) {
966 casadi_int idx = std::stoi(out_name.substr(bracket_pos + 1, close_pos - bracket_pos - 1));
967 if (idx >= 0 && idx <
static_cast<casadi_int
>(input_var_names.size())) {
968 std::string var_name = input_var_names[idx];
972 DM dm_val =
static_cast<DM>(expr);
973 var_ref.
max =
static_cast<double>(dm_val);
985 if (fmi_desc.
has_child(
"equ:BindingEquations")) {
991 if (fmi_desc.
has_child(
"equ:InitialEquations")) {
997 if (fmi_desc.
has_child(
"equ:DynamicEquations")) {
1003 casadi_assert(
symbolic_ || has_model_exchange,
1004 "FMU must be of ModelExchange type or be symbolic (FMUX)");
1008 const std::vector<std::string>& cfiles)
const {
1012 std::string model_name =
name_;
1016 r.
name =
"fmiBuildDescription";
1017 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
1020 source_file_set.
name =
"SourceFileSet";
1021 for (
auto&& f : cfiles) {
1023 source_file.
name =
"SourceFile";
1025 source_file_set.
children.push_back(source_file);
1029 bc.
name =
"BuildConfiguration";
1031 bc.
children.push_back(source_file_set);
1034 std::string xml_filename =
"buildDescription.xml";
1037 build_description.
children.push_back(r);
1040 xml_file.
dump(xml_filename, build_description);
1041 return xml_filename;
1048 std::string model_name =
name_;
1051 std::string version;
1052 std::string copyright;
1053 std::string license;
1057 r.
name =
"fmiModelDescription";
1058 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
1060 r.
set_attribute(fmi_major >= 3 ?
"instantiationToken" :
"guid", guid);
1064 if (!copyright.empty()) r.
set_attribute(
"copyright", copyright);
1069 if (fmi_major < 3) r.
set_attribute(
"numberOfEventIndicators",
"0");
1073 me.
name =
"ModelExchange";
1081 def_exp.
name =
"DefaultExperiment";
1093 std::string xml_filename =
"modelDescription.xml";
1096 model_description.
children.push_back(r);
1099 xml_file.
dump(xml_filename, model_description);
1100 return xml_filename;
1106 r.
name =
"ModelVariables";
1108 r.
children.push_back(v->export_xml(*
this));
1115 r.
name =
"ModelStructure";
1129 c.
name =
"ContinuousStateDerivative";
1137 f.
name =
"Formulation";
1142 c.
name =
"Residual";
1151 c.
name =
"InitialUnknown";
1160 c.
name =
"InitialUnknown";
1169 c.
name =
"EventIndicator";
1191 for (casadi_int k = dode_dxT.
colind(i); k < dode_dxT.
colind(i + 1); ++k) {
1192 casadi_int j = dode_dxT.
row(k);
1196 for (casadi_int k = dode_dzT.
colind(i); k < dode_dzT.
colind(i + 1); ++k) {
1197 casadi_int j = dode_dzT.
row(k);
1201 for (casadi_int k = dode_duT.
colind(i); k < dode_duT.
colind(i + 1); ++k) {
1202 casadi_int j = dode_duT.
row(k);
1209 const std::vector<size_t>& oind =
indices(cat);
1213 for (casadi_int i = 0; i < oind.size(); ++i) {
1219 for (casadi_int k = dy_dxT.
colind(i); k < dy_dxT.
colind(i + 1); ++k) {
1220 casadi_int j = dy_dxT.
row(k);
1224 for (casadi_int k = dy_dzT.
colind(i); k < dy_dzT.
colind(i + 1); ++k) {
1225 casadi_int j = dy_dzT.
row(k);
1229 for (casadi_int k = dy_duT.
colind(i); k < dy_duT.
colind(i + 1); ++k) {
1230 casadi_int j = dy_duT.
row(k);
1239 bool no_warning =
false;
1240 bool with_serialization =
true;
1241 for (
auto&& op : opts) {
1242 if (op.first ==
"no_warning") {
1243 no_warning = op.second;
1244 }
else if (op.first ==
"with_serialization") {
1245 with_serialization = op.second;
1247 casadi_error(
"No such option: " + op.first);
1251 if (!no_warning) casadi_warning(
"FMU generation is experimental and incomplete")
1255 std::string dae_filename =
name_;
1257 Function dae = shared_from_this<DaeBuilder>().
create(dae_filename,
1258 {
"t",
"x",
"z",
"p",
"u"}, {
"ode",
"alg",
"y",
"zero"});
1264 codegen_opts[
"with_header"] =
true;
1271 std::vector<std::string> sources;
1273 sources.push_back(dae_filename +
".h");
1282 for (
const std::string& s : sources) ret[s] =
"sources/" + s;
1287 if (with_serialization) {
1289 std::string serialization_ls =
"org.casadi.fmi-ls-serialization";
1291 std::string oracle_filename =
"oracle.casadi";
1292 shared_from_this<DaeBuilder>().oracle().save(oracle_filename);
1293 ret[oracle_filename] =
"extra/" + serialization_ls +
"/" + oracle_filename;
1296 r.
name =
"fmiLayeredStandardManifest";
1300 "Layered standard for serialized CasADi expressions in FMU");
1305 std::string manifest_filename = serialization_ls +
".fmi-ls-manifest.xml";
1306 xml_file.
dump(manifest_filename, manifest);
1307 ret[manifest_filename] =
"extra/" + serialization_ls +
"/fmi-ls-manifest.xml";
1312 std::string dae_ls =
"org.fmi-standard.fmi-ls-dae";
1315 r.
name =
"fmiLayeredStandardManifest";
1319 "Layered standard for DAE support in FMU");
1322 a.
name =
"AlgebraicVariables";
1325 v.
name =
"AlgebraicVariable";
1327 static_cast<casadi_int
>(
variable(i).value_reference));
1338 std::string manifest_filename = dae_ls +
".fmi-ls-manifest.xml";
1339 xml_file.
dump(manifest_filename, manifest);
1340 ret[manifest_filename] =
"extra/" + dae_ls +
"/fmi-ls-manifest.xml";
1352 for (
auto&& op : opts) {
1353 if (op.first ==
"path") {
1354 path = op.second.to_string();
1356 casadi_error(
"No such option: " + op.first);
1363 std::stringstream ss;
1366 for (
double e : v) {
1368 if (!first) ss <<
", ";
1378 std::stringstream ss;
1381 for (
double e : v) {
1383 if (!first) ss <<
", ";
1386 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << e;
1393 std::vector<double> r;
1395 for (
double s : v->start) r.push_back(s);
1403 std::string wrapper_filename =
name_ +
"_wrap.c";
1406 std::ostream& f = *f_ptr;
1410 f <<
"#include <fmi3Functions.h>\n"
1411 <<
"#include \"" <<
name_ <<
".h\"\n"
1418 f <<
"#define SZ_MEM " <<
n_mem() <<
"\n";
1421 size_t sz_arg, sz_res, sz_iw, sz_w;
1422 gen.
sz_work(sz_arg, sz_res, sz_iw, sz_w);
1423 f <<
"#define SZ_ARG " << sz_arg <<
"\n"
1424 <<
"#define SZ_RES " << sz_res <<
"\n"
1425 <<
"#define SZ_IW " << sz_iw <<
"\n"
1426 <<
"#define SZ_W " << sz_w <<
"\n";
1429 f <<
"const size_t var_offset[N_VAR + 1] = {0";
1432 mem_ind += v->numel;
1433 f <<
", " << mem_ind;
1461 std::vector<size_t> xdot;
1463 f <<
"fmi3ValueReference xdot_vr[N_X] = " <<
generate(xdot) <<
";\n"
1485 return wrapper_filename;
1494 }
catch (std::exception& e) {
1495 THROW_ERROR_NODE(
"read_variable", node, e.what());
1508 casadi_error(
"Cannot read attribute " +
to_string(att));
1515 const std::string& fullname = node.
name;
1517 if (fullname ==
"fun:If") {
1519 const XmlNode& cond = node[
"fun:Condition"];
1520 const XmlNode& then_stmt = node[
"fun:Statements"];
1521 const XmlNode& else_stmt = node[
"fun:Else"];
1523 casadi_assert(cond.
size() == 1,
"Only one condition in if expression supported");
1524 casadi_assert(then_stmt.
size() == 1,
"Only one then statement in if expression supported");
1525 casadi_assert(else_stmt.
size() == 1,
"Only one else statement in if expression supported");
1529 if (fullname.find(
"exp:")== std::string::npos) {
1530 casadi_error(
"DaeBuilderInternal::read_expr: unknown - expression is supposed to "
1531 "start with 'exp:' , got " + fullname);
1535 std::string
name = fullname.substr(4);
1542 }
else if (
name==
"Acos") {
1544 }
else if (
name==
"Asin") {
1546 }
else if (
name==
"Atan") {
1548 }
else if (
name==
"Cos") {
1550 }
else if (
name==
"Der") {
1552 }
else if (
name==
"Div") {
1554 }
else if (
name==
"Exp") {
1556 }
else if (
name==
"Identifier") {
1558 }
else if (
name==
"IntegerLiteral" ||
name==
"BooleanLiteral") {
1562 }
else if (
name==
"Instant") {
1566 }
else if (
name==
"Log") {
1568 }
else if (
name==
"Not") {
1570 }
else if (
name==
"LogLeq") {
1572 }
else if (
name==
"LogGeq") {
1574 }
else if (
name==
"LogLt") {
1576 }
else if (
name==
"LogGt") {
1578 }
else if (
name==
"Max") {
1580 }
else if (
name==
"Min") {
1582 }
else if (
name==
"Mul") {
1584 }
else if (
name==
"Neg") {
1586 }
else if (
name==
"NoEvent") {
1589 casadi_int n = node.
size();
1595 for (casadi_int i=n-3; i>=0; i -= 2) {
1600 }
else if (
name==
"Pow") {
1602 }
else if (
name==
"Pre") {
1603 casadi_warning(
"Ignoring pre attribute");
1605 }
else if (
name==
"RealLiteral") {
1609 }
else if (
name==
"Sin") {
1611 }
else if (
name==
"Sqrt") {
1613 }
else if (
name==
"StringLiteral") {
1614 casadi_error(node.
text);
1615 }
else if (
name==
"Sub") {
1617 }
else if (
name==
"Tan") {
1619 }
else if (
name==
"Time") {
1621 }
else if (
name==
"TimedVariable") {
1623 }
else if (
name==
"FunctionCall") {
1626 casadi_warning(
"Function call to '" + fname +
"' incomplete");
1628 const XmlNode& args = node[
"exp:Arguments"];
1629 std::vector<MX> farg(args.
size());
1630 for (casadi_int i = 0; i < args.
size(); ++i) {
1647 }
else if (
name==
"Array") {
1649 std::vector<MX> v(node.
size());
1650 for (casadi_int i = 0; i < v.size(); ++i) v[i] =
read_expr(node[i]);
1655 casadi_error(
"Unknown node: " +
name);
1656 }
catch (std::exception& e) {
1657 THROW_ERROR_NODE(
"read_expr", node, e.what());
1680 stream << std::endl;
1683 if (!
fun_.empty()) {
1684 stream <<
"Functions:" << std::endl;
1686 stream <<
" " << f << std::endl;
1691 stream <<
"Model variables:" << std::endl;
1694 if (
size(cat) > 0) {
1701 if (
size(cat) > 0) {
1703 for (
size_t c :
indices(cat)) {
1705 stream <<
" " << v.
name;
1707 stream << std::endl;
1714 if (
size(cat) > 0) {
1718 for (
size_t k :
indices(cat)) {
1720 stream <<
" " << v.
name <<
": " <<
der(v.
v) << std::endl;
1727 stream <<
"Outputs (y):" << std::endl;
1730 stream <<
" " << v.
name <<
": " << v.
v << std::endl;
1735 stream <<
"Algebraic equations:" << std::endl;
1737 stream <<
" 0 == " <<
variable(k).
v << std::endl;
1741 if (!
init_.empty()) {
1742 stream <<
"Initial equations:" << std::endl;
1743 for (
size_t k :
init_) {
1745 stream <<
" " << v.
name;
1747 stream << std::endl;
1751 if (!
when_.empty()) {
1752 stream <<
"When equations:" << std::endl;
1753 for (
auto weq :
when_) {
1754 stream <<
" when " <<
variable(weq.first).
v <<
" < 0 : " << std::endl;
1755 for (
size_t eq : weq.second) {
1769 std::vector<size_t> new_order;
1770 for (
const MX& e : v) new_order.push_back(
find(e.name()));
1771 std::copy(new_order.begin(), new_order.end(),
indices(cat).begin());
1776 casadi_assert(z_order.size() ==
size(
Category::Z),
"Dimension mismatch");
1781 std::vector<size_t> new_z;
1782 new_z.reserve(z_order.size());
1783 for (
const std::string& s : z_order) {
1785 casadi_assert(old_z.at(i),
"Variable \"" + s +
"\" is not an algebraic variable.");
1793 return indices_.at(
static_cast<size_t>(cat));
1805 const std::vector<size_t>& v)
const {
1807 casadi_assert(ind.size() == v.size(),
"Cannot reorder " + n +
": "
1808 +
str(v.size()) +
" elements provided for " +
str(ind.size()) +
" components.");
1811 for (
size_t i : v) set.at(i) =
true;
1813 for (
size_t i : ind) casadi_assert(set.at(i),
"Cannot reorder " + n +
": "
1816 std::copy(v.begin(), v.end(), ind.begin());
1821 std::vector<MX> f_in, f_out, v;
1822 std::vector<std::string> f_in_name, f_out_name;
1829 f_in.push_back(vertcat(v));
1837 f_out.push_back(vertcat(v));
1842 Function f(
"prune_fcn", f_in, f_out, f_in_name, f_out_name);
1844 std::vector<bool> free_variables(
n_variables(),
false);
1845 for (
const std::string& s : f.
get_free()) {
1847 casadi_assert(it !=
varind_.end(),
"No such variable: \"" + s +
"\".");
1848 free_variables.at(it->second) =
true;
1864 for (
size_t i = 0; i < u.size(); ++i) {
1865 if (!free_variables.at(u.at(i))) u.at(nu++) = u.at(i);
1873 std::vector<std::string> res, iv, iv_on_hold;
1876 std::set<std::string> iv_set;
1877 for (
auto& e : iv) iv_set.insert(e);
1878 for (
auto& e : iv_on_hold) iv_set.insert(e);
1905 std::vector<std::string>* iv, std::vector<std::string>* iv_on_hold)
const {
1907 if (res) res->clear();
1908 if (iv) iv->clear();
1909 if (iv_on_hold) iv_on_hold->clear();
1911 const std::string res_prefix =
"res__";
1913 std::vector<MX> r_hold, iv_hold;
1915 bool any_hold =
false;
1919 if (v->name.rfind(res_prefix, 0) == 0) {
1921 std::string iv_name, res_hold_name, iv_hold_name;
1924 size_t pos = res_prefix.size();
1926 size_t end = v->name.find(
"__", pos);
1927 if (end == std::string::npos) end = v->name.size();
1929 iv_name = v->name.substr(pos, end - pos);
1931 casadi_assert(
has(iv_name),
"No such variable: " + iv_name);
1933 if (end != v->name.size()) {
1936 end = v->name.find(
"__", pos);
1937 if (end == std::string::npos) end = v->name.size();
1938 res_hold_name = v->name.substr(pos, end - pos);
1940 casadi_assert(
has(res_hold_name),
"No such variable: " + res_hold_name);
1942 if (end != v->name.size()) {
1943 iv_hold_name = v->name.substr(end + 2);
1944 casadi_assert(
has(iv_hold_name),
"No such variable: " + iv_hold_name);
1947 }
catch (std::exception& e) {
1949 casadi_warning(
"Cannot process residual variable: " + v->name +
":" +
1950 std::string(e.what()));
1954 if (res_hold_name.empty()) {
1955 r_hold.push_back(
false);
1958 r_hold.push_back(
variable(res_hold_name).v);
1959 casadi_assert(r_hold.back().is_scalar(),
"Non-scalar hold variable for " + res_hold_name);
1961 if (res) res->push_back(v->name);
1963 if (iv_hold_name.empty()) {
1964 iv_hold.push_back(
false);
1967 iv_hold.push_back(
variable(iv_hold_name).v);
1968 casadi_assert(iv_hold.back().is_scalar(),
"Non-scalar hold variable for " + iv_hold_name);
1970 if (iv) iv->push_back(iv_name);
1977 casadi_error(
"not implemented");
1980 Function startfun_p = attribute_fun(
"startfun_p", {}, {
"start_p"});
1982 casadi_error(
"startfun has free variables: " +
str(startfun_p.
get_free()));
1984 DM p0 = startfun_p(std::vector<DM>{}).at(0);
1987 {vertcat(r_hold), vertcat(iv_hold)}, {
"p"}, {
"r_hold",
"iv_hold"});
1988 if (holdfun.has_free()) {
1989 casadi_error(
"holdfun has free variables: " +
str(holdfun.get_free()));
1992 std::vector<DM> hold0 = holdfun(std::vector<DM>{p0});
1993 std::vector<double> r_hold0 = hold0.at(0).nonzeros();
1994 std::vector<double> iv_hold0 = hold0.at(1).nonzeros();
1995 casadi_assert_dev(r_hold0.size() == res->size());
1996 casadi_assert_dev(iv_hold0.size() == iv->size());
2000 for (
size_t k = 0; k < res->size(); ++k) {
2001 if (!
static_cast<bool>(r_hold0.at(k))) {
2002 res->at(sz++) = res->at(k);
2009 for (
size_t k = 0; k < iv->size(); ++k) {
2010 if (!
static_cast<bool>(iv_hold0.at(k))) {
2011 if (iv) iv->at(sz++) = iv->at(k);
2013 if (iv_on_hold) iv_on_hold->push_back(iv->at(k));
2016 if (iv) iv->resize(sz);
2018 }
catch (std::exception& e) {
2020 casadi_warning(
"Failed to evaluate hold variables: " + std::string(e.what()));
2030 std::vector<std::string> r;
2047 const std::vector<casadi_int>& dimension,
const MX& expr) {
2049 casadi_assert(!
name.empty(),
"Name is empty string");
2051 casadi_assert(!
has(
name),
"Variable \"" +
name +
"\" already exists.");
2066 casadi_assert(
size(
Category::T) == 1,
"At most one time variable allowed");
2073 std::stringstream qn;
2074 bool first_part =
true;
2078 for (casadi_int i=0; i<nn.
size(); ++i) {
2080 std::string np = nn[i].
attribute<std::string>(
"name");
2083 if (np ==
"$START") {
2087 casadi_error(
"Ignoring attribute " + np);
2090 }
else if (np ==
"$PRE") {
2091 casadi_warning(
"$PRE attribute has not been implemented, ignoring");
2096 if (!first_part) qn <<
".";
2100 if (nn[i].
size()>0) {
2102 nn[i][
"exp:ArraySubscripts"][
"exp:IndexExpression"][
"exp:IntegerLiteral"].
get(&ind);
2103 qn <<
"[" << ind <<
"]";
2124 casadi_assert(
var.
is_column(),
"Input expression must be a vector");
2131 for (
MX& s : var_split) s =
der(s, may_allocate);
2136 std::vector<MX> dep = symvar(
var);
2138 std::vector<MX> dep_der;
2139 for (
size_t ind :
find(dep)) dep_der.push_back(
get_der(ind, may_allocate));
2142 std::vector<std::vector<MX>> r = {dep_der};
2143 r = forward(std::vector<MX>{
var}, dep, r);
2144 casadi_assert_dev(r.size() == 1);
2145 return vertcat(r.at(0));
2149 bool allow_no_prefix)
const {
2151 if (allow_no_prefix && !
has(prefix))
return prefix;
2154 while (
has(prefix +
str(i))) i++;
2156 return prefix +
str(i);
2167 casadi_assert(
is_acyclic(cat),
"Elimination not supported for category " +
to_string(cat));
2170 if (
size(cat) == 0)
return;
2178 if (!v->v.is_constant()) ex.push_back(v->v);
2181 std::vector<size_t> ind =
indices(cat);
2182 std::vector<MX> v =
var(ind);
2184 substitute_inplace(v, vdef, ex);
2186 auto it = ex.begin();
2188 if (!v->v.is_constant()) v->v = *it++;
2191 casadi_assert_dev(it == ex.end());
2193 for (
size_t k : ind) {
2207 std::vector<MX> new_w, new_wdef;
2208 Dict opts{{
"lift_shared", lift_shared}, {
"lift_calls", lift_calls},
2209 {
"prefix",
"w_"}, {
"suffix",
""}, {
"offset",
static_cast<casadi_int
>(
size(
Category::W))}};
2210 extract(ex, new_w, new_wdef, opts);
2212 for (
size_t i = 0; i < new_w.size(); ++i) {
2220 auto it = ex.begin();
2225 casadi_assert_dev(it == ex.end());
2236 casadi_error(
"No input category for " +
to_string(cat));
2242 to_string(ind) +
" is not an input category");
2248 std::vector<MX> ret(ind.size());
2249 for (casadi_int i=0; i<ind.size(); ++i) {
2250 ret[i] = vertcat(
inputs(ind[i]));
2268 std::vector<MX> ret;
2269 ret.reserve(
size(cat));
2275 for (
size_t v :
indices(cat)) {
2285 casadi_error(
"Missing derivative for " +
str(x.
name));
2300 std::vector<MX> ret(ind.size());
2301 for (casadi_int i=0; i<ind.size(); ++i) {
2302 ret[i] = vertcat(
outputs(ind[i]));
2312 casadi_assert(!
name.empty(),
"DaeBuilderInternal::add_lc: \"name\" is empty");
2313 for (std::string::const_iterator i=
name.begin(); i!=
name.end(); ++i) {
2314 casadi_assert(isalnum(*i),
2315 "DaeBuilderInternal::add_lc: \"name\" must be alphanumeric");
2319 casadi_assert(!f_out.empty(),
"DaeBuilderInternal::add_lc: Linear combination is empty");
2321 for (casadi_int i=0; i < f_out.size(); ++i) {
2322 auto oind =
static_cast<size_t>(to_enum<Category>(f_out[i]));
2323 casadi_assert(!in_use[oind],
"DaeBuilderInternal::add_lc: Duplicate expression " + f_out[i]);
2324 in_use[oind] =
true;
2327 std::vector<std::string>& ret1 =
lc_[
name];
2328 if (!ret1.empty()) casadi_warning(
"DaeBuilderInternal::add_lc: Overwriting " <<
name);
2333 const std::vector<std::string>& s_in,
2334 const std::vector<std::string>& s_out,
const Dict& opts,
bool sx,
bool lifted_calls)
const {
2336 bool with_underscore =
false;
2337 for (
const auto *s_io : {&s_in, &s_out}) {
2338 for (
const std::string& s : *s_io) {
2339 with_underscore = with_underscore || std::count(s.begin(), s.end(),
'_');
2345 casadi_assert(!lifted_calls,
"Lifting requires a symbolic representation");
2347 casadi_assert(!sx,
"SX expansion requires a symbolic representation");
2349 return fmu_fun(fname, s_in, s_out, opts);
2352 if (with_underscore) {
2353 std::vector<std::string> s_in_mod(s_in), s_out_mod(s_out);
2354 for (
auto *s_io : {&s_in_mod, &s_out_mod}) {
2355 for (std::string& s : *s_io) std::replace(s.begin(), s.end(),
'_',
':');
2358 return create(fname, s_in_mod, s_out_mod, opts, sx, lifted_calls);
2361 bool elim_w =
false;
2365 for (
const std::string& s : s_in) {
2376 casadi_assert(!elim_w,
"Lifted calls cannot be used if dependent variables are eliminated");
2378 lifted_calls =
false;
2380 if (vdef_comp.is_output()) {
2382 lifted_calls =
true;
2388 std::string fname_nocalls = lifted_calls ? fname +
"_nocalls" : fname;
2391 if (!lifted_calls)
return ret;
2393 std::vector<MX> ret_in = ret.
mx_in();
2394 std::vector<MX> ret_out = ret(ret_in);
2398 std::vector<MX> v_in, lam_vdef_in;
2399 for (
size_t i = 0; i < s_in.size(); ++i) {
2401 v_in = vertsplit(ret_in[i], h_offsets);
2402 }
else if (ret.
name_in(i) ==
"lam_wdef") {
2403 lam_vdef_in = vertsplit(ret_in[i], h_offsets);
2407 std::map<MXNode*, size_t> v_map;
2414 std::map<MXNode*, CallIO> call_nodes;
2415 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2417 const MX& vdefref = wdef.at(vdefind);
2421 MX c = vdefref.
dep(0);
2423 auto call_it = call_nodes.
find(c.
get());
2425 if (call_it == call_nodes.end()) {
2431 cio.
v.resize(c.
n_dep(), -1);
2432 cio.
arg.resize(cio.
v.size());
2433 for (casadi_int i = 0; i < cio.
v.size(); ++i) {
2435 cio.
arg.at(i) = c.
dep(i);
2437 size_t v_ind = v_map.at(c.
dep(i).
get());
2438 cio.
v.at(i) = v_ind;
2439 cio.
arg.at(i) = v_in.at(v_ind);
2444 cio.
res.resize(cio.
vdef.size());
2448 call_it = call_nodes.insert(std::make_pair(c.
get(), cio)).first;
2453 call_it->second.vdef.at(oind) = vdefind;
2454 call_it->second.res.at(oind) = v_in.at(vdefind);
2456 if (!lam_vdef_in.empty()) call_it->second.adj1_arg.at(oind) = lam_vdef_in.at(vdefind);
2460 for (
size_t i = 0; i < ret_out.size(); ++i) {
2461 if (ret.
name_out(i) ==
"jac_wdef_w") {
2467 for (
auto&& e :
lc_) {
2469 bool has_vdef =
false;
2470 for (
const std::string& r : e.second) {
2477 if (!has_vdef)
continue;
2479 for (
size_t i = 0; i < ret_out.size(); ++i) {
2480 if (ret.
name_out(i) ==
"hess_" + e.first +
"_w_w") {
2485 ret_out.at(i) += extra_hess_v_v;
2495 const std::vector<casadi_int>& h_offsets)
const {
2497 for (
auto call_it = call_nodes.begin(); call_it != call_nodes.end(); ++call_it) {
2498 call_it->second.calc_jac();
2501 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2503 std::vector<MX> vblocks, hblocks;
2505 std::map<size_t, MX> jac_brow;
2509 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2511 const MX& vdefref = wdef.at(vdefind);
2513 voffset_begin = voffset_end;
2514 voffset_end += vdefref.
numel();
2520 MX c = vdefref.
dep(0);
2522 auto call_it = call_nodes.
find(c.
get());
2523 casadi_assert_dev(call_it != call_nodes.end());
2526 for (casadi_int iind = 0; iind < call_it->second.arg.size(); ++iind) {
2527 size_t vind = call_it->second.v.at(iind);
2528 if (vind !=
size_t(-1)) {
2529 jac_brow[vind] = call_it->second.jac(oind, iind);
2533 if (voffset_last != voffset_begin) {
2534 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2538 casadi_int hoffset = 0;
2539 for (
auto e : jac_brow) {
2541 if (hoffset < h_offsets.at(e.first))
2542 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.at(e.first) - hoffset));
2544 hblocks.push_back(e.second);
2546 hoffset = h_offsets.at(e.first + 1);
2549 if (hoffset < h_offsets.back())
2550 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.back() - hoffset));
2552 vblocks.push_back(horzcat(hblocks));
2554 voffset_last = voffset_end;
2558 if (voffset_last != voffset_end) {
2559 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2562 return vertcat(vblocks);
2566 const std::vector<casadi_int>& h_offsets)
const {
2568 for (
auto&& call_ref : call_nodes) call_ref.second.calc_hess();
2570 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2572 std::vector<MX> vblocks, hblocks;
2574 std::map<size_t, MX> hess_brow;
2580 voffset_begin = voffset_end;
2581 voffset_end += vref.
numel();
2584 for (
auto&& call_ref : call_nodes) {
2586 for (
size_t iind1 = 0; iind1 < call_ref.second.v.size(); ++iind1) {
2587 if (call_ref.second.v.at(iind1) == vind1) {
2589 for (
size_t iind2 = 0; iind2 < call_ref.second.v.size(); ++iind2) {
2591 size_t vind2 = call_ref.second.v[iind2];
2592 if (vind2 ==
size_t(-1))
continue;
2594 MX H_contr = call_ref.second.hess(iind1, iind2);
2596 auto it = hess_brow.
find(vind2);
2597 if (it != hess_brow.end()) {
2598 it->second += H_contr;
2600 hess_brow[vind2] = H_contr;
2609 if (hess_brow.empty())
continue;
2611 if (voffset_last != voffset_begin) {
2612 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2616 casadi_int hoffset = 0;
2617 for (
auto e : hess_brow) {
2619 if (hoffset < h_offsets.at(e.first))
2620 hblocks.push_back(
MX(vref.
numel(), h_offsets.at(e.first) - hoffset));
2622 hblocks.push_back(e.second);
2624 hoffset = h_offsets.at(e.first + 1);
2627 if (hoffset < h_offsets.back())
2628 hblocks.push_back(
MX(vref.
numel(), h_offsets.back() - hoffset));
2630 vblocks.push_back(horzcat(hblocks));
2632 voffset_last = voffset_end;
2635 if (voffset_last != voffset_end) {
2636 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2639 return vertcat(vblocks);
2643 for (
bool sx : {
false,
true}) {
2644 for (
bool elim_w : {
false,
true}) {
2645 for (
bool lifted_calls : {
false,
true}) {
2655 casadi_assert(
symbolic_,
"DaeBuilder oracle only available if symbolic representation");
2660 if (
oracle_[
false][elim_w][lifted_calls].is_null()) {
2662 std::vector<MX> f_in, f_out, v;
2663 std::vector<std::string> f_in_name, f_out_name;
2665 casadi_int wdef_ind = -1;
2667 casadi_assert(!(elim_w && lifted_calls),
"Incompatible options");
2669 bool subst_v =
false;
2671 bool subst_c =
false;
2676 if (!v.empty()) subst_v =
true;
2678 if (!v.empty()) subst_c =
true;
2681 f_in.push_back(
MX(0, 1));
2683 f_in.push_back(vertcat(v));
2694 f_out.push_back(
MX(0, 1));
2697 f_out.push_back(vertcat(v));
2706 }
else if (lifted_calls && wdef_ind >= 0) {
2710 for (
MX& wdefref : wdef) {
2711 if (wdefref.is_output()) wdefref =
MX::zeros(wdefref.sparsity());
2714 f_out.at(wdef_ind) = vertcat(wdef);
2720 std::vector<casadi::MX>
cdef;
2721 for (
size_t i = 0; i < c.size(); ++i) {
2725 f_out = substitute(f_out, c,
cdef);
2729 oracle_[
false][elim_w][lifted_calls]
2730 =
Function(
"mx_oracle", f_in, f_out, f_in_name, f_out_name);
2733 if (!sx)
return oracle_[
false][elim_w][lifted_calls];
2743 for (casadi_int i = 0; i < this->
f.
n_in(); ++i) {
2744 casadi_assert(this->
f.
size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2746 for (casadi_int i = 0; i < this->
f.
n_out(); ++i) {
2747 casadi_assert(this->
f.
size_out(i) == this->res.at(i).size(),
"Call output not provided");
2754 std::vector<MX> call_in = this->
arg;
2755 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2762 for (casadi_int i = 0; i < this->f.n_in(); ++i) {
2763 casadi_assert(this->f.size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2765 casadi_assert(this->adj1_arg.size() == this->res.size(),
"Input 'lam_vdef' not provided");
2766 for (casadi_int i = 0; i < this->f.n_out(); ++i) {
2767 casadi_assert(this->f.size_out(i) == this->res.at(i).size(),
"Call output not provided");
2768 casadi_assert(this->adj1_arg.at(i).size() == this->res.at(i).size(),
2769 "Call adjoint seed not provided");
2772 if (!this->jac_res.empty())
2773 casadi_warning(
"Jacobian blocks currently not reused for gradient calculation");
2776 this->adj1_f = this->f.reverse(1);
2779 std::vector<MX> call_in = this->arg;
2780 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2781 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2783 this->adj1_res = this->adj1_f(call_in);
2788 if (this->adj1_f.is_null()) calc_grad();
2791 this->H = this->adj1_f.jacobian();
2794 std::vector<MX> call_in = this->arg;
2795 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2796 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2797 call_in.insert(call_in.end(), this->adj1_res.begin(), this->adj1_res.end());
2799 this->hess_res = this->H(call_in);
2804 casadi_int ind = iind + oind * this->arg.
size();
2806 return this->jac_res.at(ind);
2811 casadi_int ind = iind1 + iind1 * this->adj1_arg.
size();
2813 return this->hess_res.at(ind);
2818 Function vfcn(
"vfcn", {vertcat(v)}, {vertcat(vdef)}, {
"v"}, {
"vdef"},
2819 Dict{{
"allow_free",
true}});
2821 bool any_vector_valued =
false;
2822 for (
const MX& v_i : v) {
2823 casadi_assert(!v_i.is_empty(),
"Cannot have zero-dimension dependent variables");
2824 if (!v_i.is_scalar()) {
2825 any_vector_valued =
true;
2830 if (any_vector_valued) {
2832 std::vector<MX> vfcn_in(v), vfcn_arg(v);
2833 for (
size_t i = 0; i < v.size(); ++i) {
2834 if (!v.at(i).is_scalar()) {
2835 vfcn_in.at(i) =
MX::sym(v.at(i).name());
2836 vfcn_arg.at(i) = repmat(vfcn_in.at(i), v.at(i).size1());
2840 std::vector<MX> vfcn_out = vfcn(vertcat(vfcn_arg));
2841 vfcn_out = vertsplit(vfcn_out.at(0), offset(v));
2843 for (
size_t i = 0; i < v.size(); ++i) {
2844 if (!v.at(i).is_scalar()) {
2845 vfcn_out.at(i) =
dot(vfcn_out.at(i), vfcn_out.at(i));
2849 vfcn =
Function(vfcn.name(), {vertcat(vfcn_in)}, {vertcat(vfcn_out)},
2850 vfcn.name_in(), vfcn.name_out(), {{
"allow_free", true}});
2853 Sparsity Jv = vfcn.jac_sparsity(0, 0);
2859 std::vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
2860 (void)Jv.
btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
2862 std::vector<MX> tmp(v.size());
2863 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = v.at(colperm.at(k));
2864 std::copy(tmp.begin(), tmp.end(), v.begin());
2866 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = vdef.at(rowperm.at(k));
2867 std::copy(tmp.begin(), tmp.end(), vdef.begin());
2871 const std::vector<std::string>& s_in,
2872 const std::vector<std::string>& s_out)
const {
2874 bool calc_d =
false, calc_w =
false;
2876 std::vector<Category> v_out;
2877 v_out.reserve(v_out.size());
2878 for (
const std::string& s : s_out) {
2885 casadi_error(
"Can only calculate d and/or w");
2890 casadi_assert(calc_d || calc_w,
"Nothing to calculate");
2892 std::vector<Category> v_in;
2893 v_in.reserve(v_in.size());
2894 for (
const std::string& s : s_in) {
2896 if (calc_d && e ==
Category::D) casadi_error(
"'d' cannot be both input and output");
2897 if (calc_w && e ==
Category::W) casadi_error(
"'w' cannot be both input and output");
2901 std::vector<MX> f_in;
2902 f_in.reserve(s_in.size());
2905 std::vector<MX> f_out;
2906 f_out.reserve(s_out.size());
2909 std::vector<MX> dw, dwdef;
2912 dw.insert(dw.end(), d.begin(), d.end());
2914 dwdef.insert(dwdef.end(), ddef.begin(), ddef.end());
2918 dw.insert(dw.end(), w.begin(), w.end());
2920 dwdef.insert(dwdef.end(), wdef.begin(), wdef.end());
2923 substitute_inplace(dw, dwdef, f_out);
2925 return Function(fname, f_in, f_out, s_in, s_out);
2929 bool dummy_index_input)
const {
2932 casadi_assert(index >= 0 && index <
when_.size(),
"Illegal event index");
2947 std::vector<MX> when_lhs, when_rhs;
2948 for (
size_t eq :
when_.at(index).second) {
2955 std::vector<MX> ret_out = {ret_in[
DYN_X], ret_in[
DYN_Z]};
2967 if (dummy_index_input) {
2969 ret_in.insert(ret_in.begin(),
MX());
2985 std::vector<Function> f_all;
2986 for (casadi_int i = 0; i <
when_.size(); ++i) {
3000 const std::vector<std::string>& name_in,
3001 const std::vector<std::string>& name_out,
3002 const Dict& opts)
const {
3004 Dict::const_iterator it;
3006 std::vector<std::string> scheme_in;
3007 bool has_in =
false;
3008 it = opts.find(
"scheme_in");
3009 if (it != opts.end()) {
3011 scheme_in = it->second;
3012 }
catch (std::exception& e) {
3013 casadi_error(std::string(
"Cannot read 'scheme_in': ") + e.what());
3019 std::vector<std::string> scheme_out;
3020 bool has_out =
false;
3021 it = opts.find(
"scheme_out");
3022 if (it != opts.end()) {
3024 scheme_out = it->second;
3026 }
catch (std::exception& e) {
3027 casadi_error(std::string(
"Cannot read 'scheme_out': ") + e.what());
3031 if (!has_in || !has_out) {
3033 has_out ?
nullptr : &scheme_out, name_in, name_out);
3036 std::map<std::string, std::vector<size_t>> scheme;
3037 it = opts.find(
"scheme");
3038 if (it != opts.end()) {
3041 Dict scheme_dict = it->second;
3043 for (
auto&& e : scheme_dict) {
3044 std::vector<std::string> v = e.second;
3045 scheme[e.first] =
find(v);
3047 }
catch (std::exception& e) {
3048 casadi_error(std::string(
"Cannot read 'scheme': ") + e.what());
3052 for (
auto&& s :
dyn_in()) scheme[s] = std::vector<size_t>();
3053 for (
auto&& s :
dyn_out()) scheme[s] = std::vector<size_t>();
3061 for (
size_t& i : scheme[
"ode"]) i =
variable(i).
der;
3063 for (
size_t& i : scheme[
"quad"]) i =
variable(i).
der;
3068 std::vector<std::string> aux;
3069 it = opts.find(
"aux");
3070 if (it != opts.end()) {
3073 }
catch (std::exception& e) {
3074 casadi_error(std::string(
"Cannot read 'aux': ") + e.what());
3079 scheme_in, scheme_out, scheme, aux);
3087 std::vector<MX> f_out;
3089 std::vector<std::string> f_out_name;
3092 std::vector<MX> v =
outputs(cat);
3094 f_out.push_back(vertcat(v));
3099 return Function(
"all_eq", {}, f_out, {}, f_out_name, {{
"allow_free",
true}});
3103 casadi_assert(
has_t(),
"No explicit time variable");
3135 std::vector<MX> ret;
3142 std::vector<MX> ret;
3143 ret.reserve(
init_.size());
3144 for (
size_t ind :
init_) {
3151 std::vector<MX> ret;
3152 ret.reserve(
init_.size());
3153 for (
size_t ind :
init_) {
3223 std::string
description, type, initial, unit, display_unit;
3224 std::vector<casadi_int> dimension = {1};
3226 std::vector<double> start;
3228 for (
auto&& op : opts) {
3229 if (op.first==
"dimension") {
3230 dimension = op.second.to_int_vector();
3231 }
else if (op.first==
"description") {
3233 }
else if (op.first==
"unit") {
3234 unit = op.second.to_string();
3235 }
else if (op.first==
"display_unit") {
3236 display_unit = op.second.to_string();
3237 }
else if (op.first==
"min") {
3238 min = op.second.to_double();
3239 }
else if (op.first==
"max") {
3240 max = op.second.to_double();
3241 }
else if (op.first==
"nominal") {
3242 nominal = op.second.to_double();
3243 }
else if (op.first==
"start") {
3245 start.resize(1, op.second.to_double());
3247 start = op.second.to_double_vector();
3249 }
else if (op.first==
"type") {
3250 type = op.second.to_string();
3251 }
else if (op.first==
"initial") {
3252 initial = op.second.to_string();
3254 casadi_error(
"No such option: " + op.first);
3266 casadi_assert(
orig_time_index_ == -1,
"Only one independent variable is permitted");
3288 if (!type.empty()) v.
type = to_enum<Type>(type);
3291 if (!start.empty()) {
3293 if (start.size() != v.
numel) {
3294 casadi_assert(start.size() == 1,
"'start' must be scalar or match the number of elements");
3295 start.resize(v.
numel, start.back());
3299 if (!initial.empty()) {
3300 v.
initial = to_enum<Initial>(initial);
3304 if (!unit.empty()) v.
unit = unit;
3305 if (!display_unit.empty()) v.
display_unit = display_unit;
3322 casadi_error(
"'parameter' causality requires 'fixed' or 'tunable' variability");
3327 "'calculatedParameter' causality requires 'fixed' or 'tunable' variability");
3334 "'input' causality requires 'continuous' or 'discrete' variability");
3349 casadi_error(
"'output' causality requires 'constant', 'continuous' or "
3350 "'discrete' variability");
3368 casadi_error(
"'output' causality requires 'constant', 'fixed', 'tunable', 'discrete' or "
3369 "'continuous' variability");
3375 "Independent variable must be continuous");
3392 if (opts.find(
"type") != opts.end()) {
3393 type = to_enum<Type>(opts.at(
"type").to_string());
3424 size_t loc = v.size();
3425 for (
size_t i = 0; i < v.size(); ++i) {
3431 v.insert(v.begin() + loc, ind);
3435 for (
auto it = v.begin(); it != v.end(); ++it) {
3441 casadi_error(
"Variable not found");
3462 casadi_error(
"Cannot change causality of " + v.
name +
" which is of category '"
3493 casadi_error(
"The variability of " + v.
name +
", which is of category 'u', can only be "
3494 "changed to 'fixed' (for no category) or 'tunable' (for category 'p')");
3508 casadi_error(
"The variability of " + v.
name +
", which is of category 'p', can only be "
3509 "changed to 'continuous' (for category 'u') or 'fixed' (for no category)");
3523 casadi_error(
"The variability of " + v.
name +
", which is of type 'c', can only be "
3524 "changed to 'continuous' (for category 'u') or 'tunable' (for category 'p')");
3528 casadi_error(
"Cannot change variability of " + v.
name +
", which is of category '"
3607 casadi_error(
"Cannot change category of " + v.
name +
" from '"
3613 for (
auto&& op : opts) {
3614 casadi_error(
"No such option: " + op.first);
3617 casadi_assert(lhs.
is_column(),
"Left-hand-side must be a column vector");
3618 casadi_assert(rhs.
is_column(),
"Right-hand-side must be a column vector");
3621 eq(densify(lhs), rhs, opts);
3625 eq(lhs, densify(rhs), opts);
3632 eq(repmat(lhs, rhs.
size1()), rhs, opts);
3634 }
else if (lhs.
size1() > 1 && rhs.
size1() == 1) {
3635 eq(lhs, repmat(rhs, lhs.
size1()), opts);
3638 casadi_error(
"Mismatched dimensions: " +
str(lhs.
size1()) +
" vs " +
str(rhs.
size1()));
3642 std::vector<size_t> rhs_vars =
find(symvar(rhs));
3646 for (
size_t rhs : rhs_vars) {
3652 casadi_assert(x.
der == v.
index,
"Cannot handle right-hand-side variable: " + v.
name);
3656 {{
"dimension", {x.dimension}}});
3658 eq(x.get_der(*
this), der_x.v,
Dict());
3662 if (lhs.is_valid_input()) {
3664 if (lhs.is_symbolic()) {
3670 eq(
MX::zeros(lhs.sparsity()), lhs - rhs, opts);
3674 Variable& beq = assign(v.
name, rhs);
3682 casadi_assert(x.der == v.
index,
"Cannot handle left-hand-side: " +
str(lhs));
3691 Variable& def_x = add(unique_name(
"def_" + x.name,
true),
3693 {{
"dimension", {x.dimension}}});
3695 def_x.bind = x.bind;
3702 x.v - def_x.v, {{
"dimension", x.dimension}});
3706 casadi_error(
"Unexpected category for " + x.name +
": " +
to_string(x.category));
3712 casadi_error(
"Cannot handle left-hand-side: " +
str(lhs) +
" of category '"
3717 auto lhs_split = lhs.primitives();
3718 std::vector<MX> rhs_split = lhs.split_primitives(rhs);
3720 for (
size_t k = 0; k < lhs_split.size(); ++k) {
3721 eq(lhs_split.at(k), rhs_split.at(k), opts);
3728 lhs - rhs, {{
"dimension", std::vector<casadi_int>{lhs.size1()}}});
3733 for (
size_t rhs : rhs_vars) {
3745 for (
auto&& op : opts) {
3746 casadi_error(
"No such option: " + op.first);
3751 zero = cond.
dep(0) - cond.
dep(1);
3753 casadi_error(
"Only strict inequality in zero-crossing conditions permitted, got: "
3756 casadi_error(
"Cannot parse zero-crossing condition: " +
str(cond));
3764 std::vector<MX> all_lhs, all_rhs;
3765 std::vector<size_t> all_eqs;
3766 for (
auto&&
eq : eqs) {
3770 all_rhs.push_back(ee.
v);
3771 all_eqs.push_back(ee.
index);
3773 when_.push_back(std::make_pair(e.
index, all_eqs));
3778 std::string assign_name =
unique_name(
"__assign__" +
name +
"__",
true);
3808 if (old_loc ==
init_.end()) casadi_error(
"Corrupted list of initial equations");
3809 init_.erase(old_loc);
3817 casadi_error(
"Initial equation for " +
name +
" has already been set");
3824 template<
typename T>
3827 size_t sz = n.
size();
3831 for (
size_t i = 0; i < sz; ++i) {
3832 r.push_back(
T(n[i]));
3847 fmi_major_ >= 3 ?
"providesDirectionalDerivatives" :
"providesDirectionalDerivative",
false);
3849 = n.
attribute<
bool>(
"providesAdjointDerivatives",
false);
3852 n.
attribute<
bool>(
"canBeInstantiatedOnlyOncePerProcess",
false);
3855 for (
const XmlNode& sf : n[
"SourceFiles"].children) {
3863 std::vector<std::pair<std::string, std::string>> fmi1_der;
3866 for (casadi_int i = 0; i < modvars.
size(); ++i) {
3868 const XmlNode& vnode = modvars[i];
3875 std::string variable_category = vnode[
"VariableCategory"].
text;
3876 if (variable_category ==
"derivative") {
3878 std::string x_name = vnode[
"QualifiedName"][0].
attribute<std::string>(
"name");
3879 fmi1_der.push_back(std::make_pair(x_name,
name));
3884 if (
fmi_major_ == 1 &&
name.rfind(
"$whenCondition", 0) == 0)
continue;
3891 bool replaces_time = existing !=
varind_.end() && existing->second == 0
3893 && vnode.
attribute<std::string>(
"causality",
"") ==
"independent";
3895 if (existing !=
varind_.end() && !replaces_time) {
3896 casadi_warning(
"Duplicate variable '" +
name +
"' ignored");
3901 std::vector<casadi_int> dimension;
3906 casadi_int derivative = -1;
3909 type = to_enum<Type>(vnode.
name);
3911 for (casadi_int i = 0; i < vnode.
size(); ++i) {
3913 if (c.
name ==
"Dimension") {
3916 casadi_assert(has_start ^ has_vr,
"Inconsistent attributes");
3917 casadi_assert(!has_vr,
"Structural parameter dimensions not implemented");
3918 auto dim = c.
attribute<casadi_int>(
"start");
3919 dimension.push_back(dim);
3920 }
else if (c.
name ==
"Alias") {
3922 }
else if (c.
name ==
"Annotations") {
3925 casadi_error(
"Cannot handle: " + c.
name);
3933 opts[
"unit"] = vnode.
attribute<std::string>(
"unit",
"");
3934 opts[
"display_unit"] = vnode.
attribute<std::string>(
"displayUnit",
"");
3937 opts[
"nominal"] = vnode.
attribute<
double>(
"nominal", 1.);
3938 opts[
"start"] = vnode.
attribute<std::vector<double>>(
"start", std::vector<double>{0.});
3939 derivative = vnode.
attribute<casadi_int>(
"derivative", -1);
3960 const XmlNode& props = vnode[
"Real"];
3961 opts[
"unit"] = props.
attribute<std::string>(
"unit",
"");
3962 opts[
"display_unit"] = props.
attribute<std::string>(
"displayUnit",
"");
3965 opts[
"nominal"] = props.
attribute<
double>(
"nominal", 1.);
3966 opts[
"start"] = props.
attribute<
double>(
"start", 0.);
3967 derivative = props.
attribute<casadi_int>(
"derivative", -1);
3968 }
else if (vnode.
has_child(
"Integer")) {
3970 const XmlNode& props = vnode[
"Integer"];
3973 }
else if (vnode.
has_child(
"Boolean")) {
3977 }
else if (vnode.
has_child(
"Enumeration")) {
3980 casadi_warning(
"Unknown type for " +
name);
3985 if (dimension.empty()) dimension.push_back(1);
3991 std::string causality_str = vnode.
attribute<std::string>(
"causality",
"local");
3992 if (
fmi_major_ == 1 && causality_str ==
"internal") causality_str =
"local";
3996 std::string variability_str = vnode.
attribute<std::string>(
"variability",
3998 if (
fmi_major_ == 1 && variability_str ==
"parameter") variability_str =
"fixed";
4003 std::string initial_str = vnode.
attribute<std::string>(
"initial",
"");
4004 if (!initial_str.empty()) {
4008 "initial = '" + initial_str +
"' is not allowed per the FMI specification.");
4009 initial = to_enum<Initial>(initial_str);
4024 opts[
"dimension"] = dimension;
4039 var.der_of = derivative;
4044 var.value_reference =
static_cast<unsigned int>(vnode.
attribute<casadi_int>(
"valueReference"));
4067 for (
auto& p : fmi1_der) {
4081 "Default 'dependencies' not implemented");
4083 std::vector<casadi_int> r = n.
attribute<std::vector<casadi_int>>(
"dependencies", {});
4085 for (casadi_int& e : r) {
4088 e =
vrmap_.at(
static_cast<unsigned int>(e));
4099 const XmlNode& n,
size_t ndep) {
4106 auto dk_str = n.
attribute<std::vector<std::string>>(
"dependenciesKind");
4108 casadi_assert(dk_str.size() == ndep,
"Mismatching 'dependenciesKind'");
4110 std::vector<DependenciesKind> r(ndep);
4111 for (
size_t i = 0; i < ndep; ++i) {
4112 r[i] = to_enum<DependenciesKind>(dk_str[i]);
4134 bool has_lsdae =
false;
4135 std::string lsdae =
resource_.
path() +
"/extra/org.fmi-standard.fmi-ls-dae/fmi-ls-manifest.xml";
4142 for (casadi_int i = 0; i < n.
size(); ++i) {
4144 if (e.
name !=
"ContinuousStateDerivative" && e.
name !=
"Output") {
4150 }
catch (
const std::exception& e) {
4151 casadi_warning(
"Failed to load LS-DAE manifest: " + std::string(e.what()));
4156 const XmlNode& ms = has_lsdae ? lsdae_ms : n;
4157 for (casadi_int i = 0; i < ms.
size(); ++i) {
4161 if (e.
name ==
"Output") {
4172 }
else if (e.
name ==
"ContinuousStateDerivative") {
4178 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
4189 }
else if (e.
name ==
"ClockedState") {
4191 casadi_message(
"ClockedState not implemented, ignoring");
4192 }
else if (e.
name ==
"InitialUnknown") {
4197 }
else if (e.
name ==
"EventIndicator") {
4201 }
else if (e.
name ==
"Residual") {
4204 for (casadi_int form = 0; form < e.
size(); ++form) {
4206 auto form_index = f.
attribute<
size_t>(
"index");
4207 if (form_index == 1) {
4209 casadi_assert(!found,
"Duplicate index-1 formulations");
4213 f.
attribute<
size_t>(
"valueReference")));
4221 casadi_assert(found,
"Missing index-1 formulation");
4224 casadi_error(
"Unknown ModelStructure element: " + e.
name);
4226 }
catch (
const std::exception& ex) {
4227 casadi_error(
"Error processing ModelStructure element: " + e.
name +
": " + ex.what());
4233 for (
const auto& e : n[
"Derivatives"].children) {
4239 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
4249 std::vector<casadi_int> default_dependencies;
4250 default_dependencies.insert(default_dependencies.begin(),
4252 default_dependencies.insert(default_dependencies.begin(),
4254 default_dependencies.insert(default_dependencies.begin(),
4256 std::sort(default_dependencies.begin(), default_dependencies.end());
4265 std::vector<casadi_int> additional_dependencies;
4266 additional_dependencies.insert(additional_dependencies.begin(),
4268 std::vector<DependenciesKind> additional_dependencies_kind(
size(
Category::P),
4274 for (
const auto& e : n[
"Derivatives"].children) {
4275 casadi_int index =
convert_index(e.attribute<casadi_int>(
"index", 0));
4281 if (e.has_attribute(
"dependencies")) {
4289 additional_dependencies.begin(), additional_dependencies.end());
4291 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
4300 for (
const auto& e : n[
"Outputs"].children) {
4307 if (e.has_attribute(
"dependencies")) {
4315 additional_dependencies.begin(), additional_dependencies.end());
4317 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
4326 default_dependencies.clear();
4327 default_dependencies.insert(default_dependencies.begin(),
4330 if (v->initial ==
Initial::EXACT) default_dependencies.push_back(v->index);
4332 default_dependencies.insert(default_dependencies.begin(),
4334 std::sort(default_dependencies.begin(), default_dependencies.end());
4338 for (
const auto& e : n[
"InitialUnknowns"].children) {
4342 std::vector<casadi_int> dependencies;
4344 if (e.has_attribute(
"dependencies")) {
4347 dependencies = default_dependencies;
4350 dependencies.insert(dependencies.end(),
4351 additional_dependencies.begin(), additional_dependencies.end());
4361 for (
size_t i :
der_) {
4374 auto ls_version = ls_manifest.
attribute<std::string>(
"fmi-ls:fmi-ls-version",
"");
4375 casadi_assert(ls_version.empty() || ls_version ==
"1.0",
4376 "Unsupported LS-DAE version: " + ls_version);
4379 casadi_assert(ls_manifest.
has_child(
"AlgebraicVariables"),
"Missing 'AlgebraicVariables'");
4380 for (
const XmlNode& e : ls_manifest[
"AlgebraicVariables"].children) {
4381 auto vr =
static_cast<unsigned int>(e.attribute<casadi_int>(
"valueReference"));
4386 casadi_assert(ls_manifest.
has_child(
"ModelStructure"),
"Missing 'ModelStructure'");
4387 return ls_manifest[
"ModelStructure"];
4392 uout() <<
"== Structure before importing binding equations ==" << std::endl;
4397 for (casadi_int i = 0; i < eqs.
size(); ++i) {
4399 std::string eq_name =
"beq_" +
str(i);
4409 casadi_assert(
eq[1].
size() == 0,
"Not implemented");
4412 casadi_warning(
var.
name +
" has binding equation without type specifier: " +
str(val));
4418 }
catch (std::exception& e) {
4419 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
4426 uout() <<
"== Structure before importing dynamic equations ==" << std::endl;
4437 for (casadi_int i = 0; i < eqs.
size(); ++i) {
4439 std::string eq_name =
"dyneq_" +
str(i);
4442 if (
eq.name ==
"equ:When") {
4444 const XmlNode& n_cond =
eq[
"equ:Condition"];
4445 const XmlNode& n_equ =
eq[
"equ:Equation"];
4447 casadi_assert(n_cond.
size() == 1,
"Only one condition in when equation supported");
4448 casadi_assert(n_equ.
size() == 1,
"Only one equation in when equation supported");
4450 std::string cond_name = n_cond[0][0].
attribute<std::string>(
"name");
4451 std::string when_prefix =
"$whenCondition";
4452 cond_name = cond_name.substr(when_prefix.size());
4453 casadi_int ind = std::stoi(cond_name) - 1;
4457 if (n_equ[0].
name ==
"exp:Sub") {
4462 }
else if (n_equ[0].
name ==
"exp:Reinit") {
4469 casadi_error(n_equ[0].
name +
" in when equation not supported");
4471 }
else if (
eq.name ==
"equ:Equation") {
4473 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
4476 casadi_warning(eq_name +
" is empty, ignored.");
4485 std::string when_prefix =
"$whenCondition";
4486 if (lhs.
name ==
"exp:Der") {
4490 }
else if (lhs.
size() > 0
4491 && lhs[0].
attribute<std::string>(
"name").rfind(when_prefix, 0) == 0) {
4493 std::string cond_name = lhs[0].
attribute<std::string>(
"name");
4495 uout() <<
"Reading event indicator: " << cond_name <<
" := " << beq << std::endl;
4497 cond_name = cond_name.substr(when_prefix.size());
4498 casadi_int ind = std::stoi(cond_name) - 1;
4500 casadi_assert(ind ==
when_.size(),
"Non-consequitive when conditions");
4506 if (
debug_)
uout() <<
"Reading equation: " << v.
name <<
" == " << beq << std::endl;
4510 casadi_error(
"Unknown dynamic equation type, got:" +
eq.name);
4512 }
catch (std::exception& e) {
4513 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
4520 uout() <<
"== Structure before importing initial equations ==" << std::endl;
4525 std::set<std::string> already_added;
4527 for (casadi_int i = 0; i < eqs.
size(); ++i) {
4530 std::string eq_name =
"initeq_" +
str(i);
4532 if (
eq.name ==
"equ:Equation") {
4534 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
4537 casadi_warning(eq_name +
" is empty, ignored.");
4546 && lhs[0].
attribute<std::string>(
"name").rfind(
"$whenCondition", 0) == 0) {
4551 if (lhs.
size() > 0 && lhs[0].
attribute<std::string>(
"name") ==
"$PRE") {
4552 casadi_warning(eq_name +
" defines a pre-variable, ignored");
4561 casadi_warning(eq_name +
" defines a tunable parameter, ignored")
4565 std::string eq_str =
str(v.
v) +
" == " +
str(beq);
4566 auto it = already_added.insert(eq_str);
4568 casadi_warning(eq_name +
" duplicate of previous equation " + eq_str +
", ignored")
4574 casadi_error(
"Unknown initial equation type, got:" +
eq.name);
4576 }
catch (std::exception& e) {
4577 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
4587 std::vector<MX> ret;
4588 ret.reserve(ind.size());
4589 for (
size_t i : ind) ret.push_back(
var(i));
4595 casadi_assert(it !=
varind_.end(),
"No such variable: \"" +
name +
"\".");
4601 casadi_assert(v.
is_symbolic(),
"Variable must be symbolic");
4606 "Variable \"" + v.
name() +
"\" has mismatching symbolic expression");
4612 std::vector<size_t> r(
name.size());
4613 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(
name[i]);
4618 std::vector<size_t> r(v.size());
4619 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(v[i]);
4628 std::vector<std::string> r(ind.size());
4629 for (
size_t i = 0; i < r.size(); ++i) r[i] =
name(ind[i]);
4634 casadi_assert(!
has_fun(f.
name()),
"Function '" + f.
name() +
"' already exists");
4640 const std::vector<std::string>& arg,
4641 const std::vector<std::string>& res,
const Dict& opts) {
4642 casadi_assert(!
has_fun(
name),
"Function '" +
name +
"' already exists");
4647 std::vector<MX> arg_ex, res_ex;
4648 for (
auto&& s : arg) arg_ex.push_back(
var(s));
4649 for (
auto&& s : res) {
4654 res_ex.push_back(wdef.at(v_ind));
4658 casadi_assert(v_ind <
size(
Category::W),
"Cannot find dependent '" + s +
"'");
4666 if (f.name()==
name)
return true;
4674 if (f.name()==
name)
return f;
4681 std::fill(v->value.begin(), v->value.end(),
nan);
4682 v->stringvalue = std::string();
4693 const std::vector<std::string>& name)
const {
4695 std::vector<double> r;
4698 std::vector<double> r1;
4699 for (
const auto& n :
name) {
4701 r.insert(r.end(), r1.begin(), r1.end());
4711 const std::vector<double>& val) {
4712 if (
name.size() == val.size()) {
4715 }
else if (val.size() ==
size(a,
name)) {
4717 auto val_it = val.begin();
4718 for (
size_t k = 0; k <
name.size(); ++k) {
4720 auto val_next = val_it + v.
size(a);
4725 casadi_error(
"Cannot set attribute " +
to_string(a) +
": Argument is of length " +
4726 str(val.size()) +
", expected number of elements (" +
str(
size(a,
name))
4727 +
") or number of variables (" +
str(
name.size()) +
")");
4732 const std::string& name)
const {
4739 const std::vector<std::string>& name)
const {
4741 std::vector<std::string> r;
4745 for (
const auto& n :
name) {
4753 const std::string& val) {
4758 const std::vector<std::string>& name,
const std::vector<std::string>& val) {
4759 casadi_assert(
name.size() == val.size(),
"Dimension mismatch");
4770 const std::vector<size_t>& iind)
const {
4772 std::vector<casadi_int> lookup(
n_variables(), -1);
4773 for (
size_t i = 0; i < iind.size(); ++i)
4774 lookup.at(iind[i]) = i;
4776 std::vector<casadi_int> row, col;
4778 for (casadi_int j = 0; j < oind.size(); ++j) {
4779 for (casadi_int d :
variable(oind[j]).dependencies) {
4780 casadi_int i = lookup.at(d);
4792 const std::vector<size_t>& iind)
const {
4794 std::vector<casadi_int> lookup(
n_variables(), -1);
4795 for (
size_t i = 0; i < iind.size(); ++i) lookup.at(iind[i]) = i;
4797 std::vector<bool> nonlin(iind.size(),
false);
4799 std::vector<casadi_int> nonlin_list;
4801 std::vector<casadi_int> row, col;
4803 for (casadi_int j = 0; j < oind.size(); ++j) {
4809 if (i >= 0 && !nonlin.at(i)) {
4811 nonlin_list.push_back(i);
4812 nonlin.at(i) =
true;
4817 for (casadi_int k1 : nonlin_list) {
4818 for (casadi_int k2 : nonlin_list) {
4824 if (col.size() > 2 * iind.size() * iind.size()) {
4830 for (casadi_int k : nonlin_list) nonlin[k] =
false;
4831 nonlin_list.clear();
4839 auto now = std::chrono::system_clock::now();
4840 std::time_t tt = std::chrono::system_clock::to_time_t(now);
4841 auto local_tm = *std::localtime(&tt);
4843 std::stringstream ss;
4844 ss << local_tm.tm_year + 1900 <<
'-';
4845 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mon + 1 <<
'-';
4846 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mday <<
'T';
4847 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_hour <<
':';
4848 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_min <<
':';
4849 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_sec <<
'Z';
4855 static bool initialized =
false;
4857 srand(::
time(
nullptr));
4861 const char h[] =
"0123456789abcdef";
4863 const size_t len = 32;
4865 std::vector<char> buf(len);
4866 for (
size_t i = 0; i < len; ++i)
4867 buf[i] = h[rand() % 16];
4868 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 computing nfwd forward directional derivatives.
static Function conditional(const std::string &name, const std::vector< Function > &f, const Function &f_def, const Dict &opts=Dict())
Create a function that selects one of several functions by an index input.
const MX mx_in(casadi_int ind) const
Create fresh symbols with the names and sparsity patterns of the inputs.
Function expand() const
Convert an MXFunction into an equivalent SXFunction.
const std::vector< std::string > & name_in() const
Get the names of all inputs, in order.
const std::string & name() const
Get the name given at construction ("null" for a null object)
Function reverse(casadi_int nadj) const
Get a function computing nadj reverse (adjoint) directional derivatives.
Function jacobian() const
Get a function computing all Jacobian blocks at once.
casadi_int index_in(const std::string &name) const
Get the index of the input with a given name.
static Function create(FunctionInternal *node)
Create from node.
std::pair< casadi_int, casadi_int > size_out(casadi_int ind) const
Get the shape of an output: rows, columns or both.
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 the names of the free variables; empty when there are none.
bool has_free() const
Check whether the outputs contain symbols that are not inputs.
static Function load(const std::string &filename)
Read a function from a file written by save.
std::pair< casadi_int, casadi_int > size_in(casadi_int ind) const
Get the shape of an input: rows, columns or both.
casadi_int index_out(const std::string &name) const
Get the index of the output with a given name; unknown names raise an error.
const std::vector< Sparsity > & jac_sparsity(bool compact=false) const
Get the sparsity patterns 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
Build a function computing derivatives by naming inputs and outputs.
const std::vector< std::string > & name_out() const
Get the names of all outputs, in order.
casadi_int numel() const
Get the number of elements, size1()*size2()
bool is_dense() const
Check if the matrix is dense, i.e. nnz() equals numel()
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 matrix is empty, i.e. if one of the dimensions is zero.
std::pair< casadi_int, casadi_int > size() const
Get the shape as a pair (number of rows, number of columns)
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.
bool is_valid_input() const
Check if the expression can be used as a Function input.
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 the node selects one output of a multiple-output node.
casadi_int n_out() const
Number of outputs of this node.
casadi_int n_dep() const
Get the number of dependencies (child nodes) of this node.
std::string name() const
Get the name of a symbolic primitive.
static MX find(const MX &x)
bool is_constant() const
Check if the node is a constant.
MXNode * get() const
Get a const pointer to the node.
std::vector< MX > split_primitives(const MX &x) const
Split a value along the symbolic primitives of this expression.
Function which_function() const
Get the Function of a call node.
bool is_op(casadi_int op) const
Check if the node is a certain operation.
std::vector< MX > primitives() const
Get the symbolic primitives of a valid Function input.
casadi_int which_output() const
Get the output index of an OutputNode.
MX join_primitives(const std::vector< MX > &v) const
Join values along the symbolic primitives of this expression.
MX dep(casadi_int ch=0) const
Get the ch-th dependency (child node) of this node.
bool is_symbolic() const
Check if the node is a symbolic primitive (created by MX.sym)
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
Number of rows.
static Sparsity diag(casadi_int nrow)
Create a diagonal sparsity pattern.
std::vector< casadi_int > get_col() const
Column index of every nonzero, in nonzero (column-major) order.
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
Block triangular form (BTF) through the Dulmage-Mendelsohn decomposition.
std::vector< casadi_int > get_row() const
Row index of every nonzero, in nonzero (column-major) order.
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 from the (row, col) index of every nonzero.
bool is_triu(bool strictly=false) const
Check whether all nonzeros are on or above the diagonal (row <= col)
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 the output scheme of a DAE function.
std::vector< std::string > event_in()
Get the input scheme of an event transition function.
std::vector< std::string > dyn_in()
Get the input scheme of a DAE function.
std::vector< std::string > event_out()
Get the output scheme of an event transition function.
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.