moab
MeshOutputFunctor.cpp
Go to the documentation of this file.
00001 #include "MeshOutputFunctor.hpp"
00002 
00003 #include "SplitVertices.hpp"
00004 #include "moab/ParallelComm.hpp"
00005 #include "RefinerTagManager.hpp"
00006 
00007 #include <iostream>
00008 #include <set>
00009 #include <iterator>
00010 #include <algorithm>
00011 
00012 #undef MB_DEBUG
00013 
00014 namespace moab {
00015 
00016 MeshOutputFunctor::MeshOutputFunctor( RefinerTagManager* tag_mgr )
00017 {
00018   this->mesh_in  = tag_mgr->get_input_mesh();
00019   this->mesh_out = tag_mgr->get_output_mesh();
00020   this->input_is_output = ( this->mesh_in == this->mesh_out );
00021   this->tag_manager = tag_mgr;
00022   this->destination_set = 0; // don't place output entities in a set by default.
00023 
00024   // When the input mesh and the output mesh are different, this map serves
00025   // as a dictionary from input vertices to output vertices.
00026   this->vertex_map = new SplitVertices<1>( this->tag_manager );
00027 
00028   // Hold information about newly-created vertices on subdivided edges and faces.
00029   this->split_vertices.resize( 4 );
00030   this->split_vertices[0] = 0; // Vertices (0-faces) cannot be split
00031   this->split_vertices[1] = new SplitVertices<1>( this->tag_manager );
00032   this->split_vertices[2] = new SplitVertices<2>( this->tag_manager );
00033   this->split_vertices[3] = new SplitVertices<3>( this->tag_manager );
00034 
00035   // Hold information about newly-created mesh entities (other than split vertices)
00036   // This is necessary in order for global IDs to be assigned consistently across processes.
00037   this->new_entities.resize( 5 );
00038   this->new_entities[0] = new EntitySource( 1, this->tag_manager );
00039   this->new_entities[1] = new EntitySource( 2, this->tag_manager );
00040   this->new_entities[2] = new EntitySource( 3, this->tag_manager );
00041   this->new_entities[3] = new EntitySource( 4, this->tag_manager );
00042   this->new_entities[4] = new EntitySource( 5, this->tag_manager );
00043 }
00044 
00045 MeshOutputFunctor::~MeshOutputFunctor()
00046 {
00047   delete this->vertex_map;
00048   for ( int i = 1; i < 4; ++ i )
00049     delete this->split_vertices[i];
00050   for ( int i = 0; i < 5; ++ i )
00051     delete this->new_entities[i];
00052 }
00053 
00054 void MeshOutputFunctor::print_vert_crud(
00055     EntityHandle vout, int nvhash, EntityHandle* vhash, const double* vcoords, const void* /*vtags*/ )
00056 {
00057   std::cout << "+ {";
00058   for ( int i = 0; i < nvhash; ++ i )
00059     std::cout << " " << vhash[i];
00060   std::cout << " } -> " << vout << " ";
00061 
00062   std::cout << "[ " << vcoords[0];
00063   for ( int i = 1; i < 6; ++i )
00064     std::cout << ", " << vcoords[i];
00065   std::cout << " ] ";
00066 
00067 #if 0
00068   double* x = (double*)vtags;
00069   int* m = (int*)( (char*)vtags + 2 * sizeof( double ) );
00070   std::cout << "< " << x[0]
00071     << ", " << x[1];
00072   for ( int i = 0; i < 4; ++i )
00073     std::cout << ", " << m[i];
00074 #endif // 0
00075 
00076   std::cout << " >\n";
00077   //std::cout << "##############################\n";
00078   //this->mesh_out->list_entities( 0, 1 );
00079   //std::cout << "##############################\n";
00080 }
00081 
00082 void MeshOutputFunctor::assign_global_ids( ParallelComm* comm )
00083 {
00084   // First, we must gather the number of entities in each
00085   // partition (for all partitions, not just those resident locally).
00086   int lnparts = this->proc_partition_counts.size();
00087   std::vector<unsigned char> lpdefns;
00088   std::vector<int> lpsizes;
00089   lpdefns.resize( ProcessSet::SHARED_PROC_BYTES * lnparts );
00090   lpsizes.resize( lnparts );
00091 #ifdef MB_DEBUG
00092   std::cout << "**** Partition Counts ****\n";
00093 #endif // MB_DEBUG
00094   int i = 0;
00095   std::map<ProcessSet,int>::iterator it;
00096   for ( it = this->proc_partition_counts.begin(); it != this->proc_partition_counts.end(); ++ it, ++ i )
00097     {
00098     for ( int j = 0; j < ProcessSet::SHARED_PROC_BYTES; ++ j )
00099       lpdefns[ProcessSet::SHARED_PROC_BYTES * i + j] = it->first.data()[j];
00100     lpsizes[i] = it->second;
00101 #ifdef MB_DEBUG
00102     std::cout << "Partition " << it->first << ": " << it->second << "\n";
00103 #endif // MB_DEBUG
00104     }
00105 
00106   if ( ! comm )
00107     return;
00108 
00109   std::vector<int> nparts;
00110   std::vector<int> dparts;
00111   //unsigned long prank = comm->proc_config().proc_rank();
00112   unsigned long psize = comm->proc_config().proc_size();
00113   nparts.resize( psize );
00114   dparts.resize( psize + 1 );
00115   MPI_Allgather( &lnparts, 1, MPI_INT, &nparts[0], 1, MPI_INT, comm->proc_config().proc_comm() );
00116   //unsigned long ndefs = 0;
00117   for ( unsigned long rank = 1; rank <= psize; ++ rank )
00118     {
00119     dparts[rank] = nparts[rank - 1] + dparts[rank - 1];
00120 #ifdef MB_DEBUG
00121     std::cout << "Proc " << rank << ": " << nparts[rank-1] << " partitions, offset: " << dparts[rank] << "\n";
00122 #endif // MB_DEBUG
00123     }
00124   std::vector<unsigned char> part_defns;
00125   std::vector<int> part_sizes;
00126   part_defns.resize( ProcessSet::SHARED_PROC_BYTES * dparts[psize] );
00127   part_sizes.resize( dparts[psize] );
00128   MPI_Allgatherv(
00129     &lpsizes[0], lnparts, MPI_INT,
00130     &part_sizes[0], &nparts[0], &dparts[0], MPI_INT, comm->proc_config().proc_comm() );
00131   for ( unsigned long rank = 0; rank < psize; ++ rank )
00132     {
00133     nparts[rank] *= ProcessSet::SHARED_PROC_BYTES;
00134     dparts[rank] *= ProcessSet::SHARED_PROC_BYTES;
00135     }
00136   MPI_Allgatherv(
00137     &lpdefns[0], ProcessSet::SHARED_PROC_BYTES * lnparts, MPI_UNSIGNED_CHAR,
00138     &part_defns[0], &nparts[0], &dparts[0], MPI_UNSIGNED_CHAR, comm->proc_config().proc_comm() );
00139 
00140   // Now that we have the number of new entities in every partition, we
00141   // can deterministically assign the same GID to the same entity even
00142   // when shared across processors because we have an ordering that is
00143   // identical on all processes -- the vertex splits.
00144   for ( int j = 0; j < dparts[psize]; ++ j )
00145     {
00146     ProcessSet pset( &part_defns[ProcessSet::SHARED_PROC_BYTES * j] );
00147     std::map<ProcessSet,int>::iterator mit = this->proc_partition_counts.find( pset );
00148     if ( mit != this->proc_partition_counts.end() )
00149       {
00150 #ifdef MB_DEBUG
00151       std::cout << "Partition " << pset << ( mit->second == part_sizes[j] ? " matches" : " broken" ) << ".\n";
00152 #endif // MB_DEBUG
00153       }
00154     else
00155       {
00156       this->proc_partition_counts[pset] = part_sizes[j];
00157       }
00158     }
00159   
00160   std::map<ProcessSet,int> gids;
00161   std::map<ProcessSet,int>::iterator pcit;
00162   EntityHandle start_gid = 100; // FIXME: Get actual maximum GID across all processes and add 1
00163   for ( pcit = this->proc_partition_counts.begin(); pcit != this->proc_partition_counts.end(); ++ pcit )
00164     {
00165     gids[pcit->first] = start_gid;
00166     start_gid += pcit->second;
00167 #ifdef MB_DEBUG
00168     std::cout << "Partition " << pcit->first << ": " << pcit->second << " # [" << gids[pcit->first] << "]\n";
00169 #endif // MB_DEBUG
00170     }
00171   std::vector<SplitVerticesBase*>::iterator vit;
00172   vit = this->split_vertices.begin();
00173   ++ vit; // Skip split_vertices[0] since it's empty.
00174   ++ vit; // Skip split_vertices[1] since those entries already have global IDs... they exist in the input mesh.
00175   for ( /* skip */; vit != this->split_vertices.end(); ++ vit )
00176     {
00177     (*vit)->assign_global_ids( gids );
00178     }
00179   std::vector<EntitySource*>::iterator sit;
00180   for ( sit = this->new_entities.begin(); sit != this->new_entities.end(); ++ sit )
00181     {
00182     if ( *sit )
00183       (*sit)->assign_global_ids( gids );
00184     }
00185 }
00186 
00187 void MeshOutputFunctor::exchange_handles( ParallelComm*  )
00188 {
00189 }
00190 
00191 void MeshOutputFunctor::assign_tags( EntityHandle vhandle, const void* vtags )
00192 {
00193   if ( ! vhandle )
00194     return; // Ignore bad vertices
00195 
00196   int num_tags = this->tag_manager->get_number_of_vertex_tags();
00197   Tag tag_handle;
00198   int tag_offset;
00199   for ( int i = 0; i < num_tags; ++i )
00200     {
00201     this->tag_manager->get_output_vertex_tag( i, tag_handle, tag_offset );
00202     this->mesh_out->tag_set_data( tag_handle, &vhandle, 1, vtags );
00203     }
00204 }
00205 
00206 EntityHandle MeshOutputFunctor::map_vertex( EntityHandle vhash, const double* vcoords, const void* vtags )
00207 {
00208   if ( this->input_is_output )
00209     { // Don't copy the original vertex!
00210 #ifdef MB_DEBUG
00211     this->print_vert_crud( vhash, 1, &vhash, vcoords, vtags );
00212 #endif // MB_DEBUG
00213     return vhash;
00214     }
00215   EntityHandle vertex_handle;
00216   bool newly_created = this->vertex_map->find_or_create(
00217     &vhash, vcoords, vertex_handle, this->proc_partition_counts, false );
00218   if ( newly_created )
00219     {
00220     std::vector<int> gid;
00221     this->assign_tags( vertex_handle, vtags );
00222     if ( this->tag_manager->get_input_gids( 1, &vhash, gid ) == MB_SUCCESS )
00223       {
00224       this->tag_manager->set_gid( vertex_handle, gid[0] );
00225       }
00226     }
00227   if ( ! vertex_handle )
00228     {
00229     std::cerr << "Could not insert vertex into new mesh!\n";
00230     }
00231 #ifdef MB_DEBUG
00232   this->print_vert_crud( vertex_handle, 1, &vhash, vcoords, vtags );
00233   std::cout << "\nMap vert: " << vhash << " to: " << vertex_handle << "\n";
00234 #endif // MB_DEBUG
00235   return vertex_handle;
00236 }
00237 
00238 EntityHandle MeshOutputFunctor::operator () ( int nvhash, EntityHandle* vhash, const double* vcoords, const void* vtags )
00239 {
00240   EntityHandle vertex_handle;
00241   if ( nvhash < 4 )
00242     {
00243     bool newly_created = this->split_vertices[nvhash]->find_or_create(
00244       vhash, vcoords, vertex_handle, this->proc_partition_counts, true );
00245     if ( newly_created )
00246       {
00247       this->assign_tags( vertex_handle, vtags );
00248       }
00249     if ( ! vertex_handle )
00250       {
00251       std::cerr << "Could not insert mid-edge vertex!\n";
00252       }
00253 #ifdef MB_DEBUG
00254     std::cout << "(-" << nvhash << "-) ";
00255     this->print_vert_crud( vertex_handle, nvhash, vhash, vcoords, vtags );
00256 #endif // MB_DEBUG
00257     }
00258   else
00259     {
00260     vertex_handle = 0;
00261     std::cerr << "Not handling splits on faces with " << nvhash << " corners yet.\n";
00262     }
00263   return vertex_handle;
00264 }
00265 
00266 void MeshOutputFunctor::operator () ( EntityHandle h )
00267 {
00268 #ifdef MB_DEBUG
00269   std::cout << h << " ";
00270 #endif // MB_DEBUG
00271   if ( ! this->input_is_output )
00272     {
00273     // FIXME: Copy to output mesh
00274     }
00275   this->elem_vert.push_back( h );
00276 }
00277 
00278 void MeshOutputFunctor::operator () ( EntityType etyp )
00279 {
00280   EntityHandle elem_handle;
00281   int nconn = this->elem_vert.size();
00282   bool newly_created = this->new_entities[nconn]->create_element(
00283     etyp, nconn, &this->elem_vert[0], elem_handle, this->proc_partition_counts );
00284   if ( newly_created )
00285     {
00286 #ifdef MB_DEBUG
00287     std::cout << " *** ";
00288 #endif // MB_DEBUG
00289     // FIXME: Handle tag assignment for elements as well as vertices
00290     this->tag_manager->assign_element_tags( elem_handle );
00291     }
00292 #ifdef MB_DEBUG
00293   std::cout << "---------> " << elem_handle << " ( " << etyp << " )\n\n";
00294 #endif // MB_DEBUG
00295   this->elem_vert.clear();
00296 }
00297 
00298 } // namespace moab
00299 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines