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);
356 for (
int i = 0; i < ldof_group.
Size(); i++)
358 int group = ldof_group[i];
366 for (
int i = 0; i < ldof_group.
Size(); i++)
368 int group = ldof_group[i];
381 int request_counter = 0;
400 request_counter += gr_requests;
405 requests =
new MPI_Request[request_counter];
415 if (nldofs == 0) {
continue; }
425 for (
int i = 0; i < grp_size; i++)
427 if (grp_nbr_list[i] != 0)
439 if (nldofs == 0) {
continue; }
449 for (
int i = 0; i < grp_size; i++)
451 if (grp_nbr_list[i] != 0)
470 if (num_recv_groups > 0)
473 group_ids.
SetSize(num_recv_groups);
474 for (
int i = 0; i < num_recv_groups; i++)
477 group_ids[i].two = grp_list[i];
480 for (
int i = 0; i < num_recv_groups; i++)
482 grp_list[i] = group_ids[i].two;
507 for (
int i = 0; i < nldofs; i++)
522 if (num_send_groups > 0)
525 for (
int i = 0; i < num_send_groups; i++)
527 const int group = grp_list[i];
537 if (num_send_groups > 0)
540 for (
int i = 0; i < num_send_groups; i++)
542 const int group = grp_list[i];
558 if (num_recv_groups > 0)
561 for (
int i = 0; i < num_recv_groups; i++)
563 const int group = grp_list[i];
573 if (num_recv_groups > 0)
576 for (
int i = 0; i < num_recv_groups; i++)
578 const int group = grp_list[i];
604 for (
int j = 0; j < nltdofs; j++)
606 buf[j] = ldata[ltdofs[j]];
608 return buf + nltdofs;
614 for (
int j = 0; j < nldofs; j++)
616 buf[j] = ldata[ldofs[j]];
625 int group,
int layout)
const
638 for (
int j = 0; j < nldofs; j++)
640 ldata[ltdofs[j]] = buf[j];
647 for (
int j = 0; j < nldofs; j++)
649 ldata[ldofs[j]] = buf[j];
659 int group,
int layout,
666 opd.
buf =
const_cast<T*
>(buf);
672 MFEM_ABORT(
"layout 1 is not supported");
674 for (
int j = 0; j < opd.
nldofs; j++)
699 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
703 int request_counter = 0;
714 "'group_ltdof' is not set, use SetLTDofTable()");
726 if (nldofs == 0) {
continue; }
748 for (
int i = 0; i < gs; i++)
776 if (num_send_groups > 0)
783 for (
int i = 0; i < num_send_groups; i++)
799 if (num_recv_groups > 0)
807 for (
int i = 0; i < num_recv_groups; i++)
838 MFEM_VERIFY(
comm_lock == 1,
"object is NOT locked for Bcast");
848 else if (layout == 0)
853 idx != MPI_UNDEFINED)
856 if (gr == -1) {
continue; }
871 idx != MPI_UNDEFINED)
874 if (nbr == -1) {
continue; }
877 if (num_recv_groups > 0)
881 for (
int i = 0; i < num_recv_groups; i++)
898 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
902 int request_counter = 0;
913 if (nldofs == 0) {
continue; }
917 const int layout = 0;
935 for (
int i = 0; i < gs; i++)
962 if (num_send_groups > 0)
966 for (
int i = 0; i < num_send_groups; i++)
968 const int layout = 0;
984 if (num_recv_groups > 0)
988 for (
int i = 0; i < num_recv_groups; i++)
1020 MFEM_VERIFY(
comm_lock == 2,
"object is NOT locked for Reduce");
1036 idx != MPI_UNDEFINED)
1039 if (gr == -1) {
continue; }
1043 if ((--group_num_req[gr]) != 0) {
continue; }
1049 opd.
ldofs = (layout == 0) ?
1065 if (num_recv_groups > 0)
1069 for (
int i = 0; i < num_recv_groups; i++)
1089 for (
int i = 0; i < opd.
nldofs; i++)
1096 for (
int i = 0; i < opd.
nldofs; i++)
1099 for (
int j = 0; j < opd.
nb; j++)
1111 for (
int i = 0; i < opd.
nldofs; i++)
1114 for (
int j = 0; j < opd.
nb; j++)
1129 for (
int i = 0; i < opd.
nldofs; i++)
1132 for (
int j = 0; j < opd.
nb; j++)
1147 for (
int i = 0; i < opd.
nldofs; i++)
1150 for (
int j = 0; j < opd.
nb; j++)
1161 const int tag = 46800;
1164 int num_sends = 0, num_recvs = 0;
1165 size_t mem_sends = 0, mem_recvs = 0;
1166 int num_master_groups = 0, num_empty_groups = 0;
1167 int num_active_neighbors = 0;
1183 num_master_groups++;
1188 mem_recvs +=
sizeof(double)*nldofs;
1204 num_master_groups++;
1210 if (num_send_groups > 0)
1213 for (
int i = 0; i < num_send_groups; i++)
1221 if (num_recv_groups > 0)
1224 for (
int i = 0; i < num_recv_groups; i++)
1230 if (num_send_groups > 0 || num_recv_groups > 0)
1232 num_active_neighbors++;
1239 MPI_Recv(&c, 1, MPI_CHAR, myid-1, tag,
gtopo.
GetComm(),
1244 out <<
"\nGroupCommunicator:\n";
1246 out <<
"Rank " << myid <<
":\n"
1248 (
mode ==
byGroup ?
"byGroup" :
"byNeighbor") <<
"\n"
1249 " number of sends = " << num_sends <<
1250 " (" << mem_sends <<
" bytes)\n"
1251 " number of recvs = " << num_recvs <<
1252 " (" << mem_recvs <<
" bytes)\n";
1255 num_master_groups <<
" + " <<
1257 num_empty_groups <<
" (master + slave + empty)\n";
1262 num_active_neighbors <<
" + " <<
1264 " (active + inactive)\n";
1269 MPI_Send(&c, 1, MPI_CHAR, myid+1, tag,
gtopo.
GetComm());
1289 template void GroupCommunicator::BcastBegin<int>(
int *, int)
const;
1290 template void GroupCommunicator::BcastEnd<int>(
int *, int)
const;
1291 template void GroupCommunicator::ReduceBegin<int>(
const int *)
const;
1292 template void GroupCommunicator::ReduceEnd<int>(
1293 int *, int, void (*)(OpData<int>))
const;
1295 template void GroupCommunicator::BcastBegin<double>(
double *, int)
const;
1296 template void GroupCommunicator::BcastEnd<double>(
double *, int)
const;
1297 template void GroupCommunicator::ReduceBegin<double>(
const double *)
const;
1298 template void GroupCommunicator::ReduceEnd<double>(
1299 double *, int, void (*)(OpData<double>))
const;
1304 template void GroupCommunicator::Sum<int>(OpData<int>);
1305 template void GroupCommunicator::Min<int>(OpData<int>);
1306 template void GroupCommunicator::Max<int>(OpData<int>);
1307 template void GroupCommunicator::BitOR<int>(OpData<int>);
1309 template void GroupCommunicator::Sum<double>(OpData<double>);
1310 template void GroupCommunicator::Min<double>(OpData<double>);
1311 template void GroupCommunicator::Max<double>(OpData<double>);
1315 static void DebugRankCoords(
int** coords,
int dim,
int size)
1317 for (
int i = 0; i < size; i++)
1319 mfem::out <<
"Rank " << i <<
" coords: ";
1320 for (
int j = 0; j <
dim; j++)
1328 struct CompareCoords
1330 CompareCoords(
int coord) : coord(coord) {}
1333 bool operator()(
int*
const &
a,
int*
const &
b)
const
1334 {
return a[coord] < b[coord]; }
1341 bool all_same =
true;
1342 for (
int i = 1; i < size && all_same; i++)
1344 for (
int j = 0; j <
dim; j++)
1346 if (coords[i][j] != coords[0][j]) { all_same =
false;
break; }
1349 if (all_same) {
return; }
1352 std::sort(coords, coords + size, CompareCoords(d));
1353 int next = (d + 1) % dim;
1355 if (coords[0][d] < coords[size-1][d])
1358 KdTreeSort(coords + size/2, next, dim, size - size/2);
1373 MPI_Comm_rank(comm, &rank);
1374 MPI_Comm_size(comm, &size);
1377 MPIX_Torus_ndims(&dim);
1379 int* mycoords =
new int[dim + 1];
1380 MPIX_Rank2torus(rank, mycoords);
1382 MPI_Send(mycoords, dim, MPI_INT, 0, 111, comm);
1387 int** coords =
new int*[size];
1388 for (
int i = 0; i < size; i++)
1390 coords[i] =
new int[dim + 1];
1392 MPI_Recv(coords[i], dim, MPI_INT, i, 111, comm, &status);
1399 for (
int i = 0; i < size; i++)
1401 MPI_Send(&coords[i][dim], 1, MPI_INT, i, 112, comm);
1402 delete [] coords[i];
1408 MPI_Recv(&new_rank, 1, MPI_INT, 0, 112, comm, &status);
1411 MPI_Comm_split(comm, 0, new_rank, &new_comm);
int Lookup(IntegerSet &s)
int GetGroupMasterRank(int g) const
void Create(ListOfIntegerSets &groups, int mpitag)
void ReduceEnd(T *ldata, int layout, void(*Op)(OpData< T >)) const
Finalize reduction operation started with ReduceBegin().
int Size() const
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)
int GetGroupMasterGroup(int g) const
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.
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
void SetDims(int rows, int nnz)
const int * GetGroup(int g) const
void Copy(Array ©) const
Create a copy of the current array.
T * GetData()
Returns the data.
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
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)
void AddConnections(int r, const int *c, int nc)
int PickElementInSet(int i)
void BcastEnd(T *ldata, int layout) const
Finalize a broadcast started with BcastBegin().
bool IAmMaster(int g) const
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 to array, resize if necessary.
int GetNumNeighbors() const
void Finalize()
Allocate internal buffers after the GroupLDofTable is defined.
void AddConnection(int r, int c)
int Insert(IntegerSet &s)
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. 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
void Copy(GroupTopology ©) const
Copy.
void Save(std::ostream &out) const
Save the data in a stream.
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
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 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.
~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)
void ReduceBegin(const T *ldata) const
Begin reduction operation within each group where the master is the root.
void SetComm(MPI_Comm 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.