Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/d6/db4/plaza_8h_source.html
DOLFINx 0.7.3
DOLFINx C++ interface
Loading...
Searching...
No Matches
plaza.h
1// Copyright (C) 2014-2018 Chris Richardson
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#include "utils.h"
8#include <cstdint>
9#include <dolfinx/common/MPI.h>
10#include <dolfinx/graph/AdjacencyList.h>
11#include <dolfinx/mesh/Geometry.h>
12#include <dolfinx/mesh/Mesh.h>
13#include <dolfinx/mesh/Topology.h>
14#include <dolfinx/mesh/utils.h>
15#include <span>
16#include <tuple>
17#include <utility>
18#include <vector>
19
20#pragma once
21
28{
29
31enum class Option : int
32{
33 none = 0,
35 = 1,
37 = 2,
40};
41
42namespace impl
43{
47template <int tdim>
48std::vector<std::int8_t>
49compute_parent_facets(std::span<const std::int32_t> simplex_set)
50{
51 {
52 assert(simplex_set.size() % (tdim + 1) == 0);
53 std::vector<std::int8_t> parent_facet(simplex_set.size(), -1);
54
55 // Index lookups in 'indices' for the child vertices that occur on
56 // each parent facet in 2D and 3D. In 2D each edge has 3 child
57 // vertices, and in 3D each triangular facet has six child vertices.
58 constexpr std::array<std::array<int, 3>, 3> facet_table_2d{
59 {{1, 2, 3}, {0, 2, 4}, {0, 1, 5}}};
60
61 constexpr std::array<std::array<int, 6>, 4> facet_table_3d{
62 {{1, 2, 3, 4, 5, 6},
63 {0, 2, 3, 4, 7, 8},
64 {0, 1, 3, 5, 7, 9},
65 {0, 1, 2, 6, 8, 9}}};
66
67 const int ncells = simplex_set.size() / (tdim + 1);
68 for (int fpi = 0; fpi < (tdim + 1); ++fpi)
69 {
70 // For each child cell, consider all facets
71 for (int cc = 0; cc < ncells; ++cc)
72 {
73 for (int fci = 0; fci < (tdim + 1); ++fci)
74 {
75 // Indices of all vertices on child facet, sorted
76 std::array<int, tdim> cf, set_output;
77
78 int num_common_vertices;
79 if constexpr (tdim == 2)
80 {
81 for (int j = 0; j < tdim; ++j)
82 cf[j] = simplex_set[cc * 3 + facet_table_2d[fci][j]];
83 std::sort(cf.begin(), cf.end());
84 auto it = std::set_intersection(
85 facet_table_2d[fpi].begin(), facet_table_2d[fpi].end(),
86 cf.begin(), cf.end(), set_output.begin());
87 num_common_vertices = std::distance(set_output.begin(), it);
88 }
89 else
90 {
91 for (int j = 0; j < tdim; ++j)
92 cf[j] = simplex_set[cc * 4 + facet_table_3d[fci][j]];
93 std::sort(cf.begin(), cf.end());
94 auto it = std::set_intersection(
95 facet_table_3d[fpi].begin(), facet_table_3d[fpi].end(),
96 cf.begin(), cf.end(), set_output.begin());
97 num_common_vertices = std::distance(set_output.begin(), it);
98 }
99
100 if (num_common_vertices == tdim)
101 {
102 assert(parent_facet[cc * (tdim + 1) + fci] == -1);
103 // Child facet "fci" of cell cc, lies on parent facet "fpi"
104 parent_facet[cc * (tdim + 1) + fci] = fpi;
105 }
106 }
107 }
108 }
109
110 return parent_facet;
111 }
112}
113
127std::vector<std::int32_t>
128get_simplices(std::span<const std::int64_t> indices,
129 std::span<const std::int32_t> longest_edge, int tdim,
130 bool uniform);
131
134void enforce_rules(MPI_Comm comm, const graph::AdjacencyList<int>& shared_edges,
135 std::vector<std::int8_t>& marked_edges,
136 const mesh::Topology& topology,
137 std::span<const std::int32_t> long_edge);
138
140template <std::floating_point T>
141std::pair<std::vector<std::int32_t>, std::vector<std::int8_t>>
142face_long_edge(const mesh::Mesh<T>& mesh)
143{
144 const int tdim = mesh.topology()->dim();
145 // FIXME: cleanup these calls? Some of the happen internally again.
146 mesh.topology_mutable()->create_entities(1);
147 mesh.topology_mutable()->create_entities(2);
148 mesh.topology_mutable()->create_connectivity(2, 1);
149 mesh.topology_mutable()->create_connectivity(1, tdim);
150 mesh.topology_mutable()->create_connectivity(tdim, 2);
151
152 std::int64_t num_faces = mesh.topology()->index_map(2)->size_local()
153 + mesh.topology()->index_map(2)->num_ghosts();
154
155 // Storage for face-local index of longest edge
156 std::vector<std::int32_t> long_edge(num_faces);
157 std::vector<std::int8_t> edge_ratio_ok;
158
159 // Check mesh face quality (may be used in 2D to switch to "uniform"
160 // refinement)
161 const T min_ratio = sqrt(2.0) / 2.0;
162 if (tdim == 2)
163 edge_ratio_ok.resize(num_faces);
164
165 auto x_dofmap = mesh.geometry().dofmap();
166
167 auto c_to_v = mesh.topology()->connectivity(tdim, 0);
168 assert(c_to_v);
169 auto e_to_c = mesh.topology()->connectivity(1, tdim);
170 assert(e_to_c);
171 auto e_to_v = mesh.topology()->connectivity(1, 0);
172 assert(e_to_v);
173
174 // Store all edge lengths in Mesh to save recalculating for each Face
175 auto map_e = mesh.topology()->index_map(1);
176 assert(map_e);
177 std::vector<T> edge_length(map_e->size_local() + map_e->num_ghosts());
178 for (std::size_t e = 0; e < edge_length.size(); ++e)
179 {
180 // Get first attached cell
181 auto cells = e_to_c->links(e);
182 assert(!cells.empty());
183 auto cell_vertices = c_to_v->links(cells.front());
184 auto edge_vertices = e_to_v->links(e);
185
186 // Find local index of edge vertices in the cell geometry map
187 auto it0 = std::find(cell_vertices.begin(), cell_vertices.end(),
188 edge_vertices[0]);
189 assert(it0 != cell_vertices.end());
190 const std::size_t local0 = std::distance(cell_vertices.begin(), it0);
191 auto it1 = std::find(cell_vertices.begin(), cell_vertices.end(),
192 edge_vertices[1]);
193 assert(it1 != cell_vertices.end());
194 const std::size_t local1 = std::distance(cell_vertices.begin(), it1);
195
196 auto x_dofs
197 = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
198 submdspan(x_dofmap, cells.front(),
199 MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
200 std::span<const T, 3> x0(mesh.geometry().x().data() + 3 * x_dofs[local0],
201 3);
202 std::span<const T, 3> x1(mesh.geometry().x().data() + 3 * x_dofs[local1],
203 3);
204
205 // Compute length of edge between vertex x0 and x1
206 edge_length[e] = std::sqrt(std::transform_reduce(
207 x0.begin(), x0.end(), x1.begin(), 0.0, std::plus<>(),
208 [](auto x0, auto x1) { return (x0 - x1) * (x0 - x1); }));
209 }
210
211 // Get longest edge of each face
212 auto f_to_v = mesh.topology()->connectivity(2, 0);
213 assert(f_to_v);
214 auto f_to_e = mesh.topology()->connectivity(2, 1);
215 assert(f_to_e);
216 const std::vector global_indices
217 = mesh.topology()->index_map(0)->global_indices();
218 for (int f = 0; f < f_to_v->num_nodes(); ++f)
219 {
220 auto face_edges = f_to_e->links(f);
221
222 std::int32_t imax = 0;
223 T max_len = 0.0;
224 T min_len = std::numeric_limits<T>::max();
225
226 for (int i = 0; i < 3; ++i)
227 {
228 const T e_len = edge_length[face_edges[i]];
229 min_len = std::min(e_len, min_len);
230 if (e_len > max_len)
231 {
232 max_len = e_len;
233 imax = i;
234 }
235 else if (tdim == 3 and e_len == max_len)
236 {
237 // If edges are the same length, compare global index of
238 // opposite vertex. Only important so that tetrahedral faces
239 // have a matching refinement pattern across processes.
240 auto vertices = f_to_v->links(f);
241 const int vmax = vertices[imax];
242 const int vi = vertices[i];
243 if (global_indices[vi] > global_indices[vmax])
244 imax = i;
245 }
246 }
247
248 // Only save edge ratio in 2D
249 if (tdim == 2)
250 edge_ratio_ok[f] = (min_len / max_len >= min_ratio);
251
252 long_edge[f] = face_edges[imax];
253 }
254
255 return std::pair(std::move(long_edge), std::move(edge_ratio_ok));
256}
257
259template <std::floating_point T>
260std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
261 std::array<std::size_t, 2>, std::vector<std::int32_t>,
262 std::vector<std::int8_t>>
263compute_refinement(MPI_Comm neighbor_comm,
264 const std::vector<std::int8_t>& marked_edges,
265 const graph::AdjacencyList<int>& shared_edges,
266 const mesh::Mesh<T>& mesh,
267 const std::vector<std::int32_t>& long_edge,
268 const std::vector<std::int8_t>& edge_ratio_ok,
269 plaza::Option option)
270{
271 int tdim = mesh.topology()->dim();
272 int num_cell_edges = tdim * 3 - 3;
273 int num_cell_vertices = tdim + 1;
274 bool compute_facets = (option == plaza::Option::parent_facet
276 bool compute_parent_cell
277 = (option == plaza::Option::parent_cell
279
280 // Make new vertices in parallel
281 const auto [new_vertex_map, new_vertex_coords, xshape]
282 = create_new_vertices(neighbor_comm, shared_edges, mesh, marked_edges);
283
284 std::vector<std::int32_t> parent_cell;
285 std::vector<std::int8_t> parent_facet;
286 std::vector<std::int64_t> indices(num_cell_vertices + num_cell_edges);
287 std::vector<std::int32_t> simplex_set;
288
289 auto map_c = mesh.topology()->index_map(tdim);
290 assert(map_c);
291 auto c_to_v = mesh.topology()->connectivity(tdim, 0);
292 assert(c_to_v);
293 auto c_to_e = mesh.topology()->connectivity(tdim, 1);
294 assert(c_to_e);
295 auto c_to_f = mesh.topology()->connectivity(tdim, 2);
296 assert(c_to_f);
297
298 std::int32_t num_new_vertices_local = std::count(
299 marked_edges.begin(),
300 marked_edges.begin() + mesh.topology()->index_map(1)->size_local(), true);
301
302 std::vector<std::int64_t> global_indices
303 = adjust_indices(*mesh.topology()->index_map(0), num_new_vertices_local);
304
305 const int num_cells = map_c->size_local();
306
307 // Iterate over all cells, and refine if cell has a marked edge
308 std::vector<std::int64_t> cell_topology;
309 for (int c = 0; c < num_cells; ++c)
310 {
311 // Create vector of indices in the order [vertices][edges], 3+3 in
312 // 2D, 4+6 in 3D
313
314 // Copy vertices
315 auto vertices = c_to_v->links(c);
316 for (std::size_t v = 0; v < vertices.size(); ++v)
317 indices[v] = global_indices[vertices[v]];
318
319 // Get cell-local indices of marked edges
320 auto edges = c_to_e->links(c);
321 bool no_edge_marked = true;
322 for (std::size_t ei = 0; ei < edges.size(); ++ei)
323 {
324 if (marked_edges[edges[ei]])
325 {
326 no_edge_marked = false;
327 auto it = new_vertex_map.find(edges[ei]);
328 assert(it != new_vertex_map.end());
329 indices[num_cell_vertices + ei] = it->second;
330 }
331 else
332 indices[num_cell_vertices + ei] = -1;
333 }
334
335 if (no_edge_marked)
336 {
337 // Copy over existing cell to new topology
338 for (auto v : vertices)
339 cell_topology.push_back(global_indices[v]);
340
341 if (compute_parent_cell)
342 parent_cell.push_back(c);
343
344 if (compute_facets)
345 {
346 if (tdim == 3)
347 parent_facet.insert(parent_facet.end(), {0, 1, 2, 3});
348 else
349 parent_facet.insert(parent_facet.end(), {0, 1, 2});
350 }
351 }
352 else
353 {
354 // Need longest edges of each face in cell local indexing. NB in
355 // 2D the face is the cell itself, and there is just one entry.
356 std::vector<std::int32_t> longest_edge;
357 for (auto f : c_to_f->links(c))
358 longest_edge.push_back(long_edge[f]);
359
360 // Convert to cell local index
361 for (std::int32_t& p : longest_edge)
362 {
363 for (std::size_t ej = 0; ej < edges.size(); ++ej)
364 {
365 if (p == edges[ej])
366 {
367 p = ej;
368 break;
369 }
370 }
371 }
372
373 const bool uniform = (tdim == 2) ? edge_ratio_ok[c] : false;
374
375 // FIXME: this has an expensive dynamic memory allocation
376 simplex_set = get_simplices(indices, longest_edge, tdim, uniform);
377
378 // Save parent index
379 const std::int32_t ncells = simplex_set.size() / num_cell_vertices;
380
381 if (compute_parent_cell)
382 {
383 for (std::int32_t i = 0; i < ncells; ++i)
384 parent_cell.push_back(c);
385 }
386
387 if (compute_facets)
388 {
389 std::vector<std::int8_t> npf;
390 if (tdim == 3)
391 npf = compute_parent_facets<3>(simplex_set);
392 else
393 npf = compute_parent_facets<2>(simplex_set);
394 parent_facet.insert(parent_facet.end(), npf.begin(), npf.end());
395 }
396
397 // Convert from cell local index to mesh index and add to cells
398 for (std::int32_t v : simplex_set)
399 cell_topology.push_back(indices[v]);
400 }
401 }
402
403 assert(cell_topology.size() % num_cell_vertices == 0);
404 std::vector<std::int32_t> offsets(
405 cell_topology.size() / num_cell_vertices + 1, 0);
406 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
407 offsets[i + 1] = offsets[i] + num_cell_vertices;
408 graph::AdjacencyList cell_adj(std::move(cell_topology), std::move(offsets));
409
410 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
411 std::move(parent_cell), std::move(parent_facet)};
412}
413} // namespace impl
414
425template <std::floating_point T>
426std::tuple<mesh::Mesh<T>, std::vector<std::int32_t>, std::vector<std::int8_t>>
427refine(const mesh::Mesh<T>& mesh, bool redistribute, Option option)
428{
429 if (mesh.geometry().cmaps().size() > 1)
430 {
431 throw std::runtime_error("Mixed topology not supported");
432 }
433
434 auto [cell_adj, new_coords, xshape, parent_cell, parent_facet]
435 = compute_refinement_data(mesh, option);
436
437 if (dolfinx::MPI::size(mesh.comm()) == 1)
438 {
439 return {mesh::create_mesh(mesh.comm(), cell_adj, mesh.geometry().cmaps(),
440 new_coords, xshape, mesh::GhostMode::none),
441 std::move(parent_cell), std::move(parent_facet)};
442 }
443 else
444 {
445 std::shared_ptr<const common::IndexMap> map_c
446 = mesh.topology()->index_map(mesh.topology()->dim());
447 const int num_ghost_cells = map_c->num_ghosts();
448 // Check if mesh has ghost cells on any rank
449 // FIXME: this is not a robust test. Should be user option.
450 int max_ghost_cells = 0;
451 MPI_Allreduce(&num_ghost_cells, &max_ghost_cells, 1, MPI_INT, MPI_MAX,
452 mesh.comm());
453
454 // Build mesh
455 const mesh::GhostMode ghost_mode = max_ghost_cells == 0
456 ? mesh::GhostMode::none
457 : mesh::GhostMode::shared_facet;
458 return {partition<T>(mesh, cell_adj, std::span(new_coords), xshape,
459 redistribute, ghost_mode),
460 std::move(parent_cell), std::move(parent_facet)};
461 }
462}
463
475template <std::floating_point T>
476std::tuple<mesh::Mesh<T>, std::vector<std::int32_t>, std::vector<std::int8_t>>
477refine(const mesh::Mesh<T>& mesh, std::span<const std::int32_t> edges,
478 bool redistribute, Option option)
479{
480 if (mesh.geometry().cmaps().size() > 1)
481 throw std::runtime_error("Mixed topology not supported");
482
483 auto [cell_adj, new_vertex_coords, xshape, parent_cell, parent_facet]
484 = compute_refinement_data(mesh, edges, option);
485
486 if (dolfinx::MPI::size(mesh.comm()) == 1)
487 {
488 return {mesh::create_mesh(mesh.comm(), cell_adj, mesh.geometry().cmaps(),
489 new_vertex_coords, xshape, mesh::GhostMode::none),
490 std::move(parent_cell), std::move(parent_facet)};
491 }
492 else
493 {
494 std::shared_ptr<const common::IndexMap> map_c
495 = mesh.topology()->index_map(mesh.topology()->dim());
496 const int num_ghost_cells = map_c->num_ghosts();
497 // Check if mesh has ghost cells on any rank
498 // FIXME: this is not a robust test. Should be user option.
499 int max_ghost_cells = 0;
500 MPI_Allreduce(&num_ghost_cells, &max_ghost_cells, 1, MPI_INT, MPI_MAX,
501 mesh.comm());
502
503 // Build mesh
504 const mesh::GhostMode ghost_mode = max_ghost_cells == 0
505 ? mesh::GhostMode::none
506 : mesh::GhostMode::shared_facet;
507
508 return {partition<T>(mesh, cell_adj, new_vertex_coords, xshape,
509 redistribute, ghost_mode),
510 std::move(parent_cell), std::move(parent_facet)};
511 }
512}
513
522template <std::floating_point T>
523std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
524 std::array<std::size_t, 2>, std::vector<std::int32_t>,
525 std::vector<std::int8_t>>
527{
528 common::Timer t0("PLAZA: refine");
529 auto topology = mesh.topology();
530 assert(topology);
531
532 if (topology->cell_types().size() > 1)
533 throw std::runtime_error("Mixed topology not supported");
534
535 if (topology->cell_types()[0] != mesh::CellType::triangle
536 and topology->cell_types()[0] != mesh::CellType::tetrahedron)
537 {
538 throw std::runtime_error("Cell type not supported");
539 }
540
541 auto map_e = topology->index_map(1);
542 if (!map_e)
543 throw std::runtime_error("Edges must be initialised");
544
545 // Get sharing ranks for each edge
546 graph::AdjacencyList<int> edge_ranks = map_e->index_to_dest_ranks();
547
548 // Create unique list of ranks that share edges (owners of ghosts
549 // plus ranks that ghost owned indices)
550 std::vector<int> ranks(edge_ranks.array().begin(), edge_ranks.array().end());
551 std::sort(ranks.begin(), ranks.end());
552 ranks.erase(std::unique(ranks.begin(), ranks.end()), ranks.end());
553
554 // Convert edge_ranks from global rank to to neighbourhood ranks
555 std::transform(edge_ranks.array().begin(), edge_ranks.array().end(),
556 edge_ranks.array().begin(),
557 [&ranks](auto r)
558 {
559 auto it = std::lower_bound(ranks.begin(), ranks.end(), r);
560 assert(it != ranks.end() and *it == r);
561 return std::distance(ranks.begin(), it);
562 });
563
564 MPI_Comm comm;
565 MPI_Dist_graph_create_adjacent(mesh.comm(), ranks.size(), ranks.data(),
566 MPI_UNWEIGHTED, ranks.size(), ranks.data(),
567 MPI_UNWEIGHTED, MPI_INFO_NULL, false, &comm);
568
569 const auto [long_edge, edge_ratio_ok] = impl::face_long_edge(mesh);
570 auto [cell_adj, new_vertex_coords, xshape, parent_cell, parent_facet]
571 = impl::compute_refinement(
572 comm,
573 std::vector<std::int8_t>(map_e->size_local() + map_e->num_ghosts(),
574 true),
575 edge_ranks, mesh, long_edge, edge_ratio_ok, option);
576 MPI_Comm_free(&comm);
577
578 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
579 std::move(parent_cell), std::move(parent_facet)};
580}
581
591template <std::floating_point T>
592std::tuple<graph::AdjacencyList<std::int64_t>, std::vector<T>,
593 std::array<std::size_t, 2>, std::vector<std::int32_t>,
594 std::vector<std::int8_t>>
596 std::span<const std::int32_t> edges, Option option)
597{
598 common::Timer t0("PLAZA: refine");
599 auto topology = mesh.topology();
600 assert(topology);
601
602 if (topology->cell_types().size() > 1)
603 throw std::runtime_error("Mixed topology not supported");
604
605 if (topology->cell_types()[0] != mesh::CellType::triangle
606 and topology->cell_types()[0] != mesh::CellType::tetrahedron)
607 {
608 throw std::runtime_error("Cell type not supported");
609 }
610
611 auto map_e = topology->index_map(1);
612 if (!map_e)
613 throw std::runtime_error("Edges must be initialised");
614
615 // Get sharing ranks for each edge
616 graph::AdjacencyList<int> edge_ranks = map_e->index_to_dest_ranks();
617
618 // Create unique list of ranks that share edges (owners of ghosts plus
619 // ranks that ghost owned indices)
620 std::vector<int> ranks(edge_ranks.array().begin(), edge_ranks.array().end());
621 std::sort(ranks.begin(), ranks.end());
622 ranks.erase(std::unique(ranks.begin(), ranks.end()), ranks.end());
623
624 // Convert edge_ranks from global rank to to neighbourhood ranks
625 std::transform(edge_ranks.array().begin(), edge_ranks.array().end(),
626 edge_ranks.array().begin(),
627 [&ranks](auto r)
628 {
629 auto it = std::lower_bound(ranks.begin(), ranks.end(), r);
630 assert(it != ranks.end() and *it == r);
631 return std::distance(ranks.begin(), it);
632 });
633
634 // Get number of neighbors
635 std::vector<std::int8_t> marked_edges(
636 map_e->size_local() + map_e->num_ghosts(), false);
637 std::vector<std::vector<std::int32_t>> marked_for_update(ranks.size());
638 for (auto edge : edges)
639 {
640 if (!marked_edges[edge])
641 {
642 marked_edges[edge] = true;
643
644 // If it is a shared edge, add all sharing neighbors to update set
645 for (int rank : edge_ranks.links(edge))
646 marked_for_update[rank].push_back(edge);
647 }
648 }
649
650 MPI_Comm comm;
651 MPI_Dist_graph_create_adjacent(mesh.comm(), ranks.size(), ranks.data(),
652 MPI_UNWEIGHTED, ranks.size(), ranks.data(),
653 MPI_UNWEIGHTED, MPI_INFO_NULL, false, &comm);
654
655 // Communicate any shared edges
656 update_logical_edgefunction(comm, marked_for_update, marked_edges, *map_e);
657
658 // Enforce rules about refinement (i.e. if any edge is marked in a
659 // triangle, then the longest edge must also be marked).
660 const auto [long_edge, edge_ratio_ok] = impl::face_long_edge(mesh);
661 impl::enforce_rules(comm, edge_ranks, marked_edges, *topology, long_edge);
662
663 auto [cell_adj, new_vertex_coords, xshape, parent_cell, parent_facet]
664 = impl::compute_refinement(comm, marked_edges, edge_ranks, mesh,
665 long_edge, edge_ratio_ok, option);
666 MPI_Comm_free(&comm);
667
668 return {std::move(cell_adj), std::move(new_vertex_coords), xshape,
669 std::move(parent_cell), std::move(parent_facet)};
670}
671
672} // namespace dolfinx::refinement::plaza
A timer can be used for timing tasks. The basic usage is.
Definition Timer.h:31
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition AdjacencyList.h:28
std::span< T > links(std::size_t node)
Get the links (edges) for given node.
Definition AdjacencyList.h:112
const std::vector< T > & array() const
Return contiguous array of links for all nodes (const version)
Definition AdjacencyList.h:129
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
std::shared_ptr< Topology > topology()
Get mesh topology.
Definition Mesh.h:64
Geometry< T > & geometry()
Get mesh geometry.
Definition Mesh.h:76
MPI_Comm comm() const
Mesh MPI communicator.
Definition Mesh.h:84
Functions supporting mesh operations.
int size(MPI_Comm comm)
Return size of the group (number of processes) associated with the communicator.
Definition MPI.cpp:72
void cells(la::SparsityPattern &pattern, std::span< const std::int32_t > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:18
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:35
int num_cell_vertices(CellType type)
Number vertices for a cell type.
Definition cell_types.cpp:147
Mesh< typename std::remove_reference_t< typename U::value_type > > create_mesh(MPI_Comm comm, const graph::AdjacencyList< std::int64_t > &cells, const std::vector< fem::CoordinateElement< typename std::remove_reference_t< typename U::value_type > > > &elements, const U &x, std::array< std::size_t, 2 > xshape, CellPartitionFunction partitioner)
Create a mesh using a provided mesh partitioning function.
Definition utils.h:780
Plaza mesh refinement.
Definition plaza.h:28
std::tuple< graph::AdjacencyList< std::int64_t >, std::vector< T >, std::array< std::size_t, 2 >, std::vector< std::int32_t >, std::vector< std::int8_t > > compute_refinement_data(const mesh::Mesh< T > &mesh, Option option)
Refine mesh returning new mesh data.
Definition plaza.h:526
Option
Options for data to compute during mesh refinement.
Definition plaza.h:32
std::tuple< mesh::Mesh< T >, std::vector< std::int32_t >, std::vector< std::int8_t > > refine(const mesh::Mesh< T > &mesh, bool redistribute, Option option)
Uniform refine, optionally redistributing and optionally calculating the parent-child relationships`.
Definition plaza.h:427
void update_logical_edgefunction(MPI_Comm comm, const std::vector< std::vector< std::int32_t > > &marked_for_update, std::vector< std::int8_t > &marked_edges, const common::IndexMap &map)
Communicate edge markers between processes that share edges.
Definition utils.cpp:46
std::tuple< std::map< std::int32_t, std::int64_t >, std::vector< T >, std::array< std::size_t, 2 > > create_new_vertices(MPI_Comm comm, const graph::AdjacencyList< int > &shared_edges, const mesh::Mesh< T > &mesh, std::span< const std::int8_t > marked_edges)
Add new vertex for each marked edge, and create new_vertex_coordinates and global_edge->new_vertex ma...
Definition utils.h:147
std::vector< std::int64_t > adjust_indices(const common::IndexMap &map, std::int32_t n)
Add indices to account for extra n values on this process.
Definition utils.cpp:102