moab
|
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