Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
Intx2MeshOnSphere.cpp
Go to the documentation of this file.
00001 /*
00002  * Intx2MeshOnSphere.cpp
00003  *
00004  *  Created on: Oct 3, 2012
00005  */
00006 
00007 #ifdef _MSC_VER            /* windows */
00008 #define _USE_MATH_DEFINES  // For M_PI
00009 #endif
00010 
00011 #include "moab/IntxMesh/Intx2MeshOnSphere.hpp"
00012 #include "moab/IntxMesh/IntxUtils.hpp"
00013 #include "moab/GeomUtil.hpp"
00014 #ifdef MOAB_HAVE_MPI
00015 #include "moab/ParallelComm.hpp"
00016 #endif
00017 #include "MBTagConventions.hpp"
00018 
00019 #include <cassert>
00020 
00021 // #define ENABLE_DEBUG
00022 #define CHECK_CONVEXITY
00023 namespace moab
00024 {
00025 
00026 Intx2MeshOnSphere::Intx2MeshOnSphere( Interface* mbimpl, IntxAreaUtils::AreaMethod amethod )
00027     : Intx2Mesh( mbimpl ), areaMethod( amethod ), plane( 0 ), Rsrc( 0.0 ), Rdest( 0.0 )
00028 {
00029 }
00030 
00031 Intx2MeshOnSphere::~Intx2MeshOnSphere() {}
00032 
00033 /*
00034  * return also the area for robustness verification
00035  */
00036 double Intx2MeshOnSphere::setup_tgt_cell( EntityHandle tgt, int& nsTgt )
00037 {
00038 
00039     // get coordinates of the target quad, to decide the gnomonic plane
00040     double cellArea = 0;
00041 
00042     int num_nodes;
00043     ErrorCode rval = mb->get_connectivity( tgt, tgtConn, num_nodes );MB_CHK_ERR_RET_VAL( rval, cellArea );
00044 
00045     nsTgt = num_nodes;
00046     // account for possible padded polygons
00047     while( tgtConn[nsTgt - 2] == tgtConn[nsTgt - 1] && nsTgt > 3 )
00048         nsTgt--;
00049 
00050     // CartVect coords[4];
00051     rval = mb->get_coords( tgtConn, nsTgt, &( tgtCoords[0][0] ) );MB_CHK_ERR_RET_VAL( rval, cellArea );
00052 
00053     CartVect middle = tgtCoords[0];
00054     for( int i = 1; i < nsTgt; i++ )
00055         middle += tgtCoords[i];
00056     middle = 1. / nsTgt * middle;
00057 
00058     IntxUtils::decide_gnomonic_plane( middle, plane );  // output the plane
00059     for( int j = 0; j < nsTgt; j++ )
00060     {
00061         // populate coords in the plane for intersection
00062         // they should be oriented correctly, positively
00063         rval = IntxUtils::gnomonic_projection( tgtCoords[j], Rdest, plane, tgtCoords2D[2 * j], tgtCoords2D[2 * j + 1] );MB_CHK_ERR_RET_VAL( rval, cellArea );
00064     }
00065 
00066     for( int j = 1; j < nsTgt - 1; j++ )
00067         cellArea += IntxUtils::area2D( &tgtCoords2D[0], &tgtCoords2D[2 * j], &tgtCoords2D[2 * j + 2] );
00068 
00069     // take target coords in order and compute area in plane
00070     return cellArea;
00071 }
00072 
00073 /* the elements are convex for sure, then do a gnomonic projection of both,
00074  *  compute intersection in the plane, then go back to the sphere for the points
00075  *  */
00076 ErrorCode Intx2MeshOnSphere::computeIntersectionBetweenTgtAndSrc( EntityHandle tgt,
00077                                                                   EntityHandle src,
00078                                                                   double* P,
00079                                                                   int& nP,
00080                                                                   double& area,
00081                                                                   int markb[MAXEDGES],
00082                                                                   int markr[MAXEDGES],
00083                                                                   int& nsBlue,
00084                                                                   int& nsTgt,
00085                                                                   bool check_boxes_first )
00086 {
00087     // the area will be used from now on, to see how well we fill the target cell with polygons
00088     // the points will be at most 40; they will describe a convex patch, after the points will be
00089     // ordered and collapsed (eliminate doubles)
00090 
00091     // CartVect srccoords[4];
00092     int num_nodes  = 0;
00093     ErrorCode rval = mb->get_connectivity( src, srcConn, num_nodes );MB_CHK_ERR( rval );
00094     nsBlue = num_nodes;
00095     // account for possible padded polygons
00096     while( srcConn[nsBlue - 2] == srcConn[nsBlue - 1] && nsBlue > 3 )
00097         nsBlue--;
00098     rval = mb->get_coords( srcConn, nsBlue, &( srcCoords[0][0] ) );MB_CHK_ERR( rval );
00099 
00100     area = 0.;
00101     nP   = 0;  // number of intersection points we are marking the boundary of src!
00102     if( check_boxes_first )
00103     {
00104         // look at the boxes formed with vertices; if they are far away, return false early
00105         // make sure the target is setup already
00106         setup_tgt_cell( tgt, nsTgt );  // we do not need area here
00107         // use here gnomonic plane (plane) to see where source is
00108         bool overlap3d = GeomUtil::bounding_boxes_overlap( tgtCoords, nsTgt, srcCoords, nsBlue, box_error );
00109         int planeb;
00110         CartVect mid3 = ( srcCoords[0] + srcCoords[1] + srcCoords[2] ) / 3;
00111         IntxUtils::decide_gnomonic_plane( mid3, planeb );
00112         if( !overlap3d && ( plane != planeb ) )  // plane was set at setup_tgt_cell
00113             return MB_SUCCESS;                   // no error, but no intersection, decide early to get out
00114         // if same plane, still check for gnomonic plane in 2d
00115         // if no overlap in 2d, get out
00116         if( !overlap3d && plane == planeb )  // CHECK 2D too
00117         {
00118             for( int j = 0; j < nsBlue; j++ )
00119             {
00120                 rval = IntxUtils::gnomonic_projection( srcCoords[j], Rsrc, plane, srcCoords2D[2 * j],
00121                                                        srcCoords2D[2 * j + 1] );MB_CHK_ERR( rval );
00122             }
00123             bool overlap2d = GeomUtil::bounding_boxes_overlap_2d( srcCoords2D, nsBlue, tgtCoords2D, nsTgt, box_error );
00124             if( !overlap2d ) return MB_SUCCESS;  // we are sure they are not overlapping in 2d , either
00125         }
00126     }
00127 #ifdef ENABLE_DEBUG
00128     if( dbg_1 )
00129     {
00130         std::cout << "tgt " << mb->id_from_handle( tgt ) << "\n";
00131         for( int j = 0; j < nsTgt; j++ )
00132         {
00133             std::cout << tgtCoords[j] << "\n";
00134         }
00135         std::cout << "src " << mb->id_from_handle( src ) << "\n";
00136         for( int j = 0; j < nsBlue; j++ )
00137         {
00138             std::cout << srcCoords[j] << "\n";
00139         }
00140         mb->list_entities( &tgt, 1 );
00141         mb->list_entities( &src, 1 );
00142     }
00143 #endif
00144 
00145     for( int j = 0; j < nsBlue; j++ )
00146     {
00147         rval = IntxUtils::gnomonic_projection( srcCoords[j], Rsrc, plane, srcCoords2D[2 * j], srcCoords2D[2 * j + 1] );MB_CHK_ERR( rval );
00148     }
00149 
00150 #ifdef ENABLE_DEBUG
00151     if( dbg_1 )
00152     {
00153         std::cout << "gnomonic plane: " << plane << "\n";
00154         std::cout << " target                                src\n";
00155         for( int j = 0; j < nsTgt; j++ )
00156         {
00157             std::cout << tgtCoords2D[2 * j] << " " << tgtCoords2D[2 * j + 1] << "\n";
00158         }
00159         for( int j = 0; j < nsBlue; j++ )
00160         {
00161             std::cout << srcCoords2D[2 * j] << " " << srcCoords2D[2 * j + 1] << "\n";
00162         }
00163     }
00164 #endif
00165 
00166     rval = IntxUtils::EdgeIntersections2( srcCoords2D, nsBlue, tgtCoords2D, nsTgt, markb, markr, P, nP );MB_CHK_ERR( rval );
00167 
00168     int side[MAXEDGES] = { 0 };  // this refers to what side? source or tgt?
00169     int extraPoints =
00170         IntxUtils::borderPointsOfXinY2( srcCoords2D, nsBlue, tgtCoords2D, nsTgt, &( P[2 * nP] ), side, epsilon_area );
00171     if( extraPoints >= 1 )
00172     {
00173         for( int k = 0; k < nsBlue; k++ )
00174         {
00175             if( side[k] )
00176             {
00177                 // this means that vertex k of source is inside convex tgt; mark edges k-1 and k in
00178                 // src,
00179                 //   as being "intersected" by tgt; (even though they might not be intersected by
00180                 //   other edges, the fact that their apex is inside, is good enough)
00181                 markb[k] = 1;
00182                 markb[( k + nsBlue - 1 ) % nsBlue] =
00183                     1;  // it is the previous edge, actually, but instead of doing -1, it is
00184                 // better to do modulo +3 (modulo 4)
00185                 // null side b for next call
00186                 side[k] = 0;
00187             }
00188         }
00189     }
00190     nP += extraPoints;
00191 
00192     extraPoints =
00193         IntxUtils::borderPointsOfXinY2( tgtCoords2D, nsTgt, srcCoords2D, nsBlue, &( P[2 * nP] ), side, epsilon_area );
00194     if( extraPoints >= 1 )
00195     {
00196         for( int k = 0; k < nsTgt; k++ )
00197         {
00198             if( side[k] )
00199             {
00200                 // this is to mark that target edges k-1 and k are intersecting src
00201                 markr[k] = 1;
00202                 markr[( k + nsTgt - 1 ) % nsTgt] =
00203                     1;  // it is the previous edge, actually, but instead of doing -1, it is
00204                 // better to do modulo +3 (modulo 4)
00205                 // null side b for next call
00206             }
00207         }
00208     }
00209     nP += extraPoints;
00210 
00211     // now sort and orient the points in P, such that they are forming a convex polygon
00212     // this will be the foundation of our new mesh
00213     // this works if the polygons are convex
00214     IntxUtils::SortAndRemoveDoubles2( P, nP, epsilon_1 );  // nP should be at most 8 in the end ?
00215     // if there are more than 3 points, some area will be positive
00216 
00217     if( nP >= 3 )
00218     {
00219         for( int k = 1; k < nP - 1; k++ )
00220             area += IntxUtils::area2D( P, &P[2 * k], &P[2 * k + 2] );
00221 #ifdef CHECK_CONVEXITY
00222         // each edge should be large enough that we can compute angles between edges
00223         for( int k = 0; k < nP; k++ )
00224         {
00225             int k1              = ( k + 1 ) % nP;
00226             int k2              = ( k1 + 1 ) % nP;
00227             double orientedArea = IntxUtils::area2D( &P[2 * k], &P[2 * k1], &P[2 * k2] );
00228             if( orientedArea < 0 )
00229             {
00230                 std::cout << " oriented area is negative: " << orientedArea << " k:" << k << " target, src:" << tgt
00231                           << " " << src << " \n";
00232             }
00233         }
00234 #endif
00235     }
00236 
00237     return MB_SUCCESS;  // no error
00238 }
00239 
00240 // this method will also construct the triangles/quads/polygons in the new mesh
00241 // if we accept planar polygons, we just save them
00242 // also, we could just create new vertices every time, and merge only in the end;
00243 // could be too expensive, and the tolerance for merging could be an
00244 // interesting topic
00245 ErrorCode Intx2MeshOnSphere::findNodes( EntityHandle tgt, int nsTgt, EntityHandle src, int nsBlue, double* iP, int nP )
00246 {
00247 #ifdef ENABLE_DEBUG
00248     // first of all, check against target and source vertices
00249     //
00250     if( dbg_1 )
00251     {
00252         std::cout << "tgt, src, nP, P " << mb->id_from_handle( tgt ) << " " << mb->id_from_handle( src ) << " " << nP
00253                   << "\n";
00254         for( int n = 0; n < nP; n++ )
00255             std::cout << " \t" << iP[2 * n] << "\t" << iP[2 * n + 1] << "\n";
00256     }
00257 #endif
00258 
00259     IntxAreaUtils areaAdaptor;
00260     // get the edges for the target triangle; the extra points will be on those edges, saved as
00261     // lists (unordered)
00262 
00263     // first get the list of edges adjacent to the target cell
00264     // use the neighTgtEdgeTag
00265     EntityHandle adjTgtEdges[MAXEDGES];
00266     ErrorCode rval = mb->tag_get_data( neighTgtEdgeTag, &tgt, 1, &( adjTgtEdges[0] ) );MB_CHK_SET_ERR( rval, "can't get edge target tag" );
00267     // we know that we have only nsTgt edges here; [nsTgt, MAXEDGES) are ignored, but it is small
00268     // potatoes some of them will be handles to the initial vertices from source or target meshes
00269 
00270     std::vector< EntityHandle > foundIds;
00271     foundIds.resize( nP );
00272 #ifdef CHECK_CONVEXITY
00273     int npBefore1 = nP;
00274     int oldNodes  = 0;
00275     int otherIntx = 0;
00276 #endif
00277     for( int i = 0; i < nP; i++ )
00278     {
00279         double* pp = &iP[2 * i];  // iP+2*i
00280         // project the point back on the sphere
00281         CartVect pos;
00282         IntxUtils::reverse_gnomonic_projection( pp[0], pp[1], Rdest, plane, pos );
00283         int found = 0;
00284         // first, are they on vertices from target or src?
00285         // priority is the target mesh (mb2?)
00286         int j                = 0;
00287         EntityHandle outNode = (EntityHandle)0;
00288         for( j = 0; j < nsTgt && !found; j++ )
00289         {
00290             // int node = tgtTri.v[j];
00291             double d2 = IntxUtils::dist2( pp, &tgtCoords2D[2 * j] );
00292             if( d2 < epsilon_1 )
00293             {
00294 
00295                 foundIds[i] = tgtConn[j];  // no new node
00296                 found       = 1;
00297 #ifdef CHECK_CONVEXITY
00298                 oldNodes++;
00299 #endif
00300 #ifdef ENABLE_DEBUG
00301                 if( dbg_1 )
00302                     std::cout << "  target node j:" << j << " id:" << mb->id_from_handle( tgtConn[j] )
00303                               << " 2d coords:" << tgtCoords2D[2 * j] << "  " << tgtCoords2D[2 * j + 1] << " d2: " << d2
00304                               << " \n";
00305 #endif
00306             }
00307         }
00308 
00309         for( j = 0; j < nsBlue && !found; j++ )
00310         {
00311             // int node = srcTri.v[j];
00312             double d2 = IntxUtils::dist2( pp, &srcCoords2D[2 * j] );
00313             if( d2 < epsilon_1 )
00314             {
00315                 // suspect is srcConn[j] corresponding in mbOut
00316 
00317                 foundIds[i] = srcConn[j];  // no new node
00318                 found       = 1;
00319 #ifdef CHECK_CONVEXITY
00320                 oldNodes++;
00321 #endif
00322 #ifdef ENABLE_DEBUG
00323                 if( dbg_1 )
00324                     std::cout << "  source node " << j << " " << mb->id_from_handle( srcConn[j] ) << " d2:" << d2
00325                               << " \n";
00326 #endif
00327             }
00328         }
00329 
00330         if( !found )
00331         {
00332             // find the edge it belongs, first, on the red element
00333             // look at the minimum area, not at the first below some tolerance
00334             double minArea = 1.e+38;
00335             int index_min  = -1;
00336             for( j = 0; j < nsTgt; j++ )
00337             {
00338                 int j1      = ( j + 1 ) % nsTgt;
00339                 double area = fabs( IntxUtils::area2D( &tgtCoords2D[2 * j], &tgtCoords2D[2 * j1], pp ) );
00340                 // how to check if pp is between redCoords2D[j] and redCoords2D[j1] ?
00341                 // they should form a straight line; the sign should be -1
00342                 double checkx = IntxUtils::dist2( &tgtCoords2D[2 * j], pp ) +
00343                                 IntxUtils::dist2( &tgtCoords2D[2 * j1], pp ) -
00344                                 IntxUtils::dist2( &tgtCoords2D[2 * j], &tgtCoords2D[2 * j1] );
00345                 if( area < minArea && checkx < 2 * epsilon_1 )  // round off error or not?
00346                 {
00347                     index_min = j;
00348                     minArea   = area;
00349                 }
00350             }
00351             // verify that index_min is valid
00352             assert( index_min >= 0 );
00353 
00354             if( minArea < epsilon_1 / 2 )  // we found the smallest area, so we think we found the
00355                                            // target edge it belongs
00356             {
00357                 // found the edge; now find if there is a point in the list here
00358                 // std::vector<EntityHandle> * expts = extraNodesMap[tgtEdges[j]];
00359                 int indx = TgtEdges.index( adjTgtEdges[index_min] );
00360                 if( indx < 0 )  // CID 181166 (#1 of 1): Argument cannot be negative (NEGATIVE_RETURNS)
00361                 {
00362                     std::cerr << " error in adjacent target edge: " << mb->id_from_handle( adjTgtEdges[index_min] )
00363                               << "\n";
00364                     return MB_FAILURE;
00365                 }
00366                 std::vector< EntityHandle >* expts = extraNodesVec[indx];
00367                 // if the points pp is between extra points, then just give that id
00368                 // if not, create a new point, (check the id)
00369                 // get the coordinates of the extra points so far
00370                 int nbExtraNodesSoFar = expts->size();
00371                 if( nbExtraNodesSoFar > 0 )
00372                 {
00373                     std::vector< CartVect > coords1;
00374                     coords1.resize( nbExtraNodesSoFar );
00375                     mb->get_coords( &( *expts )[0], nbExtraNodesSoFar, &( coords1[0][0] ) );
00376                     // std::list<int>::iterator it;
00377                     for( int k = 0; k < nbExtraNodesSoFar && !found; k++ )
00378                     {
00379                         // int pnt = *it;
00380                         double d2 = ( pos - coords1[k] ).length();
00381                         if( d2 < 2 * epsilon_1 )  // is this below machine precision?
00382                         {
00383                             found       = 1;
00384                             foundIds[i] = ( *expts )[k];
00385 #ifdef CHECK_CONVEXITY
00386                             otherIntx++;
00387 #endif
00388                         }
00389                     }
00390                 }
00391                 if( !found )
00392                 {
00393                     // create a new point in 2d (at the intersection)
00394                     // foundIds[i] = m_num2dPoints;
00395                     // expts.push_back(m_num2dPoints);
00396                     // need to create a new node in mbOut
00397                     // this will be on the edge, and it will be added to the local list
00398                     rval = mb->create_vertex( pos.array(), outNode );MB_CHK_ERR( rval );
00399                     ( *expts ).push_back( outNode );
00400                     // CID 181168; avoid leak storage error
00401                     rval = mb->add_entities( outSet, &outNode, 1 );MB_CHK_ERR( rval );
00402                     foundIds[i] = outNode;
00403                     found       = 1;
00404                 }
00405             }
00406         }
00407         if( !found )
00408         {
00409             std::cout << " target quad: ";
00410             for( int j1 = 0; j1 < nsTgt; j1++ )
00411             {
00412                 std::cout << tgtCoords2D[2 * j1] << " " << tgtCoords2D[2 * j1 + 1] << "\n";
00413             }
00414             std::cout << " a point pp is not on a target quad " << *pp << " " << pp[1] << " target quad "
00415                       << mb->id_from_handle( tgt ) << " \n";
00416             return MB_FAILURE;
00417         }
00418     }
00419 #ifdef ENABLE_DEBUG
00420     if( dbg_1 )
00421     {
00422         std::cout << " candidate polygon: nP" << nP << " plane: " << plane << "\n";
00423         for( int i1 = 0; i1 < nP; i1++ )
00424             std::cout << iP[2 * i1] << " " << iP[2 * i1 + 1] << " " << foundIds[i1] << "\n";
00425     }
00426 #endif
00427     // first, find out if we have nodes collapsed; shrink them
00428     // we may have to reduce nP
00429     // it is possible that some nodes are collapsed after intersection only
00430     // nodes will always be in order (convex intersection)
00431 #ifdef CHECK_CONVEXITY
00432     int npBefore2 = nP;
00433 #endif
00434     correct_polygon( &foundIds[0], nP );
00435     // now we can build the triangles, from P array, with foundIds
00436     // we will put them in the out set
00437     if( nP >= 3 )
00438     {
00439         EntityHandle polyNew;
00440         rval = mb->create_element( MBPOLYGON, &foundIds[0], nP, polyNew );MB_CHK_ERR( rval );
00441         rval = mb->add_entities( outSet, &polyNew, 1 );MB_CHK_ERR( rval );
00442 
00443         // tag it with the global ids from target and source elements
00444         int globalID;
00445         rval = mb->tag_get_data( gid, &src, 1, &globalID );MB_CHK_ERR( rval );
00446         rval = mb->tag_set_data( srcParentTag, &polyNew, 1, &globalID );MB_CHK_ERR( rval );
00447         // if(!parcomm->rank()) std::cout << "Setting parent for " << mb->id_from_handle(polyNew) <<
00448         // " : Blue = " << globalID << ", " << mb->id_from_handle(src) << "\t\n";
00449         rval = mb->tag_get_data( gid, &tgt, 1, &globalID );MB_CHK_ERR( rval );
00450         rval = mb->tag_set_data( tgtParentTag, &polyNew, 1, &globalID );MB_CHK_ERR( rval );
00451         // if(parcomm->rank()) std::cout << "Setting parent for " << mb->id_from_handle(polyNew) <<
00452         // " : target = " << globalID << ", " << mb->id_from_handle(tgt) << "\n";
00453 
00454         counting++;
00455         rval = mb->tag_set_data( countTag, &polyNew, 1, &counting );MB_CHK_ERR( rval );
00456         if( orgSendProcTag )
00457         {
00458             int org_proc = -1;
00459             rval         = mb->tag_get_data( orgSendProcTag, &src, 1, &org_proc );MB_CHK_ERR( rval );
00460             rval = mb->tag_set_data( orgSendProcTag, &polyNew, 1, &org_proc );MB_CHK_ERR( rval );  // yet another tag
00461         }
00462 #ifdef CHECK_CONVEXITY
00463         // each edge should be large enough that we can compute angles between edges
00464         std::vector< double > coords;
00465         coords.resize( 3 * nP );
00466         rval = mb->get_coords( &foundIds[0], nP, &coords[0] );MB_CHK_ERR( rval );
00467         std::vector< CartVect > posi( nP );
00468         rval = mb->get_coords( &foundIds[0], nP, &( posi[0][0] ) );MB_CHK_ERR( rval );
00469 
00470         for( int k = 0; k < nP; k++ )
00471         {
00472             int k1 = ( k + 1 ) % nP;
00473             int k2 = ( k1 + 1 ) % nP;
00474             double orientedArea =
00475                     areaAdaptor.area_spherical_triangle( &coords[3 * k], &coords[3 * k1], &coords[3 * k2], Rdest, my_rank );
00476             if( orientedArea < 0 )
00477             {
00478                 std::cout << " np before + current " << npBefore1 << " " << npBefore2 << " " << nP << "\n";
00479                 for( int i = 0; i < nP; i++ )
00480                 {
00481                     int nexti         = ( i + 1 ) % nP;
00482                     double lengthEdge = ( posi[i] - posi[nexti] ).length();
00483                     std::cout << " " << foundIds[i] << " edge en:" << lengthEdge << "\n";
00484                 }
00485                 std::cout << " old verts: " << oldNodes << " other intx:" << otherIntx << "\n";
00486                 int sgid, tgid;
00487                 rval = mb->tag_get_data(gid, &src, 1, &sgid); MB_CHK_ERR( rval );
00488                 rval = mb->tag_get_data(gid, &tgt, 1, &tgid); MB_CHK_ERR( rval );
00489                 std::cout << "rank: " << my_rank << " oriented area in 3d is negative: " << orientedArea << " k:" << k
00490                           << " target, src:" << tgid << " " << sgid << " \n";
00491             }
00492         }
00493 #endif
00494 
00495 #ifdef ENABLE_DEBUG
00496         if( dbg_1 )
00497         {
00498             std::cout << "Counting: " << counting << "\n";
00499             std::cout << " polygon " << mb->id_from_handle( polyNew ) << "  nodes: " << nP << " :";
00500             for( int i1 = 0; i1 < nP; i1++ )
00501                 std::cout << " " << mb->id_from_handle( foundIds[i1] );
00502             std::cout << " plane: " << plane << "\n";
00503             std::vector< CartVect > posi( nP );
00504             mb->get_coords( &foundIds[0], nP, &( posi[0][0] ) );
00505             for( int i1 = 0; i1 < nP; i1++ )
00506                 std::cout << foundIds[i1] << " " << posi[i1] << "\n";
00507 
00508             std::stringstream fff;
00509             fff << "file0" << counting << ".vtk";
00510             rval = mb->write_mesh( fff.str().c_str(), &outSet, 1 );MB_CHK_ERR( rval );
00511         }
00512 #endif
00513     }
00514     // else {
00515     //   std::cout << "[[FAILURE]] Number of vertices in polygon is less than 3\n";
00516     // }
00517     // disable_debug();
00518     return MB_SUCCESS;
00519 }
00520 
00521 ErrorCode Intx2MeshOnSphere::update_tracer_data( EntityHandle out_set, Tag& tagElem, Tag& tagArea )
00522 {
00523     EntityHandle dum = 0;
00524 
00525     Tag corrTag;
00526     ErrorCode rval = mb->tag_get_handle( CORRTAGNAME, 1, MB_TYPE_HANDLE, corrTag, MB_TAG_DENSE,
00527                                          &dum );  // it should have been created
00528     MB_CHK_SET_ERR( rval, "can't get correlation tag" );
00529 
00530     // get all polygons out of out_set; then see where are they coming from
00531     Range polys;
00532     rval = mb->get_entities_by_dimension( out_set, 2, polys );MB_CHK_SET_ERR( rval, "can't get polygons out" );
00533 
00534     // rs2 is the target range, arrival; rs1 is src, departure;
00535     // there is a connection between rs1 and rs2, through the corrTag
00536     // corrTag is __correlation
00537     // basically, mb->tag_get_data(corrTag, &(tgtPoly), 1, &srcPoly);
00538     // also,  mb->tag_get_data(corrTag, &(srcPoly), 1, &tgtPoly);
00539     // we start from rs2 existing, then we have to update something
00540 
00541     // tagElem will have multiple tracers
00542     int numTracers = 0;
00543     rval           = mb->tag_get_length( tagElem, numTracers );MB_CHK_SET_ERR( rval, "can't get number of tracers in simulation" );
00544     if( numTracers < 1 ) MB_CHK_SET_ERR( MB_FAILURE, "no tracers data" );
00545 
00546     std::vector< double > currentVals( rs2.size() * numTracers );
00547     rval = mb->tag_get_data( tagElem, rs2, &currentVals[0] );MB_CHK_SET_ERR( rval, "can't get existing tracers values" );
00548 
00549     // create new tuple list for tracers to other processors, from remote_cells
00550 #ifdef MOAB_HAVE_MPI
00551     if( remote_cells )
00552     {
00553         int n = remote_cells->get_n();
00554         if( n > 0 )
00555         {
00556             remote_cells_with_tracers = new TupleList();
00557             remote_cells_with_tracers->initialize( 2, 0, 1, numTracers,
00558                                                    n );  // tracers are in these tuples
00559             remote_cells_with_tracers->enableWriteAccess();
00560             for( int i = 0; i < n; i++ )
00561             {
00562                 remote_cells_with_tracers->vi_wr[2 * i]     = remote_cells->vi_wr[2 * i];
00563                 remote_cells_with_tracers->vi_wr[2 * i + 1] = remote_cells->vi_wr[2 * i + 1];
00564                 //    remote_cells->vr_wr[i] = 0.; will have a different tuple for communication
00565                 remote_cells_with_tracers->vul_wr[i] =
00566                     remote_cells->vul_wr[i];  // this is the corresponding target cell (arrival)
00567                 for( int k = 0; k < numTracers; k++ )
00568                     remote_cells_with_tracers->vr_wr[numTracers * i + k] = 0;  // initialize tracers to be transported
00569                 remote_cells_with_tracers->inc_n();
00570             }
00571         }
00572         delete remote_cells;
00573         remote_cells = NULL;
00574     }
00575 #endif
00576     // for each polygon, we have 2 indices: target and source parents
00577     // we need index source to update index tgt?
00578     std::vector< double > newValues( rs2.size() * numTracers,
00579                                      0. );  // initialize with 0 all of them
00580     // area of the polygon * conc on target (old) current quantity
00581     // finally, divide by the area of the tgt
00582     double check_intx_area = 0.;
00583     moab::IntxAreaUtils intxAreas( this->areaMethod );  // use_lHuiller = true
00584     for( Range::iterator it = polys.begin(); it != polys.end(); ++it )
00585     {
00586         EntityHandle poly = *it;
00587         int srcIndex, tgtIndex;
00588         rval = mb->tag_get_data( srcParentTag, &poly, 1, &srcIndex );MB_CHK_SET_ERR( rval, "can't get source tag" );
00589 
00590         EntityHandle src = rs1[srcIndex - 1];  // big assumption, it should work for meshes where global id is the same
00591         // as element handle (ordered from 1 to number of elements); should be OK for Homme meshes
00592         rval = mb->tag_get_data( tgtParentTag, &poly, 1, &tgtIndex );MB_CHK_SET_ERR( rval, "can't get target tag" );
00593         // EntityHandle target = rs2[tgtIndex];
00594         // big assumption here, target and source are "parallel" ;we should have an index from
00595         // source to target (so a deformed source corresponds to an arrival tgt)
00596         /// TODO: VSM: Its unclear whether we need the source or destination radius here.
00597         double radius = Rsrc;
00598         double areap  = intxAreas.area_spherical_element( mb, poly, radius, my_rank );
00599         check_intx_area += areap;
00600         // so the departure cell at time t (srcIndex) covers a portion of a tgtCell
00601         // that quantity will be transported to the tgtCell at time t+dt
00602         // the source corresponds to a target arrival
00603         EntityHandle tgtArr;
00604         rval = mb->tag_get_data( corrTag, &src, 1, &tgtArr );
00605         if( 0 == tgtArr || MB_TAG_NOT_FOUND == rval )
00606         {
00607 #ifdef MOAB_HAVE_MPI
00608             if( !remote_cells_with_tracers ) MB_CHK_SET_ERR( MB_FAILURE, "no remote cells, failure\n" );
00609             // maybe the element is remote, from another processor
00610             int global_id_src;
00611             rval = mb->tag_get_data( gid, &src, 1, &global_id_src );MB_CHK_SET_ERR( rval, "can't get arrival target for corresponding source gid" );
00612             // find the
00613             int index_in_remote = remote_cells_with_tracers->find( 1, global_id_src );
00614             if( index_in_remote == -1 )
00615                 MB_CHK_SET_ERR( MB_FAILURE, "can't find the global id element in remote cells\n" );
00616             for( int k = 0; k < numTracers; k++ )
00617                 remote_cells_with_tracers->vr_wr[index_in_remote * numTracers + k] +=
00618                     currentVals[numTracers * ( tgtIndex - 1 ) + k] * areap;
00619 #endif
00620         }
00621         else if( MB_SUCCESS == rval )
00622         {
00623             int arrTgtIndex = rs2.index( tgtArr );
00624             if( -1 == arrTgtIndex ) MB_CHK_SET_ERR( MB_FAILURE, "can't find the target arrival index" );
00625             for( int k = 0; k < numTracers; k++ )
00626                 newValues[numTracers * arrTgtIndex + k] += currentVals[( tgtIndex - 1 ) * numTracers + k] * areap;
00627         }
00628 
00629         else
00630             MB_CHK_SET_ERR( rval, "can't get arrival target for corresponding " );
00631     }
00632     // now, send back the remote_cells_with_tracers to the processors they came from, with the
00633     // updated values for the tracer mass in a cell
00634 #ifdef MOAB_HAVE_MPI
00635     if( remote_cells_with_tracers )
00636     {
00637         // so this means that some cells will be sent back with tracer info to the procs they were
00638         // sent from
00639         ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, *remote_cells_with_tracers, 0 );
00640         // now, look at the global id, find the proper "tgt" cell with that index and update its
00641         // mass
00642         // remote_cells->print("remote cells after routing");
00643         int n = remote_cells_with_tracers->get_n();
00644         for( int j = 0; j < n; j++ )
00645         {
00646             EntityHandle tgtCell = remote_cells_with_tracers->vul_rd[j];  // entity handle sent back
00647             int arrTgtIndex      = rs2.index( tgtCell );
00648             if( -1 == arrTgtIndex ) MB_CHK_SET_ERR( MB_FAILURE, "can't find the target arrival index" );
00649             for( int k = 0; k < numTracers; k++ )
00650                 newValues[arrTgtIndex * numTracers + k] += remote_cells_with_tracers->vr_rd[j * numTracers + k];
00651         }
00652     }
00653 #endif /* MOAB_HAVE_MPI */
00654     // now divide by target area (current)
00655     int j                = 0;
00656     Range::iterator iter = rs2.begin();
00657     void* data           = NULL;  // used for stored area
00658     int count            = 0;
00659     std::vector< double > total_mass_local( numTracers, 0. );
00660     while( iter != rs2.end() )
00661     {
00662         rval = mb->tag_iterate( tagArea, iter, rs2.end(), count, data );MB_CHK_SET_ERR( rval, "can't tag iterate" );
00663         double* ptrArea = (double*)data;
00664         for( int i = 0; i < count; i++, ++iter, j++, ptrArea++ )
00665         {
00666             for( int k = 0; k < numTracers; k++ )
00667             {
00668                 total_mass_local[k] += newValues[j * numTracers + k];
00669                 newValues[j * numTracers + k] /= ( *ptrArea );
00670             }
00671         }
00672     }
00673     rval = mb->tag_set_data( tagElem, rs2, &newValues[0] );MB_CHK_SET_ERR( rval, "can't set new values tag" );
00674 
00675 #ifdef MOAB_HAVE_MPI
00676     std::vector< double > total_mass( numTracers, 0. );
00677     double total_intx_area = 0;
00678     int mpi_err =
00679         MPI_Reduce( &total_mass_local[0], &total_mass[0], numTracers, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );
00680     if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
00681     // now reduce total area
00682     mpi_err = MPI_Reduce( &check_intx_area, &total_intx_area, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD );
00683     if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
00684     if( my_rank == 0 )
00685     {
00686         for( int k = 0; k < numTracers; k++ )
00687             std::cout << "total mass now tracer k=" << k + 1 << " " << total_mass[k] << "\n";
00688         std::cout << "check: total intersection area: (4 * M_PI * R^2): " << 4 * M_PI * Rsrc * Rsrc << " "
00689                   << total_intx_area << "\n";
00690     }
00691 
00692     if( remote_cells_with_tracers )
00693     {
00694         delete remote_cells_with_tracers;
00695         remote_cells_with_tracers = NULL;
00696     }
00697 #else
00698     for( int k = 0; k < numTracers; k++ )
00699         std::cout << "total mass now tracer k=" << k + 1 << " " << total_mass_local[k] << "\n";
00700     std::cout << "check: total intersection area: (4 * M_PI * R^2): " << 4 * M_PI * Rsrc * Rsrc << " "
00701               << check_intx_area << "\n";
00702 #endif
00703     return MB_SUCCESS;
00704 }
00705 
00706 #ifdef MOAB_HAVE_MPI
00707 ErrorCode Intx2MeshOnSphere::build_processor_euler_boxes( EntityHandle euler_set, Range& local_verts )
00708 {
00709     localEnts.clear();
00710     ErrorCode rval = mb->get_entities_by_dimension( euler_set, 2, localEnts );MB_CHK_SET_ERR( rval, "can't get local ents" );
00711 
00712     rval = mb->get_connectivity( localEnts, local_verts );MB_CHK_SET_ERR( rval, "can't get connectivity" );
00713     int num_local_verts = (int)local_verts.size();
00714 
00715     assert( parcomm != NULL );
00716 
00717     if( num_local_verts == 0 )
00718     {
00719         // it is probably point cloud, get the local vertices from set
00720         rval = mb->get_entities_by_dimension( euler_set, 0, local_verts );MB_CHK_SET_ERR( rval, "can't get local vertices from set" );
00721         num_local_verts = (int)local_verts.size();
00722         localEnts       = local_verts;
00723     }
00724     // will use 6 gnomonic planes to decide boxes for each gnomonic plane
00725     // each gnomonic box will be 2d, min, max
00726     double gnom_box[24];
00727     for( int i = 0; i < 6; i++ )
00728     {
00729         gnom_box[4 * i] = gnom_box[4 * i + 1] = DBL_MAX;
00730         gnom_box[4 * i + 2] = gnom_box[4 * i + 3] = -DBL_MAX;
00731     }
00732 
00733     // there are 6 gnomonic planes; some elements could be on the corners, and affect multiple
00734     // planes decide what gnomonic planes will be affected by each cell some elements could appear
00735     // in multiple gnomonic planes !
00736     std::vector< double > coords( 3 * num_local_verts );
00737     rval = mb->get_coords( local_verts, &coords[0] );MB_CHK_SET_ERR( rval, "can't get vertex coords" );ERRORR( rval, "can't get coords of vertices " );
00738     // decide each local vertex to what gnomonic plane it belongs
00739 
00740     std::vector< int > gnplane;
00741     gnplane.resize( num_local_verts );
00742     for( int i = 0; i < num_local_verts; i++ )
00743     {
00744         CartVect pos( &coords[3 * i] );
00745         int pl;
00746         IntxUtils::decide_gnomonic_plane( pos, pl );
00747         gnplane[i] = pl;
00748     }
00749 
00750     for( Range::iterator it = localEnts.begin(); it != localEnts.end(); it++ )
00751     {
00752         EntityHandle cell   = *it;
00753         EntityType typeCell = mb->type_from_handle( cell );  // could be vertex, for point cloud
00754         // get coordinates, and decide gnomonic planes for it
00755         int nnodes;
00756         const EntityHandle* conn = NULL;
00757         EntityHandle c[1];
00758         if( typeCell != MBVERTEX )
00759         {
00760             rval = mb->get_connectivity( cell, conn, nnodes );MB_CHK_SET_ERR( rval, "can't get connectivity" );
00761         }
00762         else
00763         {
00764             nnodes = 1;
00765             c[0]   = cell;  // actual node
00766             conn   = &c[0];
00767         }
00768         // get coordinates of vertices involved with this
00769         std::vector< double > elco( 3 * nnodes );
00770         std::set< int > planes;
00771         for( int i = 0; i < nnodes; i++ )
00772         {
00773             int ix = local_verts.index( conn[i] );
00774             planes.insert( gnplane[ix] );
00775             for( int j = 0; j < 3; j++ )
00776             {
00777                 elco[3 * i + j] = coords[3 * ix + j];
00778             }
00779         }
00780         // now, augment the boxes for all planes involved
00781         for( std::set< int >::iterator st = planes.begin(); st != planes.end(); st++ )
00782         {
00783             int pl = *st;
00784             for( int i = 0; i < nnodes; i++ )
00785             {
00786                 CartVect pos( &elco[3 * i] );
00787                 double c2[2];
00788                 IntxUtils::gnomonic_projection( pos, Rdest, pl, c2[0],
00789                                                 c2[1] );  // 2 coordinates
00790                 //
00791                 for( int k = 0; k < 2; k++ )
00792                 {
00793                     double val = c2[k];
00794                     if( val < gnom_box[4 * ( pl - 1 ) + k] ) gnom_box[4 * ( pl - 1 ) + k] = val;  // min in k direction
00795                     if( val > gnom_box[4 * ( pl - 1 ) + 2 + k] )
00796                         gnom_box[4 * ( pl - 1 ) + 2 + k] = val;  // max in k direction
00797                 }
00798             }
00799         }
00800     }
00801 
00802     int numprocs = parcomm->proc_config().proc_size();
00803     allBoxes.resize( 24 * numprocs );  // 6 gnomonic planes , 4 doubles for each for 2d box
00804 
00805     my_rank = parcomm->proc_config().proc_rank();
00806     for( int k = 0; k < 24; k++ )
00807         allBoxes[24 * my_rank + k] = gnom_box[k];
00808 
00809     // now communicate to get all boxes
00810     int mpi_err;
00811 #if( MPI_VERSION >= 2 )
00812     // use "in place" option
00813     mpi_err = MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL, &allBoxes[0], 24, MPI_DOUBLE,
00814                              parcomm->proc_config().proc_comm() );
00815 #else
00816     {
00817         std::vector< double > allBoxes_tmp( 24 * parcomm->proc_config().proc_size() );
00818         mpi_err  = MPI_Allgather( &allBoxes[24 * my_rank], 6, MPI_DOUBLE, &allBoxes_tmp[0], 24, MPI_DOUBLE,
00819                                   parcomm->proc_config().proc_comm() );
00820         allBoxes = allBoxes_tmp;
00821     }
00822 #endif
00823     if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
00824 
00825 #ifdef VERBOSE
00826     if( my_rank == 0 )
00827     {
00828         std::cout << " maximum number of vertices per cell are " << max_edges_1 << " on first mesh and " << max_edges_2
00829                   << " on second mesh \n";
00830         for( int i = 0; i < numprocs; i++ )
00831         {
00832             std::cout << "task: " << i << " \n";
00833             for( int pl = 1; pl <= 6; pl++ )
00834             {
00835                 std::cout << "  plane " << pl << " min: \t" << allBoxes[24 * i + 4 * ( pl - 1 )] << " \t"
00836                           << allBoxes[24 * i + 4 * ( pl - 1 ) + 1] << "\n";
00837                 std::cout << " \t  max: \t" << allBoxes[24 * i + 4 * ( pl - 1 ) + 2] << " \t"
00838                           << allBoxes[24 * i + 4 * ( pl - 1 ) + 3] << "\n";
00839             }
00840         }
00841     }
00842 #endif
00843 
00844     return MB_SUCCESS;
00845 }
00846 //#define VERBOSE
00847 // this will use the bounding boxes for the (euler)/ fix  mesh that are already established
00848 // will distribute the mesh to other procs, so that on each task, the covering set covers the local
00849 // bounding box this means it will cover the second (local) mesh set; So the covering set will cover
00850 // completely the second local mesh set (in intersection)
00851 ErrorCode Intx2MeshOnSphere::construct_covering_set( EntityHandle& initial_distributed_set, EntityHandle& covering_set )
00852 {
00853     // primary element came from, in the joint communicator ; this will be forwarded by coverage
00854     // mesh needed for tag migrate later on
00855     int defaultInt = -1;  // no processor, so it was not migrated from somewhere else
00856     ErrorCode rval = mb->tag_get_handle( "orig_sending_processor", 1, MB_TYPE_INTEGER, orgSendProcTag,
00857                                          MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create original sending processor tag" );
00858 
00859     assert( parcomm != NULL );
00860     Range meshCells;
00861     rval = mb->get_entities_by_dimension( initial_distributed_set, 2, meshCells );MB_CHK_SET_ERR( rval, "can't get cells by dimension from mesh set" );
00862 
00863     if( 1 == parcomm->proc_config().proc_size() )
00864     {
00865         // move all initial cells to coverage set
00866         rval = mb->add_entities( covering_set, meshCells );MB_CHK_SET_ERR( rval, "can't add primary ents to covering set" );
00867         // if point cloud source, add vertices
00868         if( 0 == meshCells.size() || max_edges_1 == 0 )
00869         {
00870             // add vertices from the source set
00871             Range verts;
00872             rval = mb->get_entities_by_dimension( initial_distributed_set, 0, verts );MB_CHK_SET_ERR( rval, "can't get vertices from mesh set" );
00873             rval = mb->add_entities( covering_set, verts );MB_CHK_SET_ERR( rval, "can't add primary ents to covering set" );
00874         }
00875         return MB_SUCCESS;
00876     }
00877 
00878     // mark on the coverage mesh where this element came from
00879     Tag sendProcTag;  /// for coverage mesh, will store the sender
00880     rval = mb->tag_get_handle( "sending_processor", 1, MB_TYPE_INTEGER, sendProcTag, MB_TAG_DENSE | MB_TAG_CREAT,
00881                                &defaultInt );MB_CHK_SET_ERR( rval, "can't create sending processor tag" );
00882 
00883     // this information needs to be forwarded to coverage mesh, if this mesh was already migrated
00884     // from somewhere else
00885     // look at the value of orgSendProcTag for one mesh cell; if -1, no need to forward that; if
00886     // !=-1, we know that this mesh was migrated, we need to find out more about origin of cell
00887     int orig_sender      = -1;
00888     EntityHandle oneCell = 0;
00889     // decide if we need to transfer global DOFs info attached to each HOMME coarse cell; first we
00890     // need to decide if the mesh has that tag; will affect the size of the tuple list involved in
00891     // the crystal routing
00892     int size_gdofs_tag = 0;
00893     std::vector< int > valsDOFs;
00894     Tag gdsTag;
00895     rval = mb->tag_get_handle( "GLOBAL_DOFS", gdsTag );
00896 
00897     if( meshCells.size() > 0 )
00898     {
00899         oneCell = meshCells[0];  // it is possible we do not have any cells, even after migration
00900         rval    = mb->tag_get_data( orgSendProcTag, &oneCell, 1, &orig_sender );MB_CHK_SET_ERR( rval, "can't get original sending processor value" );
00901         if( gdsTag )
00902         {
00903             DataType dtype;
00904             rval = mb->tag_get_data_type( gdsTag, dtype );
00905             if( MB_SUCCESS == rval && MB_TYPE_INTEGER == dtype )
00906             {
00907                 // find the values on first cell
00908                 int lenTag = 0;
00909                 rval       = mb->tag_get_length( gdsTag, lenTag );
00910                 if( MB_SUCCESS == rval && lenTag > 0 )
00911                 {
00912                     valsDOFs.resize( lenTag );
00913                     rval = mb->tag_get_data( gdsTag, &oneCell, 1, &valsDOFs[0] );
00914                     if( MB_SUCCESS == rval && valsDOFs[0] > 0 )
00915                     {
00916                         // first value positive means we really need to transport this data during
00917                         // coverage
00918                         size_gdofs_tag = lenTag;
00919                     }
00920                 }
00921             }
00922         }
00923     }
00924 
00925     // another collective call, to see if the mesh is migrated and if the GLOBAL_DOFS tag need to be
00926     // transferred over to the coverage mesh it is possible that there is no initial mesh source
00927     // mesh on the task, so we do not know that info from the tag but TupleList needs to be sized
00928     // uniformly for all tasks do a collective MPI_MAX to see if it is migrated and if we have
00929     // (collectively) a GLOBAL_DOFS task
00930 
00931     int local_int_array[2], global_int_array[2];
00932     local_int_array[0] = orig_sender;
00933     local_int_array[1] = size_gdofs_tag;
00934     // now reduce over all processors
00935     int mpi_err =
00936         MPI_Allreduce( local_int_array, global_int_array, 2, MPI_INT, MPI_MAX, parcomm->proc_config().proc_comm() );
00937     if( MPI_SUCCESS != mpi_err ) return MB_FAILURE;
00938     orig_sender    = global_int_array[0];
00939     size_gdofs_tag = global_int_array[1];
00940 #ifdef VERBOSE
00941     std::cout << "proc: " << my_rank << " size_gdofs_tag:" << size_gdofs_tag << "\n";
00942 #endif
00943     valsDOFs.resize( size_gdofs_tag );
00944 
00945     // finally, we have correct global info, we can decide if mesh was migrated and if we have
00946     // global dofs tag that need to be sent with coverage info
00947     int migrated_mesh = 0;
00948     if( orig_sender != -1 ) migrated_mesh = 1;  //
00949     // if size_gdofs_tag>0, we are sure valsDOFs got resized to what we need
00950 
00951     // get all mesh verts1
00952     Range mesh_verts;
00953     rval = mb->get_connectivity( meshCells, mesh_verts );MB_CHK_SET_ERR( rval, "can't get  mesh vertices" );
00954     int num_mesh_verts = (int)mesh_verts.size();
00955 
00956     // now see the mesh points positions; to what boxes should we send them?
00957     std::vector< double > coords_mesh( 3 * num_mesh_verts );
00958     rval = mb->get_coords( mesh_verts, &coords_mesh[0] );MB_CHK_SET_ERR( rval, "can't get mesh points position" );
00959 
00960     // decide gnomonic plane for each vertex, as in the compute boxes
00961     std::vector< int > gnplane;
00962     gnplane.resize( num_mesh_verts );
00963     for( int i = 0; i < num_mesh_verts; i++ )
00964     {
00965         CartVect pos( &coords_mesh[3 * i] );
00966         int pl;
00967         IntxUtils::decide_gnomonic_plane( pos, pl );
00968         gnplane[i] = pl;
00969     }
00970 
00971     std::vector< int > gids( num_mesh_verts );
00972     rval = mb->tag_get_data( gid, mesh_verts, &gids[0] );MB_CHK_SET_ERR( rval, "can't get vertices gids" );
00973 
00974     // ranges to send to each processor; will hold vertices and elements (quads/ polygons)
00975     // will look if the box of the mesh cell covers bounding box(es) (within tolerances)
00976     std::map< int, Range > Rto;
00977     int numprocs = parcomm->proc_config().proc_size();
00978 
00979     for( Range::iterator eit = meshCells.begin(); eit != meshCells.end(); ++eit )
00980     {
00981         EntityHandle q = *eit;
00982         const EntityHandle* conn;
00983         int num_nodes;
00984         rval = mb->get_connectivity( q, conn, num_nodes );MB_CHK_SET_ERR( rval, "can't get connectivity on cell" );
00985 
00986         // first decide what planes need to consider
00987         std::set< int > planes;  // if this list contains more than 3 planes, we have a very bad mesh!!!
00988         std::vector< double > elco( 3 * num_nodes );
00989         for( int i = 0; i < num_nodes; i++ )
00990         {
00991             EntityHandle v = conn[i];
00992             int index      = mesh_verts.index( v );
00993             planes.insert( gnplane[index] );
00994             for( int j = 0; j < 3; j++ )
00995             {
00996                 elco[3 * i + j] = coords_mesh[3 * index + j];  // extract from coords
00997             }
00998         }
00999         // now loop over all planes that need to be considered for this element
01000         for( std::set< int >::iterator st = planes.begin(); st != planes.end(); st++ )
01001         {
01002             int pl         = *st;  // gnomonic plane considered
01003             double qmin[2] = { DBL_MAX, DBL_MAX };
01004             double qmax[2] = { -DBL_MAX, -DBL_MAX };
01005             for( int i = 0; i < num_nodes; i++ )
01006             {
01007                 CartVect dp( &elco[3 * i] );  // uses constructor for CartVect that takes a
01008                                               // pointer to double
01009                 // gnomonic projection
01010                 double c2[2];
01011                 IntxUtils::gnomonic_projection( dp, Rsrc, pl, c2[0], c2[1] );  // 2 coordinates
01012                 for( int j = 0; j < 2; j++ )
01013                 {
01014                     if( qmin[j] > c2[j] ) qmin[j] = c2[j];
01015                     if( qmax[j] < c2[j] ) qmax[j] = c2[j];
01016                 }
01017             }
01018             // now decide if processor p should be interested in this cell, by looking at plane pl
01019             // 2d box this is one of the few size n loops;
01020             for( int p = 0; p < numprocs; p++ )  // each cell q can be sent to more than one processor
01021             {
01022                 double procMin1 = allBoxes[24 * p + 4 * ( pl - 1 )];  // these were determined before
01023                 //
01024                 if( procMin1 >= DBL_MAX )  // the processor has no targets on this plane
01025                     continue;
01026                 double procMin2 = allBoxes[24 * p + 4 * ( pl - 1 ) + 1];
01027                 double procMax1 = allBoxes[24 * p + 4 * ( pl - 1 ) + 2];
01028                 double procMax2 = allBoxes[24 * p + 4 * ( pl - 1 ) + 3];
01029                 // test overlap of 2d boxes
01030                 if( procMin1 > qmax[0] + box_error || procMin2 > qmax[1] + box_error ) continue;  //
01031                 if( qmin[0] > procMax1 + box_error || qmin[1] > procMax2 + box_error ) continue;
01032                 // good to be inserted
01033                 Rto[p].insert( q );
01034             }
01035         }
01036     }
01037 
01038     // here, we will use crystal router to send each cell to designated tasks (mesh migration)
01039 
01040     // a better implementation would be to use pcomm send / recv entities; a good test case
01041     // pcomm send / receives uses point to point communication, not global gather / scatter
01042 
01043     // now, build TLv and TLq  (tuple list for vertices and cells, separately sent)
01044     size_t numq = 0;
01045     size_t numv = 0;
01046 
01047     // merge the list of vertices to be sent
01048     for( int p = 0; p < numprocs; p++ )
01049     {
01050         if( p == (int)my_rank ) continue;  // do not "send" it to current task, because it is already here
01051         Range& range_to_P = Rto[p];
01052         // add the vertices to it
01053         if( range_to_P.empty() ) continue;  // nothing to send to proc p
01054 #ifdef VERBOSE
01055         std::cout << " proc : " << my_rank << " to proc " << p << " send " << range_to_P.size() << " cells "
01056                   << " psize: " << range_to_P.psize() << "\n";
01057 #endif
01058         Range vertsToP;
01059         rval = mb->get_connectivity( range_to_P, vertsToP );MB_CHK_SET_ERR( rval, "can't get connectivity" );
01060         numq = numq + range_to_P.size();
01061         numv = numv + vertsToP.size();
01062         range_to_P.merge( vertsToP );
01063     }
01064 
01065     TupleList TLv;  // send vertices with a different tuple list
01066     TupleList TLq;
01067     TLv.initialize( 2, 0, 0, 3, numv );  // to proc, GLOBAL ID, 3 real coordinates
01068     TLv.enableWriteAccess();
01069 
01070     // add also GLOBAL_DOFS info, if found on the mesh cell; it should be found only on HOMME cells!
01071     int sizeTuple =
01072         2 + max_edges_1 + migrated_mesh + size_gdofs_tag;  // max edges could be up to MAXEDGES :) for polygons
01073     TLq.initialize( sizeTuple, 0, 0, 0,
01074                     numq );  // to proc, elem GLOBAL ID, connectivity[max_edges] (global ID v), plus
01075                              // original sender if set (migrated mesh case)
01076     // we will not send the entity handle, global ID should be more than enough
01077     // we will not need more than 2B vertices
01078     // if we need more than 2B, we will need to use a different marker anyway (GLOBAL ID is not
01079     // enough then)
01080 
01081     TLq.enableWriteAccess();
01082 #ifdef VERBOSE
01083     std::cout << "from proc " << my_rank << " send " << numv << " vertices and " << numq << " elements\n";
01084 #endif
01085 
01086     for( int to_proc = 0; to_proc < numprocs; to_proc++ )
01087     {
01088         if( to_proc == (int)my_rank ) continue;
01089         Range& range_to_P = Rto[to_proc];
01090         Range V           = range_to_P.subset_by_type( MBVERTEX );
01091 
01092         for( Range::iterator it = V.begin(); it != V.end(); ++it )
01093         {
01094             EntityHandle v = *it;
01095             int index      = mesh_verts.index( v );  //
01096             assert( -1 != index );
01097             int n                = TLv.get_n();             // current size of tuple list
01098             TLv.vi_wr[2 * n]     = to_proc;                 // send to processor
01099             TLv.vi_wr[2 * n + 1] = gids[index];             // global id needs index in the second_mesh_verts range
01100             TLv.vr_wr[3 * n]     = coords_mesh[3 * index];  // departure position, of the node local_verts[i]
01101             TLv.vr_wr[3 * n + 1] = coords_mesh[3 * index + 1];
01102             TLv.vr_wr[3 * n + 2] = coords_mesh[3 * index + 2];
01103             TLv.inc_n();  // increment tuple list size
01104         }
01105         // also, prep the 2d cells for sending ...
01106         Range Q = range_to_P.subset_by_dimension( 2 );
01107         for( Range::iterator it = Q.begin(); it != Q.end(); ++it )
01108         {
01109             EntityHandle q = *it;  // this is a second mesh cell (or src, lagrange set)
01110             int global_id;
01111             rval = mb->tag_get_data( gid, &q, 1, &global_id );MB_CHK_SET_ERR( rval, "can't get gid for polygon" );
01112             int n                    = TLq.get_n();  // current size
01113             TLq.vi_wr[sizeTuple * n] = to_proc;      //
01114             TLq.vi_wr[sizeTuple * n + 1] =
01115                 global_id;  // global id of element, used to identify it for debug purposes only
01116             const EntityHandle* conn4;
01117             int num_nodes;  // could be up to MAXEDGES; max_edges?;
01118             rval = mb->get_connectivity( q, conn4, num_nodes );MB_CHK_SET_ERR( rval, "can't get connectivity for cell" );
01119             if( num_nodes > max_edges_1 )
01120             {
01121                 mb->list_entities( &q, 1 );MB_CHK_SET_ERR( MB_FAILURE, "too many nodes in a cell (" << num_nodes << "," << max_edges_1 << ")" );
01122             }
01123             for( int i = 0; i < num_nodes; i++ )
01124             {
01125                 EntityHandle v = conn4[i];
01126                 int index      = mesh_verts.index( v );
01127                 assert( -1 != index );
01128                 TLq.vi_wr[sizeTuple * n + 2 + i] = gids[index];
01129             }
01130             for( int k = num_nodes; k < max_edges_1; k++ )
01131             {
01132                 TLq.vi_wr[sizeTuple * n + 2 + k] =
01133                     0;  // fill the rest of node ids with 0; we know that the node ids start from 1!
01134             }
01135             int currentIndexIntTuple = 2 + max_edges_1;
01136             // is the mesh migrated before or not?
01137             if( migrated_mesh )
01138             {
01139                 rval = mb->tag_get_data( orgSendProcTag, &q, 1, &orig_sender );MB_CHK_SET_ERR( rval, "can't get original sender for polygon, in migrate scenario" );
01140                 TLq.vi_wr[sizeTuple * n + currentIndexIntTuple] = orig_sender;  // should be different than -1
01141                 currentIndexIntTuple++;
01142             }
01143             // GLOBAL_DOFS info, if available
01144             if( size_gdofs_tag )
01145             {
01146                 rval = mb->tag_get_data( gdsTag, &q, 1, &valsDOFs[0] );MB_CHK_SET_ERR( rval, "can't get gdofs data in HOMME" );
01147                 for( int i = 0; i < size_gdofs_tag; i++ )
01148                 {
01149                     TLq.vi_wr[sizeTuple * n + currentIndexIntTuple + i] =
01150                         valsDOFs[i];  // should be different than 0 or -1
01151                 }
01152             }
01153 
01154             TLq.inc_n();  // increment tuple list size
01155         }
01156     }  // end for loop over total number of processors
01157 
01158     // now we are done populating the tuples; route them to the appropriate processors
01159     // this does the communication magic
01160     ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv, 0 );
01161     ( parcomm->proc_config().crystal_router() )->gs_transfer( 1, TLq, 0 );
01162 
01163     // the first mesh elements are in localEnts; we do not need them at all
01164 
01165     // maps from global ids to new vertex and cell handles, that are added
01166 
01167     std::map< int, EntityHandle > globalID_to_vertex_handle;
01168     // we already have some vertices from second mesh set; they are already in the processor, even
01169     // before receiving other verts from neighbors this is an inverse map from gid to vertex handle,
01170     // which is local here, we do not want to duplicate vertices their identifier is the global ID!!
01171     // it must be unique per mesh ! (I mean, second mesh); gid gor first mesh is not needed here
01172     int k = 0;
01173     for( Range::iterator vit = mesh_verts.begin(); vit != mesh_verts.end(); ++vit, k++ )
01174     {
01175         globalID_to_vertex_handle[gids[k]] = *vit;
01176     }
01177     /*std::map<int, EntityHandle> globalID_to_eh;*/  // do we need this one?
01178     globalID_to_eh.clear();                          // we do not really need it, but we keep it for debugging mostly
01179 
01180     // now, look at every TLv, and see if we have to create a vertex there or not
01181     int n = TLv.get_n();  // the size of the points received
01182     for( int i = 0; i < n; i++ )
01183     {
01184         int globalId = TLv.vi_rd[2 * i + 1];
01185         if( globalID_to_vertex_handle.find( globalId ) ==
01186             globalID_to_vertex_handle.end() )  // we do not have locally this vertex (yet)
01187                                                // so we have to create it, and add to the inverse map
01188         {
01189             EntityHandle new_vert;
01190             double dp_pos[3] = { TLv.vr_wr[3 * i], TLv.vr_wr[3 * i + 1], TLv.vr_wr[3 * i + 2] };
01191             rval             = mb->create_vertex( dp_pos, new_vert );MB_CHK_SET_ERR( rval, "can't create new vertex " );
01192             globalID_to_vertex_handle[globalId] = new_vert;  // now add it to the map
01193             // set the GLOBAL ID tag on the new vertex
01194             rval = mb->tag_set_data( gid, &new_vert, 1, &globalId );MB_CHK_SET_ERR( rval, "can't set global ID tag on new vertex " );
01195         }
01196     }
01197 
01198     // now, all necessary vertices should be created
01199     // look in the local list of 2d cells for this proc, and add all those cells to covering set
01200     // also
01201 
01202     Range& local  = Rto[my_rank];
01203     Range local_q = local.subset_by_dimension( 2 );
01204 
01205     for( Range::iterator it = local_q.begin(); it != local_q.end(); ++it )
01206     {
01207         EntityHandle q = *it;  // these are from lagr cells, local
01208         int gid_el;
01209         rval = mb->tag_get_data( gid, &q, 1, &gid_el );MB_CHK_SET_ERR( rval, "can't get global id of cell " );
01210         assert( gid_el >= 0 );
01211         globalID_to_eh[gid_el] = q;  // do we need this? yes, now we do; parent tags are now using it heavily
01212         rval                   = mb->tag_set_data( sendProcTag, &q, 1, &my_rank );MB_CHK_SET_ERR( rval, "can't set sender for cell" );
01213     }
01214 
01215     // now look at all elements received through; we do not want to duplicate them
01216     n = TLq.get_n();  // number of elements received by this processor
01217     // a cell should be received from one proc only; so why are we so worried about duplicated
01218     // elements? a vertex can be received from multiple sources, that is fine
01219 
01220     for( int i = 0; i < n; i++ )
01221     {
01222         int globalIdEl = TLq.vi_rd[sizeTuple * i + 1];
01223         // int from_proc=TLq.vi_rd[sizeTuple * i ]; // we do not need from_proc anymore
01224 
01225         // do we already have a quad with this global ID, represented? no way !
01226         // if (globalID_to_eh.find(globalIdEl) == globalID_to_eh.end())
01227         //{
01228         // construct the conn triangle , quad or polygon
01229         EntityHandle new_conn[MAXEDGES];  // we should use std::vector with max_edges_1
01230         int nnodes = -1;
01231         for( int j = 0; j < max_edges_1; j++ )
01232         {
01233             int vgid = TLq.vi_rd[sizeTuple * i + 2 + j];  // vertex global ID
01234             if( vgid == 0 )
01235                 new_conn[j] = 0;  // this can actually happen for polygon mesh (when we have less
01236                                   // number of vertices than max_edges)
01237             else
01238             {
01239                 assert( globalID_to_vertex_handle.find( vgid ) != globalID_to_vertex_handle.end() );
01240                 new_conn[j] = globalID_to_vertex_handle[vgid];
01241                 nnodes      = j + 1;  // nodes are at the beginning, and are variable number
01242             }
01243         }
01244         EntityHandle new_element;
01245         //
01246         EntityType entType = MBQUAD;
01247         if( nnodes > 4 ) entType = MBPOLYGON;
01248         if( nnodes < 4 ) entType = MBTRI;
01249         rval = mb->create_element( entType, new_conn, nnodes, new_element );MB_CHK_SET_ERR( rval, "can't create new element for second mesh " );
01250 
01251         globalID_to_eh[globalIdEl] = new_element;
01252         local_q.insert( new_element );
01253         rval = mb->tag_set_data( gid, &new_element, 1, &globalIdEl );MB_CHK_SET_ERR( rval, "can't set gid for cell " );
01254         int currentIndexIntTuple = 2 + max_edges_1;
01255         if( migrated_mesh )
01256         {
01257             orig_sender = TLq.vi_wr[sizeTuple * i + currentIndexIntTuple];
01258             rval        = mb->tag_set_data( orgSendProcTag, &new_element, 1, &orig_sender );MB_CHK_SET_ERR( rval, "can't set original sender for cell, in migrate scenario" );
01259             currentIndexIntTuple++;  // add one more
01260         }
01261         // check if we need to retrieve and set GLOBAL_DOFS data
01262         if( size_gdofs_tag )
01263         {
01264             for( int j = 0; j < size_gdofs_tag; j++ )
01265             {
01266                 valsDOFs[j] = TLq.vi_wr[sizeTuple * i + currentIndexIntTuple + j];
01267             }
01268             rval = mb->tag_set_data( gdsTag, &new_element, 1, &valsDOFs[0] );MB_CHK_SET_ERR( rval, "can't set GLOBAL_DOFS data on coverage mesh" );
01269         }
01270         // store also the processor this coverage element came from
01271         int from_proc = TLq.vi_rd[sizeTuple * i];
01272         rval          = mb->tag_set_data( sendProcTag, &new_element, 1, &from_proc );MB_CHK_SET_ERR( rval, "can't set sender for cell" );
01273     }
01274 
01275     // now, create a new set, covering_set
01276     rval = mb->add_entities( covering_set, local_q );MB_CHK_SET_ERR( rval, "can't add entities to new mesh set " );
01277 #ifdef VERBOSE
01278     std::cout << " proc " << my_rank << " add " << local_q.size() << " cells to covering set \n";
01279 #endif
01280     return MB_SUCCESS;
01281 }
01282 
01283 #endif  // MOAB_HAVE_MPI
01284 //#undef VERBOSE
01285 #undef CHECK_CONVEXITY
01286 
01287 } /* namespace moab */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines