Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 /* 00002 * ===================================================================================== 00003 * 00004 * Filename: TempestRemapper.hpp 00005 * 00006 * Description: Interface to the TempestRemap library to enable intersection and 00007 * high-order conservative remapping of climate solution from 00008 * arbitrary resolution of source and target grids on the sphere. 00009 * 00010 * Author: Vijay S. Mahadevan (vijaysm), [email protected] 00011 * 00012 * ===================================================================================== 00013 */ 00014 00015 #include <string> 00016 #include <iostream> 00017 #include <cassert> 00018 #include "DebugOutput.hpp" 00019 #include "moab/Remapping/TempestRemapper.hpp" 00020 #include "moab/ReadUtilIface.hpp" 00021 00022 // Intersection includes 00023 #include "moab/IntxMesh/Intx2MeshOnSphere.hpp" 00024 #include "moab/IntxMesh/IntxUtils.hpp" 00025 00026 #include "moab/AdaptiveKDTree.hpp" 00027 #include "moab/SpatialLocator.hpp" 00028 00029 // skinner for augmenting overlap mesh to complete coverage 00030 #include "moab/Skinner.hpp" 00031 #include "MBParallelConventions.h" 00032 00033 #ifdef MOAB_HAVE_TEMPESTREMAP 00034 #include "GaussLobattoQuadrature.h" 00035 #endif 00036 00037 // #define VERBOSE 00038 00039 namespace moab 00040 { 00041 00042 /////////////////////////////////////////////////////////////////////////////////// 00043 00044 ErrorCode TempestRemapper::initialize( bool initialize_fsets ) 00045 { 00046 ErrorCode rval; 00047 if( initialize_fsets ) 00048 { 00049 rval = m_interface->create_meshset( moab::MESHSET_SET, m_source_set );MB_CHK_SET_ERR( rval, "Can't create new set" ); 00050 rval = m_interface->create_meshset( moab::MESHSET_SET, m_target_set );MB_CHK_SET_ERR( rval, "Can't create new set" ); 00051 rval = m_interface->create_meshset( moab::MESHSET_SET, m_overlap_set );MB_CHK_SET_ERR( rval, "Can't create new set" ); 00052 } 00053 else 00054 { 00055 m_source_set = 0; 00056 m_target_set = 0; 00057 m_overlap_set = 0; 00058 } 00059 00060 is_parallel = false; 00061 is_root = true; 00062 rank = 0; 00063 size = 1; 00064 #ifdef MOAB_HAVE_MPI 00065 int flagInit; 00066 MPI_Initialized( &flagInit ); 00067 if( flagInit ) 00068 { 00069 is_parallel = true; 00070 assert( m_pcomm != NULL ); 00071 rank = m_pcomm->rank(); 00072 size = m_pcomm->size(); 00073 is_root = ( rank == 0 ); 00074 } 00075 #endif 00076 00077 m_source = NULL; 00078 m_target = NULL; 00079 m_overlap = NULL; 00080 m_covering_source = NULL; 00081 00082 point_cloud_source = false; 00083 point_cloud_target = false; 00084 00085 return MB_SUCCESS; 00086 } 00087 00088 /////////////////////////////////////////////////////////////////////////////////// 00089 00090 TempestRemapper::~TempestRemapper() 00091 { 00092 this->clear(); 00093 } 00094 00095 ErrorCode TempestRemapper::clear() 00096 { 00097 // destroy all meshes 00098 if( m_source ) 00099 { 00100 delete m_source; 00101 m_source = NULL; 00102 } 00103 if( m_target ) 00104 { 00105 delete m_target; 00106 m_target = NULL; 00107 } 00108 if( m_overlap ) 00109 { 00110 delete m_overlap; 00111 m_overlap = NULL; 00112 } 00113 if( m_covering_source && size > 1 ) 00114 { 00115 delete m_covering_source; 00116 m_covering_source = NULL; 00117 } 00118 00119 point_cloud_source = false; 00120 point_cloud_target = false; 00121 00122 m_source_entities.clear(); 00123 m_source_vertices.clear(); 00124 m_covering_source_entities.clear(); 00125 m_covering_source_vertices.clear(); 00126 m_target_entities.clear(); 00127 m_target_vertices.clear(); 00128 m_overlap_entities.clear(); 00129 gid_to_lid_src.clear(); 00130 gid_to_lid_tgt.clear(); 00131 gid_to_lid_covsrc.clear(); 00132 lid_to_gid_src.clear(); 00133 lid_to_gid_tgt.clear(); 00134 lid_to_gid_covsrc.clear(); 00135 00136 return MB_SUCCESS; 00137 } 00138 00139 /////////////////////////////////////////////////////////////////////////////////// 00140 00141 ErrorCode TempestRemapper::LoadMesh( Remapper::IntersectionContext ctx, 00142 std::string inputFilename, 00143 TempestMeshType type ) 00144 { 00145 if( ctx == Remapper::SourceMesh ) 00146 { 00147 m_source_type = type; 00148 return load_tempest_mesh_private( inputFilename, &m_source ); 00149 } 00150 else if( ctx == Remapper::TargetMesh ) 00151 { 00152 m_target_type = type; 00153 return load_tempest_mesh_private( inputFilename, &m_target ); 00154 } 00155 else if( ctx != Remapper::DEFAULT ) 00156 { 00157 m_overlap_type = type; 00158 return load_tempest_mesh_private( inputFilename, &m_overlap ); 00159 } 00160 else 00161 { 00162 MB_CHK_SET_ERR( MB_FAILURE, "Invalid IntersectionContext context provided" ); 00163 } 00164 } 00165 00166 ErrorCode TempestRemapper::load_tempest_mesh_private( std::string inputFilename, Mesh** tempest_mesh ) 00167 { 00168 const bool outputEnabled = ( TempestRemapper::verbose && is_root ); 00169 if( outputEnabled ) std::cout << "\nLoading TempestRemap Mesh object from file = " << inputFilename << " ...\n"; 00170 00171 { 00172 NcError error( NcError::silent_nonfatal ); 00173 00174 try 00175 { 00176 // Load input mesh 00177 if( outputEnabled ) std::cout << "Loading mesh ...\n"; 00178 Mesh* mesh = new Mesh( inputFilename ); 00179 mesh->RemoveZeroEdges(); 00180 if( outputEnabled ) std::cout << "----------------\n"; 00181 00182 // Validate mesh 00183 if( meshValidate ) 00184 { 00185 if( outputEnabled ) std::cout << "Validating mesh ...\n"; 00186 mesh->Validate(); 00187 if( outputEnabled ) std::cout << "-------------------\n"; 00188 } 00189 00190 // Construct the edge map on the mesh 00191 if( constructEdgeMap ) 00192 { 00193 if( outputEnabled ) std::cout << "Constructing edge map on mesh ...\n"; 00194 mesh->ConstructEdgeMap( false ); 00195 if( outputEnabled ) std::cout << "---------------------------------\n"; 00196 } 00197 00198 if( tempest_mesh ) *tempest_mesh = mesh; 00199 } 00200 catch( Exception& e ) 00201 { 00202 std::cout << "TempestRemap ERROR: " << e.ToString() << "\n"; 00203 return MB_FAILURE; 00204 } 00205 catch( ... ) 00206 { 00207 return MB_FAILURE; 00208 } 00209 } 00210 return MB_SUCCESS; 00211 } 00212 00213 /////////////////////////////////////////////////////////////////////////////////// 00214 00215 ErrorCode TempestRemapper::ConvertTempestMesh( Remapper::IntersectionContext ctx ) 00216 { 00217 const bool outputEnabled = ( TempestRemapper::verbose && is_root ); 00218 if( ctx == Remapper::SourceMesh ) 00219 { 00220 if( outputEnabled ) std::cout << "Converting (source) TempestRemap Mesh object to MOAB representation ...\n"; 00221 return convert_tempest_mesh_private( m_source_type, m_source, m_source_set, m_source_entities, 00222 &m_source_vertices ); 00223 } 00224 else if( ctx == Remapper::TargetMesh ) 00225 { 00226 if( outputEnabled ) std::cout << "Converting (target) TempestRemap Mesh object to MOAB representation ...\n"; 00227 return convert_tempest_mesh_private( m_target_type, m_target, m_target_set, m_target_entities, 00228 &m_target_vertices ); 00229 } 00230 else if( ctx != Remapper::DEFAULT ) 00231 { 00232 if( outputEnabled ) std::cout << "Converting (overlap) TempestRemap Mesh object to MOAB representation ...\n"; 00233 return convert_tempest_mesh_private( m_overlap_type, m_overlap, m_overlap_set, m_overlap_entities, NULL ); 00234 } 00235 else 00236 { 00237 MB_CHK_SET_ERR( MB_FAILURE, "Invalid IntersectionContext context provided" ); 00238 } 00239 } 00240 00241 ErrorCode TempestRemapper::convert_tempest_mesh_private( TempestMeshType meshType, 00242 Mesh* mesh, 00243 EntityHandle& mesh_set, 00244 Range& entities, 00245 Range* vertices ) 00246 { 00247 ErrorCode rval; 00248 00249 const bool outputEnabled = ( TempestRemapper::verbose && is_root ); 00250 const NodeVector& nodes = mesh->nodes; 00251 const FaceVector& faces = mesh->faces; 00252 00253 moab::DebugOutput dbgprint( std::cout, this->rank, 0 ); 00254 dbgprint.set_prefix( "[TempestToMOAB]: " ); 00255 00256 ReadUtilIface* iface; 00257 rval = m_interface->query_interface( iface );MB_CHK_SET_ERR( rval, "Can't get reader interface" ); 00258 00259 Tag gidTag = m_interface->globalId_tag(); 00260 00261 // Set the data for the vertices 00262 std::vector< double* > arrays; 00263 std::vector< int > gidsv( nodes.size() ); 00264 EntityHandle startv; 00265 rval = iface->get_node_coords( 3, nodes.size(), 0, startv, arrays );MB_CHK_SET_ERR( rval, "Can't get node coords" ); 00266 for( unsigned iverts = 0; iverts < nodes.size(); ++iverts ) 00267 { 00268 const Node& node = nodes[iverts]; 00269 arrays[0][iverts] = node.x; 00270 arrays[1][iverts] = node.y; 00271 arrays[2][iverts] = node.z; 00272 gidsv[iverts] = iverts + 1; 00273 } 00274 Range mbverts( startv, startv + nodes.size() - 1 ); 00275 rval = m_interface->add_entities( mesh_set, mbverts );MB_CHK_SET_ERR( rval, "Can't add entities" ); 00276 rval = m_interface->tag_set_data( gidTag, mbverts, &gidsv[0] );MB_CHK_SET_ERR( rval, "Can't set global_id tag" ); 00277 00278 gidsv.clear(); 00279 entities.clear(); 00280 00281 Tag srcParentTag, tgtParentTag; 00282 std::vector< int > srcParent, tgtParent; 00283 bool storeParentInfo = ( mesh->vecSourceFaceIx.size() > 0 ); 00284 00285 if( storeParentInfo ) 00286 { 00287 int defaultInt = -1; 00288 rval = m_interface->tag_get_handle( "TargetParent", 1, MB_TYPE_INTEGER, tgtParentTag, 00289 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create positive tag" ); 00290 00291 rval = m_interface->tag_get_handle( "SourceParent", 1, MB_TYPE_INTEGER, srcParentTag, 00292 MB_TAG_DENSE | MB_TAG_CREAT, &defaultInt );MB_CHK_SET_ERR( rval, "can't create negative tag" ); 00293 } 00294 00295 // Let us first perform a full pass assuming arbitrary polygons. This is especially true for 00296 // overlap meshes. 00297 // 1. We do a first pass over faces, decipher edge size and group into categories based on 00298 // element type 00299 // 2. Next we loop over type, and add blocks of elements into MOAB 00300 // 3. For each block within the loop, also update the connectivity of elements. 00301 { 00302 if( outputEnabled ) 00303 dbgprint.printf( 0, "..Mesh size: Nodes [%zu] Elements [%zu].\n", nodes.size(), faces.size() ); 00304 const int NMAXPOLYEDGES = 15; 00305 std::vector< unsigned > nPolys( NMAXPOLYEDGES, 0 ); 00306 std::vector< std::vector< int > > typeNSeqs( NMAXPOLYEDGES ); 00307 for( unsigned ifaces = 0; ifaces < faces.size(); ++ifaces ) 00308 { 00309 const int iType = faces[ifaces].edges.size(); 00310 nPolys[iType]++; 00311 typeNSeqs[iType].push_back( ifaces ); 00312 } 00313 int iBlock = 0; 00314 for( unsigned iType = 0; iType < NMAXPOLYEDGES; ++iType ) 00315 { 00316 if( !nPolys[iType] ) continue; // Nothing to do 00317 00318 const unsigned num_v_per_elem = iType; 00319 EntityHandle starte; // Connectivity 00320 EntityHandle* conn; 00321 00322 // Allocate the connectivity array, depending on the element type 00323 switch( num_v_per_elem ) 00324 { 00325 case 3: 00326 if( outputEnabled ) 00327 dbgprint.printf( 0, "....Block %d: Triangular Elements [%u].\n", iBlock++, nPolys[iType] ); 00328 rval = iface->get_element_connect( nPolys[iType], num_v_per_elem, MBTRI, 0, starte, conn );MB_CHK_SET_ERR( rval, "Can't get element connectivity" ); 00329 break; 00330 case 4: 00331 if( outputEnabled ) 00332 dbgprint.printf( 0, "....Block %d: Quadrilateral Elements [%u].\n", iBlock++, nPolys[iType] ); 00333 rval = iface->get_element_connect( nPolys[iType], num_v_per_elem, MBQUAD, 0, starte, conn );MB_CHK_SET_ERR( rval, "Can't get element connectivity" ); 00334 break; 00335 default: 00336 if( outputEnabled ) 00337 dbgprint.printf( 0, "....Block %d: Polygonal [%u] Elements [%u].\n", iBlock++, iType, 00338 nPolys[iType] ); 00339 rval = iface->get_element_connect( nPolys[iType], num_v_per_elem, MBPOLYGON, 0, starte, conn );MB_CHK_SET_ERR( rval, "Can't get element connectivity" ); 00340 break; 00341 } 00342 00343 Range mbcells( starte, starte + nPolys[iType] - 1 ); 00344 m_interface->add_entities( mesh_set, mbcells ); 00345 00346 if( storeParentInfo ) 00347 { 00348 srcParent.resize( mbcells.size(), -1 ); 00349 tgtParent.resize( mbcells.size(), -1 ); 00350 } 00351 00352 std::vector< int > gids( typeNSeqs[iType].size() ); 00353 for( unsigned ifaces = 0, offset = 0; ifaces < typeNSeqs[iType].size(); ++ifaces ) 00354 { 00355 const int fIndex = typeNSeqs[iType][ifaces]; 00356 const Face& face = faces[fIndex]; 00357 // conn[offset++] = startv + face.edges[0].node[0]; 00358 for( unsigned iedges = 0; iedges < face.edges.size(); ++iedges ) 00359 { 00360 conn[offset++] = startv + face.edges[iedges].node[0]; 00361 } 00362 00363 if( storeParentInfo ) 00364 { 00365 srcParent[ifaces] = mesh->vecSourceFaceIx[fIndex] + 1; 00366 tgtParent[ifaces] = mesh->vecTargetFaceIx[fIndex] + 1; 00367 } 00368 00369 gids[ifaces] = typeNSeqs[iType][ifaces] + 1; 00370 } 00371 rval = m_interface->tag_set_data( gidTag, mbcells, &gids[0] );MB_CHK_SET_ERR( rval, "Can't set global_id tag" ); 00372 00373 if( meshType == OVERLAP_FILES ) 00374 { 00375 // Now let us update the adjacency data, because some elements are new 00376 rval = iface->update_adjacencies( starte, nPolys[iType], num_v_per_elem, conn );MB_CHK_SET_ERR( rval, "Can't update adjacencies" ); 00377 // Generate all adj entities dimension 1 and 2 (edges and faces/ tri or qua) 00378 Range edges; 00379 rval = m_interface->get_adjacencies( mbcells, 1, true, edges, Interface::UNION );MB_CHK_SET_ERR( rval, "Can't get edges" ); 00380 } 00381 00382 if( storeParentInfo ) 00383 { 00384 rval = m_interface->tag_set_data( srcParentTag, mbcells, &srcParent[0] );MB_CHK_SET_ERR( rval, "Can't set tag data" ); 00385 rval = m_interface->tag_set_data( tgtParentTag, mbcells, &tgtParent[0] );MB_CHK_SET_ERR( rval, "Can't set tag data" ); 00386 } 00387 entities.merge( mbcells ); 00388 } 00389 } 00390 00391 if( vertices ) *vertices = mbverts; 00392 00393 return MB_SUCCESS; 00394 } 00395 00396 /////////////////////////////////////////////////////////////////////////////////// 00397 00398 ErrorCode TempestRemapper::ConvertMeshToTempest( Remapper::IntersectionContext ctx ) 00399 { 00400 ErrorCode rval; 00401 const bool outputEnabled = ( TempestRemapper::verbose && is_root ); 00402 00403 moab::DebugOutput dbgprint( std::cout, this->rank, 0 ); 00404 dbgprint.set_prefix( "[MOABToTempest]: " ); 00405 00406 if( ctx == Remapper::SourceMesh ) 00407 { 00408 if( !m_source ) m_source = new Mesh(); 00409 if( outputEnabled ) dbgprint.printf( 0, "Converting (source) MOAB to TempestRemap Mesh representation ...\n" ); 00410 rval = convert_mesh_to_tempest_private( m_source, m_source_set, m_source_entities, &m_source_vertices );MB_CHK_SET_ERR( rval, "Can't convert source mesh to Tempest" ); 00411 if( m_source_entities.size() == 0 && m_source_vertices.size() != 0 ) 00412 { 00413 this->point_cloud_source = true; 00414 } 00415 } 00416 else if( ctx == Remapper::TargetMesh ) 00417 { 00418 if( !m_target ) m_target = new Mesh(); 00419 if( outputEnabled ) dbgprint.printf( 0, "Converting (target) MOAB to TempestRemap Mesh representation ...\n" ); 00420 rval = convert_mesh_to_tempest_private( m_target, m_target_set, m_target_entities, &m_target_vertices );MB_CHK_SET_ERR( rval, "Can't convert target mesh to Tempest" ); 00421 if( m_target_entities.size() == 0 && m_target_vertices.size() != 0 ) this->point_cloud_target = true; 00422 } 00423 else if( ctx == Remapper::OverlapMesh ) // Overlap mesh 00424 { 00425 if( !m_overlap ) m_overlap = new Mesh(); 00426 if( outputEnabled ) dbgprint.printf( 0, "Converting (overlap) MOAB to TempestRemap Mesh representation ...\n" ); 00427 rval = convert_overlap_mesh_sorted_by_source();MB_CHK_SET_ERR( rval, "Can't convert overlap mesh to Tempest" ); 00428 } 00429 else 00430 { 00431 MB_CHK_SET_ERR( MB_FAILURE, "Invalid IntersectionContext context provided" ); 00432 } 00433 00434 return rval; 00435 } 00436 00437 ErrorCode TempestRemapper::convert_mesh_to_tempest_private( Mesh* mesh, 00438 EntityHandle mesh_set, 00439 moab::Range& elems, 00440 moab::Range* pverts ) 00441 { 00442 ErrorCode rval; 00443 Range verts; 00444 00445 NodeVector& nodes = mesh->nodes; 00446 FaceVector& faces = mesh->faces; 00447 00448 elems.clear(); 00449 rval = m_interface->get_entities_by_dimension( mesh_set, 2, elems );MB_CHK_ERR( rval ); 00450 00451 // resize the number of elements in Tempest mesh 00452 faces.resize( elems.size() ); 00453 00454 // let us now get the vertices from all the elements 00455 rval = m_interface->get_connectivity( elems, verts );MB_CHK_ERR( rval ); 00456 if( verts.size() == 0 ) 00457 { 00458 rval = m_interface->get_entities_by_dimension( mesh_set, 0, verts );MB_CHK_ERR( rval ); 00459 } 00460 // assert(verts.size() > 0); // If not, this may be an invalid mesh ! possible for unbalanced 00461 // loads 00462 00463 std::map< EntityHandle, int > indxMap; 00464 bool useRange = true; 00465 if( verts.compactness() > 0.01 ) 00466 { 00467 int j = 0; 00468 for( Range::iterator it = verts.begin(); it != verts.end(); it++ ) 00469 indxMap[*it] = j++; 00470 useRange = false; 00471 } 00472 00473 for( unsigned iface = 0; iface < elems.size(); ++iface ) 00474 { 00475 Face& face = faces[iface]; 00476 EntityHandle ehandle = elems[iface]; 00477 00478 // get the connectivity for each edge 00479 const EntityHandle* connectface; 00480 int nnodesf; 00481 rval = m_interface->get_connectivity( ehandle, connectface, nnodesf );MB_CHK_ERR( rval ); 00482 00483 face.edges.resize( nnodesf ); 00484 for( int iverts = 0; iverts < nnodesf; ++iverts ) 00485 { 00486 int indx = ( useRange ? verts.index( connectface[iverts] ) : indxMap[connectface[iverts]] ); 00487 assert( indx >= 0 ); 00488 face.SetNode( iverts, indx ); 00489 } 00490 } 00491 00492 unsigned nnodes = verts.size(); 00493 nodes.resize( nnodes ); 00494 00495 // Set the data for the vertices 00496 std::vector< double > coordx( nnodes ), coordy( nnodes ), coordz( nnodes ); 00497 rval = m_interface->get_coords( verts, &coordx[0], &coordy[0], &coordz[0] );MB_CHK_ERR( rval ); 00498 for( unsigned inode = 0; inode < nnodes; ++inode ) 00499 { 00500 Node& node = nodes[inode]; 00501 node.x = coordx[inode]; 00502 node.y = coordy[inode]; 00503 node.z = coordz[inode]; 00504 } 00505 coordx.clear(); 00506 coordy.clear(); 00507 coordz.clear(); 00508 00509 mesh->RemoveZeroEdges(); 00510 mesh->RemoveCoincidentNodes(); 00511 00512 // Generate reverse node array and edge map 00513 if( constructEdgeMap ) mesh->ConstructEdgeMap( false ); 00514 // mesh->ConstructReverseNodeArray(); 00515 00516 // mesh->Validate(); 00517 00518 if( pverts ) 00519 { 00520 pverts->clear(); 00521 *pverts = verts; 00522 } 00523 verts.clear(); 00524 00525 return MB_SUCCESS; 00526 } 00527 00528 /////////////////////////////////////////////////////////////////////////////////// 00529 00530 bool IntPairComparator( const std::pair< int, int >& a, const std::pair< int, int >& b ) 00531 { 00532 if( a.first == b.first ) 00533 return a.second < b.second; 00534 else 00535 return a.first < b.first; 00536 } 00537 00538 moab::ErrorCode moab::TempestRemapper::GetOverlapAugmentedEntities( moab::Range& sharedGhostEntities ) 00539 { 00540 sharedGhostEntities.clear(); 00541 #ifdef MOAB_HAVE_MPI 00542 moab::ErrorCode rval; 00543 00544 // Remove entities in the intersection mesh that are part of the ghosted overlap 00545 if( is_parallel && size > 1 ) 00546 { 00547 moab::Range allents; 00548 rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, allents );MB_CHK_SET_ERR( rval, "Getting entities dim 2 failed" ); 00549 00550 moab::Range sharedents; 00551 moab::Tag ghostTag; 00552 std::vector< int > ghFlags( allents.size() ); 00553 rval = m_interface->tag_get_handle( "ORIG_PROC", ghostTag );MB_CHK_ERR( rval ); 00554 rval = m_interface->tag_get_data( ghostTag, allents, &ghFlags[0] );MB_CHK_ERR( rval ); 00555 for( unsigned i = 0; i < allents.size(); ++i ) 00556 if( ghFlags[i] >= 0 ) // it means it is a ghost overlap element 00557 sharedents.insert( allents[i] ); // this should not participate in smat! 00558 00559 allents = subtract( allents, sharedents ); 00560 00561 // Get connectivity from all ghosted elements and filter out 00562 // the vertices that are not owned 00563 moab::Range ownedverts, sharedverts; 00564 rval = m_interface->get_connectivity( allents, ownedverts );MB_CHK_SET_ERR( rval, "Deleting entities dim 0 failed" ); 00565 rval = m_interface->get_connectivity( sharedents, sharedverts );MB_CHK_SET_ERR( rval, "Deleting entities dim 0 failed" ); 00566 sharedverts = subtract( sharedverts, ownedverts ); 00567 // rval = m_interface->remove_entities(m_overlap_set, sharedents);MB_CHK_SET_ERR(rval, 00568 // "Deleting entities dim 2 failed"); rval = m_interface->remove_entities(m_overlap_set, 00569 // sharedverts);MB_CHK_SET_ERR(rval, "Deleting entities dim 0 failed"); 00570 00571 sharedGhostEntities.merge( sharedents ); 00572 // sharedGhostEntities.merge(sharedverts); 00573 } 00574 #endif 00575 return moab::MB_SUCCESS; 00576 } 00577 00578 ErrorCode TempestRemapper::convert_overlap_mesh_sorted_by_source() 00579 { 00580 ErrorCode rval; 00581 00582 m_overlap_entities.clear(); 00583 rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, m_overlap_entities );MB_CHK_ERR( rval ); 00584 00585 // Allocate for the overlap mesh 00586 if( !m_overlap ) m_overlap = new Mesh(); 00587 00588 size_t n_overlap_entities = m_overlap_entities.size(); 00589 00590 std::vector< std::pair< int, int > > sorted_overlap_order( n_overlap_entities ); 00591 { 00592 Tag srcParentTag, tgtParentTag; 00593 rval = m_interface->tag_get_handle( "SourceParent", srcParentTag );MB_CHK_ERR( rval ); 00594 rval = m_interface->tag_get_handle( "TargetParent", tgtParentTag );MB_CHK_ERR( rval ); 00595 // Overlap mesh: resize the source and target connection arrays 00596 m_overlap->vecTargetFaceIx.resize( n_overlap_entities ); 00597 m_overlap->vecSourceFaceIx.resize( n_overlap_entities ); 00598 00599 // Overlap mesh: resize the source and target connection arrays 00600 std::vector< int > rbids_src( n_overlap_entities ), rbids_tgt( n_overlap_entities ); 00601 rval = m_interface->tag_get_data( srcParentTag, m_overlap_entities, &rbids_src[0] );MB_CHK_ERR( rval ); 00602 rval = m_interface->tag_get_data( tgtParentTag, m_overlap_entities, &rbids_tgt[0] );MB_CHK_ERR( rval ); 00603 for( size_t ix = 0; ix < n_overlap_entities; ++ix ) 00604 { 00605 sorted_overlap_order[ix].first = 00606 ( gid_to_lid_covsrc.size() ? gid_to_lid_covsrc[rbids_src[ix]] : rbids_src[ix] ); 00607 sorted_overlap_order[ix].second = ix; 00608 } 00609 std::sort( sorted_overlap_order.begin(), sorted_overlap_order.end(), IntPairComparator ); 00610 // sorted_overlap_order[ie].second , ie=0,nOverlap-1 is the order such that overlap elems 00611 // are ordered by source parent 00612 00613 std::vector< int > ghFlags; 00614 if( is_parallel && size > 1 ) 00615 { 00616 Tag ghostTag; 00617 ghFlags.resize( n_overlap_entities ); 00618 rval = m_interface->tag_get_handle( "ORIG_PROC", ghostTag );MB_CHK_ERR( rval ); 00619 rval = m_interface->tag_get_data( ghostTag, m_overlap_entities, &ghFlags[0] );MB_CHK_ERR( rval ); 00620 } 00621 for( unsigned ie = 0; ie < n_overlap_entities; ++ie ) 00622 { 00623 int ix = sorted_overlap_order[ie].second; // original index of the element 00624 m_overlap->vecSourceFaceIx[ie] = 00625 ( gid_to_lid_covsrc.size() ? gid_to_lid_covsrc[rbids_src[ix]] : rbids_src[ix] - 1 ); 00626 if( is_parallel && size > 1 && ghFlags[ix] >= 0 ) // it means it is a ghost overlap element 00627 m_overlap->vecTargetFaceIx[ie] = -1; // this should not participate in smat! 00628 else 00629 m_overlap->vecTargetFaceIx[ie] = 00630 ( gid_to_lid_tgt.size() ? gid_to_lid_tgt[rbids_tgt[ix]] : rbids_tgt[ix] - 1 ); 00631 } 00632 } 00633 00634 FaceVector& faces = m_overlap->faces; 00635 faces.resize( n_overlap_entities ); 00636 00637 Range verts; 00638 // let us now get the vertices from all the elements 00639 rval = m_interface->get_connectivity( m_overlap_entities, verts );MB_CHK_ERR( rval ); 00640 // std::cout << "Vertices size = " << verts.size() << " , psize = " << verts.psize() << ", 00641 // compactness = " << verts.compactness() << std::endl; 00642 00643 std::map< EntityHandle, int > indxMap; 00644 bool useRange = true; 00645 if( verts.compactness() > 0.01 ) 00646 { 00647 int j = 0; 00648 for( Range::iterator it = verts.begin(); it != verts.end(); ++it ) 00649 indxMap[*it] = j++; 00650 useRange = false; 00651 } 00652 00653 for( unsigned ifac = 0; ifac < m_overlap_entities.size(); ++ifac ) 00654 { 00655 const unsigned iface = sorted_overlap_order[ifac].second; 00656 Face& face = faces[ifac]; 00657 EntityHandle ehandle = m_overlap_entities[iface]; 00658 00659 // get the connectivity for each edge 00660 const EntityHandle* connectface; 00661 int nnodesf; 00662 rval = m_interface->get_connectivity( ehandle, connectface, nnodesf );MB_CHK_ERR( rval ); 00663 00664 face.edges.resize( nnodesf ); 00665 for( int iverts = 0; iverts < nnodesf; ++iverts ) 00666 { 00667 int indx = ( useRange ? verts.index( connectface[iverts] ) : indxMap[connectface[iverts]] ); 00668 assert( indx >= 0 ); 00669 face.SetNode( iverts, indx ); 00670 } 00671 } 00672 00673 unsigned nnodes = verts.size(); 00674 NodeVector& nodes = m_overlap->nodes; 00675 nodes.resize( nnodes ); 00676 00677 // Set the data for the vertices 00678 std::vector< double > coordx( nnodes ), coordy( nnodes ), coordz( nnodes ); 00679 rval = m_interface->get_coords( verts, &coordx[0], &coordy[0], &coordz[0] );MB_CHK_ERR( rval ); 00680 for( unsigned inode = 0; inode < nnodes; ++inode ) 00681 { 00682 Node& node = nodes[inode]; 00683 node.x = coordx[inode]; 00684 node.y = coordy[inode]; 00685 node.z = coordz[inode]; 00686 } 00687 coordx.clear(); 00688 coordy.clear(); 00689 coordz.clear(); 00690 verts.clear(); 00691 00692 m_overlap->RemoveZeroEdges(); 00693 m_overlap->RemoveCoincidentNodes( false ); 00694 00695 // Generate reverse node array and edge map 00696 // if ( constructEdgeMap ) m_overlap->ConstructEdgeMap(false); 00697 // m_overlap->ConstructReverseNodeArray(); 00698 00699 // m_overlap->Validate(); 00700 return MB_SUCCESS; 00701 } 00702 00703 // Should be ordered as Source, Target, Overlap 00704 ErrorCode TempestRemapper::ComputeGlobalLocalMaps() 00705 { 00706 ErrorCode rval; 00707 00708 if( 0 == m_covering_source ) 00709 { 00710 m_covering_source = new Mesh(); 00711 rval = convert_mesh_to_tempest_private( m_covering_source, m_covering_source_set, m_covering_source_entities, 00712 &m_covering_source_vertices );MB_CHK_SET_ERR( rval, "Can't convert source Tempest mesh" ); 00713 // std::cout << "ComputeGlobalLocalMaps: " << rank << ", " << " covering entities = [" << 00714 // m_covering_source_vertices.size() << ", " << m_covering_source_entities.size() << "]\n"; 00715 } 00716 gid_to_lid_src.clear(); 00717 lid_to_gid_src.clear(); 00718 gid_to_lid_covsrc.clear(); 00719 lid_to_gid_covsrc.clear(); 00720 gid_to_lid_tgt.clear(); 00721 lid_to_gid_tgt.clear(); 00722 { 00723 Tag gidtag = m_interface->globalId_tag(); 00724 00725 std::vector< int > gids; 00726 if( point_cloud_source ) 00727 { 00728 gids.resize( m_covering_source_vertices.size(), -1 ); 00729 rval = m_interface->tag_get_data( gidtag, m_covering_source_vertices, &gids[0] );MB_CHK_ERR( rval ); 00730 } 00731 else 00732 { 00733 gids.resize( m_covering_source_entities.size(), -1 ); 00734 rval = m_interface->tag_get_data( gidtag, m_covering_source_entities, &gids[0] );MB_CHK_ERR( rval ); 00735 } 00736 for( unsigned ie = 0; ie < gids.size(); ++ie ) 00737 { 00738 gid_to_lid_covsrc[gids[ie]] = ie; 00739 lid_to_gid_covsrc[ie] = gids[ie]; 00740 } 00741 00742 if( point_cloud_source ) 00743 { 00744 gids.resize( m_source_vertices.size(), -1 ); 00745 rval = m_interface->tag_get_data( gidtag, m_source_vertices, &gids[0] );MB_CHK_ERR( rval ); 00746 } 00747 else 00748 { 00749 gids.resize( m_source_entities.size(), -1 ); 00750 rval = m_interface->tag_get_data( gidtag, m_source_entities, &gids[0] );MB_CHK_ERR( rval ); 00751 } 00752 for( unsigned ie = 0; ie < gids.size(); ++ie ) 00753 { 00754 gid_to_lid_src[gids[ie]] = ie; 00755 lid_to_gid_src[ie] = gids[ie]; 00756 } 00757 00758 if( point_cloud_target ) 00759 { 00760 gids.resize( m_target_vertices.size(), -1 ); 00761 rval = m_interface->tag_get_data( gidtag, m_target_vertices, &gids[0] );MB_CHK_ERR( rval ); 00762 } 00763 else 00764 { 00765 gids.resize( m_target_entities.size(), -1 ); 00766 rval = m_interface->tag_get_data( gidtag, m_target_entities, &gids[0] );MB_CHK_ERR( rval ); 00767 } 00768 for( unsigned ie = 0; ie < gids.size(); ++ie ) 00769 { 00770 gid_to_lid_tgt[gids[ie]] = ie; 00771 lid_to_gid_tgt[ie] = gids[ie]; 00772 } 00773 } 00774 00775 return MB_SUCCESS; 00776 } 00777 00778 /////////////////////////////////////////////////////////////////////////////////// 00779 00780 moab::ErrorCode moab::TempestRemapper::WriteTempestIntersectionMesh( std::string strOutputFileName, 00781 const bool fAllParallel, 00782 const bool fInputConcave, 00783 const bool fOutputConcave ) 00784 { 00785 // Let us alos write out the TempestRemap equivalent so that we can do some verification checks 00786 if( fAllParallel ) 00787 { 00788 if( is_root && size == 1 ) 00789 { 00790 this->m_source->CalculateFaceAreas( fInputConcave ); 00791 this->m_target->CalculateFaceAreas( fOutputConcave ); 00792 this->m_overlap->Write( strOutputFileName.c_str(), NcFile::Netcdf4 ); 00793 } 00794 else 00795 { 00796 // Perform reduction and write from root processor 00797 // if ( is_root ) 00798 // std::cout << "--- PARALLEL IMPLEMENTATION is NOT AVAILABLE yet ---\n"; 00799 00800 this->m_source->CalculateFaceAreas( fInputConcave ); 00801 this->m_covering_source->CalculateFaceAreas( fInputConcave ); 00802 this->m_target->CalculateFaceAreas( fOutputConcave ); 00803 this->m_overlap->Write( strOutputFileName.c_str(), NcFile::Netcdf4 ); 00804 } 00805 } 00806 else 00807 { 00808 this->m_source->CalculateFaceAreas( fInputConcave ); 00809 this->m_target->CalculateFaceAreas( fOutputConcave ); 00810 this->m_overlap->Write( strOutputFileName.c_str(), NcFile::Netcdf4 ); 00811 } 00812 00813 return moab::MB_SUCCESS; 00814 } 00815 void TempestRemapper::SetMeshSet( Remapper::IntersectionContext ctx /* Remapper::CoveringMesh*/, 00816 moab::EntityHandle mset, 00817 moab::Range& entities ) 00818 { 00819 00820 if( ctx == Remapper::SourceMesh ) // should not be used 00821 { 00822 m_source_entities = entities; 00823 m_source_set = mset; 00824 } 00825 else if( ctx == Remapper::TargetMesh ) 00826 { 00827 m_target_entities = entities; 00828 m_target_set = mset; 00829 } 00830 else if( ctx == Remapper::CoveringMesh ) 00831 { 00832 m_covering_source_entities = entities; 00833 m_covering_source_set = mset; 00834 } 00835 else 00836 { 00837 // some error 00838 } 00839 return; 00840 } 00841 /////////////////////////////////////////////////////////////////////////////////// 00842 00843 #ifndef MOAB_HAVE_MPI 00844 ErrorCode TempestRemapper::assign_vertex_element_IDs( Tag idtag, 00845 EntityHandle this_set, 00846 const int dimension, 00847 const int start_id ) 00848 { 00849 assert( idtag ); 00850 00851 ErrorCode rval; 00852 Range entities; 00853 rval = m_interface->get_entities_by_dimension( this_set, dimension, entities );MB_CHK_SET_ERR( rval, "Failed to get entities" ); 00854 00855 if( entities.size() == 0 ) return moab::MB_SUCCESS; 00856 00857 int idoffset = start_id; 00858 std::vector< int > gid( entities.size() ); 00859 for( unsigned i = 0; i < entities.size(); ++i ) 00860 gid[i] = idoffset++; 00861 00862 rval = m_interface->tag_set_data( idtag, entities, &gid[0] );MB_CHK_ERR( rval ); 00863 00864 return moab::MB_SUCCESS; 00865 } 00866 #endif 00867 00868 /////////////////////////////////////////////////////////////////////////////// 00869 00870 // Create a custom comparator for Nodes 00871 bool operator<( Node const& lhs, Node const& rhs ) 00872 { 00873 return std::pow( lhs.x - rhs.x, 2.0 ) + std::pow( lhs.y - rhs.y, 2.0 ) + std::pow( lhs.z - rhs.z, 2.0 ); 00874 } 00875 00876 ErrorCode TempestRemapper::GenerateCSMeshMetadata( const int ntot_elements, 00877 moab::Range& ents, 00878 moab::Range* secondary_ents, 00879 const std::string& dofTagName, 00880 int nP ) 00881 { 00882 Mesh csMesh; 00883 int err; 00884 moab::ErrorCode rval; 00885 00886 const int res = std::sqrt( ntot_elements / 6 ); 00887 00888 // create a temporary CS mesh 00889 // NOTE: This will not work for RRM grids. Need to run HOMME for that case anyway 00890 err = GenerateCSMesh( csMesh, res, "", "NetCDF4" ); 00891 if( err ) 00892 { 00893 MB_CHK_SET_ERR( MB_FAILURE, "Failed to generate CS mesh through TempestRemap" ); 00894 ; 00895 } 00896 00897 rval = this->GenerateMeshMetadata( csMesh, ntot_elements, ents, secondary_ents, dofTagName, nP );MB_CHK_SET_ERR( rval, "Failed in call to GenerateMeshMetadata" ); 00898 00899 return moab::MB_SUCCESS; 00900 } 00901 00902 ErrorCode TempestRemapper::GenerateMeshMetadata( Mesh& csMesh, 00903 const int ntot_elements, 00904 moab::Range& ents, 00905 moab::Range* secondary_ents, 00906 const std::string dofTagName, 00907 int nP ) 00908 { 00909 moab::ErrorCode rval; 00910 00911 Tag dofTag; 00912 bool created = false; 00913 rval = m_interface->tag_get_handle( dofTagName.c_str(), nP * nP, MB_TYPE_INTEGER, dofTag, 00914 MB_TAG_DENSE | MB_TAG_CREAT, 0, &created );MB_CHK_SET_ERR( rval, "Failed creating DoF tag" ); 00915 00916 // Number of Faces 00917 int nElements = static_cast< int >( csMesh.faces.size() ); 00918 00919 assert( nElements == ntot_elements ); 00920 00921 // Initialize data structures 00922 DataArray3D< int > dataGLLnodes; 00923 dataGLLnodes.Allocate( nP, nP, nElements ); 00924 00925 std::map< Node, int > mapNodes; 00926 std::map< Node, moab::EntityHandle > mapLocalMBNodes; 00927 00928 // GLL Quadrature nodes 00929 DataArray1D< double > dG; 00930 DataArray1D< double > dW; 00931 GaussLobattoQuadrature::GetPoints( nP, 0.0, 1.0, dG, dW ); 00932 00933 moab::Range entities( ents ); 00934 if( secondary_ents ) entities.insert( secondary_ents->begin(), secondary_ents->end() ); 00935 double elcoords[3]; 00936 for( unsigned iel = 0; iel < entities.size(); ++iel ) 00937 { 00938 EntityHandle eh = entities[iel]; 00939 rval = m_interface->get_coords( &eh, 1, elcoords ); 00940 Node elCentroid( elcoords[0], elcoords[1], elcoords[2] ); 00941 mapLocalMBNodes.insert( std::pair< Node, moab::EntityHandle >( elCentroid, eh ) ); 00942 } 00943 00944 // Build a Kd-tree for local mesh (nearest neighbor searches) 00945 // Loop over all elements in CS-Mesh 00946 // Then find if current centroid is in an element 00947 // If yes - then let us compute the DoF numbering and set to tag data 00948 // If no - then compute DoF numbering BUT DO NOT SET to tag data 00949 // continue 00950 int* dofIDs = new int[nP * nP]; 00951 00952 // Write metadata 00953 for( int k = 0; k < nElements; k++ ) 00954 { 00955 const Face& face = csMesh.faces[k]; 00956 const NodeVector& nodes = csMesh.nodes; 00957 00958 if( face.edges.size() != 4 ) 00959 { 00960 _EXCEPTIONT( "Mesh must only contain quadrilateral elements" ); 00961 } 00962 00963 Node centroid; 00964 centroid.x = centroid.y = centroid.z = 0.0; 00965 for( unsigned l = 0; l < face.edges.size(); ++l ) 00966 { 00967 centroid.x += nodes[face[l]].x; 00968 centroid.y += nodes[face[l]].y; 00969 centroid.z += nodes[face[l]].z; 00970 } 00971 const double factor = 1.0 / face.edges.size(); 00972 centroid.x *= factor; 00973 centroid.y *= factor; 00974 centroid.z *= factor; 00975 00976 bool locElem = false; 00977 EntityHandle current_eh; 00978 if( mapLocalMBNodes.find( centroid ) != mapLocalMBNodes.end() ) 00979 { 00980 locElem = true; 00981 current_eh = mapLocalMBNodes[centroid]; 00982 } 00983 00984 for( int j = 0; j < nP; j++ ) 00985 { 00986 for( int i = 0; i < nP; i++ ) 00987 { 00988 00989 // Get local map vectors 00990 Node nodeGLL; 00991 Node dDx1G; 00992 Node dDx2G; 00993 00994 // ApplyLocalMap( 00995 // face, 00996 // nodevec, 00997 // dG[i], 00998 // dG[j], 00999 // nodeGLL, 01000 // dDx1G, 01001 // dDx2G); 01002 const double& dAlpha = dG[i]; 01003 const double& dBeta = dG[j]; 01004 01005 // Calculate nodal locations on the plane 01006 double dXc = nodes[face[0]].x * ( 1.0 - dAlpha ) * ( 1.0 - dBeta ) + 01007 nodes[face[1]].x * dAlpha * ( 1.0 - dBeta ) + nodes[face[2]].x * dAlpha * dBeta + 01008 nodes[face[3]].x * ( 1.0 - dAlpha ) * dBeta; 01009 01010 double dYc = nodes[face[0]].y * ( 1.0 - dAlpha ) * ( 1.0 - dBeta ) + 01011 nodes[face[1]].y * dAlpha * ( 1.0 - dBeta ) + nodes[face[2]].y * dAlpha * dBeta + 01012 nodes[face[3]].y * ( 1.0 - dAlpha ) * dBeta; 01013 01014 double dZc = nodes[face[0]].z * ( 1.0 - dAlpha ) * ( 1.0 - dBeta ) + 01015 nodes[face[1]].z * dAlpha * ( 1.0 - dBeta ) + nodes[face[2]].z * dAlpha * dBeta + 01016 nodes[face[3]].z * ( 1.0 - dAlpha ) * dBeta; 01017 01018 double dR = sqrt( dXc * dXc + dYc * dYc + dZc * dZc ); 01019 01020 // Mapped node location 01021 nodeGLL.x = dXc / dR; 01022 nodeGLL.y = dYc / dR; 01023 nodeGLL.z = dZc / dR; 01024 01025 // Determine if this is a unique Node 01026 std::map< Node, int >::const_iterator iter = mapNodes.find( nodeGLL ); 01027 if( iter == mapNodes.end() ) 01028 { 01029 // Insert new unique node into map 01030 int ixNode = static_cast< int >( mapNodes.size() ); 01031 mapNodes.insert( std::pair< Node, int >( nodeGLL, ixNode ) ); 01032 dataGLLnodes[j][i][k] = ixNode + 1; 01033 } 01034 else 01035 { 01036 dataGLLnodes[j][i][k] = iter->second + 1; 01037 } 01038 01039 dofIDs[j * nP + i] = dataGLLnodes[j][i][k]; 01040 } 01041 } 01042 01043 if( locElem ) 01044 { 01045 rval = m_interface->tag_set_data( dofTag, ¤t_eh, 1, dofIDs );MB_CHK_SET_ERR( rval, "Failed to tag_set_data for DoFs" ); 01046 } 01047 } 01048 01049 // clear memory 01050 delete[] dofIDs; 01051 mapLocalMBNodes.clear(); 01052 mapNodes.clear(); 01053 01054 return moab::MB_SUCCESS; 01055 } 01056 01057 /////////////////////////////////////////////////////////////////////////////////// 01058 01059 ErrorCode TempestRemapper::ConstructCoveringSet( double tolerance, 01060 double radius_src, 01061 double radius_tgt, 01062 double boxeps, 01063 bool regional_mesh ) 01064 { 01065 ErrorCode rval; 01066 01067 rrmgrids = regional_mesh; 01068 moab::Range local_verts; 01069 01070 // Initialize intersection context 01071 mbintx = new moab::Intx2MeshOnSphere( m_interface ); 01072 01073 mbintx->set_error_tolerance( tolerance ); 01074 mbintx->set_radius_source_mesh( radius_src ); 01075 mbintx->set_radius_destination_mesh( radius_tgt ); 01076 mbintx->set_box_error( boxeps ); 01077 #ifdef MOAB_HAVE_MPI 01078 mbintx->set_parallel_comm( m_pcomm ); 01079 #endif 01080 01081 // compute the maxiumum edges in elements comprising source and target mesh 01082 rval = mbintx->FindMaxEdges( m_source_set, m_target_set );MB_CHK_ERR( rval ); 01083 01084 this->max_source_edges = mbintx->max_edges_1; 01085 this->max_target_edges = mbintx->max_edges_2; 01086 01087 // Note: lots of communication possible, if mesh is distributed very differently 01088 #ifdef MOAB_HAVE_MPI 01089 if( is_parallel ) 01090 { 01091 rval = mbintx->build_processor_euler_boxes( m_target_set, local_verts );MB_CHK_ERR( rval ); 01092 01093 rval = m_interface->create_meshset( moab::MESHSET_SET, m_covering_source_set );MB_CHK_SET_ERR( rval, "Can't create new set" ); 01094 01095 rval = mbintx->construct_covering_set( m_source_set, m_covering_source_set );MB_CHK_ERR( rval ); 01096 // if (rank == 1) 01097 // { 01098 // moab::Range ents; 01099 // m_interface->get_entities_by_dimension(m_covering_source_set, 2, ents); 01100 // m_interface->remove_entities(m_covering_source_set, ents); 01101 // } 01102 } 01103 else 01104 { 01105 #endif 01106 if( rrmgrids ) 01107 { 01108 rval = m_interface->create_meshset( moab::MESHSET_SET, m_covering_source_set );MB_CHK_SET_ERR( rval, "Can't create new set" ); 01109 01110 double tolerance = 1e-6, btolerance = 1e-3; 01111 moab::AdaptiveKDTree tree( m_interface ); 01112 moab::Range targetVerts; 01113 01114 rval = m_interface->get_connectivity( m_target_entities, targetVerts, true );MB_CHK_ERR( rval ); 01115 01116 rval = tree.build_tree( m_source_entities, &m_source_set );MB_CHK_ERR( rval ); 01117 01118 for( unsigned ie = 0; ie < targetVerts.size(); ++ie ) 01119 { 01120 EntityHandle el = targetVerts[ie], leaf; 01121 double point[3]; 01122 01123 // Get the element centroid to be queried 01124 rval = m_interface->get_coords( &el, 1, point );MB_CHK_ERR( rval ); 01125 01126 // Search for the closest source element in the master mesh corresponding 01127 // to the target element centroid in the slave mesh 01128 rval = tree.point_search( point, leaf, tolerance, btolerance );MB_CHK_ERR( rval ); 01129 01130 if( leaf == 0 ) 01131 { 01132 leaf = m_source_set; // no hint 01133 } 01134 01135 std::vector< moab::EntityHandle > leaf_elems; 01136 // We only care about the dimension that the user specified. 01137 // MOAB partitions are ordered by elements anyway. 01138 rval = m_interface->get_entities_by_dimension( leaf, 2, leaf_elems );MB_CHK_ERR( rval ); 01139 01140 if( !leaf_elems.size() ) 01141 { 01142 // std::cout << ie << ": " << " No leaf elements found." << std::endl; 01143 continue; 01144 } 01145 01146 // Now get the master element centroids so that we can compute 01147 // the minimum distance to the target point 01148 std::vector< double > centroids( leaf_elems.size() * 3 ); 01149 rval = m_interface->get_coords( &leaf_elems[0], leaf_elems.size(), ¢roids[0] );MB_CHK_ERR( rval ); 01150 01151 double dist = 1e5; 01152 int pinelem = -1; 01153 for( size_t il = 0; il < leaf_elems.size(); ++il ) 01154 { 01155 const double* centroid = ¢roids[il * 3]; 01156 const double locdist = std::pow( point[0] - centroid[0], 2 ) + 01157 std::pow( point[1] - centroid[1], 2 ) + 01158 std::pow( point[2] - centroid[2], 2 ); 01159 01160 if( locdist < dist ) 01161 { 01162 dist = locdist; 01163 pinelem = il; 01164 m_covering_source_entities.insert( leaf_elems[il] ); 01165 } 01166 } 01167 01168 if( pinelem < 0 ) 01169 { 01170 std::cout << ie 01171 << ": [Error] - Could not find a minimum distance within the leaf " 01172 "nodes. Dist = " 01173 << dist << std::endl; 01174 } 01175 } 01176 // rval = tree.reset_tree();MB_CHK_ERR(rval); 01177 std::cout << "[INFO] - Total covering source entities = " << m_covering_source_entities.size() << std::endl; 01178 rval = m_interface->add_entities( m_covering_source_set, m_covering_source_entities );MB_CHK_ERR( rval ); 01179 } 01180 else 01181 { 01182 m_covering_source_set = m_source_set; 01183 m_covering_source = m_source; 01184 m_covering_source_entities = m_source_entities; // this is a tempest mesh object; careful about 01185 // incrementing the reference? 01186 m_covering_source_vertices = m_source_vertices; // this is a tempest mesh object; careful about 01187 // incrementing the reference? 01188 } 01189 #ifdef MOAB_HAVE_MPI 01190 } 01191 #endif 01192 01193 return rval; 01194 } 01195 01196 ErrorCode TempestRemapper::ComputeOverlapMesh( bool kdtree_search, bool use_tempest ) 01197 { 01198 ErrorCode rval; 01199 const bool outputEnabled = ( this->rank == 0 ); 01200 moab::DebugOutput dbgprint( std::cout, this->rank, 0 ); 01201 dbgprint.set_prefix( "[ComputeOverlapMesh]: " ); 01202 01203 // const double radius = 1.0 /*2.0*acos(-1.0)*/; 01204 // const double boxeps = 0.1; 01205 // Create the intersection on the sphere object and set up necessary parameters 01206 01207 // First, split based on whether to use Tempest or MOAB 01208 // If Tempest 01209 // 1) Check for valid Mesh and pointers to objects for source/target 01210 // 2) Invoke GenerateOverlapWithMeshes routine from Tempest library 01211 // If MOAB 01212 // 1) Check for valid source and target meshsets (and entities) 01213 // 2) Build processor bounding boxes and construct a covering set 01214 // 3) Perform intersection between the source (covering) and target entities 01215 if( use_tempest ) 01216 { 01217 // Now let us construct the overlap mesh, by calling TempestRemap interface directly 01218 // For the overlap method, choose between: "fuzzy", "exact" or "mixed" 01219 assert( m_source != NULL ); 01220 assert( m_target != NULL ); 01221 if( m_overlap != NULL ) delete m_overlap; 01222 m_overlap = new Mesh(); 01223 bool concaveMeshA = false, concaveMeshB = false; 01224 int err = GenerateOverlapWithMeshes( *m_covering_source, *m_target, *m_overlap, "" /*outFilename*/, "Netcdf4", 01225 "exact", concaveMeshA, concaveMeshB, false ); 01226 if( err ) 01227 { 01228 MB_CHK_SET_ERR( MB_FAILURE, "TempestRemap: Can't compute the intersection of meshes on the sphere" ); 01229 } 01230 } 01231 else 01232 { 01233 Tag gidtag = m_interface->globalId_tag(); 01234 moab::EntityHandle subrange[2]; 01235 int gid[2]; 01236 if( m_source_entities.size() > 1 ) 01237 { // Let us do some sanity checking to fix ID if they have are setup incorrectly 01238 subrange[0] = m_source_entities[0]; 01239 subrange[1] = m_source_entities[1]; 01240 rval = m_interface->tag_get_data( gidtag, subrange, 2, gid );MB_CHK_ERR( rval ); 01241 01242 // Check if we need to impose Global ID numbering for vertices and elements. This may be 01243 // needed if we load the meshes from exodus or some other formats that may not have a 01244 // numbering forced. 01245 if( gid[0] + gid[1] == 0 ) // this implies first two elements have GID = 0 01246 { 01247 #ifdef MOAB_HAVE_MPI 01248 rval = m_pcomm->assign_global_ids( m_source_set, 2, 1, false, true, false );MB_CHK_ERR( rval ); 01249 #else 01250 rval = this->assign_vertex_element_IDs( gidtag, m_source_set, 2, 1 );MB_CHK_ERR( rval ); 01251 #endif 01252 } 01253 } 01254 if( m_target_entities.size() > 1 ) 01255 { 01256 subrange[0] = m_target_entities[0]; 01257 subrange[1] = m_target_entities[1]; 01258 rval = m_interface->tag_get_data( gidtag, subrange, 2, gid );MB_CHK_ERR( rval ); 01259 01260 // Check if we need to impose Global ID numbering for vertices and elements. This may be 01261 // needed if we load the meshes from exodus or some other formats that may not have a 01262 // numbering forced. 01263 if( gid[0] + gid[1] == 0 ) // this implies first two elements have GID = 0 01264 { 01265 #ifdef MOAB_HAVE_MPI 01266 rval = m_pcomm->assign_global_ids( m_target_set, 2, 1, false, true, false );MB_CHK_ERR( rval ); 01267 #else 01268 rval = this->assign_vertex_element_IDs( gidtag, m_target_set, 2, 1 );MB_CHK_ERR( rval ); 01269 #endif 01270 } 01271 } 01272 01273 // Now perform the actual parallel intersection between the source and the target meshes 01274 if( kdtree_search ) 01275 { 01276 if( outputEnabled ) dbgprint.printf( 0, "Computing intersection mesh with the Kd-tree search algorithm" ); 01277 rval = mbintx->intersect_meshes_kdtree( m_covering_source_set, m_target_set, m_overlap_set );MB_CHK_SET_ERR( rval, "Can't compute the intersection of meshes on the sphere with brute-force" ); 01278 } 01279 else 01280 { 01281 if( outputEnabled ) 01282 dbgprint.printf( 0, "Computing intersection mesh with the advancing-front propagation algorithm" ); 01283 rval = mbintx->intersect_meshes( m_covering_source_set, m_target_set, m_overlap_set );MB_CHK_SET_ERR( rval, "Can't compute the intersection of meshes on the sphere" ); 01284 } 01285 01286 #ifdef MOAB_HAVE_MPI 01287 if( is_parallel || rrmgrids ) 01288 { 01289 #ifdef VERBOSE 01290 01291 std::stringstream ffc, fft, ffo; 01292 ffc << "cover_" << size << "_" << rank << ".h5m"; 01293 fft << "target_" << size << "_" << rank << ".h5m"; 01294 ffo << "intx_" << size << "_" << rank << ".h5m"; 01295 rval = m_interface->write_mesh( ffc.str().c_str(), &m_covering_source_set, 1 );MB_CHK_ERR( rval ); 01296 rval = m_interface->write_mesh( fft.str().c_str(), &m_target_set, 1 );MB_CHK_ERR( rval ); 01297 rval = m_interface->write_mesh( ffo.str().c_str(), &m_overlap_set, 1 );MB_CHK_ERR( rval ); 01298 01299 // write the intx mesh, only in serial 01300 std::ostringstream opts; 01301 opts << "PARALLEL=WRITE_PART"; 01302 std::ostringstream file_name; 01303 file_name << "intx_gl_" << size << ".h5m"; 01304 if( size == 1 ) 01305 { 01306 rval = m_interface->write_file( file_name.str().c_str(), 0, opts.str().c_str(), &m_overlap_set, 1 );MB_CHK_ERR( rval ); 01307 } 01308 01309 #endif 01310 // because we do not want to work with elements in coverage set that do not participate 01311 // in intersection, remove them from the coverage set we will not delete them yet, just 01312 // remove from the set ! 01313 if( !point_cloud_target ) 01314 { 01315 Range covEnts; 01316 rval = m_interface->get_entities_by_dimension( m_covering_source_set, 2, covEnts );MB_CHK_ERR( rval ); 01317 Tag gidtag = m_interface->globalId_tag(); 01318 01319 std::map< int, int > loc_gid_to_lid_covsrc; 01320 std::vector< int > gids( covEnts.size(), -1 ); 01321 rval = m_interface->tag_get_data( gidtag, covEnts, &gids[0] );MB_CHK_ERR( rval ); 01322 for( unsigned ie = 0; ie < gids.size(); ++ie ) 01323 { 01324 loc_gid_to_lid_covsrc[gids[ie]] = ie; 01325 } 01326 01327 std::set< EntityHandle > intxCov; 01328 Range intxCells; 01329 Tag srcParentTag; 01330 rval = m_interface->tag_get_handle( "SourceParent", srcParentTag );MB_CHK_ERR( rval ); 01331 rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, intxCells );MB_CHK_ERR( rval ); 01332 for( Range::iterator it = intxCells.begin(); it != intxCells.end(); it++ ) 01333 { 01334 EntityHandle intxCell = *it; 01335 int blueParent = -1; 01336 rval = m_interface->tag_get_data( srcParentTag, &intxCell, 1, &blueParent );MB_CHK_ERR( rval ); 01337 // if (is_root) std::cout << "Found intersecting element: " << blueParent << ", 01338 // " << gid_to_lid_covsrc[blueParent] << "\n"; 01339 assert( blueParent >= 0 ); 01340 intxCov.insert( covEnts[loc_gid_to_lid_covsrc[blueParent]] ); 01341 } 01342 01343 Range intxCovRange; 01344 std::copy( intxCov.rbegin(), intxCov.rend(), range_inserter( intxCovRange ) ); 01345 Range notNeededCovCells = moab::subtract( covEnts, intxCovRange ); 01346 01347 rval = m_interface->remove_entities( m_covering_source_set, notNeededCovCells );MB_CHK_ERR( rval ); 01348 covEnts = moab::subtract( covEnts, notNeededCovCells ); 01349 #ifdef VERBOSE 01350 std::cout << " total participating elements in the covering set: " << intxCov.size() << "\n"; 01351 std::cout << " remove from coverage set elements that are not intersected: " << notNeededCovCells.size() 01352 << "\n"; 01353 #endif 01354 if( size > 1 ) 01355 { 01356 // some source elements cover multiple target partitions; the conservation logic 01357 // requires to know all overlap elements for a source element; they need to be 01358 // communicated from the other target partitions 01359 // 01360 // so first we have to identify source (coverage) elements that cover multiple 01361 // target partitions 01362 01363 // we will then mark the source, we will need to migrate the overlap elements 01364 // that cover this to the original source for the source element; then 01365 // distribute the overlap elements to all processors that have the coverage mesh 01366 // used 01367 01368 rval = augment_overlap_set();MB_CHK_ERR( rval ); 01369 } 01370 } 01371 01372 // m_covering_source = new Mesh(); 01373 // rval = convert_mesh_to_tempest_private ( m_covering_source, m_covering_source_set, 01374 // m_covering_source_entities, &m_covering_source_vertices ); MB_CHK_SET_ERR ( rval, 01375 // "Can't convert source Tempest mesh" ); 01376 } 01377 #endif 01378 01379 // Fix any inconsistencies in the overlap mesh 01380 { 01381 IntxAreaUtils areaAdaptor; 01382 rval = IntxUtils::fix_degenerate_quads( m_interface, m_overlap_set );MB_CHK_ERR( rval ); 01383 rval = areaAdaptor.positive_orientation( m_interface, m_overlap_set, 1.0 /*radius*/, rank );MB_CHK_ERR( rval ); 01384 } 01385 01386 // Now let us re-convert the MOAB mesh back to Tempest representation 01387 rval = this->ComputeGlobalLocalMaps();MB_CHK_ERR( rval ); 01388 01389 rval = this->convert_overlap_mesh_sorted_by_source();MB_CHK_ERR( rval ); 01390 // free the memory 01391 delete mbintx; 01392 } 01393 01394 return MB_SUCCESS; 01395 } 01396 01397 #ifdef MOAB_HAVE_MPI 01398 // this function is called only in parallel 01399 /////////////////////////////////////////////////////////////////////////////////// 01400 ErrorCode TempestRemapper::augment_overlap_set() 01401 { 01402 /* 01403 * overall strategy: 01404 * 01405 * 1) collect all boundary target cells on the current task, affected by the partition boundary; 01406 * note: not only partition boundary, we need all boundary (all coastal lines) and partition 01407 * boundary targetBoundaryIds is the set of target boundary cell IDs 01408 * 01409 * 2) collect all source cells that are intersecting boundary cells (call them 01410 * affectedSourceCellsIds) 01411 * 01412 * 3) collect overlap, that is accumulate all overlap cells that have source target in 01413 * affectedSourceCellsIds 01414 */ 01415 // first, get all edges on the partition boundary, on the target mesh, then all the target 01416 // elements that border the partition boundary 01417 ErrorCode rval; 01418 Skinner skinner( m_interface ); 01419 Range targetCells, boundaryEdges; 01420 rval = m_interface->get_entities_by_dimension( m_target_set, 2, targetCells );MB_CHK_ERR( rval ); 01421 /// find all boundary edges 01422 rval = skinner.find_skin( 0, targetCells, false, boundaryEdges );MB_CHK_ERR( rval ); 01423 // filter boundary edges that are on partition boundary, not on boundary 01424 // find all cells adjacent to these boundary edges, from target set 01425 Range boundaryCells; // these will be filtered from target_set 01426 rval = m_interface->get_adjacencies( boundaryEdges, 2, false, boundaryCells, Interface::UNION );MB_CHK_ERR( rval ); 01427 boundaryCells = intersect( boundaryCells, targetCells ); 01428 #ifdef VERBOSE 01429 EntityHandle tmpSet; 01430 rval = m_interface->create_meshset( MESHSET_SET, tmpSet );MB_CHK_SET_ERR( rval, "Can't create temporary set" ); 01431 // add the boundary set and edges, and save it to a file 01432 rval = m_interface->add_entities( tmpSet, boundaryCells );MB_CHK_SET_ERR( rval, "Can't add entities" ); 01433 rval = m_interface->add_entities( tmpSet, boundaryEdges );MB_CHK_SET_ERR( rval, "Can't add edges" ); 01434 std::stringstream ffs; 01435 ffs << "boundaryCells_0" << rank << ".h5m"; 01436 rval = m_interface->write_mesh( ffs.str().c_str(), &tmpSet, 1 );MB_CHK_ERR( rval ); 01437 #endif 01438 01439 // now that we have the boundary cells, see which overlap polys have have these as parents; 01440 // find the ids of the boundary cells; 01441 Tag gid = m_interface->globalId_tag(); 01442 std::set< int > targetBoundaryIds; 01443 for( Range::iterator it = boundaryCells.begin(); it != boundaryCells.end(); it++ ) 01444 { 01445 int tid; 01446 EntityHandle targetCell = *it; 01447 rval = m_interface->tag_get_data( gid, &targetCell, 1, &tid );MB_CHK_SET_ERR( rval, "Can't get global id tag on target cell" ); 01448 if( tid < 0 ) std::cout << " incorrect id for a target cell\n"; 01449 targetBoundaryIds.insert( tid ); 01450 } 01451 01452 Range overlapCells; 01453 rval = m_interface->get_entities_by_dimension( m_overlap_set, 2, overlapCells );MB_CHK_ERR( rval ); 01454 01455 std::set< int > affectedSourceCellsIds; 01456 Tag targetParentTag, sourceParentTag; // do not use blue/red, as it is more confusing 01457 rval = m_interface->tag_get_handle( "TargetParent", targetParentTag );MB_CHK_ERR( rval ); 01458 rval = m_interface->tag_get_handle( "SourceParent", sourceParentTag );MB_CHK_ERR( rval ); 01459 for( Range::iterator it = overlapCells.begin(); it != overlapCells.end(); it++ ) 01460 { 01461 EntityHandle intxCell = *it; 01462 int targetParentID, sourceParentID; 01463 rval = m_interface->tag_get_data( targetParentTag, &intxCell, 1, &targetParentID );MB_CHK_ERR( rval ); 01464 if( targetBoundaryIds.find( targetParentID ) != targetBoundaryIds.end() ) 01465 { 01466 // this means that the source element is affected 01467 rval = m_interface->tag_get_data( sourceParentTag, &intxCell, 1, &sourceParentID );MB_CHK_ERR( rval ); 01468 affectedSourceCellsIds.insert( sourceParentID ); 01469 } 01470 } 01471 01472 // now find all source cells affected, based on their id; 01473 // (we do not have yet the mapping gid_to_lid_covsrc) 01474 std::map< int, EntityHandle > affectedCovCellFromID; // map from source cell id to the eh; it is needed to find out 01475 // the original processor 01476 // this one came from , so to know where to send the overlap elements 01477 01478 // use std::set<EntityHandle> instead of moab::Range for collecting cells, either on coverage or 01479 // target or intx cells 01480 std::set< EntityHandle > affectedCovCells; // their overlap cells will be sent to their 01481 // original task, then distributed to all 01482 // other processes that might need them to compute conservation 01483 01484 Range covCells; 01485 rval = m_interface->get_entities_by_dimension( m_covering_source_set, 2, covCells );MB_CHK_ERR( rval ); 01486 // loop thru all cov cells, to find the ones with global ids in affectedSourceCellsIds 01487 for( Range::iterator it = covCells.begin(); it != covCells.end(); it++ ) 01488 { 01489 EntityHandle covCell = *it; // 01490 int covID; 01491 rval = m_interface->tag_get_data( gid, &covCell, 1, &covID ); 01492 if( affectedSourceCellsIds.find( covID ) != affectedSourceCellsIds.end() ) 01493 { 01494 // this source cell is affected; 01495 affectedCovCellFromID[covID] = covCell; 01496 affectedCovCells.insert( covCell ); 01497 } 01498 } 01499 01500 // now loop again over all overlap cells, to see if their source parent is "affected" 01501 // store in ranges the overlap cells that need to be sent to original task of the source cell 01502 // from there, they will be redistributed to the tasks that need that coverage cell 01503 Tag sendProcTag; 01504 rval = m_interface->tag_get_handle( "sending_processor", 1, MB_TYPE_INTEGER, sendProcTag ); 01505 01506 // basically a map from original processor task to the set of overlap cells to be sent there 01507 std::map< int, std::set< EntityHandle > > overlapCellsForTask; 01508 // this set will contain all intx cells that will need to be sent ( a union of above sets , 01509 // that are organized per task on the above map ) 01510 std::set< EntityHandle > overlapCellsToSend; 01511 01512 for( Range::iterator it = overlapCells.begin(); it != overlapCells.end(); it++ ) 01513 { 01514 EntityHandle intxCell = *it; 01515 int sourceParentID; 01516 rval = m_interface->tag_get_data( sourceParentTag, &intxCell, 1, &sourceParentID );MB_CHK_ERR( rval ); 01517 if( affectedSourceCellsIds.find( sourceParentID ) != affectedSourceCellsIds.end() ) 01518 { 01519 EntityHandle covCell = affectedCovCellFromID[sourceParentID]; 01520 int orgTask; 01521 rval = m_interface->tag_get_data( sendProcTag, &covCell, 1, &orgTask );MB_CHK_ERR( rval ); 01522 overlapCellsForTask[orgTask].insert( 01523 intxCell ); // put the overlap cell in corresponding range (set<EntityHandle>) 01524 overlapCellsToSend.insert( intxCell ); // also put it in this range, for debugging mostly 01525 } 01526 } 01527 01528 // now prepare to send; will use crystal router, as the buffers in ParComm are prepared only 01529 // for neighbors; coverage mesh was also migrated with crystal router, so here we go again :( 01530 01531 // find out the maximum number of edges of the polygons needed to be sent 01532 // we could we conservative and use a big number, or the number from intx, if we store it then? 01533 int maxEdges = 0; 01534 for( std::set< EntityHandle >::iterator it = overlapCellsToSend.begin(); it != overlapCellsToSend.end(); it++ ) 01535 { 01536 EntityHandle intxCell = *it; 01537 int nnodes; 01538 const EntityHandle* conn; 01539 rval = m_interface->get_connectivity( intxCell, conn, nnodes );MB_CHK_ERR( rval ); 01540 if( maxEdges < nnodes ) maxEdges = nnodes; 01541 } 01542 01543 // find the maximum among processes in intersection 01544 int globalMaxEdges; 01545 if( m_pcomm ) 01546 MPI_Allreduce( &maxEdges, &globalMaxEdges, 1, MPI_INT, MPI_MAX, m_pcomm->comm() ); 01547 else 01548 globalMaxEdges = maxEdges; 01549 01550 //#ifdef VERBOSE 01551 if( is_root ) std::cout << "maximum number of edges for polygons to send is " << globalMaxEdges << "\n"; 01552 //#endif 01553 01554 #ifdef VERBOSE 01555 EntityHandle tmpSet2; 01556 rval = m_interface->create_meshset( MESHSET_SET, tmpSet2 );MB_CHK_SET_ERR( rval, "Can't create temporary set2" ); 01557 // add the affected source and overlap elements 01558 for( std::set< EntityHandle >::iterator it = overlapCellsToSend.begin(); it != overlapCellsToSend.end(); it++ ) 01559 { 01560 EntityHandle intxCell = *it; 01561 rval = m_interface->add_entities( tmpSet2, &intxCell, 1 );MB_CHK_SET_ERR( rval, "Can't add entities" ); 01562 } 01563 for( std::set< EntityHandle >::iterator it = affectedCovCells.begin(); it != affectedCovCells.end(); it++ ) 01564 { 01565 EntityHandle covCell = *it; 01566 rval = m_interface->add_entities( tmpSet2, &covCell, 1 );MB_CHK_SET_ERR( rval, "Can't add entities" ); 01567 } 01568 std::stringstream ffs2; 01569 // these will contain coverage cells and intx cells on the boundary 01570 ffs2 << "affectedCells_" << m_pcomm->rank() << ".h5m"; 01571 rval = m_interface->write_mesh( ffs2.str().c_str(), &tmpSet2, 1 );MB_CHK_ERR( rval ); 01572 #endif 01573 // form tuple lists to send vertices and cells; 01574 // the problem is that the lists of vertices will need to have other information, like the 01575 // processor it comes from, and its index in that list; we may have to duplicate vertices, but 01576 // we do not care much; we will not duplicate overlap elements, just the vertices, as they may 01577 // come from different cells and different processes each vertex will have a local index and a 01578 // processor task it is coming from 01579 01580 // look through the std::set's to be sent to other processes, and form the vertex tuples and 01581 // cell tuples 01582 // 01583 std::map< int, std::set< EntityHandle > > verticesOverlapForTask; 01584 // Range allVerticesToSend; 01585 std::set< EntityHandle > allVerticesToSend; 01586 std::map< EntityHandle, int > allVerticesToSendMap; 01587 int numVerts = 0; 01588 int numOverlapCells = 0; 01589 for( std::map< int, std::set< EntityHandle > >::iterator it = overlapCellsForTask.begin(); 01590 it != overlapCellsForTask.end(); it++ ) 01591 { 01592 int sendToProc = it->first; 01593 std::set< EntityHandle >& overlapCellsToSend2 = it->second; // organize vertices in std::set per processor 01594 // Range vertices; 01595 std::set< EntityHandle > vertices; // collect all vertices connected to overlapCellsToSend2 01596 for( std::set< EntityHandle >::iterator set_it = overlapCellsToSend2.begin(); 01597 set_it != overlapCellsToSend2.end(); ++set_it ) 01598 { 01599 int nnodes_local = 0; 01600 const EntityHandle* conn1 = NULL; 01601 rval = m_interface->get_connectivity( *set_it, conn1, nnodes_local );MB_CHK_ERR( rval ); 01602 for( int k = 0; k < nnodes_local; k++ ) 01603 vertices.insert( conn1[k] ); 01604 } 01605 verticesOverlapForTask[sendToProc] = vertices; 01606 numVerts += (int)vertices.size(); 01607 numOverlapCells += (int)overlapCellsToSend2.size(); 01608 allVerticesToSend.insert( vertices.begin(), vertices.end() ); 01609 } 01610 // build the index map, from entity handle to index in all vert set 01611 int j = 0; 01612 for( std::set< EntityHandle >::iterator vert_it = allVerticesToSend.begin(); vert_it != allVerticesToSend.end(); 01613 vert_it++, j++ ) 01614 { 01615 EntityHandle vert = *vert_it; 01616 allVerticesToSendMap[vert] = j; 01617 } 01618 01619 // first send vertices in a tuple list, then send overlap cells, according to requests 01620 // overlap cells need to send info about the blue and red parent tags, too 01621 TupleList TLv; // 01622 TLv.initialize( 2, 0, 0, 3, numVerts ); // to proc, index in all range, DP points 01623 TLv.enableWriteAccess(); 01624 01625 for( std::map< int, std::set< EntityHandle > >::iterator it = verticesOverlapForTask.begin(); 01626 it != verticesOverlapForTask.end(); it++ ) 01627 { 01628 int sendToProc = it->first; 01629 std::set< EntityHandle >& vertices = it->second; 01630 int i = 0; 01631 for( std::set< EntityHandle >::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++, i++ ) 01632 { 01633 int n = TLv.get_n(); 01634 TLv.vi_wr[2 * n] = sendToProc; // send to processor 01635 EntityHandle v = *it2; 01636 int indexInAllVert = allVerticesToSendMap[v]; 01637 TLv.vi_wr[2 * n + 1] = indexInAllVert; // will be orgProc, to differentiate indices 01638 // of vertices sent to "sentToProc" 01639 double coords[3]; 01640 rval = m_interface->get_coords( &v, 1, coords );MB_CHK_ERR( rval ); 01641 TLv.vr_wr[3 * n] = coords[0]; // departure position, of the node local_verts[i] 01642 TLv.vr_wr[3 * n + 1] = coords[1]; 01643 TLv.vr_wr[3 * n + 2] = coords[2]; 01644 TLv.inc_n(); 01645 } 01646 } 01647 01648 TupleList TLc; 01649 int sizeTuple = 4 + globalMaxEdges; 01650 // total number of overlap cells to send 01651 TLc.initialize( sizeTuple, 0, 0, 0, 01652 numOverlapCells ); // to proc, blue parent ID, red parent ID, nvert, 01653 // connectivity[globalMaxEdges] (global ID v), local eh) 01654 TLc.enableWriteAccess(); 01655 01656 for( std::map< int, std::set< EntityHandle > >::iterator it = overlapCellsForTask.begin(); 01657 it != overlapCellsForTask.end(); it++ ) 01658 { 01659 int sendToProc = it->first; 01660 std::set< EntityHandle >& overlapCellsToSend2 = it->second; 01661 // send also the target and source parents for these overlap cells 01662 for( std::set< EntityHandle >::iterator it2 = overlapCellsToSend2.begin(); it2 != overlapCellsToSend2.end(); 01663 it2++ ) 01664 { 01665 EntityHandle intxCell = *it2; 01666 int sourceParentID, targetParentID; 01667 rval = m_interface->tag_get_data( targetParentTag, &intxCell, 1, &targetParentID );MB_CHK_ERR( rval ); 01668 rval = m_interface->tag_get_data( sourceParentTag, &intxCell, 1, &sourceParentID );MB_CHK_ERR( rval ); 01669 int n = TLc.get_n(); 01670 TLc.vi_wr[sizeTuple * n] = sendToProc; 01671 TLc.vi_wr[sizeTuple * n + 1] = sourceParentID; 01672 TLc.vi_wr[sizeTuple * n + 2] = targetParentID; 01673 int nnodes; 01674 const EntityHandle* conn = NULL; 01675 rval = m_interface->get_connectivity( intxCell, conn, nnodes );MB_CHK_ERR( rval ); 01676 TLc.vi_wr[sizeTuple * n + 3] = nnodes; 01677 for( int i = 0; i < nnodes; i++ ) 01678 { 01679 int indexVertex = allVerticesToSendMap[conn[i]]; 01680 ; // the vertex index will be now unique per original proc 01681 if( -1 == indexVertex ) MB_CHK_SET_ERR( MB_FAILURE, "Can't find vertex in range of vertices to send" ); 01682 TLc.vi_wr[sizeTuple * n + 4 + i] = indexVertex; 01683 } 01684 // fill the rest with 0, just because we do not like uninitialized data 01685 for( int i = nnodes; i < globalMaxEdges; i++ ) 01686 TLc.vi_wr[sizeTuple * n + 4 + i] = 0; 01687 01688 TLc.inc_n(); 01689 } 01690 } 01691 01692 // send first the vertices and overlap cells to original task for coverage cells 01693 // now we are done populating the tuples; route them to the appropriate processors 01694 #ifdef VERBOSE 01695 std::stringstream ff1; 01696 ff1 << "TLc_" << rank << ".txt"; 01697 TLc.print_to_file( ff1.str().c_str() ); 01698 std::stringstream ffv; 01699 ffv << "TLv_" << rank << ".txt"; 01700 TLv.print_to_file( ffv.str().c_str() ); 01701 #endif 01702 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv, 0 ); 01703 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLc, 0 ); 01704 01705 #ifdef VERBOSE 01706 TLc.print_to_file( ff1.str().c_str() ); // will append to existing file 01707 TLv.print_to_file( ffv.str().c_str() ); 01708 #endif 01709 // first phase of transfer complete 01710 // now look at TLc, and sort by the source parent (index 1) 01711 01712 TupleList::buffer buffer; 01713 buffer.buffer_init( sizeTuple * TLc.get_n() * 2 ); // allocate memory for sorting !! double 01714 TLc.sort( 1, &buffer ); 01715 #ifdef VERBOSE 01716 TLc.print_to_file( ff1.str().c_str() ); 01717 #endif 01718 01719 // will keep a map with vertices per processor that will need to be used in TLv2; 01720 // so, availVertexIndicesPerProcessor[proc] is a map from vertex indices that are available from 01721 // this processor to the index in the local TLv; the used vertices will have to be sent to the 01722 // tasks that need them 01723 01724 // connectivity of a cell is given by sending proc and index in original list of vertices from 01725 // that proc 01726 01727 std::map< int, std::map< int, int > > availVertexIndicesPerProcessor; 01728 int nv = TLv.get_n(); 01729 for( int i = 0; i < nv; i++ ) 01730 { 01731 // int proc=TLv.vi_rd[3*i]; // it is coming from this processor 01732 int orgProc = TLv.vi_rd[2 * i]; // this is the original processor, for index vertex consideration 01733 int indexVert = TLv.vi_rd[2 * i + 1]; 01734 availVertexIndicesPerProcessor[orgProc][indexVert] = i; 01735 } 01736 01737 // now we have sorted the incoming overlap elements by the source element; 01738 // if we have overlap elements for one source coming from 2 or more processes, we need to send 01739 // back to the processes that do not have that overlap cell; 01740 01741 // form new TLc2, TLv2, that will be distributed to necessary processes 01742 // first count source elements that are "spread" over multiple processes 01743 // TLc is ordered now by source ID; loop over them 01744 int n = TLc.get_n(); // total number of overlap elements received on current task; 01745 std::map< int, int > currentProcsCount; 01746 // form a map from proc to sets of vertex indices that will be sent using TLv2 01747 // will form a map between a source cell ID and tasks/targets that are partially overlapped by 01748 // these sources 01749 std::map< int, std::set< int > > sourcesForTasks; 01750 int sizeOfTLc2 = 0; // only increase when we will have to send data 01751 if( n > 0 ) 01752 { 01753 int currentSourceID = TLc.vi_rd[sizeTuple * 0 + 1]; // we have written sizeTuple*0 for "clarity" 01754 int proc0 = TLc.vi_rd[sizeTuple * 0]; 01755 currentProcsCount[proc0] = 1; // 01756 01757 for( int i = 1; i < n; i++ ) 01758 { 01759 int proc = TLc.vi_rd[sizeTuple * i]; 01760 int sourceID = TLc.vi_rd[sizeTuple * i + 1]; 01761 if( sourceID == currentSourceID ) 01762 { 01763 if( currentProcsCount.find( proc ) == currentProcsCount.end() ) 01764 { 01765 currentProcsCount[proc] = 1; 01766 } 01767 else 01768 currentProcsCount[proc]++; 01769 } 01770 if( sourceID != currentSourceID || ( ( n - 1 ) == i ) ) // we study the current source if we reach the last 01771 { 01772 // we have found a new source id, need to reset the proc counts, and establish if we 01773 // need to send data 01774 if( currentProcsCount.size() > 1 ) 01775 { 01776 #ifdef VERBOSE 01777 std::cout << " source element " << currentSourceID << " intersects with " 01778 << currentProcsCount.size() << " target partitions\n"; 01779 for( std::map< int, int >::iterator it = currentProcsCount.begin(); it != currentProcsCount.end(); 01780 it++ ) 01781 { 01782 int procID = it->first; 01783 int numOverCells = it->second; 01784 std::cout << " task:" << procID << " " << numOverCells << " cells\n"; 01785 } 01786 01787 #endif 01788 // estimate what we need to send 01789 for( std::map< int, int >::iterator it1 = currentProcsCount.begin(); it1 != currentProcsCount.end(); 01790 it1++ ) 01791 { 01792 int proc1 = it1->first; 01793 sourcesForTasks[currentSourceID].insert( proc1 ); 01794 for( std::map< int, int >::iterator it2 = currentProcsCount.begin(); 01795 it2 != currentProcsCount.end(); it2++ ) 01796 { 01797 int proc2 = it2->first; 01798 if( proc1 != proc2 ) sizeOfTLc2 += it2->second; 01799 } 01800 } 01801 // mark vertices in TLv tuple that need to be sent 01802 } 01803 if( sourceID != currentSourceID ) // maybe we are not at the end, so continue on 01804 { 01805 currentSourceID = sourceID; 01806 currentProcsCount.clear(); 01807 currentProcsCount[proc] = 1; 01808 } 01809 } 01810 } 01811 } 01812 // begin a loop to send the needed cells to the processes; also mark the vertices that need to 01813 // be sent, put them in a set 01814 01815 #ifdef VERBOSE 01816 std::cout << " need to initialize TLc2 with " << sizeOfTLc2 << " cells\n "; 01817 #endif 01818 01819 TupleList TLc2; 01820 int sizeTuple2 = 5 + globalMaxEdges; // send to, original proc for intx cell, source parent id, 01821 // target parent id, 01822 // number of vertices, then connectivity in terms of indices in vertex lists from original proc 01823 TLc2.initialize( sizeTuple2, 0, 0, 0, sizeOfTLc2 ); 01824 TLc2.enableWriteAccess(); 01825 // loop again through TLc, and select intx cells that have the problem sources; 01826 01827 std::map< int, std::set< int > > verticesToSendForProc; // will look at indices in the TLv list 01828 // will form for each processor, the index list from TLv 01829 for( int i = 0; i < n; i++ ) 01830 { 01831 int sourceID = TLc.vi_rd[sizeTuple * i + 1]; 01832 if( sourcesForTasks.find( sourceID ) != sourcesForTasks.end() ) 01833 { 01834 // it means this intx cell needs to be sent to any proc that is not "original" to it 01835 std::set< int > procs = sourcesForTasks[sourceID]; // set of processors involved with this source 01836 if( procs.size() < 2 ) MB_CHK_SET_ERR( MB_FAILURE, " not enough processes involved with a sourceID cell" ); 01837 01838 int orgProc = TLc.vi_rd[sizeTuple * i]; // this intx cell was sent from this orgProc, originally 01839 // will need to be sent to all other procs from above set; also, need to mark the vertex 01840 // indices for that proc, and check that they are available to populate TLv2 01841 std::map< int, int >& availableVerticesFromThisProc = availVertexIndicesPerProcessor[orgProc]; 01842 for( std::set< int >::iterator setIt = procs.begin(); setIt != procs.end(); setIt++ ) 01843 { 01844 int procID = *setIt; 01845 // send this cell to the other processors, not to orgProc this cell is coming from 01846 01847 if( procID != orgProc ) 01848 { 01849 // send the cell to this processor; 01850 int n2 = TLc2.get_n(); 01851 if( n2 >= sizeOfTLc2 ) MB_CHK_SET_ERR( MB_FAILURE, " memory overflow" ); 01852 // 01853 std::set< int >& indexVerticesInTLv = verticesToSendForProc[procID]; 01854 TLc2.vi_wr[n2 * sizeTuple2] = procID; // send to 01855 TLc2.vi_wr[n2 * sizeTuple2 + 1] = orgProc; // this cell is coming from here 01856 TLc2.vi_wr[n2 * sizeTuple2 + 2] = sourceID; // source parent of the intx cell 01857 TLc2.vi_wr[n2 * sizeTuple2 + 3] = TLc.vi_rd[sizeTuple * i + 2]; // target parent of the intx cell 01858 // number of vertices of the intx cell 01859 int nvert = TLc.vi_rd[sizeTuple * i + 3]; 01860 TLc2.vi_wr[n2 * sizeTuple2 + 4] = nvert; 01861 // now loop through the connectivity, and make sure the vertices are available; 01862 // mark them, to populate later the TLv2 tuple list 01863 01864 // just copy the vertices, including 0 ones 01865 for( int j = 0; j < nvert; j++ ) 01866 { 01867 int vertexIndex = TLc.vi_rd[i * sizeTuple + 4 + j]; 01868 // is this vertex available from org proc? 01869 if( availableVerticesFromThisProc.find( vertexIndex ) == availableVerticesFromThisProc.end() ) 01870 { 01871 MB_CHK_SET_ERR( MB_FAILURE, " vertex index not available from processor" ); 01872 } 01873 TLc2.vi_wr[n2 * sizeTuple2 + 5 + j] = vertexIndex; 01874 int indexInTLv = availVertexIndicesPerProcessor[orgProc][vertexIndex]; 01875 indexVerticesInTLv.insert( indexInTLv ); 01876 } 01877 01878 for( int j = nvert; j < globalMaxEdges; j++ ) 01879 { 01880 TLc2.vi_wr[n2 * sizeTuple2 + 5 + j] = 0; // or mark them 0 01881 } 01882 TLc2.inc_n(); 01883 } 01884 } 01885 } 01886 } 01887 01888 // now we have to populate TLv2, with original source proc, index of vertex, and coordinates 01889 // from TLv use the verticesToSendForProc sets from above, and the map from index in proc to the 01890 // index in TLv 01891 TupleList TLv2; 01892 int numVerts2 = 0; 01893 // how many vertices to send? 01894 for( std::map< int, std::set< int > >::iterator it = verticesToSendForProc.begin(); 01895 it != verticesToSendForProc.end(); it++ ) 01896 { 01897 std::set< int >& indexInTLvSet = it->second; 01898 numVerts2 += (int)indexInTLvSet.size(); 01899 } 01900 TLv2.initialize( 3, 0, 0, 3, 01901 numVerts2 ); // send to, original proc, index in original proc, and 3 coords 01902 TLv2.enableWriteAccess(); 01903 for( std::map< int, std::set< int > >::iterator it = verticesToSendForProc.begin(); 01904 it != verticesToSendForProc.end(); it++ ) 01905 { 01906 int sendToProc = it->first; 01907 std::set< int >& indexInTLvSet = it->second; 01908 // now, look at indices in TLv, to find out the original proc, and the index in that list 01909 for( std::set< int >::iterator itSet = indexInTLvSet.begin(); itSet != indexInTLvSet.end(); itSet++ ) 01910 { 01911 int indexInTLv = *itSet; 01912 int orgProc = TLv.vi_rd[2 * indexInTLv]; 01913 int indexVertexInOrgProc = TLv.vi_rd[2 * indexInTLv + 1]; 01914 int nv2 = TLv2.get_n(); 01915 TLv2.vi_wr[3 * nv2] = sendToProc; 01916 TLv2.vi_wr[3 * nv2 + 1] = orgProc; 01917 TLv2.vi_wr[3 * nv2 + 2] = indexVertexInOrgProc; 01918 for( int j = 0; j < 3; j++ ) 01919 TLv2.vr_wr[3 * nv2 + j] = 01920 TLv.vr_rd[3 * indexInTLv + j]; // departure position, of the node local_verts[i] 01921 TLv2.inc_n(); 01922 } 01923 } 01924 // now, finally, transfer the vertices and the intx cells; 01925 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLv2, 0 ); 01926 ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, TLc2, 0 ); 01927 // now, look at vertices from TLv2, and create them 01928 // we should have in TLv2 only vertices with orgProc different from current task 01929 #ifdef VERBOSE 01930 std::stringstream ff2; 01931 ff2 << "TLc2_" << rank << ".txt"; 01932 TLc2.print_to_file( ff2.str().c_str() ); 01933 std::stringstream ffv2; 01934 ffv2 << "TLv2_" << rank << ".txt"; 01935 TLv2.print_to_file( ffv2.str().c_str() ); 01936 #endif 01937 // first create vertices, and make a map from origin processor, and index, to entity handle 01938 // (index in TLv2 ) 01939 Tag ghostTag; 01940 int orig_proc = -1; 01941 rval = m_interface->tag_get_handle( "ORIG_PROC", 1, MB_TYPE_INTEGER, ghostTag, MB_TAG_DENSE | MB_TAG_CREAT, 01942 &orig_proc );MB_CHK_ERR( rval ); 01943 01944 int nvNew = TLv2.get_n(); 01945 // if number of vertices to be created is 0, it means there is no need of ghost intx cells, 01946 // because everything matched perfectly (it can happen in manufactured cases) 01947 if( 0 == nvNew ) return MB_SUCCESS; 01948 // create a vertex h for each coordinate 01949 Range newVerts; 01950 rval = m_interface->create_vertices( &( TLv2.vr_rd[0] ), nvNew, newVerts );MB_CHK_ERR( rval ); 01951 // now create a map from index , org proc, to actual entity handle corresponding to it 01952 std::map< int, std::map< int, EntityHandle > > vertexPerProcAndIndex; 01953 for( int i = 0; i < nvNew; i++ ) 01954 { 01955 int orgProc = TLv2.vi_rd[3 * i + 1]; 01956 int indexInVert = TLv2.vi_rd[3 * i + 2]; 01957 vertexPerProcAndIndex[orgProc][indexInVert] = newVerts[i]; 01958 } 01959 01960 // new polygons will receive a dense tag, with default value -1, with the processor task they 01961 // originally belonged to 01962 01963 // now form the needed cells, in order 01964 Range newPolygons; 01965 int ne = TLc2.get_n(); 01966 for( int i = 0; i < ne; i++ ) 01967 { 01968 int orgProc = TLc2.vi_rd[i * sizeTuple2 + 1]; // this cell is coming from here, originally 01969 int sourceID = TLc2.vi_rd[i * sizeTuple2 + 2]; // source parent of the intx cell 01970 int targetID = TLc2.vi_wr[i * sizeTuple2 + 3]; // target parent of intx cell 01971 int nve = TLc2.vi_wr[i * sizeTuple2 + 4]; // number of vertices for the polygon 01972 std::vector< EntityHandle > conn; 01973 conn.resize( nve ); 01974 for( int j = 0; j < nve; j++ ) 01975 { 01976 int indexV = TLc2.vi_wr[i * sizeTuple2 + 5 + j]; 01977 EntityHandle vh = vertexPerProcAndIndex[orgProc][indexV]; 01978 conn[j] = vh; 01979 } 01980 EntityHandle polyNew; 01981 rval = m_interface->create_element( MBPOLYGON, &conn[0], nve, polyNew );MB_CHK_ERR( rval ); 01982 newPolygons.insert( polyNew ); 01983 rval = m_interface->tag_set_data( targetParentTag, &polyNew, 1, &targetID );MB_CHK_ERR( rval ); 01984 rval = m_interface->tag_set_data( sourceParentTag, &polyNew, 1, &sourceID );MB_CHK_ERR( rval ); 01985 rval = m_interface->tag_set_data( ghostTag, &polyNew, 1, &orgProc );MB_CHK_ERR( rval ); 01986 } 01987 01988 #ifdef VERBOSE 01989 EntityHandle tmpSet3; 01990 rval = m_interface->create_meshset( MESHSET_SET, tmpSet3 );MB_CHK_SET_ERR( rval, "Can't create temporary set3" ); 01991 // add the boundary set and edges, and save it to a file 01992 rval = m_interface->add_entities( tmpSet3, newPolygons );MB_CHK_SET_ERR( rval, "Can't add entities" ); 01993 01994 std::stringstream ffs4; 01995 ffs4 << "extraIntxCells" << rank << ".h5m"; 01996 rval = m_interface->write_mesh( ffs4.str().c_str(), &tmpSet3, 1 );MB_CHK_ERR( rval ); 01997 #endif 01998 01999 // add the new polygons to the overlap set 02000 // these will be ghosted, so will participate in conservation only 02001 rval = m_interface->add_entities( m_overlap_set, newPolygons );MB_CHK_ERR( rval ); 02002 #ifdef VERBOSE 02003 if( !rank ) 02004 { 02005 std::cout << "Augmenting: add " << newPolygons.size() << " polygons on root task \n"; 02006 } 02007 #endif 02008 return MB_SUCCESS; 02009 } 02010 02011 #endif 02012 02013 ErrorCode TempestRemapper::GetIMasks( Remapper::IntersectionContext ctx, std::vector< int >& masks ) 02014 { 02015 Tag maskTag; 02016 // it should have been created already, if not, we might have a problem 02017 int def_val = 1; 02018 ErrorCode rval = 02019 m_interface->tag_get_handle( "GRID_IMASK", 1, MB_TYPE_INTEGER, maskTag, MB_TAG_DENSE | MB_TAG_CREAT, &def_val );MB_CHK_SET_ERR( rval, "Trouble creating GRID_IMASK tag" ); 02020 02021 switch( ctx ) 02022 { 02023 case Remapper::SourceMesh: { 02024 if( point_cloud_source ) 02025 { 02026 masks.resize( m_source_vertices.size() ); 02027 rval = m_interface->tag_get_data( maskTag, m_source_vertices, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" ); 02028 } 02029 else 02030 { 02031 masks.resize( m_source_entities.size() ); 02032 rval = m_interface->tag_get_data( maskTag, m_source_entities, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" ); 02033 } 02034 return MB_SUCCESS; 02035 } 02036 case Remapper::TargetMesh: { 02037 if( point_cloud_target ) 02038 { 02039 masks.resize( m_target_vertices.size() ); 02040 rval = m_interface->tag_get_data( maskTag, m_target_vertices, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" ); 02041 } 02042 else 02043 { 02044 masks.resize( m_target_entities.size() ); 02045 rval = m_interface->tag_get_data( maskTag, m_target_entities, &masks[0] );MB_CHK_SET_ERR( rval, "Trouble getting GRID_IMASK tag" ); 02046 } 02047 return MB_SUCCESS; 02048 } 02049 case Remapper::CoveringMesh: 02050 case Remapper::OverlapMesh: 02051 default: 02052 return MB_SUCCESS; 02053 } 02054 } 02055 02056 } // namespace moab