LCOV - code coverage report
Current view: top level - src/parallel - ParallelMergeMesh.cpp (source / functions) Hit Total Coverage
Test: coverage_sk.info Lines: 1 324 0.3 %
Date: 2020-12-16 07:07:30 Functions: 2 18 11.1 %
Branches: 2 570 0.4 %

           Branch data     Line data    Source code
       1                 :            : #include "moab/ParallelMergeMesh.hpp"
       2                 :            : #include "moab/Core.hpp"
       3                 :            : #include "moab/CartVect.hpp"
       4                 :            : #include "moab/BoundBox.hpp"
       5                 :            : #include "moab/Skinner.hpp"
       6                 :            : #include "moab/MergeMesh.hpp"
       7                 :            : #include "moab/CN.hpp"
       8                 :            : #include "float.h"
       9                 :            : #include <algorithm>
      10                 :            : 
      11                 :            : #ifdef MOAB_HAVE_MPI
      12                 :            : #include "moab_mpi.h"
      13                 :            : #endif
      14                 :            : 
      15                 :            : namespace moab
      16                 :            : {
      17                 :            : 
      18                 :            : // Constructor
      19                 :            : /*Get Merge Data and tolerance*/
      20 [ #  # ][ #  # ]:          0 : ParallelMergeMesh::ParallelMergeMesh( ParallelComm* pc, const double epsilon ) : myPcomm( pc ), myEps( epsilon )
                 [ #  # ]
      21                 :            : {
      22         [ #  # ]:          0 :     myMB = pc->get_moab();
      23         [ #  # ]:          0 :     mySkinEnts.resize( 4 );
      24                 :          0 : }
      25                 :            : 
      26                 :            : // Have a wrapper function on the actual merge to avoid memory leaks
      27                 :            : // Merges elements within a proximity of epsilon
      28                 :          0 : ErrorCode ParallelMergeMesh::merge( EntityHandle levelset, bool skip_local_merge, int dim )
      29                 :            : {
      30 [ #  # ][ #  # ]:          0 :     ErrorCode rval = PerformMerge( levelset, skip_local_merge, dim );MB_CHK_ERR( rval );
      31                 :          0 :     CleanUp();
      32                 :          0 :     return rval;
      33                 :            : }
      34                 :            : 
      35                 :            : // Perform the merge
      36                 :          0 : ErrorCode ParallelMergeMesh::PerformMerge( EntityHandle levelset, bool skip_local_merge, int dim )
      37                 :            : {
      38                 :            :     // Get the mesh dimension
      39                 :            :     ErrorCode rval;
      40         [ #  # ]:          0 :     if( dim < 0 )
      41                 :            :     {
      42 [ #  # ][ #  # ]:          0 :         rval = myMB->get_dimension( dim );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
      43                 :            :     }
      44                 :            : 
      45                 :            :     // Get the local skin elements
      46         [ #  # ]:          0 :     rval = PopulateMySkinEnts( levelset, dim, skip_local_merge );
      47                 :            :     // If there is only 1 proc, we can return now
      48 [ #  # ][ #  # ]:          0 :     if( rval != MB_SUCCESS || myPcomm->size() == 1 ) { return rval; }
         [ #  # ][ #  # ]
      49                 :            : 
      50                 :            :     // Determine the global bounding box
      51                 :            :     double gbox[6];
      52 [ #  # ][ #  # ]:          0 :     rval = GetGlobalBox( gbox );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
      53                 :            : 
      54                 :            :     /* Assemble The Destination Tuples */
      55                 :            :     // Get a list of tuples which contain (toProc, handle, x,y,z)
      56 [ #  # ][ #  # ]:          0 :     myTup.initialize( 1, 0, 1, 3, mySkinEnts[0].size() );
                 [ #  # ]
      57 [ #  # ][ #  # ]:          0 :     rval = PopulateMyTup( gbox );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
      58                 :            : 
      59                 :            :     /* Gather-Scatter Tuple
      60                 :            :        -tup comes out as (remoteProc,handle,x,y,z) */
      61 [ #  # ][ #  # ]:          0 :     myCD.initialize( myPcomm->comm() );
      62                 :            : 
      63                 :            :     // 1 represents dynamic tuple, 0 represents index of the processor to send to
      64         [ #  # ]:          0 :     myCD.gs_transfer( 1, myTup, 0 );
      65                 :            : 
      66                 :            :     /* Sort By X,Y,Z
      67                 :            :        -Utilizes a custom quick sort incorporating epsilon*/
      68         [ #  # ]:          0 :     SortTuplesByReal( myTup, myEps );
      69                 :            : 
      70                 :            :     // Initialize another tuple list for matches
      71 [ #  # ][ #  # ]:          0 :     myMatches.initialize( 2, 0, 2, 0, mySkinEnts[0].size() );
                 [ #  # ]
      72                 :            : 
      73                 :            :     // ID the matching tuples
      74 [ #  # ][ #  # ]:          0 :     rval = PopulateMyMatches();MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
      75                 :            : 
      76                 :            :     // We can free up the tuple myTup now
      77         [ #  # ]:          0 :     myTup.reset();
      78                 :            : 
      79                 :            :     /*Gather-Scatter Again*/
      80                 :            :     // 1 represents dynamic list, 0 represents proc index to send tuple to
      81         [ #  # ]:          0 :     myCD.gs_transfer( 1, myMatches, 0 );
      82                 :            :     // We can free up the crystal router now
      83         [ #  # ]:          0 :     myCD.reset();
      84                 :            : 
      85                 :            :     // Sort the matches tuple list
      86         [ #  # ]:          0 :     SortMyMatches();
      87                 :            : 
      88                 :            :     // Tag the shared elements
      89 [ #  # ][ #  # ]:          0 :     rval = TagSharedElements( dim );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
      90                 :            : 
      91                 :            :     // Free up the matches tuples
      92         [ #  # ]:          0 :     myMatches.reset();
      93                 :          0 :     return rval;
      94                 :            : }
      95                 :            : 
      96                 :            : // Sets mySkinEnts with all of the skin entities on the processor
      97                 :          0 : ErrorCode ParallelMergeMesh::PopulateMySkinEnts( const EntityHandle meshset, int dim, bool skip_local_merge )
      98                 :            : {
      99                 :            :     /*Merge Mesh Locally*/
     100                 :            :     // Get all dim dimensional entities
     101         [ #  # ]:          0 :     Range ents;
     102 [ #  # ][ #  # ]:          0 :     ErrorCode rval = myMB->get_entities_by_dimension( meshset, dim, ents );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     103                 :            : 
     104 [ #  # ][ #  # ]:          0 :     if( ents.empty() && dim == 3 )
         [ #  # ][ #  # ]
     105                 :            :     {
     106                 :          0 :         dim--;
     107 [ #  # ][ #  # ]:          0 :         rval = myMB->get_entities_by_dimension( meshset, dim, ents );MB_CHK_ERR( rval );  // maybe dimension 2
         [ #  # ][ #  # ]
     108                 :            :     }
     109                 :            : 
     110                 :            :     // Merge Mesh Locally
     111         [ #  # ]:          0 :     if( !skip_local_merge )
     112                 :            :     {
     113         [ #  # ]:          0 :         MergeMesh merger( myMB, false );
     114         [ #  # ]:          0 :         merger.merge_entities( ents, myEps );
     115                 :            :         // We can return if there is only 1 proc
     116 [ #  # ][ #  # ]:          0 :         if( rval != MB_SUCCESS || myPcomm->size() == 1 ) { return rval; }
         [ #  # ][ #  # ]
     117                 :            : 
     118                 :            :         // Rebuild the ents range
     119         [ #  # ]:          0 :         ents.clear();
     120 [ #  # ][ #  # ]:          0 :         rval = myMB->get_entities_by_dimension( meshset, dim, ents );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
     121                 :            :     }
     122                 :            : 
     123                 :            :     /*Get Skin
     124                 :            :       -Get Range of all dimensional entities
     125                 :            :       -skinEnts[i] is the skin entities of dimension i*/
     126         [ #  # ]:          0 :     Skinner skinner( myMB );
     127         [ #  # ]:          0 :     for( int skin_dim = dim; skin_dim >= 0; skin_dim-- )
     128                 :            :     {
     129 [ #  # ][ #  # ]:          0 :         rval = skinner.find_skin( meshset, ents, skin_dim, mySkinEnts[skin_dim] );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
     130                 :            :     }
     131                 :          0 :     return MB_SUCCESS;
     132                 :            : }
     133                 :            : 
     134                 :            : // Determine the global assembly box
     135                 :          0 : ErrorCode ParallelMergeMesh::GetGlobalBox( double* gbox )
     136                 :            : {
     137                 :            :     ErrorCode rval;
     138                 :            : 
     139                 :            :     /*Get Bounding Box*/
     140         [ #  # ]:          0 :     BoundBox box;
     141 [ #  # ][ #  # ]:          0 :     if( mySkinEnts[0].size() != 0 )
                 [ #  # ]
     142                 :            :     {
     143 [ #  # ][ #  # ]:          0 :         rval = box.update( *myMB, mySkinEnts[0] );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
                 [ #  # ]
     144                 :            :     }
     145                 :            : 
     146                 :            :     // Invert the max
     147         [ #  # ]:          0 :     box.bMax *= -1;
     148                 :            : 
     149                 :            :     /*Communicate to all processors*/
     150         [ #  # ]:          0 :     MPI_Allreduce( (void*)&box, gbox, 6, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD );
     151                 :            : 
     152                 :            :     /*Assemble Global Bounding Box*/
     153                 :            :     // Flip the max back
     154         [ #  # ]:          0 :     for( int i = 3; i < 6; i++ )
     155                 :            :     {
     156                 :          0 :         gbox[i] *= -1;
     157                 :            :     }
     158                 :          0 :     return MB_SUCCESS;
     159                 :            : }
     160                 :            : 
     161                 :            : // Assemble the tuples with their processor destination
     162                 :          0 : ErrorCode ParallelMergeMesh::PopulateMyTup( double* gbox )
     163                 :            : {
     164                 :            :     /*Figure out how do partition the global box*/
     165                 :            :     double lengths[3];
     166                 :            :     int parts[3];
     167 [ #  # ][ #  # ]:          0 :     ErrorCode rval = PartitionGlobalBox( gbox, lengths, parts );MB_CHK_ERR( rval );
         [ #  # ][ #  # ]
     168                 :            : 
     169                 :            :     /* Get Skin Coordinates, Vertices */
     170 [ #  # ][ #  # ]:          0 :     double* x = new double[mySkinEnts[0].size()];
         [ #  # ][ #  # ]
     171 [ #  # ][ #  # ]:          0 :     double* y = new double[mySkinEnts[0].size()];
         [ #  # ][ #  # ]
     172 [ #  # ][ #  # ]:          0 :     double* z = new double[mySkinEnts[0].size()];
         [ #  # ][ #  # ]
     173 [ #  # ][ #  # ]:          0 :     rval      = myMB->get_coords( mySkinEnts[0], x, y, z );
     174         [ #  # ]:          0 :     if( rval != MB_SUCCESS )
     175                 :            :     {
     176                 :            :         // Prevent Memory Leak
     177         [ #  # ]:          0 :         delete[] x;
     178         [ #  # ]:          0 :         delete[] y;
     179         [ #  # ]:          0 :         delete[] z;
     180                 :          0 :         return rval;
     181                 :            :     }
     182                 :            : 
     183                 :            :     // Initialize variable to be used in the loops
     184         [ #  # ]:          0 :     std::vector< int > toProcs;
     185                 :            :     int xPart, yPart, zPart, xEps, yEps, zEps, baseProc;
     186                 :          0 :     unsigned long long tup_i = 0, tup_ul = 0, tup_r = 0, count = 0;
     187                 :            :     // These are boolean to determine if the vertex is on close enough to a given border
     188                 :            :     bool xDup, yDup, zDup;
     189         [ #  # ]:          0 :     bool canWrite = myTup.get_writeEnabled();
     190 [ #  # ][ #  # ]:          0 :     if( !canWrite ) myTup.enableWriteAccess();
     191                 :            :     // Go through each vertex
     192 [ #  # ][ #  # ]:          0 :     for( Range::iterator it = mySkinEnts[0].begin(); it != mySkinEnts[0].end(); ++it )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     193                 :            :     {
     194                 :          0 :         xDup = false;
     195                 :          0 :         yDup = false;
     196                 :          0 :         zDup = false;
     197                 :            :         // Figure out which x,y,z partition the element is in.
     198                 :          0 :         xPart = static_cast< int >( floor( ( x[count] - gbox[0] ) / lengths[0] ) );
     199         [ #  # ]:          0 :         xPart = ( xPart < parts[0] ? xPart : parts[0] - 1 );  // Make sure it stays within the bounds
     200                 :            : 
     201                 :          0 :         yPart = static_cast< int >( floor( ( y[count] - gbox[1] ) / lengths[1] ) );
     202         [ #  # ]:          0 :         yPart = ( yPart < parts[1] ? yPart : parts[1] - 1 );  // Make sure it stays within the bounds
     203                 :            : 
     204                 :          0 :         zPart = static_cast< int >( floor( ( z[count] - gbox[2] ) / lengths[2] ) );
     205         [ #  # ]:          0 :         zPart = ( zPart < parts[2] ? zPart : parts[2] - 1 );  // Make sure it stays within the bounds
     206                 :            : 
     207                 :            :         // Figure out the partition with the addition of Epsilon
     208                 :          0 :         xEps = static_cast< int >( floor( ( x[count] - gbox[0] + myEps ) / lengths[0] ) );
     209                 :          0 :         yEps = static_cast< int >( floor( ( y[count] - gbox[1] + myEps ) / lengths[1] ) );
     210                 :          0 :         zEps = static_cast< int >( floor( ( z[count] - gbox[2] + myEps ) / lengths[2] ) );
     211                 :            : 
     212                 :            :         // Figure out if the vertex needs to be sent to multiple procs
     213 [ #  # ][ #  # ]:          0 :         xDup = ( xPart != xEps && xEps < parts[0] );
     214 [ #  # ][ #  # ]:          0 :         yDup = ( yPart != yEps && yEps < parts[1] );
     215 [ #  # ][ #  # ]:          0 :         zDup = ( zPart != zEps && zEps < parts[2] );
     216                 :            : 
     217                 :            :         // Add appropriate processors to the vector
     218                 :          0 :         baseProc = xPart + yPart * parts[0] + zPart * parts[0] * parts[1];
     219         [ #  # ]:          0 :         toProcs.push_back( baseProc );
     220         [ #  # ]:          0 :         if( xDup )
     221                 :            :         {
     222         [ #  # ]:          0 :             toProcs.push_back( baseProc + 1 );  // Get partition to the right
     223                 :            :         }
     224         [ #  # ]:          0 :         if( yDup )
     225                 :            :         {
     226                 :            :             // Partition up 1
     227         [ #  # ]:          0 :             toProcs.push_back( baseProc + parts[0] );
     228                 :            :         }
     229         [ #  # ]:          0 :         if( zDup )
     230                 :            :         {
     231                 :            :             // Partition above 1
     232         [ #  # ]:          0 :             toProcs.push_back( baseProc + parts[0] * parts[1] );
     233                 :            :         }
     234 [ #  # ][ #  # ]:          0 :         if( xDup && yDup )
     235                 :            :         {
     236                 :            :             // Partition up 1 and right 1
     237         [ #  # ]:          0 :             toProcs.push_back( baseProc + parts[0] + 1 );
     238                 :            :         }
     239 [ #  # ][ #  # ]:          0 :         if( xDup && zDup )
     240                 :            :         {
     241                 :            :             // Partition right 1 and above 1
     242         [ #  # ]:          0 :             toProcs.push_back( baseProc + parts[0] * parts[1] + 1 );
     243                 :            :         }
     244 [ #  # ][ #  # ]:          0 :         if( yDup && zDup )
     245                 :            :         {
     246                 :            :             // Partition up 1 and above 1
     247         [ #  # ]:          0 :             toProcs.push_back( baseProc + parts[0] * parts[1] + parts[0] );
     248                 :            :         }
     249 [ #  # ][ #  # ]:          0 :         if( xDup && yDup && zDup )
                 [ #  # ]
     250                 :            :         {
     251                 :            :             // Partition right 1, up 1, and above 1
     252         [ #  # ]:          0 :             toProcs.push_back( baseProc + parts[0] * parts[1] + parts[0] + 1 );
     253                 :            :         }
     254                 :            :         // Grow the tuple list if necessary
     255 [ #  # ][ #  # ]:          0 :         while( myTup.get_n() + toProcs.size() >= myTup.get_max() )
                 [ #  # ]
     256                 :            :         {
     257 [ #  # ][ #  # ]:          0 :             myTup.resize( myTup.get_max() ? myTup.get_max() + myTup.get_max() / 2 + 1 : 2 );
         [ #  # ][ #  # ]
                 [ #  # ]
     258                 :            :         }
     259                 :            : 
     260                 :            :         // Add each proc as a tuple
     261 [ #  # ][ #  # ]:          0 :         for( std::vector< int >::iterator proc = toProcs.begin(); proc != toProcs.end(); ++proc )
                 [ #  # ]
     262                 :            :         {
     263         [ #  # ]:          0 :             myTup.vi_wr[tup_i++]   = *proc;
     264         [ #  # ]:          0 :             myTup.vul_wr[tup_ul++] = *it;
     265                 :          0 :             myTup.vr_wr[tup_r++]   = x[count];
     266                 :          0 :             myTup.vr_wr[tup_r++]   = y[count];
     267                 :          0 :             myTup.vr_wr[tup_r++]   = z[count];
     268         [ #  # ]:          0 :             myTup.inc_n();
     269                 :            :         }
     270                 :          0 :         count++;
     271                 :          0 :         toProcs.clear();
     272                 :            :     }
     273         [ #  # ]:          0 :     delete[] x;
     274         [ #  # ]:          0 :     delete[] y;
     275         [ #  # ]:          0 :     delete[] z;
     276 [ #  # ][ #  # ]:          0 :     if( !canWrite ) myTup.disableWriteAccess();
     277                 :          0 :     return MB_SUCCESS;
     278                 :            : }
     279                 :            : 
     280                 :            : // Partition the global box by the number of procs
     281                 :          0 : ErrorCode ParallelMergeMesh::PartitionGlobalBox( double* gbox, double* lengths, int* parts )
     282                 :            : {
     283                 :            :     // Determine the length of each side
     284                 :          0 :     double xLen       = gbox[3] - gbox[0];
     285                 :          0 :     double yLen       = gbox[4] - gbox[1];
     286                 :          0 :     double zLen       = gbox[5] - gbox[2];
     287                 :          0 :     unsigned numProcs = myPcomm->size();
     288                 :            : 
     289                 :            :     // Partition sides from the longest to shortest lengths
     290                 :            :     // If x is the longest side
     291 [ #  # ][ #  # ]:          0 :     if( xLen >= yLen && xLen >= zLen )
     292                 :            :     {
     293                 :          0 :         parts[0] = PartitionSide( xLen, yLen * zLen, numProcs, true );
     294                 :          0 :         numProcs /= parts[0];
     295                 :            :         // If y is second longest
     296         [ #  # ]:          0 :         if( yLen >= zLen )
     297                 :            :         {
     298                 :          0 :             parts[1] = PartitionSide( yLen, zLen, numProcs, false );
     299                 :          0 :             parts[2] = numProcs / parts[1];
     300                 :            :         }
     301                 :            :         // If z is the longer
     302                 :            :         else
     303                 :            :         {
     304                 :          0 :             parts[2] = PartitionSide( zLen, yLen, numProcs, false );
     305                 :          0 :             parts[1] = numProcs / parts[2];
     306                 :            :         }
     307                 :            :     }
     308                 :            :     // If y is the longest side
     309         [ #  # ]:          0 :     else if( yLen >= zLen )
     310                 :            :     {
     311                 :          0 :         parts[1] = PartitionSide( yLen, xLen * zLen, numProcs, true );
     312                 :          0 :         numProcs /= parts[1];
     313                 :            :         // If x is the second longest
     314         [ #  # ]:          0 :         if( xLen >= zLen )
     315                 :            :         {
     316                 :          0 :             parts[0] = PartitionSide( xLen, zLen, numProcs, false );
     317                 :          0 :             parts[2] = numProcs / parts[0];
     318                 :            :         }
     319                 :            :         // If z is the second longest
     320                 :            :         else
     321                 :            :         {
     322                 :          0 :             parts[2] = PartitionSide( zLen, xLen, numProcs, false );
     323                 :          0 :             parts[0] = numProcs / parts[2];
     324                 :            :         }
     325                 :            :     }
     326                 :            :     // If z is the longest side
     327                 :            :     else
     328                 :            :     {
     329                 :          0 :         parts[2] = PartitionSide( zLen, xLen * yLen, numProcs, true );
     330                 :          0 :         numProcs /= parts[2];
     331                 :            :         // If x is the second longest
     332         [ #  # ]:          0 :         if( xLen >= yLen )
     333                 :            :         {
     334                 :          0 :             parts[0] = PartitionSide( xLen, yLen, numProcs, false );
     335                 :          0 :             parts[1] = numProcs / parts[0];
     336                 :            :         }
     337                 :            :         // If y is the second longest
     338                 :            :         else
     339                 :            :         {
     340                 :          0 :             parts[1] = PartitionSide( yLen, xLen, numProcs, false );
     341                 :          0 :             parts[0] = numProcs / parts[1];
     342                 :            :         }
     343                 :            :     }
     344                 :            : 
     345                 :            :     // Divide up each side to give the lengths
     346                 :          0 :     lengths[0] = xLen / (double)parts[0];
     347                 :          0 :     lengths[1] = yLen / (double)parts[1];
     348                 :          0 :     lengths[2] = zLen / (double)parts[2];
     349                 :          0 :     return MB_SUCCESS;
     350                 :            : }
     351                 :            : 
     352                 :            : // Partition a side based on the length ratios
     353                 :          0 : int ParallelMergeMesh::PartitionSide( double sideLen, double restLen, unsigned numProcs, bool altRatio )
     354                 :            : {
     355                 :            :     // If theres only 1 processor, then just return 1
     356         [ #  # ]:          0 :     if( numProcs == 1 ) { return 1; }
     357                 :            :     // Initialize with the ratio of 1 proc
     358                 :          0 :     double ratio    = -DBL_MAX;
     359                 :          0 :     unsigned factor = 1;
     360                 :            :     // We need to be able to save the last ratio and factor (for comparison)
     361                 :          0 :     double oldRatio  = ratio;
     362                 :          0 :     double oldFactor = 1;
     363                 :            : 
     364                 :            :     // This is the ratio were shooting for
     365                 :          0 :     double goalRatio = sideLen / restLen;
     366                 :            : 
     367                 :            :     // Calculate the divisor and numerator power
     368                 :            :     // This avoid if statements in the loop and is useful since both calculations are similar
     369                 :            :     double divisor, p;
     370         [ #  # ]:          0 :     if( altRatio )
     371                 :            :     {
     372                 :          0 :         divisor = (double)numProcs * sideLen;
     373                 :          0 :         p       = 3;
     374                 :            :     }
     375                 :            :     else
     376                 :            :     {
     377                 :          0 :         divisor = (double)numProcs;
     378                 :          0 :         p       = 2;
     379                 :            :     }
     380                 :            : 
     381                 :            :     // Find each possible factor
     382         [ #  # ]:          0 :     for( unsigned i = 2; i <= numProcs / 2; i++ )
     383                 :            :     {
     384                 :            :         // If it is a factor...
     385         [ #  # ]:          0 :         if( numProcs % i == 0 )
     386                 :            :         {
     387                 :            :             // We need to save the past factor
     388                 :          0 :             oldRatio  = ratio;
     389                 :          0 :             oldFactor = factor;
     390                 :            :             // There are 2 different ways to calculate the ratio:
     391                 :            :             // Comparing 1 side to 2 sides: (i*i*i)/(numProcs*x)
     392                 :            :             // Justification:  We have a ratio x:y:z (side Lengths) == a:b:c (procs).  So a=kx,
     393                 :            :             // b=ky, c=kz. Also, abc=n (numProcs) => bc = n/a.  Also, a=kx => k=a/x => 1/k=x/a And so
     394                 :            :             // x/(yz) == (kx)/(kyz) == (kx)/(kykz(1/k)) == a/(bc(x/a)) == a/((n/a)(x/a)) == a^3/(nx).
     395                 :            :             // Comparing 1 side to 1 side: (i*i)/numprocs
     396                 :            :             // Justification: i/(n/i) == i^2/n
     397                 :          0 :             ratio  = pow( (double)i, p ) / divisor;
     398                 :          0 :             factor = i;
     399                 :            :             // Once we have passed the goal ratio, we can break since we'll only move away from the
     400                 :            :             // goal ratio
     401         [ #  # ]:          0 :             if( ratio >= goalRatio ) { break; }
     402                 :            :         }
     403                 :            :     }
     404                 :            :     // If we haven't reached the goal ratio yet, check out factor = numProcs
     405         [ #  # ]:          0 :     if( ratio < goalRatio )
     406                 :            :     {
     407                 :          0 :         oldRatio  = ratio;
     408                 :          0 :         oldFactor = factor;
     409                 :          0 :         factor    = numProcs;
     410                 :          0 :         ratio     = pow( (double)numProcs, p ) / divisor;
     411                 :            :     }
     412                 :            : 
     413                 :            :     // Figure out if our oldRatio is better than ratio
     414         [ #  # ]:          0 :     if( fabs( ratio - goalRatio ) > fabs( oldRatio - goalRatio ) ) { factor = oldFactor; }
     415                 :            :     // Return our findings
     416                 :          0 :     return factor;
     417                 :            : }
     418                 :            : 
     419                 :            : // Id the tuples that are matching
     420                 :          0 : ErrorCode ParallelMergeMesh::PopulateMyMatches()
     421                 :            : {
     422                 :            :     // Counters for accessing tuples more efficiently
     423                 :          0 :     unsigned long i = 0, mat_i = 0, mat_ul = 0, j = 0, tup_r = 0;
     424                 :          0 :     double eps2 = myEps * myEps;
     425                 :            : 
     426                 :            :     uint tup_mi, tup_ml, tup_mul, tup_mr;
     427         [ #  # ]:          0 :     myTup.getTupleSize( tup_mi, tup_ml, tup_mul, tup_mr );
     428                 :            : 
     429         [ #  # ]:          0 :     bool canWrite = myMatches.get_writeEnabled();
     430 [ #  # ][ #  # ]:          0 :     if( !canWrite ) myMatches.enableWriteAccess();
     431                 :            : 
     432 [ #  # ][ #  # ]:          0 :     while( ( i + 1 ) < myTup.get_n() )
     433                 :            :     {
     434                 :            :         // Proximity Comparison
     435                 :          0 :         double xi = myTup.vr_rd[tup_r], yi = myTup.vr_rd[tup_r + 1], zi = myTup.vr_rd[tup_r + 2];
     436                 :            : 
     437                 :          0 :         bool done = false;
     438         [ #  # ]:          0 :         while( !done )
     439                 :            :         {
     440                 :          0 :             j++;
     441                 :          0 :             tup_r += tup_mr;
     442 [ #  # ][ #  # ]:          0 :             if( j >= myTup.get_n() ) { break; }
     443         [ #  # ]:          0 :             CartVect cv( myTup.vr_rd[tup_r] - xi, myTup.vr_rd[tup_r + 1] - yi, myTup.vr_rd[tup_r + 2] - zi );
     444 [ #  # ][ #  # ]:          0 :             if( cv.length_squared() > eps2 ) { done = true; }
     445                 :            :         }
     446                 :            :         // Allocate the tuple list before adding matches
     447 [ #  # ][ #  # ]:          0 :         while( myMatches.get_n() + ( j - i ) * ( j - i - 1 ) >= myMatches.get_max() )
                 [ #  # ]
     448                 :            :         {
     449 [ #  # ][ #  # ]:          0 :             myMatches.resize( myMatches.get_max() ? myMatches.get_max() + myMatches.get_max() / 2 + 1 : 2 );
         [ #  # ][ #  # ]
                 [ #  # ]
     450                 :            :         }
     451                 :            : 
     452                 :            :         // We now know that tuples [i to j) exclusive match.
     453                 :            :         // If n tuples match, n*(n-1) match tuples will be made
     454                 :            :         // tuples are of the form (proc1,proc2,handle1,handle2)
     455         [ #  # ]:          0 :         if( i + 1 < j )
     456                 :            :         {
     457                 :          0 :             int kproc           = i * tup_mi;
     458                 :          0 :             unsigned long khand = i * tup_mul;
     459         [ #  # ]:          0 :             for( unsigned long k = i; k < j; k++ )
     460                 :            :             {
     461                 :          0 :                 int lproc           = kproc + tup_mi;
     462                 :          0 :                 unsigned long lhand = khand + tup_mul;
     463         [ #  # ]:          0 :                 for( unsigned long l = k + 1; l < j; l++ )
     464                 :            :                 {
     465                 :          0 :                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[kproc];   // proc1
     466                 :          0 :                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[lproc];   // proc2
     467                 :          0 :                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[khand];  // handle1
     468                 :          0 :                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[lhand];  // handle2
     469         [ #  # ]:          0 :                     myMatches.inc_n();
     470                 :            : 
     471                 :          0 :                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[lproc];   // proc1
     472                 :          0 :                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[kproc];   // proc2
     473                 :          0 :                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[lhand];  // handle1
     474                 :          0 :                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[khand];  // handle2
     475         [ #  # ]:          0 :                     myMatches.inc_n();
     476                 :          0 :                     lproc += tup_mi;
     477                 :          0 :                     lhand += tup_mul;
     478                 :            :                 }
     479                 :          0 :                 kproc += tup_mi;
     480                 :          0 :                 khand += tup_mul;
     481                 :            :             }  // End for(int k...
     482                 :            :         }
     483                 :          0 :         i = j;
     484                 :            :     }  // End while(i+1<tup.n)
     485                 :            : 
     486 [ #  # ][ #  # ]:          0 :     if( !canWrite ) myMatches.disableWriteAccess();
     487                 :          0 :     return MB_SUCCESS;
     488                 :            : }
     489                 :            : 
     490                 :            : // Sort the matching tuples so that vertices can be tagged accurately
     491                 :          0 : ErrorCode ParallelMergeMesh::SortMyMatches()
     492                 :            : {
     493 [ #  # ][ #  # ]:          0 :     TupleList::buffer buf( mySkinEnts[0].size() );
                 [ #  # ]
     494                 :            :     // Sorts are necessary to check for doubles
     495                 :            :     // Sort by remote handle
     496         [ #  # ]:          0 :     myMatches.sort( 3, &buf );
     497                 :            :     // Sort by matching proc
     498         [ #  # ]:          0 :     myMatches.sort( 1, &buf );
     499                 :            :     // Sort by local handle
     500         [ #  # ]:          0 :     myMatches.sort( 2, &buf );
     501         [ #  # ]:          0 :     buf.reset();
     502                 :          0 :     return MB_SUCCESS;
     503                 :            : }
     504                 :            : 
     505                 :            : // Tag the shared elements using existing PComm functionality
     506                 :          0 : ErrorCode ParallelMergeMesh::TagSharedElements( int dim )
     507                 :            : {
     508                 :            :     // Manipulate the matches list to tag vertices and entities
     509                 :            :     // Set up proc ents
     510         [ #  # ]:          0 :     Range proc_ents;
     511                 :            :     ErrorCode rval;
     512                 :            : 
     513                 :            :     // get the entities in the partition sets
     514 [ #  # ][ #  # ]:          0 :     for( Range::iterator rit = myPcomm->partitionSets.begin(); rit != myPcomm->partitionSets.end(); ++rit )
         [ #  # ][ #  # ]
                 [ #  # ]
     515                 :            :     {
     516         [ #  # ]:          0 :         Range tmp_ents;
     517 [ #  # ][ #  # ]:          0 :         rval = myMB->get_entities_by_handle( *rit, tmp_ents, true );
     518         [ #  # ]:          0 :         if( MB_SUCCESS != rval ) { return rval; }
     519 [ #  # ][ #  # ]:          0 :         proc_ents.merge( tmp_ents );
     520                 :          0 :     }
     521 [ #  # ][ #  # ]:          0 :     if( myMB->dimension_from_handle( *proc_ents.rbegin() ) != myMB->dimension_from_handle( *proc_ents.begin() ) )
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     522                 :            :     {
     523         [ #  # ]:          0 :         Range::iterator lower = proc_ents.lower_bound( CN::TypeDimensionMap[0].first ),
     524         [ #  # ]:          0 :                         upper = proc_ents.upper_bound( CN::TypeDimensionMap[dim - 1].second );
     525         [ #  # ]:          0 :         proc_ents.erase( lower, upper );
     526                 :            :     }
     527                 :            : 
     528                 :            :     // This vector doesn't appear to be used but its in resolve_shared_ents
     529                 :          0 :     int maxp = -1;
     530         [ #  # ]:          0 :     std::vector< int > sharing_procs( MAX_SHARING_PROCS );
     531         [ #  # ]:          0 :     std::fill( sharing_procs.begin(), sharing_procs.end(), maxp );
     532                 :            : 
     533                 :            :     // get ents shared by 1 or n procs
     534         [ #  # ]:          0 :     std::map< std::vector< int >, std::vector< EntityHandle > > proc_nranges;
     535         [ #  # ]:          0 :     Range proc_verts;
     536         [ #  # ]:          0 :     rval = myMB->get_adjacencies( proc_ents, 0, false, proc_verts, Interface::UNION );
     537         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) { return rval; }
     538                 :            : 
     539         [ #  # ]:          0 :     rval = myPcomm->tag_shared_verts( myMatches, proc_nranges, proc_verts );
     540         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) { return rval; }
     541                 :            : 
     542                 :            :     // get entities shared by 1 or n procs
     543 [ #  # ][ #  # ]:          0 :     rval = myPcomm->get_proc_nvecs( dim, dim - 1, &mySkinEnts[0], proc_nranges );
     544         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) { return rval; }
     545                 :            : 
     546                 :            :     // create the sets for each interface; store them as tags on
     547                 :            :     // the interface instance
     548         [ #  # ]:          0 :     Range iface_sets;
     549         [ #  # ]:          0 :     rval = myPcomm->create_interface_sets( proc_nranges );
     550         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) { return rval; }
     551                 :            :     // establish comm procs and buffers for them
     552         [ #  # ]:          0 :     std::set< unsigned int > procs;
     553         [ #  # ]:          0 :     rval = myPcomm->get_interface_procs( procs, true );
     554         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) { return rval; }
     555                 :            : 
     556                 :            :     // resolve shared entity remote handles; implemented in ghost cell exchange
     557                 :            :     // code because it's so similar
     558         [ #  # ]:          0 :     rval = myPcomm->exchange_ghost_cells( -1, -1, 0, true, true );
     559         [ #  # ]:          0 :     if( rval != MB_SUCCESS ) { return rval; }
     560                 :            :     // now build parent/child links for interface sets
     561         [ #  # ]:          0 :     rval = myPcomm->create_iface_pc_links();
     562                 :          0 :     return rval;
     563                 :            : }
     564                 :            : 
     565                 :            : // Make sure to free up any allocated data
     566                 :            : // Need to avoid a double free
     567                 :          0 : void ParallelMergeMesh::CleanUp()
     568                 :            : {
     569                 :            :     // The reset operation is now safe and avoids a double free()
     570                 :          0 :     myMatches.reset();
     571                 :          0 :     myTup.reset();
     572                 :          0 :     myCD.reset();
     573                 :          0 : }
     574                 :            : 
     575                 :            : // Simple quick  sort to real
     576                 :          0 : void ParallelMergeMesh::SortTuplesByReal( TupleList& tup, double eps )
     577                 :            : {
     578         [ #  # ]:          0 :     bool canWrite = tup.get_writeEnabled();
     579 [ #  # ][ #  # ]:          0 :     if( !canWrite ) tup.enableWriteAccess();
     580                 :            : 
     581                 :            :     uint mi, ml, mul, mr;
     582         [ #  # ]:          0 :     tup.getTupleSize( mi, ml, mul, mr );
     583 [ #  # ][ #  # ]:          0 :     PerformRealSort( tup, 0, tup.get_n(), eps, mr );
     584                 :            : 
     585 [ #  # ][ #  # ]:          0 :     if( !canWrite ) tup.disableWriteAccess();
     586                 :          0 : }
     587                 :            : 
     588                 :            : // Swap around tuples
     589                 :          0 : void ParallelMergeMesh::SwapTuples( TupleList& tup, unsigned long a, unsigned long b )
     590                 :            : {
     591         [ #  # ]:          0 :     if( a == b ) return;
     592                 :            : 
     593                 :            :     uint mi, ml, mul, mr;
     594         [ #  # ]:          0 :     tup.getTupleSize( mi, ml, mul, mr );
     595                 :            : 
     596                 :            :     // Swap mi
     597                 :          0 :     unsigned long a_val = a * mi, b_val = b * mi;
     598         [ #  # ]:          0 :     for( unsigned long i = 0; i < mi; i++ )
     599                 :            :     {
     600                 :          0 :         sint t           = tup.vi_rd[a_val];
     601                 :          0 :         tup.vi_wr[a_val] = tup.vi_rd[b_val];
     602                 :          0 :         tup.vi_wr[b_val] = t;
     603                 :          0 :         a_val++;
     604                 :          0 :         b_val++;
     605                 :            :     }
     606                 :            :     // Swap ml
     607                 :          0 :     a_val = a * ml;
     608                 :          0 :     b_val = b * ml;
     609         [ #  # ]:          0 :     for( unsigned long i = 0; i < ml; i++ )
     610                 :            :     {
     611                 :          0 :         slong t          = tup.vl_rd[a_val];
     612                 :          0 :         tup.vl_wr[a_val] = tup.vl_rd[b_val];
     613                 :          0 :         tup.vl_wr[b_val] = t;
     614                 :          0 :         a_val++;
     615                 :          0 :         b_val++;
     616                 :            :     }
     617                 :            :     // Swap mul
     618                 :          0 :     a_val = a * mul;
     619                 :          0 :     b_val = b * mul;
     620         [ #  # ]:          0 :     for( unsigned long i = 0; i < mul; i++ )
     621                 :            :     {
     622                 :          0 :         Ulong t           = tup.vul_rd[a_val];
     623                 :          0 :         tup.vul_wr[a_val] = tup.vul_rd[b_val];
     624                 :          0 :         tup.vul_wr[b_val] = t;
     625                 :          0 :         a_val++;
     626                 :          0 :         b_val++;
     627                 :            :     }
     628                 :            :     // Swap mr
     629                 :          0 :     a_val = a * mr;
     630                 :          0 :     b_val = b * mr;
     631         [ #  # ]:          0 :     for( unsigned long i = 0; i < mr; i++ )
     632                 :            :     {
     633                 :          0 :         realType t       = tup.vr_rd[a_val];
     634                 :          0 :         tup.vr_wr[a_val] = tup.vr_rd[b_val];
     635                 :          0 :         tup.vr_wr[b_val] = t;
     636                 :          0 :         a_val++;
     637                 :          0 :         b_val++;
     638                 :            :     }
     639                 :            : }
     640                 :            : 
     641                 :            : // Perform the sorting of a tuple by real
     642                 :            : // To sort an entire tuple_list, call (tup,0,tup.n,epsilon)
     643                 :          0 : void ParallelMergeMesh::PerformRealSort( TupleList& tup, unsigned long left, unsigned long right, double eps,
     644                 :            :                                          uint tup_mr )
     645                 :            : {
     646                 :            :     // If list size is only 1 or 0 return
     647         [ #  # ]:          0 :     if( left + 1 >= right ) { return; }
     648                 :          0 :     unsigned long swap = left, tup_l = left * tup_mr, tup_t = tup_l + tup_mr;
     649                 :            : 
     650                 :            :     // Swap the median with the left position for a (hopefully) better split
     651                 :          0 :     SwapTuples( tup, left, ( left + right ) / 2 );
     652                 :            : 
     653                 :            :     // Partition the data
     654         [ #  # ]:          0 :     for( unsigned long t = left + 1; t < right; t++ )
     655                 :            :     {
     656                 :            :         // If the left value(pivot) is greater than t_val, swap it into swap
     657         [ #  # ]:          0 :         if( TupleGreaterThan( tup, tup_l, tup_t, eps, tup_mr ) )
     658                 :            :         {
     659                 :          0 :             swap++;
     660                 :          0 :             SwapTuples( tup, swap, t );
     661                 :            :         }
     662                 :          0 :         tup_t += tup_mr;
     663                 :            :     }
     664                 :            : 
     665                 :            :     // Swap so that position swap is in the correct position
     666                 :          0 :     SwapTuples( tup, left, swap );
     667                 :            : 
     668                 :            :     // Sort left and right of swap
     669                 :          0 :     PerformRealSort( tup, left, swap, eps, tup_mr );
     670                 :          0 :     PerformRealSort( tup, swap + 1, right, eps, tup_mr );
     671                 :            : }
     672                 :            : 
     673                 :            : // Note, this takes the actual tup.vr[] index (aka i*tup.mr)
     674                 :          0 : bool ParallelMergeMesh::TupleGreaterThan( TupleList& tup, unsigned long vrI, unsigned long vrJ, double eps,
     675                 :            :                                           uint tup_mr )
     676                 :            : {
     677                 :          0 :     unsigned check = 0;
     678         [ #  # ]:          0 :     while( check < tup_mr )
     679                 :            :     {
     680                 :            :         // If the values are the same
     681         [ #  # ]:          0 :         if( fabs( tup.vr_rd[vrI + check] - tup.vr_rd[vrJ + check] ) <= eps )
     682                 :            :         {
     683                 :          0 :             check++;
     684                 :          0 :             continue;
     685                 :            :         }
     686                 :            :         // If I greater than J
     687         [ #  # ]:          0 :         else if( tup.vr_rd[vrI + check] > tup.vr_rd[vrJ + check] )
     688                 :            :         {
     689                 :          0 :             return true;
     690                 :            :         }
     691                 :            :         // If J greater than I
     692                 :            :         else
     693                 :            :         {
     694                 :          0 :             return false;
     695                 :            :         }
     696                 :            :     }
     697                 :            :     // All Values are the same
     698                 :          0 :     return false;
     699                 :            : }
     700                 :            : 
     701 [ +  - ][ +  - ]:        228 : }  // End namespace moab

Generated by: LCOV version 1.11