10 using namespace utils;
16 bool matches_fe_space(
const int entry_fe_space_id,
const int fe_space_id)
18 return entry_fe_space_id < 0 || fe_space_id < 0 || entry_fe_space_id == fe_space_id;
21 int fe_space_id(
const json &entry)
23 return entry.value(
"fe_space", -1);
26 bool is_body_value_entry(
const json &entry)
28 if (!entry.is_object() || !entry.contains(
"id") || !entry.contains(
"value"))
31 const json &
id = entry[
"id"];
34 for (
const json &value : id)
35 if (value.is_number_integer() && value.get<int>() != -1)
40 return id.is_number_integer() &&
id.get<
int>() != -1;
43 bool has_body_value_entries(
const json &value)
45 return is_body_value_entry(value) || (value.is_array() && !value.empty() && is_body_value_entry(value.front()));
48 template <
typename Map>
49 const typename Map::mapped_type *find_for_fe_space(
const Map &values,
const int fe_space_id)
51 if (
const auto it = values.find(fe_space_id); it != values.end())
53 if (
const auto it = values.find(-1); it != values.end())
55 if (fe_space_id < 0 && values.size() == 1)
56 return &values.begin()->second;
60 std::vector<json> flatten_ids(
const json &p_j_boundary_tmp)
64 std::vector<json> j_boundary;
66 for (
size_t i = 0; i < j_boundary_tmp.size(); ++i)
68 const auto &
tmp = j_boundary_tmp[i];
72 j_boundary.push_back(tmp);
75 if (!
tmp.contains(
"id"))
78 if (tmp[
"id"].is_array())
80 for (
size_t j = 0; j <
tmp[
"id"].size(); ++j)
83 newj[
"id"] =
tmp[
"id"][j].get<
int>();
84 j_boundary.push_back(newj);
88 j_boundary.push_back(tmp);
99 double z = pts.size() == 2 ? 0 : pts(2);
119 assert(pts.size() == 2 || pts.size() == 3);
120 double x = pts(0),
y = pts(1),
z = pts.size() == 3 ? pts(2) : 0.0;
125 :
Problem(name), is_all_(false)
133 for (
int i = 0; i < 3; ++i)
135 for (
auto &[fe_space_id,
rhs] :
rhs_)
136 rhs[i].set_unit_type(units.
force());
139 for (
int i = 0; i < 3; ++i)
146 v.set_unit_type(units.
force());
155 v.second.set_unit_type(units.
pressure());
158 for (
int i = 0; i < 3; ++i)
159 v.value[i].set_unit_type(units.
velocity());
162 for (
int i = 0; i < 3; ++i)
163 v.value[i].set_unit_type(units.
velocity());
166 for (
int i = 0; i < 3; ++i)
170 v.second.set_unit_type(units.
velocity());
173 v.second.set_unit_type(units.
force());
177 for (
int i = 0; i < 3; ++i)
179 for (
auto &[fe_space_id,
rhs] :
rhs_)
183 for (
int i = 0; i < 3; ++i)
187 v.set_unit_type(units.
length());
190 v.set_unit_type(units.
force());
199 v.second.set_unit_type(units.
pressure());
202 for (
int i = 0; i < 3; ++i)
203 v.value[i].set_unit_type(units.
length());
206 for (
int i = 0; i < 3; ++i)
207 v.value[i].set_unit_type(units.
velocity());
210 for (
int i = 0; i < 3; ++i)
214 v.second.set_unit_type(units.
length());
217 v.second.set_unit_type(units.
force());
223 const auto *
rhs = find_for_fe_space(
rhs_, fe_space_id);
224 const auto *rhs_size = find_for_fe_space(
rhs_size_, fe_space_id);
225 const int size = rhs_size ==
nullptr ? pts.cols() : *rhs_size;
226 val.resize(pts.rows(), size);
234 const bool planar = pts.cols() == 2;
235 for (
int i = 0; i < pts.rows(); ++i)
237 for (
int j = 0; j < size; ++j)
239 double x = pts(i, 0),
y = pts(i, 1),
z = planar ? 0 : pts(i, 2);
240 val(i, j) = (*rhs)[j](
x,
y,
z, t);
249 rhs(assembler, pts, t,
val, fe_space_id);
253 int value_size = pts.cols();
256 if (matches_fe_space(entry.fe_space_id, fe_space_id))
258 value_size = entry.size;
263 val.resize(pts.rows(), value_size);
270 if (entry.body_id == body_id && matches_fe_space(entry.fe_space_id, fe_space_id))
277 if (body_rhs ==
nullptr)
280 const bool planar = pts.cols() == 2;
281 for (
int i = 0; i < pts.rows(); ++i)
283 for (
int j = 0; j <
val.cols(); ++j)
285 const double x = pts(i, 0),
y = pts(i, 1),
z = planar ? 0 : pts(i, 2);
293 const auto *
rhs = find_for_fe_space(
rhs_, fe_space_id);
294 const auto *rhs_size = find_for_fe_space(
rhs_size_, fe_space_id);
295 if (
rhs !=
nullptr && rhs_size !=
nullptr)
297 for (
int i = 0; i < *rhs_size; ++i)
298 if (!(*
rhs)[i].is_zero())
304 if (!matches_fe_space(entry.fe_space_id, fe_space_id))
306 for (
int i = 0; i < entry.size; ++i)
307 if (!entry.value[i].is_zero())
358 if (!matches_fe_space(displacement.fe_space_id, fe_space_id))
361 for (
int d = 0; d < displacement.dirichlet_dimension.size(); ++d)
363 if (!displacement.dirichlet_dimension(d))
370 for (
int i = 0; i < n_dirichlet.rows(); ++i)
372 for (
int d = 1; d < n_dirichlet.cols(); ++d)
374 if (std::isnan(n_dirichlet(i, d)))
388 if (displacement.size > 0 && matches_fe_space(displacement.fe_space_id, fe_space_id))
390 value_size = displacement.size;
394 val = Eigen::MatrixXd::Zero(pts.rows(), value_size);
396 for (
long i = 0; i < pts.rows(); ++i)
413 void GenericTensorProblem::neumann_bc(
const mesh::Mesh &mesh,
const Eigen::MatrixXi &global_ids,
const Eigen::MatrixXd &uv,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &normals,
const double t, Eigen::MatrixXd &
val,
const int fe_space_id)
const
415 val = Eigen::MatrixXd::Zero(pts.rows(), mesh.
dimension());
417 for (
long i = 0; i < pts.rows(); ++i)
425 for (
int d = 0; d < std::min<int>(
val.cols(),
forces_[b].size); ++d)
427 val(i, d) =
forces_[b].eval(pts.row(i), d, t);
438 for (
int d = 0; d <
val.cols(); ++d)
450 val = Eigen::MatrixXd::Zero(pts.rows(), 1);
452 for (
long i = 0; i < pts.rows(); ++i)
477 const bool planar = pts.cols() == 2;
478 val.resize(pts.rows(), pts.cols());
480 for (
int i = 0; i < pts.rows(); ++i)
482 for (
int j = 0; j < pts.cols(); ++j)
484 double x = pts(i, 0),
y = pts(i, 1),
z = planar ? 0 : pts(i, 2);
492 const int size = pts.cols();
493 val.resize(pts.rows(), pts.cols() * size);
497 const bool planar = size == 2;
498 for (
int i = 0; i < pts.rows(); ++i)
500 for (
int j = 0; j < pts.cols() * size; ++j)
502 double x = pts(i, 0),
y = pts(i, 1),
z = planar ? 0 : pts(i, 2);
518 for (
int d = 0; d <
val.cols(); ++d)
526 for (
int i = 0; i < n_dirichlet.rows(); ++i)
528 if (n_dirichlet(i, 0) == node_id)
530 for (
int d = 0; d <
val.cols(); ++d)
532 val(d) = n_dirichlet(i, d + 1);
550 val = Eigen::MatrixXd::Zero(1, it->second.size);
551 for (
int d = 0; d <
val.cols(); ++d)
552 val(d) = it->second.eval(pt, d, t);
558 for (
int i = 0; i < n_neumann.rows(); ++i)
560 if (n_neumann(i, 0) == node_id)
562 val.resize(1, n_neumann.cols() - 1);
563 for (
int d = 0; d <
val.cols(); ++d)
564 val(d) = n_neumann(i, d + 1);
581 for (
int i = 0; i < n_dirichlet.rows(); ++i)
583 if (n_dirichlet(i, 0) == n_id)
594 return matches_fe_space(it->second.fe_space_id, fe_space_id);
598 for (
int i = 0; i < n_neumann.rows(); ++i)
600 if (n_neumann(i, 0) == n_id)
621 if (matches_fe_space(force.fe_space_id, fe_space_id))
635 for (
int i = 0; i < n_dirichlet.rows(); ++i)
637 if (n_dirichlet(i, 0) == n_id)
639 return !std::isnan(n_dirichlet(i, dim + 1));
653 logger().debug(
"Skipping updating in nodes to nodes in problem, already done once...");
658 for (
int n = 0; n < n_dirichlet.rows(); ++n)
660 const int node_id = in_node_to_node[n_dirichlet(n, 0)];
661 n_dirichlet(n, 0) = node_id;
666 for (
int n = 0; n < n_neumann.rows(); ++n)
668 const int node_id = in_node_to_node[n_neumann(n, 0)];
669 n_neumann(n, 0) = node_id;
684 const json &rr = params[
"rhs"];
685 const bool has_fe_spaces = rr.is_array() && !rr.empty() && rr.front().is_object() && rr.front().contains(
"fe_space") && rr.front().contains(
"value");
686 const bool has_body_ids = has_body_value_entries(rr);
689 const std::vector<json>
entries = flatten_ids(rr);
691 for (
size_t k = 0; k <
entries.size(); ++k)
695 const auto &value =
entries[k][
"value"];
696 body_rhs_[k].size = value.is_array() ? int(value.size()) : 1;
699 for (
int d = 0; d <
body_rhs_[k].size; ++d)
700 body_rhs_[k].value[d].
init(value.is_array() ? value[d] : value, root_path);
703 else if (has_fe_spaces)
705 for (
const json &entry : rr)
707 const int id = fe_space_id(entry);
708 const json &value = entry[
"value"];
709 const int size = value.is_array() ? int(value.size()) : 1;
711 log_and_throw_error(
"RHS for FE space {} has {} components; at most 3 are supported.",
id, size);
713 for (
int k = 0; k < size; ++k)
714 rhs_[
id][k].
init(value.is_array() ? value[k] : value, root_path);
717 else if (rr.is_array() && !rr.empty())
722 for (
size_t k = 0; k < rr.size(); ++k)
725 else if (!rr.is_array())
731 auto ex = params[
"reference"][
"solution"];
735 for (
size_t k = 0; k < ex.size(); ++k)
746 auto ex = params[
"reference"][
"gradient"];
750 for (
size_t k = 0; k < ex.size(); ++k)
763 std::vector<json> j_boundary = flatten_ids(params[
"dirichlet_boundary"]);
770 if (j_boundary[i - offset].is_string())
772 const std::string path =
resolve_path(j_boundary[i - offset], params[
"root_path"]);
773 if (!std::filesystem::is_regular_file(path))
784 displacements_[i].fe_space_id = fe_space_id(j_boundary[i - offset]);
786 if (j_boundary[i - offset][
"id"] ==
"all")
800 auto ff = j_boundary[i - offset][
"value"];
806 for (
size_t k = 0; k < ff.size(); ++k)
809 if (j_boundary[i - offset].contains(
"time_reference") && j_boundary[i - offset][
"time_reference"].size() > 0)
810 displacements_[i].value[k].set_t(j_boundary[i - offset][
"time_reference"]);
824 if (j_boundary[i - offset].contains(
"dimension"))
826 auto &tmp = j_boundary[i - offset][
"dimension"];
827 assert(tmp.is_array());
828 for (
size_t k = 0; k < tmp.size(); ++k)
835 if (j_boundary[i - offset][
"interpolation"].is_array())
837 for (
int ii = 0; ii < j_boundary[i - offset][
"interpolation"].size(); ++ii)
852 auto j_boundary_tmp = params[
"neumann_boundary"];
853 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
856 forces_.resize(offset + j_boundary.size());
861 forces_[i].fe_space_id = fe_space_id(j_boundary[i - offset]);
863 auto ff = j_boundary[i - offset][
"value"];
864 forces_[i].size = ff.is_array() ? int(ff.size()) : 1;
867 for (
int k = 0; k <
forces_[i].size; ++k)
868 forces_[i].value[k].
init(ff.is_array() ? ff[k] : ff, root_path);
870 if (j_boundary[i - offset][
"interpolation"].is_array())
872 for (
int ii = 0; ii < j_boundary[i - offset][
"interpolation"].size(); ++ii)
884 std::vector<json> j_boundary = flatten_ids(params[
"nodal_neumann_boundary"]);
886 for (
size_t i = 0; i < j_boundary.size(); ++i)
888 if (j_boundary[i].is_string())
890 const std::string path =
resolve_path(j_boundary[i], params[
"root_path"]);
891 if (!std::filesystem::is_regular_file(path))
901 const int id = j_boundary[i][
"id"];
903 nodal_neumann.
fe_space_id = fe_space_id(j_boundary[i]);
905 auto ff = j_boundary[i][
"value"];
906 nodal_neumann.
size = ff.is_array() ? int(ff.size()) : 1;
907 if (nodal_neumann.
size > 3)
909 for (
int k = 0; k < nodal_neumann.
size; ++k)
910 nodal_neumann.
value[k].init(ff.is_array() ? ff[k] : ff, root_path);
912 if (j_boundary[i][
"interpolation"].is_array())
914 for (
int ii = 0; ii < j_boundary[i][
"interpolation"].size(); ++ii)
930 auto j_boundary_tmp = params[
"normal_aligned_neumann_boundary"];
931 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
941 auto ff = j_boundary[i - offset][
"value"];
944 if (j_boundary[i - offset].contains(
"interpolation"))
956 auto j_boundary_tmp = params[
"pressure_boundary"];
957 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
960 pressures_.resize(offset + j_boundary.size());
966 auto ff = j_boundary[i - offset][
"value"];
968 if (j_boundary[i - offset].contains(
"time_reference") && j_boundary[i - offset][
"time_reference"].size() > 0)
969 pressures_[i].value.set_t(j_boundary[i - offset][
"time_reference"]);
971 pressures_[i].interpolation = std::make_shared<NoInterpolation>();
979 auto j_boundary_tmp = params[
"pressure_cavity"];
980 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
986 int boundary_id = j_boundary[i - offset][
"id"];
993 auto ff = j_boundary[i - offset][
"value"];
996 cavity_pressures_[boundary_id].interpolation = std::make_shared<NoInterpolation>();
1003 auto rr = params[
"solution"];
1005 assert(rr.is_array());
1007 for (
size_t k = 0; k < rr.size(); ++k)
1011 const auto v = rr[k][
"value"];
1022 auto rr = params[
"velocity"];
1024 assert(rr.is_array());
1026 for (
size_t k = 0; k < rr.size(); ++k)
1030 const auto v = rr[k][
"value"];
1041 auto rr = params[
"acceleration"];
1043 assert(rr.is_array());
1045 for (
size_t k = 0; k < rr.size(); ++k)
1049 const auto v = rr[k][
"value"];
1061 int value_size = pts.cols();
1063 if (matches_fe_space(entry.fe_space_id, fe_space_id))
1065 value_size = entry.size;
1068 val.resize(pts.rows(), value_size);
1075 const bool planar = pts.cols() == 2;
1076 for (
int i = 0; i < pts.rows(); ++i)
1090 val.row(i).setZero();
1094 for (
int j = 0; j <
val.cols(); ++j)
1101 int value_size = pts.cols();
1103 if (matches_fe_space(entry.fe_space_id, fe_space_id))
1105 value_size = entry.size;
1108 val.resize(pts.rows(), value_size);
1115 const bool planar = pts.cols() == 2;
1116 for (
int i = 0; i < pts.rows(); ++i)
1130 val.row(i).setZero();
1134 for (
int j = 0; j <
val.cols(); ++j)
1141 int value_size = pts.cols();
1143 if (matches_fe_space(entry.fe_space_id, fe_space_id))
1145 value_size = entry.size;
1148 val.resize(pts.rows(), value_size);
1155 const bool planar = pts.cols() == 2;
1156 for (
int i = 0; i < pts.rows(); ++i)
1170 val.row(i).setZero();
1174 for (
int j = 0; j <
val.cols(); ++j)
1203 for (
int i = 0; i <
exact_.size(); ++i)
1212 :
Problem(name), is_all_(false)
1221 v.set_unit_type(
"");
1224 v.set_unit_type(
"");
1227 v.second.set_unit_type(
"");
1230 v.second.set_unit_type(
"");
1233 v.value.set_unit_type(
"");
1235 for (
auto &[fe_space_id,
rhs] :
rhs_)
1236 rhs.set_unit_type(
"");
1239 for (
int i = 0; i < 3; ++i)
1245 val.resize(pts.rows(), 1);
1246 const auto *
rhs = find_for_fe_space(
rhs_, fe_space_id);
1247 if (
rhs ==
nullptr ||
rhs->is_zero())
1252 const bool planar = pts.cols() == 2;
1253 for (
int i = 0; i < pts.rows(); ++i)
1255 double x = pts(i, 0),
y = pts(i, 1),
z = planar ? 0 : pts(i, 2);
1256 val(i) = (*rhs)(
x,
y,
z, t);
1264 rhs(assembler, pts, t,
val, fe_space_id);
1268 val.resize(pts.rows(), 1);
1275 if (entry.body_id == body_id && matches_fe_space(entry.fe_space_id, fe_space_id))
1282 if (body_rhs ==
nullptr)
1285 const bool planar = pts.cols() == 2;
1286 for (
int i = 0; i < pts.rows(); ++i)
1288 const double x = pts(i, 0),
y = pts(i, 1),
z = planar ? 0 : pts(i, 2);
1295 const auto *
rhs = find_for_fe_space(
rhs_, fe_space_id);
1296 if (
rhs !=
nullptr && !
rhs->is_zero())
1300 if (matches_fe_space(entry.fe_space_id, fe_space_id) && !entry.value.is_zero())
1325 val = Eigen::MatrixXd::Zero(pts.rows(), 1);
1327 for (
long i = 0; i < pts.rows(); ++i)
1341 void GenericScalarProblem::neumann_bc(
const mesh::Mesh &mesh,
const Eigen::MatrixXi &global_ids,
const Eigen::MatrixXd &uv,
const Eigen::MatrixXd &pts,
const Eigen::MatrixXd &normals,
const double t, Eigen::MatrixXd &
val,
const int fe_space_id)
const
1343 val = Eigen::MatrixXd::Zero(pts.rows(), 1);
1345 for (
long i = 0; i < pts.rows(); ++i)
1353 double x = pts(i, 0),
y = pts(i, 1),
z = pts.cols() == 2 ? 0 : pts(i, 2);
1363 val.resize(pts.rows(), 1);
1370 const bool planar = pts.cols() == 2;
1371 for (
int i = 0; i < pts.rows(); ++i)
1396 const bool planar = pts.cols() == 2;
1397 val.resize(pts.rows(), 1);
1399 for (
int i = 0; i < pts.rows(); ++i)
1401 double x = pts(i, 0),
y = pts(i, 1),
z = pts.cols() == 2 ? 0 : pts(i, 2);
1408 val.resize(pts.rows(), pts.cols());
1412 const bool planar = pts.cols() == 2;
1413 for (
int i = 0; i < pts.rows(); ++i)
1415 for (
int j = 0; j < pts.cols(); ++j)
1417 double x = pts(i, 0),
y = pts(i, 1),
z = pts.cols() == 2 ? 0 : pts(i, 2);
1436 throw "Invalid boundary id for pressure update";
1441 Eigen::MatrixXd curr_val =
pressures_[index].value.get_mat();
1442 assert(time_step <= curr_val.size());
1443 assert(curr_val.cols() == 1);
1444 curr_val(time_step) =
val;
1466 throw "Invalid boundary id for dirichlet update";
1469 for (
int i = 0; i <
val.size(); ++i)
1473 Eigen::MatrixXd curr_val =
displacements_[index].value[i].get_mat();
1474 assert(time_step <= curr_val.size());
1475 assert(curr_val.cols() == 1);
1476 curr_val(time_step) =
val(i);
1488 assert(node_ids.size() == nodal_dirichlet.rows());
1492 for (
int i = 0; i < node_ids.size(); ++i)
1494 int mapped_node_id = in_node_to_node(node_ids(i));
1495 for (
int j = 0; j < n_dirichlet.rows(); ++j)
1496 if (mapped_node_id == n_dirichlet(j, 0))
1497 for (
int k = 0; k < n_dirichlet.cols() - 1; ++k)
1498 n_dirichlet(j, k + 1) = nodal_dirichlet(i, k);
1504 val = Eigen::MatrixXd::Zero(1, 1);
1518 for (
int i = 0; i < n_dirichlet.rows(); ++i)
1520 if (n_dirichlet(i, 0) == node_id)
1522 val(0) = n_dirichlet(i, 1);
1533 val = Eigen::MatrixXd::Zero(1, 1);
1538 val(0) = it->second.eval(pt, t);
1544 for (
int i = 0; i < n_neumann.rows(); ++i)
1546 if (n_neumann(i, 0) == node_id)
1548 val(0) = n_neumann(i, 1);
1565 for (
int i = 0; i < n_dirichlet.rows(); ++i)
1567 if (n_dirichlet(i, 0) == n_id)
1578 return matches_fe_space(it->second.fe_space_id, fe_space_id);
1582 for (
int i = 0; i < n_neumann.rows(); ++i)
1584 if (n_neumann(i, 0) == n_id)
1605 if (matches_fe_space(neumann.fe_space_id, fe_space_id))
1617 for (
int n = 0; n < n_dirichlet.rows(); ++n)
1619 const int node_id = in_node_to_node[n_dirichlet(n, 0)];
1620 n_dirichlet(n, 0) = node_id;
1625 for (
int n = 0; n < n_neumann.rows(); ++n)
1627 const int node_id = in_node_to_node[n_neumann(n, 0)];
1628 n_neumann(n, 0) = node_id;
1643 const json &rr = params[
"rhs"];
1644 const bool has_fe_spaces = rr.is_array() && !rr.empty() && rr.front().is_object() && rr.front().contains(
"fe_space") && rr.front().contains(
"value");
1645 const bool has_body_ids = has_body_value_entries(rr);
1648 const std::vector<json>
entries = flatten_ids(rr);
1650 for (
size_t k = 0; k <
entries.size(); ++k)
1657 else if (has_fe_spaces)
1659 for (
const json &entry : rr)
1660 rhs_[fe_space_id(entry)].init(entry[
"value"], root_path);
1662 else if (!rr.is_array() || !rr.empty())
1668 has_exact_ = !params[
"reference"][
"solution"].empty();
1669 exact_.
init(params[
"reference"][
"solution"], root_path);
1674 auto ex = params[
"reference"][
"gradient"];
1678 for (
size_t k = 0; k < ex.size(); ++k)
1691 std::vector<json> j_boundary = flatten_ids(params[
"dirichlet_boundary"]);
1694 dirichlet_.resize(offset + j_boundary.size());
1698 if (j_boundary[i - offset].is_string())
1700 const std::string path =
resolve_path(j_boundary[i - offset], params[
"root_path"]);
1701 if (!std::filesystem::is_regular_file(path))
1704 Eigen::MatrixXd tmp;
1711 int current_id = -1;
1712 dirichlet_[i].fe_space_id = fe_space_id(j_boundary[i - offset]);
1714 if (j_boundary[i - offset][
"id"] ==
"all")
1728 auto ff = j_boundary[i - offset][
"value"];
1732 if (j_boundary[i - offset][
"interpolation"].is_array())
1734 if (j_boundary[i - offset][
"interpolation"].size() == 0)
1735 dirichlet_[i].interpolation = std::make_shared<NoInterpolation>();
1736 else if (j_boundary[i - offset][
"interpolation"].size() == 1)
1752 auto j_boundary_tmp = params[
"neumann_boundary"];
1753 std::vector<json> j_boundary = flatten_ids(j_boundary_tmp);
1756 neumann_.resize(offset + j_boundary.size());
1761 neumann_[i].fe_space_id = fe_space_id(j_boundary[i - offset]);
1763 auto ff = j_boundary[i - offset][
"value"];
1764 neumann_[i].value.init(ff, root_path);
1766 if (j_boundary[i - offset][
"interpolation"].is_array())
1768 if (j_boundary[i - offset][
"interpolation"].size() == 0)
1769 neumann_[i].interpolation = std::make_shared<NoInterpolation>();
1770 else if (j_boundary[i - offset][
"interpolation"].size() == 1)
1782 std::vector<json> j_boundary = flatten_ids(params[
"nodal_neumann_boundary"]);
1784 for (
size_t i = 0; i < j_boundary.size(); ++i)
1786 if (j_boundary[i].is_string())
1788 const std::string path =
resolve_path(j_boundary[i], params[
"root_path"]);
1789 if (!std::filesystem::is_regular_file(path))
1792 Eigen::MatrixXd tmp;
1799 const int id = j_boundary[i][
"id"];
1801 nodal_neumann.
fe_space_id = fe_space_id(j_boundary[i]);
1802 nodal_neumann.
value.
init(j_boundary[i][
"value"], root_path);
1804 if (j_boundary[i][
"interpolation"].is_array())
1806 if (j_boundary[i][
"interpolation"].size() == 0)
1807 nodal_neumann.
interpolation = std::make_shared<NoInterpolation>();
1808 else if (j_boundary[i][
"interpolation"].size() == 1)
1822 auto rr = params[
"solution"];
1824 assert(rr.is_array());
1826 for (
size_t k = 0; k < rr.size(); ++k)
std::vector< Eigen::Triplet< double > > entries
std::string force() const
std::string pressure() const
std::string velocity() const
std::string acceleration() const
const std::string & length() const
virtual bool is_fluid() const
void neumann_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
bool is_nodal_neumann_boundary(const int n_id, const int tag, const int fe_space_id=-1) override
std::vector< ScalarBCValue > neumann_
void initial_solution(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< Eigen::MatrixXd > nodal_neumann_mat_
void update_nodes(const Eigen::VectorXi &in_node_to_node) override
void dirichlet_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
bool is_nodal_dirichlet_boundary(const int n_id, const int tag, const int fe_space_id=-1) override
std::vector< ScalarInitialValue > body_rhs_
utils::ExpressionValue exact_
std::array< utils::ExpressionValue, 3 > exact_grad_
bool has_nodal_dirichlet(const int fe_space_id=-1) override
void exact_grad(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
bool has_nodal_neumann(const int fe_space_id=-1) override
std::map< int, utils::ExpressionValue > rhs_
void neumann_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const Eigen::MatrixXd &normal, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::map< int, ScalarBCValue > nodal_dirichlet_
void rhs(const assembler::Assembler &assembler, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< ScalarInitialValue > initial_solution_
bool is_rhs_zero(const int fe_space_id=-1) const override
void set_units(const assembler::Assembler &assembler, const Units &units) override
GenericScalarProblem(const std::string &name)
std::map< int, ScalarBCValue > nodal_neumann_
bool has_exact_sol() const override
std::vector< ScalarBCValue > dirichlet_
void set_parameters(const json ¶ms, const std::string &root_path) override
bool has_boundary(const BoundaryKind kind, const int tag, const int fe_space_id) override
void exact(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
void dirichlet_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< Eigen::MatrixXd > nodal_dirichlet_mat_
void update_pressure_boundary(const int id, const int time_step, const double val)
bool has_boundary(const BoundaryKind kind, const int tag, const int fe_space_id) override
std::map< int, TensorBCValue > nodal_neumann_
std::vector< TensorInitialValue > initial_acceleration_
void set_parameters(const json ¶ms, const std::string &root_path) override
void initial_acceleration(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
void initial_solution(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::unordered_map< int, ScalarBCValue > cavity_pressures_
std::vector< TensorInitialValue > initial_position_
void rhs(const assembler::Assembler &assembler, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
void update_nodes(const Eigen::VectorXi &in_node_to_node) override
GenericTensorProblem(const std::string &name)
std::map< int, int > rhs_size_
std::vector< TensorInitialValue > body_rhs_
std::vector< TensorInitialValue > initial_velocity_
bool all_dimensions_dirichlet(const int fe_space_id) const override
void update_dirichlet_nodes(const Eigen::VectorXi &in_node_to_node, const Eigen::VectorXi &node_ids, const Eigen::MatrixXd &nodal_dirichlet)
std::vector< TensorBCValue > displacements_
void neumann_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< ScalarBCValue > normal_aligned_forces_
std::map< int, std::array< utils::ExpressionValue, 3 > > rhs_
bool is_nodal_dimension_dirichlet(const int n_id, const int tag, const int dim, const int fe_space_id=-1) const override
void dirichlet_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< Eigen::MatrixXd > nodal_neumann_mat_
bool is_nodal_neumann_boundary(const int n_id, const int tag, const int fe_space_id=-1) override
bool is_dimension_dirichet(const int tag, const int dim, const int fe_space_id=-1) const override
void pressure_bc(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &uv, const Eigen::MatrixXd &pts, const Eigen::MatrixXd &normals, const double t, Eigen::MatrixXd &val) const override
void exact(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
std::map< int, TensorBCValue > nodal_dirichlet_
bool has_nodal_neumann(const int fe_space_id=-1) override
std::array< utils::ExpressionValue, 9 > exact_grad_
bool is_rhs_zero(const int fe_space_id=-1) const override
void dirichlet_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< TensorBCValue > forces_
void update_dirichlet_boundary(const int id, const int time_step, const Eigen::VectorXd &val)
double pressure_cavity_bc(const int boundary_id, const double t) const override
std::vector< ScalarBCValue > pressures_
bool is_nodal_dirichlet_boundary(const int n_id, const int tag, const int fe_space_id=-1) override
void neumann_nodal_value(const mesh::Mesh &mesh, const int node_id, const RowVectorNd &pt, const Eigen::MatrixXd &normal, const double t, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
bool has_exact_sol() const override
void exact_grad(const Eigen::MatrixXd &pts, const double t, Eigen::MatrixXd &val) const override
bool has_nodal_dirichlet(const int fe_space_id=-1) override
void set_units(const assembler::Assembler &assembler, const Units &units) override
std::array< utils::ExpressionValue, 3 > exact_
std::vector< Eigen::MatrixXd > nodal_dirichlet_mat_
void initial_velocity(const mesh::Mesh &mesh, const Eigen::MatrixXi &global_ids, const Eigen::MatrixXd &pts, Eigen::MatrixXd &val, const int fe_space_id=-1) const override
std::vector< int > normal_aligned_neumann_boundary_ids_
bool updated_dirichlet_node_ordering_
std::vector< int > pressure_boundary_ids_
std::vector< int > boundary_ids_
virtual void init(const mesh::Mesh &mesh)
std::vector< int > neumann_boundary_ids_
std::vector< int > pressure_cavity_ids_
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
virtual int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
virtual int get_boundary_id(const int primitive) const
Get the boundary selection of an element (face in 3d, edge in 2d)
int dimension() const
utily for dimension
virtual int get_node_id(const int node_id) const
Get the boundary selection of a node.
void init(const json &vals, const std::string &root_path)
void set_unit_type(const std::string &unit_type)
static std::shared_ptr< Interpolation > build(const json ¶ms)
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
std::string resolve_path(const std::string &path, const std::string &input_file_path, const bool only_if_exists=false)
std::vector< T > json_as_array(const json &j)
Return the value of a json object as an array.
bool is_param_valid(const json ¶ms, const std::string &key)
Determine if a key exists and is non-null in a json object.
spdlog::logger & logger()
Retrieves the current logger.
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
void log_and_throw_error(const std::string &msg)
std::shared_ptr< utils::Interpolation > interpolation
double eval(const RowVectorNd &pts, const double t) const
utils::ExpressionValue value
utils::ExpressionValue value
std::vector< std::shared_ptr< utils::Interpolation > > interpolation
std::array< utils::ExpressionValue, 3 > value
double eval(const RowVectorNd &pts, const int dim, const double t, const int el_id=-1) const
std::array< utils::ExpressionValue, 3 > value