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"
46 #define THROW_ERROR_NODE(FNAME, NODE, WHAT) \
47 throw CasadiException("Error in DaeBuilderInternal::" FNAME " for '" + this->name_ \
48 + "', node '" + NODE.name + "' (line " + str(NODE.line) + ") at " \
49 + CASADI_WHERE + ":\n" + std::string(WHAT));
52 #define THROW_ERROR(FNAME, WHAT) \
53 throw CasadiException("Error in DaeBuilderInternal::" FNAME " for '" + this->name_ \
55 + CASADI_WHERE + ":\n" + std::string(WHAT));
88 casadi_error(
to_string(v) +
" cannot be converted to FMI 2");
241 casadi_error(
"Cannot handle: " +
to_string(cat));
265 casadi_error(
"No dependent definition category for: " +
to_string(cat));
269 std::vector<Category> ret;
271 auto cat =
static_cast<Category>(i);
278 std::vector<OutputCategory> ret;
299 casadi_assert(
numel == 1,
"Variable " +
name +
" is not scalar");
312 if (val) *val =
start.front();
315 if (val) *val =
value.front();
320 casadi_error(
"Cannot handle: " +
to_string(a));
325 if (val) val->resize(
size(a));
331 if (val) std::copy(
start.begin(),
start.end(), val->begin());
334 if (val) std::copy(
start.begin(),
start.end(), val->begin());
339 casadi_error(
"Cannot handle: " +
to_string(a));
350 casadi_error(
"Cannot handle: " +
to_string(a));
374 casadi_error(
"Cannot handle: " +
to_string(a));
381 casadi_assert(val.size() ==
numel,
"Wrong size for attribute " +
to_string(a));
385 std::copy(val.begin(), val.end(),
start.begin());
388 std::copy(val.begin(), val.end(),
value.begin());
393 casadi_error(
"Cannot handle: " +
to_string(a));
408 Variable::Variable(casadi_int index,
const std::string& name,
409 const std::vector<casadi_int>& dimension,
const MX& expr)
410 : index(index), name(name), dimension(dimension), v(expr) {
412 casadi_assert(
dimension.size() > 0,
"Variable must have at least one dimension");
413 for (casadi_int d :
dimension) casadi_assert(d > 0,
"Dimensions must be positive");
484 casadi_warning(
"Start attribute for String, Binary not implemented.");
487 std::stringstream ss;
488 for (
size_t i = 0; i <
start.size(); ++i) {
489 if (i > 0) ss <<
" ";
493 ss << static_cast<casadi_int>(
start.at(i));
535 casadi_assert(
der >= 0,
"Variable " +
name +
" has no time derivative");
537 return self.variable(
der).v;
553 self.derivatives_.push_back(der_v.
index);
566 const Dict& opts) : name_(name), resource_(
path) {
582 std::string resource_serialize =
"link";
584 for (
auto&& op : opts) {
585 if (op.first==
"debug") {
587 }
else if (op.first==
"fmutol") {
589 }
else if (op.first==
"ignore_time") {
591 }
else if (op.first==
"detect_quad") {
593 }
else if (op.first==
"resource_serialize_mode") {
596 casadi_error(
"No such option: " + op.first);
606 casadi_error(
"Could not open file '" +
filename +
"'.");
608 casadi_error(
"Could not open file '" +
filename +
"'. "
609 "Note that, since CasADi was compiled without WITH_GHC_FILESYSTEM=ON, "
610 "passing fmu files to DaeBuilder is unsupported. "
611 "You could manually unzip the FMU file and "
612 "pass the path to the unzipped directory instead.");
617 casadi_assert(
n_variables() == 0,
"Instance already has variables");
641 fmi_major_ >= 3 ?
"instantiationToken" :
"guid");
656 if (fmi_desc.
has_child(
"DefaultExperiment")) {
661 bool has_model_exchange =
false;
662 if (fmi_desc.
has_child(
"ModelExchange")) {
663 has_model_exchange =
true;
668 casadi_assert(fmi_desc.
has_child(
"ModelVariables"),
"Missing 'ModelVariables'");
672 if (fmi_desc.
has_child(
"ModelStructure")) {
680 if (fmi_desc.
has_child(
"equ:BindingEquations")) {
686 if (fmi_desc.
has_child(
"equ:InitialEquations")) {
692 if (fmi_desc.
has_child(
"equ:DynamicEquations")) {
698 casadi_assert(
symbolic_ || has_model_exchange,
699 "FMU must be of ModelExchange type or be symbolic (FMUX)");
703 const std::vector<std::string>& cfiles)
const {
707 std::string model_name =
name_;
711 r.
name =
"fmiBuildDescription";
712 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
715 source_file_set.
name =
"SourceFileSet";
716 for (
auto&& f : cfiles) {
718 source_file.
name =
"SourceFile";
720 source_file_set.
children.push_back(source_file);
724 bc.
name =
"BuildConfiguration";
726 bc.
children.push_back(source_file_set);
729 std::string xml_filename =
"buildDescription.xml";
732 build_description.
children.push_back(r);
735 xml_file.
dump(xml_filename, build_description);
743 std::string model_name =
name_;
747 std::string copyright;
752 r.
name =
"fmiModelDescription";
753 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
755 r.
set_attribute(fmi_major >= 3 ?
"instantiationToken" :
"guid", guid);
759 if (!copyright.empty()) r.
set_attribute(
"copyright", copyright);
764 if (fmi_major < 3) r.
set_attribute(
"numberOfEventIndicators",
"0");
767 me.
name =
"ModelExchange";
773 def_exp.
name =
"DefaultExperiment";
785 std::string xml_filename =
"modelDescription.xml";
788 model_description.
children.push_back(r);
791 xml_file.
dump(xml_filename, model_description);
798 r.
name =
"ModelVariables";
800 r.
children.push_back(v->export_xml(*
this));
807 r.
name =
"ModelStructure";
821 c.
name =
"ContinuousStateDerivative";
830 c.
name =
"InitialUnknown";
839 c.
name =
"InitialUnknown";
848 c.
name =
"EventIndicator";
868 for (casadi_int k = dode_dxT.
colind(i); k < dode_dxT.
colind(i + 1); ++k) {
869 casadi_int j = dode_dxT.
row(k);
873 for (casadi_int k = dode_duT.
colind(i); k < dode_duT.
colind(i + 1); ++k) {
874 casadi_int j = dode_duT.
row(k);
879 for (std::string catname : {
"y",
"zero"}) {
883 for (casadi_int i = 0; i < oind.size(); ++i) {
889 for (casadi_int k = dy_dxT.
colind(i); k < dy_dxT.
colind(i + 1); ++k) {
890 casadi_int j = dy_dxT.
row(k);
894 for (casadi_int k = dy_duT.
colind(i); k < dy_duT.
colind(i + 1); ++k) {
895 casadi_int j = dy_duT.
row(k);
904 bool no_warning =
false;
905 for (
auto&& op : opts) {
906 if (op.first ==
"no_warning") {
907 no_warning = op.second;
911 if (!no_warning) casadi_warning(
"FMU generation is experimental and incomplete")
913 std::vector<std::string> ret;
917 std::string dae_filename =
name_;
919 Function dae = shared_from_this<DaeBuilder>().
create(dae_filename,
920 {
"t",
"x",
"p",
"u"}, {
"ode",
"y",
"zero"});
926 codegen_opts[
"with_header"] =
true;
933 ret.push_back(dae_filename +
".h");
938 ret.push_back(wrapper_filename);
948 std::stringstream ss;
953 if (!first) ss <<
", ";
963 std::stringstream ss;
968 if (!first) ss <<
", ";
971 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << e;
978 std::vector<double> r;
980 for (
double s : v->start) r.push_back(s);
988 std::string wrapper_filename =
name_ +
"_wrap.c";
991 std::ostream& f = *f_ptr;
995 f <<
"#include <fmi3Functions.h>\n"
996 <<
"#include \"" <<
name_ <<
".h\"\n"
1003 f <<
"#define SZ_MEM " <<
n_mem() <<
"\n";
1006 size_t sz_arg, sz_res, sz_iw, sz_w;
1007 gen.
sz_work(sz_arg, sz_res, sz_iw, sz_w);
1008 f <<
"#define SZ_ARG " << sz_arg <<
"\n"
1009 <<
"#define SZ_RES " << sz_res <<
"\n"
1010 <<
"#define SZ_IW " << sz_iw <<
"\n"
1011 <<
"#define SZ_W " << sz_w <<
"\n";
1014 f <<
"const size_t var_offset[N_VAR + 1] = {0";
1017 mem_ind += v->numel;
1018 f <<
", " << mem_ind;
1041 std::vector<size_t> xdot;
1043 f <<
"fmi3ValueReference xdot_vr[N_X] = " <<
generate(xdot) <<
";\n"
1047 f <<
"#define N_Y " <<
outputs_.size() <<
"\n"
1061 return wrapper_filename;
1070 }
catch (std::exception& e) {
1071 THROW_ERROR_NODE(
"read_variable", node, e.what());
1084 casadi_error(
"Cannot read attribute " +
to_string(att));
1091 const std::string& fullname = node.
name;
1093 if (fullname ==
"fun:If") {
1095 const XmlNode& cond = node[
"fun:Condition"];
1096 const XmlNode& then_stmt = node[
"fun:Statements"];
1097 const XmlNode& else_stmt = node[
"fun:Else"];
1099 casadi_assert(cond.
size() == 1,
"Only one condition in if expression supported");
1100 casadi_assert(then_stmt.
size() == 1,
"Only one then statement in if expression supported");
1101 casadi_assert(else_stmt.
size() == 1,
"Only one else statement in if expression supported");
1105 if (fullname.find(
"exp:")== std::string::npos) {
1106 casadi_error(
"DaeBuilderInternal::read_expr: unknown - expression is supposed to "
1107 "start with 'exp:' , got " + fullname);
1111 std::string
name = fullname.substr(4);
1118 }
else if (
name==
"Acos") {
1120 }
else if (
name==
"Asin") {
1122 }
else if (
name==
"Atan") {
1124 }
else if (
name==
"Cos") {
1126 }
else if (
name==
"Der") {
1128 }
else if (
name==
"Div") {
1130 }
else if (
name==
"Exp") {
1132 }
else if (
name==
"Identifier") {
1134 }
else if (
name==
"IntegerLiteral" ||
name==
"BooleanLiteral") {
1138 }
else if (
name==
"Instant") {
1142 }
else if (
name==
"Log") {
1144 }
else if (
name==
"Not") {
1146 }
else if (
name==
"LogLeq") {
1148 }
else if (
name==
"LogGeq") {
1150 }
else if (
name==
"LogLt") {
1152 }
else if (
name==
"LogGt") {
1154 }
else if (
name==
"Max") {
1156 }
else if (
name==
"Min") {
1158 }
else if (
name==
"Mul") {
1160 }
else if (
name==
"Neg") {
1162 }
else if (
name==
"NoEvent") {
1165 casadi_int n = node.
size();
1171 for (casadi_int i=n-3; i>=0; i -= 2) {
1176 }
else if (
name==
"Pow") {
1178 }
else if (
name==
"Pre") {
1179 casadi_warning(
"Ignoring pre attribute");
1181 }
else if (
name==
"RealLiteral") {
1185 }
else if (
name==
"Sin") {
1187 }
else if (
name==
"Sqrt") {
1189 }
else if (
name==
"StringLiteral") {
1190 casadi_error(node.
text);
1191 }
else if (
name==
"Sub") {
1193 }
else if (
name==
"Tan") {
1195 }
else if (
name==
"Time") {
1197 }
else if (
name==
"TimedVariable") {
1199 }
else if (
name==
"FunctionCall") {
1202 casadi_warning(
"Function call to '" + fname +
"' incomplete");
1204 const XmlNode& args = node[
"exp:Arguments"];
1205 std::vector<MX> farg(args.
size());
1206 for (casadi_int i = 0; i < args.
size(); ++i) {
1223 }
else if (
name==
"Array") {
1225 std::vector<MX> v(node.
size());
1226 for (casadi_int i = 0; i < v.size(); ++i) v[i] =
read_expr(node[i]);
1231 casadi_error(
"Unknown node: " +
name);
1232 }
catch (std::exception& e) {
1233 THROW_ERROR_NODE(
"read_expr", node, e.what());
1246 <<
"ny = " <<
outputs_.size() <<
", "
1255 stream << std::endl;
1258 if (!
fun_.empty()) {
1259 stream <<
"Functions:" << std::endl;
1261 stream <<
" " << f << std::endl;
1266 stream <<
"Model variables:" << std::endl;
1269 if (
size(cat) > 0) {
1276 if (
size(cat) > 0) {
1278 for (
size_t c :
indices(cat)) {
1280 stream <<
" " << v.
name;
1282 stream << std::endl;
1289 if (
size(cat) > 0) {
1292 for (
size_t k :
indices(cat)) {
1294 stream <<
" " << v.
name <<
": " <<
der(v.
v) << std::endl;
1301 stream <<
"Outputs (y):" << std::endl;
1304 stream <<
" " << v.
name <<
": " << v.
v << std::endl;
1309 stream <<
"Algebraic equations:" << std::endl;
1311 stream <<
" 0 == " <<
variable(k).
v << std::endl;
1315 if (!
init_.empty()) {
1316 stream <<
"Initial equations:" << std::endl;
1317 for (
size_t k :
init_) {
1319 stream <<
" " << v.
name;
1321 stream << std::endl;
1325 if (!
when_.empty()) {
1326 stream <<
"When equations:" << std::endl;
1327 for (
auto weq :
when_) {
1328 stream <<
" when " <<
variable(weq.first).
v <<
" < 0 : " << std::endl;
1329 for (
size_t eq : weq.second) {
1343 std::vector<size_t> new_order;
1344 for (
const MX& e : v) new_order.push_back(
find(e.name()));
1345 std::copy(new_order.begin(), new_order.end(),
indices(cat).begin());
1350 casadi_assert(z_order.size() ==
size(
Category::Z),
"Dimension mismatch");
1355 std::vector<size_t> new_z;
1356 new_z.reserve(z_order.size());
1357 for (
const std::string& s : z_order) {
1359 casadi_assert(old_z.at(i),
"Variable \"" + s +
"\" is not an algebraic variable.");
1367 return indices_.at(
static_cast<size_t>(cat));
1379 const std::vector<size_t>& v)
const {
1381 casadi_assert(ind.size() == v.size(),
"Cannot reorder " + n +
": "
1382 +
str(v.size()) +
" elements provided for " +
str(ind.size()) +
" components.");
1385 for (
size_t i : v) set.at(i) =
true;
1387 for (
size_t i : ind) casadi_assert(set.at(i),
"Cannot reorder " + n +
": "
1390 std::copy(v.begin(), v.end(), ind.begin());
1395 std::vector<MX> f_in, f_out, v;
1396 std::vector<std::string> f_in_name, f_out_name;
1403 f_in.push_back(vertcat(v));
1411 f_out.push_back(vertcat(v));
1416 Function f(
"prune_fcn", f_in, f_out, f_in_name, f_out_name);
1418 std::vector<bool> free_variables(
n_variables(),
false);
1419 for (
const std::string& s : f.
get_free()) {
1421 casadi_assert(it !=
varind_.end(),
"No such variable: \"" + s +
"\".");
1422 free_variables.at(it->second) =
true;
1438 for (
size_t i = 0; i < u.size(); ++i) {
1439 if (!free_variables.at(u.at(i))) u.at(nu++) = u.at(i);
1447 const std::string res_prefix =
"res__";
1449 std::vector<std::string> res, iv, iv_on_hold;
1452 std::set<std::string> iv_set;
1453 for (
auto& e : iv) iv_set.insert(e);
1454 for (
auto& e : iv_on_hold) iv_set.insert(e);
1481 std::vector<std::string>* iv, std::vector<std::string>* iv_on_hold)
const {
1483 if (res) res->clear();
1484 if (iv) iv->clear();
1485 if (iv_on_hold) iv_on_hold->clear();
1487 const std::string res_prefix =
"res__";
1489 std::vector<MX> r_hold, iv_hold;
1491 bool any_hold =
false;
1495 if (v->name.rfind(res_prefix, 0) == 0) {
1497 std::string iv_name, res_hold_name, iv_hold_name;
1500 size_t pos = res_prefix.size();
1502 size_t end = v->name.find(
"__", pos);
1503 if (end == std::string::npos) end = v->name.size();
1505 iv_name = v->name.substr(pos, end - pos);
1507 casadi_assert(
has(iv_name),
"No such variable: " + iv_name);
1509 if (end != v->name.size()) {
1512 end = v->name.find(
"__", pos);
1513 if (end == std::string::npos) end = v->name.size();
1514 res_hold_name = v->name.substr(pos, end - pos);
1516 casadi_assert(
has(res_hold_name),
"No such variable: " + res_hold_name);
1518 if (end != v->name.size()) {
1519 iv_hold_name = v->name.substr(end + 2);
1520 casadi_assert(
has(iv_hold_name),
"No such variable: " + iv_hold_name);
1523 }
catch (std::exception& e) {
1525 casadi_warning(
"Cannot process residual variable: " + v->name +
":" +
1526 std::string(e.what()));
1530 if (res_hold_name.empty()) {
1531 r_hold.push_back(
false);
1534 r_hold.push_back(
variable(res_hold_name).v);
1535 casadi_assert(r_hold.back().is_scalar(),
"Non-scalar hold variable for " + res_hold_name);
1537 if (res) res->push_back(v->name);
1539 if (iv_hold_name.empty()) {
1540 iv_hold.push_back(
false);
1543 iv_hold.push_back(
variable(iv_hold_name).v);
1544 casadi_assert(iv_hold.back().is_scalar(),
"Non-scalar hold variable for " + iv_hold_name);
1546 if (iv) iv->push_back(iv_name);
1553 casadi_error(
"not implemented");
1556 Function startfun_p = attribute_fun(
"startfun_p", {}, {
"start_p"});
1558 casadi_error(
"startfun has free variables: " +
str(startfun_p.
get_free()));
1560 DM p0 = startfun_p(std::vector<DM>{}).at(0);
1563 {vertcat(r_hold), vertcat(iv_hold)}, {
"p"}, {
"r_hold",
"iv_hold"});
1564 if (holdfun.has_free()) {
1565 casadi_error(
"holdfun has free variables: " +
str(holdfun.get_free()));
1568 std::vector<DM> hold0 = holdfun(std::vector<DM>{p0});
1569 std::vector<double> r_hold0 = hold0.at(0).nonzeros();
1570 std::vector<double> iv_hold0 = hold0.at(1).nonzeros();
1571 casadi_assert_dev(r_hold0.size() == res->size());
1572 casadi_assert_dev(iv_hold0.size() == iv->size());
1576 for (
size_t k = 0; k < res->size(); ++k) {
1577 if (!
static_cast<bool>(r_hold0.at(k))) {
1578 res->at(sz++) = res->at(k);
1585 for (
size_t k = 0; k < iv->size(); ++k) {
1586 if (!
static_cast<bool>(iv_hold0.at(k))) {
1587 if (iv) iv->at(sz++) = iv->at(k);
1589 if (iv_on_hold) iv_on_hold->push_back(iv->at(k));
1592 if (iv) iv->resize(sz);
1594 }
catch (std::exception& e) {
1596 casadi_warning(
"Failed to evaluate hold variables: " + std::string(e.what()));
1606 std::vector<std::string> r;
1623 const std::vector<casadi_int>& dimension,
const MX& expr) {
1625 casadi_assert(!
name.empty(),
"Name is empty string");
1627 casadi_assert(!
has(
name),
"Variable \"" +
name +
"\" already exists.");
1642 casadi_assert(
size(
Category::T) == 1,
"At most one time variable allowed");
1649 std::stringstream qn;
1650 bool first_part =
true;
1654 for (casadi_int i=0; i<nn.
size(); ++i) {
1656 std::string np = nn[i].
attribute<std::string>(
"name");
1659 if (np ==
"$START") {
1663 casadi_error(
"Ignoring attribute " + np);
1666 }
else if (np ==
"$PRE") {
1667 casadi_warning(
"$PRE attribute has not been implemented, ignoring");
1672 if (!first_part) qn <<
".";
1676 if (nn[i].
size()>0) {
1678 nn[i][
"exp:ArraySubscripts"][
"exp:IndexExpression"][
"exp:IntegerLiteral"].
get(&ind);
1679 qn <<
"[" << ind <<
"]";
1700 casadi_assert(
var.
is_column(),
"Input expression must be a vector");
1707 for (
MX& s : var_split) s =
der(s, may_allocate);
1712 std::vector<MX> dep = symvar(
var);
1714 std::vector<MX> dep_der;
1715 for (
size_t ind :
find(dep)) dep_der.push_back(
get_der(ind, may_allocate));
1718 std::vector<std::vector<MX>> r = {dep_der};
1719 r = forward(std::vector<MX>{
var}, dep, r);
1720 casadi_assert_dev(r.size() == 1);
1721 return vertcat(r.at(0));
1725 bool allow_no_prefix)
const {
1727 if (allow_no_prefix && !
has(prefix))
return prefix;
1730 while (
has(prefix +
str(i))) i++;
1732 return prefix +
str(i);
1743 casadi_assert(
is_acyclic(cat),
"Elimination not supported for category " +
to_string(cat));
1746 if (
size(cat) == 0)
return;
1754 if (!v->v.is_constant()) ex.push_back(v->v);
1757 std::vector<size_t> ind =
indices(cat);
1758 std::vector<MX> v =
var(ind);
1760 substitute_inplace(v, vdef, ex);
1762 auto it = ex.begin();
1764 if (!v->v.is_constant()) v->v = *it++;
1767 casadi_assert_dev(it == ex.end());
1769 for (
size_t k : ind) {
1783 std::vector<MX> new_w, new_wdef;
1784 Dict opts{{
"lift_shared", lift_shared}, {
"lift_calls", lift_calls},
1785 {
"prefix",
"w_"}, {
"suffix",
""}, {
"offset",
static_cast<casadi_int
>(
size(
Category::W))}};
1786 extract(ex, new_w, new_wdef, opts);
1788 for (
size_t i = 0; i < new_w.size(); ++i) {
1796 auto it = ex.begin();
1801 casadi_assert_dev(it == ex.end());
1827 casadi_error(
"No input category for " +
to_string(cat));
1834 to_string(ind) +
" is not an input category");
1840 std::vector<MX> ret(ind.size());
1841 for (casadi_int i=0; i<ind.size(); ++i) {
1842 ret[i] = vertcat(
input(ind[i]));
1864 std::vector<MX> ret;
1865 ret.reserve(
size(cat));
1871 for (
size_t v :
indices(cat)) {
1881 casadi_error(
"Missing derivative for " +
str(x.
name));
1896 std::vector<MX> ret(ind.size());
1897 for (casadi_int i=0; i<ind.size(); ++i) {
1898 ret[i] = vertcat(
output(ind[i]));
1908 casadi_assert(!
name.empty(),
"DaeBuilderInternal::add_lc: \"name\" is empty");
1909 for (std::string::const_iterator i=
name.begin(); i!=
name.end(); ++i) {
1910 casadi_assert(isalnum(*i),
1911 "DaeBuilderInternal::add_lc: \"name\" must be alphanumeric");
1915 casadi_assert(!f_out.empty(),
"DaeBuilderInternal::add_lc: Linear combination is empty");
1917 for (casadi_int i=0; i < f_out.size(); ++i) {
1918 auto oind =
static_cast<size_t>(to_enum<OutputCategory>(f_out[i]));
1919 casadi_assert(!in_use[oind],
"DaeBuilderInternal::add_lc: Duplicate expression " + f_out[i]);
1920 in_use[oind] =
true;
1923 std::vector<std::string>& ret1 =
lc_[
name];
1924 if (!ret1.empty()) casadi_warning(
"DaeBuilderInternal::add_lc: Overwriting " <<
name);
1929 const std::vector<std::string>& s_in,
1930 const std::vector<std::string>& s_out,
const Dict& opts,
bool sx,
bool lifted_calls)
const {
1932 bool with_underscore =
false;
1933 for (
auto s_io : {&s_in, &s_out}) {
1934 for (
const std::string& s : *s_io) {
1935 with_underscore = with_underscore || std::count(s.begin(), s.end(),
'_');
1941 casadi_assert(!lifted_calls,
"Lifting requires a symbolic representation");
1943 casadi_assert(!sx,
"SX expansion requires a symbolic representation");
1945 return fmu_fun(fname, s_in, s_out, opts);
1948 if (with_underscore) {
1949 std::vector<std::string> s_in_mod(s_in), s_out_mod(s_out);
1950 for (
auto s_io : {&s_in_mod, &s_out_mod}) {
1951 for (std::string& s : *s_io) std::replace(s.begin(), s.end(),
'_',
':');
1954 return create(fname, s_in_mod, s_out_mod, opts, sx, lifted_calls);
1957 bool elim_w =
false;
1961 for (
const std::string& s : s_in) {
1972 casadi_assert(!elim_w,
"Lifted calls cannot be used if dependent variables are eliminated");
1974 lifted_calls =
false;
1976 if (vdef_comp.is_output()) {
1978 lifted_calls =
true;
1984 std::string fname_nocalls = lifted_calls ? fname +
"_nocalls" : fname;
1987 if (!lifted_calls)
return ret;
1989 std::vector<MX> ret_in = ret.
mx_in();
1990 std::vector<MX> ret_out = ret(ret_in);
1994 std::vector<MX> v_in, lam_vdef_in;
1995 for (
size_t i = 0; i < s_in.size(); ++i) {
1997 v_in = vertsplit(ret_in[i], h_offsets);
1998 }
else if (ret.
name_in(i) ==
"lam_wdef") {
1999 lam_vdef_in = vertsplit(ret_in[i], h_offsets);
2003 std::map<MXNode*, size_t> v_map;
2010 std::map<MXNode*, CallIO> call_nodes;
2011 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2013 const MX& vdefref = wdef.at(vdefind);
2017 MX c = vdefref.
dep(0);
2019 auto call_it = call_nodes.
find(c.
get());
2021 if (call_it == call_nodes.end()) {
2027 cio.
v.resize(c.
n_dep(), -1);
2028 cio.
arg.resize(cio.
v.size());
2029 for (casadi_int i = 0; i < cio.
v.size(); ++i) {
2031 cio.
arg.at(i) = c.
dep(i);
2033 size_t v_ind = v_map.at(c.
dep(i).
get());
2034 cio.
v.at(i) = v_ind;
2035 cio.
arg.at(i) = v_in.at(v_ind);
2040 cio.
res.resize(cio.
vdef.size());
2044 call_it = call_nodes.insert(std::make_pair(c.
get(), cio)).first;
2049 call_it->second.vdef.at(oind) = vdefind;
2050 call_it->second.res.at(oind) = v_in.at(vdefind);
2052 if (!lam_vdef_in.empty()) call_it->second.adj1_arg.at(oind) = lam_vdef_in.at(vdefind);
2056 for (
size_t i = 0; i < ret_out.size(); ++i) {
2057 if (ret.
name_out(i) ==
"jac_wdef_w") {
2063 for (
auto&& e :
lc_) {
2065 bool has_vdef =
false;
2066 for (
const std::string& r : e.second) {
2073 if (!has_vdef)
continue;
2075 for (
size_t i = 0; i < ret_out.size(); ++i) {
2076 if (ret.
name_out(i) ==
"hess_" + e.first +
"_w_w") {
2081 ret_out.at(i) += extra_hess_v_v;
2091 const std::vector<casadi_int>& h_offsets)
const {
2093 for (
auto call_it = call_nodes.begin(); call_it != call_nodes.end(); ++call_it) {
2094 call_it->second.calc_jac();
2097 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2099 std::vector<MX> vblocks, hblocks;
2101 std::map<size_t, MX> jac_brow;
2105 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2107 const MX& vdefref = wdef.at(vdefind);
2109 voffset_begin = voffset_end;
2110 voffset_end += vdefref.
numel();
2116 MX c = vdefref.
dep(0);
2118 auto call_it = call_nodes.
find(c.
get());
2119 casadi_assert_dev(call_it != call_nodes.end());
2122 for (casadi_int iind = 0; iind < call_it->second.arg.size(); ++iind) {
2123 size_t vind = call_it->second.v.at(iind);
2124 if (vind !=
size_t(-1)) {
2125 jac_brow[vind] = call_it->second.jac(oind, iind);
2129 if (voffset_last != voffset_begin) {
2130 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2134 casadi_int hoffset = 0;
2135 for (
auto e : jac_brow) {
2137 if (hoffset < h_offsets.at(e.first))
2138 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.at(e.first) - hoffset));
2140 hblocks.push_back(e.second);
2142 hoffset = h_offsets.at(e.first + 1);
2145 if (hoffset < h_offsets.back())
2146 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.back() - hoffset));
2148 vblocks.push_back(horzcat(hblocks));
2150 voffset_last = voffset_end;
2154 if (voffset_last != voffset_end) {
2155 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2158 return vertcat(vblocks);
2162 const std::vector<casadi_int>& h_offsets)
const {
2164 for (
auto&& call_ref : call_nodes) call_ref.second.calc_hess();
2166 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2168 std::vector<MX> vblocks, hblocks;
2170 std::map<size_t, MX> hess_brow;
2176 voffset_begin = voffset_end;
2177 voffset_end += vref.
numel();
2180 for (
auto&& call_ref : call_nodes) {
2182 for (
size_t iind1 = 0; iind1 < call_ref.second.v.size(); ++iind1) {
2183 if (call_ref.second.v.at(iind1) == vind1) {
2185 for (
size_t iind2 = 0; iind2 < call_ref.second.v.size(); ++iind2) {
2187 size_t vind2 = call_ref.second.v[iind2];
2188 if (vind2 ==
size_t(-1))
continue;
2190 MX H_contr = call_ref.second.hess(iind1, iind2);
2192 auto it = hess_brow.
find(vind2);
2193 if (it != hess_brow.end()) {
2194 it->second += H_contr;
2196 hess_brow[vind2] = H_contr;
2205 if (hess_brow.empty())
continue;
2207 if (voffset_last != voffset_begin) {
2208 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2212 casadi_int hoffset = 0;
2213 for (
auto e : hess_brow) {
2215 if (hoffset < h_offsets.at(e.first))
2216 hblocks.push_back(
MX(vref.
numel(), h_offsets.at(e.first) - hoffset));
2218 hblocks.push_back(e.second);
2220 hoffset = h_offsets.at(e.first + 1);
2223 if (hoffset < h_offsets.back())
2224 hblocks.push_back(
MX(vref.
numel(), h_offsets.back() - hoffset));
2226 vblocks.push_back(horzcat(hblocks));
2228 voffset_last = voffset_end;
2231 if (voffset_last != voffset_end) {
2232 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2235 return vertcat(vblocks);
2239 for (
bool sx : {
false,
true}) {
2240 for (
bool elim_w : {
false,
true}) {
2241 for (
bool lifted_calls : {
false,
true}) {
2251 casadi_assert(
symbolic_,
"DaeBuilder oracle only available if symbolic representation");
2256 if (
oracle_[
false][elim_w][lifted_calls].is_null()) {
2258 std::vector<MX> f_in, f_out, v;
2259 std::vector<std::string> f_in_name, f_out_name;
2261 casadi_int wdef_ind = -1;
2263 casadi_assert(!(elim_w && lifted_calls),
"Incompatible options");
2265 bool subst_v =
false;
2270 if (!v.empty()) subst_v =
true;
2273 f_in.push_back(
MX(0, 1));
2275 f_in.push_back(vertcat(v));
2286 f_out.push_back(
MX(0, 1));
2289 f_out.push_back(vertcat(v));
2298 }
else if (lifted_calls && wdef_ind >= 0) {
2302 for (
MX& wdefref : wdef) {
2303 if (wdefref.is_output()) wdefref =
MX::zeros(wdefref.sparsity());
2306 f_out.at(wdef_ind) = vertcat(wdef);
2309 oracle_[
false][elim_w][lifted_calls]
2310 =
Function(
"mx_oracle", f_in, f_out, f_in_name, f_out_name);
2313 if (!sx)
return oracle_[
false][elim_w][lifted_calls];
2323 for (casadi_int i = 0; i < this->
f.
n_in(); ++i) {
2324 casadi_assert(this->
f.
size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2326 for (casadi_int i = 0; i < this->
f.
n_out(); ++i) {
2327 casadi_assert(this->
f.
size_out(i) == this->res.at(i).size(),
"Call output not provided");
2334 std::vector<MX> call_in = this->
arg;
2335 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2342 for (casadi_int i = 0; i < this->f.n_in(); ++i) {
2343 casadi_assert(this->f.size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2345 casadi_assert(this->adj1_arg.size() == this->res.size(),
"Input 'lam_vdef' not provided");
2346 for (casadi_int i = 0; i < this->f.n_out(); ++i) {
2347 casadi_assert(this->f.size_out(i) == this->res.at(i).size(),
"Call output not provided");
2348 casadi_assert(this->adj1_arg.at(i).size() == this->res.at(i).size(),
2349 "Call adjoint seed not provided");
2352 if (!this->jac_res.empty())
2353 casadi_warning(
"Jacobian blocks currently not reused for gradient calculation");
2356 this->adj1_f = this->f.reverse(1);
2359 std::vector<MX> call_in = this->arg;
2360 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2361 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2363 this->adj1_res = this->adj1_f(call_in);
2368 if (this->adj1_f.is_null()) calc_grad();
2371 this->H = this->adj1_f.jacobian();
2374 std::vector<MX> call_in = this->arg;
2375 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2376 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2377 call_in.insert(call_in.end(), this->adj1_res.begin(), this->adj1_res.end());
2379 this->hess_res = this->H(call_in);
2384 casadi_int ind = iind + oind * this->arg.
size();
2386 return this->jac_res.at(ind);
2391 casadi_int ind = iind1 + iind1 * this->adj1_arg.
size();
2393 return this->hess_res.at(ind);
2398 Function vfcn(
"vfcn", {vertcat(v)}, {vertcat(vdef)}, {
"v"}, {
"vdef"},
2399 Dict{{
"allow_free",
true}});
2401 bool any_vector_valued =
false;
2402 for (
const MX& v_i : v) {
2403 casadi_assert(!v_i.is_empty(),
"Cannot have zero-dimension dependent variables");
2404 if (!v_i.is_scalar()) {
2405 any_vector_valued =
true;
2410 if (any_vector_valued) {
2412 std::vector<MX> vfcn_in(v), vfcn_arg(v);
2413 for (
size_t i = 0; i < v.size(); ++i) {
2414 if (!v.at(i).is_scalar()) {
2415 vfcn_in.at(i) =
MX::sym(v.at(i).name());
2416 vfcn_arg.at(i) = repmat(vfcn_in.at(i), v.at(i).size1());
2420 std::vector<MX> vfcn_out = vfcn(vertcat(vfcn_arg));
2421 vfcn_out = vertsplit(vfcn_out.at(0), offset(v));
2423 for (
size_t i = 0; i < v.size(); ++i) {
2424 if (!v.at(i).is_scalar()) {
2425 vfcn_out.at(i) =
dot(vfcn_out.at(i), vfcn_out.at(i));
2429 vfcn =
Function(vfcn.name(), {vertcat(vfcn_in)}, {vertcat(vfcn_out)},
2430 vfcn.name_in(), vfcn.name_out(), {{
"allow_free", true}});
2433 Sparsity Jv = vfcn.jac_sparsity(0, 0);
2439 std::vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
2440 (void)Jv.
btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
2442 std::vector<MX> tmp(v.size());
2443 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = v.at(colperm.at(k));
2444 std::copy(tmp.begin(), tmp.end(), v.begin());
2446 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = vdef.at(rowperm.at(k));
2447 std::copy(tmp.begin(), tmp.end(), vdef.begin());
2451 const std::vector<std::string>& s_in,
2452 const std::vector<std::string>& s_out)
const {
2454 bool calc_d =
false, calc_w =
false;
2456 std::vector<Category> v_out;
2457 v_out.reserve(v_out.size());
2458 for (
const std::string& s : s_out) {
2465 casadi_error(
"Can only calculate d and/or w");
2470 casadi_assert(calc_d || calc_w,
"Nothing to calculate");
2472 std::vector<Category> v_in;
2473 v_in.reserve(v_in.size());
2474 for (
const std::string& s : s_in) {
2476 if (calc_d && e ==
Category::D) casadi_error(
"'d' cannot be both input and output");
2477 if (calc_w && e ==
Category::W) casadi_error(
"'w' cannot be both input and output");
2481 std::vector<MX> f_in;
2482 f_in.reserve(s_in.size());
2485 std::vector<MX> f_out;
2486 f_out.reserve(s_out.size());
2487 for (
Category v : v_out) f_out.push_back(vertcat(
input(v)));
2489 std::vector<MX> dw, dwdef;
2492 dw.insert(dw.end(), d.begin(), d.end());
2494 dwdef.insert(dwdef.end(), ddef.begin(), ddef.end());
2498 dw.insert(dw.end(), w.begin(), w.end());
2500 dwdef.insert(dwdef.end(), wdef.begin(), wdef.end());
2503 substitute_inplace(dw, dwdef, f_out);
2505 return Function(fname, f_in, f_out, s_in, s_out);
2509 bool dummy_index_input)
const {
2512 casadi_assert(index >= 0 && index <
when_.size(),
"Illegal event index");
2526 std::vector<MX> when_lhs, when_rhs;
2527 for (
size_t eq :
when_.at(index).second) {
2534 std::vector<MX> ret_out = {ret_in[
DYN_X], ret_in[
DYN_Z]};
2546 if (dummy_index_input) {
2548 ret_in.insert(ret_in.begin(),
MX());
2564 std::vector<Function> f_all;
2565 for (casadi_int i = 0; i <
when_.size(); ++i) {
2579 const std::vector<std::string>& name_in,
2580 const std::vector<std::string>& name_out,
2581 const Dict& opts)
const {
2583 Dict::const_iterator it;
2585 std::vector<std::string> scheme_in;
2586 bool has_in =
false;
2587 if ((it = opts.find(
"scheme_in")) != opts.end()) {
2589 scheme_in = it->second;
2590 }
catch (std::exception& e) {
2591 casadi_error(std::string(
"Cannot read 'scheme_in': ") + e.what());
2597 std::vector<std::string> scheme_out;
2598 bool has_out =
false;
2599 if ((it = opts.find(
"scheme_out")) != opts.end()) {
2601 scheme_out = it->second;
2603 }
catch (std::exception& e) {
2604 casadi_error(std::string(
"Cannot read 'scheme_out': ") + e.what());
2608 if (!has_in || !has_out) {
2612 std::map<std::string, std::vector<size_t>> scheme;
2613 if ((it = opts.find(
"scheme")) != opts.end()) {
2616 Dict scheme_dict = it->second;
2618 for (
auto&& e : scheme_dict) {
2619 std::vector<std::string> v = e.second;
2620 scheme[e.first] =
find(v);
2622 }
catch (std::exception& e) {
2623 casadi_error(std::string(
"Cannot read 'scheme': ") + e.what());
2627 for (
auto&& s :
dyn_in()) scheme[s] = std::vector<size_t>();
2628 for (
auto&& s :
dyn_out()) scheme[s] = std::vector<size_t>();
2636 for (
size_t& i : scheme[
"ode"]) i =
variable(i).
der;
2638 for (
size_t& i : scheme[
"quad"]) i =
variable(i).
der;
2642 scheme[
"rate"] =
rate_;
2645 std::vector<std::string> aux;
2646 if ((it = opts.find(
"aux")) != opts.end()) {
2649 }
catch (std::exception& e) {
2650 casadi_error(std::string(
"Cannot read 'aux': ") + e.what());
2655 scheme_in, scheme_out, scheme, aux);
2663 std::vector<MX> f_out;
2665 std::vector<std::string> f_out_name;
2668 std::vector<MX> v =
output(cat);
2670 f_out.push_back(vertcat(v));
2675 return Function(
"all_eq", {}, f_out, {}, f_out_name, {{
"allow_free",
true}});
2679 casadi_assert(
has_t(),
"No explicit time variable");
2688 std::vector<MX> ret;
2695 std::vector<MX> ret;
2696 ret.reserve(
init_.size());
2697 for (
size_t ind :
init_) {
2704 std::vector<MX> ret;
2705 ret.reserve(
init_.size());
2706 for (
size_t ind :
init_) {
2764 std::string
description, type, initial, unit, display_unit;
2765 std::vector<casadi_int> dimension = {1};
2767 std::vector<double> start;
2769 for (
auto&& op : opts) {
2770 if (op.first==
"dimension") {
2771 dimension = op.second.to_int_vector();
2772 }
else if (op.first==
"description") {
2774 }
else if (op.first==
"unit") {
2775 unit = op.second.to_string();
2776 }
else if (op.first==
"display_unit") {
2777 display_unit = op.second.to_string();
2778 }
else if (op.first==
"min") {
2779 min = op.second.to_double();
2780 }
else if (op.first==
"max") {
2781 max = op.second.to_double();
2782 }
else if (op.first==
"nominal") {
2783 nominal = op.second.to_double();
2784 }
else if (op.first==
"start") {
2786 start.resize(1, op.second.to_double());
2788 start = op.second.to_double_vector();
2790 }
else if (op.first==
"type") {
2791 type = op.second.to_string();
2792 }
else if (op.first==
"initial") {
2793 initial = op.second.to_string();
2795 casadi_error(
"No such option: " + op.first);
2801 if (!type.empty()) v.
type = to_enum<Type>(type);
2804 if (!start.empty()) v.
start = start;
2805 if (!initial.empty()) v.
initial = to_enum<Initial>(initial);
2806 if (!unit.empty()) v.
unit = unit;
2807 if (!display_unit.empty()) v.
display_unit = display_unit;
2820 casadi_error(
"'parameter' causality requires 'fixed' or 'tunable' variability");
2825 "'calculatedParameter' causality requires 'fixed' or 'tunable' variability");
2832 "'input' causality requires 'continuous' or 'discrete' variability");
2847 casadi_error(
"'output' causality requires 'constant', 'continuous' or "
2848 "'discrete' variability");
2866 casadi_error(
"'output' causality requires 'constant', 'fixed', 'tunable', 'discrete' or "
2867 "'continuous' variability");
2872 casadi_assert(!
has_t(),
"'t' already defined");
2874 "Independent variable must be continuous");
2889 if (opts.find(
"type") != opts.end()) {
2890 type = to_enum<Type>(opts.at(
"type").to_string());
2921 size_t loc = v.size();
2922 for (
size_t i = 0; i < v.size(); ++i) {
2928 v.insert(v.begin() + loc, ind);
2932 for (
auto it = v.begin(); it != v.end(); ++it) {
2938 casadi_error(
"Variable not found");
2959 casadi_error(
"Cannot change causality of " + v.
name +
" which is of category '"
2990 casadi_error(
"The variability of " + v.
name +
", which is of category 'u', can only be "
2991 "changed to 'fixed' (for no category) or 'tunable' (for category 'p')");
3005 casadi_error(
"The variability of " + v.
name +
", which is of category 'p', can only be "
3006 "changed to 'continuous' (for category 'u') or 'fixed' (for no category)");
3020 casadi_error(
"The variability of " + v.
name +
", which is of type 'c', can only be "
3021 "changed to 'continuous' (for category 'u') or 'tunable' (for category 'p')");
3025 casadi_error(
"Cannot change variability of " + v.
name +
", which is of category '"
3074 casadi_error(
"Cannot change category of " + v.
name +
" from '"
3080 for (
auto&& op : opts) {
3081 casadi_error(
"No such option: " + op.first);
3084 casadi_assert(lhs.
is_column(),
"Left-hand-side must be a column vector");
3085 casadi_assert(rhs.
is_column(),
"Right-hand-side must be a column vector");
3087 if (!lhs.
is_dense())
return eq(densify(lhs), rhs, opts);
3088 if (!rhs.
is_dense())
return eq(lhs, densify(rhs), opts);
3093 return eq(repmat(lhs, rhs.
size1()), rhs, opts);
3094 }
else if (lhs.
size1() > 1 && rhs.
size1() == 1) {
3095 return eq(lhs, repmat(rhs, lhs.
size1()), opts);
3097 casadi_error(
"Mismatched dimensions: " +
str(lhs.
size1()) +
" vs " +
str(rhs.
size1()));
3101 std::vector<size_t> rhs_vars =
find(symvar(rhs));
3105 for (
size_t rhs : rhs_vars) {
3111 casadi_assert(x.
der == v.
index,
"Cannot handle right-hand-side variable: " + v.
name);
3115 {{
"dimension", {x.dimension}}});
3117 eq(x.get_der(*
this), der_x.v,
Dict());
3121 if (lhs.is_valid_input()) {
3123 if (lhs.is_symbolic()) {
3129 return eq(
MX::zeros(lhs.sparsity()), lhs - rhs, opts);
3132 Variable& beq = assign(v.
name, rhs);
3140 casadi_assert(x.der == v.
index,
"Cannot handle left-hand-side: " +
str(lhs));
3149 Variable& def_x = add(unique_name(
"def_" + x.name,
true),
3151 {{
"dimension", {x.dimension}}});
3153 def_x.bind = x.bind;
3160 x.v - def_x.v, {{
"dimension", x.dimension}});
3162 residuals_.push_back(alg.index);
3164 casadi_error(
"Unexpected category for " + x.name +
": " +
to_string(x.category));
3170 casadi_error(
"Cannot handle left-hand-side: " +
str(lhs) +
" of category '"
3175 auto lhs_split = lhs.primitives();
3176 std::vector<MX> rhs_split = lhs.split_primitives(rhs);
3178 for (
size_t k = 0; k < lhs_split.size(); ++k) {
3179 eq(lhs_split.at(k), rhs_split.at(k), opts);
3186 lhs - rhs, {{
"dimension", std::vector<casadi_int>{lhs.size1()}}});
3188 residuals_.push_back(alg.index);
3191 for (
size_t rhs : rhs_vars) {
3203 for (
auto&& op : opts) {
3204 casadi_error(
"No such option: " + op.first);
3209 zero = cond.
dep(0) - cond.
dep(1);
3211 casadi_error(
"Only strict inequality in zero-crossing conditions permitted, got: "
3214 casadi_error(
"Cannot parse zero-crossing condition: " +
str(cond));
3222 std::vector<MX> all_lhs, all_rhs;
3223 std::vector<size_t> all_eqs;
3224 for (
auto&&
eq : eqs) {
3228 all_rhs.push_back(ee.
v);
3229 all_eqs.push_back(ee.
index);
3231 when_.push_back(std::make_pair(e.
index, all_eqs));
3266 if (old_loc ==
init_.end()) casadi_error(
"Corrupted list of initial equations");
3267 init_.erase(old_loc);
3275 casadi_error(
"Initial equation for " +
name +
" has already been set");
3282 template<
typename T>
3285 size_t sz = n.
size();
3289 for (
size_t i = 0; i < sz; ++i) {
3290 r.push_back(
T(n[i]));
3305 fmi_major_ >= 3 ?
"providesDirectionalDerivatives" :
"providesDirectionalDerivative",
false);
3307 = n.
attribute<
bool>(
"providesAdjointDerivatives",
false);
3310 n.
attribute<
bool>(
"canBeInstantiatedOnlyOncePerProcess",
false);
3313 for (
const XmlNode& sf : n[
"SourceFiles"].children) {
3321 std::vector<std::pair<std::string, std::string>> fmi1_der;
3324 std::vector<const XmlNode*> modvars_children;
3326 for (casadi_int i = 0; i < modvars.
size(); ++i) {
3328 const XmlNode& vnode = modvars[i];
3329 std::string causality_str = vnode.
attribute<std::string>(
"causality",
"local");
3330 if (causality_str==
"independent") {
3331 modvars_children.push_back(&vnode);
3335 for (casadi_int i = 0; i < modvars.
size(); ++i) {
3337 const XmlNode& vnode = modvars[i];
3338 std::string causality_str = vnode.
attribute<std::string>(
"causality",
"local");
3339 if (causality_str!=
"independent") {
3340 modvars_children.push_back(&vnode);
3345 for (
const XmlNode* & vnode_ptr : modvars_children) {
3347 const XmlNode& vnode = *vnode_ptr;
3354 std::string variable_category = vnode[
"VariableCategory"].
text;
3355 if (variable_category ==
"derivative") {
3357 std::string x_name = vnode[
"QualifiedName"][0].
attribute<std::string>(
"name");
3358 fmi1_der.push_back(std::make_pair(x_name,
name));
3363 if (
fmi_major_ == 1 &&
name.rfind(
"$whenCondition", 0) == 0)
continue;
3367 casadi_warning(
"Duplicate variable '" +
name +
"' ignored");
3374 casadi_int derivative = -1;
3377 type = to_enum<Type>(vnode.
name);
3382 opts[
"unit"] = vnode.
attribute<std::string>(
"unit",
"");
3383 opts[
"display_unit"] = vnode.
attribute<std::string>(
"displayUnit",
"");
3386 opts[
"nominal"] = vnode.
attribute<
double>(
"nominal", 1.);
3387 opts[
"start"] = vnode.
attribute<
double>(
"start", 0.);
3388 derivative = vnode.
attribute<casadi_int>(
"derivative", -1);
3409 const XmlNode& props = vnode[
"Real"];
3410 opts[
"unit"] = props.
attribute<std::string>(
"unit",
"");
3411 opts[
"display_unit"] = props.
attribute<std::string>(
"displayUnit",
"");
3414 opts[
"nominal"] = props.
attribute<
double>(
"nominal", 1.);
3415 opts[
"start"] = props.
attribute<
double>(
"start", 0.);
3416 derivative = props.
attribute<casadi_int>(
"derivative", -1);
3417 }
else if (vnode.
has_child(
"Integer")) {
3419 const XmlNode& props = vnode[
"Integer"];
3422 }
else if (vnode.
has_child(
"Boolean")) {
3426 }
else if (vnode.
has_child(
"Enumeration")) {
3429 casadi_warning(
"Unknown type for " +
name);
3437 std::string causality_str = vnode.
attribute<std::string>(
"causality",
"local");
3438 if (
fmi_major_ == 1 && causality_str ==
"internal") causality_str =
"local";
3442 std::string variability_str = vnode.
attribute<std::string>(
"variability",
3444 if (
fmi_major_ == 1 && variability_str ==
"parameter") variability_str =
"fixed";
3449 std::string initial_str = vnode.
attribute<std::string>(
"initial",
"");
3450 if (!initial_str.empty()) {
3454 "initial = '" + initial_str +
"' is not allowed per the FMI specification.");
3455 initial = to_enum<Initial>(initial_str);
3486 var.value_reference =
static_cast<unsigned int>(vnode.
attribute<casadi_int>(
"valueReference"));
3488 var.der_of = derivative;
3508 for (
auto& p : fmi1_der) {
3522 "Default 'dependencies' not implemented");
3524 std::vector<casadi_int> r = n.
attribute<std::vector<casadi_int>>(
"dependencies", {});
3526 for (casadi_int& e : r) {
3529 e =
vrmap_.at(
static_cast<unsigned int>(e));
3540 const XmlNode& n,
size_t ndep) {
3547 auto dk_str = n.
attribute<std::vector<std::string>>(
"dependenciesKind");
3549 casadi_assert(dk_str.size() == ndep,
"Mismatching 'dependenciesKind'");
3551 std::vector<DependenciesKind> r(ndep);
3552 for (
size_t i = 0; i < ndep; ++i) {
3553 r[i] = to_enum<DependenciesKind>(dk_str[i]);
3575 for (casadi_int i = 0; i < n.
size(); ++i) {
3578 if (e.
name ==
"Output") {
3589 }
else if (e.
name ==
"ContinuousStateDerivative") {
3595 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
3606 }
else if (e.
name ==
"ClockedState") {
3608 casadi_message(
"ClockedState not implemented, ignoring");
3609 }
else if (e.
name ==
"InitialUnknown") {
3614 }
else if (e.
name ==
"EventIndicator") {
3620 casadi_error(
"Unknown ModelStructure element: " + e.
name);
3626 for (
auto& e : n[
"Derivatives"].children) {
3628 derivatives_.push_back(e.attribute<casadi_int>(
"index", 0) - 1);
3632 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
3642 std::vector<casadi_int> default_dependencies;
3643 default_dependencies.insert(default_dependencies.begin(),
3645 default_dependencies.insert(default_dependencies.begin(),
3647 default_dependencies.insert(default_dependencies.begin(),
3649 std::sort(default_dependencies.begin(), default_dependencies.end());
3658 std::vector<casadi_int> additional_dependencies;
3659 additional_dependencies.insert(additional_dependencies.begin(),
3661 std::vector<DependenciesKind> additional_dependencies_kind(
size(
Category::P),
3667 for (
auto& e : n[
"Derivatives"].children) {
3668 casadi_int index = e.attribute<casadi_int>(
"index", 0)-1;
3674 if (e.has_attribute(
"dependencies")) {
3677 v.dependencies = default_dependencies;
3681 v.dependencies.insert(v.dependencies.end(),
3682 additional_dependencies.begin(), additional_dependencies.end());
3683 v.dependenciesKind.insert(v.dependenciesKind.end(),
3684 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
3693 for (
auto& e : n[
"Outputs"].children) {
3695 outputs_.push_back(e.attribute<casadi_int>(
"index", 0) - 1);
3699 if (e.has_attribute(
"dependencies")) {
3707 additional_dependencies.begin(), additional_dependencies.end());
3709 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
3718 default_dependencies.clear();
3719 default_dependencies.insert(default_dependencies.begin(),
3722 if (v->initial ==
Initial::EXACT) default_dependencies.push_back(v->index);
3724 default_dependencies.insert(default_dependencies.begin(),
3726 std::sort(default_dependencies.begin(), default_dependencies.end());
3730 for (
auto& e : n[
"InitialUnknowns"].children) {
3734 std::vector<casadi_int> dependencies;
3736 if (e.has_attribute(
"dependencies")) {
3739 dependencies = default_dependencies;
3742 dependencies.insert(dependencies.end(),
3743 additional_dependencies.begin(), additional_dependencies.end());
3762 uout() <<
"== Structure before importing binding equations ==" << std::endl;
3767 for (casadi_int i = 0; i < eqs.
size(); ++i) {
3769 std::string eq_name =
"beq_" +
str(i);
3779 casadi_assert(
eq[1].
size() == 0,
"Not implemented");
3782 casadi_warning(
var.
name +
" has binding equation without type specifier: " +
str(val));
3788 }
catch (std::exception& e) {
3789 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
3796 uout() <<
"== Structure before importing dynamic equations ==" << std::endl;
3807 for (casadi_int i = 0; i < eqs.
size(); ++i) {
3809 std::string eq_name =
"dyneq_" +
str(i);
3812 if (
eq.name ==
"equ:When") {
3814 const XmlNode& n_cond =
eq[
"equ:Condition"];
3815 const XmlNode& n_equ =
eq[
"equ:Equation"];
3817 casadi_assert(n_cond.
size() == 1,
"Only one condition in when equation supported");
3818 casadi_assert(n_equ.
size() == 1,
"Only one equation in when equation supported");
3820 std::string cond_name = n_cond[0][0].
attribute<std::string>(
"name");
3821 std::string when_prefix =
"$whenCondition";
3822 cond_name = cond_name.substr(when_prefix.size());
3823 casadi_int ind = std::stoi(cond_name) - 1;
3827 if (n_equ[0].
name ==
"exp:Sub") {
3832 }
else if (n_equ[0].
name ==
"exp:Reinit") {
3839 casadi_error(n_equ[0].
name +
" in when equation not supported");
3841 }
else if (
eq.name ==
"equ:Equation") {
3843 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
3846 casadi_warning(eq_name +
" is empty, ignored.");
3855 std::string when_prefix =
"$whenCondition";
3856 if (lhs.
name ==
"exp:Der") {
3860 }
else if (lhs.
size() > 0
3861 && lhs[0].
attribute<std::string>(
"name").rfind(when_prefix, 0) == 0) {
3863 std::string cond_name = lhs[0].
attribute<std::string>(
"name");
3865 uout() <<
"Reading event indicator: " << cond_name <<
" := " << beq << std::endl;
3867 cond_name = cond_name.substr(when_prefix.size());
3868 casadi_int ind = std::stoi(cond_name) - 1;
3870 casadi_assert(ind ==
when_.size(),
"Non-consequitive when conditions");
3876 if (
debug_)
uout() <<
"Reading equation: " << v.
name <<
" == " << beq << std::endl;
3880 casadi_error(
"Unknown dynamic equation type, got:" +
eq.name);
3882 }
catch (std::exception& e) {
3883 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
3890 uout() <<
"== Structure before importing initial equations ==" << std::endl;
3895 std::set<std::string> already_added;
3897 for (casadi_int i = 0; i < eqs.
size(); ++i) {
3900 std::string eq_name =
"initeq_" +
str(i);
3902 if (
eq.name ==
"equ:Equation") {
3904 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
3907 casadi_warning(eq_name +
" is empty, ignored.");
3916 && lhs[0].
attribute<std::string>(
"name").rfind(
"$whenCondition", 0) == 0) {
3921 if (lhs.
size() > 0 && lhs[0].
attribute<std::string>(
"name") ==
"$PRE") {
3922 casadi_warning(eq_name +
" defines a pre-variable, ignored");
3931 casadi_warning(eq_name +
" defines a tunable parameter, ignored")
3935 std::string eq_str =
str(v.
v) +
" == " +
str(beq);
3936 auto it = already_added.insert(eq_str);
3938 casadi_warning(eq_name +
" duplicate of previous equation " + eq_str +
", ignored")
3944 casadi_error(
"Unknown initial equation type, got:" +
eq.name);
3946 }
catch (std::exception& e) {
3947 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
3957 std::vector<MX> ret;
3958 ret.reserve(ind.size());
3959 for (
size_t i : ind) ret.push_back(
var(i));
3965 casadi_assert(it !=
varind_.end(),
"No such variable: \"" +
name +
"\".");
3971 casadi_assert(v.
is_symbolic(),
"Variable must be symbolic");
3976 "Variable \"" + v.
name() +
"\" has mismatching symbolic expression");
3982 std::vector<size_t> r(
name.size());
3983 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(
name[i]);
3988 std::vector<size_t> r(v.size());
3989 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(v[i]);
3998 std::vector<std::string> r(ind.size());
3999 for (
size_t i = 0; i < r.size(); ++i) r[i] =
name(ind[i]);
4004 casadi_assert(!
has_fun(f.
name()),
"Function '" + f.
name() +
"' already exists");
4010 const std::vector<std::string>& arg,
4011 const std::vector<std::string>& res,
const Dict& opts) {
4012 casadi_assert(!
has_fun(
name),
"Function '" +
name +
"' already exists");
4017 std::vector<MX> arg_ex, res_ex;
4018 for (
auto&& s : arg) arg_ex.push_back(
var(s));
4019 for (
auto&& s : res) {
4024 res_ex.push_back(wdef.at(v_ind));
4028 casadi_assert(v_ind <
size(
Category::W),
"Cannot find dependent '" + s +
"'");
4036 if (f.name()==
name)
return true;
4044 if (f.name()==
name)
return f;
4051 std::fill(v->value.begin(), v->value.end(),
nan);
4052 v->stringvalue = std::string();
4063 const std::vector<std::string>& name)
const {
4065 std::vector<double> r;
4068 std::vector<double> r1;
4069 for (
auto& n :
name) {
4071 r.insert(r.end(), r1.begin(), r1.end());
4081 const std::vector<double>& val) {
4082 if (
name.size() == val.size()) {
4085 }
else if (val.size() ==
size(a,
name)) {
4087 auto val_it = val.begin();
4088 for (
size_t k = 0; k <
name.size(); ++k) {
4090 auto val_next = val_it + v.
size(a);
4095 casadi_error(
"Cannot set attribute " +
to_string(a) +
": Argument is of length " +
4096 str(val.size()) +
", expected number of elements (" +
str(
size(a,
name))
4097 +
") or number of variables (" +
str(
name.size()) +
")");
4102 const std::string& name)
const {
4109 const std::vector<std::string>& name)
const {
4111 std::vector<std::string> r;
4115 for (
auto& n :
name) {
4123 const std::string& val) {
4128 const std::vector<std::string>& name,
const std::vector<std::string>& val) {
4129 casadi_assert(
name.size() == val.size(),
"Dimension mismatch");
4140 const std::vector<size_t>& iind)
const {
4142 std::vector<casadi_int> lookup(
n_variables(), -1);
4143 for (
size_t i = 0; i < iind.size(); ++i)
4144 lookup.at(iind[i]) = i;
4146 std::vector<casadi_int> row, col;
4148 for (casadi_int j = 0; j < oind.size(); ++j) {
4149 for (casadi_int d :
variable(oind[j]).dependencies) {
4150 casadi_int i = lookup.at(d);
4162 const std::vector<size_t>& iind)
const {
4164 std::vector<casadi_int> lookup(
n_variables(), -1);
4165 for (
size_t i = 0; i < iind.size(); ++i) lookup.at(iind[i]) = i;
4167 std::vector<bool> nonlin(iind.size(),
false);
4169 std::vector<casadi_int> nonlin_list;
4171 std::vector<casadi_int> row, col;
4173 for (casadi_int j = 0; j < oind.size(); ++j) {
4179 if (i >= 0 && !nonlin.at(i)) {
4181 nonlin_list.push_back(i);
4182 nonlin.at(i) =
true;
4187 for (casadi_int k1 : nonlin_list) {
4188 for (casadi_int k2 : nonlin_list) {
4194 if (col.size() > 2 * iind.size() * iind.size()) {
4200 for (casadi_int k : nonlin_list) nonlin[k] =
false;
4201 nonlin_list.clear();
4209 auto now = std::chrono::system_clock::now();
4210 std::time_t tt = std::chrono::system_clock::to_time_t(now);
4211 auto local_tm = *std::localtime(&tt);
4213 std::stringstream ss;
4214 ss << local_tm.tm_year + 1900 <<
'-';
4215 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mon + 1 <<
'-';
4216 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mday <<
'T';
4217 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_hour <<
':';
4218 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_min <<
':';
4219 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_sec <<
'Z';
4225 static bool initialized =
false;
4227 srand(::
time(
nullptr));
4231 const char h[] =
"0123456789abcdef";
4233 const size_t len = 32;
4235 std::vector<char> buf(len);
4236 for (
size_t i = 0; i < len; ++i)
4237 buf[i] = h[rand() % 16];
4238 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.
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.
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::vector< size_t > rate_
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.
std::vector< size_t > derivatives_
std::vector< MX > output(OutputCategory ind) const
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.
Variable & read_variable(const XmlNode &node, Attribute *att=0)
Read a variable.
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.
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)
std::vector< size_t > outputs_
void import_model_variables(const XmlNode &modvars)
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 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.
std::vector< MX > input(Category ind) const
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.
std::string unique_name(const std::string &prefix, bool allow_no_prefix=true) const
Find a unique name, with a specific prefix.
std::vector< size_t > event_indicators_
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.
void set_variability(size_t ind, Variability variability)
Set variability.
static std::string qualified_name(const XmlNode &nn, Attribute *att=0)
Get the qualified name.
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::vector< size_t > residuals_
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_
XmlNode generate_model_structure() const
Generate FMU ModelStructure.
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< std::string > export_fmu(const Dict &opts) const
Export instance into an FMU (experimental)
Variable & assign(const std::string &name, const MX &val)
Assignment inside when-equations or if-else equations.
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)
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)
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_
Sparsity hess_sparsity(const std::vector< size_t > &oind, const std::vector< size_t > &iind) const
Get what is known of the Hessian sparsity.
casadi_int number_of_event_indicators_
void disp(std::ostream &stream, bool more) const override
Print description.
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::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)
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.
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?
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.
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 change_option(const std::string &option_name, const GenericType &option_value)
Change option after object creation for debugging.
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?
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)
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< OutputCategory > output_categories()
std::vector< Category > input_categories()
std::string str(const T &v)
String representation, any type.
GenericType::Dict Dict
C++ equivalent of Python's dict or MATLAB's struct.
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 input_category(OutputCategory cat)
bool is_acyclic(Category cat)
OutputCategory dependent_definition(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)
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.
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.