Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/de/d78/refinement_2utils_8h_source.html
DOLFINx 0.7.3
DOLFINx C++ interface
Loading...
Searching...
No Matches
utils.h
1// Copyright (C) 2012-2020 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#pragma once
8
9#include <array>
10#include <concepts>
11#include <cstdint>
12#include <dolfinx/common/MPI.h>
13#include <dolfinx/graph/AdjacencyList.h>
14#include <dolfinx/mesh/Mesh.h>
15#include <dolfinx/mesh/utils.h>
16#include <map>
17#include <memory>
18#include <set>
19#include <span>
20#include <tuple>
21#include <vector>
22
23namespace dolfinx::mesh
24{
25template <typename T>
26class MeshTags;
27class Topology;
28enum class GhostMode;
29} // namespace dolfinx::mesh
30
31namespace dolfinx::common
32{
33class IndexMap;
34} // namespace dolfinx::common
35
36namespace dolfinx::refinement
37{
38
39namespace impl
40{
41
43std::int64_t local_to_global(std::int32_t local_index,
44 const common::IndexMap& map);
45
52template <std::floating_point T>
53std::pair<std::vector<T>, std::array<std::size_t, 2>> create_new_geometry(
54 const mesh::Mesh<T>& mesh,
55 const std::map<std::int32_t, std::int64_t>& local_edge_to_new_vertex)
56{
57 // Build map from vertex -> geometry dof
58 auto x_dofmap = mesh.geometry().dofmap();
59 const int tdim = mesh.topology()->dim();
60 auto c_to_v = mesh.topology()->connectivity(tdim, 0);
61 assert(c_to_v);
62 auto map_v = mesh.topology()->index_map(0);
63 assert(map_v);
64 std::vector<std::int32_t> vertex_to_x(map_v->size_local()
65 + map_v->num_ghosts());
66 auto map_c = mesh.topology()->index_map(tdim);
67
68 assert(map_c);
69 auto dof_layout = mesh.geometry().cmaps()[0].create_dof_layout();
70 auto entity_dofs_all = dof_layout.entity_dofs_all();
71 for (int c = 0; c < map_c->size_local() + map_c->num_ghosts(); ++c)
72 {
73 auto vertices = c_to_v->links(c);
74 auto dofs = MDSPAN_IMPL_STANDARD_NAMESPACE::MDSPAN_IMPL_PROPOSED_NAMESPACE::
75 submdspan(x_dofmap, c, MDSPAN_IMPL_STANDARD_NAMESPACE::full_extent);
76 for (std::size_t i = 0; i < vertices.size(); ++i)
77 {
78 auto vertex_pos = entity_dofs_all[0][i][0];
79 vertex_to_x[vertices[i]] = dofs[vertex_pos];
80 }
81 }
82
83 // Copy over existing mesh vertices
84 std::span<const T> x_g = mesh.geometry().x();
85 const std::size_t gdim = mesh.geometry().dim();
86 const std::size_t num_vertices = map_v->size_local();
87 const std::size_t num_new_vertices = local_edge_to_new_vertex.size();
88
89 std::array<std::size_t, 2> shape = {num_vertices + num_new_vertices, gdim};
90 std::vector<T> new_vertex_coords(shape[0] * shape[1]);
91 for (std::size_t v = 0; v < num_vertices; ++v)
92 {
93 std::size_t pos = 3 * vertex_to_x[v];
94 for (std::size_t j = 0; j < gdim; ++j)
95 new_vertex_coords[gdim * v + j] = x_g[pos + j];
96 }
97
98 // Compute new vertices
99 if (num_new_vertices > 0)
100 {
101 std::vector<int> edges(num_new_vertices);
102 int i = 0;
103 for (auto& e : local_edge_to_new_vertex)
104 edges[i++] = e.first;
105
106 // Compute midpoint of each edge (padded to 3D)
107 const std::vector<T> midpoints = mesh::compute_midpoints(mesh, 1, edges);
108 for (std::size_t i = 0; i < num_new_vertices; ++i)
109 for (std::size_t j = 0; j < gdim; ++j)
110 new_vertex_coords[gdim * (num_vertices + i) + j] = midpoints[3 * i + j];
111 }
112
113 return {std::move(new_vertex_coords), shape};
114}
115
116} // namespace impl
117
128 MPI_Comm comm,
129 const std::vector<std::vector<std::int32_t>>& marked_for_update,
130 std::vector<std::int8_t>& marked_edges, const common::IndexMap& map);
131
144template <std::floating_point T>
145std::tuple<std::map<std::int32_t, std::int64_t>, std::vector<T>,
146 std::array<std::size_t, 2>>
148 const graph::AdjacencyList<int>& shared_edges,
149 const mesh::Mesh<T>& mesh,
150 std::span<const std::int8_t> marked_edges)
151{
152 // Take marked_edges and use to create new vertices
153 std::shared_ptr<const common::IndexMap> edge_index_map
154 = mesh.topology()->index_map(1);
155
156 // Add new edge midpoints to list of vertices
157 int n = 0;
158 std::map<std::int32_t, std::int64_t> local_edge_to_new_vertex;
159 for (int local_i = 0; local_i < edge_index_map->size_local(); ++local_i)
160 {
161 if (marked_edges[local_i])
162 {
163 [[maybe_unused]] auto it = local_edge_to_new_vertex.insert({local_i, n});
164 assert(it.second);
165 ++n;
166 }
167 }
168
169 const std::int64_t num_local = n;
170 std::int64_t global_offset = 0;
171 MPI_Exscan(&num_local, &global_offset, 1, MPI_INT64_T, MPI_SUM, mesh.comm());
172 global_offset += mesh.topology()->index_map(0)->local_range()[1];
173 std::for_each(local_edge_to_new_vertex.begin(),
174 local_edge_to_new_vertex.end(),
175 [global_offset](auto& e) { e.second += global_offset; });
176
177 // Create actual points
178 auto [new_vertex_coords, xshape]
179 = impl::create_new_geometry(mesh, local_edge_to_new_vertex);
180
181 // If they are shared, then the new global vertex index needs to be
182 // sent off-process.
183
184 // Get number of neighbors
185 int indegree(-1), outdegree(-2), weighted(-1);
186 MPI_Dist_graph_neighbors_count(comm, &indegree, &outdegree, &weighted);
187 assert(indegree == outdegree);
188 const int num_neighbors = indegree;
189
190 std::vector<std::vector<std::int64_t>> values_to_send(num_neighbors);
191 for (auto& local_edge : local_edge_to_new_vertex)
192 {
193 const std::size_t local_i = local_edge.first;
194 // shared, but locally owned : remote owned are not in list.
195
196 for (int remote_process : shared_edges.links(local_i))
197 {
198 // Send (global edge index) -> (new global vertex index) map
199 values_to_send[remote_process].push_back(
200 impl::local_to_global(local_i, *edge_index_map));
201 values_to_send[remote_process].push_back(local_edge.second);
202 }
203 }
204
205 // Send all shared edges marked for update and receive from other
206 // processes
207 std::vector<std::int64_t> received_values;
208 {
209 int indegree(-1), outdegree(-2), weighted(-1);
210 MPI_Dist_graph_neighbors_count(comm, &indegree, &outdegree, &weighted);
211 assert(indegree == outdegree);
212
213 std::vector<std::int64_t> send_buffer;
214 std::vector<int> send_sizes;
215 for (auto& x : values_to_send)
216 {
217 send_sizes.push_back(x.size());
218 send_buffer.insert(send_buffer.end(), x.begin(), x.end());
219 }
220 assert((int)send_sizes.size() == outdegree);
221
222 std::vector<int> recv_sizes(outdegree);
223 send_sizes.reserve(1);
224 recv_sizes.reserve(1);
225 MPI_Neighbor_alltoall(send_sizes.data(), 1, MPI_INT, recv_sizes.data(), 1,
226 MPI_INT, comm);
227
228 // Build displacements
229 std::vector<int> send_disp = {0};
230 std::partial_sum(send_sizes.begin(), send_sizes.end(),
231 std::back_inserter(send_disp));
232 std::vector<int> recv_disp = {0};
233 std::partial_sum(recv_sizes.begin(), recv_sizes.end(),
234 std::back_inserter(recv_disp));
235
236 received_values.resize(recv_disp.back());
237 MPI_Neighbor_alltoallv(send_buffer.data(), send_sizes.data(),
238 send_disp.data(), MPI_INT64_T,
239 received_values.data(), recv_sizes.data(),
240 recv_disp.data(), MPI_INT64_T, comm);
241 }
242
243 // Add received remote global vertex indices to map
244 std::vector<std::int64_t> recv_global_edge;
245 assert(received_values.size() % 2 == 0);
246 for (std::size_t i = 0; i < received_values.size() / 2; ++i)
247 recv_global_edge.push_back(received_values[i * 2]);
248 std::vector<std::int32_t> recv_local_edge(recv_global_edge.size());
249 mesh.topology()->index_map(1)->global_to_local(recv_global_edge,
250 recv_local_edge);
251 for (std::size_t i = 0; i < received_values.size() / 2; ++i)
252 {
253 assert(recv_local_edge[i] != -1);
254 [[maybe_unused]] auto it = local_edge_to_new_vertex.insert(
255 {recv_local_edge[i], received_values[i * 2 + 1]});
256 assert(it.second);
257 }
258
259 return {std::move(local_edge_to_new_vertex), std::move(new_vertex_coords),
260 xshape};
261}
262
272template <std::floating_point T>
274 const graph::AdjacencyList<std::int64_t>& cell_topology,
275 std::span<const T> new_coords,
276 std::array<std::size_t, 2> xshape, bool redistribute,
277 mesh::GhostMode ghost_mode)
278{
279 if (redistribute)
280 {
281 return mesh::create_mesh(old_mesh.comm(), cell_topology,
282 old_mesh.geometry().cmaps(), new_coords, xshape,
283 ghost_mode);
284 }
285 else
286 {
287 auto partitioner
288 = [](MPI_Comm comm, int, int,
289 const graph::AdjacencyList<std::int64_t>& cell_topology)
290 {
291 const int mpi_rank = MPI::rank(comm);
292 const int num_cells = cell_topology.num_nodes();
293 std::vector<std::int32_t> destinations(num_cells, mpi_rank);
294 std::vector<std::int32_t> dest_offsets(num_cells + 1);
295 std::iota(dest_offsets.begin(), dest_offsets.end(), 0);
296 return graph::AdjacencyList(std::move(destinations),
297 std::move(dest_offsets));
298 };
299
300 return mesh::create_mesh(old_mesh.comm(), cell_topology,
301 old_mesh.geometry().cmaps(), new_coords, xshape,
302 partitioner);
303 }
304}
305
318std::vector<std::int64_t> adjust_indices(const common::IndexMap& map,
319 std::int32_t n);
320
330std::array<std::vector<std::int32_t>, 2> transfer_facet_meshtag(
331 const mesh::MeshTags<std::int32_t>& tags0, const mesh::Topology& topology1,
332 std::span<const std::int32_t> cell, std::span<const std::int8_t> facet);
333
344std::array<std::vector<std::int32_t>, 2>
346 const mesh::Topology& topology1,
347 std::span<const std::int32_t> parent_cell);
348
349} // namespace dolfinx::refinement
This class represents the distribution index arrays across processes. An index array is a contiguous ...
Definition IndexMap.h:64
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
std::int32_t num_nodes() const
Get the number of nodes.
Definition AdjacencyList.h:97
MeshTags associate values with mesh topology entities.
Definition MeshTags.h:33
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
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:44
Functions supporting mesh operations.
int rank(MPI_Comm comm)
Return process rank for the communicator.
Definition MPI.cpp:64
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
Mesh data structures and algorithms on meshes.
Definition DofMap.h:32
GhostMode
Enum for different partitioning ghost modes.
Definition utils.h:35
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
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:397
Mesh refinement algorithms.
Definition dolfinx_refinement.h:8
std::array< std::vector< std::int32_t >, 2 > transfer_facet_meshtag(const mesh::MeshTags< std::int32_t > &tags0, const mesh::Topology &topology1, std::span< const std::int32_t > cell, std::span< const std::int8_t > facet)
Transfer facet MeshTags from coarse mesh to refined mesh.
Definition utils.cpp:155
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
mesh::Mesh< T > partition(const mesh::Mesh< T > &old_mesh, const graph::AdjacencyList< std::int64_t > &cell_topology, std::span< const T > new_coords, std::array< std::size_t, 2 > xshape, bool redistribute, mesh::GhostMode ghost_mode)
Use vertex and topology data to partition new mesh across processes.
Definition utils.h:273
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
std::array< std::vector< std::int32_t >, 2 > transfer_cell_meshtag(const mesh::MeshTags< std::int32_t > &tags0, const mesh::Topology &topology1, std::span< const std::int32_t > parent_cell)
Transfer cell MeshTags from coarse mesh to refined mesh.
Definition utils.cpp:275