9 #include <fei_macros.hpp>
15 #include <fei_TemplateUtils.hpp>
16 #include <fei_mpiTraits.hpp>
17 #include <fei_CommUtils.hpp>
18 #include <fei_NodeDescriptor.hpp>
19 #include <fei_NodeCommMgr.hpp>
20 #include <SNL_FEI_Structure.hpp>
22 #include <fei_NodeDatabase.hpp>
25 #define fei_file "fei_NodeCommMgr.cpp"
26 #include <fei_ErrMacros.hpp>
29 NodeCommMgr::NodeCommMgr(MPI_Comm comm,
const SNL_FEI_Structure& problemStructure,
int sharedNodeOwnership)
31 sharedNodesAllocated_(false),
32 sharedNodeOwnership_(sharedNodeOwnership),
36 sharedNodeSubdomains(),
37 trivialSubdomainList(1),
41 remoteSharingProcs_(),
43 nodesPerSharingProc_(),
50 initCompleteCalled_(false),
51 probStruc(problemStructure)
55 trivialSubdomainList[0] = localProc_;
59 NodeCommMgr::~NodeCommMgr() {
61 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
62 delete sharingProcs_[i];
65 delete [] sharedNodes_;
66 sharedNodesAllocated_ =
false;
70 int NodeCommMgr::getSharedNodeIndex(GlobalID nodeID)
76 int NodeCommMgr::getSharedNodeNumSubdomains(GlobalID nodeID)
78 int index = getSharedNodeIndex(nodeID);
82 if (index < 0)
return(1);
87 return(sharedNodeSubdomains[index].size());
91 std::vector<int>* NodeCommMgr::getSharedNodeSubdomainList(GlobalID nodeID)
93 int index = getSharedNodeIndex(nodeID);
97 if (index < 0)
return( &trivialSubdomainList );
101 return( &(sharedNodeSubdomains[index]) );
116 if (numProcs_ == 1)
return(0);
118 GlobalID nodeID = node.getGlobalNodeID();
120 int sharedIndex = getSharedNodeIndex(nodeID);
123 if (sharedIndex < 0)
return(0);
131 if (index == -2)
return(-2);
137 int NodeCommMgr::getGlobalMaxFieldsBlocks(
int& maxFields,
int& maxBlocks)
139 std::vector<int> localMax(2, 0), globalMax(2, 0);
141 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
142 int numFlds = sharedNodes_[i]->getNumFields();
143 if (numFlds > localMax[0]) localMax[0] = numFlds;
145 int numBlks = sharedNodes_[i]->getNumBlocks();
146 if (numBlks > localMax[1]) localMax[1] = numBlks;
150 if (err != 0)
return(err);
152 maxFields = globalMax[0];
153 maxBlocks = globalMax[1];
159 int NodeCommMgr::getGlobalMaxFieldsBlocksSubdomains()
161 std::vector<int> localMax(3, 0), globalMax(3, 0);
163 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
164 int numFlds = sharedNodes_[i]->getNumFields();
165 if (numFlds > localMax[0]) localMax[0] = numFlds;
167 int numBlks = sharedNodes_[i]->getNumBlocks();
168 if (numBlks > localMax[1]) localMax[1] = numBlks;
170 int numShrd = sharingProcs_[i]->size();
171 if (numShrd > localMax[2]) localMax[2] = numShrd;
175 if (err != 0)
return(err);
177 maxFields_ = globalMax[0];
178 maxBlocks_ = globalMax[1];
179 maxSubdomains_ = globalMax[2];
187 return( remoteSharingProcs_ );
193 return( remoteOwnerProcs_ );
199 std::vector<int>::iterator
200 rs_iter = std::lower_bound(remoteSharingProcs_.begin(),
201 remoteSharingProcs_.end(), destProc);
202 if (rs_iter == remoteSharingProcs_.end() || destProc != *rs_iter) {
206 int idx = rs_iter - remoteSharingProcs_.begin();
208 int len = 7+maxFields_*2 + maxBlocks_ + maxSubdomains_;
209 messageLength = nodesPerSharingProc_[idx] * (len+1);
216 std::vector<int>::iterator
217 rs_iter = std::lower_bound(remoteSharingProcs_.begin(),
218 remoteSharingProcs_.end(), destProc);
219 if (rs_iter == remoteSharingProcs_.end() || destProc != *rs_iter) {
223 int idx = rs_iter - remoteSharingProcs_.begin();
228 packLocalNodesAndData(&message[0], destProc,
229 nodesPerSharingProc_[idx], len);
237 remoteOwnerProcs_.size());
238 int numNodes = nodesPerOwnerProc_[idx];
239 int* msgPtr = &message[0];
242 for(
int j=0; j<numNodes; j++) {
243 int nIndex =
fei::binarySearch(msgPtr[j], &sharedNodeIDs[0], sharedNodeIDs.size());
244 if (nIndex < 0)
return(-1);
247 int nodeNum = msgPtr[numNodes+offset++];
248 int numFields = msgPtr[numNodes+offset++];
249 int numBlocks = msgPtr[numNodes+offset++];
250 int numSubdomains = msgPtr[numNodes+offset++];
252 node->setNodeNumber(nodeNum);
253 node->setNumNodalDOF( msgPtr[numNodes+offset++]);
254 node->setBlkEqnNumber(msgPtr[numNodes+offset++]);
256 for(
int fld=0; fld<numFields; fld++) {
257 int fieldID = msgPtr[numNodes+offset++];
258 int eqnNum = msgPtr[numNodes+offset++];
259 node->addField(fieldID);
260 node->setFieldEqnNumber(fieldID, eqnNum);
263 for(
int blk=0; blk<numBlocks; blk++) {
267 node->addBlockIndex(blk_idx);
271 sharedNodeSubdomains[nIndex].resize(numSubdomains);
272 for(
int sd=0; sd<numSubdomains; sd++) {
273 (sharedNodeSubdomains[nIndex])[sd] =
274 msgPtr[numNodes+offset++];
282 int NodeCommMgr::exchangeEqnInfo()
301 if (numProcs_ == 1)
return(0);
306 CHK_ERR( getGlobalMaxFieldsBlocksSubdomains() );
308 CHK_ERR( fei::exchange(comm_,
this) );
310 setNodeNumbersArray();
312 #endif //#ifndef FEI_SER
318 void NodeCommMgr::packLocalNodesAndData(
int* data,
319 int proc,
int numNodes,
int len)
345 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
346 if (sharedNodes_[i]->getOwnerProc() != localProc_)
continue;
352 std::vector<int>& sProcs = *(sharingProcs_[i]);
356 if (index < 0)
continue;
358 if (nodeCounter >= numNodes) {
360 <<
" nodeCounter >= numNodes." << FEI_ENDL;
363 data[nodeCounter++] = (int)(node->getGlobalNodeID());
365 int nodeNum = node->getNodeNumber();
366 int numFields = node->getNumFields();
367 int numBlocks = node->getNumBlocks();
368 const int* fieldIDsPtr = node->getFieldIDList();
369 const int* fieldEqnNums = node->getFieldEqnNumbers();
370 int blkEqnNumber = node->getBlkEqnNumber();
372 const std::vector<unsigned>& nodeBlocks = node->getBlockIndexList();
373 std::vector<int>& subdomains = sharedNodeSubdomains[i];
375 data[numNodes+offset++] = nodeNum;
376 data[numNodes+offset++] = numFields;
377 data[numNodes+offset++] = numBlocks;
378 data[numNodes+offset++] = subdomains.size();
379 data[numNodes+offset++] = node->getNumNodalDOF();
380 data[numNodes+offset++] = blkEqnNumber;
382 for(
int j=0; j<numFields; j++) {
383 data[numNodes+offset++] = fieldIDsPtr[j];
387 <<
" offset >= len." << FEI_ENDL;
390 data[numNodes+offset++] = fieldEqnNums[j];
393 for(
int kk=0; kk<numBlocks; kk++) {
394 GlobalID blkID = probStruc.
getBlockID(nodeBlocks[kk]);
395 data[numNodes+offset++] = blkID;
398 for(
unsigned k=0; k<subdomains.size(); k++) {
399 data[numNodes+offset++] = subdomains[k];
405 void NodeCommMgr::packRemoteNodesAndData(GlobalID* data,
406 int proc,
int numNodes,
int len)
431 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
434 int thisProc = node->getOwnerProc();
435 if (thisProc != proc)
continue;
437 if (nodeCounter >= numNodes) {
438 fei::console_out() << localProc_ <<
": NodeCommMgr::packRemoteNodesAndData: ERROR,"
439 <<
" nodeCounter >= numNodes: " << numNodes << FEI_ENDL;
442 data[nodeCounter++] = node->getGlobalNodeID();
444 int numFields = node->getNumFields();
445 int numBlocks = node->getNumBlocks();
446 const int* fieldIDsPtr = node->getFieldIDList();
448 const std::vector<unsigned>& nodeBlocks = node->getBlockIndexList();
449 int lindex =
fei::binarySearch(sharedNodeIDs[i], &localNodeIDs[0], localNodeIDs.size());
451 data[numNodes+offset++] = (lindex >= 0) ? 1 : 0;
452 data[numNodes+offset++] = (GlobalID)numFields;
453 data[numNodes+offset++] = (GlobalID)numBlocks;
454 data[numNodes+offset++] = (GlobalID)node->getNumNodalDOF();
456 for(
int j=0; j<numFields; j++) {
459 <<
" offset >= len." << FEI_ENDL;
462 data[numNodes+offset++] = (GlobalID)fieldIDsPtr[j];
465 for(
int k=0; k<numBlocks; k++) {
468 <<
" offset >= len." << FEI_ENDL;
471 data[numNodes+offset++] = probStruc.
getBlockID(nodeBlocks[k]);
477 int NodeCommMgr::createProcList(std::vector<int>& itemsPerProc,
478 std::vector<int>& procs)
488 int len = itemsPerProc.size();
490 for(
int i=0; i<len; i++) {
491 if (itemsPerProc[i] > 0) numProcs++;
494 procs.resize(numProcs);
498 for(
int i=0; i<len; i++) {
499 if (itemsPerProc[i] > 0) procs[offset++] = i;
505 int NodeCommMgr::getSharedNodeIndex_num(
int nodeNumber)
507 for(
unsigned i=0; i<sharedNodeNumbers.size(); ++i) {
508 if (sharedNodeNumbers[i] == nodeNumber)
return(i);
515 int NodeCommMgr::addSharedNodes(
const GlobalID* nodeIDs,
517 const int*
const* procs,
518 const int* numProcs )
527 for(
int i=0; i<numNodes; i++) {
528 int insertPoint = -1;
531 sharingProcs_.insert(sharingProcs_.begin()+insertPoint,
new std::vector<int>);
533 sharedNodeIDs.insert(sharedNodeIDs.begin()+insertPoint, nodeIDs[i]);
538 int err = storeNodeProcs(index, sharingProcs_, procs[i], numProcs[i]);
539 if (err != 0)
return(err);
543 catch(std::runtime_error& exc) {
552 int NodeCommMgr::allocateNodeDescriptorPtrs(
NodeDatabase& nodeDB)
559 if (sharedNodeIDs.size() == 0)
return(0);
561 if (sharedNodes_ != NULL)
delete [] sharedNodes_;
563 if (sharedNodes_ == NULL)
return(-1);
565 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
568 if (err != 0)
return(-1);
570 sharedNodes_[i] = node;
573 sharedNodesAllocated_ =
true;
578 int NodeCommMgr::initComplete(
NodeDatabase& nodeDB,
bool safetyCheck)
593 int err = allocateNodeDescriptorPtrs(nodeDB);
594 if (err != 0)
return(err);
600 for(
unsigned ii=0; ii<sharedNodeIDs.size(); ii++) {
601 std::vector<int>& shProcs = *(sharingProcs_[ii]);
607 std::vector<int>::iterator sh_iter =
608 std::lower_bound(shProcs.begin(), shProcs.end(), localProc_);
609 if (sh_iter == shProcs.end() || localProc_ != *sh_iter) {
610 shProcs.insert(sh_iter, localProc_);
613 int proc = shProcs[0];
615 sharedNodes_[ii]->setOwnerProc(proc);
621 sharedNodeSubdomains.resize(sharedNodeIDs.size());
623 for(
unsigned i=0; i<sharedNodeSubdomains.size(); ++i) {
624 sharedNodeSubdomains[i].resize(0);
629 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
630 int index =
fei::binarySearch(sharedNodeIDs[i], &localNodeIDs[0], localNodeIDs.size());
632 sharedNodeSubdomains[i].push_back(localProc_);
636 if (sharedNodeOwnership_ == PROC_WITH_LOCAL_ELEM) {
637 err = adjustSharedOwnership();
638 if (err != 0)
return(err);
641 err = createProcLists();
644 err = checkSharedNodeInfo();
645 if (err != 0)
return(-1);
648 exchangeSharedRemoteFieldsBlks();
650 initCompleteCalled_ =
true;
657 #define _feiFunc_ "NodeCommMgr::checkSharedNodeInfo"
658 int NodeCommMgr::checkSharedNodeInfo()
672 if (numProcs_==1)
return(0);
677 std::vector<int> globalOwnerProcs, globalSharingProcs;
678 std::vector<int> recvOwnerLengths, recvSharingLengths;
680 std::vector<int> globalNodesPerOwnerProcs, globalNodesPerSharingProcs;
681 std::vector<int> recvNodesPerOwnerLengths, recvNodesPerSharingLengths;
687 recvOwnerLengths, globalOwnerProcs) );
690 recvNodesPerOwnerLengths,
691 globalNodesPerOwnerProcs) );
694 recvSharingLengths, globalSharingProcs) );
697 recvNodesPerSharingLengths,
698 globalNodesPerSharingProcs) );
702 int err = checkCommArrays(
"owners",
703 globalOwnerProcs, globalNodesPerOwnerProcs,
705 nodesPerSharingProc_, remoteSharingProcs_ );
709 err += checkCommArrays(
"sharing",
710 globalSharingProcs, globalNodesPerSharingProcs,
712 nodesPerOwnerProc_, remoteOwnerProcs_ );
722 int NodeCommMgr::checkCommArrays(
const char* whichCheck,
723 std::vector<int>& globalRemoteProcs,
724 std::vector<int>& globalNodesPerRemoteProc,
725 std::vector<int>& globalRemoteProcLengths,
726 std::vector<int>& nodesPerRemoteProc,
727 std::vector<int>& remoteProcs)
731 for(
int i=0; i<numProcs_; i++) {
732 int length = globalRemoteProcLengths[i];
734 if (i==localProc_) { offset += length;
continue; }
736 for(
int j=0; j<length; j++) {
737 if (globalRemoteProcs[offset+j] == localProc_) {
739 int numShared = globalNodesPerRemoteProc[offset+j];
745 <<
" ERROR. Local proc (" << localProc_
746 <<
") doesn't share nodes with proc " << i <<
" but proc " << i
747 <<
" thinks it shares nodes with proc " << localProc_ << FEI_ENDL;
753 int numWeThinkWeShare = nodesPerRemoteProc[index];
754 if (numWeThinkWeShare != numShared) {
756 <<
" ERROR. Local proc (" << localProc_ <<
") thinks it shares "
757 << numWeThinkWeShare <<
" nodes with proc " << i <<
", but proc "
758 << i <<
" thinks it shares " << numShared <<
" nodes with proc "
759 << localProc_ <<
"." << FEI_ENDL;
772 int NodeCommMgr::adjustSharedOwnership()
783 remoteNodeIDs.resize(0);
785 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
786 GlobalID nodeID = sharedNodeIDs[i];
788 std::vector<int>& shProcs = *(sharingProcs_[i]);
790 if (
fei::binarySearch(nodeID, &localNodeIDs[0], localNodeIDs.size()) >= 0)
continue;
792 int proc = shProcs[0];
794 if (proc == localProc_) {
795 sharedNodes_[i]->setOwnerProc(shProcs[1]);
797 if (err == -2)
return(err);
807 std::vector<GlobalID> allRemoteNodeIDs;
808 std::vector<int> numPerProc;
810 err =
fei::Allgatherv(comm_, remoteNodeIDs, numPerProc, allRemoteNodeIDs);
811 if (err != 0)
return(-1);
819 remoteNodeIDs.resize(0);
822 for(
unsigned i=0; i<numPerProc.size(); i++) {
823 for(
int j=0; j<numPerProc[i]; j++) {
826 if ((
int)i==localProc_) {offset++;
continue;}
828 GlobalID nodeID = allRemoteNodeIDs[offset++];
829 int index = getSharedNodeIndex(nodeID);
832 if (index < 0)
continue;
843 err =
fei::Allgatherv(comm_, remoteNodeIDs, numPerProc, allRemoteNodeIDs);
844 if (err != 0)
return(-1);
850 offset = allRemoteNodeIDs.size()-1;
851 for(
int i=(
int)numPerProc.size()-1; i>=0; i--) {
852 for(
int j=0; j<numPerProc[i]; j++) {
853 GlobalID nodeID = allRemoteNodeIDs[offset--];
854 int index = getSharedNodeIndex(nodeID);
856 if (index < 0)
continue;
858 sharedNodes_[index]->setOwnerProc(i);
866 void NodeCommMgr::setNodeNumbersArray()
868 sharedNodeNumbers.resize(sharedNodeIDs.size());
870 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
871 sharedNodeNumbers[i] = sharedNodes_[i]->getNodeNumber();
876 int NodeCommMgr::createProcLists()
878 std::vector<int> localNodesPerProc(numProcs_, 0);
879 std::vector<int> remoteNodesPerProc(numProcs_, 0);
885 for(
unsigned i=0; i<sharedNodeIDs.size(); i++) {
886 int proc = sharedNodes_[i]->getOwnerProc();
888 if (proc != localProc_) {
889 remoteNodesPerProc[proc]++;
892 std::vector<int>& shProcs = *(sharingProcs_[i]);
893 for(
unsigned j=0; j<shProcs.size(); j++) {
894 int sproc = shProcs[j];
896 if (sproc != localProc_) {
897 localNodesPerProc[sproc]++;
905 int err = createProcList(remoteNodesPerProc, remoteOwnerProcs_);
906 if (err != 0)
return(err);
908 err = createProcList(localNodesPerProc, remoteSharingProcs_);
909 if (err != 0)
return(err);
912 nodesPerOwnerProc_.resize(remoteOwnerProcs_.size());
914 nodesPerSharingProc_.resize(remoteSharingProcs_.size());
917 for(
int i=0; i<numProcs_; i++) {
918 if (remoteNodesPerProc[i] > 0)
919 nodesPerOwnerProc_[offset++] = remoteNodesPerProc[i];
923 for(
int i=0; i<numProcs_; i++) {
924 if (localNodesPerProc[i] > 0)
925 nodesPerSharingProc_[offset++] = localNodesPerProc[i];
932 int NodeCommMgr::exchangeSharedRemoteFieldsBlks()
940 int maxFields, maxBlocks;
941 int err = getGlobalMaxFieldsBlocks(maxFields, maxBlocks);
948 int len = 4 + maxFields + maxBlocks;
950 GlobalID** recvData = NULL;
951 MPI_Request* recvDataReqs = NULL;
953 unsigned i, numRecvProcs = remoteSharingProcs_.size();
955 if (numRecvProcs > 0) {
956 recvData =
new GlobalID*[numRecvProcs];
957 recvDataReqs =
new MPI_Request[numRecvProcs];
962 int numRcvStarted = 0;
963 for(i=0; i<remoteSharingProcs_.size(); i++) {
964 int numRecvNodes = nodesPerSharingProc_[i];
965 recvData[i] =
new GlobalID[numRecvNodes*(len+1)];
966 MPI_Irecv(recvData[i], numRecvNodes*(len+1),
967 fei::mpiTraits<GlobalID>::mpi_type(),
968 remoteSharingProcs_[i], dataTag, comm_, &recvDataReqs[i]);
976 for(i=0; i<remoteOwnerProcs_.size(); i++) {
977 int numSendNodes = nodesPerOwnerProc_[i];
979 std::vector<GlobalID> sendData(numSendNodes*(len+1), 0);
981 packRemoteNodesAndData(&sendData[0], remoteOwnerProcs_[i],
982 numSendNodes, numSendNodes*len);
984 MPI_Send(&sendData[0], sendData.size(),
985 fei::mpiTraits<GlobalID>::mpi_type(),
986 remoteOwnerProcs_[i], dataTag, comm_);
990 int numCompleted = 0;
991 for(i=0; i<remoteSharingProcs_.size(); i++) {
994 MPI_Wait(&recvDataReqs[index], &status);
996 int remoteProc = status.MPI_SOURCE;
999 int numNodes = nodesPerSharingProc_[index];
1001 for(
int j=0; j<numNodes; j++) {
1002 int nIndex =
fei::binarySearch(recvData[index][j], &sharedNodeIDs[0], sharedNodeIDs.size());
1004 fei::console_out() <<
"NodeCommMgr::exchangeSharedRemote...: error, unknown nodeID "
1005 << (int)recvData[index][j] <<
", " << j
1006 <<
"th node recvd from proc "
1007 <<remoteSharingProcs_[index]
1008 <<
". Probably a communication mis-match, we expected "
1010 <<
" nodes from that proc, but recvd less than that." << FEI_ENDL;
1014 int residesRemotely = (int)recvData[index][numNodes+offset++];
1016 if (residesRemotely) {
1017 std::vector<int>& snSubd = sharedNodeSubdomains[nIndex];
1018 std::vector<int>::iterator sn_iter =
1019 std::lower_bound(snSubd.begin(), snSubd.end(), remoteProc);
1020 if (sn_iter == snSubd.end() || remoteProc != *sn_iter) {
1021 snSubd.insert(sn_iter, remoteProc);
1024 int numFields = (int)recvData[index][numNodes+offset++];
1025 int numBlocks = (int)recvData[index][numNodes+offset++];
1026 sharedNodes_[nIndex]->
1027 setNumNodalDOF((
int)recvData[index][numNodes+offset++]);
1029 for(
int fld=0; fld<numFields; fld++) {
1030 int fieldID = (int)recvData[index][numNodes+offset++];
1032 sharedNodes_[nIndex]->addField(fieldID);
1035 for(
int blk=0; blk<numBlocks; blk++) {
1036 int blk_idx = probStruc.
getIndexOfBlock(recvData[index][numNodes+offset++]);
1039 sharedNodes_[nIndex]->addBlockIndex(blk_idx);
1045 if (numRcvStarted != numCompleted) {
1046 fei::console_out() <<
"NodeCommMgr::exchangeSharedRemote...: recv-send mismatch;"
1047 <<
" numRcvStarted: " << numRcvStarted <<
", numCompleted: "
1048 << numCompleted << FEI_ENDL;
1052 for(i=0; i<numRecvProcs; i++) {
1053 delete [] recvData[i];
1057 delete [] recvDataReqs;
1059 #endif //#ifndef FEI_SER
1065 int NodeCommMgr::storeNodeProcs(
int index,
1066 std::vector<std::vector<int>*>& procTable,
1067 const int* procs,
int numProcs)
1074 std::vector<int>& row_index = *(procTable[index]);
1075 for(
int i=0; i<numProcs; i++) {
1076 std::vector<int>::iterator r_iter =
1077 std::lower_bound(row_index.begin(), row_index.end(), procs[i]);
1078 if (r_iter == row_index.end() || procs[i] != *r_iter) {
1079 row_index.insert(r_iter, procs[i]);
int GlobalSum(MPI_Comm comm, std::vector< T > &local, std::vector< T > &global)
int sortedListInsert(const T &item, std::vector< T > &list)
int Allgatherv(MPI_Comm comm, std::vector< T > &sendbuf, std::vector< int > &recvLengths, std::vector< T > &recvbuf)
int getBlockID(unsigned index) const
std::vector< int > & getSendProcs()
int binarySearch(const T &item, const T *list, int len)
int getSendMessage(int destProc, std::vector< int > &message)
std::vector< int > & getRecvProcs()
std::ostream & console_out()
int GlobalMax(MPI_Comm comm, std::vector< T > &local, std::vector< T > &global)
int localProc(MPI_Comm comm)
int getSendMessageLength(int destProc, int &messageLength)
int getNodeWithID(GlobalID nodeID, const NodeDescriptor *&node) const
int processRecvMessage(int srcProc, std::vector< int > &message)
int numProcs(MPI_Comm comm)
int getIndexOfBlock(GlobalID blockID) const