31#ifdef MFEM_USE_STRUMPACK
32#include <StrumpackConfig.hpp>
44#if defined(MFEM_USE_STRUMPACK) && \
45 (defined(STRUMPACK_USE_PTSCOTCH) || defined(STRUMPACK_USE_SLATE_SCALAPACK))
54 group_lproc(gt.group_lproc)
56 gt.groupmaster_lproc.
Copy(groupmaster_lproc);
57 gt.lproc_proc.
Copy(lproc_proc);
58 gt.group_mgroup.
Copy(group_mgroup);
61void GroupTopology::ProcToLProc()
64 MPI_Comm_size(MyComm, &
NRanks);
66 map<int, int> proc_lproc;
71 int lproc_counter = 0;
74 const pair<const int, int>
p(group_lproc.
GetJ()[i], lproc_counter);
75 if (proc_lproc.insert(
p).second)
82 lproc_proc.
SetSize(lproc_counter);
83 for (map<int, int>::iterator it = proc_lproc.begin();
84 it != proc_lproc.end(); ++it)
86 lproc_proc[it->second] = it->first;
91 group_lproc.
GetJ()[i] = proc_lproc[group_lproc.
GetJ()[i]];
94 for (
int i = 0; i <
NGroups(); i++)
96 groupmaster_lproc[i] = proc_lproc[groupmaster_lproc[i]];
104 Table group_mgroupandproc;
107 for (
int i = 0; i <
NGroups(); i++)
109 int j = group_mgroupandproc.
GetI()[i];
110 group_mgroupandproc.
GetI()[i+1] = j + group_lproc.
RowSize(i) + 1;
111 group_mgroupandproc.
GetJ()[j] = i;
113 for (
int k = group_lproc.
GetI()[i];
114 j < group_mgroupandproc.
GetI()[i+1]; j++, k++)
116 group_mgroupandproc.
GetJ()[j] = group_lproc.
GetJ()[k];
124 for (
int i = 0; i <
NGroups(); i++)
142 MFEM_DEBUG_DO(group_mgroup = -1);
143 for (
int g = 0; g <
NGroups(); g++)
145 if (
IAmMaster(g)) { group_mgroup[g] = g; }
153 for (
int g = 1; g <
NGroups(); g++)
159 for (
int i = 0; i < gs; i++)
172 lproc_cgroup_list.
Sort();
173 lproc_cgroup_list.
Unique();
185 for (
int nbr = 1; nbr < lproc_cgroup.
Size(); nbr++)
187 const int send_row = 2*(nbr-1);
188 const int recv_row = send_row+1;
189 const int ng = lproc_cgroup.
RowSize(nbr);
190 const int *g = lproc_cgroup.
GetRow(nbr);
191 for (
int j = 0; j < ng; j++)
193 const int gs = group_lproc.
RowSize(g[j]);
206 for (
int nbr = 1; nbr < lproc_cgroup.
Size(); nbr++)
208 const int send_row = 2*(nbr-1);
209 const int recv_row = send_row+1;
210 const int ng = lproc_cgroup.
RowSize(nbr);
211 const int *g = lproc_cgroup.
GetRow(nbr);
212 for (
int j = 0; j < ng; j++)
214 const int gs = group_lproc.
RowSize(g[j]);
219 send_row, group_mgroupandproc.
GetRow(g[j]), gs+1);
230 send_requests = MPI_REQUEST_NULL;
231 recv_requests = MPI_REQUEST_NULL;
232 for (
int nbr = 1; nbr < lproc_cgroup.
Size(); nbr++)
234 const int send_row = 2*(nbr-1);
235 const int recv_row = send_row+1;
236 const int send_size = buffer.
RowSize(send_row);
237 const int recv_size = buffer.
RowSize(recv_row);
240 MPI_Isend(buffer.
GetRow(send_row), send_size, MPI_INT, lproc_proc[nbr],
241 mpitag, MyComm, &send_requests[nbr-1]);
245 MPI_Irecv(buffer.
GetRow(recv_row), recv_size, MPI_INT, lproc_proc[nbr],
246 mpitag, MyComm, &recv_requests[nbr-1]);
250 if (recv_requests.
Size() > 0)
254 while (MPI_Waitany(recv_requests.
Size(), recv_requests.
GetData(), &idx,
256 idx != MPI_UNDEFINED)
258 const int recv_size = buffer.
RowSize(2*idx+1);
259 const int *recv_buf = buffer.
GetRow(2*idx+1);
260 for (
int s = 0; s < recv_size; s += recv_buf[s]+2)
262 group.
Recreate(recv_buf[s], recv_buf+s+2);
263 const int g = groups.
Lookup(group);
264 MFEM_ASSERT(group_mgroup[g] == -1,
"communication error");
265 group_mgroup[g] = recv_buf[s+1];
270 MPI_Waitall(send_requests.
Size(), send_requests.
GetData(),
271 MPI_STATUSES_IGNORE);
278 os <<
"\ncommunication_groups\n";
279 os <<
"number_of_groups " <<
NGroups() <<
"\n\n";
281 os <<
"# number of entities in each group, followed by ranks in group\n";
282 for (
int group_id = 0; group_id <
NGroups(); ++group_id)
285 const int * group_ptr =
GetGroup(group_id);
287 for (
int group_member_index = 0; group_member_index < group_size;
288 ++group_member_index)
306 int number_of_groups = -1;
308 MFEM_VERIFY(ident ==
"number_of_groups",
309 "GroupTopology::Load - expected 'number_of_groups' entry.");
310 in >> number_of_groups;
316 for (
int group_id = 0; group_id < number_of_groups; ++group_id)
322 array.Reserve(group_size);
329 integer_sets.
Insert(integer_set);
332 Create(integer_sets, 823);
337 copy.SetComm(MyComm);
338 group_lproc.
Copy(copy.group_lproc);
339 groupmaster_lproc.
Copy(copy.groupmaster_lproc);
340 lproc_proc.
Copy(copy.lproc_proc);
341 group_mgroup.
Copy(copy.group_mgroup);
348 mfem::Swap(groupmaster_lproc, other.groupmaster_lproc);
366 MPI_UNSIGNED_LONG_LONG;
389 "the GroupCommunicator is already Finalized!");
392 for (
int i = 0; i < ldof_group.
Size(); i++)
394 int group = ldof_group[i];
402 for (
int i = 0; i < ldof_group.
Size(); i++)
404 int group = ldof_group[i];
419 int request_counter = 0;
438 request_counter += gr_requests;
443 requests =
new MPI_Request[request_counter];
453 if (nldofs == 0) {
continue; }
463 for (
int i = 0; i < grp_size; i++)
465 if (grp_nbr_list[i] != 0)
477 if (nldofs == 0) {
continue; }
487 for (
int i = 0; i < grp_size; i++)
489 if (grp_nbr_list[i] != 0)
508 if (num_recv_groups > 0)
511 group_ids.
SetSize(num_recv_groups);
512 for (
int i = 0; i < num_recv_groups; i++)
515 group_ids[i].two = grp_list[i];
518 for (
int i = 0; i < num_recv_groups; i++)
520 grp_list[i] = group_ids[i].two;
529 "SetLTDofTable() should be called at most once!");
546 for (
int i = 0; i < nldofs; i++)
555 const int ltdof_size = (
ldof_size == 0) ? 0 :
556 std::max(ldof_ltdof.
Max() + 1, 0);
559 int ltdof_counter = 0;
562 for (
int ldof = 0; ldof < ldof_ltdof.
Size(); ldof++)
564 const int ltdof = ldof_ltdof[ldof];
570 MFEM_ASSERT(
ltdof_ldof[ltdof] == -1,
"repeated ltdof indices found!");
574 MFEM_ASSERT(ltdof_counter == ltdof_size,
"unassigned ltdof indices found!");
581static void BuildNeighborDofTable(
const Table &group_dof,
582 const Table &nbr_groups,
586 for (
int nbr = 1; nbr < nbr_groups.
Size(); nbr++)
588 const int num_groups = nbr_groups.
RowSize(nbr);
589 if (num_groups == 0) {
continue; }
590 const int *grp_list = nbr_groups.
GetRow(nbr);
591 for (
int i = 0; i < num_groups; i++)
593 const int group = grp_list[i];
594 const int ndofs = group_dof.
RowSize(group);
599 for (
int nbr = 1; nbr < nbr_groups.
Size(); nbr++)
601 const int num_groups = nbr_groups.
RowSize(nbr);
602 if (num_groups == 0) {
continue; }
603 const int *grp_list = nbr_groups.
GetRow(nbr);
604 for (
int i = 0; i < num_groups; i++)
606 const int group = grp_list[i];
607 const int ndofs = group_dof.
RowSize(group);
608 const int *dofs = group_dof.
GetRow(group);
654 for (
int j = 0; j < nltdofs; j++)
656 buf[j] = ldata[ltdofs[j]];
658 return buf + nltdofs;
664 for (
int j = 0; j < nldofs; j++)
666 buf[j] = ldata[ldofs[j]];
675 int group,
int layout)
const
688 for (
int j = 0; j < nldofs; j++)
690 ldata[ltdofs[j]] = buf[j];
697 for (
int j = 0; j < nldofs; j++)
699 ldata[ldofs[j]] = buf[j];
709 int group,
int layout,
716 opd.
buf =
const_cast<T*
>(buf);
722 MFEM_ABORT(
"layout 1 is not supported");
724 for (
int j = 0; j < opd.
nldofs; j++)
749 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
750 MFEM_ASSERT(0 <= layout && layout <= 2,
"invalid layout: " << layout);
758 int request_counter = 0;
769 "'group_ltdof' is not set, use SetLTDofTable()");
781 if (nldofs == 0) {
continue; }
803 for (
int i = 0; i < gs; i++)
831 if (num_send_groups > 0)
838 for (
int i = 0; i < num_send_groups; i++)
854 if (num_recv_groups > 0)
862 for (
int i = 0; i < num_recv_groups; i++)
891 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
892 MFEM_ASSERT(0 <= layout && layout <= 2,
"invalid layout: " << layout);
924 else if (layout == 2)
948 MFEM_VERIFY(
comm_lock == 1,
"object is NOT locked for Bcast");
949 MFEM_ASSERT(layout == 0 || layout == 1,
"invalid layout: " << layout);
965 else if (layout == 0)
970 idx != MPI_UNDEFINED)
973 if (gr == -1) {
continue; }
988 idx != MPI_UNDEFINED)
991 if (nbr == -1) {
continue; }
994 if (num_recv_groups > 0)
998 for (
int i = 0; i < num_recv_groups; i++)
1015 MFEM_VERIFY(
comm_lock == 1,
"object is NOT locked for Bcast");
1016 MFEM_ASSERT(layout == 0 || layout == 1,
"invalid layout: " << layout);
1056 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
1067 int request_counter = 0;
1078 if (nldofs == 0) {
continue; }
1082 const int layout = 0;
1100 for (
int i = 0; i < gs; i++)
1127 if (num_send_groups > 0)
1131 for (
int i = 0; i < num_send_groups; i++)
1133 const int layout = 0;
1136 MPI_Isend(buf_start,
1149 if (num_recv_groups > 0)
1153 for (
int i = 0; i < num_recv_groups; i++)
1179template <
typename T>
1180static inline bool OpIsSupportedDeviceOp(
1188 const OpFunc sum_op = &GroupCommunicator::template Sum<T>;
1189 const OpFunc min_op = &GroupCommunicator::template Min<T>;
1190 const OpFunc max_op = &GroupCommunicator::template Max<T>;
1195 else if (Op == min_op)
1199 else if (Op == max_op)
1214 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
1242 if (Op ==
nullptr || OpIsSupportedDeviceOp(Op, device_op))
1265 MFEM_VERIFY(
comm_lock == 2,
"object is NOT locked for Reduce");
1266 MFEM_ASSERT(layout == 0 || layout == 2,
"invalid layout: " << layout);
1288 idx != MPI_UNDEFINED)
1291 if (gr == -1) {
continue; }
1295 if ((--group_num_req[gr]) != 0) {
continue; }
1301 opd.
ldofs = (layout == 0) ?
1317 if (num_recv_groups > 0)
1321 for (
int i = 0; i < num_recv_groups; i++)
1340 MFEM_VERIFY(
comm_lock == 2,
"object is NOT locked for Reduce");
1341 MFEM_ASSERT(layout == 0 || layout == 2,
"invalid layout: " << layout);
1367 MFEM_VERIFY(BeginOp ==
nullptr || BeginOp == Op,
1368 "the reduction operations given to ReduceBegin() and "
1369 "ReduceEnd() do not match!");
1371 const bool op_is_supported_device_op =
1372 OpIsSupportedDeviceOp(Op, device_op);
1377 const bool reduce_began_on_device =
1378 (BeginOp ==
nullptr) || op_is_supported_device_op;
1379 if (reduce_began_on_device)
1381 MFEM_VERIFY(op_is_supported_device_op,
1382 "the reduce operation 'Op' is not supported on device!"
1383 "\n\tTo resolve this error, provide 'Op' to ReduceBegin() "
1384 "in the second argument.");
1410 MFEM_VERIFY(
comm_lock == 2,
"object is NOT locked for Reduce");
1426 idx != MPI_UNDEFINED)
1429 if (gr == -1) {
continue; }
1433 if ((--group_num_req[gr]) != 0) {
continue; }
1439 opd.
ldofs = (layout == 0) ?
1449 for (
int i = 0; i < opd.
nldofs; i++)
1451 if (marker[opd.
ldofs[i]])
1453 for (
int j = 0; j < opd.
nb; j++)
1455 single_buf[j] = opd.
buf[j*opd.
nldofs + i];
1460 single_opd.
ldata = ldata;
1464 single_opd.
nb = opd.
nb;
1482 if (num_recv_groups > 0)
1486 for (
int i = 0; i < num_recv_groups; i++)
1489 int gr = grp_list[i];
1490 const int *ldofs = (layout == 0) ?
1494 for (
int j = 0; j < nldofs; j++)
1496 if (marker[ldofs[j]])
1501 opd.
buf =
const_cast<T*
>(buf) + j;
1502 opd.
ldofs = ldofs + j;
1528 for (
int i = 0; i < opd.
nldofs; i++)
1535 for (
int i = 0; i < opd.
nldofs; i++)
1538 for (
int j = 0; j < opd.
nb; j++)
1550 for (
int i = 0; i < opd.
nldofs; i++)
1553 for (
int j = 0; j < opd.
nb; j++)
1568 for (
int i = 0; i < opd.
nldofs; i++)
1571 for (
int j = 0; j < opd.
nb; j++)
1586 static_assert(std::is_integral<T>::value,
1587 "BitOR reduction requires an integral type.");
1588 for (
int i = 0; i < opd.
nldofs; i++)
1591 for (
int j = 0; j < opd.
nb; j++)
1602 for (
int i = 0; i < opd.
nldofs; i++)
1605 T abs_data = std::abs(data);
1607 for (
int j = 0; j < opd.
nb; j++)
1610 T abs_b = std::abs(
b);
1614 if (abs_data < abs_b || (abs_data == abs_b && data <
b))
1629 const int tag = 46800;
1632 int num_sends = 0, num_recvs = 0;
1633 size_t mem_sends = 0, mem_recvs = 0;
1634 int num_master_groups = 0, num_empty_groups = 0;
1635 int num_active_neighbors = 0;
1651 num_master_groups++;
1656 mem_recvs +=
sizeof(double)*nldofs;
1672 num_master_groups++;
1678 if (num_send_groups > 0)
1681 for (
int i = 0; i < num_send_groups; i++)
1689 if (num_recv_groups > 0)
1692 for (
int i = 0; i < num_recv_groups; i++)
1698 if (num_send_groups > 0 || num_recv_groups > 0)
1700 num_active_neighbors++;
1707 MPI_Recv(&c, 1, MPI_CHAR, myid-1, tag,
gtopo.
GetComm(),
1712 os <<
"\nGroupCommunicator:\n";
1714 os <<
"Rank " << myid <<
":\n"
1716 (
mode ==
byGroup ?
"byGroup" :
"byNeighbor") <<
"\n"
1717 " number of sends = " << num_sends <<
1718 " (" << mem_sends <<
" bytes)\n"
1719 " number of recvs = " << num_recvs <<
1720 " (" << mem_recvs <<
" bytes)\n";
1723 num_master_groups <<
" + " <<
1725 num_empty_groups <<
" (master + slave + empty)\n";
1730 num_active_neighbors <<
" + " <<
1732 " (active + inactive)\n";
1737 MPI_Send(&c, 1, MPI_CHAR, myid+1, tag,
gtopo.
GetComm());
1761template <
typename T>
1762static void ExtractSubArray(
const Array<int> &indices,
1766 MFEM_ASSERT(indices.
Size() == xout.
Size(),
"incompatible sizes!");
1767 auto y = xout.
Write();
1768 const auto x = xin.
Read();
1769 const auto I = indices.
Read();
1779template <
typename T>
1780static void SetSubArray(
const Array<int> &indices,
1781 const Array<T> &xin,
1784 MFEM_ASSERT(indices.Size() == xin.Size(),
"incompatible sizes!");
1786 auto y = xout.ReadWrite();
1787 const auto x = xin.Read();
1788 const auto I = indices.Read();
1789 mfem::forall(indices.Size(), [=] MFEM_HOST_DEVICE (
int i)
1799template <
typename T>
1800static void SetSubArray(
const Array<int> &indices, Array<T> &xout, T val)
1803 auto y = xout.ReadWrite();
1804 const auto I = indices.Read();
1805 mfem::forall(indices.Size(), [=] MFEM_HOST_DEVICE (
int i)
1816template <
typename T>
1817static void BooleanAddMult(
const Array<int> &unique_dst_indices,
1818 const Array<int> &unique_to_src_offsets,
1819 const Array<int> &unique_to_src_indices,
1820 const Array<T> &src,
1823 auto y = dst.ReadWrite();
1824 const auto x = src.Read();
1825 const auto DST_I = unique_dst_indices.Read();
1826 const auto SRC_O = unique_to_src_offsets.Read();
1827 const auto SRC_I = unique_to_src_indices.Read();
1828 mfem::forall(unique_dst_indices.Size(), [=] MFEM_HOST_DEVICE (
int i)
1830 const int dst_idx = DST_I[i];
1832 const int end = SRC_O[i+1];
1833 for (
int j = SRC_O[i]; j != end; ++j) { sum += x[SRC_I[j]]; }
1845template <
typename T>
1846static void BooleanReduceApply(
const Array<int> &unique_dst_indices,
1847 const Array<int> &unique_to_src_offsets,
1848 const Array<int> &unique_to_src_indices,
1849 const Array<T> &src,
1853 auto y = dst.ReadWrite();
1854 const auto x = src.Read();
1855 const auto DST_I = unique_dst_indices.Read();
1856 const auto SRC_O = unique_to_src_offsets.Read();
1857 const auto SRC_I = unique_to_src_indices.Read();
1858 mfem::forall(unique_dst_indices.Size(), [=] MFEM_HOST_DEVICE (
int i)
1860 const int dst_idx = DST_I[i];
1862 const int end = SRC_O[i+1];
1866 for (
int j = SRC_O[i]; j != end; ++j) { val += x[SRC_I[j]]; }
1869 for (
int j = SRC_O[i]; j != end; ++j)
1871 const T xj = x[SRC_I[j]];
1872 val = (xj < val) ? xj : val;
1876 for (
int j = SRC_O[i]; j != end; ++j)
1878 const T xj = x[SRC_I[j]];
1879 val = (xj > val) ? xj : val;
1894 "Device group-communicator requires neighbor mode.");
1896 "The GroupCommunicator method SetLTDofTable() must be called "
1897 "before constructing the DeviceGroupCommunicator!");
1904 nbr_ltdof.
Size()+1,
true);
1916 unique_ltdof.
Sort();
1922 for (
int i = 0; i < shr_unique.
Size(); i++)
1925 MFEM_ASSERT(shr_unique[i] != -1,
"internal error");
1932 unique_shr.
Size()+1,
true);
1946 nbr_ldof.
Size()+1,
true);
1959 int req_counter = 0;
1964 if (send_size > 0) { req_counter++; }
1968 if (recv_size > 0) { req_counter++; }
1974template <
typename T>
1983template <
typename T>
1992template <
typename T>
2000template <
typename T>
2009template <
typename T>
2017template <
typename T>
2026 shr_buf_t.
view, x_ldof);
2031 shr_buf_t.
view, x_ldof, op);
2035template <
typename T>
2043template <
typename T>
2058template <
typename T>
2074template <
typename T>
2079 internal::ExtractSubArray(
gc.
ltdof_ldof, x_ldof, x_tdof);
2082template <
typename T>
2087 internal::SetSubArray(
ext_ldof, x_ldof, T(0));
2090template <
typename T>
2099 auto send_ptr = mpi_gpu_aware ? send_buf.
Read() : send_buf.
HostRead();
2100 auto recv_ptr = mpi_gpu_aware ? recv_buf.
Write() : recv_buf.
HostWrite();
2104 const int send_offset = send_offsets[nbr];
2105 const int send_size = send_offsets[nbr+1] - send_offset;
2112 const int recv_offset = recv_offsets[nbr];
2113 const int recv_size = recv_offsets[nbr+1] - recv_offset;
2123template <
typename T>
2127 const int tag = 41822;
2131template <
typename T>
2135 const int tag = 41823;
2139template <
typename T>
2144 internal::ExtractSubArray(
ext_ldof, x_ldof, ext_buf_t);
2148template <
typename T>
2162 shr_buf_t, x_tdof, op);
2166template <
typename T>
2171 internal::ExtractSubArray(
shr_ltdof, x_tdof, shr_buf_t);
2175template <
typename T>
2180 internal::ExtractSubArray(
shr_ldof, x_ldof, shr_buf_t);
2184template <
typename T>
2189 internal::SetSubArray(
ext_ldof, ext_buf_t, x_ldof);
2206 const Array<int> &,
void (*)(OpData<int>))
const;
2208 int *,
int,
void (*)(OpData<int>))
const;
2210 Array<int> &,
int,
void (*)(OpData<int>))
const;
2212 int*,
const Array<int>&,
int,
void (*)(OpData<int>))
const;
2222 double *,
int,
void (*)(OpData<double>))
const;
2226 double*,
const Array<int>&,
int,
void (*)(OpData<double>))
const;
2236 float *,
int,
void (*)(OpData<float>))
const;
2240 float*,
const Array<int>&,
int,
void (*)(OpData<float>))
const;
2311static void DebugRankCoords(
int** coords,
int dim,
int size)
2313 for (
int i = 0; i < size; i++)
2315 mfem::out <<
"Rank " << i <<
" coords: ";
2316 for (
int j = 0; j <
dim; j++)
2326 CompareCoords(
int coord) : coord(coord) {}
2329 bool operator()(
int*
const &
a,
int*
const &
b)
const
2330 {
return a[coord] <
b[coord]; }
2337 bool all_same =
true;
2338 for (
int i = 1; i < size && all_same; i++)
2340 for (
int j = 0; j <
dim; j++)
2342 if (coords[i][j] != coords[0][j]) { all_same =
false;
break; }
2345 if (all_same) {
return; }
2348 std::sort(coords, coords + size, CompareCoords(d));
2349 int next = (d + 1) %
dim;
2351 if (coords[0][d] < coords[size-1][d])
2369 MPI_Comm_rank(comm, &rank);
2370 MPI_Comm_size(comm, &size);
2373 MPIX_Torus_ndims(&
dim);
2375 int* mycoords =
new int[
dim + 1];
2376 MPIX_Rank2torus(rank, mycoords);
2378 MPI_Send(mycoords,
dim, MPI_INT, 0, 111, comm);
2383 int** coords =
new int*[size];
2384 for (
int i = 0; i < size; i++)
2386 coords[i] =
new int[
dim + 1];
2388 MPI_Recv(coords[i],
dim, MPI_INT, i, 111, comm, &status);
2395 for (
int i = 0; i < size; i++)
2397 MPI_Send(&coords[i][
dim], 1, MPI_INT, i, 112, comm);
2398 delete [] coords[i];
2404 MPI_Recv(&new_rank, 1, MPI_INT, 0, 112, comm, &status);
2407 MPI_Comm_split(comm, 0, new_rank, &new_comm);
Memory< T > & GetMemory()
Return a reference to the Memory object used by the Array.
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
int FindSorted(const T &el) const
Do bisection search for 'el' in a sorted array; return -1 if not found.
const T * HostRead() const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), false).
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
void CopyFrom(const U *src)
Copy from src into this array. Copies enough entries to fill the Capacity size of this array....
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
int Size() const
Return the logical size of the array.
T * Write(bool on_dev=true)
Shortcut for mfem::Write(a.GetMemory(), a.Size(), on_dev).
int Append(const T &el)
Append element 'el' to array, resize if necessary.
void UseDevice(bool use_dev) const
Set the device flag of the Array, i.e. the device flag of the Memory object used by the Array.
T * GetData()
Returns the data.
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T.
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
void NewMemoryAndSize(const Memory< T > &mem, int s, bool own_mem)
Reset the Array to use the given external Memory mem and size s.
T * HostWrite()
Shortcut for mfem::Write(a.GetMemory(), a.Size(), false).
Auxiliary class used by class GroupCommunicator implementing its device (GPU) code paths for data pas...
Array< buffer_max_type > ext_buf
void RestrictTranspose(const Array< T > &x_tdof, Array< T > &x_ldof) const
Transpose of Restrict(): copy the true-dof data x_tdof into the owned local dofs of x_ldof and set th...
void Restrict(const Array< T > &x_ldof, Array< T > &x_tdof) const
Kernel: copy owned ldofs from x_ldof to ltdofs in x_tdof, i.e. x_tdof[i] = x_ldof[ltdof_ldof[i]].
Array< int > shr_buf_offsets
void BcastEndCopy(const Array< T > &ext_buf_t, Array< T > &x_ldof) const
void CopyTDofsToLDofs(const Array< T > &x_tdof, Array< T > &x_ldof) const
Kernel: copy ltdofs from x_tdof to ldofs in x_ldof, i.e. x_ldof[ltdof_ldof[i]] = x_tdof[i].
void ReduceEndLDofs(Array< T > &x_ldof, Op op) const
Finalize a group reduction into the local-dof data x_ldof, applying the reduction operation op.
void BcastBeginTDofs(Array< T > &x_tdof) const
Begin a group broadcast of the true-dof data x_tdof.
const GroupCommunicator & gc
void ProlongateTranspose(const Array< T > &x_ldof, Array< T > &x_tdof, Op op=Op::Sum) const
Transpose of Prolongate(): reduce the local-dof data x_ldof into the true-dof data x_tdof,...
Array< int > ext_buf_offsets
void ReduceEndAssembleTDofs(const Array< T > &shr_buf_t, Array< T > &x_tdof, Op op) const
Array< buffer_max_type > shr_buf
void BcastBeginCopyTDofs(const Array< T > &x_tdof, Array< T > &shr_buf_t) const
void ReduceEndTDofs(Array< T > &x_tdof, Op op) const
Finalize a group reduction into the true-dof data x_tdof, applying the reduction operation op.
void ReduceBeginLDofs(const Array< T > &x_ldof) const
Begin a group reduction of the local-dof data x_ldof.
void ExchangeSharedToExternal(const Array< T > &shr_buf, Array< T > &ext_buf) const
Op
Reduction operation applied at the receiving dofs.
void BcastBeginLDofs(Array< T > &x_ldof) const
Begin a group broadcast of the local-dof data x_ldof.
void ReduceBeginCopy(const Array< T > &x_ldof, Array< T > &ext_buf_t) const
DeviceGroupCommunicator(const GroupCommunicator &gc_)
Construct a device communicator based on the GroupCommunicator gc_.
void BcastEndLDofs(Array< T > &x_ldof) const
Finalize a group broadcast into the local-dof data x_ldof.
void BcastBeginCopyLDofs(const Array< T > &x_ldof, Array< T > &shr_buf_t) const
Array< MPI_Request > requests
void ExchangeExternalToShared(const Array< T > &ext_buf, Array< T > &shr_buf) const
void Prolongate(const Array< T > &x_tdof, Array< T > &x_ldof) const
Prolongate the true-dof data x_tdof to the local-dof data x_ldof.
void Exchange(const Array< T > &send_buf, const Array< int > &send_offsets, Array< T > &recv_buf, const Array< int > &recv_offsets, int tag) const
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
static bool GetGPUAwareMPI()
Get the status of GPU-aware MPI flag.
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
GroupCommunicator(const GroupTopology >, Mode m=byNeighbor)
Construct a GroupCommunicator object.
DeviceGroupCommunicator * device_gc
void GetNeighborLTDofTable(Table &nbr_ltdof) const
Dofs to be sent (during Bcast) to communication neighbors.
@ byGroup
Communications are performed one group at a time.
void GetNeighborLDofTable(Table &nbr_ldof) const
Dofs to be received (during Bcast) from communication neighbors.
const T * ReduceGroupFromBuffer(const T *buf, T *ldata, int group, int layout, void(*Op)(OpData< T >)) const
Perform the reduction operation Op to the entries of group group using the values from the buffer buf...
void ReduceMarked(T *ldata, const Array< int > &marker, int layout, void(*Op)(OpData< T >)) const
Finalize reduction operation started with ReduceBegin(), but only apply the reduction to DOFs marked ...
static void MaxAbs(OpData< T >)
void ReduceEnd(T *ldata, int layout, void(*Op)(OpData< T >)) const
Finalize reduction operation started with the host version of ReduceBegin().
const GroupTopology & GetGroupTopology() const
Get a const reference to the associated GroupTopology object.
const GroupTopology & gtopo
T * CopyGroupToBuffer(const T *ldata, T *buf, int group, int layout) const
Copy the entries corresponding to the group group from the local array ldata to the buffer buf.
const T * CopyGroupFromBuffer(const T *buf, T *ldata, int group, int layout) const
Copy the entries corresponding to the group group from the buffer buf to the local array ldata.
void BcastEnd(T *ldata, int layout) const
Finalize a broadcast started with the host version of BcastBegin().
void ReduceBegin(const T *ldata) const
Begin reduction operation within each group where the master is the root, host version.
void Create(const Array< int > &ldof_group)
Initialize the communicator from a local-dof to group map. Finalize() is called internally.
~GroupCommunicator()
Destroy a GroupCommunicator object, deallocating internal data structures and buffers.
friend class DeviceGroupCommunicator
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int, double and float.
void SetLTDofTable(const Array< int > &ldof_ltdof)
Initialize the internal group_ltdof Table.
static void BitOR(OpData< T >)
Reduce operation bitwise OR, instantiated for int only.
static void Max(OpData< T >)
Reduce operation Max, instantiated for int, double and float.
static void Min(OpData< T >)
Reduce operation Min, instantiated for int, double and float.
void BcastBegin(T *ldata, int layout) const
Begin a broadcast within each group where the master is the root, host version.
void Finalize()
Allocate internal buffers after the GroupLDofTable is defined.
void PrintInfo(std::ostream &out=mfem::out) const
Print information about the GroupCommunicator from all MPI ranks.
const DeviceGroupCommunicator & GetDeviceComm() const
Return the device communicator, 'device_gc', constructing it if it was not already constructed.
int GetNeighborRank(int i) const
Return the MPI rank of neighbor 'i'.
int NRanks() const
Return the number of MPI ranks within this object's communicator.
bool IAmMaster(int g) const
Return true if I am master for group 'g'.
void Swap(GroupTopology &other)
Swap the internal data with another GroupTopology object.
void Save(std::ostream &out) const
Save the data in a stream.
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor.
int MyRank() const
Return the MPI rank within this object's communicator.
int GetGroupSize(int g) const
Get the number of processors in a group.
int GetGroupMaster(int g) const
Return the neighbor index of the group master for a given group. Neighbor 0 is the local processor.
void Load(std::istream &in)
Load the data from a stream.
GroupTopology()
Constructor with the MPI communicator = 0.
int GetGroupMasterRank(int g) const
Return the rank of the group master for group 'g'.
void Create(ListOfIntegerSets &groups, int mpitag)
Set up the group topology given the list of sets of shared entities.
MPI_Comm GetComm() const
Return the MPI communicator.
void Copy(GroupTopology ©) const
Copy the internal data to the external 'copy'.
int GetNumNeighbors() const
Return the number of neighbors including the local processor.
int NGroups() const
Return the number of groups.
int GetGroupMasterGroup(int g) const
Return the group number in the master for group 'g'.
void Recreate(const int n, const int *p)
Create an integer set from C-array 'p' of 'n' integers. Overwrites any existing set data.
int Insert(const IntegerSet &s)
Check to see if set 's' is in the list. If not append it to the end of the list. Returns the index of...
void AsTable(Table &t) const
Write the list of sets into table 't'.
int PickElementInSet(int i) const
Return the value of the first element of the ith set.
int Lookup(const IntegerSet &s) const
bool UseDevice() const
Read the internal device flag.
static MFEM_EXPORT int default_thread_required
Default level of thread support for MPI_Init_thread.
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
void LoseData()
Releases ownership of and null-ifies the data.
void AddConnections(int r, const int *c, int nc)
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
void AddConnection(int r, int c)
int Size() const
Returns the number of TYPE I elements.
int Size_of_connections() const
Returns the number of connections in the table.
void AddColumnsInRow(int r, int ncol)
void MakeFromList(int nrows, const Array< Connection > &list)
Create the table from a list of connections {(from, to)}, where 'from' is a TYPE I index and 'to' is ...
void Copy(Table ©) const
Memory< int > & GetJMemory()
void AddAColumnInRow(int r)
void SetDims(int rows, int nnz)
Set the rows and the number of all connections for the table.
Memory< int > & GetIMemory()
int index(int i, int j, int nx, int ny)
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
void KdTreeSort(int **coords, int d, int dim, int size)
MPI_Comm ReorderRanksZCurve(MPI_Comm comm)
void forall(int N, lambda &&body)
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
real_t p(const Vector &x, real_t t)
@ DEVICE_MASK
Biwise-OR of all device backends.
Helper struct for defining a connectivity table, see Table::MakeFromList.
Data structure on which we define reduce operations. The data is associated with (and the operation i...
Helper struct to convert a C++ type to an MPI type.