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);
607 casadi_error(
"Could not open file '" +
filename +
"'.");
609 casadi_error(
"Could not open file '" +
filename +
"'. "
610 "Note that, since CasADi was compiled without WITH_GHC_FILESYSTEM=ON, "
611 "passing fmu files to DaeBuilder is unsupported. "
612 "You could manually unzip the FMU file and "
613 "pass the path to the unzipped directory instead.");
618 casadi_assert(
n_variables() == 0,
"Instance already has variables");
642 fmi_major_ >= 3 ?
"instantiationToken" :
"guid");
657 if (fmi_desc.
has_child(
"DefaultExperiment")) {
662 bool has_model_exchange =
false;
663 if (fmi_desc.
has_child(
"ModelExchange")) {
664 has_model_exchange =
true;
669 casadi_assert(fmi_desc.
has_child(
"ModelVariables"),
"Missing 'ModelVariables'");
673 if (fmi_desc.
has_child(
"ModelStructure")) {
681 if (fmi_desc.
has_child(
"equ:BindingEquations")) {
687 if (fmi_desc.
has_child(
"equ:InitialEquations")) {
693 if (fmi_desc.
has_child(
"equ:DynamicEquations")) {
699 casadi_assert(
symbolic_ || has_model_exchange,
700 "FMU must be of ModelExchange type or be symbolic (FMUX)");
704 const std::vector<std::string>& cfiles)
const {
708 std::string model_name =
name_;
712 r.
name =
"fmiBuildDescription";
713 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
716 source_file_set.
name =
"SourceFileSet";
717 for (
auto&& f : cfiles) {
719 source_file.
name =
"SourceFile";
721 source_file_set.
children.push_back(source_file);
725 bc.
name =
"BuildConfiguration";
727 bc.
children.push_back(source_file_set);
730 std::string xml_filename =
"buildDescription.xml";
733 build_description.
children.push_back(r);
736 xml_file.
dump(xml_filename, build_description);
744 std::string model_name =
name_;
748 std::string copyright;
753 r.
name =
"fmiModelDescription";
754 r.
set_attribute(
"fmiVersion", std::to_string(fmi_major) +
"." + std::to_string(fmi_minor));
756 r.
set_attribute(fmi_major >= 3 ?
"instantiationToken" :
"guid", guid);
760 if (!copyright.empty()) r.
set_attribute(
"copyright", copyright);
765 if (fmi_major < 3) r.
set_attribute(
"numberOfEventIndicators",
"0");
768 me.
name =
"ModelExchange";
776 std::string xml_filename =
"modelDescription.xml";
779 model_description.
children.push_back(r);
782 xml_file.
dump(xml_filename, model_description);
789 r.
name =
"ModelVariables";
791 r.
children.push_back(v->export_xml(*
this));
798 r.
name =
"ModelStructure";
812 c.
name =
"ContinuousStateDerivative";
821 c.
name =
"InitialUnknown";
830 c.
name =
"InitialUnknown";
839 c.
name =
"EventIndicator";
859 for (casadi_int k = dode_dxT.
colind(i); k < dode_dxT.
colind(i + 1); ++k) {
860 casadi_int j = dode_dxT.
row(k);
864 for (casadi_int k = dode_duT.
colind(i); k < dode_duT.
colind(i + 1); ++k) {
865 casadi_int j = dode_duT.
row(k);
870 for (std::string catname : {
"y",
"zero"}) {
874 for (casadi_int i = 0; i < oind.size(); ++i) {
880 for (casadi_int k = dy_dxT.
colind(i); k < dy_dxT.
colind(i + 1); ++k) {
881 casadi_int j = dy_dxT.
row(k);
885 for (casadi_int k = dy_duT.
colind(i); k < dy_duT.
colind(i + 1); ++k) {
886 casadi_int j = dy_duT.
row(k);
895 bool no_warning =
false;
896 for (
auto&& op : opts) {
897 if (op.first ==
"no_warning") {
898 no_warning = op.second;
902 if (!no_warning) casadi_warning(
"FMU generation is experimental and incomplete")
904 std::vector<std::string> ret;
908 std::string dae_filename =
name_;
909 Function dae = shared_from_this<DaeBuilder>().
create(dae_filename,
910 {
"t",
"x",
"p",
"u"}, {
"ode",
"y",
"zero"});
916 codegen_opts[
"with_header"] =
true;
923 ret.push_back(dae_filename +
".h");
928 ret.push_back(wrapper_filename);
938 std::stringstream ss;
943 if (!first) ss <<
", ";
953 std::stringstream ss;
958 if (!first) ss <<
", ";
961 ss << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << e;
968 std::vector<double> r;
970 for (
double s : v->start) r.push_back(s);
978 std::string wrapper_filename =
name_ +
"_wrap.c";
983 f <<
"#include <fmi3Functions.h>\n"
984 <<
"#include \"" <<
name_ <<
".h\"\n"
991 f <<
"#define SZ_MEM " <<
n_mem() <<
"\n";
994 size_t sz_arg, sz_res, sz_iw, sz_w;
995 gen.
sz_work(sz_arg, sz_res, sz_iw, sz_w);
996 f <<
"#define SZ_ARG " << sz_arg <<
"\n"
997 <<
"#define SZ_RES " << sz_res <<
"\n"
998 <<
"#define SZ_IW " << sz_iw <<
"\n"
999 <<
"#define SZ_W " << sz_w <<
"\n";
1002 f <<
"const size_t var_offset[N_VAR + 1] = {0";
1005 mem_ind += v->numel;
1006 f <<
", " << mem_ind;
1029 std::vector<size_t> xdot;
1031 f <<
"fmi3ValueReference xdot_vr[N_X] = " <<
generate(xdot) <<
";\n"
1035 f <<
"#define N_Y " <<
outputs_.size() <<
"\n"
1049 return wrapper_filename;
1058 }
catch (std::exception& e) {
1059 THROW_ERROR_NODE(
"read_variable", node, e.what());
1072 casadi_error(
"Cannot read attribute " +
to_string(att));
1079 const std::string& fullname = node.
name;
1081 if (fullname ==
"fun:If") {
1083 const XmlNode& cond = node[
"fun:Condition"];
1084 const XmlNode& then_stmt = node[
"fun:Statements"];
1085 const XmlNode& else_stmt = node[
"fun:Else"];
1087 casadi_assert(cond.
size() == 1,
"Only one condition in if expression supported");
1088 casadi_assert(then_stmt.
size() == 1,
"Only one then statement in if expression supported");
1089 casadi_assert(else_stmt.
size() == 1,
"Only one else statement in if expression supported");
1093 if (fullname.find(
"exp:")== std::string::npos) {
1094 casadi_error(
"DaeBuilderInternal::read_expr: unknown - expression is supposed to "
1095 "start with 'exp:' , got " + fullname);
1099 std::string
name = fullname.substr(4);
1106 }
else if (
name==
"Acos") {
1108 }
else if (
name==
"Asin") {
1110 }
else if (
name==
"Atan") {
1112 }
else if (
name==
"Cos") {
1114 }
else if (
name==
"Der") {
1116 }
else if (
name==
"Div") {
1118 }
else if (
name==
"Exp") {
1120 }
else if (
name==
"Identifier") {
1122 }
else if (
name==
"IntegerLiteral" ||
name==
"BooleanLiteral") {
1126 }
else if (
name==
"Instant") {
1130 }
else if (
name==
"Log") {
1132 }
else if (
name==
"Not") {
1134 }
else if (
name==
"LogLeq") {
1136 }
else if (
name==
"LogGeq") {
1138 }
else if (
name==
"LogLt") {
1140 }
else if (
name==
"LogGt") {
1142 }
else if (
name==
"Max") {
1144 }
else if (
name==
"Min") {
1146 }
else if (
name==
"Mul") {
1148 }
else if (
name==
"Neg") {
1150 }
else if (
name==
"NoEvent") {
1153 casadi_int n = node.
size();
1159 for (casadi_int i=n-3; i>=0; i -= 2) {
1164 }
else if (
name==
"Pow") {
1166 }
else if (
name==
"Pre") {
1167 casadi_warning(
"Ignoring pre attribute");
1169 }
else if (
name==
"RealLiteral") {
1173 }
else if (
name==
"Sin") {
1175 }
else if (
name==
"Sqrt") {
1177 }
else if (
name==
"StringLiteral") {
1178 casadi_error(node.
text);
1179 }
else if (
name==
"Sub") {
1181 }
else if (
name==
"Tan") {
1183 }
else if (
name==
"Time") {
1185 }
else if (
name==
"TimedVariable") {
1187 }
else if (
name==
"FunctionCall") {
1190 casadi_warning(
"Function call to '" + fname +
"' incomplete");
1192 const XmlNode& args = node[
"exp:Arguments"];
1193 std::vector<MX> farg(args.
size());
1194 for (casadi_int i = 0; i < args.
size(); ++i) {
1211 }
else if (
name==
"Array") {
1213 std::vector<MX> v(node.
size());
1214 for (casadi_int i = 0; i < v.size(); ++i) v[i] =
read_expr(node[i]);
1219 casadi_error(
"Unknown node: " +
name);
1220 }
catch (std::exception& e) {
1221 THROW_ERROR_NODE(
"read_expr", node, e.what());
1234 <<
"ny = " <<
outputs_.size() <<
", "
1243 stream << std::endl;
1246 if (!
fun_.empty()) {
1247 stream <<
"Functions:" << std::endl;
1249 stream <<
" " << f << std::endl;
1254 stream <<
"Model variables:" << std::endl;
1257 if (
size(cat) > 0) {
1264 if (
size(cat) > 0) {
1266 for (
size_t c :
indices(cat)) {
1268 stream <<
" " << v.
name;
1270 stream << std::endl;
1277 if (
size(cat) > 0) {
1280 for (
size_t k :
indices(cat)) {
1282 stream <<
" " << v.
name <<
": " <<
der(v.
v) << std::endl;
1289 stream <<
"Outputs (y):" << std::endl;
1292 stream <<
" " << v.
name <<
": " << v.
v << std::endl;
1297 stream <<
"Algebraic equations:" << std::endl;
1299 stream <<
" 0 == " <<
variable(k).
v << std::endl;
1303 if (!
init_.empty()) {
1304 stream <<
"Initial equations:" << std::endl;
1305 for (
size_t k :
init_) {
1307 stream <<
" " << v.
name;
1309 stream << std::endl;
1313 if (!
when_.empty()) {
1314 stream <<
"When equations:" << std::endl;
1315 for (
auto weq :
when_) {
1316 stream <<
" when " <<
variable(weq.first).
v <<
" < 0 : " << std::endl;
1317 for (
size_t eq : weq.second) {
1331 std::vector<size_t> new_order;
1332 for (
const MX& e : v) new_order.push_back(
find(e.name()));
1333 std::copy(new_order.begin(), new_order.end(),
indices(cat).begin());
1338 casadi_assert(z_order.size() ==
size(
Category::Z),
"Dimension mismatch");
1343 std::vector<size_t> new_z;
1344 new_z.reserve(z_order.size());
1345 for (
const std::string& s : z_order) {
1347 casadi_assert(old_z.at(i),
"Variable \"" + s +
"\" is not an algebraic variable.");
1355 return indices_.at(
static_cast<size_t>(cat));
1367 const std::vector<size_t>& v)
const {
1369 casadi_assert(ind.size() == v.size(),
"Cannot reorder " + n +
": "
1370 +
str(v.size()) +
" elements provided for " +
str(ind.size()) +
" components.");
1373 for (
size_t i : v) set.at(i) =
true;
1375 for (
size_t i : ind) casadi_assert(set.at(i),
"Cannot reorder " + n +
": "
1378 std::copy(v.begin(), v.end(), ind.begin());
1383 std::vector<MX> f_in, f_out, v;
1384 std::vector<std::string> f_in_name, f_out_name;
1391 f_in.push_back(vertcat(v));
1399 f_out.push_back(vertcat(v));
1404 Function f(
"prune_fcn", f_in, f_out, f_in_name, f_out_name);
1406 std::vector<bool> free_variables(
n_variables(),
false);
1407 for (
const std::string& s : f.
get_free()) {
1409 casadi_assert(it !=
varind_.end(),
"No such variable: \"" + s +
"\".");
1410 free_variables.at(it->second) =
true;
1426 for (
size_t i = 0; i < u.size(); ++i) {
1427 if (!free_variables.at(u.at(i))) u.at(nu++) = u.at(i);
1435 const std::string res_prefix =
"res__";
1437 std::vector<std::string> res, iv, iv_on_hold;
1440 std::set<std::string> iv_set;
1441 for (
auto& e : iv) iv_set.insert(e);
1442 for (
auto& e : iv_on_hold) iv_set.insert(e);
1469 std::vector<std::string>* iv, std::vector<std::string>* iv_on_hold)
const {
1471 if (res) res->clear();
1472 if (iv) iv->clear();
1473 if (iv_on_hold) iv_on_hold->clear();
1475 const std::string res_prefix =
"res__";
1477 std::vector<MX> r_hold, iv_hold;
1479 bool any_hold =
false;
1483 if (v->name.rfind(res_prefix, 0) == 0) {
1485 std::string iv_name, res_hold_name, iv_hold_name;
1488 size_t pos = res_prefix.size();
1490 size_t end = v->name.find(
"__", pos);
1491 if (end == std::string::npos) end = v->name.size();
1493 iv_name = v->name.substr(pos, end - pos);
1495 casadi_assert(
has(iv_name),
"No such variable: " + iv_name);
1497 if (end != v->name.size()) {
1500 end = v->name.find(
"__", pos);
1501 if (end == std::string::npos) end = v->name.size();
1502 res_hold_name = v->name.substr(pos, end - pos);
1504 casadi_assert(
has(res_hold_name),
"No such variable: " + res_hold_name);
1506 if (end != v->name.size()) {
1507 iv_hold_name = v->name.substr(end + 2);
1508 casadi_assert(
has(iv_hold_name),
"No such variable: " + iv_hold_name);
1511 }
catch (std::exception& e) {
1513 casadi_warning(
"Cannot process residual variable: " + v->name +
":" +
1514 std::string(e.what()));
1518 if (res_hold_name.empty()) {
1519 r_hold.push_back(
false);
1522 r_hold.push_back(
variable(res_hold_name).v);
1523 casadi_assert(r_hold.back().is_scalar(),
"Non-scalar hold variable for " + res_hold_name);
1525 if (res) res->push_back(v->name);
1527 if (iv_hold_name.empty()) {
1528 iv_hold.push_back(
false);
1531 iv_hold.push_back(
variable(iv_hold_name).v);
1532 casadi_assert(iv_hold.back().is_scalar(),
"Non-scalar hold variable for " + iv_hold_name);
1534 if (iv) iv->push_back(iv_name);
1541 casadi_error(
"not implemented");
1544 Function startfun_p = attribute_fun(
"startfun_p", {}, {
"start_p"});
1546 casadi_error(
"startfun has free variables: " +
str(startfun_p.
get_free()));
1548 DM p0 = startfun_p(std::vector<DM>{}).at(0);
1551 {vertcat(r_hold), vertcat(iv_hold)}, {
"p"}, {
"r_hold",
"iv_hold"});
1552 if (holdfun.has_free()) {
1553 casadi_error(
"holdfun has free variables: " +
str(holdfun.get_free()));
1556 std::vector<DM> hold0 = holdfun(std::vector<DM>{p0});
1557 std::vector<double> r_hold0 = hold0.at(0).nonzeros();
1558 std::vector<double> iv_hold0 = hold0.at(1).nonzeros();
1559 casadi_assert_dev(r_hold0.size() == res->size());
1560 casadi_assert_dev(iv_hold0.size() == iv->size());
1564 for (
size_t k = 0; k < res->size(); ++k) {
1565 if (!
static_cast<bool>(r_hold0.at(k))) {
1566 res->at(sz++) = res->at(k);
1573 for (
size_t k = 0; k < iv->size(); ++k) {
1574 if (!
static_cast<bool>(iv_hold0.at(k))) {
1575 if (iv) iv->at(sz++) = iv->at(k);
1577 if (iv_on_hold) iv_on_hold->push_back(iv->at(k));
1580 if (iv) iv->resize(sz);
1582 }
catch (std::exception& e) {
1584 casadi_warning(
"Failed to evaluate hold variables: " + std::string(e.what()));
1594 std::vector<std::string> r;
1611 const std::vector<casadi_int>& dimension,
const MX& expr) {
1613 casadi_assert(!
name.empty(),
"Name is empty string");
1615 casadi_assert(!
has(
name),
"Variable \"" +
name +
"\" already exists.");
1630 casadi_assert(
size(
Category::T) == 1,
"At most one time variable allowed");
1637 std::stringstream qn;
1638 bool first_part =
true;
1642 for (casadi_int i=0; i<nn.
size(); ++i) {
1644 std::string np = nn[i].
attribute<std::string>(
"name");
1647 if (np ==
"$START") {
1651 casadi_error(
"Ignoring attribute " + np);
1654 }
else if (np ==
"$PRE") {
1655 casadi_warning(
"$PRE attribute has not been implemented, ignoring");
1660 if (!first_part) qn <<
".";
1664 if (nn[i].
size()>0) {
1666 nn[i][
"exp:ArraySubscripts"][
"exp:IndexExpression"][
"exp:IntegerLiteral"].
get(&ind);
1667 qn <<
"[" << ind <<
"]";
1688 casadi_assert(
var.
is_column(),
"Input expression must be a vector");
1695 for (
MX& s : var_split) s =
der(s, may_allocate);
1700 std::vector<MX> dep = symvar(
var);
1702 std::vector<MX> dep_der;
1703 for (
size_t ind :
find(dep)) dep_der.push_back(
get_der(ind, may_allocate));
1706 std::vector<std::vector<MX>> r = {dep_der};
1707 r = forward(std::vector<MX>{
var}, dep, r);
1708 casadi_assert_dev(r.size() == 1);
1709 return vertcat(r.at(0));
1713 bool allow_no_prefix)
const {
1715 if (allow_no_prefix && !
has(prefix))
return prefix;
1718 while (
has(prefix +
str(i))) i++;
1720 return prefix +
str(i);
1731 casadi_assert(
is_acyclic(cat),
"Elimination not supported for category " +
to_string(cat));
1734 if (
size(cat) == 0)
return;
1742 if (!v->v.is_constant()) ex.push_back(v->v);
1745 std::vector<size_t> ind =
indices(cat);
1746 std::vector<MX> v =
var(ind);
1748 substitute_inplace(v, vdef, ex);
1750 auto it = ex.begin();
1752 if (!v->v.is_constant()) v->v = *it++;
1755 casadi_assert_dev(it == ex.end());
1757 for (
size_t k : ind) {
1771 std::vector<MX> new_w, new_wdef;
1772 Dict opts{{
"lift_shared", lift_shared}, {
"lift_calls", lift_calls},
1773 {
"prefix",
"w_"}, {
"suffix",
""}, {
"offset",
static_cast<casadi_int
>(
size(
Category::W))}};
1774 extract(ex, new_w, new_wdef, opts);
1776 for (
size_t i = 0; i < new_w.size(); ++i) {
1784 auto it = ex.begin();
1789 casadi_assert_dev(it == ex.end());
1814 casadi_error(
"No input category for " +
to_string(cat));
1821 to_string(ind) +
" is not an input category");
1827 std::vector<MX> ret(ind.size());
1828 for (casadi_int i=0; i<ind.size(); ++i) {
1829 ret[i] = vertcat(
input(ind[i]));
1848 std::vector<MX> ret;
1849 ret.reserve(
size(cat));
1855 for (
size_t v :
indices(cat)) {
1865 casadi_error(
"Missing derivative for " +
str(x.
name));
1880 std::vector<MX> ret(ind.size());
1881 for (casadi_int i=0; i<ind.size(); ++i) {
1882 ret[i] = vertcat(
output(ind[i]));
1892 casadi_assert(!
name.empty(),
"DaeBuilderInternal::add_lc: \"name\" is empty");
1893 for (std::string::const_iterator i=
name.begin(); i!=
name.end(); ++i) {
1894 casadi_assert(isalnum(*i),
1895 "DaeBuilderInternal::add_lc: \"name\" must be alphanumeric");
1899 casadi_assert(!f_out.empty(),
"DaeBuilderInternal::add_lc: Linear combination is empty");
1901 for (casadi_int i=0; i < f_out.size(); ++i) {
1902 auto oind =
static_cast<size_t>(to_enum<OutputCategory>(f_out[i]));
1903 casadi_assert(!in_use[oind],
"DaeBuilderInternal::add_lc: Duplicate expression " + f_out[i]);
1904 in_use[oind] =
true;
1907 std::vector<std::string>& ret1 =
lc_[
name];
1908 if (!ret1.empty()) casadi_warning(
"DaeBuilderInternal::add_lc: Overwriting " <<
name);
1913 const std::vector<std::string>& s_in,
1914 const std::vector<std::string>& s_out,
const Dict& opts,
bool sx,
bool lifted_calls)
const {
1916 bool with_underscore =
false;
1917 for (
auto s_io : {&s_in, &s_out}) {
1918 for (
const std::string& s : *s_io) {
1919 with_underscore = with_underscore || std::count(s.begin(), s.end(),
'_');
1925 casadi_assert(!lifted_calls,
"Lifting requires a symbolic representation");
1927 casadi_assert(!sx,
"SX expansion requires a symbolic representation");
1929 return fmu_fun(fname, s_in, s_out, opts);
1932 if (with_underscore) {
1933 std::vector<std::string> s_in_mod(s_in), s_out_mod(s_out);
1934 for (
auto s_io : {&s_in_mod, &s_out_mod}) {
1935 for (std::string& s : *s_io) std::replace(s.begin(), s.end(),
'_',
':');
1938 return create(fname, s_in_mod, s_out_mod, opts, sx, lifted_calls);
1941 bool elim_w =
false;
1945 for (
const std::string& s : s_in) {
1956 casadi_assert(!elim_w,
"Lifted calls cannot be used if dependent variables are eliminated");
1958 lifted_calls =
false;
1960 if (vdef_comp.is_output()) {
1962 lifted_calls =
true;
1968 std::string fname_nocalls = lifted_calls ? fname +
"_nocalls" : fname;
1971 if (!lifted_calls)
return ret;
1973 std::vector<MX> ret_in = ret.
mx_in();
1974 std::vector<MX> ret_out = ret(ret_in);
1978 std::vector<MX> v_in, lam_vdef_in;
1979 for (
size_t i = 0; i < s_in.size(); ++i) {
1981 v_in = vertsplit(ret_in[i], h_offsets);
1982 }
else if (ret.
name_in(i) ==
"lam_wdef") {
1983 lam_vdef_in = vertsplit(ret_in[i], h_offsets);
1987 std::map<MXNode*, size_t> v_map;
1994 std::map<MXNode*, CallIO> call_nodes;
1995 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
1997 const MX& vdefref = wdef.at(vdefind);
2001 MX c = vdefref.
dep(0);
2003 auto call_it = call_nodes.
find(c.
get());
2005 if (call_it == call_nodes.end()) {
2011 cio.
v.resize(c.
n_dep(), -1);
2012 cio.
arg.resize(cio.
v.size());
2013 for (casadi_int i = 0; i < cio.
v.size(); ++i) {
2015 cio.
arg.at(i) = c.
dep(i);
2017 size_t v_ind = v_map.at(c.
dep(i).
get());
2018 cio.
v.at(i) = v_ind;
2019 cio.
arg.at(i) = v_in.at(v_ind);
2024 cio.
res.resize(cio.
vdef.size());
2028 call_it = call_nodes.insert(std::make_pair(c.
get(), cio)).first;
2033 call_it->second.vdef.at(oind) = vdefind;
2034 call_it->second.res.at(oind) = v_in.at(vdefind);
2036 if (!lam_vdef_in.empty()) call_it->second.adj1_arg.at(oind) = lam_vdef_in.at(vdefind);
2040 for (
size_t i = 0; i < ret_out.size(); ++i) {
2041 if (ret.
name_out(i) ==
"jac_wdef_w") {
2047 for (
auto&& e :
lc_) {
2049 bool has_vdef =
false;
2050 for (
const std::string& r : e.second) {
2057 if (!has_vdef)
continue;
2059 for (
size_t i = 0; i < ret_out.size(); ++i) {
2060 if (ret.
name_out(i) ==
"hess_" + e.first +
"_w_w") {
2065 ret_out.at(i) += extra_hess_v_v;
2075 const std::vector<casadi_int>& h_offsets)
const {
2077 for (
auto call_it = call_nodes.begin(); call_it != call_nodes.end(); ++call_it) {
2078 call_it->second.calc_jac();
2081 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2083 std::vector<MX> vblocks, hblocks;
2085 std::map<size_t, MX> jac_brow;
2089 for (
size_t vdefind = 0; vdefind < wdef.size(); ++vdefind) {
2091 const MX& vdefref = wdef.at(vdefind);
2093 voffset_begin = voffset_end;
2094 voffset_end += vdefref.
numel();
2100 MX c = vdefref.
dep(0);
2102 auto call_it = call_nodes.
find(c.
get());
2103 casadi_assert_dev(call_it != call_nodes.end());
2106 for (casadi_int iind = 0; iind < call_it->second.arg.size(); ++iind) {
2107 size_t vind = call_it->second.v.at(iind);
2108 if (vind !=
size_t(-1)) {
2109 jac_brow[vind] = call_it->second.jac(oind, iind);
2113 if (voffset_last != voffset_begin) {
2114 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2118 casadi_int hoffset = 0;
2119 for (
auto e : jac_brow) {
2121 if (hoffset < h_offsets.at(e.first))
2122 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.at(e.first) - hoffset));
2124 hblocks.push_back(e.second);
2126 hoffset = h_offsets.at(e.first + 1);
2129 if (hoffset < h_offsets.back())
2130 hblocks.push_back(
MX(vdefref.
numel(), h_offsets.back() - hoffset));
2132 vblocks.push_back(horzcat(hblocks));
2134 voffset_last = voffset_end;
2138 if (voffset_last != voffset_end) {
2139 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2142 return vertcat(vblocks);
2146 const std::vector<casadi_int>& h_offsets)
const {
2148 for (
auto&& call_ref : call_nodes) call_ref.second.calc_hess();
2150 casadi_int voffset_begin = 0, voffset_end = 0, voffset_last = 0;
2152 std::vector<MX> vblocks, hblocks;
2154 std::map<size_t, MX> hess_brow;
2160 voffset_begin = voffset_end;
2161 voffset_end += vref.
numel();
2164 for (
auto&& call_ref : call_nodes) {
2166 for (
size_t iind1 = 0; iind1 < call_ref.second.v.size(); ++iind1) {
2167 if (call_ref.second.v.at(iind1) == vind1) {
2169 for (
size_t iind2 = 0; iind2 < call_ref.second.v.size(); ++iind2) {
2171 size_t vind2 = call_ref.second.v[iind2];
2172 if (vind2 ==
size_t(-1))
continue;
2174 MX H_contr = call_ref.second.hess(iind1, iind2);
2176 auto it = hess_brow.
find(vind2);
2177 if (it != hess_brow.end()) {
2178 it->second += H_contr;
2180 hess_brow[vind2] = H_contr;
2189 if (hess_brow.empty())
continue;
2191 if (voffset_last != voffset_begin) {
2192 vblocks.push_back(
MX(voffset_begin - voffset_last, h_offsets.back()));
2196 casadi_int hoffset = 0;
2197 for (
auto e : hess_brow) {
2199 if (hoffset < h_offsets.at(e.first))
2200 hblocks.push_back(
MX(vref.
numel(), h_offsets.at(e.first) - hoffset));
2202 hblocks.push_back(e.second);
2204 hoffset = h_offsets.at(e.first + 1);
2207 if (hoffset < h_offsets.back())
2208 hblocks.push_back(
MX(vref.
numel(), h_offsets.back() - hoffset));
2210 vblocks.push_back(horzcat(hblocks));
2212 voffset_last = voffset_end;
2215 if (voffset_last != voffset_end) {
2216 vblocks.push_back(
MX(voffset_end - voffset_last, h_offsets.back()));
2219 return vertcat(vblocks);
2223 for (
bool sx : {
false,
true}) {
2224 for (
bool elim_w : {
false,
true}) {
2225 for (
bool lifted_calls : {
false,
true}) {
2235 casadi_assert(
symbolic_,
"DaeBuilder oracle only available if symbolic representation");
2240 if (
oracle_[
false][elim_w][lifted_calls].is_null()) {
2242 std::vector<MX> f_in, f_out, v;
2243 std::vector<std::string> f_in_name, f_out_name;
2245 casadi_int wdef_ind = -1;
2247 casadi_assert(!(elim_w && lifted_calls),
"Incompatible options");
2249 bool subst_v =
false;
2254 if (!v.empty()) subst_v =
true;
2257 f_in.push_back(
MX(0, 1));
2259 f_in.push_back(vertcat(v));
2270 f_out.push_back(
MX(0, 1));
2273 f_out.push_back(vertcat(v));
2282 }
else if (lifted_calls && wdef_ind >= 0) {
2286 for (
MX& wdefref : wdef) {
2287 if (wdefref.is_output()) wdefref =
MX::zeros(wdefref.sparsity());
2290 f_out.at(wdef_ind) = vertcat(wdef);
2293 oracle_[
false][elim_w][lifted_calls]
2294 =
Function(
"mx_oracle", f_in, f_out, f_in_name, f_out_name);
2297 if (!sx)
return oracle_[
false][elim_w][lifted_calls];
2307 for (casadi_int i = 0; i < this->
f.
n_in(); ++i) {
2308 casadi_assert(this->
f.
size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2310 for (casadi_int i = 0; i < this->
f.
n_out(); ++i) {
2311 casadi_assert(this->
f.
size_out(i) == this->res.at(i).size(),
"Call output not provided");
2318 std::vector<MX> call_in = this->
arg;
2319 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2326 for (casadi_int i = 0; i < this->f.n_in(); ++i) {
2327 casadi_assert(this->f.size_in(i) == this->arg.at(i).size(),
"Call input not provided");
2329 casadi_assert(this->adj1_arg.size() == this->res.size(),
"Input 'lam_vdef' not provided");
2330 for (casadi_int i = 0; i < this->f.n_out(); ++i) {
2331 casadi_assert(this->f.size_out(i) == this->res.at(i).size(),
"Call output not provided");
2332 casadi_assert(this->adj1_arg.at(i).size() == this->res.at(i).size(),
2333 "Call adjoint seed not provided");
2336 if (!this->jac_res.empty())
2337 casadi_warning(
"Jacobian blocks currently not reused for gradient calculation");
2340 this->adj1_f = this->f.reverse(1);
2343 std::vector<MX> call_in = this->arg;
2344 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2345 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2347 this->adj1_res = this->adj1_f(call_in);
2352 if (this->adj1_f.is_null()) calc_grad();
2355 this->H = this->adj1_f.jacobian();
2358 std::vector<MX> call_in = this->arg;
2359 call_in.insert(call_in.end(), this->res.begin(), this->res.end());
2360 call_in.insert(call_in.end(), this->adj1_arg.begin(), this->adj1_arg.end());
2361 call_in.insert(call_in.end(), this->adj1_res.begin(), this->adj1_res.end());
2363 this->hess_res = this->H(call_in);
2368 casadi_int ind = iind + oind * this->arg.
size();
2370 return this->jac_res.at(ind);
2375 casadi_int ind = iind1 + iind1 * this->adj1_arg.
size();
2377 return this->hess_res.at(ind);
2382 Function vfcn(
"vfcn", {vertcat(v)}, {vertcat(vdef)}, {
"v"}, {
"vdef"},
2383 Dict{{
"allow_free",
true}});
2385 bool any_vector_valued =
false;
2386 for (
const MX& v_i : v) {
2387 casadi_assert(!v_i.is_empty(),
"Cannot have zero-dimension dependent variables");
2388 if (!v_i.is_scalar()) {
2389 any_vector_valued =
true;
2394 if (any_vector_valued) {
2396 std::vector<MX> vfcn_in(v), vfcn_arg(v);
2397 for (
size_t i = 0; i < v.size(); ++i) {
2398 if (!v.at(i).is_scalar()) {
2399 vfcn_in.at(i) =
MX::sym(v.at(i).name());
2400 vfcn_arg.at(i) = repmat(vfcn_in.at(i), v.at(i).size1());
2404 std::vector<MX> vfcn_out = vfcn(vertcat(vfcn_arg));
2405 vfcn_out = vertsplit(vfcn_out.at(0), offset(v));
2407 for (
size_t i = 0; i < v.size(); ++i) {
2408 if (!v.at(i).is_scalar()) {
2409 vfcn_out.at(i) =
dot(vfcn_out.at(i), vfcn_out.at(i));
2413 vfcn =
Function(vfcn.name(), {vertcat(vfcn_in)}, {vertcat(vfcn_out)},
2414 vfcn.name_in(), vfcn.name_out(), {{
"allow_free", true}});
2417 Sparsity Jv = vfcn.jac_sparsity(0, 0);
2423 std::vector<casadi_int> rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock;
2424 (void)Jv.
btf(rowperm, colperm, rowblock, colblock, coarse_rowblock, coarse_colblock);
2426 std::vector<MX> tmp(v.size());
2427 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = v.at(colperm.at(k));
2428 std::copy(tmp.begin(), tmp.end(), v.begin());
2430 for (
size_t k = 0; k < v.size(); ++k) tmp[k] = vdef.at(rowperm.at(k));
2431 std::copy(tmp.begin(), tmp.end(), vdef.begin());
2435 const std::vector<std::string>& s_in,
2436 const std::vector<std::string>& s_out)
const {
2438 bool calc_d =
false, calc_w =
false;
2440 std::vector<Category> v_out;
2441 v_out.reserve(v_out.size());
2442 for (
const std::string& s : s_out) {
2449 casadi_error(
"Can only calculate d and/or w");
2454 casadi_assert(calc_d || calc_w,
"Nothing to calculate");
2456 std::vector<Category> v_in;
2457 v_in.reserve(v_in.size());
2458 for (
const std::string& s : s_in) {
2460 if (calc_d && e ==
Category::D) casadi_error(
"'d' cannot be both input and output");
2461 if (calc_w && e ==
Category::W) casadi_error(
"'w' cannot be both input and output");
2465 std::vector<MX> f_in;
2466 f_in.reserve(s_in.size());
2469 std::vector<MX> f_out;
2470 f_out.reserve(s_out.size());
2471 for (
Category v : v_out) f_out.push_back(vertcat(
input(v)));
2473 std::vector<MX> dw, dwdef;
2476 dw.insert(dw.end(), d.begin(), d.end());
2478 dwdef.insert(dwdef.end(), ddef.begin(), ddef.end());
2482 dw.insert(dw.end(), w.begin(), w.end());
2484 dwdef.insert(dwdef.end(), wdef.begin(), wdef.end());
2487 substitute_inplace(dw, dwdef, f_out);
2489 return Function(fname, f_in, f_out, s_in, s_out);
2493 bool dummy_index_input)
const {
2496 casadi_assert(index >= 0 && index <
when_.size(),
"Illegal event index");
2510 std::vector<MX> when_lhs, when_rhs;
2511 for (
size_t eq :
when_.at(index).second) {
2518 std::vector<MX> ret_out = {ret_in[
DYN_X], ret_in[
DYN_Z]};
2530 if (dummy_index_input) {
2532 ret_in.insert(ret_in.begin(),
MX());
2548 std::vector<Function> f_all;
2549 for (casadi_int i = 0; i <
when_.size(); ++i) {
2563 const std::vector<std::string>& name_in,
2564 const std::vector<std::string>& name_out,
2565 const Dict& opts)
const {
2567 Dict::const_iterator it;
2569 std::vector<std::string> scheme_in;
2570 bool has_in =
false;
2571 if ((it = opts.find(
"scheme_in")) != opts.end()) {
2573 scheme_in = it->second;
2574 }
catch (std::exception& e) {
2575 casadi_error(std::string(
"Cannot read 'scheme_in': ") + e.what());
2580 std::vector<std::string> scheme_out;
2581 bool has_out =
false;
2582 if ((it = opts.find(
"scheme_out")) != opts.end()) {
2584 scheme_out = it->second;
2586 }
catch (std::exception& e) {
2587 casadi_error(std::string(
"Cannot read 'scheme_out': ") + e.what());
2591 if (!has_in || !has_out) {
2595 std::map<std::string, std::vector<size_t>> scheme;
2596 if ((it = opts.find(
"scheme")) != opts.end()) {
2599 Dict scheme_dict = it->second;
2601 for (
auto&& e : scheme_dict) {
2602 std::vector<std::string> v = e.second;
2603 scheme[e.first] =
find(v);
2605 }
catch (std::exception& e) {
2606 casadi_error(std::string(
"Cannot read 'scheme': ") + e.what());
2610 for (
auto&& s :
dyn_in()) scheme[s] = std::vector<size_t>();
2611 for (
auto&& s :
dyn_out()) scheme[s] = std::vector<size_t>();
2619 for (
size_t& i : scheme[
"ode"]) i =
variable(i).
der;
2625 std::vector<std::string> aux;
2626 if ((it = opts.find(
"aux")) != opts.end()) {
2629 }
catch (std::exception& e) {
2630 casadi_error(std::string(
"Cannot read 'aux': ") + e.what());
2635 scheme_in, scheme_out, scheme, aux);
2643 std::vector<MX> f_out;
2645 std::vector<std::string> f_out_name;
2648 std::vector<MX> v =
output(cat);
2650 f_out.push_back(vertcat(v));
2655 return Function(
"all_eq", {}, f_out, {}, f_out_name, {{
"allow_free",
true}});
2659 casadi_assert(
has_t(),
"No explicit time variable");
2668 std::vector<MX> ret;
2675 std::vector<MX> ret;
2676 ret.reserve(
init_.size());
2677 for (
size_t ind :
init_) {
2684 std::vector<MX> ret;
2685 ret.reserve(
init_.size());
2686 for (
size_t ind :
init_) {
2744 std::string
description, type, initial, unit, display_unit;
2745 std::vector<casadi_int> dimension = {1};
2747 std::vector<double> start;
2749 for (
auto&& op : opts) {
2750 if (op.first==
"dimension") {
2751 dimension = op.second.to_int_vector();
2752 }
else if (op.first==
"description") {
2754 }
else if (op.first==
"unit") {
2755 unit = op.second.to_string();
2756 }
else if (op.first==
"display_unit") {
2757 display_unit = op.second.to_string();
2758 }
else if (op.first==
"min") {
2759 min = op.second.to_double();
2760 }
else if (op.first==
"max") {
2761 max = op.second.to_double();
2762 }
else if (op.first==
"nominal") {
2763 nominal = op.second.to_double();
2764 }
else if (op.first==
"start") {
2766 start.resize(1, op.second.to_double());
2768 start = op.second.to_double_vector();
2770 }
else if (op.first==
"type") {
2771 type = op.second.to_string();
2772 }
else if (op.first==
"initial") {
2773 initial = op.second.to_string();
2775 casadi_error(
"No such option: " + op.first);
2781 if (!type.empty()) v.
type = to_enum<Type>(type);
2784 if (!start.empty()) v.
start = start;
2785 if (!initial.empty()) v.
initial = to_enum<Initial>(initial);
2786 if (!unit.empty()) v.
unit = unit;
2787 if (!display_unit.empty()) v.
display_unit = display_unit;
2800 casadi_error(
"'parameter' causality requires 'fixed' or 'tunable' variability");
2805 "'calculatedParameter' causality requires 'fixed' or 'tunable' variability");
2812 "'input' causality requires 'continuous' or 'discrete' variability");
2827 casadi_error(
"'output' causality requires 'constant', 'continuous' or "
2828 "'discrete' variability");
2846 casadi_error(
"'output' causality requires 'constant', 'fixed', 'tunable', 'discrete' or "
2847 "'continuous' variability");
2852 casadi_assert(!
has_t(),
"'t' already defined");
2854 "Independent variable must be continuous");
2869 if (opts.find(
"type") != opts.end()) {
2870 type = to_enum<Type>(opts.at(
"type").to_string());
2901 size_t loc = v.size();
2902 for (
size_t i = 0; i < v.size(); ++i) {
2908 v.insert(v.begin() + loc, ind);
2912 for (
auto it = v.begin(); it != v.end(); ++it) {
2918 casadi_error(
"Variable not found");
2939 casadi_error(
"Cannot change causality of " + v.
name +
" which is of category '"
2970 casadi_error(
"The variability of " + v.
name +
", which is of category 'u', can only be "
2971 "changed to 'fixed' (for no category) or 'tunable' (for category 'p')");
2985 casadi_error(
"The variability of " + v.
name +
", which is of category 'p', can only be "
2986 "changed to 'continuous' (for category 'u') or 'fixed' (for no category)");
3000 casadi_error(
"The variability of " + v.
name +
", which is of type 'c', can only be "
3001 "changed to 'continuous' (for category 'u') or 'tunable' (for category 'p')");
3005 casadi_error(
"Cannot change variability of " + v.
name +
", which is of category '"
3054 casadi_error(
"Cannot change category of " + v.
name +
" from '"
3060 for (
auto&& op : opts) {
3061 casadi_error(
"No such option: " + op.first);
3064 casadi_assert(lhs.
is_column(),
"Left-hand-side must be a column vector");
3065 casadi_assert(rhs.
is_column(),
"Right-hand-side must be a column vector");
3067 if (!lhs.
is_dense())
return eq(densify(lhs), rhs, opts);
3068 if (!rhs.
is_dense())
return eq(lhs, densify(rhs), opts);
3073 return eq(repmat(lhs, rhs.
size1()), rhs, opts);
3074 }
else if (lhs.
size1() > 1 && rhs.
size1() == 1) {
3075 return eq(lhs, repmat(rhs, lhs.
size1()), opts);
3077 casadi_error(
"Mismatched dimensions: " +
str(lhs.
size1()) +
" vs " +
str(rhs.
size1()));
3081 std::vector<size_t> rhs_vars =
find(symvar(rhs));
3085 for (
size_t rhs : rhs_vars) {
3091 casadi_assert(x.
der == v.
index,
"Cannot handle right-hand-side variable: " + v.
name);
3095 {{
"dimension", {x.dimension}}});
3097 eq(x.get_der(*
this), der_x.v,
Dict());
3101 if (lhs.is_valid_input()) {
3103 if (lhs.is_symbolic()) {
3109 return eq(
MX::zeros(lhs.sparsity()), lhs - rhs, opts);
3112 Variable& beq = assign(v.
name, rhs);
3120 casadi_assert(x.der == v.
index,
"Cannot handle left-hand-side: " +
str(lhs));
3129 Variable& def_x = add(unique_name(
"def_" + x.name,
true),
3131 {{
"dimension", {x.dimension}}});
3133 def_x.bind = x.bind;
3140 x.v - def_x.v, {{
"dimension", x.dimension}});
3142 residuals_.push_back(alg.index);
3144 casadi_error(
"Unexpected category for " + x.name +
": " +
to_string(x.category));
3150 casadi_error(
"Cannot handle left-hand-side: " +
str(lhs) +
" of category '"
3155 auto lhs_split = lhs.primitives();
3156 std::vector<MX> rhs_split = lhs.split_primitives(rhs);
3158 for (
size_t k = 0; k < lhs_split.size(); ++k) {
3159 eq(lhs_split.at(k), rhs_split.at(k), opts);
3166 lhs - rhs, {{
"dimension", std::vector<casadi_int>{lhs.size1()}}});
3168 residuals_.push_back(alg.index);
3171 for (
size_t rhs : rhs_vars) {
3183 for (
auto&& op : opts) {
3184 casadi_error(
"No such option: " + op.first);
3189 zero = cond.
dep(0) - cond.
dep(1);
3191 casadi_error(
"Only strict inequality in zero-crossing conditions permitted, got: "
3194 casadi_error(
"Cannot parse zero-crossing condition: " +
str(cond));
3202 std::vector<MX> all_lhs, all_rhs;
3203 std::vector<size_t> all_eqs;
3204 for (
auto&&
eq : eqs) {
3208 all_rhs.push_back(ee.
v);
3209 all_eqs.push_back(ee.
index);
3211 when_.push_back(std::make_pair(e.
index, all_eqs));
3246 if (old_loc ==
init_.end()) casadi_error(
"Corrupted list of initial equations");
3247 init_.erase(old_loc);
3255 casadi_error(
"Initial equation for " +
name +
" has already been set");
3262 template<
typename T>
3265 size_t sz = n.
size();
3269 for (
size_t i = 0; i < sz; ++i) {
3270 r.push_back(
T(n[i]));
3285 fmi_major_ >= 3 ?
"providesDirectionalDerivatives" :
"providesDirectionalDerivative",
false);
3287 = n.
attribute<
bool>(
"providesAdjointDerivatives",
false);
3290 n.
attribute<
bool>(
"canBeInstantiatedOnlyOncePerProcess",
false);
3293 for (
const XmlNode& sf : n[
"SourceFiles"].children) {
3301 std::vector<std::pair<std::string, std::string>> fmi1_der;
3304 for (casadi_int i = 0; i < modvars.
size(); ++i) {
3306 const XmlNode& vnode = modvars[i];
3313 std::string variable_category = vnode[
"VariableCategory"].
text;
3314 if (variable_category ==
"derivative") {
3316 std::string x_name = vnode[
"QualifiedName"][0].
attribute<std::string>(
"name");
3317 fmi1_der.push_back(std::make_pair(x_name,
name));
3322 if (
fmi_major_ == 1 &&
name.rfind(
"$whenCondition", 0) == 0)
continue;
3326 casadi_warning(
"Duplicate variable '" +
name +
"' ignored");
3333 casadi_int derivative = -1;
3336 type = to_enum<Type>(vnode.
name);
3341 opts[
"unit"] = vnode.
attribute<std::string>(
"unit",
"");
3342 opts[
"display_unit"] = vnode.
attribute<std::string>(
"displayUnit",
"");
3345 opts[
"nominal"] = vnode.
attribute<
double>(
"nominal", 1.);
3346 opts[
"start"] = vnode.
attribute<
double>(
"start", 0.);
3347 derivative = vnode.
attribute<casadi_int>(
"derivative", -1);
3368 const XmlNode& props = vnode[
"Real"];
3369 opts[
"unit"] = props.
attribute<std::string>(
"unit",
"");
3370 opts[
"display_unit"] = props.
attribute<std::string>(
"displayUnit",
"");
3373 opts[
"nominal"] = props.
attribute<
double>(
"nominal", 1.);
3374 opts[
"start"] = props.
attribute<
double>(
"start", 0.);
3375 derivative = props.
attribute<casadi_int>(
"derivative", -1);
3376 }
else if (vnode.
has_child(
"Integer")) {
3378 const XmlNode& props = vnode[
"Integer"];
3381 }
else if (vnode.
has_child(
"Boolean")) {
3385 }
else if (vnode.
has_child(
"Enumeration")) {
3388 casadi_warning(
"Unknown type for " +
name);
3396 std::string causality_str = vnode.
attribute<std::string>(
"causality",
"local");
3397 if (
fmi_major_ == 1 && causality_str ==
"internal") causality_str =
"local";
3401 std::string variability_str = vnode.
attribute<std::string>(
"variability",
3403 if (
fmi_major_ == 1 && variability_str ==
"parameter") variability_str =
"fixed";
3408 std::string initial_str = vnode.
attribute<std::string>(
"initial",
"");
3409 if (!initial_str.empty()) {
3413 "initial = '" + initial_str +
"' is not allowed per the FMI specification.");
3414 initial = to_enum<Initial>(initial_str);
3445 var.value_reference =
static_cast<unsigned int>(vnode.
attribute<casadi_int>(
"valueReference"));
3447 var.der_of = derivative;
3467 for (
auto& p : fmi1_der) {
3481 "Default 'dependencies' not implemented");
3483 std::vector<casadi_int> r = n.
attribute<std::vector<casadi_int>>(
"dependencies", {});
3485 for (casadi_int& e : r) {
3488 e =
vrmap_.at(
static_cast<unsigned int>(e));
3499 const XmlNode& n,
size_t ndep) {
3506 auto dk_str = n.
attribute<std::vector<std::string>>(
"dependenciesKind");
3508 casadi_assert(dk_str.size() == ndep,
"Mismatching 'dependenciesKind'");
3510 std::vector<DependenciesKind> r(ndep);
3511 for (
size_t i = 0; i < ndep; ++i) {
3512 r[i] = to_enum<DependenciesKind>(dk_str[i]);
3534 for (casadi_int i = 0; i < n.
size(); ++i) {
3537 if (e.
name ==
"Output") {
3547 }
else if (e.
name ==
"ContinuousStateDerivative") {
3553 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
3563 }
else if (e.
name ==
"ClockedState") {
3565 casadi_message(
"ClockedState not implemented, ignoring");
3566 }
else if (e.
name ==
"InitialUnknown") {
3571 }
else if (e.
name ==
"EventIndicator") {
3577 casadi_error(
"Unknown ModelStructure element: " + e.
name);
3583 for (
auto& e : n[
"Derivatives"].children) {
3585 derivatives_.push_back(e.attribute<casadi_int>(
"index", 0) - 1);
3589 casadi_assert(v.
parent >= 0,
"Error processing derivative info for " + v.
name);
3599 std::vector<casadi_int> default_dependencies;
3600 default_dependencies.insert(default_dependencies.begin(),
3602 default_dependencies.insert(default_dependencies.begin(),
3604 default_dependencies.insert(default_dependencies.begin(),
3606 std::sort(default_dependencies.begin(), default_dependencies.end());
3615 std::vector<casadi_int> additional_dependencies;
3616 additional_dependencies.insert(additional_dependencies.begin(),
3618 std::vector<DependenciesKind> additional_dependencies_kind(
size(
Category::P),
3624 for (
auto& e : n[
"Derivatives"].children) {
3625 casadi_int index = e.attribute<casadi_int>(
"index", 0)-1;
3631 if (e.has_attribute(
"dependencies")) {
3634 v.dependencies = default_dependencies;
3638 v.dependencies.insert(v.dependencies.end(),
3639 additional_dependencies.begin(), additional_dependencies.end());
3640 v.dependenciesKind.insert(v.dependenciesKind.end(),
3641 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
3649 for (
auto& e : n[
"Outputs"].children) {
3651 outputs_.push_back(e.attribute<casadi_int>(
"index", 0) - 1);
3655 if (e.has_attribute(
"dependencies")) {
3663 additional_dependencies.begin(), additional_dependencies.end());
3665 additional_dependencies_kind.begin(), additional_dependencies_kind.end());
3673 default_dependencies.clear();
3674 default_dependencies.insert(default_dependencies.begin(),
3677 if (v->initial ==
Initial::EXACT) default_dependencies.push_back(v->index);
3679 default_dependencies.insert(default_dependencies.begin(),
3681 std::sort(default_dependencies.begin(), default_dependencies.end());
3685 for (
auto& e : n[
"InitialUnknowns"].children) {
3689 std::vector<casadi_int> dependencies;
3691 if (e.has_attribute(
"dependencies")) {
3694 dependencies = default_dependencies;
3697 dependencies.insert(dependencies.end(),
3698 additional_dependencies.begin(), additional_dependencies.end());
3709 uout() <<
"== Structure before importing binding equations ==" << std::endl;
3714 for (casadi_int i = 0; i < eqs.
size(); ++i) {
3716 std::string eq_name =
"beq_" +
str(i);
3726 casadi_assert(
eq[1].
size() == 0,
"Not implemented");
3729 casadi_warning(
var.
name +
" has binding equation without type specifier: " +
str(val));
3735 }
catch (std::exception& e) {
3736 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
3743 uout() <<
"== Structure before importing dynamic equations ==" << std::endl;
3754 for (casadi_int i = 0; i < eqs.
size(); ++i) {
3756 std::string eq_name =
"dyneq_" +
str(i);
3759 if (
eq.name ==
"equ:When") {
3761 const XmlNode& n_cond =
eq[
"equ:Condition"];
3762 const XmlNode& n_equ =
eq[
"equ:Equation"];
3764 casadi_assert(n_cond.
size() == 1,
"Only one condition in when equation supported");
3765 casadi_assert(n_equ.
size() == 1,
"Only one equation in when equation supported");
3767 std::string cond_name = n_cond[0][0].
attribute<std::string>(
"name");
3768 std::string when_prefix =
"$whenCondition";
3769 cond_name = cond_name.substr(when_prefix.size());
3770 casadi_int ind = std::stoi(cond_name) - 1;
3774 if (n_equ[0].
name ==
"exp:Sub") {
3779 }
else if (n_equ[0].
name ==
"exp:Reinit") {
3786 casadi_error(n_equ[0].
name +
" in when equation not supported");
3788 }
else if (
eq.name ==
"equ:Equation") {
3790 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
3793 casadi_warning(eq_name +
" is empty, ignored.");
3802 std::string when_prefix =
"$whenCondition";
3803 if (lhs.
name ==
"exp:Der") {
3807 }
else if (lhs.
size() > 0
3808 && lhs[0].
attribute<std::string>(
"name").rfind(when_prefix, 0) == 0) {
3810 std::string cond_name = lhs[0].
attribute<std::string>(
"name");
3812 uout() <<
"Reading event indicator: " << cond_name <<
" := " << beq << std::endl;
3814 cond_name = cond_name.substr(when_prefix.size());
3815 casadi_int ind = std::stoi(cond_name) - 1;
3817 casadi_assert(ind ==
when_.size(),
"Non-consequitive when conditions");
3823 if (
debug_)
uout() <<
"Reading equation: " << v.
name <<
" == " << beq << std::endl;
3827 casadi_error(
"Unknown dynamic equation type, got:" +
eq.name);
3829 }
catch (std::exception& e) {
3830 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
3837 uout() <<
"== Structure before importing initial equations ==" << std::endl;
3842 std::set<std::string> already_added;
3844 for (casadi_int i = 0; i < eqs.
size(); ++i) {
3847 std::string eq_name =
"initeq_" +
str(i);
3849 if (
eq.name ==
"equ:Equation") {
3851 casadi_assert_dev(
eq.size() == 1 &&
eq[0].name ==
"exp:Sub");
3854 casadi_warning(eq_name +
" is empty, ignored.");
3863 && lhs[0].
attribute<std::string>(
"name").rfind(
"$whenCondition", 0) == 0) {
3868 if (lhs.
size() > 0 && lhs[0].
attribute<std::string>(
"name") ==
"$PRE") {
3869 casadi_warning(eq_name +
" defines a pre-variable, ignored");
3878 casadi_warning(eq_name +
" defines a tunable parameter, ignored")
3882 std::string eq_str =
str(v.
v) +
" == " +
str(beq);
3883 auto it = already_added.insert(eq_str);
3885 casadi_warning(eq_name +
" duplicate of previous equation " + eq_str +
", ignored")
3891 casadi_error(
"Unknown initial equation type, got:" +
eq.name);
3893 }
catch (std::exception& e) {
3894 casadi_error(
"Failed to read " + eq_name +
":" +
str(e.what()));
3904 std::vector<MX> ret;
3905 ret.reserve(ind.size());
3906 for (
size_t i : ind) ret.push_back(
var(i));
3912 casadi_assert(it !=
varind_.end(),
"No such variable: \"" +
name +
"\".");
3918 casadi_assert(v.
is_symbolic(),
"Variable must be symbolic");
3923 "Variable \"" + v.
name() +
"\" has mismatching symbolic expression");
3929 std::vector<size_t> r(
name.size());
3930 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(
name[i]);
3935 std::vector<size_t> r(v.size());
3936 for (
size_t i = 0; i < r.size(); ++i) r[i] =
find(v[i]);
3945 std::vector<std::string> r(ind.size());
3946 for (
size_t i = 0; i < r.size(); ++i) r[i] =
name(ind[i]);
3951 casadi_assert(!
has_fun(f.
name()),
"Function '" + f.
name() +
"' already exists");
3957 const std::vector<std::string>& arg,
3958 const std::vector<std::string>& res,
const Dict& opts) {
3959 casadi_assert(!
has_fun(
name),
"Function '" +
name +
"' already exists");
3964 std::vector<MX> arg_ex, res_ex;
3965 for (
auto&& s : arg) arg_ex.push_back(
var(s));
3966 for (
auto&& s : res) {
3971 res_ex.push_back(wdef.at(v_ind));
3975 casadi_assert(v_ind <
size(
Category::W),
"Cannot find dependent '" + s +
"'");
3983 if (f.name()==
name)
return true;
3991 if (f.name()==
name)
return f;
3998 std::fill(v->value.begin(), v->value.end(),
nan);
3999 v->stringvalue = std::string();
4010 const std::vector<std::string>& name)
const {
4012 std::vector<double> r;
4015 std::vector<double> r1;
4016 for (
auto& n :
name) {
4018 r.insert(r.end(), r1.begin(), r1.end());
4028 const std::vector<double>& val) {
4029 if (
name.size() == val.size()) {
4032 }
else if (val.size() ==
size(a,
name)) {
4034 auto val_it = val.begin();
4035 for (
size_t k = 0; k <
name.size(); ++k) {
4037 auto val_next = val_it + v.
size(a);
4042 casadi_error(
"Cannot set attribute " +
to_string(a) +
": Argument is of length " +
4043 str(val.size()) +
", expected number of elements (" +
str(
size(a,
name))
4044 +
") or number of variables (" +
str(
name.size()) +
")");
4049 const std::string& name)
const {
4056 const std::vector<std::string>& name)
const {
4058 std::vector<std::string> r;
4062 for (
auto& n :
name) {
4070 const std::string& val) {
4075 const std::vector<std::string>& name,
const std::vector<std::string>& val) {
4076 casadi_assert(
name.size() == val.size(),
"Dimension mismatch");
4087 const std::vector<size_t>& iind)
const {
4089 std::vector<casadi_int> lookup(
n_variables(), -1);
4090 for (
size_t i = 0; i < iind.size(); ++i)
4091 lookup.at(iind[i]) = i;
4093 std::vector<casadi_int> row, col;
4095 for (casadi_int j = 0; j < oind.size(); ++j) {
4096 for (casadi_int d :
variable(oind[j]).dependencies) {
4097 casadi_int i = lookup.at(d);
4109 const std::vector<size_t>& iind)
const {
4111 std::vector<casadi_int> lookup(
n_variables(), -1);
4112 for (
size_t i = 0; i < iind.size(); ++i) lookup.at(iind[i]) = i;
4114 std::vector<bool> nonlin(iind.size(),
false);
4116 std::vector<casadi_int> nonlin_list;
4118 std::vector<casadi_int> row, col;
4120 for (casadi_int j = 0; j < oind.size(); ++j) {
4126 if (i >= 0 && !nonlin.at(i)) {
4128 nonlin_list.push_back(i);
4129 nonlin.at(i) =
true;
4134 for (casadi_int k1 : nonlin_list) {
4135 for (casadi_int k2 : nonlin_list) {
4141 if (col.size() > 2 * iind.size() * iind.size()) {
4147 for (casadi_int k : nonlin_list) nonlin[k] =
false;
4148 nonlin_list.clear();
4156 auto now = std::chrono::system_clock::now();
4157 std::time_t tt = std::chrono::system_clock::to_time_t(now);
4158 auto local_tm = *std::localtime(&tt);
4160 std::stringstream ss;
4161 ss << local_tm.tm_year + 1900 <<
'-';
4162 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mon + 1 <<
'-';
4163 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_mday <<
'T';
4164 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_hour <<
':';
4165 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_min <<
':';
4166 ss << std::setfill(
'0') << std::setw(2) << local_tm.tm_sec <<
'Z';
4172 static bool initialized =
false;
4174 srand(::
time(
nullptr));
4178 const char h[] =
"0123456789abcdef";
4180 const size_t len = 32;
4182 std::vector<char> buf(len);
4183 for (
size_t i = 0; i < len; ++i)
4184 buf[i] = h[rand() % 16];
4185 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 file_close(std::ofstream &f, bool cpp)
Print file header.
std::string generate(const std::string &prefix="")
Generate file(s)
static void file_open(std::ofstream &f, const std::string &name, bool cpp)
Print file header.
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::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 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.
size_t size() const
Get the number of children.
Helper class: Specify number of entries in an enum.