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