MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 #include "RefinerTagManager.hpp" 00002 00003 #include "moab/Interface.hpp" 00004 #include "moab/ParallelComm.hpp" 00005 #include "MBParallelConventions.h" 00006 #include "MBTagConventions.hpp" 00007 00008 #include <iostream> 00009 #include <stdexcept> 00010 #include <cassert> 00011 00012 #undef MB_DEBUG 00013 00014 namespace moab 00015 { 00016 00017 /// Construct an evaluator. 00018 RefinerTagManager::RefinerTagManager( Interface* in_mesh, Interface* out_mesh ) 00019 : shared_procs_in( 5 * MAX_SHARING_PROCS, -1 ), shared_procs_out( MAX_SHARING_PROCS, -1 ) 00020 { 00021 assert( in_mesh ); 00022 if( !out_mesh ) out_mesh = in_mesh; 00023 00024 this->input_mesh = in_mesh; 00025 this->output_mesh = out_mesh; 00026 this->reset_vertex_tags(); 00027 this->reset_element_tags(); 00028 ParallelComm* ipcomm = ParallelComm::get_pcomm( this->input_mesh, 0 ); 00029 ParallelComm* opcomm = 0; 00030 if( this->output_mesh != this->input_mesh ) 00031 { 00032 opcomm = ParallelComm::get_pcomm( this->output_mesh, 0 ); 00033 if( !opcomm ) 00034 { 00035 #ifdef MB_DEBUG 00036 std::cout << "Creating opcomm: " << opcomm << "\n"; 00037 #endif // MB_DEBUG 00038 opcomm = new ParallelComm( this->output_mesh, MPI_COMM_WORLD ); 00039 } 00040 } 00041 else 00042 { 00043 opcomm = ipcomm; 00044 } 00045 00046 if( ipcomm ) 00047 { 00048 ipcomm->get_shared_proc_tags( this->tag_ipsproc, this->tag_ipsprocs, this->tag_ipshand, this->tag_ipshands, 00049 this->tag_ipstatus ); 00050 } 00051 else 00052 { 00053 this->tag_ipsproc = this->tag_ipsprocs = 0; 00054 this->tag_ipshand = this->tag_ipshands = 0; 00055 this->tag_ipstatus = 0; 00056 } 00057 00058 if( opcomm ) 00059 { 00060 opcomm->get_shared_proc_tags( this->tag_opsproc, this->tag_opsprocs, this->tag_opshand, this->tag_opshands, 00061 this->tag_opstatus ); 00062 } 00063 else 00064 { 00065 this->tag_opsproc = this->tag_opsprocs = 0; 00066 this->tag_opshand = this->tag_opshands = 0; 00067 this->tag_opstatus = 0; 00068 } 00069 00070 this->rank = ipcomm ? ipcomm->proc_config().proc_rank() : ( opcomm ? opcomm->proc_config().proc_rank() : 0 ); 00071 00072 // Create the mesh global ID tags if they aren't already there. 00073 00074 this->tag_igid = this->input_mesh->globalId_tag(); 00075 if( this->tag_igid == 0 ) 00076 { 00077 throw new std::logic_error( "Unable to find input mesh global ID tag \"" GLOBAL_ID_TAG_NAME "\"" ); 00078 } 00079 this->tag_ogid = this->output_mesh->globalId_tag(); 00080 if( this->tag_ogid == 0 ) 00081 { 00082 throw new std::logic_error( "Unable to find/create output mesh global ID tag \"" GLOBAL_ID_TAG_NAME "\"" ); 00083 } 00084 00085 #ifdef MB_DEBUG 00086 std::cout << "psproc: " << this->tag_ipsproc << ", " << this->tag_opsproc << "\n" 00087 << "psprocs: " << this->tag_ipsprocs << ", " << this->tag_opsprocs << "\n" 00088 << "pshand: " << this->tag_ipshand << ", " << this->tag_opshand << "\n" 00089 << "pshands: " << this->tag_ipshands << ", " << this->tag_opshands << "\n" 00090 << "pstatus: " << this->tag_ipstatus << ", " << this->tag_opstatus << "\n" 00091 << "gid: " << this->tag_igid << ", " << this->tag_ogid << "\n"; 00092 #endif // MB_DEBUG 00093 } 00094 00095 /// Destruction is virtual so subclasses may clean up after refinement. 00096 RefinerTagManager::~RefinerTagManager() {} 00097 00098 /**\fn bool RefinerTagManager::evaluate_edge( \ 00099 * const double* p0, const void* t0, double* p1, void* t1, const double* p2, const void* t2 00100 *) \brief Returns true if the edge \a p0 - \a p2 should be subdivided, false otherwise. 00101 * 00102 * The arguments \a p0, \a p1, and \a p2 are all pointers to arrays of 6 doubles each 00103 * while the arguments \a t0, \a t1, and \a t2 are all pointers to arrays of tag data 00104 * defined at the corresponding point. While the endpoints \a p0 and \a p2 are 00105 * immutable, the mid-edge point coordinates \a p1 and tag data \a t1 may be altered by 00106 * evaluate_edge(). Altered values will be ignored if evaluate_edge() returns false. 00107 * Be careful to ensure that all calls to evaluate_edge() perform identical modifications 00108 * given identical input values! 00109 * 00110 * A list of tags passed in \a t0, \a t1, and \a t2 is stored in the \a input_vertex_tags member. 00111 * (for tag handles defined on the input mesh) and the \a output_vertex_tags (for the same tag 00112 *handles defined on the output mesh). The vertex_size member stores the total length of data 00113 *associated with each pointer (in bytes). Subclasses may access input_vertex_tags, 00114 *output_vertex_tags, and vertex_size directly; the refiner uses public methods to set them before 00115 *any entities are evaluated for subdivision. The output_vertex_tags member is populated when the 00116 *refiner calls create_output_tags(). When the input mesh and output mesh pointers are identical, 00117 *this simply copies input_vertex_tags to output_vertex_tags. When the pointers are distinct, tags 00118 *are created on the output mesh. 00119 */ 00120 00121 /// Clear the list of tag values that will appear past the vertex coordinates in \a p0, \a p1, and 00122 /// \a p2. 00123 void RefinerTagManager::reset_vertex_tags() 00124 { 00125 this->vertex_size = 0; 00126 this->input_vertex_tags.clear(); 00127 this->output_vertex_tags.clear(); 00128 } 00129 00130 /** Add a tag to the list of tag values that will appear past the vertex coordinates. 00131 * The return value is the offset into each vertex coordinate pointer (\a p0, \a p1, \a p2) where 00132 * the tag value(s) will be stored. 00133 */ 00134 int RefinerTagManager::add_vertex_tag( Tag tag_handle ) 00135 { 00136 int offset = this->vertex_size; // old size is offset of tag being added 00137 int tag_size; 00138 TagType tagType; 00139 if( this->input_mesh->tag_get_bytes( tag_handle, tag_size ) != MB_SUCCESS ) return -1; 00140 00141 if( this->input_mesh->tag_get_type( tag_handle, tagType ) != MB_SUCCESS ) return -1; 00142 00143 if( tagType == MB_TAG_BIT ) 00144 { 00145 // Pad any bit tags to a size in full bytes. 00146 tag_size = ( tag_size % 8 ? 1 : 0 ) + ( tag_size / 8 ); 00147 } 00148 00149 // Now pad so that the next tag will be word-aligned: 00150 while( tag_size % sizeof( int ) ) 00151 ++tag_size; 00152 00153 this->vertex_size += tag_size; 00154 00155 this->input_vertex_tags.push_back( std::pair< Tag, int >( tag_handle, offset ) ); 00156 return offset; 00157 } 00158 00159 /**\fn int RefinerTagManager::get_vertex_tag_size() 00160 *\brief Return the number of bytes to allocate for tag data per point. 00161 */ 00162 00163 /**\fn int RefinerTagManager::get_number_of_vertex_tags() const 00164 *\brief Return the number of tags that will be output with each new vertex. 00165 */ 00166 00167 /// Clear the list of tag values that will appear past the element coordinates in \a p0, \a p1, and 00168 /// \a p2. 00169 void RefinerTagManager::reset_element_tags() 00170 { 00171 this->element_size = 0; 00172 this->input_element_tags.clear(); 00173 this->output_element_tags.clear(); 00174 this->element_tag_data.clear(); 00175 } 00176 00177 /** Add a tag to the list of tag values that will appear past the element coordinates. 00178 * The return value is the offset into each element coordinate pointer (\a p0, \a p1, \a p2) where 00179 * the tag value(s) will be stored. 00180 */ 00181 int RefinerTagManager::add_element_tag( Tag tag_handle ) 00182 { 00183 int offset = this->element_size; // old size is offset of tag being added 00184 int tag_size; 00185 TagType tagType; 00186 if( this->input_mesh->tag_get_bytes( tag_handle, tag_size ) != MB_SUCCESS ) return -1; 00187 00188 if( this->input_mesh->tag_get_type( tag_handle, tagType ) != MB_SUCCESS ) return -1; 00189 00190 if( tagType == MB_TAG_BIT ) 00191 { 00192 // Pad any bit tags to a size in full bytes. 00193 tag_size = ( tag_size % 8 ? 1 : 0 ) + ( tag_size / 8 ); 00194 } 00195 00196 // Now pad so that the next tag will be word-aligned: 00197 while( tag_size % sizeof( int ) ) 00198 ++tag_size; 00199 00200 this->element_size += tag_size; 00201 this->element_tag_data.resize( this->element_size ); 00202 00203 this->input_element_tags.push_back( std::pair< Tag, int >( tag_handle, offset ) ); 00204 return offset; 00205 } 00206 00207 /**\fn int RefinerTagManager::get_element_tag_size() 00208 *\brief Return the number of bytes to allocate for tag data per point. 00209 */ 00210 00211 /**\fn int RefinerTagManager::get_number_of_element_tags() const 00212 *\brief Return the number of tags that will be output with each new element. 00213 */ 00214 00215 /**\brief Populate the list of output tags to match the list of input tags. 00216 * 00217 * When the input mesh and output mesh pointers are identical, this simply copies the list of input 00218 * tags. When the two meshes are distinct, the corresponding tags are created on the output mesh. 00219 */ 00220 void RefinerTagManager::create_output_tags() 00221 { 00222 if( this->input_mesh == this->output_mesh ) 00223 { 00224 this->output_vertex_tags = this->input_vertex_tags; 00225 this->output_element_tags = this->input_element_tags; 00226 return; 00227 } 00228 00229 std::vector< std::pair< Tag, int > >::iterator it; 00230 for( it = this->input_vertex_tags.begin(); it != this->input_vertex_tags.end(); ++it ) 00231 { 00232 this->create_tag_internal( it->first, it->second ); 00233 } 00234 } 00235 00236 /**\brief Return the tag handle and its offset in the array of tag data of each vertex. 00237 * 00238 * @param[in] i An index into the list of tags for the vertex. 00239 * @param[out] tag The tag handle on the input mesh for the $i$-th vertex tag. 00240 * @param[out] byte_offset The offset (in bytes) of the start of this tag's data in a vertex tag 00241 * record. 00242 */ 00243 void RefinerTagManager::get_input_vertex_tag( int i, Tag& tag, int& byte_offset ) 00244 { 00245 std::vector< std::pair< Tag, int > >::iterator it = this->input_vertex_tags.begin() + i; 00246 tag = it->first; 00247 byte_offset = it->second; 00248 } 00249 00250 /**\brief Return the tag handle and its offset in the array of tag data of each vertex. 00251 * 00252 * @param[in] i An index into the list of tags for the vertex. 00253 * @param[out] tag The tag handle on the output mesh for the $i$-th vertex tag. 00254 * @param[out] byte_offset The offset (in bytes) of the start of this tag's data in a vertex tag 00255 * record. 00256 */ 00257 void RefinerTagManager::get_output_vertex_tag( int i, Tag& tag, int& byte_offset ) 00258 { 00259 std::vector< std::pair< Tag, int > >::iterator it = this->output_vertex_tags.begin() + i; 00260 tag = it->first; 00261 byte_offset = it->second; 00262 } 00263 00264 /**\brief Retrieve the global ID of each input entity and push it onto the output vector. 00265 * 00266 * The \a gids array is emptied by this call before any new values are added. 00267 * Note that this routine fetches global IDs from the input mesh, not the output mesh; 00268 * your entity handles must be from the input mesh. 00269 * 00270 * @param[in] ents An array of entities in the input mesh whose global IDs you desire 00271 * @param[in] n The number of entities in the \a ents array. 00272 * @param[out] gids A vector to contain the resulting global IDs. 00273 * @retval A MOAB error code as supplied by the Interface::tag_get_data() call. 00274 */ 00275 int RefinerTagManager::get_input_gids( int n, const EntityHandle* ents, std::vector< int >& gids ) 00276 { 00277 int stat = 0; 00278 gids.clear(); 00279 for( int i = 0; i < n; ++i ) 00280 { 00281 int gid = -1; 00282 stat |= this->input_mesh->tag_get_data( this->tag_igid, ents + i, 1, &gid ); 00283 gids.push_back( gid ); 00284 } 00285 return stat; 00286 } 00287 00288 /**\brief Retrieve the global ID of each output entity and push it onto the output vector. 00289 * 00290 * The \a gids array is emptied by this call before any new values are added. 00291 * Note that this routine fetches global IDs from the output mesh, not the input mesh; 00292 * your entity handles must be from the output mesh. 00293 * Also, be aware that many output entities will not have global IDs assigned; 00294 * only those vertices which exist in the input mesh are guaranteed to have global IDs 00295 * assigned to them -- vertices that only exist in the output mesh and all higher-dimensional 00296 * output entities have no global IDs assigned until after a complete subdivision pass has been 00297 * made. 00298 * 00299 * @param[in] ents An array of entities in the output mesh whose global IDs you desire 00300 * @param[in] n The number of entities in the \a ents array. 00301 * @param[out] gids A vector to contain the resulting global IDs. 00302 * @retval A MOAB error code as supplied by the Interface::tag_get_data() call. 00303 */ 00304 int RefinerTagManager::get_output_gids( int n, const EntityHandle* ents, std::vector< int >& gids ) 00305 { 00306 int stat = 0; 00307 gids.clear(); 00308 for( int i = 0; i < n; ++i ) 00309 { 00310 int gid = -1; 00311 stat |= this->output_mesh->tag_get_data( this->tag_ogid, ents + i, 1, &gid ); 00312 gids.push_back( gid ); 00313 } 00314 return stat; 00315 } 00316 00317 /**\brief Assign a global ID to an output entity. 00318 * 00319 * @param[in] ent The entity whose ID will be set 00320 * @param[out] id The global ID 00321 * @retval An error code as returned by Interface::tag_set_data(). 00322 */ 00323 int RefinerTagManager::set_gid( EntityHandle ent, int gid ) 00324 { 00325 return this->output_mesh->tag_set_data( this->tag_ogid, &ent, 1, &gid ); 00326 } 00327 00328 /**\brief Copy a global ID from an entity of the input mesh to an entity of the output mesh. 00329 * 00330 * @param[in] ent_input An entity on the input mesh with a global ID. 00331 * @param[in] ent_output An entity on the output mesh whose global ID should be set. 00332 * @retval Normally MB_SUCCESS, but returns other values if tag_get_data or 00333 * tag_set_data fail. 00334 */ 00335 int RefinerTagManager::copy_gid( EntityHandle ent_input, EntityHandle ent_output ) 00336 { 00337 int gid = -1; 00338 int status; 00339 if( ( status = this->input_mesh->tag_get_data( this->tag_igid, &ent_input, 1, &gid ) ) == MB_SUCCESS ) 00340 { 00341 status = this->output_mesh->tag_set_data( this->tag_ogid, &ent_output, 1, &gid ); 00342 } 00343 return status; 00344 } 00345 00346 /**\brief Set parallel status and sharing process list on an entity. 00347 * 00348 * This sets tag values for the PARALLEL_STATUS and one of PARALLEL_SHARED_PROC or 00349 * PARALLEL_SHARED_PROCS tags if \a procs contains any processes (the current process is assumed 00350 * <b>not</b> to be set in \a procs). 00351 * 00352 * @param[in] ent_handle The entity whose information will be set 00353 * @param[in] procs The set of sharing processes. 00354 */ 00355 void RefinerTagManager::set_sharing( EntityHandle ent_handle, ProcessSet& procs ) 00356 { 00357 int pstat; 00358 if( procs.get_process_members( this->rank, this->shared_procs_out ) ) 00359 pstat = PSTATUS_SHARED | PSTATUS_INTERFACE; 00360 else 00361 pstat = PSTATUS_SHARED | PSTATUS_INTERFACE | PSTATUS_NOT_OWNED; 00362 if( this->shared_procs_out[0] >= 0 ) 00363 { 00364 // assert( MAX_SHARING_PROCS > 1 ); 00365 // Since get_process_members pads to MAX_SHARING_PROCS, this will be work: 00366 if( this->shared_procs_out[1] <= 0 ) 00367 { 00368 // std::cout << " (proc )"; 00369 this->output_mesh->tag_set_data( this->tag_opsproc, &ent_handle, 1, &this->shared_procs_out[0] ); 00370 this->output_mesh->tag_set_data( this->tag_opstatus, &ent_handle, 1, &pstat ); 00371 } 00372 else 00373 { 00374 // std::cout << " (procS)"; 00375 this->output_mesh->tag_set_data( this->tag_opsprocs, &ent_handle, 1, &this->shared_procs_out[0] ); 00376 this->output_mesh->tag_set_data( this->tag_opstatus, &ent_handle, 1, &pstat ); 00377 } 00378 } 00379 else 00380 { 00381 // std::cout << " (none )"; 00382 } 00383 // std::cout << " new pstat: " << pstat << "\n"; 00384 } 00385 00386 /**\brief Determine the subset of processes which all share the specified entities. 00387 * 00388 * This is used to determine which processes an output entity should reside on when 00389 * it is defined using several input entities (such as vertices). 00390 */ 00391 void RefinerTagManager::get_common_processes( int num, 00392 const EntityHandle* src, 00393 ProcessSet& common_shared_procs, 00394 bool on_output_mesh ) 00395 { 00396 Interface* mesh; 00397 Tag psproc; 00398 Tag psprocs; 00399 if( on_output_mesh ) 00400 { 00401 mesh = this->output_mesh; 00402 psproc = this->tag_opsproc; 00403 psprocs = this->tag_opsprocs; 00404 } 00405 else 00406 { 00407 mesh = this->input_mesh; 00408 psproc = this->tag_ipsproc; 00409 psprocs = this->tag_ipsprocs; 00410 } 00411 bool first_ent = true; 00412 common_shared_procs.clear(); 00413 for( int i = 0; i < num; ++i ) 00414 { 00415 EntityHandle ent_in = src[i]; 00416 // std::cout << "<(" << ent_in << ")>"; 00417 int stat; 00418 bool got = false; 00419 this->current_shared_procs.clear(); 00420 stat = mesh->tag_get_data( psproc, &ent_in, 1, &this->shared_procs_in[0] ); 00421 if( stat == MB_SUCCESS && this->shared_procs_in[0] != -1 ) 00422 { 00423 got = true; 00424 // std::cout << " s" << this->rank << " s" << this->shared_procs_in[0] << " | "; 00425 this->shared_procs_in[1] = -1; 00426 } 00427 stat = mesh->tag_get_data( psprocs, &ent_in, 1, &this->shared_procs_in[0] ); 00428 if( stat == MB_SUCCESS && this->shared_procs_in[0] != -1 ) 00429 { 00430 got = true; 00431 /* 00432 int i; 00433 for ( i = 0; i < MAX_SHARING_PROCS && this->shared_procs_in[i] != -1; ++ i ) 00434 std::cout << " m" << this->shared_procs_in[i]; 00435 std::cout << " | "; 00436 */ 00437 } 00438 if( got ) 00439 { 00440 this->current_shared_procs.set_process_members( this->shared_procs_in ); 00441 this->current_shared_procs.set_process_member( this->rank ); 00442 if( first_ent ) 00443 { 00444 common_shared_procs.unite( this->current_shared_procs ); 00445 first_ent = false; 00446 } 00447 else 00448 { 00449 common_shared_procs.intersect( this->current_shared_procs ); 00450 } 00451 } 00452 else 00453 { 00454 // not shared, but everthing exists on this process, so make sure that bit is set... 00455 common_shared_procs.set_process_member( this->rank ); 00456 } 00457 } 00458 #ifdef MB_DEBUG 00459 std::cout << " Common procs " << common_shared_procs; 00460 std::cout << "\n"; 00461 #endif // MB_DEBUG 00462 } 00463 00464 void RefinerTagManager::create_tag_internal( Tag tag_in, int offset ) 00465 { 00466 std::pair< Tag, int > tag_rec; 00467 std::vector< char > tag_default; 00468 std::string tag_name; 00469 TagType tag_type; 00470 DataType tag_data_type; 00471 int tag_size; 00472 00473 tag_rec.second = offset; 00474 this->input_mesh->tag_get_name( tag_in, tag_name ); 00475 this->input_mesh->tag_get_bytes( tag_in, tag_size ); 00476 this->input_mesh->tag_get_type( tag_in, tag_type ); 00477 this->input_mesh->tag_get_data_type( tag_in, tag_data_type ); 00478 this->input_mesh->tag_get_default_value( tag_in, (void*)&tag_default[0] ); 00479 tag_default.resize( tag_size ); 00480 ErrorCode res = this->output_mesh->tag_get_handle( tag_name.c_str(), tag_size, tag_data_type, tag_rec.first, 00481 tag_type | MB_TAG_BYTES | MB_TAG_EXCL, &tag_default[0] ); 00482 #ifdef MB_DEBUG 00483 std::cout << "Creating output tag: \"" << tag_name.c_str() << "\" handle: " << tag_rec.first 00484 << " input handle: " << tag_in << "\n"; 00485 #endif // MB_DEBUG 00486 if( res == MB_FAILURE ) 00487 { 00488 std::cerr << "Could not create output tag name: \"" << tag_name.c_str() << "\" type: " << tag_type 00489 << " data type: " << tag_data_type << "\n"; 00490 } 00491 else 00492 { 00493 this->output_vertex_tags.push_back( tag_rec ); 00494 } 00495 } 00496 00497 void RefinerTagManager::set_element_tags_from_ent( EntityHandle ent_input ) 00498 { 00499 std::vector< std::pair< Tag, int > >::iterator it; 00500 for( it = this->input_element_tags.begin(); it != this->input_element_tags.end(); ++it ) 00501 { 00502 this->input_mesh->tag_get_data( it->first, &ent_input, 1, &this->element_tag_data[it->second] ); 00503 } 00504 } 00505 00506 void RefinerTagManager::assign_element_tags( EntityHandle ent_output ) 00507 { 00508 std::vector< std::pair< Tag, int > >::iterator it; 00509 for( it = this->output_element_tags.begin(); it != this->output_element_tags.end(); ++it ) 00510 { 00511 this->output_mesh->tag_set_data( it->first, &ent_output, 1, &this->element_tag_data[it->second] ); 00512 } 00513 } 00514 00515 } // namespace moab