134 template <
class InputIterator,
class T>
135 int find_index(InputIterator first, InputIterator last,
const T &
val)
137 return std::distance(first, std::find(first, last,
val));
142 std::array<int, 4> v = {{v1, v2, v3, v4}};
143 std::sort(v.begin(), v.end());
150 std::array<int, 4> u;
156 std::sort(u.begin(), u.end());
166 std::array<int, 4> tet_vertices_local_to_global(
const Mesh3D &mesh,
int c)
170 std::array<int, 4> l2g;
172 for (
int vi : mesh.get_ordered_vertices_from_tet(c))
180 std::array<int, 8> hex_vertices_local_to_global(
const Mesh3D &mesh,
int c)
185 std::array<int, 8> l2g;
187 for (
int vi : mesh.get_ordered_vertices_from_hex(c))
195 std::array<int, 6> prism_vertices_local_to_global(
const Mesh3D &mesh,
int c)
200 std::array<int, 6> l2g;
202 for (
int vi : mesh.get_ordered_vertices_from_prism(c))
210 int lowest_order_elem_on_edge(
const polyfem::mesh::NCMesh3D &mesh,
const Eigen::VectorXi &discr_orders,
const int eid)
213 int min = std::numeric_limits<int>::max();
215 for (
const auto e : elem_list)
216 if (discr_orders[
e] < min)
221 void tet_local_to_global(
const bool is_geom_bases,
const int p,
const Mesh3D &mesh,
int c,
const Eigen::VectorXi &discr_order,
const Eigen::VectorXi &edge_orders,
const Eigen::VectorXi &face_orders, std::vector<int> &res,
polyfem::mesh::MeshNodes &nodes, std::vector<std::vector<int>> &edge_virtual_nodes, std::vector<std::vector<int>> &face_virtual_nodes)
223 const int n_edge_nodes = p > 1 ? ((p - 1) * 6) : 0;
224 const int nn = p > 2 ? (p - 2) : 0;
225 const int n_loc_f = (
nn * (
nn + 1) / 2);
226 const int n_face_nodes = n_loc_f * 4;
227 int n_cell_nodes = 0;
228 for (
int pp = 4; pp <= p; ++pp)
229 n_cell_nodes += ((pp - 3) * ((pp - 3) + 1) / 2);
233 res.push_back(
nodes.node_id_from_cell(c));
238 res.reserve(4 + n_edge_nodes + n_face_nodes + n_cell_nodes);
241 Eigen::Matrix<Navigation3D::Index, 4, 1>
f;
243 auto v = tet_vertices_local_to_global(mesh, c);
244 Eigen::Matrix<int, 4, 3> fv;
245 fv.row(0) << v[0], v[1], v[2];
246 fv.row(1) << v[0], v[1], v[3];
247 fv.row(2) << v[1], v[2], v[3];
248 fv.row(3) << v[2], v[0], v[3];
250 for (
long lf = 0; lf < fv.rows(); ++lf)
256 Eigen::Matrix<Navigation3D::Index, 6, 1>
e;
257 Eigen::Matrix<int, 6, 2> ev;
258 ev.row(0) << v[0], v[1];
259 ev.row(1) << v[1], v[2];
260 ev.row(2) << v[2], v[0];
262 ev.row(3) << v[0], v[3];
263 ev.row(4) << v[1], v[3];
264 ev.row(5) << v[2], v[3];
266 for (
int le = 0; le <
e.rows(); ++le)
274 for (
size_t lv = 0; lv < v.size(); ++lv)
278 const auto &ncmesh =
dynamic_cast<const NCMesh3D &
>(mesh);
280 if (ncmesh.leader_edge_of_vertex(v[lv]) >= 0 || ncmesh.leader_face_of_vertex(v[lv]) >= 0)
281 res.push_back(-lv - 1);
283 res.push_back(
nodes.node_id_from_primitive(v[lv]));
286 res.push_back(
nodes.node_id_from_primitive(v[lv]));
290 for (
int le = 0; le <
e.rows(); ++le)
292 const auto index =
e[le];
294 int min_p = discr_order.size() > 0 ? discr_order(c) : 0;
298 auto node_ids =
nodes.node_ids_from_edge(index, p - 1);
299 res.insert(res.end(), node_ids.begin(), node_ids.end());
305 const auto &ncmesh =
dynamic_cast<const NCMesh3D &
>(mesh);
307 if (ncmesh.leader_edge_of_edge(index.edge) >= 0 || ncmesh.leader_face_of_edge(index.edge) >= 0)
309 for (
int tmp = 0;
tmp < p - 1; ++
tmp)
310 res.push_back(-le - 1);
313 else if (edge_orders[index.edge] < discr_order(c))
315 for (
int tmp = 0;
tmp < p - 1; ++
tmp)
316 res.push_back(-le - 1);
318 int min_order_elem = lowest_order_elem_on_edge(ncmesh, discr_order, index.edge);
320 if (min_order_elem == c)
321 edge_virtual_nodes[index.edge] =
nodes.node_ids_from_edge(index, edge_orders[index.edge] - 1);
325 auto node_ids =
nodes.node_ids_from_edge(index, p - 1);
326 res.insert(res.end(), node_ids.begin(), node_ids.end());
331 for (
auto cid : neighs)
333 min_p = std::min(min_p, discr_order.size() > 0 ? discr_order(cid) : 0);
336 if (discr_order.size() > 0 && discr_order(c) > min_p)
338 for (
int tmp = 0;
tmp < p - 1; ++
tmp)
339 res.push_back(-le - 10);
343 auto node_ids =
nodes.node_ids_from_edge(index, p - 1);
344 res.insert(res.end(), node_ids.begin(), node_ids.end());
351 for (
int lf = 0; lf <
f.rows(); ++lf)
353 const auto index =
f[lf];
356 const bool skip_other = discr_order.size() > 0 && other_cell >= 0 && discr_order(c) > discr_order(other_cell);
360 auto node_ids =
nodes.node_ids_from_face(index, p - 2);
361 res.insert(res.end(), node_ids.begin(), node_ids.end());
367 const auto &ncmesh =
dynamic_cast<const NCMesh3D &
>(mesh);
369 if (ncmesh.leader_face_of_face(index.face) >= 0)
371 for (
int tmp = 0;
tmp < n_loc_f; ++
tmp)
372 res.push_back(-lf - 1);
375 else if (face_orders[index.face] < discr_order[c])
377 for (
int tmp = 0;
tmp < n_loc_f; ++
tmp)
378 res.push_back(-lf - 1);
380 if (ncmesh.n_follower_faces(index.face) > 0 && face_orders[index.face] > 2)
381 face_virtual_nodes[index.face] =
nodes.node_ids_from_face(index, face_orders[index.face] - 2);
385 auto node_ids =
nodes.node_ids_from_face(index, p - 2);
386 res.insert(res.end(), node_ids.begin(), node_ids.end());
393 for (
int tmp = 0;
tmp < n_loc_f; ++
tmp)
394 res.push_back(-lf - 1);
398 auto node_ids =
nodes.node_ids_from_face(index, p - 2);
399 res.insert(res.end(), node_ids.begin(), node_ids.end());
406 if (n_cell_nodes > 0)
408 const auto index =
f[0];
410 auto node_ids =
nodes.node_ids_from_cell(index, p - 3);
411 res.insert(res.end(), node_ids.begin(), node_ids.end());
414 assert(res.size() ==
size_t(4 + n_edge_nodes + n_face_nodes + n_cell_nodes));
417 void hex_local_to_global(
const bool serendipity,
const int q,
const Mesh3D &mesh,
int c,
const Eigen::VectorXi &discr_order, std::vector<int> &res,
MeshNodes &nodes)
421 const int n_edge_nodes = ((q - 1) * 12);
422 const int nn = (q - 1);
423 const int n_loc_f = serendipity ? 0 : (
nn *
nn);
424 const int n_face_nodes = serendipity ? 0 : (n_loc_f * 6);
425 const int n_cell_nodes = serendipity ? 0 : (
nn *
nn *
nn);
429 res.push_back(
nodes.node_id_from_cell(c));
434 res.reserve(8 + n_edge_nodes + n_face_nodes + n_cell_nodes);
437 auto v = hex_vertices_local_to_global(mesh, c);
440 Eigen::Matrix<Navigation3D::Index, 12, 1>
e;
441 Eigen::Matrix<int, 12, 2> ev;
442 ev.row(0) << v[0], v[1];
443 ev.row(1) << v[1], v[2];
444 ev.row(2) << v[2], v[3];
445 ev.row(3) << v[3], v[0];
446 ev.row(4) << v[0], v[4];
447 ev.row(5) << v[1], v[5];
448 ev.row(6) << v[2], v[6];
449 ev.row(7) << v[3], v[7];
450 ev.row(8) << v[4], v[5];
451 ev.row(9) << v[5], v[6];
452 ev.row(10) << v[6], v[7];
453 ev.row(11) << v[7], v[4];
454 for (
int le = 0; le <
e.rows(); ++le)
461 Eigen::Matrix<Navigation3D::Index, 6, 1>
f;
462 Eigen::Matrix<int, 6, 4> fv;
463 fv.row(0) << v[0], v[3], v[4], v[7];
464 fv.row(1) << v[1], v[2], v[5], v[6];
465 fv.row(2) << v[0], v[1], v[5], v[4];
466 fv.row(3) << v[3], v[2], v[6], v[7];
467 fv.row(4) << v[0], v[1], v[2], v[3];
468 fv.row(5) << v[4], v[5], v[6], v[7];
469 for (
int lf = 0; lf <
f.rows(); ++lf)
471 const auto index = find_quad_face(mesh, c, fv(lf, 0), fv(lf, 1), fv(lf, 2), fv(lf, 3));
476 for (
size_t lv = 0; lv < v.size(); ++lv)
478 res.push_back(
nodes.node_id_from_primitive(v[lv]));
480 assert(res.size() ==
size_t(8));
483 for (
int le = 0; le <
e.rows(); ++le)
485 const auto index =
e[le];
487 int min_q = discr_order.size() > 0 ? discr_order(c) : 0;
489 for (
auto cid : neighs)
491 min_q = std::min(min_q, discr_order.size() > 0 ? discr_order(cid) : 0);
494 if (discr_order.size() > 0 && discr_order(c) > min_q)
496 for (
int tmp = 0;
tmp < q - 1; ++
tmp)
497 res.push_back(-le - 10);
501 auto node_ids =
nodes.node_ids_from_edge(index, q - 1);
502 res.insert(res.end(), node_ids.begin(), node_ids.end());
505 assert(res.size() ==
size_t(8 + n_edge_nodes));
508 for (
int lf = 0; lf <
f.rows(); ++lf)
510 const auto index =
f[lf];
513 const bool skip_other = discr_order.size() > 0 && other_cell >= 0 && discr_order(c) > discr_order(other_cell);
517 for (
int tmp = 0;
tmp < n_loc_f; ++
tmp)
518 res.push_back(-lf - 1);
522 auto node_ids =
nodes.node_ids_from_face(index, serendipity ? 0 : (q - 1));
523 assert(node_ids.size() == n_loc_f);
524 res.insert(res.end(), node_ids.begin(), node_ids.end());
527 assert(res.size() ==
size_t(8 + n_edge_nodes + n_face_nodes));
530 if (n_cell_nodes > 0)
532 const auto index =
f[0];
534 auto node_ids =
nodes.node_ids_from_cell(index, q - 1);
535 res.insert(res.end(), node_ids.begin(), node_ids.end());
538 assert(res.size() ==
size_t(8 + n_edge_nodes + n_face_nodes + n_cell_nodes));
541 void prism_local_to_global(
const int p,
const int q,
const Mesh3D &mesh,
int c,
const Eigen::VectorXi &discr_order, std::vector<int> &res,
MeshNodes &nodes)
545 const int n_edge_nodest = p > 1 ? ((p - 1) * 3) : 0;
546 const int nnt = p > 2 ? (p - 2) : 0;
547 const int n_face_nodest = nnt * (nnt + 1) / 2;
549 const int nnq = q > 1 ? (q - 1) : 0;
550 const int n_face_nodesq = nnq * n_edge_nodest / 3;
552 const int n_edge_nodes = n_edge_nodest * 2 + nnq * 3;
553 const int n_face_nodes = n_face_nodest * 2 + n_face_nodesq * 3;
554 const int n_cell_nodes = n_face_nodest * nnq;
556 if (p == 0 && q == 0)
558 res.push_back(
nodes.node_id_from_cell(c));
562 res.reserve(6 + n_edge_nodes + n_face_nodes + n_cell_nodes);
565 auto v = prism_vertices_local_to_global(mesh, c);
568 Eigen::Matrix<Navigation3D::Index, 9, 1>
e;
569 Eigen::Matrix<int, 9, 2> ev;
570 ev.row(0) << v[0], v[1];
571 ev.row(1) << v[1], v[2];
572 ev.row(2) << v[2], v[0];
573 ev.row(3) << v[3], v[4];
574 ev.row(4) << v[4], v[5];
575 ev.row(5) << v[5], v[3];
576 ev.row(6) << v[0], v[3];
577 ev.row(7) << v[1], v[4];
578 ev.row(8) << v[2], v[5];
580 for (
int le = 0; le <
e.rows(); ++le)
586 Eigen::Matrix<Navigation3D::Index, 5, 1>
f;
587 Eigen::Matrix<int, 2, 3> fvt;
588 fvt.row(0) << v[0], v[1], v[2];
589 fvt.row(1) << v[3], v[4], v[5];
590 for (
int lf = 0; lf < fvt.rows(); ++lf)
596 Eigen::Matrix<int, 3, 4> fvq;
597 fvq.row(0) << v[0], v[1], v[4], v[3];
598 fvq.row(1) << v[1], v[2], v[5], v[4];
599 fvq.row(2) << v[2], v[0], v[3], v[5];
600 for (
int lf = 0; lf < fvq.rows(); ++lf)
602 const auto index = find_quad_face(mesh, c, fvq(lf, 0), fvq(lf, 1), fvq(lf, 2), fvq(lf, 3));
607 for (
size_t lv = 0; lv < v.size(); ++lv)
609 res.push_back(
nodes.node_id_from_primitive(v[lv]));
611 assert(res.size() ==
size_t(6));
614 for (
int le = 0; le <
e.rows(); ++le)
616 const auto index =
e[le];
633 auto node_ids =
nodes.node_ids_from_edge(index, (le < 6 ? p : q) - 1);
634 res.insert(res.end(), node_ids.begin(), node_ids.end());
637 assert(res.size() ==
size_t(6 + n_edge_nodes));
640 for (
int lf = 0; lf <
f.rows(); ++lf)
642 const auto index =
f[lf];
656 auto node_ids =
nodes.node_ids_from_face(index, lf < 2 ? (p - 2) : ((q - 1) * (p - 1)));
658 res.insert(res.end(), node_ids.begin(), node_ids.end());
661 assert(res.size() ==
size_t(6 + n_edge_nodes + n_face_nodes));
664 if (n_cell_nodes > 0)
669 const auto index =
f[0];
671 auto node_ids =
nodes.node_ids_from_cell(index, q - 1);
672 res.insert(res.end(), node_ids.begin(), node_ids.end());
675 assert(res.size() ==
size_t(6 + n_edge_nodes + n_face_nodes + n_cell_nodes));
694 const Eigen::VectorXi &discr_ordersp,
695 const Eigen::VectorXi &discr_ordersq,
696 const Eigen::VectorXi &edge_orders,
697 const Eigen::VectorXi &face_orders,
698 const bool serendipity,
699 const bool has_polys,
700 const bool is_geom_bases,
702 std::vector<std::vector<int>> &edge_virtual_nodes,
703 std::vector<std::vector<int>> &face_virtual_nodes,
704 std::vector<std::vector<int>> &element_nodes_id,
705 std::vector<LocalBoundary> &local_boundary,
706 std::map<int, InterfaceData> &poly_face_to_data)
709 local_boundary.clear();
711 element_nodes_id.resize(mesh.
n_faces());
715 const auto &ncmesh =
dynamic_cast<const NCMesh3D &
>(mesh);
716 edge_virtual_nodes.resize(ncmesh.n_edges());
717 face_virtual_nodes.resize(ncmesh.n_faces());
720 for (
int c = 0; c < mesh.
n_cells(); ++c)
722 const int discr_order = discr_ordersp(c);
723 const int discr_orderq = discr_ordersq(c);
727 hex_local_to_global(serendipity, discr_order, mesh, c, discr_ordersp, element_nodes_id[c], nodes);
729 auto v = hex_vertices_local_to_global(mesh, c);
730 Eigen::Matrix<int, 6, 4> fv;
731 fv.row(0) << v[0], v[3], v[4], v[7];
732 fv.row(1) << v[1], v[2], v[5], v[6];
733 fv.row(2) << v[0], v[1], v[5], v[4];
734 fv.row(3) << v[3], v[2], v[6], v[7];
735 fv.row(4) << v[0], v[1], v[2], v[3];
736 fv.row(5) << v[4], v[5], v[6], v[7];
739 for (
int i = 0; i < fv.rows(); ++i)
741 const int f = find_quad_face(mesh, c, fv(i, 0), fv(i, 1), fv(i, 2), fv(i, 3)).face;
745 lb.add_boundary_primitive(f, i);
750 local_boundary.emplace_back(lb);
755 tet_local_to_global(is_geom_bases, discr_order, mesh, c, discr_ordersp, edge_orders, face_orders, element_nodes_id[c], nodes, edge_virtual_nodes, face_virtual_nodes);
757 auto v = tet_vertices_local_to_global(mesh, c);
758 Eigen::Matrix<int, 4, 3> fv;
759 fv.row(0) << v[0], v[1], v[2];
760 fv.row(1) << v[0], v[1], v[3];
761 fv.row(2) << v[1], v[2], v[3];
762 fv.row(3) << v[2], v[0], v[3];
765 for (
long i = 0; i < fv.rows(); ++i)
771 lb.add_boundary_primitive(f, i);
776 local_boundary.emplace_back(lb);
781 prism_local_to_global(discr_order, discr_orderq, mesh, c, discr_ordersp, element_nodes_id[c], nodes);
783 auto v = prism_vertices_local_to_global(mesh, c);
784 Eigen::Matrix<int, 2, 3> fvt;
785 fvt.row(0) << v[0], v[1], v[2];
786 fvt.row(1) << v[3], v[4], v[5];
789 for (
long i = 0; i < fvt.rows(); ++i)
795 lb.add_boundary_primitive(f, i);
799 Eigen::Matrix<int, 3, 4> fvq;
800 fvq.row(0) << v[0], v[1], v[4], v[3];
801 fvq.row(1) << v[1], v[2], v[5], v[4];
802 fvq.row(2) << v[2], v[0], v[3], v[5];
804 for (
long i = 0; i < fvq.rows(); ++i)
806 const int f = find_quad_face(mesh, c, fvq(i, 0), fvq(i, 1), fvq(i, 2), fvq(i, 3)).face;
810 lb.add_boundary_primitive(f, i + 2);
815 local_boundary.emplace_back(lb);
824 for (
int c = 0; c < mesh.
n_cells(); ++c)
836 int c2 = index2.element;
839 const int discr_order = discr_ordersp(c2);
840 const int discr_orderq = discr_ordersq(c2);
859 poly_face_to_data[index2.face] = data;
869 void local_to_global(
const Eigen::MatrixXd &verts,
const Eigen::MatrixXd &uv, Eigen::MatrixXd &pts)
871 const int dim = verts.cols();
872 const int N = uv.rows();
874 assert(uv.cols() == dim);
875 assert(verts.rows() == dim + 1);
878 for (
int i = 0; i <
N; i++)
879 pts.row(i) = uv(i, 0) * verts.row(1) + uv(i, 1) * verts.row(2) + uv(i, 2) * verts.row(3) + (1.0 - uv(i, 0) - uv(i, 1) - uv(i, 2)) * verts.row(0);
882 void local_to_global_face(
const Eigen::MatrixXd &verts,
const Eigen::MatrixXd &uv, Eigen::MatrixXd &pts)
884 const int dim = verts.cols();
885 const int N = uv.rows();
887 assert(uv.cols() == 2);
888 assert(verts.rows() == 3);
891 for (
int i = 0; i <
N; i++)
892 pts.row(i) = uv(i, 0) * verts.row(1) + uv(i, 1) * verts.row(2) + (1.0 - uv(i, 0) - uv(i, 1)) * verts.row(0);
901 void global_to_local(
const Eigen::MatrixXd &verts,
const Eigen::MatrixXd &pts, Eigen::MatrixXd &uv)
903 const int dim = verts.cols();
904 const int N = pts.rows();
906 assert(verts.rows() == dim + 1);
907 assert(pts.cols() == dim);
910 for (
int i = 0; i <
dim; i++)
911 J.col(i) = verts.row(i + 1) - verts.row(0);
913 Eigen::Matrix3d Jinv = J.inverse();
917 for (
int i = start; i < end; i++)
919 auto point = pts.row(i) - verts.row(0);
920 uv.row(i) = Jinv * point.transpose();
925 void global_to_local_face(
const Eigen::MatrixXd &verts,
const Eigen::MatrixXd &pts, Eigen::MatrixXd &uv)
927 const int dim = verts.cols();
928 const int N = pts.rows();
930 assert(verts.rows() == 3);
931 assert(pts.cols() == dim);
934 for (
int i = 0; i < 2; i++)
935 J.col(i) = verts.row(i + 1) - verts.row(0);
937 Eigen::Vector3d a = J.col(0);
938 Eigen::Vector3d b = J.col(1);
939 Eigen::Vector3d virtual_vert = a.cross(b);
940 J.col(2) = virtual_vert;
944 for (
int i = start; i < end; i++)
946 auto point = pts.row(i) - verts.row(0);
947 Eigen::Vector3d
x = J.colPivHouseholderQr().solve(point.transpose());
948 uv.row(i) =
x.block(0, 0, 2, 1);
949 assert(std::abs(
x(2)) < 1e-8);
954 void global_to_local_edge(
const Eigen::MatrixXd &verts,
const Eigen::MatrixXd &pts, Eigen::VectorXd &uv)
956 const int dim = verts.cols();
957 const int N = pts.rows();
959 assert(verts.rows() == 2);
960 assert(pts.cols() == dim);
962 auto edge = verts.row(1) - verts.row(0);
963 double squared_length = edge.squaredNorm();
967 for (
int i = start; i < end; i++)
969 auto vec = pts.row(i) - verts.row(0);
970 uv(i) = (
vec.dot(edge)) / squared_length;
975 bool check_edge_face_orders(
const polyfem::mesh::NCMesh3D &mesh,
const Eigen::VectorXi &elem_orders,
const Eigen::VectorXi &edge_orders,
const Eigen::VectorXi &face_orders)
978 for (
int i = 0; i < mesh.
n_faces(); i++)
984 for (
int i = 0; i < mesh.
n_faces(); i++)
991 if (edge_orders[e_id] > face_orders[i])
997 for (
int i = 0; i < mesh.
n_edges(); i++)
1003 for (
int i = 0; i < mesh.
n_edges(); i++)
1021 void compute_edge_face_orders(
const polyfem::mesh::NCMesh3D &mesh,
const Eigen::VectorXi &elem_orders, Eigen::VectorXi &edge_orders, Eigen::VectorXi &face_orders)
1023 const int max_order = elem_orders.maxCoeff();
1024 edge_orders.setConstant(mesh.
n_edges(), max_order);
1025 face_orders.setConstant(mesh.
n_faces(), max_order);
1027 for (
int i = 0; i < mesh.
n_cells(); i++)
1029 face_orders[mesh.
cell_face(i, j)] = std::min(face_orders[mesh.
cell_face(i, j)], elem_orders[i]);
1031 for (
int i = 0; i < mesh.
n_cells(); i++)
1033 edge_orders[mesh.
cell_edge(i, j)] = std::min(edge_orders[mesh.
cell_edge(i, j)], elem_orders[i]);
1035 while (!check_edge_face_orders(mesh, elem_orders, edge_orders, face_orders))
1038 for (
int i = 0; i < mesh.
n_faces(); i++)
1042 for (
int i = 0; i < mesh.
n_faces(); i++)
1047 for (
int i = 0; i < mesh.
n_faces(); i++)
1054 edge_orders[e_id] = std::min(edge_orders[e_id], face_orders[i]);
1059 for (
int i = 0; i < mesh.
n_edges(); i++)
1063 for (
int i = 0; i < mesh.
n_edges(); i++)
1068 for (
int i = 0; i < mesh.
n_edges(); i++)
1081 const int nn = p > 2 ? (p - 2) : 0;
1082 const int n_edge_nodes = (p - 1) * 6;
1083 const int n_face_nodes = nn * (nn + 1) / 2;
1089 const auto l2g = tet_vertices_local_to_global(mesh, c);
1092 Eigen::VectorXi result(3 + (p - 1) * 3 + n_face_nodes);
1093 result[0] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1097 Eigen::Matrix<Navigation3D::Index, 6, 1> e;
1098 Eigen::Matrix<int, 6, 2> ev;
1099 ev.row(0) << l2g[0], l2g[1];
1100 ev.row(1) << l2g[1], l2g[2];
1101 ev.row(2) << l2g[2], l2g[0];
1103 ev.row(3) << l2g[0], l2g[3];
1104 ev.row(4) << l2g[1], l2g[3];
1105 ev.row(5) << l2g[2], l2g[3];
1109 for (
int le = 0; le < e.rows(); ++le)
1117 for (
int k = 0; k < 3; ++k)
1119 bool reverse =
false;
1121 for (; le < ev.rows(); ++le)
1125 const auto l_index = e[le];
1126 if (l_index.edge == tmp.edge)
1128 if (l_index.vertex == tmp.vertex)
1145 for (
int i = 0; i < p - 1; ++i)
1147 result[ii++] = 4 + le * (p - 1) + i;
1152 for (
int i = 0; i < p - 1; ++i)
1154 result[ii++] = 4 + (le + 1) * (p - 1) - i - 1;
1163 Eigen::Matrix<int, 4, 3> fv;
1164 fv.row(0) << l2g[0], l2g[1], l2g[2];
1165 fv.row(1) << l2g[0], l2g[1], l2g[3];
1166 fv.row(2) << l2g[1], l2g[2], l2g[3];
1167 fv.row(3) << l2g[2], l2g[0], l2g[3];
1170 for (; lf < fv.rows(); ++lf)
1173 if (l_index.face == index.
face)
1177 assert(lf < fv.rows());
1179 if (n_face_nodes == 0)
1182 else if (n_face_nodes == 1)
1183 result[ii++] = 4 + n_edge_nodes + lf;
1187 const auto get_order = [&p, &nn, &n_face_nodes](
const std::array<int, 3> &corners) {
1192 std::vector<int> order1(n_face_nodes);
1193 for (
int k = 0; k < n_face_nodes; ++k)
1196 std::vector<int> order2(n_face_nodes);
1199 for (
int k = 0; k < nn; ++k)
1201 for (
int l = 0; l < nn - k; ++l)
1203 order2[index] = start - l;
1206 start += (nn - 1) - k;
1209 std::vector<int> order3(n_face_nodes);
1211 for (
int k = 0; k < nn; ++k)
1214 for (
int l = 0; l < nn - k; ++l)
1216 order3[index] = offset;
1223 std::vector<int> order4(n_face_nodes);
1225 start = n_face_nodes - 1;
1226 for (
int k = 0; k < nn; ++k)
1229 for (
int l = 0; l < nn - k; ++l)
1231 order4[index] = start - offset;
1232 offset += k + 2 + l;
1239 std::vector<int> order5(n_face_nodes);
1242 for (
int k = 0; k < nn; ++k)
1245 for (
int l = 0; l < nn - k; ++l)
1247 order5[index] = start + offset;
1248 offset += nn - 1 - l;
1255 std::vector<int> order6(n_face_nodes);
1257 start = n_face_nodes;
1258 for (
int k = 0; k < nn; ++k)
1261 start = start - k - 1;
1262 for (
int l = 0; l < nn - k; ++l)
1264 order6[index] = start - offset;
1265 offset += l + 1 + k;
1270 if (corners[0] == order1[0] && corners[1] == order1[nn - 1])
1272 assert(corners[2] == order1[n_face_nodes - 1]);
1276 if (corners[0] == order2[0] && corners[1] == order2[nn - 1])
1278 assert(corners[2] == order2[n_face_nodes - 1]);
1282 if (corners[0] == order3[0] && corners[1] == order3[nn - 1])
1284 assert(corners[2] == order3[n_face_nodes - 1]);
1288 if (corners[0] == order4[0] && corners[1] == order4[nn - 1])
1290 assert(corners[2] == order4[n_face_nodes - 1]);
1294 if (corners[0] == order5[0] && corners[1] == order5[nn - 1])
1296 assert(corners[2] == order5[n_face_nodes - 1]);
1300 if (corners[0] == order6[0] && corners[1] == order6[nn - 1])
1302 assert(corners[2] == order6[n_face_nodes - 1]);
1310 Eigen::MatrixXd nodes;
1316 std::array<int, 3> idx;
1317 for (
int lv = 0; lv < 3; ++lv)
1319 idx[lv] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1322 Eigen::Matrix3d pos(3, 3);
1326 pos.row(cnt++) = nodes.row(i);
1329 const Eigen::RowVector3d bary = pos.colwise().mean();
1331 const int offset = 4 + n_edge_nodes;
1333 for (
int lff = 0; lff < 4; ++lff)
1335 Eigen::MatrixXd loc_nodes = nodes.block(offset + lff * n_face_nodes, 0, n_face_nodes, 3);
1336 Eigen::RowVector3d node_bary = loc_nodes.colwise().mean();
1338 if ((node_bary - bary).norm() < 1e-10)
1340 std::array<int, 3> corners;
1342 for (
int m = 0; m < 3; ++m)
1344 auto t = pos.row(m);
1346 double min_dis = 10000;
1348 for (
int n = 0; n < n_face_nodes; ++n)
1350 double dis = (loc_nodes.row(n) - t).squaredNorm();
1359 assert(min_n < n_face_nodes);
1363 const auto indices = get_order(corners);
1364 for (
int min_n : indices)
1367 result[ii++] = 4 + n_edge_nodes + min_n + lf * n_face_nodes;
1370 assert(sum == (n_face_nodes - 1) * n_face_nodes / 2);
1386 assert(ii == result.size());
1392 const int nn = q - 1;
1393 const int n_edge_nodes = nn * 12;
1394 const int n_face_nodes = serendipity ? 0 : nn * nn;
1400 const auto l2g = hex_vertices_local_to_global(mesh, c);
1403 Eigen::VectorXi result(4 + nn * 4 + n_face_nodes);
1404 result[0] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1409 Eigen::Matrix<Navigation3D::Index, 12, 1> e;
1410 Eigen::Matrix<int, 12, 2> ev;
1411 ev.row(0) << l2g[0], l2g[1];
1412 ev.row(1) << l2g[1], l2g[2];
1413 ev.row(2) << l2g[2], l2g[3];
1414 ev.row(3) << l2g[3], l2g[0];
1415 ev.row(4) << l2g[0], l2g[4];
1416 ev.row(5) << l2g[1], l2g[5];
1417 ev.row(6) << l2g[2], l2g[6];
1418 ev.row(7) << l2g[3], l2g[7];
1419 ev.row(8) << l2g[4], l2g[5];
1420 ev.row(9) << l2g[5], l2g[6];
1421 ev.row(10) << l2g[6], l2g[7];
1422 ev.row(11) << l2g[7], l2g[4];
1426 for (
int le = 0; le < e.rows(); ++le)
1433 for (
int k = 0; k < 4; ++k)
1435 bool reverse =
false;
1437 for (; le < ev.rows(); ++le)
1441 const auto l_index = e[le];
1442 if (l_index.edge == tmp.edge)
1444 if (l_index.vertex == tmp.vertex)
1460 for (
int i = 0; i < q - 1; ++i)
1462 result[ii++] = 8 + le * (q - 1) + i;
1467 for (
int i = 0; i < q - 1; ++i)
1469 result[ii++] = 8 + (le + 1) * (q - 1) - i - 1;
1478 Eigen::Matrix<int, 6, 4> fv;
1479 fv.row(0) << l2g[0], l2g[3], l2g[4], l2g[7];
1480 fv.row(1) << l2g[1], l2g[2], l2g[5], l2g[6];
1481 fv.row(2) << l2g[0], l2g[1], l2g[5], l2g[4];
1482 fv.row(3) << l2g[3], l2g[2], l2g[6], l2g[7];
1483 fv.row(4) << l2g[0], l2g[1], l2g[2], l2g[3];
1484 fv.row(5) << l2g[4], l2g[5], l2g[6], l2g[7];
1487 for (; lf < fv.rows(); ++lf)
1489 const auto l_index = find_quad_face(mesh, c, fv(lf, 0), fv(lf, 1), fv(lf, 2), fv(lf, 3));
1490 if (l_index.face == index.
face)
1494 assert(lf < fv.rows());
1496 if (n_face_nodes == 1)
1497 result[ii++] = 8 + n_edge_nodes + lf;
1498 else if (n_face_nodes != 0)
1500 Eigen::MatrixXd nodes;
1506 std::array<int, 4> idx;
1507 for (
int lv = 0; lv < 4; ++lv)
1509 idx[lv] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1512 Eigen::Matrix<double, 4, 3> pos(4, 3);
1516 pos.row(cnt++) = nodes.row(i);
1519 const Eigen::RowVector3d bary = pos.colwise().mean();
1521 const int offset = 8 + n_edge_nodes;
1523 for (
int lff = 0; lff < 6; ++lff)
1525 Eigen::Matrix<double, 4, 3> loc_nodes = nodes.block<4, 3>(offset + lff * n_face_nodes, 0);
1526 Eigen::RowVector3d node_bary = loc_nodes.colwise().mean();
1528 if ((node_bary - bary).norm() < 1e-10)
1531 for (
int m = 0; m < 4; ++m)
1533 auto t = pos.row(m);
1535 double min_dis = 10000;
1537 for (
int n = 0; n < 4; ++n)
1539 double dis = (loc_nodes.row(n) - t).squaredNorm();
1552 result[ii++] = 8 + n_edge_nodes + min_n + lf * n_face_nodes;
1568 assert(ii == result.size());
1578 const auto l2g = prism_vertices_local_to_global(mesh, c);
1580 const int global_n_edges_nodes = (p - 1) * 6 + (q - 1) * 3;
1584 const int nn = p > 2 ? (p - 2) : 0;
1585 const int n_edge_nodes = (p - 1) * 6;
1586 const int n_face_nodes = nn * (nn + 1) / 2;
1589 Eigen::VectorXi result(3 + (p - 1) * 3 + n_face_nodes);
1590 result[0] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1594 Eigen::Matrix<Navigation3D::Index, 6, 1> e;
1595 Eigen::Matrix<int, 6, 2> ev;
1596 ev.row(0) << l2g[0], l2g[1];
1597 ev.row(1) << l2g[1], l2g[2];
1598 ev.row(2) << l2g[2], l2g[0];
1600 ev.row(3) << l2g[3], l2g[4];
1601 ev.row(4) << l2g[4], l2g[5];
1602 ev.row(5) << l2g[5], l2g[3];
1606 for (
int le = 0; le < e.rows(); ++le)
1614 for (
int k = 0; k < 3; ++k)
1616 bool reverse =
false;
1618 for (; le < ev.rows(); ++le)
1622 const auto l_index = e[le];
1623 if (l_index.edge == tmp.edge)
1625 if (l_index.vertex == tmp.vertex)
1642 for (
int i = 0; i < p - 1; ++i)
1644 result[ii++] = 6 + le * (p - 1) + i;
1649 for (
int i = 0; i < p - 1; ++i)
1651 result[ii++] = 6 + (le + 1) * (p - 1) - i - 1;
1660 Eigen::Matrix<int, 2, 3> fv;
1661 fv.row(0) << l2g[0], l2g[1], l2g[2];
1662 fv.row(1) << l2g[3], l2g[4], l2g[5];
1665 for (; lf < fv.rows(); ++lf)
1668 if (l_index.face == index.
face)
1672 assert(lf < fv.rows());
1674 if (n_face_nodes == 0)
1677 else if (n_face_nodes == 1)
1678 result[ii++] = 6 + global_n_edges_nodes + lf;
1682 const auto get_order = [&p, &q, &nn, &n_face_nodes](
const std::array<int, 3> &corners) {
1687 std::vector<int> order1(n_face_nodes);
1688 for (
int k = 0; k < n_face_nodes; ++k)
1691 std::vector<int> order2(n_face_nodes);
1694 for (
int k = 0; k < nn; ++k)
1696 for (
int l = 0; l < nn - k; ++l)
1698 order2[index] = start - l;
1701 start += (nn - 1) - k;
1704 std::vector<int> order3(n_face_nodes);
1706 for (
int k = 0; k < nn; ++k)
1709 for (
int l = 0; l < nn - k; ++l)
1711 order3[index] = offset;
1718 std::vector<int> order4(n_face_nodes);
1720 start = n_face_nodes - 1;
1721 for (
int k = 0; k < nn; ++k)
1724 for (
int l = 0; l < nn - k; ++l)
1726 order4[index] = start - offset;
1727 offset += k + 2 + l;
1734 std::vector<int> order5(n_face_nodes);
1737 for (
int k = 0; k < nn; ++k)
1740 for (
int l = 0; l < nn - k; ++l)
1742 order5[index] = start + offset;
1743 offset += nn - 1 - l;
1750 std::vector<int> order6(n_face_nodes);
1752 start = n_face_nodes;
1753 for (
int k = 0; k < nn; ++k)
1756 start = start - k - 1;
1757 for (
int l = 0; l < nn - k; ++l)
1759 order6[index] = start - offset;
1760 offset += l + 1 + k;
1765 if (corners[0] == order1[0] && corners[1] == order1[nn - 1])
1767 assert(corners[2] == order1[n_face_nodes - 1]);
1771 if (corners[0] == order2[0] && corners[1] == order2[nn - 1])
1773 assert(corners[2] == order2[n_face_nodes - 1]);
1777 if (corners[0] == order3[0] && corners[1] == order3[nn - 1])
1779 assert(corners[2] == order3[n_face_nodes - 1]);
1783 if (corners[0] == order4[0] && corners[1] == order4[nn - 1])
1785 assert(corners[2] == order4[n_face_nodes - 1]);
1789 if (corners[0] == order5[0] && corners[1] == order5[nn - 1])
1791 assert(corners[2] == order5[n_face_nodes - 1]);
1795 if (corners[0] == order6[0] && corners[1] == order6[nn - 1])
1797 assert(corners[2] == order6[n_face_nodes - 1]);
1805 Eigen::MatrixXd nodes;
1811 std::array<int, 3> idx;
1812 for (
int lv = 0; lv < 3; ++lv)
1814 idx[lv] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1817 Eigen::Matrix3d pos(3, 3);
1821 pos.row(cnt++) = nodes.row(i);
1824 const Eigen::RowVector3d bary = pos.colwise().mean();
1826 const int offset = 6 + global_n_edges_nodes;
1828 for (
int lff = 0; lff < 2; ++lff)
1830 Eigen::MatrixXd loc_nodes = nodes.block(offset + lff * n_face_nodes, 0, n_face_nodes, 3);
1831 Eigen::RowVector3d node_bary = loc_nodes.colwise().mean();
1833 if ((node_bary - bary).norm() < 1e-10)
1835 std::array<int, 3> corners;
1837 for (
int m = 0; m < 3; ++m)
1839 auto t = pos.row(m);
1841 double min_dis = 10000;
1843 for (
int n = 0; n < n_face_nodes; ++n)
1845 double dis = (loc_nodes.row(n) - t).squaredNorm();
1854 assert(min_n < n_face_nodes);
1858 const auto indices = get_order(corners);
1859 for (
int min_n : indices)
1862 result[ii++] = 6 + global_n_edges_nodes + min_n + lf * n_face_nodes;
1865 assert(sum == (n_face_nodes - 1) * n_face_nodes / 2);
1881 assert(ii == result.size());
1886 const int nn = q - 1;
1887 const int n_edge_nodes = nn * 12;
1888 const int n_face_nodes = nn * nn;
1891 Eigen::VectorXi result(4 + nn * 4 + n_face_nodes);
1892 result[0] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1897 Eigen::Matrix<Navigation3D::Index, 9, 1> e;
1898 Eigen::Matrix<int, 9, 2> ev;
1899 ev.row(0) << l2g[0], l2g[1];
1900 ev.row(1) << l2g[1], l2g[2];
1901 ev.row(2) << l2g[2], l2g[0];
1903 ev.row(3) << l2g[3], l2g[4];
1904 ev.row(4) << l2g[4], l2g[5];
1905 ev.row(5) << l2g[5], l2g[3];
1907 ev.row(6) << l2g[0], l2g[3];
1908 ev.row(7) << l2g[1], l2g[4];
1909 ev.row(8) << l2g[2], l2g[5];
1913 for (
int le = 0; le < e.rows(); ++le)
1920 for (
int k = 0; k < 4; ++k)
1922 bool reverse =
false;
1924 for (; le < ev.rows(); ++le)
1928 const auto l_index = e[le];
1929 if (l_index.edge == tmp.edge)
1931 if (l_index.vertex == tmp.vertex)
1947 for (
int i = 0; i < q - 1; ++i)
1949 result[ii++] = 6 + le * (q - 1) + i;
1954 for (
int i = 0; i < q - 1; ++i)
1956 result[ii++] = 6 + (le + 1) * (q - 1) - i - 1;
1965 Eigen::Matrix<int, 3, 4> fv;
1966 fv.row(0) << l2g[0], l2g[3], l2g[4], l2g[1];
1967 fv.row(1) << l2g[1], l2g[4], l2g[5], l2g[2];
1968 fv.row(2) << l2g[2], l2g[5], l2g[3], l2g[0];
1971 for (; lf < fv.rows(); ++lf)
1973 const auto l_index = find_quad_face(mesh, c, fv(lf, 0), fv(lf, 1), fv(lf, 2), fv(lf, 3));
1974 if (l_index.face == index.
face)
1978 assert(lf < fv.rows());
1980 if (n_face_nodes == 1)
1981 result[ii++] = 6 + global_n_edges_nodes + lf;
1982 else if (n_face_nodes != 0)
1984 Eigen::MatrixXd nodes;
1990 std::array<int, 4> idx;
1991 for (
int lv = 0; lv < 4; ++lv)
1993 idx[lv] = find_index(l2g.begin(), l2g.end(), index.
vertex);
1996 Eigen::Matrix<double, 4, 3> pos(4, 3);
2000 pos.row(cnt++) = nodes.row(i);
2003 const Eigen::RowVector3d bary = pos.colwise().mean();
2005 const int offset = 8 + n_edge_nodes;
2007 for (
int lff = 0; lff < 6; ++lff)
2009 Eigen::Matrix<double, 4, 3> loc_nodes = nodes.block<4, 3>(offset + lff * n_face_nodes, 0);
2010 Eigen::RowVector3d node_bary = loc_nodes.colwise().mean();
2012 if ((node_bary - bary).norm() < 1e-10)
2015 for (
int m = 0; m < 4; ++m)
2017 auto t = pos.row(m);
2019 double min_dis = 10000;
2021 for (
int n = 0; n < 4; ++n)
2023 double dis = (loc_nodes.row(n) - t).squaredNorm();
2036 result[ii++] = 8 + n_edge_nodes + min_n + lf * n_face_nodes;
2052 assert(ii == result.size());
2059 const std::string &assembler,
2060 const int quadrature_order,
2061 const int mass_quadrature_order,
2062 const int discr_orderp,
2063 const int discr_orderq,
2064 const bool bernstein,
2065 const bool serendipity,
2066 const bool has_polys,
2067 const bool is_geom_bases,
2068 const bool use_corner_quadrature,
2069 std::vector<ElementBases> &bases,
2070 std::vector<LocalBoundary> &local_boundary,
2071 std::map<int, InterfaceData> &poly_face_to_data,
2072 std::shared_ptr<MeshNodes> &mesh_nodes)
2074 Eigen::VectorXi discr_ordersp(mesh.
n_cells());
2075 discr_ordersp.setConstant(discr_orderp);
2077 Eigen::VectorXi discr_ordersq(mesh.
n_cells());
2078 discr_ordersq.setConstant(discr_orderq);
2080 return build_bases(mesh, assembler, quadrature_order, mass_quadrature_order, discr_ordersp, discr_ordersq, bernstein, serendipity, has_polys, is_geom_bases, use_corner_quadrature, bases, local_boundary, poly_face_to_data, mesh_nodes);
2085 const std::string &assembler,
2086 const int quadrature_order,
2087 const int mass_quadrature_order,
2088 const Eigen::VectorXi &discr_ordersp,
2089 const Eigen::VectorXi &discr_ordersq,
2090 const bool bernstein,
2091 const bool serendipity,
2092 const bool has_polys,
2093 const bool is_geom_bases,
2094 const bool use_corner_quadrature,
2095 std::vector<ElementBases> &bases,
2096 std::vector<LocalBoundary> &local_boundary,
2097 std::map<int, InterfaceData> &poly_face_to_data,
2098 std::shared_ptr<MeshNodes> &mesh_nodes)
2101 assert(discr_ordersp.size() == mesh.
n_cells());
2102 assert(discr_ordersq.size() == mesh.
n_cells());
2110 const int max_p = discr_ordersp.maxCoeff();
2111 const int max_q = discr_ordersq.maxCoeff();
2112 const int mmax = std::max(max_p, max_q);
2115 const int nn = mmax > 1 ? (mmax - 1) : 0;
2116 const int n_face_nodes = nn * nn;
2117 const int n_cells_nodes = nn * nn * nn;
2119 Eigen::VectorXi edge_orders, face_orders;
2122 const auto &ncmesh =
dynamic_cast<const NCMesh3D &
>(mesh);
2123 compute_edge_face_orders(ncmesh, discr_ordersp, edge_orders, face_orders);
2126 mesh_nodes = std::make_shared<MeshNodes>(mesh, has_polys, !is_geom_bases, nn, n_face_nodes * (is_geom_bases ? 2 : 1), mmax == 0 ? 1 : n_cells_nodes);
2128 std::vector<std::vector<int>> element_nodes_id, edge_virtual_nodes, face_virtual_nodes;
2129 compute_nodes(mesh, discr_ordersp, discr_ordersq, edge_orders, face_orders, serendipity, has_polys, is_geom_bases, nodes, edge_virtual_nodes, face_virtual_nodes, element_nodes_id, local_boundary, poly_face_to_data);
2133 std::vector<int> interface_elements;
2134 interface_elements.reserve(mesh.
n_faces());
2136 for (
int e = 0; e < mesh.
n_cells(); ++e)
2139 const int discr_order = discr_ordersp(e);
2140 const int discr_orderq = discr_ordersq(e);
2141 const int n_el_bases = (int)element_nodes_id[e].size();
2142 b.
bases.resize(n_el_bases);
2144 bool skip_interface_element =
false;
2146 for (
int j = 0; j < n_el_bases; ++j)
2148 const int global_index = element_nodes_id[e][j];
2149 if (global_index < 0)
2151 skip_interface_element =
true;
2156 if (skip_interface_element)
2158 interface_elements.push_back(e);
2163 const int real_order = quadrature_order > 0 ? quadrature_order :
AssemblerUtils::quadrature_order(assembler, discr_order, AssemblerUtils::BasisType::CUBE_LAGRANGE, 3);
2164 const int real_mass_order = mass_quadrature_order > 0 ? mass_quadrature_order :
AssemblerUtils::quadrature_order(
"Mass", discr_order, AssemblerUtils::BasisType::CUBE_LAGRANGE, 3);
2175 const auto &mesh3d =
dynamic_cast<const Mesh3D &
>(mesh);
2178 for (
int lf = 0; lf < 6; ++lf)
2180 index = mesh3d.get_index_from_element(e, lf, 0);
2181 if (index.
face == primitive_id)
2184 assert(index.
face == primitive_id);
2188 for (
int j = 0; j < n_el_bases; ++j)
2190 const int global_index = element_nodes_id[
e][j];
2192 b.
bases[j].init(discr_order, global_index, j,
nodes.node_position(global_index));
2194 const int dtmp = serendipity ? -2 : discr_order;
2202 const int real_order = quadrature_order > 0 ? quadrature_order :
AssemblerUtils::quadrature_order(assembler, discr_order, AssemblerUtils::BasisType::SIMPLEX_LAGRANGE, 3);
2203 const int real_mass_order = mass_quadrature_order > 0 ? mass_quadrature_order :
AssemblerUtils::quadrature_order(
"Mass", discr_order, AssemblerUtils::BasisType::SIMPLEX_LAGRANGE, 3);
2207 tet_quadrature.get_quadrature(real_order, quad);
2211 tet_quadrature.get_quadrature(real_mass_order, quad);
2215 const auto &mesh3d =
dynamic_cast<const Mesh3D &
>(mesh);
2218 for (
int lf = 0; lf < mesh3d.n_cell_faces(e); ++lf)
2220 index = mesh3d.get_index_from_element(e, lf, 0);
2221 if (index.
face == primitive_id)
2224 assert(index.
face == primitive_id);
2231 for (
int j = 0; j < n_el_bases; ++j)
2233 const int global_index = element_nodes_id[
e][j];
2234 if (!skip_interface_element)
2236 b.
bases[j].init(discr_order, global_index, j,
nodes.node_position(global_index));
2245 const int orderp = quadrature_order > 0 ? quadrature_order :
AssemblerUtils::quadrature_order(assembler, discr_order, AssemblerUtils::BasisType::PRISM_LAGRANGE, 2);
2246 const int orderq = quadrature_order > 0 ? quadrature_order :
AssemblerUtils::quadrature_order(assembler, discr_orderq, AssemblerUtils::BasisType::PRISM_LAGRANGE, 1);
2248 const int mass_orderp = mass_quadrature_order > 0 ? mass_quadrature_order :
AssemblerUtils::quadrature_order(
"Mass", discr_order, AssemblerUtils::BasisType::PRISM_LAGRANGE, 2);
2249 const int mass_orderq = mass_quadrature_order > 0 ? mass_quadrature_order :
AssemblerUtils::quadrature_order(
"Mass", discr_orderq, AssemblerUtils::BasisType::PRISM_LAGRANGE, 1);
2261 const auto &mesh3d =
dynamic_cast<const Mesh3D &
>(mesh);
2264 for (
int lf = 0; lf < mesh3d.n_cell_faces(e); ++lf)
2266 index = mesh3d.get_index_from_element(e, lf, 0);
2267 if (index.
face == primitive_id)
2270 assert(index.
face == primitive_id);
2274 for (
int j = 0; j < n_el_bases; ++j)
2276 const int global_index = element_nodes_id[
e][j];
2277 if (!skip_interface_element)
2279 b.
bases[j].init(discr_order, global_index, j,
nodes.node_position(global_index));
2297 const auto &ncmesh =
dynamic_cast<const NCMesh3D &
>(mesh);
2299 std::vector<std::vector<int>> elementOrder;
2301 const int max_order = discr_ordersp.maxCoeff(), min_order = discr_ordersp.minCoeff();
2303 for (
int e = 0;
e < ncmesh.n_cells();
e++)
2304 if (max_level < ncmesh.cell_ref_level(e))
2307 elementOrder.resize((max_level + 1) * (max_order - min_order + 1));
2310 while (cur_level <= max_level)
2312 int order = min_order;
2313 while (order <= max_order)
2315 int cur_bucket = (max_order - min_order + 1) * cur_level + (order - min_order);
2316 for (
int i = 0; i < ncmesh.n_cells(); i++)
2318 if (ncmesh.cell_ref_level(i) != cur_level || discr_ordersp[i] != order)
2322 elementOrder[cur_bucket].push_back(i);
2330 for (
const auto &bucket : elementOrder)
2332 if (bucket.size() == 0)
2335 for (int e_aux = start; e_aux < end; e_aux++)
2337 const int e = bucket[e_aux];
2338 ElementBases &b = bases[e];
2339 const int discr_order = discr_ordersp(e);
2340 const int n_edge_nodes = discr_order - 1;
2341 const int n_face_nodes = (discr_order - 1) * (discr_order - 2) / 2;
2342 const int n_el_bases = element_nodes_id[e].size();
2344 auto v = tet_vertices_local_to_global(mesh, e);
2346 Eigen::Matrix<Navigation3D::Index, 4, 1> cell_faces;
2347 Eigen::Matrix<int, 4, 3> fv;
2348 fv.row(0) << v[0], v[1], v[2];
2349 fv.row(1) << v[0], v[1], v[3];
2350 fv.row(2) << v[1], v[2], v[3];
2351 fv.row(3) << v[2], v[0], v[3];
2353 for (long lf = 0; lf < fv.rows(); ++lf)
2355 const auto index = mesh.get_index_from_element_face(e, fv(lf, 0), fv(lf, 1), fv(lf, 2));
2356 cell_faces[lf] = index;
2359 Eigen::Matrix<Navigation3D::Index, 6, 1> cell_edges;
2360 Eigen::Matrix<int, 6, 2> ev;
2361 ev.row(0) << v[0], v[1];
2362 ev.row(1) << v[1], v[2];
2363 ev.row(2) << v[2], v[0];
2365 ev.row(3) << v[0], v[3];
2366 ev.row(4) << v[1], v[3];
2367 ev.row(5) << v[2], v[3];
2369 for (int le = 0; le < ev.rows(); ++le)
2372 const auto index = mesh.get_index_from_element_edge(e, ev(le, 0), ev(le, 1));
2373 cell_edges[le] = index;
2376 Eigen::MatrixXd verts(4, 3);
2377 for (int i = 0; i < ncmesh.n_cell_vertices(e); i++)
2378 verts.row(i) = ncmesh.point(v[i]);
2380 for (int j = 0; j < n_el_bases; ++j)
2382 const int global_index = element_nodes_id[e][j];
2384 if (global_index >= 0)
2386 b.bases[j].init(discr_order, global_index, j, nodes.node_position(global_index));
2393 int large_elem = -1;
2394 if (ncmesh.leader_edge_of_vertex(v[j]) >= 0)
2396 large_elem = lowest_order_elem_on_edge(ncmesh, discr_ordersp, ncmesh.leader_edge_of_vertex(v[j]));
2398 else if (ncmesh.leader_face_of_vertex(v[j]) >= 0)
2400 std::vector<int> ids;
2401 ncmesh.get_face_elements_neighs(ncmesh.leader_face_of_vertex(v[j]), ids);
2402 assert(ids.size() == 1);
2403 large_elem = ids[0];
2408 Eigen::MatrixXd large_elem_verts(4, 3);
2409 auto v_large = tet_vertices_local_to_global(mesh, large_elem);
2410 for (int i = 0; i < ncmesh.n_cell_vertices(large_elem); i++)
2411 large_elem_verts.row(i) = ncmesh.point(v_large[i]);
2413 Eigen::MatrixXd node_position;
2414 global_to_local(large_elem_verts, verts.row(j), node_position);
2417 const auto &other_bases = bases[large_elem];
2418 std::vector<AssemblyValues> w;
2419 other_bases.evaluate_bases(node_position, w);
2422 for (long i = 0; i < w.size(); ++i)
2424 assert(w[i].val.size() == 1);
2425 if (std::abs(w[i].val(0)) < 1e-12)
2428 assert(other_bases.bases[i].global().size() > 0);
2429 for (size_t ii = 0; ii < other_bases.bases[i].global().size(); ++ii)
2431 const auto &other_global = other_bases.bases[i].global()[ii];
2432 assert(other_global.index >= 0);
2433 b.bases[j].global().emplace_back(other_global.index, other_global.node, w[i].val(0) * other_global.val);
2438 else if (j < 4 + 6 * n_edge_nodes)
2440 const int local_edge_id = (j - 4) / n_edge_nodes;
2441 const int edge_id = cell_edges[local_edge_id].edge;
2442 bool need_extra_fake_nodes = false;
2443 int large_elem = -1;
2446 if (ncmesh.leader_edge_of_edge(edge_id) >= 0)
2448 std::vector<int> ids;
2449 ncmesh.get_edge_elements_neighs(ncmesh.leader_edge_of_edge(edge_id), ids);
2450 large_elem = ids[0];
2453 else if (ncmesh.leader_face_of_edge(edge_id) >= 0)
2455 std::vector<int> ids;
2456 ncmesh.get_face_elements_neighs(ncmesh.leader_face_of_edge(edge_id), ids);
2457 assert(ids.size() == 1);
2458 large_elem = ids[0];
2461 else if (discr_order > edge_orders[edge_id])
2463 int min_order_elem = lowest_order_elem_on_edge(ncmesh, discr_ordersp, edge_id);
2465 if (discr_ordersp[min_order_elem] < discr_order)
2466 large_elem = min_order_elem;
2472 need_extra_fake_nodes = true;
2478 assert(large_elem >= 0 || need_extra_fake_nodes);
2479 Eigen::MatrixXd lnodes;
2480 autogen::p_nodes_3d(discr_order, lnodes);
2481 Eigen::MatrixXd local_position = lnodes.row(j);
2482 if (need_extra_fake_nodes)
2484 Eigen::MatrixXd global_position, edge_verts(2, 3);
2485 Eigen::VectorXd point_weight;
2487 edge_verts.row(0) = ncmesh.point(ncmesh.edge_vertex(edge_id, 0));
2488 edge_verts.row(1) = ncmesh.point(ncmesh.edge_vertex(edge_id, 1));
2490 local_to_global(verts, local_position, global_position);
2491 global_to_local_edge(edge_verts, global_position, point_weight);
2493 std::function<double(const int, const int, const double)> basis_1d = [](const int order, const int id, const double x) -> double {
2494 assert(id <= order && id >= 0);
2496 for (int o = 0; o <= order; o++)
2499 y *= (x * order - o) / (id - o);
2505 for (int i = 0; i < edge_virtual_nodes[edge_id].size(); i++)
2507 const int global_index = edge_virtual_nodes[edge_id][i];
2509 Eigen::VectorXd node_weight;
2510 global_to_local_edge(edge_verts, nodes.node_position(global_index), node_weight);
2511 const int basis_id = std::lround(node_weight(0) * edge_orders[edge_id]);
2512 const double weight = basis_1d(edge_orders[edge_id], basis_id, point_weight(0));
2513 if (std::abs(weight) < 1e-12)
2515 b.bases[j].global().emplace_back(global_index, nodes.node_position(global_index), weight);
2519 for (int i = 0; i < 2; i++)
2521 const int lv = ev(local_edge_id, i);
2522 const auto &global_ = b.bases[lv].global();
2523 Eigen::VectorXd node_weight;
2524 global_to_local_edge(edge_verts, verts.row(lv), node_weight);
2525 const int basis_id = std::lround(node_weight(0) * edge_orders[edge_id]);
2526 const double weight = basis_1d(edge_orders[edge_id], basis_id, point_weight(0));
2527 if (std::abs(weight) > 1e-12)
2529 assert(global_.size() > 0);
2530 for (size_t ii = 0; ii < global_.size(); ++ii)
2531 b.bases[j].global().emplace_back(global_[ii].index, global_[ii].node, weight * global_[ii].val);
2537 Eigen::MatrixXd global_position, large_elem_verts(4, 3);
2538 auto v_large = tet_vertices_local_to_global(mesh, large_elem);
2539 for (int i = 0; i < ncmesh.n_cell_vertices(large_elem); i++)
2540 large_elem_verts.row(i) = ncmesh.point(v_large[i]);
2541 local_to_global(verts, local_position, global_position);
2542 global_to_local(large_elem_verts, global_position, local_position);
2545 const auto &other_bases = bases[large_elem];
2546 std::vector<AssemblyValues> w;
2547 other_bases.evaluate_bases(local_position, w);
2550 for (long i = 0; i < w.size(); ++i)
2552 assert(w[i].val.size() == 1);
2553 if (std::abs(w[i].val(0)) < 1e-12)
2556 assert(other_bases.bases[i].global().size() > 0);
2557 for (size_t ii = 0; ii < other_bases.bases[i].global().size(); ++ii)
2559 const auto &other_global = other_bases.bases[i].global()[ii];
2560 assert(other_global.index >= 0);
2561 b.bases[j].global().emplace_back(other_global.index, other_global.node, w[i].val(0) * other_global.val);
2567 else if (j < 4 + 6 * n_edge_nodes + 4 * n_face_nodes)
2569 const int local_face_id = (j - (4 + 6 * n_edge_nodes)) / n_face_nodes;
2570 const int face_id = cell_faces(local_face_id).face;
2571 int large_elem = -1;
2572 bool need_extra_fake_nodes = false;
2574 std::vector<int> ids;
2575 ncmesh.get_face_elements_neighs(ncmesh.leader_face_of_face(face_id), ids);
2577 Eigen::MatrixXd face_verts(3, 3);
2578 for (int i = 0; i < ncmesh.n_face_vertices(face_id); i++)
2579 face_verts.row(i) = ncmesh.point(ncmesh.face_vertex(face_id, i));
2582 if (ncmesh.leader_face_of_face(face_id) >= 0)
2584 assert(ids.size() == 1);
2585 large_elem = ids[0];
2589 else if (face_orders[face_id] < discr_order && ids.size() == 2)
2591 large_elem = ids[0] == e ? ids[1] : ids[0];
2594 else if (face_orders[face_id] < discr_order && ncmesh.n_follower_faces(face_id) > 0)
2597 need_extra_fake_nodes = true;
2602 assert(large_elem >= 0 || need_extra_fake_nodes);
2603 Eigen::MatrixXd lnodes;
2604 autogen::p_nodes_3d(discr_order, lnodes);
2605 Eigen::MatrixXd local_position = lnodes.row(j);
2606 if (need_extra_fake_nodes)
2608 Eigen::MatrixXd global_position;
2609 local_to_global(verts, local_position, global_position);
2611 Eigen::MatrixXd tmp;
2612 global_to_local_face(face_verts, global_position, tmp);
2613 Eigen::VectorXd face_weight = tmp.transpose();
2615 std::function<double(const int, const int, const double)> basis_aux = [](const int order, const int id, const double x) -> double {
2616 assert(id <= order && id >= 0);
2618 for (int o = 0; o < id; o++)
2619 y *= (x * order - o) / (id - o);
2623 std::function<double(const int, const int, const int, const Eigen::Vector2d)> basis_2d = [&basis_aux](const int order, const int i, const int j, const Eigen::Vector2d uv) -> double {
2624 assert(i + j <= order && i >= 0 && j >= 0);
2625 double u = uv(0), v = uv(1);
2626 return basis_aux(order, i, u) * basis_aux(order, j, v) * basis_aux(order, order - i - j, 1 - u - v);
2630 for (int global_ : face_virtual_nodes[face_id])
2632 auto low_order_node = nodes.node_position(global_);
2633 Eigen::MatrixXd low_order_node_face_weight;
2634 global_to_local_face(face_verts, low_order_node, low_order_node_face_weight);
2635 int x = round(low_order_node_face_weight(0) * face_orders[face_id]), y = round(low_order_node_face_weight(1) * face_orders[face_id]);
2636 const double weight = basis_2d(face_orders[face_id], x, y, face_weight);
2637 if (std::abs(weight) < 1e-12)
2639 b.bases[j].global().emplace_back(global_, nodes.node_position(global_), weight);
2643 for (int i = 0; i < 3; i++)
2645 const auto &global_ = b.bases[fv(local_face_id, i)].global();
2646 auto low_order_node = ncmesh.point(fv(local_face_id, i));
2647 Eigen::MatrixXd low_order_node_face_weight;
2648 global_to_local_face(face_verts, low_order_node, low_order_node_face_weight);
2649 int x = round(low_order_node_face_weight(0) * face_orders[face_id]), y = round(low_order_node_face_weight(1) * face_orders[face_id]);
2650 double weight = basis_2d(face_orders[face_id], x, y, face_weight);
2651 if (std::abs(weight) > 1e-12)
2653 assert(global_.size() > 0);
2654 for (size_t ii = 0; ii < global_.size(); ++ii)
2655 b.bases[j].global().emplace_back(global_[ii].index, global_[ii].node, weight * global_[ii].val);
2660 for (int x = 0, idx = 0; x <= face_orders[face_id]; x++)
2662 for (int y = 0; x + y <= face_orders[face_id]; y++)
2664 const int z = face_orders[face_id] - x - y;
2665 int flag = (int)(x == 0) + (int)(y == 0) + (int)(z == 0);
2670 const double weight = basis_2d(face_orders[face_id], x, y, face_weight);
2671 if (std::abs(weight) < 1e-12)
2673 Eigen::MatrixXd face_weight(1, 2);
2674 face_weight << (double)x / face_orders[face_id], (double)y / face_orders[face_id];
2675 Eigen::MatrixXd pos, local_pos;
2676 local_to_global_face(face_verts, face_weight, pos);
2677 global_to_local(verts, pos, local_pos);
2678 Local2Global step1(idx, local_pos, weight);
2683 const auto &other_bases = bases[e];
2684 std::vector<AssemblyValues> w;
2685 other_bases.evaluate_bases(local_pos, w);
2688 for (long i = 0; i < w.size(); ++i)
2690 assert(w[i].val.size() == 1);
2691 if (std::abs(w[i].val(0)) < 1e-12)
2694 assert(other_bases.bases[i].global().size() > 0);
2695 for (size_t ii = 0; ii < other_bases.bases[i].global().size(); ++ii)
2697 const auto &other_global = other_bases.bases[i].global()[ii];
2698 assert(other_global.index >= 0);
2699 b.bases[j].global().emplace_back(other_global.index, other_global.node, step1.val * w[i].val(0) * other_global.val);
2708 Eigen::MatrixXd global_position, large_elem_verts(4, 3);
2709 auto v_large = tet_vertices_local_to_global(mesh, large_elem);
2710 for (int i = 0; i < ncmesh.n_cell_vertices(large_elem); i++)
2711 large_elem_verts.row(i) = ncmesh.point(v_large[i]);
2712 local_to_global(verts, local_position, global_position);
2713 global_to_local(large_elem_verts, global_position, local_position);
2716 const auto &other_bases = bases[large_elem];
2717 std::vector<AssemblyValues> w;
2718 other_bases.evaluate_bases(local_position, w);
2721 for (long i = 0; i < w.size(); ++i)
2723 assert(w[i].val.size() == 1);
2724 if (std::abs(w[i].val(0)) < 1e-12)
2727 assert(other_bases.bases[i].global().size() > 0);
2728 for (size_t ii = 0; ii < other_bases.bases[i].global().size(); ++ii)
2730 const auto &other_global = other_bases.bases[i].global()[ii];
2731 assert(other_global.index >= 0);
2732 b.bases[j].global().emplace_back(other_global.index, other_global.node, w[i].val(0) * other_global.val);
2740 auto &global_ = b.bases[j].global();
2741 if (global_.size() <= 1)
2744 std::map<int, Local2Global> list;
2745 for (size_t ii = 0; ii < global_.size(); ii++)
2747 auto pair = list.insert({global_[ii].index, global_[ii]});
2748 if (!pair.second && pair.first != list.end())
2750 assert((pair.first->second.node - global_[ii].node).norm() < 1e-12);
2751 pair.first->second.val += global_[ii].val;
2756 for (auto it = list.begin(); it != list.end(); ++it)
2758 if (std::abs(it->second.val) > 1e-12)
2760 global_.push_back(it->second);
2771 for (
int pp = 2; pp <= autogen::MAX_P_BASES; ++pp)
2773 for (
int e : interface_elements)
2777 const int discr_order = discr_ordersp(e);
2778 const int n_el_bases = element_nodes_id[
e].size();
2779 assert(discr_order > 1);
2780 if (discr_order != pp)
2790 for (
int j = 0; j < n_el_bases; ++j)
2792 const int global_index = element_nodes_id[
e][j];
2794 if (global_index >= 0)
2795 b.
bases[j].init(discr_order, global_index, j,
nodes.node_position(global_index));
2798 const int lnn = max_p > 2 ? (discr_order - 2) : 0;
2799 const int ln_edge_nodes = discr_order - 1;
2800 const int ln_face_nodes = lnn * (lnn + 1) / 2;
2802 const auto v = tet_vertices_local_to_global(mesh, e);
2804 if (global_index <= -30)
2828 else if (global_index <= -10)
2830 const auto le = -(global_index + 10);
2831 assert(le >= 0 && le < 6);
2832 assert(j >= 4 && j < 4 + 6 * ln_edge_nodes);
2834 Eigen::Matrix<int, 6, 2> ev;
2835 ev.row(0) << v[0], v[1];
2836 ev.row(1) << v[1], v[2];
2837 ev.row(2) << v[2], v[0];
2839 ev.row(3) << v[0], v[3];
2840 ev.row(4) << v[1], v[3];
2841 ev.row(5) << v[2], v[3];
2844 const auto edge_index = mesh.get_index_from_element_edge(e, ev(le, 0), ev(le, 1));
2845 auto neighs = mesh.edge_neighs(edge_index.edge);
2846 int min_p = discr_order;
2847 int min_cell = edge_index.element;
2849 for (
auto cid : neighs)
2851 if (discr_ordersp[cid] < min_p)
2853 min_p = discr_ordersp[cid];
2859 for (
int lf = 0; lf < 4; ++lf)
2861 for (
int lv = 0; lv < 4; ++lv)
2863 index = mesh.get_index_from_element(min_cell, lf, lv);
2865 if (index.
vertex == edge_index.vertex)
2867 if (index.
edge != edge_index.edge)
2870 index = mesh.switch_edge(tmp);
2872 if (index.
edge != edge_index.edge)
2874 index = mesh.switch_edge(mesh.switch_face(tmp));
2887 assert(index.
vertex == edge_index.vertex && index.
edge == edge_index.edge);
2888 assert(index.
element != edge_index.element);
2892 const auto lf = -(global_index + 1);
2893 assert(lf >= 0 && lf < 4);
2894 assert(j >= 4 + 6 * ln_edge_nodes && j < 4 + 6 * ln_edge_nodes + 4 * ln_face_nodes);
2896 Eigen::Matrix<int, 4, 3> fv;
2897 fv.row(0) << v[0], v[1], v[2];
2898 fv.row(1) << v[0], v[1], v[3];
2899 fv.row(2) << v[1], v[2], v[3];
2900 fv.row(3) << v[2], v[0], v[3];
2902 index = mesh.switch_element(mesh.get_index_from_element_face(e, fv(lf, 0), fv(lf, 1), fv(lf, 2)));
2905 const auto other_cell = index.
element;
2906 assert(other_cell >= 0);
2907 assert(discr_order > discr_ordersp(other_cell));
2910 Eigen::MatrixXd lnodes;
2912 Eigen::RowVector3d node_position;
2915 node_position = lnodes.row(
indices(0));
2916 else if (j < 4 + 6 * ln_edge_nodes)
2917 node_position = lnodes.row(
indices(((j - 4) % ln_edge_nodes) + 3));
2918 else if (j < 4 + 6 * ln_edge_nodes + 4 * ln_face_nodes)
2923 for (ii = 0; ii < me_indices.size(); ++ii)
2925 if (me_indices(ii) == j)
2929 assert(ii >= 3 + 3 * ln_edge_nodes);
2930 assert(ii < me_indices.size());
2932 node_position = lnodes.row(
indices(ii));
2937 const auto &other_bases = bases[other_cell];
2939 std::vector<AssemblyValues> w;
2940 other_bases.evaluate_bases(node_position, w);
2942 assert(b.
bases[j].global().size() == 0);
2944 for (
long i = 0; i < w.size(); ++i)
2946 assert(w[i].
val.size() == 1);
2947 if (std::abs(w[i].
val(0)) < 1e-8)
2951 for (
size_t ii = 0; ii < other_bases.bases[i].global().size(); ++ii)
2953 const auto &other_global = other_bases.bases[i].global()[ii];
2955 b.
bases[j].global().emplace_back(other_global.index, other_global.node, w[i].val(0) * other_global.val);
2970 return nodes.n_nodes();
static int quadrature_order(const std::string &assembler, const int basis_degree, const BasisType &b_type, const int dim)
utility for retrieving the needed quadrature order to precisely integrate the given form on the given...
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
void set_quadrature(const QuadratureFunction &fun)
void set_local_node_from_primitive_func(LocalNodeFromPrimitiveFunc fun)
sets mapping from local nodes to global nodes
std::vector< Basis > bases
one basis function per node in the element
void set_mass_quadrature(const QuadratureFunction &fun)
static Eigen::VectorXi hex_face_local_nodes(const bool serendipity, const int q, const mesh::Mesh3D &mesh, mesh::Navigation3D::Index index)
static Eigen::VectorXi prism_face_local_nodes(const int p, const int q, const mesh::Mesh3D &mesh, mesh::Navigation3D::Index index)
static int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_orderp, const int discr_orderq, const bool bernstein, const bool serendipity, const bool has_polys, const bool is_geom_bases, const bool use_corner_quadrature, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over tets, Q1, Q2 over hes).
static Eigen::VectorXi tet_face_local_nodes(const int p, const mesh::Mesh3D &mesh, mesh::Navigation3D::Index index)
Boundary primitive IDs for a single element.
virtual Navigation3D::Index get_index_from_element(int hi, int lf, int lv) const =0
virtual Navigation3D::Index switch_element(Navigation3D::Index idx) const =0
virtual Navigation3D::Index get_index_from_element_edge(int hi, int v0, int v1) const =0
virtual int n_cell_faces(const int c_id) const =0
virtual std::vector< uint32_t > edge_neighs(const int e_gid) const =0
bool is_volume() const override
checks if mesh is volume
virtual Navigation3D::Index next_around_face(Navigation3D::Index idx) const =0
virtual Navigation3D::Index get_index_from_element_face(int hi, int v0, int v1, int v2) const =0
virtual Navigation3D::Index switch_vertex(Navigation3D::Index idx) const =0
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
bool is_polytope(const int el_id) const
checks if element is polygon compatible
bool is_rational() const
check if curved mesh has rational polynomials elements
virtual bool is_conforming() const =0
if the mesh is conforming
bool is_cube(const int el_id) const
checks if element is cube compatible
virtual bool is_boundary_face(const int face_global_id) const =0
is face boundary
virtual int get_boundary_id(const int primitive) const
Get the boundary selection of an element (face in 3d, edge in 2d)
bool is_simplex(const int el_id) const
checks if element is simplex
bool is_prism(const int el_id) const
checks if element is a prism
const std::vector< double > & cell_weights(const int cell_index) const
weights for rational polynomial meshes
virtual int n_cells() const =0
number of cells
virtual int n_faces() const =0
number of faces
virtual int n_face_vertices(const int f_id) const =0
number of vertices of a face
int cell_ref_level(const int c_id) const
int n_faces() const override
number of faces
int face_edge(const int f_id, const int le_id) const
int n_cell_faces(const int c_id) const override
int n_edge_cells(const int e_id) const
int n_cells() const override
number of cells
int n_edges() const override
number of edges
int n_face_vertices(const int f_id) const override
number of vertices of a face
std::vector< uint32_t > edge_neighs(const int e_gid) const override
int leader_face_of_edge(const int e_id) const
int cell_face(const int c_id, const int lf_id) const override
int leader_edge_of_edge(const int e_id) const
int n_cell_edges(const int c_id) const override
int cell_edge(const int c_id, const int le_id) const override
int leader_face_of_face(const int f_id) const
int n_face_cells(const int f_id) const
void get_quadrature(const int order, Quadrature &quad)
void get_quadrature(const int order, const int order_h, Quadrature &quad)
void q_grad_basis_value_3d(const int q, const int local_index, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)
void prism_basis_value_3d(const int p, const int q, const int li, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)
void prism_grad_basis_value_3d(const int p, const int q, const int li, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)
void prism_nodes_3d(const int p, const int q, Eigen::MatrixXd &val)
void p_grad_basis_value_3d(const bool bernstein, const int p, const int local_index, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)
void p_nodes_3d(const int p, Eigen::MatrixXd &val)
void p_basis_value_3d(const bool bernstein, const int p, const int local_index, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)
void q_nodes_3d(const int q, Eigen::MatrixXd &val)
void q_basis_value_3d(const int q, const int local_index, const Eigen::MatrixXd &uv, Eigen::MatrixXd &val)
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
void log_and_throw_error(const std::string &msg)
std::vector< int > local_indices