9#include <polysolve/linear/Solver.hpp>
17#include <Eigen/Sparse>
30 using namespace Eigen;
32 using namespace assembler;
44 inline const int &operator()(
const int i,
const int j,
const int k)
const
49 inline int &operator()(
const int i,
const int j,
const int k)
58 bool is_regular(
const int xx,
const int yy,
const int zz)
const
63 return !((x == 1 && y == yy && z == zz) || (x == xx && y == 1 && z == zz) || (x == xx && y == yy && z == 1));
68 std::array<Matrix<int, 3, 3>, 3>
space_;
71 bool is_edge_singular(
const Navigation3D::Index &index,
const Mesh3D &mesh)
74 mesh.get_edge_elements_neighs(index.edge, ids);
76 if (ids.size() == 4 || mesh.is_boundary_edge(index.edge))
81 if (mesh.is_polytope(idx))
88 void print_local_space(
const SpaceMatrix &space)
90 for (
int k = 2; k >= 0; --k)
92 for (
int j = 2; j >= 0; --j)
94 for (
int i = 0; i < 3; ++i)
98 std::cout << space(i, j, k) <<
"\t";
103 std::cout << std::endl;
111 int node_id_from_face_index(
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const Navigation3D::Index &index)
113 int el_id = mesh.switch_element(index).element;
114 if (el_id >= 0 && mesh.is_cube(el_id))
116 return mesh_nodes.node_id_from_cell(el_id);
119 return mesh_nodes.node_id_from_face(index.face);
122 int node_id_from_edge_index(
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const Navigation3D::Index &index)
124 Navigation3D::Index new_index = mesh.switch_element(index);
125 int el_id = new_index.element;
127 if (el_id < 0 || mesh.is_polytope(el_id))
129 new_index = mesh.switch_element(mesh.switch_face(index));
130 el_id = new_index.element;
132 if (el_id < 0 || mesh.is_polytope(el_id))
134 return mesh_nodes.node_id_from_edge(index.edge);
137 return node_id_from_face_index(mesh, mesh_nodes, mesh.switch_face(new_index));
140 return node_id_from_face_index(mesh, mesh_nodes, mesh.switch_face(new_index));
143 int node_id_from_vertex_index_explore(
const Mesh3D &mesh,
const MeshNodes &mesh_nodes,
const Navigation3D::Index &index,
int &node_id)
145 Navigation3D::Index new_index = mesh.switch_element(index);
147 int id = new_index.element;
149 if (
id < 0 || mesh.is_polytope(
id))
153 node_id = mesh_nodes.primitive_from_vertex(index.vertex);
157 new_index = mesh.switch_element(mesh.switch_face(new_index));
158 id = new_index.element;
160 if (
id < 0 || mesh.is_polytope(
id))
164 node_id = mesh_nodes.primitive_from_edge(mesh.switch_edge(new_index).edge);
168 new_index = mesh.switch_element(mesh.switch_face(mesh.switch_edge(new_index)));
169 id = new_index.element;
171 if (
id < 0 || mesh.is_polytope(
id))
175 node_id = mesh_nodes.primitive_from_face(new_index.face);
180 node_id = mesh_nodes.primitive_from_cell(
id);
184 int node_id_from_vertex_index(
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const Navigation3D::Index &index)
186 std::array<int, 6>
path;
187 std::array<int, 6> primitive_ids;
189 path[0] = node_id_from_vertex_index_explore(mesh, mesh_nodes, index, primitive_ids[0]);
190 path[1] = node_id_from_vertex_index_explore(mesh, mesh_nodes, mesh.switch_face(index), primitive_ids[1]);
192 path[2] = node_id_from_vertex_index_explore(mesh, mesh_nodes, mesh.switch_edge(index), primitive_ids[2]);
193 path[3] = node_id_from_vertex_index_explore(mesh, mesh_nodes, mesh.switch_face(mesh.switch_edge(index)), primitive_ids[3]);
195 path[4] = node_id_from_vertex_index_explore(mesh, mesh_nodes, mesh.switch_edge(mesh.switch_face(index)), primitive_ids[4]);
196 path[5] = node_id_from_vertex_index_explore(mesh, mesh_nodes, mesh.switch_face(mesh.switch_edge(mesh.switch_face(index))), primitive_ids[5]);
198 const int min_path = *std::min_element(
path.begin(),
path.end());
200 int primitive_id = 0;
201 for (
int i = 0; i < 6; ++i)
203 if (path[i] == min_path)
205 primitive_id = primitive_ids[i];
210 return mesh_nodes.node_id_from_primitive(primitive_id);
213 void get_edge_elements_neighs(
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int element_id,
const int edge_id,
int dir, std::vector<int> &ids)
215 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 12> to_edge;
216 mesh.to_edge_functions(to_edge);
218 Navigation3D::Index index;
219 for (
int i = 0; i < 12; ++i)
221 index = to_edge[i](mesh.get_index_from_element(element_id));
234 ids.push_back(mesh_nodes.node_id_from_cell(index.element));
235 index = mesh.next_around_edge(index);
236 }
while (index.element != element_id);
246 const Navigation3D::Index f_index = mesh.switch_face(mesh.switch_edge(index));
247 ids.push_back(node_id_from_face_index(mesh, mesh_nodes, f_index));
249 index = mesh.next_around_edge(index);
250 }
while (index.element != element_id);
260 const Navigation3D::Index f_index = mesh.switch_face(mesh.switch_edge(mesh.switch_vertex(index)));
261 ids.push_back(node_id_from_face_index(mesh, mesh_nodes, f_index));
263 index = mesh.next_around_edge(index);
264 }
while (index.element != element_id);
272 void add_edge_id_for_poly(
const Navigation3D::Index &index,
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int global_index, std::map<int, InterfaceData> &poly_face_to_data)
274 const int f1 = index.face;
275 const int f2 = mesh.switch_face(index).face;
277 const int id1 = mesh_nodes.primitive_from_face(f1);
278 const int id2 = mesh_nodes.primitive_from_face(f2);
280 if (mesh_nodes.is_primitive_interface(id1))
282 InterfaceData &data = poly_face_to_data[f1];
283 data.local_indices.push_back(global_index);
286 if (mesh_nodes.is_primitive_interface(id2))
288 InterfaceData &data = poly_face_to_data[f2];
289 data.local_indices.push_back(global_index);
293 void add_vertex_id_for_poly(
const Navigation3D::Index &index,
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int global_index, std::map<int, InterfaceData> &poly_face_to_data)
295 const int f1 = index.face;
296 const int f2 = mesh.switch_face(index).face;
297 const int f3 = mesh.switch_face(mesh.switch_edge(index)).face;
299 const int id1 = mesh_nodes.primitive_from_face(f1);
300 const int id2 = mesh_nodes.primitive_from_face(f2);
301 const int id3 = mesh_nodes.primitive_from_face(f3);
303 if (mesh_nodes.is_primitive_interface(id1))
305 InterfaceData &data = poly_face_to_data[f1];
306 data.local_indices.push_back(global_index);
309 if (mesh_nodes.is_primitive_interface(id2))
311 InterfaceData &data = poly_face_to_data[f2];
312 data.local_indices.push_back(global_index);
315 if (mesh_nodes.is_primitive_interface(id3))
317 InterfaceData &data = poly_face_to_data[f3];
318 data.local_indices.push_back(global_index);
322 void explore_edge(
const Navigation3D::Index &index,
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int x,
const int y,
const int z, SpaceMatrix &space, LocalBoundary &local_boundary, std::map<int, InterfaceData> &poly_face_to_data)
324 int node_id = node_id_from_edge_index(mesh, mesh_nodes, index);
325 space(
x,
y,
z) = node_id;
328 if (is_edge_singular(index, mesh))
330 std::vector<int> ids;
331 mesh.get_edge_elements_neighs(index.edge, ids);
334 assert(!space.is_k_regular);
335 space.is_k_regular =
true;
339 space.edge_id = index.edge;
345 add_edge_id_for_poly(index, mesh, mesh_nodes, 9 *
z + 3 *
y +
x, poly_face_to_data);
348 void explore_vertex(
const Navigation3D::Index &index,
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int x,
const int y,
const int z, SpaceMatrix &space, LocalBoundary &local_boundary, std::map<int, InterfaceData> &poly_face_to_data)
350 int node_id = node_id_from_vertex_index(mesh, mesh_nodes, index);
351 space(
x,
y,
z) = node_id;
357 add_vertex_id_for_poly(index, mesh, mesh_nodes, 9 *
z + 3 *
y +
x, poly_face_to_data);
360 void explore_face(
const Navigation3D::Index &index,
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int x,
const int y,
const int z, SpaceMatrix &space, LocalBoundary &local_boundary, std::map<int, InterfaceData> &poly_face_to_data)
362 int node_id = node_id_from_face_index(mesh, mesh_nodes, index);
363 space(
x,
y,
z) = node_id;
366 if (mesh_nodes.is_boundary(node_id))
372 else if (mesh_nodes.is_interface(node_id))
374 InterfaceData &data = poly_face_to_data[index.face];
375 data.local_indices.push_back(9 *
z + 3 *
y +
x);
381 void build_local_space(
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const int el_index, SpaceMatrix &space, std::vector<LocalBoundary> &local_boundary, std::map<int, InterfaceData> &poly_face_to_data)
383 assert(mesh.is_volume());
385 Navigation3D::Index start_index = mesh.get_index_from_element(el_index);
386 Navigation3D::Index index;
388 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 6> to_face;
389 mesh.to_face_functions(to_face);
391 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 12> to_edge;
392 mesh.to_edge_functions(to_edge);
394 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 8> to_vertex;
395 mesh.to_vertex_functions(to_vertex);
397 const int node_id = mesh_nodes.node_id_from_cell(el_index);
398 space(1, 1, 1) = node_id;
401 LocalBoundary lb(el_index, BoundaryType::QUAD);
404 index = to_face[1](start_index);
405 explore_face(index, mesh, mesh_nodes, 1, 1, 0, space, lb, poly_face_to_data);
407 index = to_face[0](start_index);
408 explore_face(index, mesh, mesh_nodes, 1, 1, 2, space, lb, poly_face_to_data);
410 index = to_face[3](start_index);
411 explore_face(index, mesh, mesh_nodes, 0, 1, 1, space, lb, poly_face_to_data);
413 index = to_face[2](start_index);
414 explore_face(index, mesh, mesh_nodes, 2, 1, 1, space, lb, poly_face_to_data);
416 index = to_face[5](start_index);
417 explore_face(index, mesh, mesh_nodes, 1, 0, 1, space, lb, poly_face_to_data);
419 index = to_face[4](start_index);
420 explore_face(index, mesh, mesh_nodes, 1, 2, 1, space, lb, poly_face_to_data);
423 index = to_edge[0](start_index);
424 explore_edge(index, mesh, mesh_nodes, 1, 0, 0, space, lb, poly_face_to_data);
426 index = to_edge[1](start_index);
427 explore_edge(index, mesh, mesh_nodes, 2, 1, 0, space, lb, poly_face_to_data);
429 index = to_edge[2](start_index);
430 explore_edge(index, mesh, mesh_nodes, 1, 2, 0, space, lb, poly_face_to_data);
432 index = to_edge[3](start_index);
433 explore_edge(index, mesh, mesh_nodes, 0, 1, 0, space, lb, poly_face_to_data);
435 index = to_edge[4](start_index);
436 explore_edge(index, mesh, mesh_nodes, 0, 0, 1, space, lb, poly_face_to_data);
438 index = to_edge[5](start_index);
439 explore_edge(index, mesh, mesh_nodes, 2, 0, 1, space, lb, poly_face_to_data);
441 index = to_edge[6](start_index);
442 explore_edge(index, mesh, mesh_nodes, 2, 2, 1, space, lb, poly_face_to_data);
444 index = to_edge[7](start_index);
445 explore_edge(index, mesh, mesh_nodes, 0, 2, 1, space, lb, poly_face_to_data);
447 index = to_edge[8](start_index);
448 explore_edge(index, mesh, mesh_nodes, 1, 0, 2, space, lb, poly_face_to_data);
450 index = to_edge[9](start_index);
451 explore_edge(index, mesh, mesh_nodes, 2, 1, 2, space, lb, poly_face_to_data);
453 index = to_edge[10](start_index);
454 explore_edge(index, mesh, mesh_nodes, 1, 2, 2, space, lb, poly_face_to_data);
456 index = to_edge[11](start_index);
457 explore_edge(index, mesh, mesh_nodes, 0, 1, 2, space, lb, poly_face_to_data);
460 index = to_vertex[0](start_index);
461 explore_vertex(index, mesh, mesh_nodes, 0, 0, 0, space, lb, poly_face_to_data);
463 index = to_vertex[1](start_index);
464 explore_vertex(index, mesh, mesh_nodes, 2, 0, 0, space, lb, poly_face_to_data);
466 index = to_vertex[2](start_index);
467 explore_vertex(index, mesh, mesh_nodes, 2, 2, 0, space, lb, poly_face_to_data);
469 index = to_vertex[3](start_index);
470 explore_vertex(index, mesh, mesh_nodes, 0, 2, 0, space, lb, poly_face_to_data);
472 index = to_vertex[4](start_index);
473 explore_vertex(index, mesh, mesh_nodes, 0, 0, 2, space, lb, poly_face_to_data);
475 index = to_vertex[5](start_index);
476 explore_vertex(index, mesh, mesh_nodes, 2, 0, 2, space, lb, poly_face_to_data);
478 index = to_vertex[6](start_index);
479 explore_vertex(index, mesh, mesh_nodes, 2, 2, 2, space, lb, poly_face_to_data);
481 index = to_vertex[7](start_index);
482 explore_vertex(index, mesh, mesh_nodes, 0, 2, 2, space, lb, poly_face_to_data);
485 local_boundary.emplace_back(lb);
488 void setup_knots_vectors(MeshNodes &mesh_nodes,
const SpaceMatrix &space, std::array<std::array<double, 4>, 3> &h_knots, std::array<std::array<double, 4>, 3> &v_knots, std::array<std::array<double, 4>, 3> &w_knots)
491 if (mesh_nodes.is_boundary_or_interface(space(0, 1, 1)) && mesh_nodes.is_boundary_or_interface(space(2, 1, 1)))
493 h_knots[0] = {{0, 0, 0, 1}};
494 h_knots[1] = {{0, 0, 1, 1}};
495 h_knots[2] = {{0, 1, 1, 1}};
498 else if (mesh_nodes.is_boundary_or_interface(space(0, 1, 1)))
500 h_knots[0] = {{0, 0, 0, 1}};
501 h_knots[1] = {{0, 0, 1, 2}};
502 h_knots[2] = {{0, 1, 2, 3}};
505 else if (mesh_nodes.is_boundary_or_interface(space(2, 1, 1)))
507 h_knots[0] = {{-2, -1, 0, 1}};
508 h_knots[1] = {{-1, 0, 1, 1}};
509 h_knots[2] = {{0, 1, 1, 1}};
513 h_knots[0] = {{-2, -1, 0, 1}};
514 h_knots[1] = {{-1, 0, 1, 2}};
515 h_knots[2] = {{0, 1, 2, 3}};
519 if (mesh_nodes.is_boundary_or_interface(space(1, 0, 1)) && mesh_nodes.is_boundary_or_interface(space(1, 2, 1)))
521 v_knots[0] = {{0, 0, 0, 1}};
522 v_knots[1] = {{0, 0, 1, 1}};
523 v_knots[2] = {{0, 1, 1, 1}};
526 else if (mesh_nodes.is_boundary_or_interface(space(1, 0, 1)))
528 v_knots[0] = {{0, 0, 0, 1}};
529 v_knots[1] = {{0, 0, 1, 2}};
530 v_knots[2] = {{0, 1, 2, 3}};
533 else if (mesh_nodes.is_boundary_or_interface(space(1, 2, 1)))
535 v_knots[0] = {{-2, -1, 0, 1}};
536 v_knots[1] = {{-1, 0, 1, 1}};
537 v_knots[2] = {{0, 1, 1, 1}};
541 v_knots[0] = {{-2, -1, 0, 1}};
542 v_knots[1] = {{-1, 0, 1, 2}};
543 v_knots[2] = {{0, 1, 2, 3}};
547 if (mesh_nodes.is_boundary_or_interface(space(1, 1, 0)) && mesh_nodes.is_boundary_or_interface(space(1, 1, 2)))
549 w_knots[0] = {{0, 0, 0, 1}};
550 w_knots[1] = {{0, 0, 1, 1}};
551 w_knots[2] = {{0, 1, 1, 1}};
554 else if (mesh_nodes.is_boundary_or_interface(space(1, 1, 0)))
556 w_knots[0] = {{0, 0, 0, 1}};
557 w_knots[1] = {{0, 0, 1, 2}};
558 w_knots[2] = {{0, 1, 2, 3}};
561 else if (mesh_nodes.is_boundary_or_interface(space(1, 1, 2)))
563 w_knots[0] = {{-2, -1, 0, 1}};
564 w_knots[1] = {{-1, 0, 1, 1}};
565 w_knots[2] = {{0, 1, 1, 1}};
569 w_knots[0] = {{-2, -1, 0, 1}};
570 w_knots[1] = {{-1, 0, 1, 2}};
571 w_knots[2] = {{0, 1, 2, 3}};
575 void basis_for_regular_hex(MeshNodes &mesh_nodes,
const SpaceMatrix &space,
const std::array<std::array<double, 4>, 3> &h_knots,
const std::array<std::array<double, 4>, 3> &v_knots,
const std::array<std::array<double, 4>, 3> &w_knots, ElementBases &b)
577 for (
int z = 0;
z < 3; ++
z)
579 for (
int y = 0;
y < 3; ++
y)
581 for (
int x = 0;
x < 3; ++
x)
583 if (space.is_regular(
x,
y,
z))
585 const int local_index = 9 *
z + 3 *
y +
x;
586 const int global_index = space(
x,
y,
z);
587 const auto node = mesh_nodes.node_position(global_index);
590 b.bases[local_index].init(2, global_index, local_index, node);
592 const QuadraticBSpline3d spline(h_knots[
x], v_knots[
y], w_knots[
z]);
594 b.bases[local_index].set_basis([spline](
const Eigen::MatrixXd &uv, Eigen::MatrixXd &
val) { spline.interpolate(uv,
val); });
595 b.bases[local_index].set_grad([spline](
const Eigen::MatrixXd &uv, Eigen::MatrixXd &
val) { spline.derivative(uv,
val); });
602 void basis_for_irregulard_hex(
const int el_index,
const Mesh3D &mesh, MeshNodes &mesh_nodes,
const SpaceMatrix &space,
const std::array<std::array<double, 4>, 3> &h_knots,
const std::array<std::array<double, 4>, 3> &v_knots,
const std::array<std::array<double, 4>, 3> &w_knots, ElementBases &b, std::map<int, InterfaceData> &poly_face_to_data)
604 for (
int z = 0;
z < 3; ++
z)
606 for (
int y = 0;
y < 3; ++
y)
608 for (
int x = 0;
x < 3; ++
x)
610 if (!space.is_regular(
x,
y,
z))
612 const int local_index = 9 *
z + 3 *
y +
x;
626 const int edge_id = space.edge_id;
629 if (space.x ==
x && space.y ==
y && space.z == 1)
642 else if (space.x ==
x && space.y == 1 && space.z ==
z)
655 else if (space.x == 1 && space.y ==
y && space.z ==
z)
671 const auto ¢er = b.bases[zz * 9 + yy * 3 + xx].global().front();
673 const auto &el1 = b.bases[mpz * 9 + mpy * 3 + mpx].global().front();
674 const auto &el2 = b.bases[mmz * 9 + mmy * 3 + mmx].global().front();
681 std::vector<int> ids;
682 get_edge_elements_neighs(mesh, mesh_nodes, el_index,
edge_id, dir, ids);
684 if (ids.front() != center.index)
688 get_edge_elements_neighs(mesh, mesh_nodes, el_index,
edge_id, dir == 2 ? 0 : 2, ids);
691 assert(ids.front() == center.index);
693 std::vector<int> other_indices;
694 std::vector<Eigen::MatrixXd> other_nodes;
695 for (
size_t i = 0; i < ids.size(); ++i)
697 const int node_id = ids[i];
698 if (node_id != center.index && node_id != el1.index && node_id != el2.index)
700 other_indices.push_back(node_id);
706 auto &
base = b.bases[local_index];
708 const int k = int(other_indices.size()) + 3;
713 base.global().resize(k);
715 base.global()[0].index = center.index;
716 base.global()[0].val = (4. - k) / k;
717 base.global()[0].node = center.node;
719 base.global()[1].index = el1.index;
720 base.global()[1].val = (4. - k) / k;
721 base.global()[1].node = el1.node;
723 base.global()[2].index = el2.index;
724 base.global()[2].val = (4. - k) / k;
725 base.global()[2].node = el2.node;
731 for (std::size_t n = 0; n < other_indices.size(); ++n)
733 base.global()[3 + n].index = other_indices[n];
734 base.global()[3 + n].val = 4. / k;
735 base.global()[3 + n].node = mesh_nodes.node_position(other_indices[n]);
738 const QuadraticBSpline3d spline(h_knots[
x], v_knots[
y], w_knots[
z]);
740 b.bases[local_index].set_basis([spline](
const Eigen::MatrixXd &uv, Eigen::MatrixXd &
val) { spline.interpolate(uv,
val); });
741 b.bases[local_index].set_grad([spline](
const Eigen::MatrixXd &uv, Eigen::MatrixXd &
val) { spline.derivative(uv,
val); });
748 void create_q2_nodes(
const Mesh3D &mesh,
const int el_index, std::set<int> &vertex_id, std::set<int> &
edge_id, std::set<int> &face_id, ElementBases &b, std::vector<LocalBoundary> &local_boundary,
int &n_bases)
752 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 6> to_face;
753 mesh.to_face_functions(to_face);
755 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 12> to_edge;
756 mesh.to_edge_functions(to_edge);
758 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 8> to_vertex;
759 mesh.to_vertex_functions(to_vertex);
761 LocalBoundary lb(el_index, BoundaryType::QUAD);
763 const Navigation3D::Index start_index = mesh.get_index_from_element(el_index);
764 for (
int j = 0; j < 8; ++j)
766 const Navigation3D::Index index = to_vertex[j](start_index);
770 int current_vertex_node_id = -1;
771 Eigen::MatrixXd current_vertex_node;
774 bool is_vertex_q2 =
true;
776 std::vector<int> vertex_neighs;
777 mesh.get_vertex_elements_neighs(index.vertex, vertex_neighs);
779 for (
size_t i = 0; i < vertex_neighs.size(); ++i)
781 if (mesh.is_spline_compatible(vertex_neighs[i]))
783 is_vertex_q2 =
false;
787 const bool is_vertex_boundary = mesh.is_boundary_vertex(index.vertex);
791 const bool is_new_vertex = vertex_id.insert(index.vertex).second;
795 current_vertex_node_id = n_bases++;
796 current_vertex_node = mesh.point(index.vertex);
804 if (current_vertex_node_id >= 0)
805 b.bases[loc_index].init(2, current_vertex_node_id, loc_index, current_vertex_node);
811 for (
int j = 0; j < 12; ++j)
813 Navigation3D::Index index = to_edge[j](start_index);
815 int current_edge_node_id = -1;
816 Eigen::Matrix<double, 1, 3> current_edge_node;
820 bool is_edge_q2 =
true;
822 std::vector<int> edge_neighs;
823 mesh.get_edge_elements_neighs(index.edge, edge_neighs);
825 for (
size_t i = 0; i < edge_neighs.size(); ++i)
827 if (mesh.is_spline_compatible(edge_neighs[i]))
833 const bool is_edge_boundary = mesh.is_boundary_edge(index.edge);
837 const bool is_new_edge =
edge_id.insert(index.edge).second;
841 current_edge_node_id = n_bases++;
842 current_edge_node = mesh.edge_barycenter(index.edge);
850 if (current_edge_node_id >= 0)
851 b.bases[loc_index].init(2, current_edge_node_id, loc_index, current_edge_node);
857 for (
int j = 0; j < 6; ++j)
859 Navigation3D::Index index = to_face[j](start_index);
861 int current_face_node_id = -1;
863 Eigen::Matrix<double, 1, 3> current_face_node;
864 const int opposite_element = mesh.switch_element(index).element;
865 const bool is_face_q2 = opposite_element < 0 || !mesh.is_spline_compatible(opposite_element);
871 const bool is_new_face = face_id.insert(index.face).second;
875 current_face_node_id = n_bases++;
876 current_face_node = mesh.face_barycenter(index.face);
878 const int b_index = loc_index - 20;
880 if (opposite_element < 0)
883 lb.add_boundary_primitive(index.face, b_index);
889 if (current_face_node_id >= 0)
890 b.bases[loc_index].init(2, current_face_node_id, loc_index, current_face_node);
897 b.bases[26].init(2, n_bases++, 26, mesh.cell_barycenter(el_index));
902 local_boundary.emplace_back(lb);
905 void insert_into_global(
const int el_index,
const Local2Global &data, std::vector<Local2Global> &
vec,
const int size)
908 if (fabs(data.val) < 1e-10)
913 for (
int i = 0; i < size; ++i)
915 if (
vec[i].index == data.index)
922 assert((
vec[i].node - data.node).norm() < 1e-10);
932 void assign_q2_weights(
const Mesh3D &mesh,
const int el_index, std::vector<ElementBases> &bases)
935 std::vector<AssemblyValues> eval_p;
936 const Navigation3D::Index start_index = mesh.get_index_from_element(el_index);
937 ElementBases &b = bases[el_index];
939 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 6> to_face;
940 mesh.to_face_functions(to_face);
941 for (
int f = 0;
f < 6; ++
f)
943 const Navigation3D::Index index = to_face[
f](start_index);
944 const int opposite_element = mesh.switch_element(index).element;
946 if (opposite_element < 0 || !mesh.is_cube(opposite_element))
950 Eigen::Matrix<double, 9, 3> param_p;
952 Eigen::MatrixXd hex_loc_nodes;
955 for (
int k = 0; k < 9; ++k)
956 param_p.row(k) = hex_loc_nodes.row(opposite_indices[k]);
958 const auto &other_bases = bases[opposite_element];
963 std::array<int, 9> sizes;
965 for (
int l = 0; l < 9; ++l)
966 sizes[l] = b.bases[indices[l]].global().size();
968 other_bases.evaluate_bases(param_p, eval_p);
969 for (std::size_t i = 0; i < other_bases.bases.size(); ++i)
971 const auto &other_b = other_bases.bases[i];
973 if (other_b.global().empty())
977 assert(eval_p[i].
val.size() == 9);
980 if (eval_p[i].
val.cwiseAbs().maxCoeff() <= 1e-10)
983 for (std::size_t k = 0; k < other_b.global().size(); ++k)
985 for (
int l = 0; l < 9; ++l)
987 Local2Global glob = other_b.global()[k];
988 glob.val *= eval_p[i].val(l);
990 insert_into_global(el_index, glob, b.bases[indices[l]].global(), sizes[l]);
997 void setup_data_for_polygons(
const Mesh3D &mesh,
const int el_index,
const ElementBases &b, std::map<int, InterfaceData> &poly_face_to_data)
999 const Navigation3D::Index start_index = mesh.get_index_from_element(el_index);
1000 std::array<std::function<Navigation3D::Index(Navigation3D::Index)>, 6> to_face;
1001 mesh.to_face_functions(to_face);
1002 for (
int f = 0;
f < 6; ++
f)
1004 const Navigation3D::Index index = to_face[
f](start_index);
1006 const int opposite_element = mesh.switch_element(index).element;
1007 const bool is_neigh_poly = opposite_element >= 0 && mesh.is_polytope(opposite_element);
1014 InterfaceData &data = poly_face_to_data[index.face];
1016 for (
int kk = 0; kk < e2l.size(); ++kk)
1018 const auto idx = e2l(kk);
1019 data.local_indices.push_back(idx);
1027 const std::string &assembler,
1028 const int quadrature_order,
const int mass_quadrature_order, std::vector<ElementBases> &bases, std::vector<LocalBoundary> &local_boundary, std::map<int, InterfaceData> &poly_face_to_data)
1033 MeshNodes mesh_nodes(mesh,
true,
true, 1, 1, 1);
1036 bases.resize(n_els);
1037 local_boundary.clear();
1043 std::array<std::array<double, 4>, 3> h_knots;
1044 std::array<std::array<double, 4>, 3> v_knots;
1045 std::array<std::array<double, 4>, 3> w_knots;
1047 for (
int e = 0; e < n_els; ++e)
1054 build_local_space(mesh, mesh_nodes, e, space, local_boundary, poly_face_to_data);
1058 const int real_mass_order = mass_quadrature_order > 0 ? mass_quadrature_order :
AssemblerUtils::quadrature_order(
"Mass", 2, AssemblerUtils::BasisType::SPLINE, 3);
1072 const auto &mesh3d =
dynamic_cast<const Mesh3D &
>(mesh);
1075 mesh3d.to_face_functions(to_face);
1077 auto start_index = mesh3d.get_index_from_element(e);
1078 auto index = start_index;
1081 for (lf = 0; lf < mesh3d.n_cell_faces(e); ++lf)
1083 index = to_face[lf](start_index);
1084 if (index.face == primitive_id)
1087 assert(index.face == primitive_id);
1089 static constexpr std::array<std::array<int, 9>, 6> face_to_index = {{
1090 {{2 * 9 + 0 * 3 + 0, 2 * 9 + 1 * 3 + 0, 2 * 9 + 2 * 3 + 0, 2 * 9 + 0 * 3 + 1, 2 * 9 + 1 * 3 + 1, 2 * 9 + 2 * 3 + 1, 2 * 9 + 0 * 3 + 2, 2 * 9 + 1 * 3 + 2, 2 * 9 + 2 * 3 + 2}},
1091 {{0 * 9 + 0 * 3 + 0, 0 * 9 + 1 * 3 + 0, 0 * 9 + 2 * 3 + 0, 0 * 9 + 0 * 3 + 1, 0 * 9 + 1 * 3 + 1, 0 * 9 + 2 * 3 + 1, 0 * 9 + 0 * 3 + 2, 0 * 9 + 1 * 3 + 2, 0 * 9 + 2 * 3 + 2}},
1093 {{0 * 9 + 0 * 3 + 2, 0 * 9 + 1 * 3 + 2, 0 * 9 + 2 * 3 + 2, 1 * 9 + 0 * 3 + 2, 1 * 9 + 1 * 3 + 2, 1 * 9 + 2 * 3 + 2, 2 * 9 + 0 * 3 + 2, 2 * 9 + 1 * 3 + 2, 2 * 9 + 2 * 3 + 2}},
1094 {{0 * 9 + 0 * 3 + 0, 0 * 9 + 1 * 3 + 0, 0 * 9 + 2 * 3 + 0, 1 * 9 + 0 * 3 + 0, 1 * 9 + 1 * 3 + 0, 1 * 9 + 2 * 3 + 0, 2 * 9 + 0 * 3 + 0, 2 * 9 + 1 * 3 + 0, 2 * 9 + 2 * 3 + 0}},
1096 {{0 * 9 + 2 * 3 + 0, 0 * 9 + 2 * 3 + 1, 0 * 9 + 2 * 3 + 2, 1 * 9 + 2 * 3 + 0, 1 * 9 + 2 * 3 + 1, 1 * 9 + 2 * 3 + 2, 2 * 9 + 2 * 3 + 0, 2 * 9 + 2 * 3 + 1, 2 * 9 + 2 * 3 + 2}},
1097 {{0 * 9 + 0 * 3 + 0, 0 * 9 + 0 * 3 + 1, 0 * 9 + 0 * 3 + 2, 1 * 9 + 0 * 3 + 0, 1 * 9 + 0 * 3 + 1, 1 * 9 + 0 * 3 + 2, 2 * 9 + 0 * 3 + 0, 2 * 9 + 0 * 3 + 1, 2 * 9 + 0 * 3 + 2}},
1100 Eigen::VectorXi res(9);
1102 for (
int i = 0; i < 9; ++i)
1103 res(i) = face_to_index[lf][i];
1108 setup_knots_vectors(mesh_nodes, space, h_knots, v_knots, w_knots);
1111 basis_for_regular_hex(mesh_nodes, space, h_knots, v_knots, w_knots, b);
1112 basis_for_irregulard_hex(e, mesh, mesh_nodes, space, h_knots, v_knots, w_knots, b, poly_face_to_data);
1115 int n_bases = mesh_nodes.
n_nodes();
1117 std::set<int> face_id;
1119 std::set<int> vertex_id;
1121 for (
int e = 0; e < n_els; ++e)
1128 const int real_order = quadrature_order > 0 ? quadrature_order :
AssemblerUtils::quadrature_order(assembler, 2, AssemblerUtils::BasisType::CUBE_LAGRANGE, 3);
1129 const int real_mass_order = mass_quadrature_order > 0 ? mass_quadrature_order :
AssemblerUtils::quadrature_order(
"Mass", 2, AssemblerUtils::BasisType::CUBE_LAGRANGE, 3);
1142 const auto &mesh3d =
dynamic_cast<const Mesh3D &
>(mesh);
1145 for (
int lf = 0; lf < 6; ++lf)
1147 index = mesh3d.get_index_from_element(e, lf, 0);
1148 if (index.
face == primitive_id)
1151 assert(index.
face == primitive_id);
1155 Eigen::VectorXi res(indices.size());
1157 for (
size_t i = 0; i < indices.size(); ++i)
1158 res(i) = indices[i];
1163 create_q2_nodes(mesh, e, vertex_id,
edge_id, face_id, b, local_boundary, n_bases);
1166 bool missing_bases =
false;
1169 missing_bases =
false;
1170 for (
int e = 0; e < n_els; ++e)
1176 if (b.is_complete())
1179 assign_q2_weights(mesh, e, bases);
1181 missing_bases = missing_bases || b.is_complete();
1183 }
while (missing_bases);
1185 for (
int e = 0; e < n_els; ++e)
1191 setup_data_for_polygons(mesh, e, b, poly_face_to_data);
1212 for (
auto &k : poly_face_to_data)
1214 auto &array = k.second.local_indices;
1215 std::sort(array.begin(), array.end());
1216 auto it = std::unique(array.begin(), array.end());
1217 array.resize(std::distance(array.begin(), it));
std::array< Matrix< int, 3, 3 >, 3 > space_
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 int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data)
static void fit_nodes(const mesh::Mesh3D &mesh, const int n_bases, std::vector< ElementBases > &gbases)
bool is_volume() const override
checks if mesh is volume
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
bool is_polytope(const int el_id) const
checks if element is polygon compatible
bool is_spline_compatible(const int el_id) const
checks if element is spline compatible
void get_quadrature(const int order, Quadrature &quad)
void q_grad_basis_value_3d(const int q, 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)