12 #include "../config/config.hpp"
37 void MPI_Session::GetRankAndSize()
39 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
40 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
46 group_lproc(gt.group_lproc)
48 gt.groupmaster_lproc.
Copy(groupmaster_lproc);
49 gt.lproc_proc.
Copy(lproc_proc);
50 gt.group_mgroup.
Copy(group_mgroup);
53 void GroupTopology::ProcToLProc()
56 MPI_Comm_size(MyComm, &NRanks);
58 map<int, int> proc_lproc;
63 int lproc_counter = 0;
66 const pair<const int, int>
p(group_lproc.
GetJ()[i], lproc_counter);
67 if (proc_lproc.insert(
p).second)
74 lproc_proc.
SetSize(lproc_counter);
75 for (map<int, int>::iterator it = proc_lproc.begin();
76 it != proc_lproc.end(); ++it)
78 lproc_proc[it->second] = it->first;
83 group_lproc.
GetJ()[i] = proc_lproc[group_lproc.
GetJ()[i]];
86 for (
int i = 0; i <
NGroups(); i++)
88 groupmaster_lproc[i] = proc_lproc[groupmaster_lproc[i]];
96 Table group_mgroupandproc;
99 for (
int i = 0; i <
NGroups(); i++)
101 int j = group_mgroupandproc.
GetI()[i];
102 group_mgroupandproc.
GetI()[i+1] = j + group_lproc.
RowSize(i) + 1;
103 group_mgroupandproc.
GetJ()[j] = i;
105 for (
int k = group_lproc.
GetI()[i];
106 j < group_mgroupandproc.
GetI()[i+1]; j++, k++)
108 group_mgroupandproc.
GetJ()[j] = group_lproc.
GetJ()[k];
116 for (
int i = 0; i <
NGroups(); i++)
134 MFEM_DEBUG_DO(group_mgroup = -1);
135 for (
int g = 0; g <
NGroups(); g++)
137 if (
IAmMaster(g)) { group_mgroup[g] = g; }
145 for (
int g = 1; g <
NGroups(); g++)
151 for (
int i = 0; i < gs; i++)
164 lproc_cgroup_list.
Sort();
165 lproc_cgroup_list.
Unique();
177 for (
int nbr = 1; nbr < lproc_cgroup.
Size(); nbr++)
179 const int send_row = 2*(nbr-1);
180 const int recv_row = send_row+1;
181 const int ng = lproc_cgroup.
RowSize(nbr);
182 const int *g = lproc_cgroup.
GetRow(nbr);
183 for (
int j = 0; j < ng; j++)
185 const int gs = group_lproc.
RowSize(g[j]);
198 for (
int nbr = 1; nbr < lproc_cgroup.
Size(); nbr++)
200 const int send_row = 2*(nbr-1);
201 const int recv_row = send_row+1;
202 const int ng = lproc_cgroup.
RowSize(nbr);
203 const int *g = lproc_cgroup.
GetRow(nbr);
204 for (
int j = 0; j < ng; j++)
206 const int gs = group_lproc.
RowSize(g[j]);
211 send_row, group_mgroupandproc.
GetRow(g[j]), gs+1);
222 send_requests = MPI_REQUEST_NULL;
223 recv_requests = MPI_REQUEST_NULL;
224 for (
int nbr = 1; nbr < lproc_cgroup.
Size(); nbr++)
226 const int send_row = 2*(nbr-1);
227 const int recv_row = send_row+1;
228 const int send_size = buffer.
RowSize(send_row);
229 const int recv_size = buffer.
RowSize(recv_row);
232 MPI_Isend(buffer.
GetRow(send_row), send_size, MPI_INT, lproc_proc[nbr],
233 mpitag, MyComm, &send_requests[nbr-1]);
237 MPI_Irecv(buffer.
GetRow(recv_row), recv_size, MPI_INT, lproc_proc[nbr],
238 mpitag, MyComm, &recv_requests[nbr-1]);
242 if (recv_requests.Size() > 0)
246 while (MPI_Waitany(recv_requests.Size(), recv_requests.GetData(), &idx,
248 idx != MPI_UNDEFINED)
250 const int recv_size = buffer.
RowSize(2*idx+1);
251 const int *recv_buf = buffer.
GetRow(2*idx+1);
252 for (
int s = 0;
s < recv_size;
s += recv_buf[
s]+2)
254 group.
Recreate(recv_buf[
s], recv_buf+s+2);
255 const int g = groups.
Lookup(group);
256 MFEM_ASSERT(group_mgroup[g] == -1,
"communication error");
257 group_mgroup[g] = recv_buf[s+1];
262 MPI_Waitall(send_requests.
Size(), send_requests.
GetData(),
263 MPI_STATUSES_IGNORE);
270 out <<
"\ncommunication_groups\n";
271 out <<
"number_of_groups " <<
NGroups() <<
"\n\n";
273 out <<
"# number of entities in each group, followed by group ids in group\n";
274 for (
int group_id = 0; group_id <
NGroups(); ++group_id)
277 const int * group_ptr =
GetGroup(group_id);
279 for (
int group_member_index = 0; group_member_index < group_size;
280 ++group_member_index)
298 int number_of_groups = -1;
300 MFEM_VERIFY(ident ==
"number_of_groups",
301 "GroupTopology::Load - expected 'number_of_groups' entry.");
302 in >> number_of_groups;
308 for (
int group_id = 0; group_id < number_of_groups; ++group_id)
321 integer_sets.
Insert(integer_set);
324 Create(integer_sets, 823);
330 group_lproc.
Copy(copy.group_lproc);
331 groupmaster_lproc.
Copy(copy.groupmaster_lproc);
332 lproc_proc.
Copy(copy.lproc_proc);
333 group_mgroup.
Copy(copy.group_mgroup);
340 mfem::Swap(groupmaster_lproc, other.groupmaster_lproc);
365 for (
int i = 0; i < ldof_group.
Size(); i++)
367 int group = ldof_group[i];
375 for (
int i = 0; i < ldof_group.
Size(); i++)
377 int group = ldof_group[i];
390 int request_counter = 0;
409 request_counter += gr_requests;
414 requests =
new MPI_Request[request_counter];
424 if (nldofs == 0) {
continue; }
434 for (
int i = 0; i < grp_size; i++)
436 if (grp_nbr_list[i] != 0)
448 if (nldofs == 0) {
continue; }
458 for (
int i = 0; i < grp_size; i++)
460 if (grp_nbr_list[i] != 0)
479 if (num_recv_groups > 0)
482 group_ids.
SetSize(num_recv_groups);
483 for (
int i = 0; i < num_recv_groups; i++)
486 group_ids[i].two = grp_list[i];
489 for (
int i = 0; i < num_recv_groups; i++)
491 grp_list[i] = group_ids[i].two;
516 for (
int i = 0; i < nldofs; i++)
531 if (num_send_groups > 0)
534 for (
int i = 0; i < num_send_groups; i++)
536 const int group = grp_list[i];
546 if (num_send_groups > 0)
549 for (
int i = 0; i < num_send_groups; i++)
551 const int group = grp_list[i];
567 if (num_recv_groups > 0)
570 for (
int i = 0; i < num_recv_groups; i++)
572 const int group = grp_list[i];
582 if (num_recv_groups > 0)
585 for (
int i = 0; i < num_recv_groups; i++)
587 const int group = grp_list[i];
613 for (
int j = 0; j < nltdofs; j++)
615 buf[j] = ldata[ltdofs[j]];
617 return buf + nltdofs;
623 for (
int j = 0; j < nldofs; j++)
625 buf[j] = ldata[ldofs[j]];
634 int group,
int layout)
const
647 for (
int j = 0; j < nldofs; j++)
649 ldata[ltdofs[j]] = buf[j];
656 for (
int j = 0; j < nldofs; j++)
658 ldata[ldofs[j]] = buf[j];
668 int group,
int layout,
675 opd.
buf =
const_cast<T*
>(buf);
681 MFEM_ABORT(
"layout 1 is not supported");
683 for (
int j = 0; j < opd.
nldofs; j++)
708 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
712 int request_counter = 0;
723 "'group_ltdof' is not set, use SetLTDofTable()");
735 if (nldofs == 0) {
continue; }
757 for (
int i = 0; i < gs; i++)
785 if (num_send_groups > 0)
792 for (
int i = 0; i < num_send_groups; i++)
808 if (num_recv_groups > 0)
816 for (
int i = 0; i < num_recv_groups; i++)
847 MFEM_VERIFY(
comm_lock == 1,
"object is NOT locked for Bcast");
857 else if (layout == 0)
862 idx != MPI_UNDEFINED)
865 if (gr == -1) {
continue; }
880 idx != MPI_UNDEFINED)
883 if (nbr == -1) {
continue; }
886 if (num_recv_groups > 0)
890 for (
int i = 0; i < num_recv_groups; i++)
907 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
911 int request_counter = 0;
922 if (nldofs == 0) {
continue; }
926 const int layout = 0;
944 for (
int i = 0; i < gs; i++)
971 if (num_send_groups > 0)
975 for (
int i = 0; i < num_send_groups; i++)
977 const int layout = 0;
993 if (num_recv_groups > 0)
997 for (
int i = 0; i < num_recv_groups; i++)
1029 MFEM_VERIFY(
comm_lock == 2,
"object is NOT locked for Reduce");
1045 idx != MPI_UNDEFINED)
1048 if (gr == -1) {
continue; }
1052 if ((--group_num_req[gr]) != 0) {
continue; }
1058 opd.
ldofs = (layout == 0) ?
1074 if (num_recv_groups > 0)
1078 for (
int i = 0; i < num_recv_groups; i++)
1098 for (
int i = 0; i < opd.
nldofs; i++)
1105 for (
int i = 0; i < opd.
nldofs; i++)
1108 for (
int j = 0; j < opd.
nb; j++)
1120 for (
int i = 0; i < opd.
nldofs; i++)
1123 for (
int j = 0; j < opd.
nb; j++)
1138 for (
int i = 0; i < opd.
nldofs; i++)
1141 for (
int j = 0; j < opd.
nb; j++)
1156 for (
int i = 0; i < opd.
nldofs; i++)
1159 for (
int j = 0; j < opd.
nb; j++)
1170 const int tag = 46800;
1173 int num_sends = 0, num_recvs = 0;
1174 size_t mem_sends = 0, mem_recvs = 0;
1175 int num_master_groups = 0, num_empty_groups = 0;
1176 int num_active_neighbors = 0;
1192 num_master_groups++;
1197 mem_recvs +=
sizeof(double)*nldofs;
1213 num_master_groups++;
1219 if (num_send_groups > 0)
1222 for (
int i = 0; i < num_send_groups; i++)
1230 if (num_recv_groups > 0)
1233 for (
int i = 0; i < num_recv_groups; i++)
1239 if (num_send_groups > 0 || num_recv_groups > 0)
1241 num_active_neighbors++;
1248 MPI_Recv(&c, 1, MPI_CHAR, myid-1, tag,
gtopo.
GetComm(),
1253 out <<
"\nGroupCommunicator:\n";
1255 out <<
"Rank " << myid <<
":\n"
1257 (
mode ==
byGroup ?
"byGroup" :
"byNeighbor") <<
"\n"
1258 " number of sends = " << num_sends <<
1259 " (" << mem_sends <<
" bytes)\n"
1260 " number of recvs = " << num_recvs <<
1261 " (" << mem_recvs <<
" bytes)\n";
1264 num_master_groups <<
" + " <<
1266 num_empty_groups <<
" (master + slave + empty)\n";
1271 num_active_neighbors <<
" + " <<
1273 " (active + inactive)\n";
1278 MPI_Send(&c, 1, MPI_CHAR, myid+1, tag,
gtopo.
GetComm());
1298 template void GroupCommunicator::BcastBegin<int>(
int *, int)
const;
1299 template void GroupCommunicator::BcastEnd<int>(
int *, int)
const;
1300 template void GroupCommunicator::ReduceBegin<int>(
const int *)
const;
1301 template void GroupCommunicator::ReduceEnd<int>(
1302 int *, int, void (*)(OpData<int>))
const;
1304 template void GroupCommunicator::BcastBegin<double>(
double *, int)
const;
1305 template void GroupCommunicator::BcastEnd<double>(
double *, int)
const;
1306 template void GroupCommunicator::ReduceBegin<double>(
const double *)
const;
1307 template void GroupCommunicator::ReduceEnd<double>(
1308 double *, int, void (*)(OpData<double>))
const;
1313 template void GroupCommunicator::Sum<int>(OpData<int>);
1314 template void GroupCommunicator::Min<int>(OpData<int>);
1315 template void GroupCommunicator::Max<int>(OpData<int>);
1316 template void GroupCommunicator::BitOR<int>(OpData<int>);
1318 template void GroupCommunicator::Sum<double>(OpData<double>);
1319 template void GroupCommunicator::Min<double>(OpData<double>);
1320 template void GroupCommunicator::Max<double>(OpData<double>);
1324 static void DebugRankCoords(
int** coords,
int dim,
int size)
1326 for (
int i = 0; i < size; i++)
1328 mfem::out <<
"Rank " << i <<
" coords: ";
1329 for (
int j = 0; j <
dim; j++)
1337 struct CompareCoords
1339 CompareCoords(
int coord) : coord(coord) {}
1342 bool operator()(
int*
const &
a,
int*
const &
b)
const
1343 {
return a[coord] < b[coord]; }
1350 bool all_same =
true;
1351 for (
int i = 1; i < size && all_same; i++)
1353 for (
int j = 0; j <
dim; j++)
1355 if (coords[i][j] != coords[0][j]) { all_same =
false;
break; }
1358 if (all_same) {
return; }
1361 std::sort(coords, coords + size, CompareCoords(d));
1362 int next = (d + 1) % dim;
1364 if (coords[0][d] < coords[size-1][d])
1367 KdTreeSort(coords + size/2, next, dim, size - size/2);
1382 MPI_Comm_rank(comm, &rank);
1383 MPI_Comm_size(comm, &size);
1386 MPIX_Torus_ndims(&dim);
1388 int* mycoords =
new int[dim + 1];
1389 MPIX_Rank2torus(rank, mycoords);
1391 MPI_Send(mycoords, dim, MPI_INT, 0, 111, comm);
1396 int** coords =
new int*[size];
1397 for (
int i = 0; i < size; i++)
1399 coords[i] =
new int[dim + 1];
1401 MPI_Recv(coords[i], dim, MPI_INT, i, 111, comm, &status);
1408 for (
int i = 0; i < size; i++)
1410 MPI_Send(&coords[i][dim], 1, MPI_INT, i, 112, comm);
1411 delete [] coords[i];
1417 MPI_Recv(&new_rank, 1, MPI_INT, 0, 112, comm, &status);
1420 MPI_Comm_split(comm, 0, new_rank, &new_comm);
int Lookup(IntegerSet &s)
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.
void ReduceEnd(T *ldata, int layout, void(*Op)(OpData< T >)) const
Finalize reduction operation started with ReduceBegin().
int Size() const
Return the logical size of the array.
void GetNeighborLDofTable(Table &nbr_ldof) const
Dofs to be received from communication neighbors.
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 GetGroupMasterGroup(int g) const
Return the group number in the master for group 'g'.
void Unique()
Removes duplicities from a sorted array. This requires operator== to be defined for T...
void AsTable(Table &t)
Write the list of sets into table 't'.
Helper struct to convert a C++ type to an MPI type.
void GetNeighborLTDofTable(Table &nbr_ltdof) const
Dofs to be sent to communication neighbors.
MPI_Comm ReorderRanksZCurve(MPI_Comm comm)
void AddColumnsInRow(int r, int ncol)
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
int NRanks() const
Return the number of MPI ranks within this object's communicator.
void Create(const Array< int > &ldof_group)
Initialize the communicator from a local-dof to group map. Finalize() is called internally.
int GetGroupSize(int g) const
Get the number of processors in a group.
void SetDims(int rows, int nnz)
const int * GetGroup(int g) const
Return a pointer to a list of neighbors for a given group. Neighbor 0 is the local processor...
void Copy(Array ©) const
Create a copy of the internal array to the provided copy.
T * GetData()
Returns the data.
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
void Swap(GroupTopology &other)
Swap the internal data with another GroupTopology object.
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...
int Size_of_connections() const
void skip_comment_lines(std::istream &is, const char comment_char)
Check if the stream starts with comment_char. If so skip it.
void AddConnections(int r, const int *c, int nc)
int PickElementInSet(int i)
Return the value of the first element of the ith set.
void BcastEnd(T *ldata, int layout) const
Finalize a broadcast started with BcastBegin().
bool IAmMaster(int g) const
Return true if I am master for group 'g'.
void MakeFromList(int nrows, const Array< Connection > &list)
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int and double.
int Append(const T &el)
Append element 'el' to array, resize if necessary.
int GetNumNeighbors() const
Return the number of neighbors including the local processor.
int MyRank() const
Return the MPI rank within this object's communicator.
void Finalize()
Allocate internal buffers after the GroupLDofTable is defined.
MPI_Comm GetComm() const
Return the MPI communicator.
void AddConnection(int r, int c)
int Insert(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 Reserve(int capacity)
Ensures that the allocated size is at least the given size.
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...
static void Min(OpData< T >)
Reduce operation Min, instantiated for int and double.
void Sort()
Sorts the array in ascending order. This requires operator< to be defined for T.
int Size() const
Returns the number of TYPE I elements.
GroupCommunicator(GroupTopology >, Mode m=byNeighbor)
Construct a GroupCommunicator object.
int GetGroupMaster(int g) const
Return the neighbor index of the group master for a given group. Neighbor 0 is the local processor...
void Copy(GroupTopology ©) const
Copy the internal data to the external 'copy'.
void Save(std::ostream &out) const
Save the data in a stream.
void Swap(Array< T > &, Array< T > &)
double p(const Vector &x, double t)
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...
int GetNeighborRank(int i) const
Return the MPI rank of neighbor 'i'.
static void Max(OpData< T >)
Reduce operation Max, instantiated for int and double.
Communications are performed one group at a time.
void AddAColumnInRow(int r)
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Helper struct for defining a connectivity table, see Table::MakeFromList.
void SetLTDofTable(const Array< int > &ldof_ltdof)
Initialize the internal group_ltdof Table.
void BcastBegin(T *ldata, int layout) const
Begin a broadcast within each group where the master is the root.
Data structure on which we define reduce operations. The data is associated with (and the operation i...
~GroupCommunicator()
Destroy a GroupCommunicator object, deallocating internal data structures and buffers.
void KdTreeSort(int **coords, int d, int dim, int size)
int index(int i, int j, int nx, int ny)
int NGroups() const
Return the number of groups.
void ReduceBegin(const T *ldata) const
Begin reduction operation within each group where the master is the root.
void SetComm(MPI_Comm comm)
Set the MPI communicator to 'comm'.
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
void PrintInfo(std::ostream &out=mfem::out) const
Print information about the GroupCommunicator from all MPI ranks.
void Copy(Table ©) const
void Load(std::istream &in)
Load the data from a stream.
static void BitOR(OpData< T >)
Reduce operation bitwise OR, instantiated for int only.