Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
RefinerTagManager.cpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines