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
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)
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.
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.