Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
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, ¤tVals[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 */