61 const mesh::Topology& topology, std::span<const std::int64_t> nodes_g,
63 md::mdspan<
const std::int32_t, md::dextents<std::size_t, 2>> xdofmap,
65 md::mdspan<
const std::int64_t, md::dextents<std::size_t, 2>> entities,
66 std::span<const T> data)
68 assert(entities.extent(0) == data.size());
70 spdlog::info(
"XDMF distribute entity data");
74 std::vector<int> cell_vertex_dofs;
77 const std::vector<int>& local_index = cmap_dof_layout.
entity_dofs(0, i);
78 assert(local_index.size() == 1);
79 cell_vertex_dofs.push_back(local_index[0]);
84 auto to_vertex_entities
92 const std::vector<int> entity_layout
94 std::vector<int> entity_vertex_dofs;
95 for (std::size_t i = 0; i < cell_vertex_dofs.size(); ++i)
97 auto it = std::find(entity_layout.begin(), entity_layout.end(),
99 if (it != entity_layout.end())
100 entity_vertex_dofs.push_back(std::distance(entity_layout.begin(), it));
106 assert(entities.extent(1) == entity_layout.size());
107 std::vector<std::int64_t> entities_v(entities.extent(0) * num_vert_per_e);
108 for (std::size_t e = 0; e < entities.extent(0); ++e)
110 std::span entity(entities_v.data() + e * num_vert_per_e, num_vert_per_e);
111 for (std::size_t i = 0; i < num_vert_per_e; ++i)
112 entity[i] = entities(e, entity_vertex_dofs[i]);
113 std::ranges::sort(entity);
116 std::array shape{entities.extent(0), num_vert_per_e};
117 return std::pair(std::move(entities_v), shape);
119 const auto [entities_v_b, shapev] = to_vertex_entities(
120 cmap_dof_layout, entity_dim, cell_vertex_dofs, cell_type, entities);
122 md::mdspan<const std::int64_t, md::dextents<std::size_t, 2>> entities_v(
123 entities_v_b.data(), shapev);
125 MPI_Comm comm = topology.
comm();
126 MPI_Datatype compound_type;
127 MPI_Type_contiguous(entities_v.extent(1), MPI_INT64_T, &compound_type);
128 MPI_Type_commit(&compound_type);
131 auto send_entities_to_postmaster
132 = [](MPI_Comm comm, MPI_Datatype compound_type, std::int64_t num_nodes_g,
133 auto entities, std::span<const T> data)
138 std::vector<int> dest0;
139 for (std::size_t e = 0; e < entities.extent(0); ++e)
144 std::vector<int> perm(dest0.size());
145 std::iota(perm.begin(), perm.end(), 0);
146 std::ranges::sort(perm, [&dest0](
auto x0,
auto x1)
147 {
return dest0[x0] < dest0[x1]; });
152 std::vector<int> dest;
153 std::vector<std::int32_t> num_items_send;
155 auto it = perm.begin();
156 while (it != perm.end())
158 dest.push_back(dest0[*it]);
160 = std::find_if(it, perm.end(), [&dest0, r = dest.back()](
auto idx)
161 { return dest0[idx] != r; });
162 num_items_send.push_back(std::distance(it, it1));
168 std::vector<int> send_disp(num_items_send.size() + 1, 0);
169 std::partial_sum(num_items_send.begin(), num_items_send.end(),
170 std::next(send_disp.begin()));
175 std::ranges::sort(src);
180 int err = MPI_Dist_graph_create_adjacent(
181 comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(), dest.data(),
182 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
186 std::vector<int> num_items_recv(src.size());
187 num_items_send.reserve(1);
188 num_items_recv.reserve(1);
189 MPI_Neighbor_alltoall(num_items_send.data(), 1, MPI_INT,
190 num_items_recv.data(), 1, MPI_INT, comm0);
194 std::vector<int> recv_disp(num_items_recv.size() + 1, 0);
195 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
196 std::next(recv_disp.begin()));
199 std::vector<std::int64_t> send_buffer;
200 std::vector<T> send_values_buffer;
201 send_buffer.reserve(entities.size());
202 send_values_buffer.reserve(data.size());
203 for (std::size_t e = 0; e < entities.extent(0); ++e)
206 auto it = std::next(entities.data_handle(), idx * entities.extent(1));
207 send_buffer.insert(send_buffer.end(), it, it + entities.extent(1));
208 send_values_buffer.push_back(data[idx]);
211 std::vector<std::int64_t> recv_buffer(recv_disp.back()
212 * entities.extent(1));
213 err = MPI_Neighbor_alltoallv(send_buffer.data(), num_items_send.data(),
214 send_disp.data(), compound_type,
215 recv_buffer.data(), num_items_recv.data(),
216 recv_disp.data(), compound_type, comm0);
218 std::vector<T> recv_values_buffer(recv_disp.back());
219 err = MPI_Neighbor_alltoallv(
220 send_values_buffer.data(), num_items_send.data(), send_disp.data(),
224 err = MPI_Comm_free(&comm0);
227 std::array shape{recv_buffer.size() / (entities.extent(1)),
228 (entities.extent(1))};
229 return std::tuple<std::vector<std::int64_t>, std::vector<T>,
230 std::array<std::size_t, 2>>(
231 std::move(recv_buffer), std::move(recv_values_buffer), shape);
233 const auto [entitiesp_b, entitiesp_v, shapep] = send_entities_to_postmaster(
234 comm, compound_type, num_nodes_g, entities_v, data);
235 md::mdspan<const std::int64_t, md::dextents<std::size_t, 2>> entitiesp(
236 entitiesp_b.data(), shapep);
239 auto indices_to_postoffice = [](MPI_Comm comm, std::int64_t num_nodes,
240 std::span<const std::int64_t> indices)
243 std::vector<std::pair<int, std::int64_t>> dest_to_index;
244 std::ranges::transform(
245 indices, std::back_inserter(dest_to_index),
246 [size, num_nodes](
auto n)
250 std::ranges::sort(dest_to_index);
254 std::vector<int> dest;
255 std::vector<std::int32_t> num_items_send;
257 auto it = dest_to_index.begin();
258 while (it != dest_to_index.end())
260 dest.push_back(it->first);
262 = std::find_if(it, dest_to_index.end(), [r = dest.back()](
auto idx)
263 { return idx.first != r; });
264 num_items_send.push_back(std::distance(it, it1));
270 std::vector<int> send_disp(num_items_send.size() + 1, 0);
271 std::partial_sum(num_items_send.begin(), num_items_send.end(),
272 std::next(send_disp.begin()));
277 std::ranges::sort(src);
281 int err = MPI_Dist_graph_create_adjacent(
282 comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(), dest.data(),
283 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
288 std::vector<int> num_items_recv(src.size());
289 num_items_send.reserve(1);
290 num_items_recv.reserve(1);
291 MPI_Neighbor_alltoall(num_items_send.data(), 1, MPI_INT,
292 num_items_recv.data(), 1, MPI_INT, comm0);
296 std::vector<int> recv_disp(num_items_recv.size() + 1, 0);
297 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
298 std::next(recv_disp.begin()));
301 std::vector<std::int64_t> send_buffer;
302 send_buffer.reserve(indices.size());
303 std::ranges::transform(dest_to_index, std::back_inserter(send_buffer),
304 [](
auto x) {
return x.second; });
306 std::vector<std::int64_t> recv_buffer(recv_disp.back());
307 err = MPI_Neighbor_alltoallv(send_buffer.data(), num_items_send.data(),
308 send_disp.data(), MPI_INT64_T,
309 recv_buffer.data(), num_items_recv.data(),
310 recv_disp.data(), MPI_INT64_T, comm0);
312 err = MPI_Comm_free(&comm0);
314 return std::tuple(std::move(recv_buffer), std::move(recv_disp),
315 std::move(src), std::move(dest));
317 const auto [nodes_g_p, recv_disp, src, dest]
318 = indices_to_postoffice(comm, num_nodes_g, nodes_g);
322 = [](MPI_Comm comm, MPI_Datatype compound_type,
323 std::span<const std::int64_t> indices_recv,
324 std::span<const int> indices_recv_disp, std::span<const int> src,
325 std::span<const int> dest,
auto entities, std::span<const T> data)
329 std::multimap<std::int64_t, int> node_to_rank;
330 for (std::size_t i = 0; i < indices_recv_disp.size() - 1; ++i)
331 for (
int j = indices_recv_disp[i]; j < indices_recv_disp[i + 1]; ++j)
332 node_to_rank.insert({indices_recv[j], i});
334 std::vector<std::vector<std::int64_t>> send_data(dest.size());
335 std::vector<std::vector<T>> send_values(dest.size());
336 for (std::size_t e = 0; e < entities.extent(0); ++e)
338 std::span e_recv(entities.data_handle() + e * entities.extent(1),
340 auto [it0, it1] = node_to_rank.equal_range(entities(e, 0));
341 for (
auto it = it0; it != it1; ++it)
344 send_data[p].insert(send_data[p].end(), e_recv.begin(), e_recv.end());
345 send_values[p].push_back(data[e]);
350 int err = MPI_Dist_graph_create_adjacent(
351 comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(), dest.data(),
352 MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
355 std::vector<int> num_items_send;
356 for (
auto& x : send_data)
357 num_items_send.push_back(x.size() / entities.extent(1));
359 std::vector<int> num_items_recv(src.size());
360 num_items_send.reserve(1);
361 num_items_recv.reserve(1);
362 err = MPI_Neighbor_alltoall(num_items_send.data(), 1, MPI_INT,
363 num_items_recv.data(), 1, MPI_INT, comm0);
367 std::vector<std::int32_t> send_disp(num_items_send.size() + 1, 0);
368 std::partial_sum(num_items_send.begin(), num_items_send.end(),
369 std::next(send_disp.begin()));
372 std::vector<std::int32_t> recv_disp(num_items_recv.size() + 1, 0);
373 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
374 std::next(recv_disp.begin()));
377 std::vector<std::int64_t> send_buffer;
378 std::vector<T> send_values_buffer;
379 for (
auto& x : send_data)
380 send_buffer.insert(send_buffer.end(), x.begin(), x.end());
381 for (
auto& v : send_values)
382 send_values_buffer.insert(send_values_buffer.end(), v.begin(), v.end());
383 std::vector<std::int64_t> recv_buffer(entities.extent(1)
385 err = MPI_Neighbor_alltoallv(send_buffer.data(), num_items_send.data(),
386 send_disp.data(), compound_type,
387 recv_buffer.data(), num_items_recv.data(),
388 recv_disp.data(), compound_type, comm0);
392 std::vector<T> recv_values_buffer(recv_disp.back());
393 err = MPI_Neighbor_alltoallv(
394 send_values_buffer.data(), num_items_send.data(), send_disp.data(),
400 err = MPI_Comm_free(&comm0);
403 std::array shape{recv_buffer.size() / entities.extent(1),
405 return std::tuple<std::vector<std::int64_t>, std::vector<T>,
406 std::array<std::size_t, 2>>(
407 std::move(recv_buffer), std::move(recv_values_buffer), shape);
411 const auto [entities_data_b, entities_values, shape_eb]
412 = candidate_ranks(comm, compound_type, nodes_g_p, recv_disp, dest, src,
413 entitiesp, std::span(entitiesp_v));
414 md::mdspan<const std::int64_t, md::dextents<std::size_t, 2>> entities_data(
415 entities_data_b.data(), shape_eb);
426 std::span<const std::int64_t> nodes_g,
427 std::span<const int> cell_vertex_dofs,
auto entities_data,
428 std::span<const T> entities_values)
430 spdlog::info(
"XDMF build map");
433 throw std::runtime_error(
"Missing cell-vertex connectivity.");
435 std::map<std::int64_t, std::int32_t> input_idx_to_vertex;
436 for (
int c = 0; c < c_to_v->num_nodes(); ++c)
438 auto vertices = c_to_v->links(c);
439 std::span xdofs(xdofmap.data_handle() + c * xdofmap.extent(1),
441 for (std::size_t v = 0; v < vertices.size(); ++v)
442 input_idx_to_vertex[nodes_g[xdofs[cell_vertex_dofs[v]]]] = vertices[v];
445 std::vector<std::int32_t> entities;
447 std::vector<std::int32_t> entity(entities_data.extent(1));
448 for (std::size_t e = 0; e < entities_data.extent(0); ++e)
450 bool entity_found =
true;
451 for (std::size_t i = 0; i < entities_data.extent(1); ++i)
453 if (
auto it = input_idx_to_vertex.find(entities_data(e, i));
454 it == input_idx_to_vertex.end())
458 entity_found =
false;
462 entity[i] = it->second;
467 entities.insert(entities.end(), entity.begin(), entity.end());
468 data.push_back(entities_values[e]);
472 return std::pair(std::move(entities), std::move(data));
475 MPI_Type_free(&compound_type);
477 return select_entities(topology, xdofmap, nodes_g, cell_vertex_dofs,
478 entities_data, std::span(entities_values));