MOAB: Mesh Oriented datABase  (version 5.4.1)
ParallelMergeMesh.cpp
Go to the documentation of this file.
00001 #include "moab/ParallelMergeMesh.hpp"
00002 #include "moab/Core.hpp"
00003 #include "moab/CartVect.hpp"
00004 #include "moab/BoundBox.hpp"
00005 #include "moab/Skinner.hpp"
00006 #include "moab/MergeMesh.hpp"
00007 #include "moab/CN.hpp"
00008 #include <cfloat>
00009 #include <algorithm>
00010 
00011 #ifdef MOAB_HAVE_MPI
00012 #include "moab_mpi.h"
00013 #endif
00014 
00015 namespace moab
00016 {
00017 
00018 // Constructor
00019 /*Get Merge Data and tolerance*/
00020 ParallelMergeMesh::ParallelMergeMesh( ParallelComm* pc, const double epsilon ) : myPcomm( pc ), myEps( epsilon )
00021 {
00022     myMB = pc->get_moab();
00023     mySkinEnts.resize( 4 );
00024 }
00025 
00026 // Have a wrapper function on the actual merge to avoid memory leaks
00027 // Merges elements within a proximity of epsilon
00028 ErrorCode ParallelMergeMesh::merge( EntityHandle levelset, bool skip_local_merge, int dim )
00029 {
00030     ErrorCode rval = PerformMerge( levelset, skip_local_merge, dim );MB_CHK_ERR( rval );
00031     CleanUp();
00032     return rval;
00033 }
00034 
00035 // Perform the merge
00036 ErrorCode ParallelMergeMesh::PerformMerge( EntityHandle levelset, bool skip_local_merge, int dim )
00037 {
00038     // Get the mesh dimension
00039     ErrorCode rval;
00040     if( dim < 0 )
00041     {
00042         rval = myMB->get_dimension( dim );MB_CHK_ERR( rval );
00043     }
00044 
00045     // Get the local skin elements
00046     rval = PopulateMySkinEnts( levelset, dim, skip_local_merge );
00047     // If there is only 1 proc, we can return now
00048     if( rval != MB_SUCCESS || myPcomm->size() == 1 )
00049     {
00050         return rval;
00051     }
00052 
00053     // Determine the global bounding box
00054     double gbox[6];
00055     rval = GetGlobalBox( gbox );MB_CHK_ERR( rval );
00056 
00057     /* Assemble The Destination Tuples */
00058     // Get a list of tuples which contain (toProc, handle, x,y,z)
00059     myTup.initialize( 1, 0, 1, 3, mySkinEnts[0].size() );
00060     rval = PopulateMyTup( gbox );MB_CHK_ERR( rval );
00061 
00062     /* Gather-Scatter Tuple
00063        -tup comes out as (remoteProc,handle,x,y,z) */
00064     myCD.initialize( myPcomm->comm() );
00065 
00066     // 1 represents dynamic tuple, 0 represents index of the processor to send to
00067     myCD.gs_transfer( 1, myTup, 0 );
00068 
00069     /* Sort By X,Y,Z
00070        -Utilizes a custom quick sort incorporating epsilon*/
00071     SortTuplesByReal( myTup, myEps );
00072 
00073     // Initialize another tuple list for matches
00074     myMatches.initialize( 2, 0, 2, 0, mySkinEnts[0].size() );
00075 
00076     // ID the matching tuples
00077     rval = PopulateMyMatches();MB_CHK_ERR( rval );
00078 
00079     // We can free up the tuple myTup now
00080     myTup.reset();
00081 
00082     /*Gather-Scatter Again*/
00083     // 1 represents dynamic list, 0 represents proc index to send tuple to
00084     myCD.gs_transfer( 1, myMatches, 0 );
00085     // We can free up the crystal router now
00086     myCD.reset();
00087 
00088     // Sort the matches tuple list
00089     SortMyMatches();
00090 
00091     // Tag the shared elements
00092     rval = TagSharedElements( dim );MB_CHK_ERR( rval );
00093 
00094     // Free up the matches tuples
00095     myMatches.reset();
00096     return rval;
00097 }
00098 
00099 // Sets mySkinEnts with all of the skin entities on the processor
00100 ErrorCode ParallelMergeMesh::PopulateMySkinEnts( const EntityHandle meshset, int dim, bool skip_local_merge )
00101 {
00102     /*Merge Mesh Locally*/
00103     // Get all dim dimensional entities
00104     Range ents;
00105     ErrorCode rval = myMB->get_entities_by_dimension( meshset, dim, ents );MB_CHK_ERR( rval );
00106 
00107     if( ents.empty() && dim == 3 )
00108     {
00109         dim--;
00110         rval = myMB->get_entities_by_dimension( meshset, dim, ents );MB_CHK_ERR( rval );  // maybe dimension 2
00111     }
00112 
00113     // Merge Mesh Locally
00114     if( !skip_local_merge )
00115     {
00116         MergeMesh merger( myMB, false );
00117         merger.merge_entities( ents, myEps );
00118         // We can return if there is only 1 proc
00119         if( rval != MB_SUCCESS || myPcomm->size() == 1 )
00120         {
00121             return rval;
00122         }
00123 
00124         // Rebuild the ents range
00125         ents.clear();
00126         rval = myMB->get_entities_by_dimension( meshset, dim, ents );MB_CHK_ERR( rval );
00127     }
00128 
00129     /*Get Skin
00130       -Get Range of all dimensional entities
00131       -skinEnts[i] is the skin entities of dimension i*/
00132     Skinner skinner( myMB );
00133     for( int skin_dim = dim; skin_dim >= 0; skin_dim-- )
00134     {
00135         rval = skinner.find_skin( meshset, ents, skin_dim, mySkinEnts[skin_dim] );MB_CHK_ERR( rval );
00136     }
00137     return MB_SUCCESS;
00138 }
00139 
00140 // Determine the global assembly box
00141 ErrorCode ParallelMergeMesh::GetGlobalBox( double* gbox )
00142 {
00143     ErrorCode rval;
00144 
00145     /*Get Bounding Box*/
00146     BoundBox box;
00147     if( mySkinEnts[0].size() != 0 )
00148     {
00149         rval = box.update( *myMB, mySkinEnts[0] );MB_CHK_ERR( rval );
00150     }
00151 
00152     // Invert the max
00153     box.bMax *= -1;
00154 
00155     /*Communicate to all processors*/
00156     MPI_Allreduce( (void*)&box, gbox, 6, MPI_DOUBLE, MPI_MIN, myPcomm->comm() );
00157 
00158     /*Assemble Global Bounding Box*/
00159     // Flip the max back
00160     for( int i = 3; i < 6; i++ )
00161     {
00162         gbox[i] *= -1;
00163     }
00164     return MB_SUCCESS;
00165 }
00166 
00167 // Assemble the tuples with their processor destination
00168 ErrorCode ParallelMergeMesh::PopulateMyTup( double* gbox )
00169 {
00170     /*Figure out how do partition the global box*/
00171     double lengths[3];
00172     int parts[3];
00173     ErrorCode rval = PartitionGlobalBox( gbox, lengths, parts );MB_CHK_ERR( rval );
00174 
00175     /* Get Skin Coordinates, Vertices */
00176     double* x = new double[mySkinEnts[0].size()];
00177     double* y = new double[mySkinEnts[0].size()];
00178     double* z = new double[mySkinEnts[0].size()];
00179     rval      = myMB->get_coords( mySkinEnts[0], x, y, z );
00180     if( rval != MB_SUCCESS )
00181     {
00182         // Prevent Memory Leak
00183         delete[] x;
00184         delete[] y;
00185         delete[] z;
00186         return rval;
00187     }
00188 
00189     // Initialize variable to be used in the loops
00190     std::vector< int > toProcs;
00191     int xPart, yPart, zPart, xEps, yEps, zEps, baseProc;
00192     unsigned long long tup_i = 0, tup_ul = 0, tup_r = 0, count = 0;
00193     // These are boolean to determine if the vertex is on close enough to a given border
00194     bool xDup, yDup, zDup;
00195     bool canWrite = myTup.get_writeEnabled();
00196     if( !canWrite ) myTup.enableWriteAccess();
00197     // Go through each vertex
00198     for( Range::iterator it = mySkinEnts[0].begin(); it != mySkinEnts[0].end(); ++it )
00199     {
00200         xDup = false;
00201         yDup = false;
00202         zDup = false;
00203         // Figure out which x,y,z partition the element is in.
00204         xPart = static_cast< int >( floor( ( x[count] - gbox[0] ) / lengths[0] ) );
00205         xPart = ( xPart < parts[0] ? xPart : parts[0] - 1 );  // Make sure it stays within the bounds
00206 
00207         yPart = static_cast< int >( floor( ( y[count] - gbox[1] ) / lengths[1] ) );
00208         yPart = ( yPart < parts[1] ? yPart : parts[1] - 1 );  // Make sure it stays within the bounds
00209 
00210         zPart = static_cast< int >( floor( ( z[count] - gbox[2] ) / lengths[2] ) );
00211         zPart = ( zPart < parts[2] ? zPart : parts[2] - 1 );  // Make sure it stays within the bounds
00212 
00213         // Figure out the partition with the addition of Epsilon
00214         xEps = static_cast< int >( floor( ( x[count] - gbox[0] + myEps ) / lengths[0] ) );
00215         yEps = static_cast< int >( floor( ( y[count] - gbox[1] + myEps ) / lengths[1] ) );
00216         zEps = static_cast< int >( floor( ( z[count] - gbox[2] + myEps ) / lengths[2] ) );
00217 
00218         // Figure out if the vertex needs to be sent to multiple procs
00219         xDup = ( xPart != xEps && xEps < parts[0] );
00220         yDup = ( yPart != yEps && yEps < parts[1] );
00221         zDup = ( zPart != zEps && zEps < parts[2] );
00222 
00223         // Add appropriate processors to the vector
00224         baseProc = xPart + yPart * parts[0] + zPart * parts[0] * parts[1];
00225         toProcs.push_back( baseProc );
00226         if( xDup )
00227         {
00228             toProcs.push_back( baseProc + 1 );  // Get partition to the right
00229         }
00230         if( yDup )
00231         {
00232             // Partition up 1
00233             toProcs.push_back( baseProc + parts[0] );
00234         }
00235         if( zDup )
00236         {
00237             // Partition above 1
00238             toProcs.push_back( baseProc + parts[0] * parts[1] );
00239         }
00240         if( xDup && yDup )
00241         {
00242             // Partition up 1 and right 1
00243             toProcs.push_back( baseProc + parts[0] + 1 );
00244         }
00245         if( xDup && zDup )
00246         {
00247             // Partition right 1 and above 1
00248             toProcs.push_back( baseProc + parts[0] * parts[1] + 1 );
00249         }
00250         if( yDup && zDup )
00251         {
00252             // Partition up 1 and above 1
00253             toProcs.push_back( baseProc + parts[0] * parts[1] + parts[0] );
00254         }
00255         if( xDup && yDup && zDup )
00256         {
00257             // Partition right 1, up 1, and above 1
00258             toProcs.push_back( baseProc + parts[0] * parts[1] + parts[0] + 1 );
00259         }
00260         // Grow the tuple list if necessary
00261         while( myTup.get_n() + toProcs.size() >= myTup.get_max() )
00262         {
00263             myTup.resize( myTup.get_max() ? myTup.get_max() + myTup.get_max() / 2 + 1 : 2 );
00264         }
00265 
00266         // Add each proc as a tuple
00267         for( std::vector< int >::iterator proc = toProcs.begin(); proc != toProcs.end(); ++proc )
00268         {
00269             myTup.vi_wr[tup_i++]   = *proc;
00270             myTup.vul_wr[tup_ul++] = *it;
00271             myTup.vr_wr[tup_r++]   = x[count];
00272             myTup.vr_wr[tup_r++]   = y[count];
00273             myTup.vr_wr[tup_r++]   = z[count];
00274             myTup.inc_n();
00275         }
00276         count++;
00277         toProcs.clear();
00278     }
00279     delete[] x;
00280     delete[] y;
00281     delete[] z;
00282     if( !canWrite ) myTup.disableWriteAccess();
00283     return MB_SUCCESS;
00284 }
00285 
00286 // Partition the global box by the number of procs
00287 ErrorCode ParallelMergeMesh::PartitionGlobalBox( double* gbox, double* lengths, int* parts )
00288 {
00289     // Determine the length of each side
00290     double xLen       = gbox[3] - gbox[0];
00291     double yLen       = gbox[4] - gbox[1];
00292     double zLen       = gbox[5] - gbox[2];
00293     // avoid division by zero for deciding the way to partition the global box
00294     // make all sides of the box at least myEps
00295     // it can be zero in some cases, so not possible to compare the ratios :) for best division
00296     if (xLen < myEps) xLen = myEps;
00297     if (yLen < myEps) yLen = myEps;
00298     if (zLen < myEps) zLen = myEps;
00299     unsigned numProcs = myPcomm->size();
00300 
00301     // Partition sides from the longest to shortest lengths
00302     // If x is the longest side
00303     if( xLen >= yLen && xLen >= zLen )
00304     {
00305         parts[0] = PartitionSide( xLen, yLen * zLen, numProcs, true );
00306         numProcs /= parts[0];
00307         // If y is second longest
00308         if( yLen >= zLen )
00309         {
00310             parts[1] = PartitionSide( yLen, zLen, numProcs, false );
00311             parts[2] = numProcs / parts[1];
00312         }
00313         // If z is the longer
00314         else
00315         {
00316             parts[2] = PartitionSide( zLen, yLen, numProcs, false );
00317             parts[1] = numProcs / parts[2];
00318         }
00319     }
00320     // If y is the longest side
00321     else if( yLen >= zLen )
00322     {
00323         parts[1] = PartitionSide( yLen, xLen * zLen, numProcs, true );
00324         numProcs /= parts[1];
00325         // If x is the second longest
00326         if( xLen >= zLen )
00327         {
00328             parts[0] = PartitionSide( xLen, zLen, numProcs, false );
00329             parts[2] = numProcs / parts[0];
00330         }
00331         // If z is the second longest
00332         else
00333         {
00334             parts[2] = PartitionSide( zLen, xLen, numProcs, false );
00335             parts[0] = numProcs / parts[2];
00336         }
00337     }
00338     // If z is the longest side
00339     else
00340     {
00341         parts[2] = PartitionSide( zLen, xLen * yLen, numProcs, true );
00342         numProcs /= parts[2];
00343         // If x is the second longest
00344         if( xLen >= yLen )
00345         {
00346             parts[0] = PartitionSide( xLen, yLen, numProcs, false );
00347             parts[1] = numProcs / parts[0];
00348         }
00349         // If y is the second longest
00350         else
00351         {
00352             parts[1] = PartitionSide( yLen, xLen, numProcs, false );
00353             parts[0] = numProcs / parts[1];
00354         }
00355     }
00356 
00357     // Divide up each side to give the lengths
00358     lengths[0] = xLen / (double)parts[0];
00359     lengths[1] = yLen / (double)parts[1];
00360     lengths[2] = zLen / (double)parts[2];
00361     return MB_SUCCESS;
00362 }
00363 
00364 // Partition a side based on the length ratios
00365 int ParallelMergeMesh::PartitionSide( double sideLen, double restLen, unsigned numProcs, bool altRatio )
00366 {
00367     // If theres only 1 processor, then just return 1
00368     if( numProcs == 1 )
00369     {
00370         return 1;
00371     }
00372     // Initialize with the ratio of 1 proc
00373     double ratio    = -DBL_MAX;
00374     unsigned factor = 1;
00375     // We need to be able to save the last ratio and factor (for comparison)
00376     double oldRatio  = ratio;
00377     double oldFactor = 1;
00378 
00379     // This is the ratio were shooting for
00380     double goalRatio = sideLen / restLen;
00381 
00382     // Calculate the divisor and numerator power
00383     // This avoid if statements in the loop and is useful since both calculations are similar
00384     double divisor, p;
00385     if( altRatio )
00386     {
00387         divisor = (double)numProcs * sideLen;
00388         p       = 3;
00389     }
00390     else
00391     {
00392         divisor = (double)numProcs;
00393         p       = 2;
00394     }
00395 
00396     // Find each possible factor
00397     for( unsigned i = 2; i <= numProcs / 2; i++ )
00398     {
00399         // If it is a factor...
00400         if( numProcs % i == 0 )
00401         {
00402             // We need to save the past factor
00403             oldRatio  = ratio;
00404             oldFactor = factor;
00405             // There are 2 different ways to calculate the ratio:
00406             // Comparing 1 side to 2 sides: (i*i*i)/(numProcs*x)
00407             // Justification:  We have a ratio x:y:z (side Lengths) == a:b:c (procs).  So a=kx,
00408             // b=ky, c=kz. Also, abc=n (numProcs) => bc = n/a.  Also, a=kx => k=a/x => 1/k=x/a And so
00409             // x/(yz) == (kx)/(kyz) == (kx)/(kykz(1/k)) == a/(bc(x/a)) == a/((n/a)(x/a)) == a^3/(nx).
00410             // Comparing 1 side to 1 side: (i*i)/numprocs
00411             // Justification: i/(n/i) == i^2/n
00412             ratio  = pow( (double)i, p ) / divisor;
00413             factor = i;
00414             // Once we have passed the goal ratio, we can break since we'll only move away from the
00415             // goal ratio
00416             if( ratio >= goalRatio )
00417             {
00418                 break;
00419             }
00420         }
00421     }
00422     // If we haven't reached the goal ratio yet, check out factor = numProcs
00423     if( ratio < goalRatio )
00424     {
00425         oldRatio  = ratio;
00426         oldFactor = factor;
00427         factor    = numProcs;
00428         ratio     = pow( (double)numProcs, p ) / divisor;
00429     }
00430 
00431     // Figure out if our oldRatio is better than ratio
00432     if( fabs( ratio - goalRatio ) > fabs( oldRatio - goalRatio ) )
00433     {
00434         factor = oldFactor;
00435     }
00436     // Return our findings
00437     return factor;
00438 }
00439 
00440 // Id the tuples that are matching
00441 ErrorCode ParallelMergeMesh::PopulateMyMatches()
00442 {
00443     // Counters for accessing tuples more efficiently
00444     unsigned long i = 0, mat_i = 0, mat_ul = 0, j = 0, tup_r = 0;
00445     double eps2 = myEps * myEps;
00446 
00447     uint tup_mi, tup_ml, tup_mul, tup_mr;
00448     myTup.getTupleSize( tup_mi, tup_ml, tup_mul, tup_mr );
00449 
00450     bool canWrite = myMatches.get_writeEnabled();
00451     if( !canWrite ) myMatches.enableWriteAccess();
00452 
00453     while( ( i + 1 ) < myTup.get_n() )
00454     {
00455         // Proximity Comparison
00456         double xi = myTup.vr_rd[tup_r], yi = myTup.vr_rd[tup_r + 1], zi = myTup.vr_rd[tup_r + 2];
00457 
00458         bool done = false;
00459         while( !done )
00460         {
00461             j++;
00462             tup_r += tup_mr;
00463             if( j >= myTup.get_n() )
00464             {
00465                 break;
00466             }
00467             CartVect cv( myTup.vr_rd[tup_r] - xi, myTup.vr_rd[tup_r + 1] - yi, myTup.vr_rd[tup_r + 2] - zi );
00468             if( cv.length_squared() > eps2 )
00469             {
00470                 done = true;
00471             }
00472         }
00473         // Allocate the tuple list before adding matches
00474         while( myMatches.get_n() + ( j - i ) * ( j - i - 1 ) >= myMatches.get_max() )
00475         {
00476             myMatches.resize( myMatches.get_max() ? myMatches.get_max() + myMatches.get_max() / 2 + 1 : 2 );
00477         }
00478 
00479         // We now know that tuples [i to j) exclusive match.
00480         // If n tuples match, n*(n-1) match tuples will be made
00481         // tuples are of the form (proc1,proc2,handle1,handle2)
00482         if( i + 1 < j )
00483         {
00484             int kproc           = i * tup_mi;
00485             unsigned long khand = i * tup_mul;
00486             for( unsigned long k = i; k < j; k++ )
00487             {
00488                 int lproc           = kproc + tup_mi;
00489                 unsigned long lhand = khand + tup_mul;
00490                 for( unsigned long l = k + 1; l < j; l++ )
00491                 {
00492                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[kproc];   // proc1
00493                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[lproc];   // proc2
00494                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[khand];  // handle1
00495                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[lhand];  // handle2
00496                     myMatches.inc_n();
00497 
00498                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[lproc];   // proc1
00499                     myMatches.vi_wr[mat_i++]   = myTup.vi_rd[kproc];   // proc2
00500                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[lhand];  // handle1
00501                     myMatches.vul_wr[mat_ul++] = myTup.vul_rd[khand];  // handle2
00502                     myMatches.inc_n();
00503                     lproc += tup_mi;
00504                     lhand += tup_mul;
00505                 }
00506                 kproc += tup_mi;
00507                 khand += tup_mul;
00508             }  // End for(int k...
00509         }
00510         i = j;
00511     }  // End while(i+1<tup.n)
00512 
00513     if( !canWrite ) myMatches.disableWriteAccess();
00514     return MB_SUCCESS;
00515 }
00516 
00517 // Sort the matching tuples so that vertices can be tagged accurately
00518 ErrorCode ParallelMergeMesh::SortMyMatches()
00519 {
00520     TupleList::buffer buf( mySkinEnts[0].size() );
00521     // Sorts are necessary to check for doubles
00522     // Sort by remote handle
00523     myMatches.sort( 3, &buf );
00524     // Sort by matching proc
00525     myMatches.sort( 1, &buf );
00526     // Sort by local handle
00527     myMatches.sort( 2, &buf );
00528     buf.reset();
00529     return MB_SUCCESS;
00530 }
00531 
00532 // Tag the shared elements using existing PComm functionality
00533 ErrorCode ParallelMergeMesh::TagSharedElements( int dim )
00534 {
00535     // Manipulate the matches list to tag vertices and entities
00536     // Set up proc ents
00537     Range proc_ents;
00538     ErrorCode rval;
00539 
00540     // get the entities in the partition sets
00541     for( Range::iterator rit = myPcomm->partitionSets.begin(); rit != myPcomm->partitionSets.end(); ++rit )
00542     {
00543         Range tmp_ents;
00544         rval = myMB->get_entities_by_handle( *rit, tmp_ents, true );
00545         if( MB_SUCCESS != rval )
00546         {
00547             return rval;
00548         }
00549         proc_ents.merge( tmp_ents );
00550     }
00551     if( myMB->dimension_from_handle( *proc_ents.rbegin() ) != myMB->dimension_from_handle( *proc_ents.begin() ) )
00552     {
00553         Range::iterator lower = proc_ents.lower_bound( CN::TypeDimensionMap[0].first ),
00554                         upper = proc_ents.upper_bound( CN::TypeDimensionMap[dim - 1].second );
00555         proc_ents.erase( lower, upper );
00556     }
00557 
00558     // This vector doesn't appear to be used but its in resolve_shared_ents
00559     int maxp = -1;
00560     std::vector< int > sharing_procs( MAX_SHARING_PROCS );
00561     std::fill( sharing_procs.begin(), sharing_procs.end(), maxp );
00562 
00563     // get ents shared by 1 or n procs
00564     std::map< std::vector< int >, std::vector< EntityHandle > > proc_nranges;
00565     Range proc_verts;
00566     rval = myMB->get_adjacencies( proc_ents, 0, false, proc_verts, Interface::UNION );
00567     if( rval != MB_SUCCESS )
00568     {
00569         return rval;
00570     }
00571 
00572     rval = myPcomm->tag_shared_verts( myMatches, proc_nranges, proc_verts );
00573     if( rval != MB_SUCCESS )
00574     {
00575         return rval;
00576     }
00577 
00578     // get entities shared by 1 or n procs
00579     rval = myPcomm->get_proc_nvecs( dim, dim - 1, &mySkinEnts[0], proc_nranges );
00580     if( rval != MB_SUCCESS )
00581     {
00582         return rval;
00583     }
00584 
00585     // create the sets for each interface; store them as tags on
00586     // the interface instance
00587     Range iface_sets;
00588     rval = myPcomm->create_interface_sets( proc_nranges );
00589     if( rval != MB_SUCCESS )
00590     {
00591         return rval;
00592     }
00593     // establish comm procs and buffers for them
00594     std::set< unsigned int > procs;
00595     rval = myPcomm->get_interface_procs( procs, true );
00596     if( rval != MB_SUCCESS )
00597     {
00598         return rval;
00599     }
00600 
00601     // resolve shared entity remote handles; implemented in ghost cell exchange
00602     // code because it's so similar
00603     rval = myPcomm->exchange_ghost_cells( -1, -1, 0, true, true );
00604     if( rval != MB_SUCCESS )
00605     {
00606         return rval;
00607     }
00608     // now build parent/child links for interface sets
00609     rval = myPcomm->create_iface_pc_links();
00610     return rval;
00611 }
00612 
00613 // Make sure to free up any allocated data
00614 // Need to avoid a double free
00615 void ParallelMergeMesh::CleanUp()
00616 {
00617     // The reset operation is now safe and avoids a double free()
00618     myMatches.reset();
00619     myTup.reset();
00620     myCD.reset();
00621 }
00622 
00623 // Simple quick  sort to real
00624 void ParallelMergeMesh::SortTuplesByReal( TupleList& tup, double eps )
00625 {
00626     bool canWrite = tup.get_writeEnabled();
00627     if( !canWrite ) tup.enableWriteAccess();
00628 
00629     uint mi, ml, mul, mr;
00630     tup.getTupleSize( mi, ml, mul, mr );
00631     PerformRealSort( tup, 0, tup.get_n(), eps, mr );
00632 
00633     if( !canWrite ) tup.disableWriteAccess();
00634 }
00635 
00636 // Swap around tuples
00637 void ParallelMergeMesh::SwapTuples( TupleList& tup, unsigned long a, unsigned long b )
00638 {
00639     if( a == b ) return;
00640 
00641     uint mi, ml, mul, mr;
00642     tup.getTupleSize( mi, ml, mul, mr );
00643 
00644     // Swap mi
00645     unsigned long a_val = a * mi, b_val = b * mi;
00646     for( unsigned long i = 0; i < mi; i++ )
00647     {
00648         sint t           = tup.vi_rd[a_val];
00649         tup.vi_wr[a_val] = tup.vi_rd[b_val];
00650         tup.vi_wr[b_val] = t;
00651         a_val++;
00652         b_val++;
00653     }
00654     // Swap ml
00655     a_val = a * ml;
00656     b_val = b * ml;
00657     for( unsigned long i = 0; i < ml; i++ )
00658     {
00659         slong t          = tup.vl_rd[a_val];
00660         tup.vl_wr[a_val] = tup.vl_rd[b_val];
00661         tup.vl_wr[b_val] = t;
00662         a_val++;
00663         b_val++;
00664     }
00665     // Swap mul
00666     a_val = a * mul;
00667     b_val = b * mul;
00668     for( unsigned long i = 0; i < mul; i++ )
00669     {
00670         Ulong t           = tup.vul_rd[a_val];
00671         tup.vul_wr[a_val] = tup.vul_rd[b_val];
00672         tup.vul_wr[b_val] = t;
00673         a_val++;
00674         b_val++;
00675     }
00676     // Swap mr
00677     a_val = a * mr;
00678     b_val = b * mr;
00679     for( unsigned long i = 0; i < mr; i++ )
00680     {
00681         realType t       = tup.vr_rd[a_val];
00682         tup.vr_wr[a_val] = tup.vr_rd[b_val];
00683         tup.vr_wr[b_val] = t;
00684         a_val++;
00685         b_val++;
00686     }
00687 }
00688 
00689 // Perform the sorting of a tuple by real
00690 // To sort an entire tuple_list, call (tup,0,tup.n,epsilon)
00691 void ParallelMergeMesh::PerformRealSort( TupleList& tup,
00692                                          unsigned long left,
00693                                          unsigned long right,
00694                                          double eps,
00695                                          uint tup_mr )
00696 {
00697     // If list size is only 1 or 0 return
00698     if( left + 1 >= right )
00699     {
00700         return;
00701     }
00702     unsigned long swap = left, tup_l = left * tup_mr, tup_t = tup_l + tup_mr;
00703 
00704     // Swap the median with the left position for a (hopefully) better split
00705     SwapTuples( tup, left, ( left + right ) / 2 );
00706 
00707     // Partition the data
00708     for( unsigned long t = left + 1; t < right; t++ )
00709     {
00710         // If the left value(pivot) is greater than t_val, swap it into swap
00711         if( TupleGreaterThan( tup, tup_l, tup_t, eps, tup_mr ) )
00712         {
00713             swap++;
00714             SwapTuples( tup, swap, t );
00715         }
00716         tup_t += tup_mr;
00717     }
00718 
00719     // Swap so that position swap is in the correct position
00720     SwapTuples( tup, left, swap );
00721 
00722     // Sort left and right of swap
00723     PerformRealSort( tup, left, swap, eps, tup_mr );
00724     PerformRealSort( tup, swap + 1, right, eps, tup_mr );
00725 }
00726 
00727 // Note, this takes the actual tup.vr[] index (aka i*tup.mr)
00728 bool ParallelMergeMesh::TupleGreaterThan( TupleList& tup,
00729                                           unsigned long vrI,
00730                                           unsigned long vrJ,
00731                                           double eps,
00732                                           uint tup_mr )
00733 {
00734     unsigned check = 0;
00735     while( check < tup_mr )
00736     {
00737         // If the values are the same
00738         if( fabs( tup.vr_rd[vrI + check] - tup.vr_rd[vrJ + check] ) <= eps )
00739         {
00740             check++;
00741             continue;
00742         }
00743         // If I greater than J
00744         else if( tup.vr_rd[vrI + check] > tup.vr_rd[vrJ + check] )
00745         {
00746             return true;
00747         }
00748         // If J greater than I
00749         else
00750         {
00751             return false;
00752         }
00753     }
00754     // All Values are the same
00755     return false;
00756 }
00757 
00758 }  // End namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines