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)
315 for (
int index = 0; index < group_size; ++index )
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++)
532 for (
int j = 0; j < nltdofs; j++)
534 buf[j] = ldata[ltdofs[j]];
536 return buf + nltdofs;
542 for (
int j = 0; j < nldofs; j++)
544 buf[j] = ldata[ldofs[j]];
553 int group,
int layout)
const
566 for (
int j = 0; j < nldofs; j++)
568 ldata[ltdofs[j]] = buf[j];
575 for (
int j = 0; j < nldofs; j++)
577 ldata[ldofs[j]] = buf[j];
587 int group,
int layout,
594 opd.
buf =
const_cast<T*
>(buf);
600 MFEM_ABORT(
"layout 1 is not supported");
602 for (
int j = 0; j < opd.
nldofs; j++)
627 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
631 int request_counter = 0;
642 "'group_ltdof' is not set, use SetLTDofTable()");
654 if (nldofs == 0) {
continue; }
676 for (
int i = 0; i < gs; i++)
704 if (num_send_groups > 0)
711 for (
int i = 0; i < num_send_groups; i++)
727 if (num_recv_groups > 0)
735 for (
int i = 0; i < num_recv_groups; i++)
766 MFEM_VERIFY(
comm_lock == 1,
"object is NOT locked for Bcast");
776 else if (layout == 0)
781 idx != MPI_UNDEFINED)
784 if (gr == -1) {
continue; }
799 idx != MPI_UNDEFINED)
802 if (nbr == -1) {
continue; }
805 if (num_recv_groups > 0)
809 for (
int i = 0; i < num_recv_groups; i++)
826 MFEM_VERIFY(
comm_lock == 0,
"object is already in use");
830 int request_counter = 0;
841 if (nldofs == 0) {
continue; }
845 const int layout = 0;
863 for (
int i = 0; i < gs; i++)
890 if (num_send_groups > 0)
894 for (
int i = 0; i < num_send_groups; i++)
896 const int layout = 0;
912 if (num_recv_groups > 0)
916 for (
int i = 0; i < num_recv_groups; i++)
948 MFEM_VERIFY(
comm_lock == 2,
"object is NOT locked for Reduce");
964 idx != MPI_UNDEFINED)
967 if (gr == -1) {
continue; }
971 if ((--group_num_req[gr]) != 0) {
continue; }
977 opd.
ldofs = (layout == 0) ?
993 if (num_recv_groups > 0)
997 for (
int i = 0; i < num_recv_groups; i++)
1017 for (
int i = 0; i < opd.
nldofs; i++)
1024 for (
int i = 0; i < opd.
nldofs; i++)
1027 for (
int j = 0; j < opd.
nb; j++)
1039 for (
int i = 0; i < opd.
nldofs; i++)
1042 for (
int j = 0; j < opd.
nb; j++)
1057 for (
int i = 0; i < opd.
nldofs; i++)
1060 for (
int j = 0; j < opd.
nb; j++)
1075 for (
int i = 0; i < opd.
nldofs; i++)
1078 for (
int j = 0; j < opd.
nb; j++)
1089 const int tag = 46800;
1092 int num_sends = 0, num_recvs = 0;
1093 size_t mem_sends = 0, mem_recvs = 0;
1094 int num_master_groups = 0, num_empty_groups = 0;
1095 int num_active_neighbors = 0;
1111 num_master_groups++;
1116 mem_recvs +=
sizeof(double)*nldofs;
1132 num_master_groups++;
1138 if (num_send_groups > 0)
1141 for (
int i = 0; i < num_send_groups; i++)
1149 if (num_recv_groups > 0)
1152 for (
int i = 0; i < num_recv_groups; i++)
1158 if (num_send_groups > 0 || num_recv_groups > 0)
1160 num_active_neighbors++;
1167 MPI_Recv(&c, 1, MPI_CHAR, myid-1, tag,
gtopo.
GetComm(),
1172 out <<
"\nGroupCommunicator:\n";
1174 out <<
"Rank " << myid <<
":\n"
1176 (
mode ==
byGroup ?
"byGroup" :
"byNeighbor") <<
"\n"
1177 " number of sends = " << num_sends <<
1178 " (" << mem_sends <<
" bytes)\n"
1179 " number of recvs = " << num_recvs <<
1180 " (" << mem_recvs <<
" bytes)\n";
1183 num_master_groups <<
" + " <<
1185 num_empty_groups <<
" (master + slave + empty)\n";
1190 num_active_neighbors <<
" + " <<
1192 " (active + inactive)\n";
1197 MPI_Send(&c, 1, MPI_CHAR, myid+1, tag,
gtopo.
GetComm());
1217 template void GroupCommunicator::BcastBegin<int>(
int *, int)
const;
1218 template void GroupCommunicator::BcastEnd<int>(
int *, int)
const;
1219 template void GroupCommunicator::ReduceBegin<int>(
const int *)
const;
1220 template void GroupCommunicator::ReduceEnd<int>(
1221 int *, int, void (*)(OpData<int>))
const;
1223 template void GroupCommunicator::BcastBegin<double>(
double *, int)
const;
1224 template void GroupCommunicator::BcastEnd<double>(
double *, int)
const;
1225 template void GroupCommunicator::ReduceBegin<double>(
const double *)
const;
1226 template void GroupCommunicator::ReduceEnd<double>(
1227 double *, int, void (*)(OpData<double>))
const;
1232 template void GroupCommunicator::Sum<int>(OpData<int>);
1233 template void GroupCommunicator::Min<int>(OpData<int>);
1234 template void GroupCommunicator::Max<int>(OpData<int>);
1235 template void GroupCommunicator::BitOR<int>(OpData<int>);
1237 template void GroupCommunicator::Sum<double>(OpData<double>);
1238 template void GroupCommunicator::Min<double>(OpData<double>);
1239 template void GroupCommunicator::Max<double>(OpData<double>);
1243 static void DebugRankCoords(
int** coords,
int dim,
int size)
1245 for (
int i = 0; i < size; i++)
1247 mfem::out <<
"Rank " << i <<
" coords: ";
1248 for (
int j = 0; j <
dim; j++)
1256 struct CompareCoords
1258 CompareCoords(
int coord) : coord(coord) {}
1261 bool operator()(
int*
const &a,
int*
const &b)
const
1262 {
return a[coord] < b[coord]; }
1269 bool all_same =
true;
1270 for (
int i = 1; i < size && all_same; i++)
1272 for (
int j = 0; j <
dim; j++)
1274 if (coords[i][j] != coords[0][j]) { all_same =
false;
break; }
1277 if (all_same) {
return; }
1280 std::sort(coords, coords + size, CompareCoords(d));
1281 int next = (d + 1) % dim;
1283 if (coords[0][d] < coords[size-1][d])
1286 KdTreeSort(coords + size/2, next, dim, size - size/2);
1301 MPI_Comm_rank(comm, &rank);
1302 MPI_Comm_size(comm, &size);
1305 MPIX_Torus_ndims(&dim);
1307 int* mycoords =
new int[dim + 1];
1308 MPIX_Rank2torus(rank, mycoords);
1310 MPI_Send(mycoords, dim, MPI_INT, 0, 111, comm);
1315 int** coords =
new int*[size];
1316 for (
int i = 0; i < size; i++)
1318 coords[i] =
new int[dim + 1];
1320 MPI_Recv(coords[i], dim, MPI_INT, i, 111, comm, &status);
1327 for (
int i = 0; i < size; i++)
1329 MPI_Send(&coords[i][dim], 1, MPI_INT, i, 112, comm);
1330 delete [] coords[i];
1336 MPI_Recv(&new_rank, 1, MPI_INT, 0, 112, comm, &status);
1339 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 Recreate(const int n, const int *p)
int GetGroupMasterGroup(int g) const
Helper struct to convert a C++ type to an MPI type.
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)
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.