DOLFINx 0.10.0.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1// Copyright (C) 2019-2024 Garth N. Wells
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include "Mesh.h"
10#include "Topology.h"
11#include "graphbuild.h"
12#include <algorithm>
13#include <basix/mdspan.hpp>
14#include <concepts>
15#include <dolfinx/graph/AdjacencyList.h>
16#include <dolfinx/graph/ordering.h>
17#include <dolfinx/graph/partition.h>
18#include <functional>
19#include <mpi.h>
20#include <numeric>
21#include <span>
22
25
26namespace dolfinx::fem
27{
28class ElementDofLayout;
29}
30
31namespace dolfinx::mesh
32{
33enum class CellType;
34
36enum class GhostMode : int
37{
38 none,
39 shared_facet,
40 shared_vertex
41};
42
43namespace impl
44{
50template <typename T>
51void reorder_list(std::span<T> list, std::span<const std::int32_t> nodemap)
52{
53 if (nodemap.empty())
54 return;
55
56 assert(list.size() % nodemap.size() == 0);
57 std::size_t degree = list.size() / nodemap.size();
58 const std::vector<T> orig(list.begin(), list.end());
59 for (std::size_t n = 0; n < nodemap.size(); ++n)
60 {
61 std::span links_old(orig.data() + n * degree, degree);
62 auto links_new = list.subspan(nodemap[n] * degree, degree);
63 std::ranges::copy(links_old, links_new.begin());
64 }
65}
66
80template <std::floating_point T>
81std::tuple<std::vector<std::int32_t>, std::vector<T>, std::vector<std::int32_t>>
83 std::span<const std::int32_t> facets)
84{
85 auto topology = mesh.topology();
86 assert(topology);
87 const int tdim = topology->dim();
88 if (dim == tdim)
89 {
90 throw std::runtime_error(
91 "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
92 }
93
94 // Build set of vertices on boundary and set of boundary entities
95 mesh.topology_mutable()->create_connectivity(tdim - 1, 0);
96 mesh.topology_mutable()->create_connectivity(tdim - 1, dim);
97 std::vector<std::int32_t> vertices, entities;
98 {
99 auto f_to_v = topology->connectivity(tdim - 1, 0);
100 assert(f_to_v);
101 auto f_to_e = topology->connectivity(tdim - 1, dim);
102 assert(f_to_e);
103 for (auto f : facets)
104 {
105 auto v = f_to_v->links(f);
106 vertices.insert(vertices.end(), v.begin(), v.end());
107 auto e = f_to_e->links(f);
108 entities.insert(entities.end(), e.begin(), e.end());
109 }
110
111 // Build vector of boundary vertices
112 {
113 std::ranges::sort(vertices);
114 auto [unique_end, range_end] = std::ranges::unique(vertices);
115 vertices.erase(unique_end, range_end);
116 }
117
118 {
119 std::ranges::sort(entities);
120 auto [unique_end, range_end] = std::ranges::unique(entities);
121 entities.erase(unique_end, range_end);
122 }
123 }
124
125 // Get geometry data
126 auto x_dofmap = mesh.geometry().dofmap();
127 std::span<const T> x_nodes = mesh.geometry().x();
128
129 // Get all vertex 'node' indices
130 mesh.topology_mutable()->create_connectivity(0, tdim);
131 mesh.topology_mutable()->create_connectivity(tdim, 0);
132 auto v_to_c = topology->connectivity(0, tdim);
133 assert(v_to_c);
134 auto c_to_v = topology->connectivity(tdim, 0);
135 assert(c_to_v);
136 std::vector<T> x_vertices(3 * vertices.size(), -1.0);
137 std::vector<std::int32_t> vertex_to_pos(v_to_c->num_nodes(), -1);
138 for (std::size_t i = 0; i < vertices.size(); ++i)
139 {
140 const std::int32_t v = vertices[i];
141
142 // Get first cell and find position
143 const std::int32_t c = v_to_c->links(v).front();
144 auto cell_vertices = c_to_v->links(c);
145 auto it = std::find(cell_vertices.begin(), cell_vertices.end(), v);
146 assert(it != cell_vertices.end());
147 const std::size_t local_pos = std::distance(cell_vertices.begin(), it);
148
149 auto dofs = MDSPAN_IMPL_STANDARD_NAMESPACE::submdspan(
150 x_dofmap, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
151 for (std::size_t j = 0; j < 3; ++j)
152 x_vertices[j * vertices.size() + i] = x_nodes[3 * dofs[local_pos] + j];
153 vertex_to_pos[v] = i;
154 }
155
156 return {std::move(entities), std::move(x_vertices), std::move(vertex_to_pos)};
157}
158
159} // namespace impl
160
172std::vector<std::int32_t> exterior_facet_indices(const Topology& topology);
173
191using CellPartitionFunction = std::function<graph::AdjacencyList<std::int32_t>(
192 MPI_Comm comm, int nparts, const std::vector<CellType>& cell_types,
193 const std::vector<std::span<const std::int64_t>>& cells)>;
194
204std::vector<std::int64_t> extract_topology(CellType cell_type,
205 const fem::ElementDofLayout& layout,
206 std::span<const std::int64_t> cells);
207
216template <std::floating_point T>
217std::vector<T> h(const Mesh<T>& mesh, std::span<const std::int32_t> entities,
218 int dim)
219{
220 if (entities.empty())
221 return std::vector<T>();
222 if (dim == 0)
223 return std::vector<T>(entities.size(), 0);
224
225 // Get the geometry dofs for the vertices of each entity
226 const std::vector<std::int32_t> vertex_xdofs
227 = entities_to_geometry(mesh, dim, entities, false);
228 assert(!entities.empty());
229 const std::size_t num_vertices = vertex_xdofs.size() / entities.size();
230
231 // Get the geometry coordinate
232 std::span<const T> x = mesh.geometry().x();
233
234 // Function to compute the length of (p0 - p1)
235 auto delta_norm = [](auto&& p0, auto&& p1)
236 {
237 T norm = 0;
238 for (std::size_t i = 0; i < 3; ++i)
239 norm += (p0[i] - p1[i]) * (p0[i] - p1[i]);
240 return std::sqrt(norm);
241 };
242
243 // Compute greatest distance between any to vertices
244 assert(dim > 0);
245 std::vector<T> h(entities.size(), 0);
246 for (std::size_t e = 0; e < entities.size(); ++e)
247 {
248 // Get geometry 'dof' for each vertex of entity e
249 std::span<const std::int32_t> e_vertices(
250 vertex_xdofs.data() + e * num_vertices, num_vertices);
251
252 // Compute maximum distance between any two vertices
253 for (std::size_t i = 0; i < e_vertices.size(); ++i)
254 {
255 std::span<const T, 3> p0(x.data() + 3 * e_vertices[i], 3);
256 for (std::size_t j = i + 1; j < e_vertices.size(); ++j)
257 {
258 std::span<const T, 3> p1(x.data() + 3 * e_vertices[j], 3);
259 h[e] = std::max(h[e], delta_norm(p0, p1));
260 }
261 }
262 }
263
264 return h;
265}
266
270template <std::floating_point T>
271std::vector<T> cell_normals(const Mesh<T>& mesh, int dim,
272 std::span<const std::int32_t> entities)
273{
274 if (entities.empty())
275 return std::vector<T>();
276
277 auto topology = mesh.topology();
278 assert(topology);
279 if (topology->cell_type() == CellType::prism and dim == 2)
280 {
281 throw std::runtime_error(
282 "Cell normal computation for prism cells not yet supported.");
283 }
284
285 const int gdim = mesh.geometry().dim();
286 const CellType type = cell_entity_type(topology->cell_type(), dim, 0);
287
288 // Find geometry nodes for topology entities
289 std::span<const T> x = mesh.geometry().x();
290 std::vector<std::int32_t> geometry_entities
291 = entities_to_geometry(mesh, dim, entities, false);
292
293 const std::size_t shape1 = geometry_entities.size() / entities.size();
294 std::vector<T> n(entities.size() * 3);
295 switch (type)
296 {
297 case CellType::interval:
298 {
299 if (gdim > 2)
300 throw std::invalid_argument("Interval cell normal undefined in 3D.");
301 for (std::size_t i = 0; i < entities.size(); ++i)
302 {
303 // Get the two vertices as points
304 std::array vertices{geometry_entities[i * shape1],
305 geometry_entities[i * shape1 + 1]};
306 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
307 std::span<const T, 3>(x.data() + 3 * vertices[1], 3)};
308
309 // Define normal by rotating tangent counter-clockwise
310 std::array<T, 3> t;
311 std::ranges::transform(p[1], p[0], t.begin(),
312 [](auto x, auto y) { return x - y; });
313
314 T norm = std::sqrt(t[0] * t[0] + t[1] * t[1]);
315 std::span<T, 3> ni(n.data() + 3 * i, 3);
316 ni[0] = -t[1] / norm;
317 ni[1] = t[0] / norm;
318 ni[2] = 0.0;
319 }
320 return n;
321 }
322 case CellType::triangle:
323 {
324 for (std::size_t i = 0; i < entities.size(); ++i)
325 {
326 // Get the three vertices as points
327 std::array vertices = {geometry_entities[i * shape1 + 0],
328 geometry_entities[i * shape1 + 1],
329 geometry_entities[i * shape1 + 2]};
330 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
331 std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
332 std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
333
334 // Compute (p1 - p0) and (p2 - p0)
335 std::array<T, 3> dp1, dp2;
336 std::ranges::transform(p[1], p[0], dp1.begin(),
337 [](auto x, auto y) { return x - y; });
338 std::ranges::transform(p[2], p[0], dp2.begin(),
339 [](auto x, auto y) { return x - y; });
340
341 // Define cell normal via cross product of first two edges
342 std::array<T, 3> ni = math::cross(dp1, dp2);
343 T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
344 std::ranges::transform(ni, std::next(n.begin(), 3 * i),
345 [norm](auto x) { return x / norm; });
346 }
347
348 return n;
349 }
350 case CellType::quadrilateral:
351 {
352 // TODO: check
353 for (std::size_t i = 0; i < entities.size(); ++i)
354 {
355 // Get the three vertices as points
356 std::array vertices = {geometry_entities[i * shape1 + 0],
357 geometry_entities[i * shape1 + 1],
358 geometry_entities[i * shape1 + 2]};
359 std::array p = {std::span<const T, 3>(x.data() + 3 * vertices[0], 3),
360 std::span<const T, 3>(x.data() + 3 * vertices[1], 3),
361 std::span<const T, 3>(x.data() + 3 * vertices[2], 3)};
362
363 // Compute (p1 - p0) and (p2 - p0)
364 std::array<T, 3> dp1, dp2;
365 std::ranges::transform(p[1], p[0], dp1.begin(),
366 [](auto x, auto y) { return x - y; });
367 std::ranges::transform(p[2], p[0], dp2.begin(),
368 [](auto x, auto y) { return x - y; });
369
370 // Define cell normal via cross product of first two edges
371 std::array<T, 3> ni = math::cross(dp1, dp2);
372 T norm = std::sqrt(ni[0] * ni[0] + ni[1] * ni[1] + ni[2] * ni[2]);
373 std::ranges::transform(ni, std::next(n.begin(), 3 * i),
374 [norm](auto x) { return x / norm; });
375 }
376
377 return n;
378 }
379 default:
380 throw std::invalid_argument(
381 "cell_normal not supported for this cell type.");
382 }
383}
384
388template <std::floating_point T>
389std::vector<T> compute_midpoints(const Mesh<T>& mesh, int dim,
390 std::span<const std::int32_t> entities)
391{
392 if (entities.empty())
393 return std::vector<T>();
394
395 std::span<const T> x = mesh.geometry().x();
396
397 // Build map from entity -> geometry dof
398 const std::vector<std::int32_t> e_to_g
399 = entities_to_geometry(mesh, dim, entities, false);
400 std::size_t shape1 = e_to_g.size() / entities.size();
401
402 std::vector<T> x_mid(entities.size() * 3, 0);
403 for (std::size_t e = 0; e < entities.size(); ++e)
404 {
405 std::span<T, 3> p(x_mid.data() + 3 * e, 3);
406 std::span<const std::int32_t> rows(e_to_g.data() + e * shape1, shape1);
407 for (auto row : rows)
408 {
409 std::span<const T, 3> xg(x.data() + 3 * row, 3);
410 std::ranges::transform(p, xg, p.begin(),
411 [size = rows.size()](auto x, auto y)
412 { return x + y / size; });
413 }
414 }
415
416 return x_mid;
417}
418
419namespace impl
420{
425template <std::floating_point T>
426std::pair<std::vector<T>, std::array<std::size_t, 2>>
428{
429 auto topology = mesh.topology();
430 assert(topology);
431 const int tdim = topology->dim();
432
433 // Create entities and connectivities
434 mesh.topology_mutable()->create_connectivity(tdim, 0);
435
436 // Get all vertex 'node' indices
437 auto x_dofmap = mesh.geometry().dofmap();
438 const std::int32_t num_vertices = topology->index_map(0)->size_local()
439 + topology->index_map(0)->num_ghosts();
440 auto c_to_v = topology->connectivity(tdim, 0);
441 assert(c_to_v);
442 std::vector<std::int32_t> vertex_to_node(num_vertices);
443 for (int c = 0; c < c_to_v->num_nodes(); ++c)
444 {
445 auto x_dofs = MDSPAN_IMPL_STANDARD_NAMESPACE::submdspan(
446 x_dofmap, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
447 auto vertices = c_to_v->links(c);
448 for (std::size_t i = 0; i < vertices.size(); ++i)
449 vertex_to_node[vertices[i]] = x_dofs[i];
450 }
451
452 // Pack coordinates of vertices
453 std::span<const T> x_nodes = mesh.geometry().x();
454 std::vector<T> x_vertices(3 * vertex_to_node.size(), 0.0);
455 for (std::size_t i = 0; i < vertex_to_node.size(); ++i)
456 {
457 std::int32_t pos = 3 * vertex_to_node[i];
458 for (std::size_t j = 0; j < 3; ++j)
459 x_vertices[j * vertex_to_node.size() + i] = x_nodes[pos + j];
460 }
461
462 return {std::move(x_vertices), {3, vertex_to_node.size()}};
463}
464
465} // namespace impl
466
468template <typename Fn, typename T>
469concept MarkerFn = std::is_invocable_r<
470 std::vector<std::int8_t>, Fn,
471 MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
472 const T, MDSPAN_IMPL_STANDARD_NAMESPACE::extents<
473 std::size_t, 3,
474 MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent>>>::value;
475
489template <std::floating_point T, MarkerFn<T> U>
490std::vector<std::int32_t> locate_entities(const Mesh<T>& mesh, int dim,
491 U marker)
492{
493 using cmdspan3x_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
494 const T,
495 MDSPAN_IMPL_STANDARD_NAMESPACE::extents<
496 std::size_t, 3, MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent>>;
497
498 // Run marker function on vertex coordinates
499 const auto [xdata, xshape] = impl::compute_vertex_coords(mesh);
500 cmdspan3x_t x(xdata.data(), xshape);
501 const std::vector<std::int8_t> marked = marker(x);
502 if (marked.size() != x.extent(1))
503 throw std::runtime_error("Length of array of markers is wrong.");
504
505 auto topology = mesh.topology();
506 assert(topology);
507 const int tdim = topology->dim();
508
509 mesh.topology_mutable()->create_entities(dim);
510 mesh.topology_mutable()->create_connectivity(tdim, 0);
511 if (dim < tdim)
512 mesh.topology_mutable()->create_connectivity(dim, 0);
513
514 // Iterate over entities of dimension 'dim' to build vector of marked
515 // entities
516 auto e_to_v = topology->connectivity(dim, 0);
517 assert(e_to_v);
518 std::vector<std::int32_t> entities;
519 for (int e = 0; e < e_to_v->num_nodes(); ++e)
520 {
521 // Iterate over entity vertices
522 bool all_vertices_marked = true;
523 for (std::int32_t v : e_to_v->links(e))
524 {
525 if (!marked[v])
526 {
527 all_vertices_marked = false;
528 break;
529 }
530 }
531
532 if (all_vertices_marked)
533 entities.push_back(e);
534 }
535
536 return entities;
537}
538
562template <std::floating_point T, MarkerFn<T> U>
563std::vector<std::int32_t> locate_entities_boundary(const Mesh<T>& mesh, int dim,
564 U marker)
565{
566 auto topology = mesh.topology();
567 assert(topology);
568 int tdim = topology->dim();
569 if (dim == tdim)
570 {
571 throw std::runtime_error(
572 "Cannot use mesh::locate_entities_boundary (boundary) for cells.");
573 }
574
575 // Compute list of boundary facets
576 mesh.topology_mutable()->create_entities(tdim - 1);
577 mesh.topology_mutable()->create_connectivity(tdim - 1, tdim);
578 std::vector<std::int32_t> boundary_facets = exterior_facet_indices(*topology);
579
580 using cmdspan3x_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
581 const T,
582 MDSPAN_IMPL_STANDARD_NAMESPACE::extents<
583 std::size_t, 3, MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent>>;
584
585 // Run marker function on the vertex coordinates
586 auto [facet_entities, xdata, vertex_to_pos]
587 = impl::compute_vertex_coords_boundary(mesh, dim, boundary_facets);
588 cmdspan3x_t x(xdata.data(), 3, xdata.size() / 3);
589 std::vector<std::int8_t> marked = marker(x);
590 if (marked.size() != x.extent(1))
591 throw std::runtime_error("Length of array of markers is wrong.");
592
593 // Loop over entities and check vertex markers
594 mesh.topology_mutable()->create_entities(dim);
595 auto e_to_v = topology->connectivity(dim, 0);
596 assert(e_to_v);
597 std::vector<std::int32_t> entities;
598 for (auto e : facet_entities)
599 {
600 // Iterate over entity vertices
601 bool all_vertices_marked = true;
602 for (auto v : e_to_v->links(e))
603 {
604 const std::int32_t pos = vertex_to_pos[v];
605 if (!marked[pos])
606 {
607 all_vertices_marked = false;
608 break;
609 }
610 }
611
612 // Mark facet with all vertices marked
613 if (all_vertices_marked)
614 entities.push_back(e);
615 }
616
617 return entities;
618}
619
638template <std::floating_point T>
639std::vector<std::int32_t>
640entities_to_geometry(const Mesh<T>& mesh, int dim,
641 std::span<const std::int32_t> entities,
642 bool permute = false)
643{
644 auto topology = mesh.topology();
645 assert(topology);
646 CellType cell_type = topology->cell_type();
647 if (cell_type == CellType::prism and dim == 2)
648 {
649 throw std::runtime_error(
650 "mesh::entities_to_geometry for prism cells not yet supported.");
651 }
652
653 const int tdim = topology->dim();
654 const Geometry<T>& geometry = mesh.geometry();
655 auto xdofs = geometry.dofmap();
656
657 // Get the DOF layout and the number of DOFs per entity
658 const fem::CoordinateElement<T>& coord_ele = geometry.cmap();
659 const fem::ElementDofLayout layout = coord_ele.create_dof_layout();
660 const std::size_t num_entity_dofs = layout.num_entity_closure_dofs(dim);
661 std::vector<std::int32_t> entity_xdofs;
662 entity_xdofs.reserve(entities.size() * num_entity_dofs);
663
664 // Get the element's closure DOFs
665 const std::vector<std::vector<std::vector<int>>>& closure_dofs_all
666 = layout.entity_closure_dofs_all();
667
668 // Special case when dim == tdim (cells)
669 if (dim == tdim)
670 {
671 for (std::size_t i = 0; i < entities.size(); ++i)
672 {
673 const std::int32_t c = entities[i];
674 // Extract degrees of freedom
675 auto x_c = MDSPAN_IMPL_STANDARD_NAMESPACE::submdspan(
676 xdofs, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
677 for (std::int32_t entity_dof : closure_dofs_all[tdim][0])
678 entity_xdofs.push_back(x_c[entity_dof]);
679 }
680 return entity_xdofs;
681 }
682
683 assert(dim != tdim);
684
685 auto e_to_c = topology->connectivity(dim, tdim);
686 if (!e_to_c)
687 {
688 throw std::runtime_error(
689 "Entity-to-cell connectivity has not been computed. Missing dims "
690 + std::to_string(dim) + "->" + std::to_string(tdim));
691 }
692
693 auto c_to_e = topology->connectivity(tdim, dim);
694 if (!c_to_e)
695 {
696 throw std::runtime_error(
697 "Cell-to-entity connectivity has not been computed. Missing dims "
698 + std::to_string(tdim) + "->" + std::to_string(dim));
699 }
700
701 // Get the cell info, which is needed to permute the closure dofs
702 std::span<const std::uint32_t> cell_info;
703 if (permute)
704 cell_info = std::span(mesh.topology()->get_cell_permutation_info());
705
706 for (std::size_t i = 0; i < entities.size(); ++i)
707 {
708 const std::int32_t e = entities[i];
709
710 // Get a cell connected to the entity
711 assert(!e_to_c->links(e).empty());
712 std::int32_t c = e_to_c->links(e).front();
713
714 // Get the local index of the entity
715 std::span<const std::int32_t> cell_entities = c_to_e->links(c);
716 auto it = std::find(cell_entities.begin(), cell_entities.end(), e);
717 assert(it != cell_entities.end());
718 std::size_t local_entity = std::distance(cell_entities.begin(), it);
719
720 std::vector<std::int32_t> closure_dofs(closure_dofs_all[dim][local_entity]);
721
722 // Cell sub-entities must be permuted so that their local
723 // orientation agrees with their global orientation
724 if (permute)
725 {
726 mesh::CellType entity_type
727 = mesh::cell_entity_type(cell_type, dim, local_entity);
728 coord_ele.permute_subentity_closure(closure_dofs, cell_info[c],
729 entity_type, local_entity);
730 }
731
732 // Extract degrees of freedom
733 auto x_c = MDSPAN_IMPL_STANDARD_NAMESPACE::submdspan(
734 xdofs, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
735 for (std::int32_t entity_dof : closure_dofs)
736 entity_xdofs.push_back(x_c[entity_dof]);
737 }
738
739 return entity_xdofs;
740}
741
747 = mesh::GhostMode::none,
748 const graph::partition_fn& partfn
750
758std::vector<std::int32_t>
759compute_incident_entities(const Topology& topology,
760 std::span<const std::int32_t> entities, int d0,
761 int d1);
762
802template <typename U>
804 MPI_Comm comm, MPI_Comm commt,
805 std::vector<std::span<const std::int64_t>> cells,
806 const std::vector<fem::CoordinateElement<
807 typename std::remove_reference_t<typename U::value_type>>>& elements,
808 MPI_Comm commg, const U& x, std::array<std::size_t, 2> xshape,
809 const CellPartitionFunction& partitioner)
810{
811 assert(cells.size() == elements.size());
812 std::vector<CellType> celltypes;
813 std::ranges::transform(elements, std::back_inserter(celltypes),
814 [](auto e) { return e.cell_shape(); });
815 std::vector<fem::ElementDofLayout> doflayouts;
816 std::ranges::transform(elements, std::back_inserter(doflayouts),
817 [](auto e) { return e.create_dof_layout(); });
818
819 // Note: `extract_topology` extracts topology data, i.e. just the
820 // vertices. For P1 geometry this should just be the identity
821 // operator. For other elements the filtered lists may have 'gaps',
822 // i.e. the indices might not be contiguous.
823 //
824 // `extract_topology` could be skipped for 'P1 geometry' elements
825
826 std::int32_t num_cell_types = cells.size();
827
828 // -- Partition topology across ranks of comm
829 std::vector<std::vector<std::int64_t>> cells1(num_cell_types);
830 std::vector<std::vector<std::int64_t>> original_idx1(num_cell_types);
831 std::vector<std::vector<int>> ghost_owners(num_cell_types);
832 if (partitioner)
833 {
834 spdlog::info("Using partitioner with cell data ({} cell types)",
835 num_cell_types);
837 if (commt != MPI_COMM_NULL)
838 {
839 int size = dolfinx::MPI::size(comm);
840 std::vector<std::vector<std::int64_t>> t(num_cell_types);
841 std::vector<std::span<const std::int64_t>> tspan(num_cell_types);
842 for (std::int32_t i = 0; i < num_cell_types; ++i)
843 {
844 t[i] = extract_topology(celltypes[i], doflayouts[i], cells[i]);
845 tspan[i] = std::span(t[i]);
846 }
847 dest = partitioner(commt, size, celltypes, tspan);
848 }
849
850 std::int32_t cell_offset = 0;
851 for (std::int32_t i = 0; i < num_cell_types; ++i)
852 {
853 std::size_t num_cell_nodes = doflayouts[i].num_dofs();
854 assert(cells[i].size() % num_cell_nodes == 0);
855 std::size_t num_cells = cells[i].size() / num_cell_nodes;
856
857 // Extract destination AdjacencyList for this cell type
858 std::vector<std::int32_t> offsets_i(
859 std::next(dest.offsets().begin(), cell_offset),
860 std::next(dest.offsets().begin(), cell_offset + num_cells + 1));
861 std::vector<std::int32_t> data_i(
862 std::next(dest.array().begin(), offsets_i.front()),
863 std::next(dest.array().begin(), offsets_i.back()));
864 std::int32_t offset_0 = offsets_i.front();
865 std::ranges::for_each(offsets_i,
866 [&offset_0](std::int32_t& j) { j -= offset_0; });
867 graph::AdjacencyList<std::int32_t> dest_i(data_i, offsets_i);
868 cell_offset += num_cells;
869
870 // Distribute cells (topology, includes higher-order 'nodes') to
871 // destination rank
872 std::vector<int> src_ranks;
873 std::tie(cells1[i], src_ranks, original_idx1[i], ghost_owners[i])
874 = graph::build::distribute(comm, cells[i],
875 {num_cells, num_cell_nodes}, dest_i);
876 spdlog::debug("Got {} cells from distribution", cells1[i].size());
877 }
878 }
879 else
880 {
881 // No partitioning, construct a global index
882 std::int64_t num_owned = 0;
883 for (std::int32_t i = 0; i < num_cell_types; ++i)
884 {
885 cells1[i] = std::vector<std::int64_t>(cells[i].begin(), cells[i].end());
886 std::int32_t num_cell_nodes = doflayouts[i].num_dofs();
887 assert(cells1[i].size() % num_cell_nodes == 0);
888 original_idx1[i].resize(cells1[i].size() / num_cell_nodes);
889 num_owned += original_idx1[i].size();
890 }
891
892 // Add on global offset
893 std::int64_t global_offset = 0;
894 MPI_Exscan(&num_owned, &global_offset, 1, MPI_INT64_T, MPI_SUM, comm);
895 for (std::int32_t i = 0; i < num_cell_types; ++i)
896 {
897 std::iota(original_idx1[i].begin(), original_idx1[i].end(),
898 global_offset);
899 global_offset += original_idx1[i].size();
900 }
901 }
902
903 // Extract cell 'topology', i.e. extract the vertices for each cell
904 // and discard any 'higher-order' nodes
905 std::vector<std::vector<std::int64_t>> cells1_v(num_cell_types);
906 for (std::int32_t i = 0; i < num_cell_types; ++i)
907 {
908 cells1_v[i] = extract_topology(celltypes[i], doflayouts[i], cells1[i]);
909 spdlog::info("Extract basic topology: {}->{}", cells1[i].size(),
910 cells1_v[i].size());
911 }
912
913 // Build local dual graph for owned cells to (i) get list of vertices
914 // on the process boundary and (ii) apply re-ordering to cells for
915 // locality
916 auto boundary_v_fn = [](const std::vector<CellType>& celltypes,
917 const std::vector<fem::ElementDofLayout>& doflayouts,
918 const std::vector<std::vector<int>>& ghost_owners,
919 std::vector<std::vector<std::int64_t>>& cells1,
920 std::vector<std::vector<std::int64_t>>& cells1_v,
921 std::vector<std::vector<std::int64_t>>& original_idx1)
922 {
923 spdlog::info("Build local dual graphs, re-order cells, and compute process "
924 "boundary vertices.");
925
926 std::vector<std::pair<std::vector<std::int64_t>, int>> facets;
927
928 // Build lists of cells (by cell type) that excludes ghosts
929 std::vector<std::span<const std::int64_t>> cells1_v_local;
930 for (std::size_t i = 0; i < celltypes.size(); ++i)
931 {
932 int num_cell_vertices = mesh::num_cell_vertices(celltypes[i]);
933 std::size_t num_owned_cells
934 = cells1_v[i].size() / num_cell_vertices - ghost_owners[i].size();
935 cells1_v_local.emplace_back(cells1_v[i].data(),
936 num_owned_cells * num_cell_vertices);
937
938 // Build local dual graph for cell type
939 auto [graph, unmatched_facets, max_v, _facet_attached_cells]
940 = build_local_dual_graph(std::vector{celltypes[i]},
941 std::vector{cells1_v_local.back()});
942
943 // Store unmatched_facets for current cell type
944 facets.emplace_back(std::move(unmatched_facets), max_v);
945
946 // Compute re-ordering of graph
947 const std::vector<std::int32_t> remap = graph::reorder_gps(graph);
948
949 // Update 'original' indices
950 const std::vector<std::int64_t>& orig_idx = original_idx1[i];
951 std::vector<std::int64_t> _original_idx(orig_idx.size());
952 std::copy_n(orig_idx.rbegin(), ghost_owners[i].size(),
953 _original_idx.rbegin());
954 {
955 for (std::size_t j = 0; j < remap.size(); ++j)
956 _original_idx[remap[j]] = orig_idx[j];
957 }
958 original_idx1[i] = _original_idx;
959
960 // Reorder cells
961 impl::reorder_list(
962 std::span(cells1_v[i].data(), remap.size() * num_cell_vertices),
963 remap);
964 impl::reorder_list(
965 std::span(cells1[i].data(), remap.size() * doflayouts[i].num_dofs()),
966 remap);
967 }
968
969 if (facets.size() == 1) // Optimisation for single cell type
970 {
971 std::vector<std::int64_t>& vertices = facets.front().first;
972
973 // Remove duplicated vertex indices
974 std::ranges::sort(vertices);
975 auto [unique_end, range_end] = std::ranges::unique(vertices);
976 vertices.erase(unique_end, range_end);
977
978 // Remove -1 if it appears as first entity. This can happen in
979 // mixed topology meshes where '-1' is used to pad facet data when
980 // cells facets have differing numbers of vertices.
981 if (!vertices.empty() and vertices.front() == -1)
982 vertices.erase(vertices.begin());
983
984 return vertices;
985 }
986 else
987 {
988 // Pack 'unmatched' facets for all cell types into single array
989 // (facets0)
990 std::vector<std::int64_t> facets0;
991 facets0.reserve(std::accumulate(facets.begin(), facets.end(),
992 std::size_t(0), [](std::size_t x, auto& y)
993 { return x + y.first.size(); }));
994 int max_v = std::ranges::max_element(facets, [](auto& a, auto& b)
995 { return a.second < b.second; })
996 ->second;
997 for (const auto& [v_data, num_v] : facets)
998 {
999 for (auto it = v_data.begin(); it != v_data.end(); it += num_v)
1000 {
1001 facets0.insert(facets0.end(), it, std::next(it, num_v));
1002 facets0.insert(facets0.end(), max_v - num_v, -1);
1003 }
1004 }
1005
1006 // Compute row permutation
1007 const std::vector<std::int32_t> perm = dolfinx::sort_by_perm(
1008 std::span<const std::int64_t>(facets0), max_v);
1009
1010 // For facets in facets0 that appear only once, store the facet
1011 // vertices
1012 std::vector<std::int64_t> vertices;
1013 auto it = perm.begin();
1014 while (it != perm.end())
1015 {
1016 // Find iterator to next facet different from f and trim any -1
1017 // padding
1018 std::span _f(facets0.data() + (*it) * max_v, max_v);
1019 auto end = std::find_if(_f.rbegin(), _f.rend(),
1020 [](auto a) { return a >= 0; });
1021 auto f = _f.first(std::distance(end, _f.rend()));
1022
1023 auto it1 = std::find_if_not(
1024 it, perm.end(),
1025 [f, max_v, it0 = facets0.begin()](auto p) -> bool
1026 {
1027 return std::equal(f.begin(), f.end(), std::next(it0, p * max_v));
1028 });
1029
1030 // If no repeated facet found, insert f vertices
1031 if (std::distance(it, it1) == 1)
1032 vertices.insert(vertices.end(), f.begin(), f.end());
1033 else if (std::distance(it, it1) > 2)
1034 throw std::runtime_error("More than two matching facets found.");
1035
1036 // Advance iterator
1037 it = it1;
1038 }
1039
1040 // Remove duplicate indices
1041 std::ranges::sort(vertices);
1042 auto [unique_end, range_end] = std::ranges::unique(vertices);
1043 vertices.erase(unique_end, range_end);
1044
1045 return vertices;
1046 }
1047 };
1048
1049 const std::vector<std::int64_t> boundary_v = boundary_v_fn(
1050 celltypes, doflayouts, ghost_owners, cells1, cells1_v, original_idx1);
1051
1052 spdlog::debug("Got {} boundary vertices", boundary_v.size());
1053
1054 // Create Topology
1055 std::vector<std::span<const std::int64_t>> cells1_v_span;
1056 std::ranges::transform(cells1_v, std::back_inserter(cells1_v_span),
1057 [](auto& c) { return std::span(c); });
1058 std::vector<std::span<const std::int64_t>> original_idx1_span;
1059 std::ranges::transform(original_idx1, std::back_inserter(original_idx1_span),
1060 [](auto& c) { return std::span(c); });
1061 std::vector<std::span<const int>> ghost_owners_span;
1062 std::ranges::transform(ghost_owners, std::back_inserter(ghost_owners_span),
1063 [](auto& c) { return std::span(c); });
1064 Topology topology
1065 = create_topology(comm, celltypes, cells1_v_span, original_idx1_span,
1066 ghost_owners_span, boundary_v);
1067
1068 // Create connectivities required higher-order geometries for creating
1069 // a Geometry object
1070 for (int i = 0; i < num_cell_types; ++i)
1071 {
1072 for (int e = 1; e < topology.dim(); ++e)
1073 {
1074 if (doflayouts[i].num_entity_dofs(e) > 0)
1075 topology.create_entities(e);
1076 }
1077
1078 if (elements[i].needs_dof_permutations())
1079 topology.create_entity_permutations();
1080 }
1081
1082 // Build list of unique (global) node indices from cells1 and
1083 // distribute coordinate data
1084 std::vector<std::int64_t> nodes1, nodes2;
1085 for (std::vector<std::int64_t>& c : cells1)
1086 nodes1.insert(nodes1.end(), c.begin(), c.end());
1087 for (std::vector<std::int64_t>& c : cells1)
1088 nodes2.insert(nodes2.end(), c.begin(), c.end());
1089
1090 dolfinx::radix_sort(nodes1);
1091 auto [unique_end, range_end] = std::ranges::unique(nodes1);
1092 nodes1.erase(unique_end, range_end);
1093
1094 std::vector coords
1095 = dolfinx::MPI::distribute_data(comm, nodes1, commg, x, xshape[1]);
1096
1097 // Create geometry object
1098 Geometry geometry
1099 = create_geometry(topology, elements, nodes1, nodes2, coords, xshape[1]);
1100
1101 return Mesh(comm, std::make_shared<Topology>(std::move(topology)),
1102 std::move(geometry));
1103}
1104
1138template <typename U>
1140 MPI_Comm comm, MPI_Comm commt, std::span<const std::int64_t> cells,
1142 typename std::remove_reference_t<typename U::value_type>>& element,
1143 MPI_Comm commg, const U& x, std::array<std::size_t, 2> xshape,
1144 const CellPartitionFunction& partitioner)
1145{
1146 return create_mesh(comm, commt, std::vector{cells}, std::vector{element},
1147 commg, x, xshape, partitioner);
1148}
1149
1168template <typename U>
1169Mesh<typename std::remove_reference_t<typename U::value_type>>
1170create_mesh(MPI_Comm comm, std::span<const std::int64_t> cells,
1172 std::remove_reference_t<typename U::value_type>>& elements,
1173 const U& x, std::array<std::size_t, 2> xshape, GhostMode ghost_mode)
1174{
1175 if (dolfinx::MPI::size(comm) == 1)
1176 return create_mesh(comm, comm, std::vector{cells}, std::vector{elements},
1177 comm, x, xshape, nullptr);
1178 else
1179 {
1180 return create_mesh(comm, comm, std::vector{cells}, std::vector{elements},
1181 comm, x, xshape, create_cell_partitioner(ghost_mode));
1182 }
1183}
1184
1198template <std::floating_point T>
1199std::pair<Geometry<T>, std::vector<int32_t>>
1200create_subgeometry(const Mesh<T>& mesh, int dim,
1201 std::span<const std::int32_t> subentity_to_entity)
1202{
1203 const Geometry<T>& geometry = mesh.geometry();
1204
1205 // Get the geometry dofs in the sub-geometry based on the entities in
1206 // sub-geometry
1207 const fem::ElementDofLayout layout = geometry.cmap().create_dof_layout();
1208
1209 std::vector<std::int32_t> x_indices
1210 = entities_to_geometry(mesh, dim, subentity_to_entity, true);
1211
1212 std::vector<std::int32_t> sub_x_dofs = x_indices;
1213 std::ranges::sort(sub_x_dofs);
1214 auto [unique_end, range_end] = std::ranges::unique(sub_x_dofs);
1215 sub_x_dofs.erase(unique_end, range_end);
1216
1217 // Get the sub-geometry dofs owned by this process
1218 auto x_index_map = geometry.index_map();
1219 assert(x_index_map);
1220
1221 std::shared_ptr<common::IndexMap> sub_x_dof_index_map;
1222 std::vector<std::int32_t> subx_to_x_dofmap;
1223 {
1224 auto [map, new_to_old] = common::create_sub_index_map(
1225 *x_index_map, sub_x_dofs, common::IndexMapOrder::any, true);
1226 sub_x_dof_index_map = std::make_shared<common::IndexMap>(std::move(map));
1227 subx_to_x_dofmap = std::move(new_to_old);
1228 }
1229
1230 // Create sub-geometry coordinates
1231 std::span<const T> x = geometry.x();
1232 std::int32_t sub_num_x_dofs = subx_to_x_dofmap.size();
1233 std::vector<T> sub_x(3 * sub_num_x_dofs);
1234 for (std::int32_t i = 0; i < sub_num_x_dofs; ++i)
1235 {
1236 std::copy_n(std::next(x.begin(), 3 * subx_to_x_dofmap[i]), 3,
1237 std::next(sub_x.begin(), 3 * i));
1238 }
1239
1240 // Create geometry to sub-geometry map
1241 std::vector<std::int32_t> x_to_subx_dof_map(
1242 x_index_map->size_local() + x_index_map->num_ghosts(), -1);
1243 for (std::size_t i = 0; i < subx_to_x_dofmap.size(); ++i)
1244 x_to_subx_dof_map[subx_to_x_dofmap[i]] = i;
1245
1246 // Create sub-geometry dofmap
1247 std::vector<std::int32_t> sub_x_dofmap;
1248 sub_x_dofmap.reserve(x_indices.size());
1249 std::ranges::transform(x_indices, std::back_inserter(sub_x_dofmap),
1250 [&x_to_subx_dof_map](auto x_dof)
1251 {
1252 assert(x_to_subx_dof_map[x_dof] != -1);
1253 return x_to_subx_dof_map[x_dof];
1254 });
1255
1256 // Create sub-geometry coordinate element
1257 CellType sub_coord_cell
1258 = cell_entity_type(geometry.cmap().cell_shape(), dim, 0);
1259 // Special handling if point meshes, as they only support constant basis
1260 // functions
1261 int degree = geometry.cmap().degree();
1262 if (sub_coord_cell == CellType::point)
1263 degree = 0;
1264 fem::CoordinateElement<T> sub_cmap(sub_coord_cell, degree,
1265 geometry.cmap().variant());
1266
1267 // Sub-geometry input_global_indices
1268 const std::vector<std::int64_t>& igi = geometry.input_global_indices();
1269 std::vector<std::int64_t> sub_igi;
1270 sub_igi.reserve(subx_to_x_dofmap.size());
1271 std::ranges::transform(subx_to_x_dofmap, std::back_inserter(sub_igi),
1272 [&igi](auto sub_x_dof) { return igi[sub_x_dof]; });
1273
1274 // Create geometry
1275 return {Geometry(
1276 sub_x_dof_index_map,
1277 std::vector<std::vector<std::int32_t>>{std::move(sub_x_dofmap)},
1278 {sub_cmap}, std::move(sub_x), geometry.dim(), std::move(sub_igi)),
1279 std::move(subx_to_x_dofmap)};
1280}
1281
1291template <std::floating_point T>
1292std::tuple<Mesh<T>, std::vector<std::int32_t>, std::vector<std::int32_t>,
1293 std::vector<std::int32_t>>
1294create_submesh(const Mesh<T>& mesh, int dim,
1295 std::span<const std::int32_t> entities)
1296{
1297 // Create sub-topology
1298 mesh.topology_mutable()->create_connectivity(dim, 0);
1299 auto [topology, subentity_to_entity, subvertex_to_vertex]
1300 = mesh::create_subtopology(*mesh.topology(), dim, entities);
1301
1302 // Create sub-geometry
1303 const int tdim = mesh.topology()->dim();
1304 mesh.topology_mutable()->create_entities(dim);
1305 mesh.topology_mutable()->create_connectivity(dim, tdim);
1306 mesh.topology_mutable()->create_connectivity(tdim, dim);
1307 mesh.topology_mutable()->create_entity_permutations();
1308 auto [geometry, subx_to_x_dofmap]
1309 = mesh::create_subgeometry(mesh, dim, subentity_to_entity);
1310
1311 return {Mesh(mesh.comm(), std::make_shared<Topology>(std::move(topology)),
1312 std::move(geometry)),
1313 std::move(subentity_to_entity), std::move(subvertex_to_vertex),
1314 std::move(subx_to_x_dofmap)};
1315}
1316
1317} // namespace dolfinx::mesh
Definition XDMFFile.h:29
ElementDofLayout create_dof_layout() const
Compute and return the dof layout.
Definition CoordinateElement.cpp:75
void permute_subentity_closure(std::span< std::int32_t > d, std::uint32_t cell_info, mesh::CellType entity_type, int entity_index) const
Given the closure DOFs of a cell sub-entity in reference ordering, this function computes the permut...
Definition CoordinateElement.cpp:64
Definition ElementDofLayout.h:30
const std::vector< std::vector< std::vector< int > > > & entity_closure_dofs_all() const
Definition ElementDofLayout.cpp:92
int num_entity_closure_dofs(int dim) const
Definition ElementDofLayout.cpp:68
Definition topologycomputation.h:24
const std::vector< T > & array() const
Return contiguous array of links for all nodes (const version)
Definition AdjacencyList.h:128
const std::vector< std::int32_t > & offsets() const
Offset for each node in array() (const version)
Definition AdjacencyList.h:134
Geometry stores the geometry imposed on a mesh.
Definition Geometry.h:34
std::shared_ptr< const common::IndexMap > index_map() const
Index map for the geometry 'degrees-of-freedom'.
Definition Geometry.h:141
const fem::CoordinateElement< value_type > & cmap() const
The element that describes the geometry map.
Definition Geometry.h:173
int dim() const
Return dimension of the Euclidean coordinate system.
Definition Geometry.h:107
MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan< const std::int32_t, MDSPAN_IMPL_STANDARD_NAMESPACE::dextents< std::size_t, 2 > > dofmap() const
DofMap for the geometry.
Definition Geometry.h:114
const std::vector< std::int64_t > & input_global_indices() const
Global user indices.
Definition Geometry.h:181
std::span< const value_type > x() const
Access geometry degrees-of-freedom data (const version).
Definition Geometry.h:150
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:46
Requirements on function for geometry marking.
Definition utils.h:469
void reorder_list(std::span< T > list, std::span< const std::int32_t > nodemap)
Re-order the nodes of a fixed-degree adjacency list.
Definition utils.h:51
std::tuple< std::vector< std::int32_t >, std::vector< T >, std::vector< std::int32_t > > compute_vertex_coords_boundary(const mesh::Mesh< T > &mesh, int dim, std::span< const std::int32_t > facets)
Compute the coordinates of 'vertices' for entities of a given dimension that are attached to specifie...
Definition utils.h:82
std::pair< std::vector< T >, std::array< std::size_t, 2 > > compute_vertex_coords(const mesh::Mesh< T > &mesh)
The coordinates for all 'vertices' in the mesh.
Definition utils.h:427
std::vector< typename std::remove_reference_t< typename U::value_type > > distribute_data(MPI_Comm comm0, std::span< const std::int64_t > indices, MPI_Comm comm1, const U &x, int shape1)
Distribute rows of a rectangular data array to ranks where they are required (scalable version).
Definition MPI.h:681
int size(MPI_Comm comm)
Definition MPI.cpp:72
std::pair< IndexMap, std::vector< std::int32_t > > create_sub_index_map(const IndexMap &imap, std::span< const std::int32_t > indices, IndexMapOrder order=IndexMapOrder::any, bool allow_owner_change=false)
Create a new index map from a subset of indices in an existing index map.
Definition IndexMap.cpp:815
@ any
Allow arbitrary ordering of ghost indices in sub-maps.
Finite element method functionality.
Definition assemble_matrix_impl.h:26
std::tuple< graph::AdjacencyList< std::int64_t >, std::vector< int >, std::vector< std::int64_t >, std::vector< int > > distribute(MPI_Comm comm, const graph::AdjacencyList< std::int64_t > &list, const graph::AdjacencyList< std::int32_t > &destinations)
Distribute adjacency list nodes to destination ranks.
Definition partition.cpp:38
std::vector< std::int32_t > reorder_gps(const graph::AdjacencyList< std::int32_t > &graph)
Re-order a graph using the Gibbs-Poole-Stockmeyer algorithm.
Definition ordering.cpp:360
std::function< graph::AdjacencyList< std::int32_t >( MPI_Comm, int, const AdjacencyList< std::int64_t > &, bool)> partition_fn
Signature of functions for computing the parallel partitioning of a distributed graph.
Definition partition.h:31
AdjacencyList< std::int32_t > partition_graph(MPI_Comm comm, int nparts, const AdjacencyList< std::int64_t > &local_graph, bool ghosting)
Partition graph across processes using the default graph partitioner.
Definition partition.cpp:21
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:37
Topology create_topology(MPI_Comm comm, const std::vector< CellType > &cell_types, std::vector< std::span< const std::int64_t > > cells, std::vector< std::span< const std::int64_t > > original_cell_index, std::vector< std::span< const int > > ghost_owners, std::span< const std::int64_t > boundary_vertices)
Create a mesh topology.
Definition Topology.cpp:975
Geometry< typename std::remove_reference_t< typename U::value_type > > create_geometry(const Topology &topology, const std::vector< fem::CoordinateElement< std::remove_reference_t< typename U::value_type > > > &elements, std::span< const std::int64_t > nodes, std::span< const std::int64_t > xdofs, const U &x, int dim, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn=nullptr)
Build Geometry from input data.
Definition Geometry.h:243
std::vector< T > cell_normals(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Compute normal to given cell (viewed as embedded in 3D).
Definition utils.h:271
CellType cell_entity_type(CellType type, int d, int index)
Return type of cell for entity of dimension d at given entity index.
Definition cell_types.cpp:64
std::tuple< Topology, std::vector< int32_t >, std::vector< int32_t > > create_subtopology(const Topology &topology, int dim, std::span< const std::int32_t > entities)
Create a topology for a subset of entities of a given topological dimension.
Definition Topology.cpp:1261
std::vector< std::int32_t > locate_entities_boundary(const Mesh< T > &mesh, int dim, U marker)
Compute indices of all mesh entities that are attached to an owned boundary facet and evaluate to tru...
Definition utils.h:563
int num_cell_vertices(CellType type)
Definition cell_types.cpp:147
std::vector< T > h(const Mesh< T > &mesh, std::span< const std::int32_t > entities, int dim)
Compute greatest distance between any two vertices of the mesh entities (h).
Definition utils.h:217
std::pair< Geometry< T >, std::vector< int32_t > > create_subgeometry(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > subentity_to_entity)
Create a sub-geometry from a mesh and a subset of mesh entities to be included.
Definition utils.h:1200
std::vector< std::int32_t > entities_to_geometry(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities, bool permute=false)
Compute the geometry degrees of freedom associated with the closure of a given set of cell entities.
Definition utils.h:640
Mesh< typename std::remove_reference_t< typename U::value_type > > create_mesh(MPI_Comm comm, MPI_Comm commt, std::vector< std::span< const std::int64_t > > cells, const std::vector< fem::CoordinateElement< typename std::remove_reference_t< typename U::value_type > > > &elements, MPI_Comm commg, const U &x, std::array< std::size_t, 2 > xshape, const CellPartitionFunction &partitioner)
Create a distributed mesh::Mesh from mesh data and using the provided graph partitioning function for...
Definition utils.h:803
std::tuple< graph::AdjacencyList< std::int32_t >, std::vector< std::int64_t >, std::size_t, std::vector< std::int32_t > > build_local_dual_graph(std::span< const CellType > celltypes, const std::vector< std::span< const std::int64_t > > &cells)
Compute the local part of the dual graph (cell-cell connections via facets) and facets with only one ...
Definition graphbuild.cpp:354
std::vector< std::int32_t > locate_entities(const Mesh< T > &mesh, int dim, U marker)
Compute indices of all mesh entities that evaluate to true for the provided geometric marking functio...
Definition utils.h:490
std::vector< std::int32_t > exterior_facet_indices(const Topology &topology)
Compute the indices of all exterior facets that are owned by the caller.
Definition utils.cpp:58
std::vector< std::int32_t > compute_incident_entities(const Topology &topology, std::span< const std::int32_t > entities, int d0, int d1)
Compute incident entities.
Definition utils.cpp:108
std::vector< std::int64_t > extract_topology(CellType cell_type, const fem::ElementDofLayout &layout, std::span< const std::int64_t > cells)
Extract topology from cell data, i.e. extract cell vertices.
Definition utils.cpp:29
CellType
Cell type identifier.
Definition cell_types.h:22
std::function< graph::AdjacencyList< std::int32_t >( MPI_Comm comm, int nparts, const std::vector< CellType > &cell_types, const std::vector< std::span< const std::int64_t > > &cells)> CellPartitionFunction
Signature for the cell partitioning function. Function that implement this interface compute the dest...
Definition utils.h:191
std::vector< T > compute_midpoints(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Compute the midpoints for mesh entities of a given dimension.
Definition utils.h:389
std::tuple< Mesh< T >, std::vector< std::int32_t >, std::vector< std::int32_t >, std::vector< std::int32_t > > create_submesh(const Mesh< T > &mesh, int dim, std::span< const std::int32_t > entities)
Create a new mesh consisting of a subset of entities in a mesh.
Definition utils.h:1294
CellPartitionFunction create_cell_partitioner(mesh::GhostMode ghost_mode=mesh::GhostMode::none, const graph::partition_fn &partfn=&graph::partition_graph)
Create a function that computes destination rank for mesh cells on this rank by applying the default ...
Definition utils.cpp:85
std::vector< std::int32_t > sort_by_perm(std::span< const T > x, std::size_t shape1)
Compute the permutation array that sorts a 2D array by row.
Definition sort.h:135
constexpr __radix_sort radix_sort
Radix sort.
Definition sort.h:122