63 const mesh::Topology& topology, std::span<const std::int64_t> nodes_g,
65 md::mdspan<
const std::int32_t, md::dextents<std::size_t, 2>> xdofmap,
67 md::mdspan<
const std::int64_t, md::dextents<std::size_t, 2>> entities,
68 std::span<const T> data)
70 assert(entities.extent(0) == data.size());
72 spdlog::info(
"XDMF distribute entity data");
76 std::vector<int> cell_vertex_dofs;
79 const std::vector<int>& local_index = cmap_dof_layout.
entity_dofs(0, i);
80 assert(local_index.size() == 1);
81 cell_vertex_dofs.push_back(local_index[0]);
86 auto to_vertex_entities
94 std::vector<int> entity_vertex_dofs;
95 for (std::size_t i = 0; i < 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(
101 std::ranges::distance(entity_layout.begin(), it));
104 const std::size_t num_vert_per_e
107 assert(ents.extent(1) == entity_layout.size());
108 std::vector<std::int64_t> entities_v(ents.extent(0) * num_vert_per_e);
109 for (std::size_t e = 0; e < ents.extent(0); ++e)
111 std::span entity(entities_v.data() + e * num_vert_per_e, num_vert_per_e);
112 for (std::size_t i = 0; i < num_vert_per_e; ++i)
113 entity[i] = ents(e, entity_vertex_dofs[i]);
114 std::ranges::sort(entity);
117 std::array shape{ents.extent(0), num_vert_per_e};
118 return std::pair(std::move(entities_v), shape);
120 const auto [entities_v_b, shapev] = to_vertex_entities(
121 cmap_dof_layout, entity_dim, cell_vertex_dofs, cell_type, entities);
123 md::mdspan<const std::int64_t, md::dextents<std::size_t, 2>> entities_v(
124 entities_v_b.data(), shapev);
126 MPI_Comm comm = topology.
comm();
127 MPI_Datatype compound_type;
128 MPI_Type_contiguous(entities_v.extent(1), MPI_INT64_T, &compound_type);
129 MPI_Type_commit(&compound_type);
132 auto send_entities_to_postmaster
133 = [](MPI_Comm pm_comm, MPI_Datatype pm_compound_type,
134 std::int64_t pm_num_nodes_g,
auto pm_entities,
135 std::span<const T> pm_data)
140 std::vector<int> dest0;
141 dest0.reserve(pm_entities.extent(0));
142 for (std::size_t e = 0; e < pm_entities.extent(0); ++e)
147 std::vector<int> perm(dest0.size());
148 std::iota(perm.begin(), perm.end(), 0);
149 std::ranges::sort(perm, [&dest0](
auto x0,
auto x1)
150 {
return dest0[x0] < dest0[x1]; });
155 std::vector<int> dest;
156 std::vector<std::int32_t> num_items_send;
158 auto it = perm.begin();
159 while (it != perm.end())
161 dest.push_back(dest0[*it]);
163 = std::find_if(it, perm.end(), [&dest0, r = dest.back()](
auto idx)
164 { return dest0[idx] != r; });
165 num_items_send.push_back(std::ranges::distance(it, it1));
171 std::vector<int> send_disp(num_items_send.size() + 1, 0);
172 std::partial_sum(num_items_send.begin(), num_items_send.end(),
173 std::next(send_disp.begin()));
178 std::ranges::sort(src);
183 int err = MPI_Dist_graph_create_adjacent(
184 pm_comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(),
185 dest.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
189 std::vector<int> num_items_recv(src.size());
190 num_items_send.reserve(1);
191 num_items_recv.reserve(1);
192 MPI_Neighbor_alltoall(num_items_send.data(), 1, MPI_INT,
193 num_items_recv.data(), 1, MPI_INT, comm0);
197 std::vector<int> recv_disp(num_items_recv.size() + 1, 0);
198 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
199 std::next(recv_disp.begin()));
202 std::vector<std::int64_t> send_buffer;
203 std::vector<T> send_values_buffer;
204 send_buffer.reserve(pm_entities.size());
205 send_values_buffer.reserve(pm_data.size());
206 for (std::size_t e = 0; e < pm_entities.extent(0); ++e)
210 = std::next(pm_entities.data_handle(), idx * pm_entities.extent(1));
211 send_buffer.insert(send_buffer.end(), it, it + pm_entities.extent(1));
212 send_values_buffer.push_back(pm_data[idx]);
215 std::vector<std::int64_t> recv_buffer(recv_disp.back()
216 * pm_entities.extent(1));
217 err = MPI_Neighbor_alltoallv(send_buffer.data(), num_items_send.data(),
218 send_disp.data(), pm_compound_type,
219 recv_buffer.data(), num_items_recv.data(),
220 recv_disp.data(), pm_compound_type, comm0);
222 std::vector<T> recv_values_buffer(recv_disp.back());
223 err = MPI_Neighbor_alltoallv(
224 send_values_buffer.data(), num_items_send.data(), send_disp.data(),
228 err = MPI_Comm_free(&comm0);
231 std::array shape{recv_buffer.size() / (pm_entities.extent(1)),
232 (pm_entities.extent(1))};
233 return std::tuple<std::vector<std::int64_t>, std::vector<T>,
234 std::array<std::size_t, 2>>(
235 std::move(recv_buffer), std::move(recv_values_buffer), shape);
237 const auto [entitiesp_b, entitiesp_v, shapep] = send_entities_to_postmaster(
238 comm, compound_type, num_nodes_g, entities_v, data);
239 md::mdspan<const std::int64_t, md::dextents<std::size_t, 2>> entitiesp(
240 entitiesp_b.data(), shapep);
243 auto indices_to_postoffice = [](MPI_Comm po_comm, std::int64_t num_nodes,
244 std::span<const std::int64_t> indices)
247 std::vector<std::pair<int, std::int64_t>> dest_to_index;
248 std::ranges::transform(
249 indices, std::back_inserter(dest_to_index),
250 [size, num_nodes](
auto n)
254 std::ranges::sort(dest_to_index);
258 std::vector<int> dest;
259 std::vector<std::int32_t> num_items_send;
261 auto it = dest_to_index.begin();
262 while (it != dest_to_index.end())
264 dest.push_back(it->first);
266 = std::find_if(it, dest_to_index.end(), [r = dest.back()](
auto idx)
267 { return idx.first != r; });
268 num_items_send.push_back(std::ranges::distance(it, it1));
274 std::vector<int> send_disp(num_items_send.size() + 1, 0);
275 std::partial_sum(num_items_send.begin(), num_items_send.end(),
276 std::next(send_disp.begin()));
281 std::ranges::sort(src);
285 int err = MPI_Dist_graph_create_adjacent(
286 po_comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(),
287 dest.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
292 std::vector<int> num_items_recv(src.size());
293 num_items_send.reserve(1);
294 num_items_recv.reserve(1);
295 MPI_Neighbor_alltoall(num_items_send.data(), 1, MPI_INT,
296 num_items_recv.data(), 1, MPI_INT, comm0);
300 std::vector<int> recv_disp(num_items_recv.size() + 1, 0);
301 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
302 std::next(recv_disp.begin()));
305 std::vector<std::int64_t> send_buffer;
306 send_buffer.reserve(indices.size());
307 std::ranges::transform(dest_to_index, std::back_inserter(send_buffer),
308 [](
auto x) {
return x.second; });
310 std::vector<std::int64_t> recv_buffer(recv_disp.back());
311 err = MPI_Neighbor_alltoallv(send_buffer.data(), num_items_send.data(),
312 send_disp.data(), MPI_INT64_T,
313 recv_buffer.data(), num_items_recv.data(),
314 recv_disp.data(), MPI_INT64_T, comm0);
316 err = MPI_Comm_free(&comm0);
318 return std::tuple(std::move(recv_buffer), std::move(recv_disp),
319 std::move(src), std::move(dest));
321 const auto [nodes_g_p, nodes_g_p_disp, post_src, post_dest]
322 = indices_to_postoffice(comm, num_nodes_g, nodes_g);
326 = [](MPI_Comm cr_comm, MPI_Datatype cr_compound_type,
327 std::span<const std::int64_t> indices_recv,
328 std::span<const int> indices_recv_disp, std::span<const int> src,
329 std::span<const int> dest,
auto entities, std::span<const T> cr_data)
333 std::multimap<std::int64_t, int> node_to_rank;
334 for (std::size_t i = 0; i < indices_recv_disp.size() - 1; ++i)
335 for (
int j = indices_recv_disp[i]; j < indices_recv_disp[i + 1]; ++j)
336 node_to_rank.insert({indices_recv[j], i});
338 std::vector<std::vector<std::int64_t>> send_data(dest.size());
339 std::vector<std::vector<T>> send_values(dest.size());
340 for (std::size_t e = 0; e < entities.extent(0); ++e)
342 std::span e_recv(entities.data_handle() + e * entities.extent(1),
344 auto [it0, it1] = node_to_rank.equal_range(entities(e, 0));
345 for (
auto it = it0; it != it1; ++it)
348 send_data[p].insert(send_data[p].end(), e_recv.begin(), e_recv.end());
349 send_values[p].push_back(cr_data[e]);
354 int err = MPI_Dist_graph_create_adjacent(
355 cr_comm, src.size(), src.data(), MPI_UNWEIGHTED, dest.size(),
356 dest.data(), MPI_UNWEIGHTED, MPI_INFO_NULL,
false, &comm0);
359 std::vector<int> num_items_send;
360 num_items_send.reserve(send_data.size());
361 for (
auto& x : send_data)
362 num_items_send.push_back(x.size() / entities.extent(1));
364 std::vector<int> num_items_recv(src.size());
365 num_items_send.reserve(1);
366 num_items_recv.reserve(1);
367 err = MPI_Neighbor_alltoall(num_items_send.data(), 1, MPI_INT,
368 num_items_recv.data(), 1, MPI_INT, comm0);
372 std::vector<std::int32_t> send_disp(num_items_send.size() + 1, 0);
373 std::partial_sum(num_items_send.begin(), num_items_send.end(),
374 std::next(send_disp.begin()));
377 std::vector<std::int32_t> recv_disp(num_items_recv.size() + 1, 0);
378 std::partial_sum(num_items_recv.begin(), num_items_recv.end(),
379 std::next(recv_disp.begin()));
382 std::vector<std::int64_t> send_buffer;
383 std::vector<T> send_values_buffer;
384 for (
auto& x : send_data)
385 send_buffer.insert(send_buffer.end(), x.begin(), x.end());
386 for (
auto& v : send_values)
387 send_values_buffer.insert(send_values_buffer.end(), v.begin(), v.end());
388 std::vector<std::int64_t> recv_buffer(entities.extent(1)
390 err = MPI_Neighbor_alltoallv(send_buffer.data(), num_items_send.data(),
391 send_disp.data(), cr_compound_type,
392 recv_buffer.data(), num_items_recv.data(),
393 recv_disp.data(), cr_compound_type, comm0);
397 std::vector<T> recv_values_buffer(recv_disp.back());
398 err = MPI_Neighbor_alltoallv(
399 send_values_buffer.data(), num_items_send.data(), send_disp.data(),
405 err = MPI_Comm_free(&comm0);
408 std::array shape{recv_buffer.size() / entities.extent(1),
410 return std::tuple<std::vector<std::int64_t>, std::vector<T>,
411 std::array<std::size_t, 2>>(
412 std::move(recv_buffer), std::move(recv_values_buffer), shape);
416 const auto [entities_data_b, entities_values, shape_eb]
417 = candidate_ranks(comm, compound_type, nodes_g_p, nodes_g_p_disp,
418 post_dest, post_src, entitiesp, std::span(entitiesp_v));
419 md::mdspan<const std::int64_t, md::dextents<std::size_t, 2>> entities_data(
420 entities_data_b.data(), shape_eb);
429 auto select_entities = [](
const mesh::Topology& topo,
auto xdofmap,
430 std::span<const std::int64_t> nodes,
431 std::span<const int> cell_vertex_dofs,
432 auto entities_data, std::span<const T> values)
434 spdlog::info(
"XDMF build map");
437 throw std::runtime_error(
"Missing cell-vertex connectivity.");
440 boost::unordered_flat_map<std::int64_t, std::int32_t> input_idx_to_vertex;
441 input_idx_to_vertex.reserve(c_to_v->num_nodes() * cell_vertex_dofs.size());
442 for (
int c = 0; c < c_to_v->num_nodes(); ++c)
444 auto vertices = c_to_v->links(c);
445 std::span xdofs(xdofmap.data_handle() + c * xdofmap.extent(1),
447 for (std::size_t v = 0; v < vertices.size(); ++v)
448 input_idx_to_vertex[nodes[xdofs[cell_vertex_dofs[v]]]] = vertices[v];
451 std::vector<std::int32_t> local_entities;
452 std::vector<T> local_data;
453 local_entities.reserve(entities_data.extent(0) * entities_data.extent(1));
454 local_data.reserve(entities_data.extent(0));
455 std::vector<std::int32_t> entity(entities_data.extent(1));
456 for (std::size_t e = 0; e < entities_data.extent(0); ++e)
458 bool entity_found =
true;
459 for (std::size_t i = 0; i < entities_data.extent(1); ++i)
461 if (
auto it = input_idx_to_vertex.find(entities_data(e, i));
462 it == input_idx_to_vertex.end())
466 entity_found =
false;
470 entity[i] = it->second;
475 local_entities.insert(local_entities.end(), entity.begin(),
477 local_data.push_back(values[e]);
481 return std::pair(std::move(local_entities), std::move(local_data));
484 MPI_Type_free(&compound_type);
486 return select_entities(topology, xdofmap, nodes_g, cell_vertex_dofs,
487 entities_data, std::span(entities_values));