Skip to content

Commit 25214e7

Browse files
authored
Merge branch 'main' into main
2 parents cc41cac + cd10d4e commit 25214e7

37 files changed

+1016
-456
lines changed

cpp/demo/custom_kernel/main.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ double assemble_vector1(const mesh::Geometry<T>& g, const fem::DofMap& dofmap,
168168
common::Timer timer("Assembler1 lambda (vector)");
169169
fem::impl::assemble_cells<T, 1>([](auto, auto, auto, auto) {},
170170
b.mutable_array(), g.dofmap(), g.x(), cells,
171-
dofmap.map(), 1, kernel, {}, {}, 0, {});
171+
{dofmap.map(), 1, cells}, kernel, {}, {}, 0, {});
172172
b.scatter_rev(std::plus<T>());
173173
return la::squared_norm(b);
174174
}

cpp/dolfinx/common/IndexMap.cpp

+39-14
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ communicate_ghosts_to_owners(MPI_Comm comm, std::span<const int> src,
164164
/// @param[in] imap An index map.
165165
/// @param[in] indices List of entity indices (indices local to the
166166
/// process).
167+
/// @param[in] order Control the order in which ghost indices appear in
168+
/// the new map.
167169
/// @param[in] allow_owner_change Allows indices that are not included
168170
/// by their owning process but included on sharing processes to be
169171
/// included in the submap. These indices will be owned by one of the
@@ -176,7 +178,7 @@ std::tuple<std::vector<std::int32_t>, std::vector<std::int32_t>,
176178
std::vector<int>, std::vector<int>, std::vector<int>>
177179
compute_submap_indices(const IndexMap& imap,
178180
std::span<const std::int32_t> indices,
179-
bool allow_owner_change)
181+
IndexMapOrder order, bool allow_owner_change)
180182
{
181183
std::span<const int> src = imap.src();
182184
std::span<const int> dest = imap.dest();
@@ -203,7 +205,7 @@ compute_submap_indices(const IndexMap& imap,
203205
// `recv_indices` will necessarily be in `indices` on this process, and thus
204206
// other processes must own them in the submap.
205207

206-
std::vector<int> recv_owners(send_disp.back()), submap_dest;
208+
std::vector<int> recv_owners(send_disp.back());
207209
const int rank = dolfinx::MPI::rank(imap.comm());
208210
{
209211
// Flag to track if the owner of any indices have changed in the submap
@@ -231,11 +233,7 @@ compute_submap_indices(const IndexMap& imap,
231233
// this process remains its owner in the submap. Otherwise,
232234
// add the process that sent it to the list of possible owners.
233235
if (is_in_submap[idx_local])
234-
{
235236
global_idx_to_possible_owner.push_back({idx, rank});
236-
// Add the sending process as a destination rank in the submap
237-
submap_dest.push_back(dest[i]);
238-
}
239237
else
240238
{
241239
owners_changed = true;
@@ -250,10 +248,6 @@ compute_submap_indices(const IndexMap& imap,
250248

251249
std::sort(global_idx_to_possible_owner.begin(),
252250
global_idx_to_possible_owner.end());
253-
std::sort(submap_dest.begin(), submap_dest.end());
254-
submap_dest.erase(std::unique(submap_dest.begin(), submap_dest.end()),
255-
submap_dest.end());
256-
submap_dest.shrink_to_fit();
257251

258252
// Choose the submap owner for each index in `recv_indices`
259253
std::vector<int> send_owners;
@@ -350,6 +344,37 @@ compute_submap_indices(const IndexMap& imap,
350344
submap_src.end());
351345
submap_src.shrink_to_fit();
352346

347+
// If required, preserve the order of the ghost indices
348+
if (order == IndexMapOrder::preserve)
349+
{
350+
// Build (old postion, new position) list for ghosts and sort
351+
std::vector<std::pair<std::int32_t, std::int32_t>> pos;
352+
pos.reserve(submap_ghost.size());
353+
for (std::int32_t idx : submap_ghost)
354+
pos.emplace_back(idx, pos.size());
355+
std::sort(pos.begin(), pos.end());
356+
357+
// Order ghosts in the sub-map by their position in the parent map
358+
std::vector<int> submap_ghost_owners1;
359+
submap_ghost_owners1.reserve(submap_ghost_owners.size());
360+
std::vector<std::int32_t> submap_ghost1;
361+
submap_ghost1.reserve(submap_ghost.size());
362+
for (auto [_, idx] : pos)
363+
{
364+
submap_ghost_owners1.push_back(submap_ghost_owners[idx]);
365+
submap_ghost1.push_back(submap_ghost[idx]);
366+
}
367+
368+
submap_ghost_owners = std::move(submap_ghost_owners1);
369+
submap_ghost = std::move(submap_ghost1);
370+
}
371+
372+
// Compute submap destination ranks
373+
// FIXME Remove call to NBX
374+
std::vector<int> submap_dest
375+
= dolfinx::MPI::compute_graph_edges_nbx(imap.comm(), submap_src);
376+
std::sort(submap_dest.begin(), submap_dest.end());
377+
353378
return {std::move(submap_owned), std::move(submap_ghost),
354379
std::move(submap_ghost_owners), std::move(submap_src),
355380
std::move(submap_dest)};
@@ -725,14 +750,14 @@ common::stack_index_maps(
725750
std::pair<IndexMap, std::vector<std::int32_t>>
726751
common::create_sub_index_map(const IndexMap& imap,
727752
std::span<const std::int32_t> indices,
728-
bool allow_owner_change)
753+
IndexMapOrder order, bool allow_owner_change)
729754
{
730755
// Compute the owned, ghost, and ghost owners of submap indices.
731756
// NOTE: All indices are local and numbered w.r.t. the original (imap)
732757
// index map
733-
const auto [submap_owned, submap_ghost, submap_ghost_owners, submap_src,
734-
submap_dest]
735-
= compute_submap_indices(imap, indices, allow_owner_change);
758+
auto [submap_owned, submap_ghost, submap_ghost_owners, submap_src,
759+
submap_dest]
760+
= compute_submap_indices(imap, indices, order, allow_owner_change);
736761

737762
// Compute submap offset for this rank
738763
std::int64_t submap_local_size = submap_owned.size();

cpp/dolfinx/common/IndexMap.h

+25-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2015-2022 Chris Richardson, Garth N. Wells and Igor Baratta
1+
// Copyright (C) 2015-2024 Chris Richardson, Garth N. Wells and Igor Baratta
22
//
33
// This file is part of DOLFINx (https://www.fenicsproject.org)
44
//
@@ -19,6 +19,14 @@ namespace dolfinx::common
1919
// Forward declaration
2020
class IndexMap;
2121

22+
/// Enum to control preservation of ghost index ordering in
23+
/// sub-IndexMaps.
24+
enum class IndexMapOrder : bool
25+
{
26+
preserve = true, ///< Preserve the ordering of ghost indices
27+
any = false ///< Allow arbitrary ordering of ghost indices in sub-maps
28+
};
29+
2230
/// @brief Given a sorted vector of indices (local numbering, owned or
2331
/// ghost) and an index map, this function returns the indices owned by
2432
/// this process, including indices that might have been in the list of
@@ -60,6 +68,8 @@ stack_index_maps(
6068
/// @param[in] imap Parent map to create a new sub-map from.
6169
/// @param[in] indices Local indices in `imap` (owned and ghost) to
6270
/// include in the new index map.
71+
/// @param[in] order Control the order in which ghost indices appear in
72+
/// the new map.
6373
/// @param[in] allow_owner_change If `true`, indices that are not
6474
/// included in `indices` by their owning process can be included in
6575
/// `indices` by processes that ghost the indices to be included in the
@@ -70,10 +80,9 @@ stack_index_maps(
7080
/// @return The (i) new index map and (ii) a map from local indices in
7181
/// the submap to local indices in the original (this) map.
7282
/// @pre `indices` must be sorted and must not contain duplicates.
73-
std::pair<IndexMap, std::vector<std::int32_t>>
74-
create_sub_index_map(const IndexMap& imap,
75-
std::span<const std::int32_t> indices,
76-
bool allow_owner_change = false);
83+
std::pair<IndexMap, std::vector<std::int32_t>> create_sub_index_map(
84+
const IndexMap& imap, std::span<const std::int32_t> indices,
85+
IndexMapOrder order = IndexMapOrder::any, bool allow_owner_change = false);
7786

7887
/// This class represents the distribution index arrays across
7988
/// processes. An index array is a contiguous collection of `N+1`
@@ -227,18 +236,19 @@ class IndexMap
227236

228237
/// @brief Returns the imbalance of the current IndexMap.
229238
///
230-
/// The imbalance is a measure of load balancing across all processes, defined
231-
/// as the maximum number of indices on any process divided by the average
232-
/// number of indices per process. This function calculates the imbalance
233-
/// separately for owned indices and ghost indices and returns them as a
234-
/// std::array<double, 2>. If the total number of owned or ghost indices is
235-
/// zero, the respective entry in the array is set to -1.
239+
/// The imbalance is a measure of load balancing across all processes,
240+
/// defined as the maximum number of indices on any process divided by
241+
/// the average number of indices per process. This function
242+
/// calculates the imbalance separately for owned indices and ghost
243+
/// indices and returns them as a std::array<double, 2>. If the total
244+
/// number of owned or ghost indices is zero, the respective entry in
245+
/// the array is set to -1.
236246
///
237-
/// @note This is a collective operation and must be called by all processes
238-
/// in the communicator associated with the IndexMap.
247+
/// @note This is a collective operation and must be called by all
248+
/// processes in the communicator associated with the IndexMap.
239249
///
240-
/// @return An array containing the imbalance in owned indices
241-
/// (first element) and the imbalance in ghost indices (second element).
250+
/// @return An array containing the imbalance in owned indices (first
251+
/// element) and the imbalance in ghost indices (second element).
242252
std::array<double, 2> imbalance() const;
243253

244254
private:

cpp/dolfinx/common/MPI.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,10 @@ dolfinx::MPI::compute_graph_edges_pcx(MPI_Comm comm, std::span<const int> edges)
116116
dolfinx::MPI::check_error(comm, err);
117117

118118
std::vector<MPI_Request> send_requests(edges.size());
119-
std::byte send_buffer;
119+
std::vector<std::byte> send_buffer(edges.size());
120120
for (std::size_t e = 0; e < edges.size(); ++e)
121121
{
122-
int err = MPI_Isend(&send_buffer, 1, MPI_BYTE, edges[e],
122+
int err = MPI_Isend(send_buffer.data() + e, 1, MPI_BYTE, edges[e],
123123
static_cast<int>(tag::consensus_pcx), comm,
124124
&send_requests[e]);
125125
dolfinx::MPI::check_error(comm, err);
@@ -168,10 +168,10 @@ dolfinx::MPI::compute_graph_edges_nbx(MPI_Comm comm, std::span<const int> edges)
168168

169169
// Start non-blocking synchronised send
170170
std::vector<MPI_Request> send_requests(edges.size());
171-
std::byte send_buffer;
171+
std::vector<std::byte> send_buffer(edges.size());
172172
for (std::size_t e = 0; e < edges.size(); ++e)
173173
{
174-
int err = MPI_Issend(&send_buffer, 1, MPI_BYTE, edges[e],
174+
int err = MPI_Issend(send_buffer.data() + e, 1, MPI_BYTE, edges[e],
175175
static_cast<int>(tag::consensus_pex), comm,
176176
&send_requests[e]);
177177
dolfinx::MPI::check_error(comm, err);

cpp/dolfinx/fem/DofMap.cpp

+4-6
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,8 @@ fem::DofMap build_collapsed_dofmap(const DofMap& dofmap_view,
6060
std::vector<std::int32_t> sub_imap_to_imap;
6161
if (bs_view == 1)
6262
{
63-
auto [_index_map, _sub_imap_to_imap]
64-
= dolfinx::common::create_sub_index_map(*dofmap_view.index_map,
65-
dofs_view);
63+
auto [_index_map, _sub_imap_to_imap] = common::create_sub_index_map(
64+
*dofmap_view.index_map, dofs_view, common::IndexMapOrder::preserve);
6665
index_map = std::make_shared<common::IndexMap>(std::move(_index_map));
6766
sub_imap_to_imap = std::move(_sub_imap_to_imap);
6867
}
@@ -73,9 +72,8 @@ fem::DofMap build_collapsed_dofmap(const DofMap& dofmap_view,
7372
std::transform(dofs_view.begin(), dofs_view.end(),
7473
std::back_inserter(indices),
7574
[bs_view](auto idx) { return idx / bs_view; });
76-
auto [_index_map, _sub_imap_to_imap]
77-
= dolfinx::common::create_sub_index_map(*dofmap_view.index_map,
78-
indices);
75+
auto [_index_map, _sub_imap_to_imap] = common::create_sub_index_map(
76+
*dofmap_view.index_map, indices, common::IndexMapOrder::preserve);
7977
index_map = std::make_shared<common::IndexMap>(std::move(_index_map));
8078
sub_imap_to_imap = std::move(_sub_imap_to_imap);
8179
}

cpp/dolfinx/fem/assemble_matrix_impl.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ using mdspan2_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
4040
/// @param dofmap0 Test function (row) degree-of-freedom data holding
4141
/// the (0) dofmap, (1) dofmap block size and (2) dofmap cell indices.
4242
/// @param P0 Function that applies transformation P_0 A in-place to
43-
/// transform trial degrees-of-freedom.
43+
/// transform test degrees-of-freedom.
4444
/// @param dofmap1 Trial function (column) degree-of-freedom data
4545
/// holding the (0) dofmap, (1) dofmap block size and (2) dofmap cell
4646
/// indices.
@@ -168,7 +168,7 @@ void assemble_cells(
168168
/// @param dofmap0 Test function (row) degree-of-freedom data holding
169169
/// the (0) dofmap, (1) dofmap block size and (2) dofmap cell indices.
170170
/// @param P0 Function that applies transformation P0.A in-place to
171-
/// transform trial degrees-of-freedom.
171+
/// transform test degrees-of-freedom.
172172
/// @param dofmap1 Trial function (column) degree-of-freedom data
173173
/// holding the (0) dofmap, (1) dofmap block size and (2) dofmap cell
174174
/// indices.
@@ -218,13 +218,13 @@ void assemble_exterior_facets(
218218
assert(facets1.size() == facets.size());
219219
for (std::size_t index = 0; index < facets.size(); index += 2)
220220
{
221-
// Cell in the integration domain
221+
// Cell in the integration domain, local facet index relative to the
222+
// integration domain cell, and cells in the test and trial function
223+
// meshes
222224
std::int32_t cell = facets[index];
223-
// Cell in the test function mesh
225+
std::int32_t local_facet = facets[index + 1];
224226
std::int32_t cell0 = facets0[index];
225-
// Cell in the trial function mesh
226227
std::int32_t cell1 = facets1[index];
227-
std::int32_t local_facet = facets[index + 1];
228228

229229
// Get cell coordinates/geometry
230230
auto x_dofs = MDSPAN_IMPL_STANDARD_NAMESPACE::submdspan(
@@ -295,7 +295,7 @@ void assemble_exterior_facets(
295295
/// @param dofmap0 Test function (row) degree-of-freedom data holding
296296
/// the (0) dofmap, (1) dofmap block size and (2) dofmap cell indices.
297297
/// @param P0 Function that applies transformation P0.A in-place to
298-
/// transform trial degrees-of-freedom.
298+
/// transform test degrees-of-freedom.
299299
/// @param dofmap1 Trial function (column) degree-of-freedom data
300300
/// holding the (0) dofmap, (1) dofmap block size and (2) dofmap cell
301301
/// indices.

0 commit comments

Comments
 (0)