@@ -792,15 +792,20 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) {
792792 nPoint_Send_All[0 ] = 0 ;
793793 int * nPoint_Recv_All = new int [size + 1 ];
794794 nPoint_Recv_All[0 ] = 0 ;
795- int * nPoint_Flag = new int [size];
796795
797- for (iRank = 0 ; iRank < size; iRank++) {
798- nPoint_Send_All[iRank] = 0 ;
799- nPoint_Recv_All[iRank] = 0 ;
800- nPoint_Flag[iRank] = -1 ;
801- }
802- nPoint_Send_All[size] = 0 ;
803- nPoint_Recv_All[size] = 0 ;
796+ /* --- Store a set of unique (point, marker) pairs per destination rank. ---*/
797+ using PointMarkerPair = std::pair<unsigned long , unsigned long >;
798+
799+ auto pairHash = [](const PointMarkerPair& p) -> std::size_t {
800+ // Use the golden ratio constant and bit mixing to generate pair hash
801+ std::size_t h1 = std::hash<unsigned long >{}(p.first );
802+ std::size_t h2 = std::hash<unsigned long >{}(p.second );
803+
804+ return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6 ) + (h1 >> 2 ));
805+ };
806+
807+ using PointMarkerSet = std::unordered_set<PointMarkerPair, decltype (pairHash)>;
808+ std::vector<PointMarkerSet> Points_Send_All (size, PointMarkerSet (0 , pairHash));
804809
805810 /* --- Loop through all of our periodic markers and track
806811 our sends with each rank. ---*/
@@ -821,19 +826,17 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) {
821826
822827 iRank = static_cast <int >(geometry->vertex [iMarker][iVertex]->GetDonorProcessor ());
823828
824- /* --- If we have not visited this point last, increment our
825- number of points that must be sent to a particular proc. ---*/
826-
827- if ((nPoint_Flag[iRank] != static_cast <int >(iPoint))) {
828- nPoint_Flag[iRank] = static_cast <int >(iPoint);
829- nPoint_Send_All[iRank + 1 ] += 1 ;
830- }
829+ /* --- Store the (point, marker) pair in the set for the destination rank. ---*/
830+ Points_Send_All[iRank].insert (std::make_pair (iPoint, static_cast <unsigned long >(iMarker)));
831831 }
832832 }
833833 }
834834 }
835835
836- delete[] nPoint_Flag;
836+ for (iRank = 0 ; iRank < size; iRank++) {
837+ nPoint_Send_All[iRank + 1 ] = Points_Send_All[iRank].size ();
838+ nPoint_Recv_All[iRank + 1 ] = 0 ;
839+ }
837840
838841 /* --- Communicate the number of points to be sent/recv'd amongst
839842 all processors. After this communication, each proc knows how
@@ -943,11 +946,15 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) {
943946 auto * idSend = new unsigned long [nPoint_PeriodicSend[nPeriodicSend] * nPackets];
944947 for (iSend = 0 ; iSend < nPoint_PeriodicSend[nPeriodicSend] * nPackets; iSend++) idSend[iSend] = 0 ;
945948
949+ /* --- Re-use set of unique points per destination rank. ---*/
950+ for (iRank = 0 ; iRank < size; iRank++) Points_Send_All[iRank].clear ();
951+
946952 /* --- Build the lists of local index and periodic marker index values. ---*/
947953
948954 ii = 0 ;
949955 jj = 0 ;
950956 for (iSend = 0 ; iSend < nPeriodicSend; iSend++) {
957+ int destRank = Neighbors_PeriodicSend[iSend];
951958 for (iMarker = 0 ; iMarker < config->GetnMarker_All (); iMarker++) {
952959 if (config->GetMarker_All_KindBC (iMarker) == PERIODIC_BOUNDARY) {
953960 iPeriodic = config->GetMarker_All_PerBound (iMarker);
@@ -969,14 +976,21 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) {
969976 index on the matching periodic point and the periodic marker
970977 index to be communicated to the recv rank. ---*/
971978
972- if (iRank == Neighbors_PeriodicSend[iSend]) {
973- Local_Point_PeriodicSend[ii] = iPoint;
974- Local_Marker_PeriodicSend[ii] = static_cast <unsigned long >(iMarker);
975- jj = ii * nPackets;
976- idSend[jj] = geometry->vertex [iMarker][iVertex]->GetDonorPoint ();
977- jj++;
978- idSend[jj] = static_cast <unsigned long >(iPeriodic);
979- ii++;
979+ if (iRank == destRank) {
980+ /* --- Check if we have already added this (point, marker) pair
981+ for this destination rank. Use the result if insert(), which is
982+ a pair whose second element is success. ---*/
983+ const auto pointMarkerPair = std::make_pair (iPoint, static_cast <unsigned long >(iMarker));
984+ const auto insertResult = Points_Send_All[destRank].insert (pointMarkerPair);
985+ if (insertResult.second ) {
986+ Local_Point_PeriodicSend[ii] = iPoint;
987+ Local_Marker_PeriodicSend[ii] = static_cast <unsigned long >(iMarker);
988+ jj = ii * nPackets;
989+ idSend[jj] = geometry->vertex [iMarker][iVertex]->GetDonorPoint ();
990+ jj++;
991+ idSend[jj] = static_cast <unsigned long >(iPeriodic);
992+ ii++;
993+ }
980994 }
981995 }
982996 }
0 commit comments