21 LF_ASSERT_MSG(codim >= 0,
"codim negative.");
22 LF_ASSERT_MSG(codim <= dim_world_, "codim > dimWorld.
");
24 return entity_pointers_[codim];
26 // auto l = [&](auto i) -> const mesh::Entity & { return **i; };
29 // return {base::make_DereferenceLambdaRandomAccessIterator(
30 // entity_pointers_[0].begin(), l),
31 // base::make_DereferenceLambdaRandomAccessIterator(
32 // entity_pointers_[0].end(), l)};
35 // //return {segments_.begin(), segments_.end()};
37 // return {points_.begin(), points_.end()};
39 // LF_VERIFY_MSG(false, "Something is horribly wrong, codim =
" +
40 // std::to_string(codim) + " is out of bounds.
");
42 // base::ForwardIterator<const Entity>(static_cast<Entity
43 // *>(nullptr)), base::ForwardIterator<const
44 // Entity>(static_cast<Entity *>(nullptr))};
178Mesh::Mesh(dim_t dim_world, NodeCoordList nodes, EdgeList edges, CellList cells,
179 bool check_completeness)
180 : dim_world_(dim_world) {
181 // Auxiliary data type for gathering information about cells adjacent to an
184 AdjCellInfo(size_type _cell_idx, size_type _edge_idx)
185 : cell_idx(_cell_idx), edge_idx(_edge_idx) {}
186 size_type cell_idx; // index of adjacent cell
187 size_type edge_idx; // local index of edge in adjacent cell
189 // Information about cells adjacent to an edge
190 using AdjCellsList = std::vector<AdjCellInfo>;
191 // Information about edge in auxiliary array
193 EdgeData(GeometryPtr geo_uptr, AdjCellsList _adj_cells_list)
194 : geo_uptr(std::move(geo_uptr)),
195 adj_cells_list(std::move(_adj_cells_list)),
196 edge_global_index(-1),
198 EdgeData(GeometryPtr geo_uptr, AdjCellsList _adj_cells_list,
199 glb_idx_t global_index)
200 : geo_uptr(std::move(geo_uptr)),
201 adj_cells_list(std::move(_adj_cells_list)),
202 edge_global_index(global_index),
204 EdgeData(const EdgeData &) = delete;
205 EdgeData(EdgeData &&) = default;
206 EdgeData &operator=(const EdgeData &) = delete;
207 EdgeData &operator=(EdgeData &&) = default;
208 ~EdgeData() = default;
209 // temporary storage for unique pointer to edge geometry, if provided
210 GeometryPtr geo_uptr;
211 // Information about neighbors
212 AdjCellsList adj_cells_list;
214 glb_idx_t edge_global_index;
215 // Flag indicating reversed orientation
219 // Type of associative auxiliary array for edge information
220 using EdgeMap = std::map<EndpointIndexPair, EdgeData>;
222 // For extracting point coordinates
223 const Eigen::MatrixXd zero_point = base::RefEl::kPoint().NodeCoords();
225 // ASSUMPTION: The length of the nodes vector gives the number of nodes
227 const size_type no_of_nodes(nodes.size());
228 SPDLOG_LOGGER_DEBUG(Logger(), "Constructing mesh: {} nodes
", no_of_nodes);
230 // ======================================================================
231 // STEP I: Initialize array of edges using pointers to
232 // entries of the array of nodes
234 // Register supplied edges in auxiliary map data structure
235 SPDLOG_LOGGER_DEBUG(Logger(), "Initializing edge map
");
238 glb_idx_t edge_index = 0; // position in the array gives index of edge
240 for (auto &e : edges) {
241 // Node indices of endpoints: the KEY
242 std::array<size_type, 2> end_nodes(e.first);
243 const EndpointIndexPair e_endpoint_idx(end_nodes[0], end_nodes[1]);
245 (end_nodes[0] < no_of_nodes) && (end_nodes[1] < no_of_nodes),
246 "Illegal edge node numbers
" << end_nodes[0] << ",
" << end_nodes[1]);
247 SPDLOG_LOGGER_TRACE(Logger(), "Register edge: {} <-> {}
", end_nodes[0],
250 // If one of the endpoints of a edge does not have a geometry, supply it
251 // with one inherited from the edge.
252 for (int j = 0; j < 2; ++j) {
253 if (nodes[end_nodes[j]] == nullptr) {
254 // if no geometry for node exists request geomtry for an endpoint of the
255 // edge Note: endpoints are entities of relative co-dimension 1
256 nodes[end_nodes[j]] = e.second->SubGeometry(1, j);
260 // Store provided geometry information; information on adjacent cells
261 // not yet available.
262 LF_ASSERT_MSG(e.second != nullptr,
263 "Edge
" << edge_index << ": missing geometry!
");
264 const AdjCellsList empty_cells_list{};
265 EdgeData edge_data(std::move(e.second), empty_cells_list, edge_index);
266 EdgeMap::value_type edge_info =
267 std::make_pair(e_endpoint_idx, std::move(edge_data));
268 const std::pair<EdgeMap::iterator, bool> insert_status =
269 edge_map.insert(std::move(edge_info));
270 LF_ASSERT_MSG(insert_status.second,
271 "Duplicate edge
" << end_nodes[0] << " <->
" << end_nodes[1]);
274 } // end loop over predefined edges
275 // ======================================================================
277 // ======================================================================
278 // Step II: Building edge map from cell information
280 // At this point all predefined edges have been stored in the auxiliary
281 // associative array, though without information about adjacent cells.
282 // The variable edge_index contains the number of edges with externally
283 // supplied geometry. The indexing of all extra edges created below must start
286 if (Logger()->should_log(spdlog::level::trace)) {
287 std::stringstream ss;
288 ss << "Edge map after edge registration
" << '\n';
289 for (auto &edge_info : edge_map) {
290 const EndpointIndexPair &eip(edge_info.first);
291 const EdgeData &edat(edge_info.second);
292 ss << "Edge
" << eip.first_node() << " <->
" << eip.second_node() << ":
";
293 const AdjCellsList &acl(edat.adj_cells_list);
294 const GeometryPtr &gptr(edat.geo_uptr);
295 for (const auto &i : acl) {
296 ss << "[
" << i.cell_idx << ",
" << i.edge_idx << "]
";
298 SPDLOG_LOGGER_TRACE(Logger(), ss.str());
302 // Run through cells in order to
303 // (i) build edges missing in the list of predefined edges
304 // (ii) determine cells adjacent to edges
305 size_type cell_index = 0;
306 size_type no_of_trilaterals = 0;
307 size_type no_of_quadrilaterals = 0;
309 SPDLOG_LOGGER_DEBUG(Logger(), "Scanning list of cells
");
311 for (const auto &c : cells) {
312 // node indices of corners of cell c
313 const std::array<size_type, 4> &cell_node_list(c.first);
314 // Geometry of current cell
315 const GeometryPtr &cell_geometry(c.second);
316 // Can be either a trilateral or a quadrilateral
317 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
318 // A triangle is marked by an invalid node number
319 // in the last position
320 size_type no_of_vertices;
321 if (cell_node_list[3] == idx_nil) {
322 no_of_vertices = 3; // triangle
325 no_of_vertices = 4; // quadrilateral
326 no_of_quadrilaterals++;
328 // Fix the type of the cell
329 const base::RefEl ref_el =
330 (no_of_vertices == 3) ? base::RefEl::kTria() : base::RefEl::kQuad();
331 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
333 std::stringstream ss_log_line;
334 if (Logger()->should_log(spdlog::level::trace)) {
335 ss_log_line << "Cell
" << cell_index;
336 if (no_of_vertices == 3) {
337 ss_log_line << ", tria
" << no_of_trilaterals << ":
";
339 ss_log_line << ", quad
" << no_of_quadrilaterals << ":
";
343 // Verify validity of vertex indices
344 for (unsigned l = 0; l < no_of_vertices; l++) {
345 LF_VERIFY_MSG(cell_node_list[l] < no_of_nodes,
346 "Node
" << l << " of cell
" << cell_index
347 << ": invalid index
" << cell_node_list[l]);
350 // If the cell has a geometry, it can be used to generate the
351 // geometry for its vertices through the SubGeometry() method of Geometry
353 if (cell_geometry != nullptr) {
354 for (unsigned j = 0; j < no_of_vertices; ++j) {
355 if (nodes[cell_node_list[j]] == nullptr) {
356 // if no geometry for node exists request geomtry for an vertex from
357 // the cell Note: vertices are entities of relative co-dimension 2
358 nodes[cell_node_list[j]] = cell_geometry->SubGeometry(2, j);
364 // There may be cells without a specified geometry.
365 // In case an edge is not equipped with a geometry and not
366 // adjacent to a cell with a specific geometry, assume a straight
367 // edge connecting the two endpoints.
370 // Visit all edges of the current cell
371 for (unsigned int j = 0; j < ref_el.NumSubEntities(1); j++) {
372 // Fetch local indices of endpoints of edge j
373 const size_type p0_local_index =
374 ref_el.SubSubEntity2SubEntity(1, j, 1, 0);
375 const size_type p1_local_index =
376 ref_el.SubSubEntity2SubEntity(1, j, 1, 1);
377 // Fetch global indices of the endnodes of edge j
378 const EndpointIndexPair c_edge_vertex_indices(
379 cell_node_list[p0_local_index], cell_node_list[p1_local_index]);
381 if (Logger()->should_log(spdlog::level::trace)) {
382 ss_log_line << "e(
" << j << ") = local
" << p0_local_index << " <->
"
383 << p1_local_index << ", global
"
384 << c_edge_vertex_indices.first_node() << " <->
"
385 << c_edge_vertex_indices.second_node() << " #
";
387 // Store number of cell and the local index j of the edge
388 const AdjCellInfo edge_cell_info(cell_index, j);
389 // Check whether edge exists already
390 auto edge_ptr = edge_map.find(c_edge_vertex_indices);
391 if (edge_ptr == edge_map.end()) {
392 // Inherit geometry of edge from adjacent cell
393 GeometryPtr edge_geo_ptr;
395 edge_geo_ptr = cell_geometry->SubGeometry(1, j);
397 // Beginning of list of adjacent elements
398 const AdjCellsList single_cell_list{edge_cell_info};
399 EdgeData edge_data(std::move(edge_geo_ptr), single_cell_list);
400 const std::pair<EdgeMap::iterator, bool> insert_status =
402 std::make_pair(c_edge_vertex_indices, std::move(edge_data)));
403 LF_ASSERT_MSG(insert_status.second, "Duplicate not found earlier!
");
404 edge_ptr = insert_status.first; // pointer to newly inserted edge
406 // Here *edge_ptr is a valid std::pair<EndpointIndexPair,EdgeData>
408 // Store information about neighboring cell
409 AdjCellsList &edge_adj_cellslist((edge_ptr->second).adj_cells_list);
410 edge_adj_cellslist.push_back(edge_cell_info);
411 // Check, if the edge possesses geometry information
412 GeometryPtr &edge_supplied_geo_uptr((*edge_ptr).second.geo_uptr);
413 if (edge_supplied_geo_uptr == nullptr) {
414 // Edge does not know its geometry yet. Try to obtain it from the
417 edge_supplied_geo_uptr =
418 std::move(cell_geometry->SubGeometry(1, j));
419 // NOTE: the local orientation of the edge of the cell and that
420 // pointed to by edge_ptr can differ. In this case the
421 // endpoints of the edge have to be swapped. To detect orientation
422 // mismatch, compare c_edge_vertex_indices (cell infomation) and
423 // edge_ptr->first (edge information)
424 if (!coincide(c_edge_vertex_indices, edge_ptr->first)) {
425 // Reverse the direction of the edge
426 (edge_ptr->second).reversed = true;
431 // At this point edge_ptr points to the map entry for the current edge
432 } // end of loop over edges
436 SPDLOG_LOGGER_TRACE(Logger(), ss_log_line.str());
437 } // end loop over cells
441 SPDLOG_LOGGER_DEBUG(Logger(),
442 "=============================================
");
444 if (Logger()->should_log(spdlog::level::trace)) {
445 SPDLOG_LOGGER_TRACE(Logger(), "Edge map after cell scan
");
447 size_type edge_cnt = 0;
448 for (auto &edge_info : edge_map) {
449 std::stringstream ss_log_line;
451 const EndpointIndexPair &eip(edge_info.first);
452 const EdgeData &edat(edge_info.second);
453 ss_log_line << "Edge
" << edge_cnt << ":
" << eip.first_node()
454 << " <->
" << eip.second_node();
455 if (edat.edge_global_index == -1) {
456 ss_log_line << " no index :
";
458 ss_log_line << ": index =
" << edat.edge_global_index << ":
";
460 const AdjCellsList &acl(edat.adj_cells_list);
461 const GeometryPtr &gptr(edat.geo_uptr);
462 for (const auto &i : acl) {
463 ss_log_line << "[
" << i.cell_idx << ",
" << i.edge_idx << "]
";
465 ss_log_line << " geo =
" << '\n';
467 const Eigen::MatrixXd edp_c(
468 gptr->Global(base::RefEl::kSegment().NodeCoords()));
469 ss_log_line << edp_c;
471 ss_log_line << "NO GEOMETRY
";
474 SPDLOG_LOGGER_TRACE(Logger(), ss_log_line.str());
476 SPDLOG_LOGGER_TRACE(Logger(),
477 "=============================================
");
481 // ======================================================================
482 // NEXT STEP : Set up and fill array of nodes: points_
483 // In the beginning initialize vector of vertices and do not touch it anymore
484 // Initialize vector for Node entities of size `no_of_nodes`
485 points_.reserve(no_of_nodes);
487 size_type node_index = 0;
488 for (hybrid2d::Mesh::GeometryPtr &pt_geo_ptr : nodes) {
489 // OLD VERSION. In the new version the geomtry of a point is passed in
490 // 'nodes' const Eigen::VectorXd &node_coordinates(v); GeometryPtr point_geo
491 // = std::make_unique<geometry::Point>(node_coordinates);
492 LF_VERIFY_MSG(pt_geo_ptr != nullptr,
493 "Missing geometry
for node
" << node_index);
495 Logger(), "-> Adding node {} at {}
", node_index,
496 (pt_geo_ptr->Global(Eigen::Matrix<double, 0, 1>())).transpose());
498 points_.emplace_back(node_index, std::move(pt_geo_ptr));
502 // Run through the entire associative container for edges
503 // and build edge Entities
504 // This is the length to be reserved for the edge vector
505 const size_type no_of_edges = edge_map.size();
507 // Initialized vector of Edge entities here
508 segments_.reserve(no_of_edges);
510 // if we check for mesh completeness, initialize a vector that stores for
511 // every node if he has a super entity.
512 std::vector<bool> nodeHasSuperEntity;
513 if (check_completeness) {
514 nodeHasSuperEntity.resize(nodes.size(), false);
517 // Note: the variable edge_index contains the number externally supplied
518 // edges, whose index must agree with their position in the
521 // Note: iteration variable cannot be declared const, because
522 // moving the geometry pointer changes it!
523 for (EdgeMap::value_type &edge : edge_map) {
524 // Indices of the two endpoints of the current edge
525 // Use this to obtain pointers/references to nodes
526 // from the vector of nodes
527 size_type p0(edge.first.first_node()); // index of first endpoint
528 size_type p1(edge.first.second_node()); // index of second endpoint
530 // Swap the indices of the endpoints in case of a geometry mismatch
531 // that requires a reversal of orientation.
532 if (edge.second.reversed) {
536 const Point *p0_ptr = &points_[p0]; // pointer to first endpoint
537 const Point *p1_ptr = &points_[p1]; // pointer to second endpoint
539 // obtain geometry of the edge
540 GeometryPtr edge_geo_ptr(std::move(edge.second.geo_uptr));
542 // If the edge does not have a geometry build a straight edge
543 Eigen::Matrix<double, 2, 2> straight_edge_coords;
544 straight_edge_coords.block<2, 1>(0, 0) =
545 p0_ptr->Geometry()->Global(zero_point);
546 straight_edge_coords.block<2, 1>(0, 1) =
547 p1_ptr->Geometry()->Global(zero_point);
549 std::make_unique<geometry::SegmentO1>(straight_edge_coords);
551 // Determine index of current edge. Two cases have to be distinguished:
552 // (i) the edge geometry was specified in the `edges` argument. In this case
553 // the edge index must agree with its possition in that array. This position
555 // (ii) the edge has to be created internally. In this case assign an index
556 // larger than the index of any supplied edge.
557 if (edge.second.edge_global_index == idx_nil) {
558 // Internally created edge needs new index.
559 edge.second.edge_global_index = edge_index;
560 // Increment 'edge_index', which will give the index of the next
561 // internally created edge
565 if (check_completeness) {
566 // record that the nodes of this edge have a super-entity (this edge):
567 nodeHasSuperEntity[p0] = true;
568 nodeHasSuperEntity[p1] = true;
570 // make sure that the edge belongs to at least one cell:
571 LF_VERIFY_MSG(!edge.second.adj_cells_list.empty(),
572 "
Mesh is incomplete: Edge with global index
"
573 << edge.second.edge_global_index
574 << " does not belong to a cell.
");
578 SPDLOG_LOGGER_TRACE(Logger(), "Registering edge {}: {} <-> {}
",
579 edge.second.edge_global_index, p0, p1);
580 // Building edge by adding another element to the edge vector.
581 segments_.emplace_back(edge.second.edge_global_index,
582 std::move(edge_geo_ptr), p0_ptr, p1_ptr);
583 } // end loop over all edges
584 LF_ASSERT_MSG(edge_index == no_of_edges, "Edge index mismatch
");
586 if (check_completeness) {
587 // Check that all nodes have a super entity:
588 for (std::size_t i = 0; i < nodes.size(); ++i) {
589 LF_VERIFY_MSG(nodeHasSuperEntity[i],
590 "Mesh is incomplete: Node with global index
"
591 << i << " is not part of any edge.
");
594 // ======================================================================
595 // NEXT STEP: Create cells
597 const size_type no_of_cells = cells.size();
599 // Create an auxiliary data structure to store the edges for the cells
600 // For every cell and its edges the global edge index is extracted
601 // from the auxiliary associative array.
602 std::vector<std::array<size_type, 4>> edge_indices(no_of_cells);
604 size_type edge_array_position = 0; // actual position in edge array
605 for (const EdgeMap::value_type &edge : edge_map) {
606 // Obtain array of indices of adjacent cells
607 const AdjCellsList adjacent_cells(edge.second.adj_cells_list);
608 for (const auto &adj_cell : adjacent_cells) {
609 const size_type adj_cell_index = adj_cell.cell_idx;
610 // Local index of edge in adjacent cell
611 const size_type edge_local_index = adj_cell.edge_idx;
612 LF_ASSERT_MSG(adj_cell_index < no_of_cells, "adj_cell_idx out of bounds
");
613 LF_ASSERT_MSG(edge_local_index < cells[adj_cell_index].first.size(),
614 "local edge index out of bounds
");
615 // Set edge index in auxiliary cell matrix
616 edge_indices[adj_cell_index][edge_local_index] = edge_array_position;
618 edge_array_position++;
622 SPDLOG_LOGGER_TRACE(Logger(), "########################################
");
623 SPDLOG_LOGGER_TRACE(Logger(), "Edge array indices
for cells
");
625 // Now complete information is available for the construction
626 // of cells = entities of co-dimension 0
627 // Initialize two vectors, one for trilaterals of size `no_of_trilaterals`
628 // and a second for quadrilaterals of size `no_of_quadrilaterals`
629 trias_.reserve(no_of_trilaterals);
630 quads_.reserve(no_of_quadrilaterals);
631 // Loop over all cells
633 for (auto &c : cells) {
634 // Node indices for the current cell
635 const std::array<size_type, 4> &c_node_indices(c.first);
636 const std::array<size_type, 4> &c_edge_indices(edge_indices[cell_index]);
637 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
638 // A triangle is marked by an invalid node number
639 // in the last position (also see above)
640 size_type no_of_vertices;
641 if (c_node_indices[3] == static_cast<size_type>(-1)) {
642 no_of_vertices = 3; // triangle
644 no_of_vertices = 4; // quadrilateral
647 // Verify validity of node/ede indices
648 for (unsigned l = 0; l < no_of_vertices; l++) {
649 LF_VERIFY_MSG(c_node_indices[l] < no_of_nodes,
650 "Node
" << l << " of cell
" << cell_index
651 << ": invalid index
" << c_node_indices[l]);
652 LF_VERIFY_MSG(c_edge_indices[l] < no_of_edges,
653 "Edge
" << l << " of cell
" << cell_index
654 << ": invalid index
" << c_edge_indices[l]);
657 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
658 GeometryPtr c_geo_ptr(std::move(c.second));
659 if (no_of_vertices == 3) {
660 // Case of a trilateral
664 Logger(), "Triangular cell {}: nodes {}, {}, {}, edges {}, {}, {}
",
665 cell_index, c_node_indices[0], c_node_indices[1], c_node_indices[2],
666 c_edge_indices[0], c_edge_indices[1], c_edge_indices[2]);
669 Add a trilateral entity to the vector of trilaterals
670 Use information in c_node_indices, c_edge_indices to
671 obtain pointers to nodes and edges.
674 const Point *corner0 = &points_[c_node_indices[0]];
675 const Point *corner1 = &points_[c_node_indices[1]];
676 const Point *corner2 = &points_[c_node_indices[2]];
677 const Segment *edge0 = &segments_[c_edge_indices[0]];
678 const Segment *edge1 = &segments_[c_edge_indices[1]];
679 const Segment *edge2 = &segments_[c_edge_indices[2]];
681 // Cell is lacking a geometry and its shape has to
682 // be determined from the shape of the edges or
683 // location of the vertices
684 // At this point only the latter policy is implemented
685 // and we build an affine triangle.
686 // First assemble corner coordinates into matrix
687 Eigen::Matrix<double, 2, 3> triag_corner_coords;
688 triag_corner_coords.block<2, 1>(0, 0) =
689 corner0->Geometry()->Global(zero_point);
690 triag_corner_coords.block<2, 1>(0, 1) =
691 corner1->Geometry()->Global(zero_point);
692 triag_corner_coords.block<2, 1>(0, 2) =
693 corner2->Geometry()->Global(zero_point);
696 SPDLOG_LOGGER_TRACE(Logger(), "Creating triangle with geometry \n{}
",
697 triag_corner_coords);
699 // Then create geometry of an affine triangle
700 c_geo_ptr = std::make_unique<geometry::TriaO1>(triag_corner_coords);
702 // If blended geometries are available, a cell could also
703 // inherit its geometry from the edges
705 trias_.emplace_back(cell_index, std::move(c_geo_ptr), corner0, corner1,
706 corner2, edge0, edge1, edge2);
708 // Case of a quadrilateral
711 SPDLOG_LOGGER_TRACE(Logger(), "Quadrilateral cell {}: nodes {}, edges {}
",
712 cell_index, c_node_indices, c_edge_indices);
715 Add a quadrilateral entity to the vector of quadrilaterals
716 Use information in c_node_indices, c_edge_indices to
717 obtain pointers to nodes and edges.
720 const Point *corner0 = &points_[c_node_indices[0]];
721 const Point *corner1 = &points_[c_node_indices[1]];
722 const Point *corner2 = &points_[c_node_indices[2]];
723 const Point *corner3 = &points_[c_node_indices[3]];
724 const Segment *edge0 = &segments_[c_edge_indices[0]];
725 const Segment *edge1 = &segments_[c_edge_indices[1]];
726 const Segment *edge2 = &segments_[c_edge_indices[2]];
727 const Segment *edge3 = &segments_[c_edge_indices[3]];
729 // Cell is lacking a geometry and its shape has to
730 // be determined from the shape of the edges or
731 // location of the vertices
732 // At this point we can only build a quadrilateral
733 // with straight edges ("bilinear quadrilateral
")
734 // First assemble corner coordinates into matrix
736 Eigen::Matrix<double, 2, 4> quad_corner_coords;
737 quad_corner_coords.block<2, 1>(0, 0) =
738 corner0->Geometry()->Global(zero_point);
739 quad_corner_coords.block<2, 1>(0, 1) =
740 corner1->Geometry()->Global(zero_point);
741 quad_corner_coords.block<2, 1>(0, 2) =
742 corner2->Geometry()->Global(zero_point);
743 quad_corner_coords.block<2, 1>(0, 3) =
744 corner3->Geometry()->Global(zero_point);
745 // Then create geometry of an affine triangle
748 SPDLOG_LOGGER_TRACE(Logger(),
749 "Creating quadrilateral with geometry\n{}
",
752 c_geo_ptr = std::make_unique<geometry::QuadO1>(quad_corner_coords);
754 quads_.emplace_back(cell_index, std::move(c_geo_ptr), corner0, corner1,
755 corner2, corner3, edge0, edge1, edge2, edge3);
759 // ======================================================================
760 // Initialization of auxiliary entity pointer arrays
762 // Order the cells according to their indices!
763 // First fill the array with NIL pointers
764 entity_pointers_[0] =
765 std::vector<const mesh::Entity *>(trias_.size() + quads_.size(), nullptr);
766 size_type cell_ptr_cnt = 0;
768 // First retrieve pointers to triangular cells
769 for (int j = 0; j < trias_.size(); j++, cell_ptr_cnt++) {
770 // Fetch index of a triangle by a non-virtual call to Index()
771 const glb_idx_t cell_index = lf::mesh::hybrid2d::Mesh::Index(trias_[j]);
772 LF_ASSERT_MSG(cell_index < entity_pointers_[0].size(),
773 "Cell index out of range
");
774 // This index must be unique !
775 LF_ASSERT_MSG(entity_pointers_[0][cell_index] == nullptr,
776 "Cell index
" << cell_index << " occurs twice!
");
777 entity_pointers_[0][cell_index] = &(trias_[j]);
778 } // end loop over triangles
780 // Second deal with the quadrilateral cells
781 for (int j = 0; j < quads_.size(); j++, cell_ptr_cnt++) {
782 // Fetch index of a quadrilateral by a non-virtual call to Index()
783 const glb_idx_t cell_index = lf::mesh::hybrid2d::Mesh::Index(quads_[j]);
784 LF_ASSERT_MSG(cell_index < entity_pointers_[0].size(),
785 "Cell index out of range
");
786 // This index must be unique !
787 LF_ASSERT_MSG(entity_pointers_[0][cell_index] == nullptr,
788 "Cell index
" << cell_index << " occurs twice!
");
789 entity_pointers_[0][cell_index] = &(quads_[j]);
791 LF_VERIFY_MSG(cell_ptr_cnt == entity_pointers_[0].size(),
792 "Size mismatch
for cell counters array
");
794 // Next the edges and nodes
796 entity_pointers_[1] =
797 std::vector<const mesh::Entity *>(segments_.size(), nullptr);
798 entity_pointers_[2] =
799 std::vector<const mesh::Entity *>(points_.size(), nullptr);
801 // set the entity pointers (note that the entities in segments_ and points_
802 // are not ordered according to their index):
803 for (auto &p : points_) {
804 entity_pointers_[2][p.index()] = &p;
806 for (auto &s : segments_) {
807 entity_pointers_[1][s.index()] = &s;
810} // namespace lf::mesh::hybrid2d