![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
00001 //
00002 // Usage:
00003 // tools/mbslavepart -d 2 -m mpas/x1.2562.grid.h5m -s mpas/x1.10242.grid.h5m -o mpas_slave.h5m -e
00004 // 1e-8 -b 1e-6 -O
00005 //
00006 #include
00007 #include
00008 #include
00009 #include
00010 #include
00011
00012 #include "moab/ProgOptions.hpp"
00013 #include "moab/Core.hpp"
00014 #include "moab/AdaptiveKDTree.hpp"
00015 #include "moab/BVHTree.hpp"
00016
00017 #include "moab/IntxMesh/IntxUtils.hpp"
00018
00019 #ifdef MOAB_HAVE_MPI
00020 #include "moab_mpi.h"
00021 #include "moab/ParallelComm.hpp"
00022 #include "MBParallelConventions.h"
00023 #endif
00024
00025 using namespace moab;
00026
00027 // A function to get the non-default value from a std::map
00028 template < typename K, typename V >
00029 static V get_map_value( const std::map< K, V >& m, const K& key, const V& defval )
00030 {
00031 typename std::map< K, V >::const_iterator it = m.find( key );
00032 if( it == m.end() )
00033 {
00034 return defval;
00035 }
00036 else
00037 {
00038 return it->second;
00039 }
00040 }
00041
00042 int main( int argc, char* argv[] )
00043 {
00044 int nprocs = 1, dimension = 3;
00045 int dimension_source = 3;
00046 #ifdef MOAB_HAVE_MPI
00047 int proc_id = 0;
00048 MPI_Init( &argc, &argv );
00049 MPI_Comm_rank( MPI_COMM_WORLD, &proc_id );
00050 MPI_Comm_size( MPI_COMM_WORLD, &nprocs );
00051 #endif
00052
00053 int defaultpart = 0;
00054 double tolerance = 1e-2, treetolerance = 1e-13, btolerance = 1e-4;
00055 std::string masterfile, slavefile, outfile( "slavemesh.h5m" );
00056 bool keepsparts = false;
00057 bool use_spherical = false;
00058 ProgOptions opts;
00059
00060 opts.addOpt< std::string >( "master,m", "Master mesh filename", &masterfile );
00061 opts.addOpt< std::string >( "slave,s", "Slave mesh filename", &slavefile );
00062 opts.addOpt< std::string >( "output,o", "Output partitioned mesh filename", &outfile );
00063 opts.addOpt< int >( "dims,c", "Dimension of entities in source used for partitioning", &dimension_source );
00064 opts.addOpt< int >( "dim,d", "Dimension of entities in target to use for partitioning", &dimension );
00065 opts.addOpt< int >( "defaultpart,p", "Default partition number if target element is not found on source grid",
00066 &defaultpart );
00067 opts.addOpt< double >( "eps,e", "Tolerance for the point search", &tolerance );
00068 opts.addOpt< double >( "beps,b", "Tolerance for the bounding box search", &btolerance );
00069 opts.addOpt< void >( "keep,K",
00070 "Keep the existing partitions in the slave mesh (use PARALLEL_PARTITION_SLAVE instead)",
00071 &keepsparts );
00072 opts.addOpt< void >( "spherical", "Hint that the meshes are defined on a spherical surface (Climate problems)",
00073 &use_spherical );
00074 opts.parseCommandLine( argc, argv );
00075
00076 if( masterfile.empty() || slavefile.empty() )
00077 {
00078 opts.printHelp();
00079 #ifdef MOAB_HAVE_MPI
00080 MPI_Finalize();
00081 #endif
00082 exit( 1 );
00083 }
00084
00085 ErrorCode error;
00086 Core* mbCore = new Core();
00087
00088 // Set the read options for parallel file loading
00089 const std::string partition_set_name = "PARALLEL_PARTITION";
00090 const std::string global_id_name = "GLOBAL_ID";
00091 std::vector< std::string > read_opts, write_opts;
00092 std::string read_options( "" ), write_options( "" );
00093
00094 if( nprocs > 1 )
00095 {
00096 read_options = "PARALLEL=READ_PART;PARTITION=" + partition_set_name + ";PARALLEL_RESOLVE_SHARED_ENTS";
00097 write_options = "PARALLEL=WRITE_PART";
00098 }
00099
00100 EntityHandle masterfileset, slavefileset;
00101 error = mbCore->create_meshset( moab::MESHSET_TRACK_OWNER | moab::MESHSET_SET, masterfileset );MB_CHK_ERR( error );
00102 error = mbCore->create_meshset( moab::MESHSET_TRACK_OWNER | moab::MESHSET_SET, slavefileset );MB_CHK_ERR( error );
00103
00104 // Load file
00105 error = mbCore->load_file( masterfile.c_str(), &masterfileset, read_options.c_str() );MB_CHK_ERR( error );
00106 error = mbCore->load_file( slavefile.c_str(), &slavefileset, read_options.c_str() );MB_CHK_ERR( error );
00107 // if (error != MB_SUCCESS && size > 1)
00108 // {
00109 // std::string newread_options = "PARALLEL=BCAST_DELETE;PARALLEL_RESOLVE_SHARED_ENTS";
00110 // error = mbCore->load_file(slavefile.c_str(), &slavefileset, newread_options.c_str());
00111 // }
00112 // else MB_CHK_ERR(error);
00113
00114 Tag gidtag = 0, parttag = 0, sparttag = 0;
00115 int dum_id = -1;
00116 error = mbCore->tag_get_handle( partition_set_name.c_str(), 1, MB_TYPE_INTEGER, parttag,
00117 MB_TAG_SPARSE | MB_TAG_CREAT, &dum_id );MB_CHK_ERR( error );
00118 gidtag = mbCore->globalId_tag();
00119 if( keepsparts )
00120 {
00121 error = mbCore->tag_get_handle( std::string( partition_set_name + "_SLAVE" ).c_str(), 1, MB_TYPE_INTEGER,
00122 sparttag, MB_TAG_CREAT | MB_TAG_SPARSE, &dum_id );MB_CHK_ERR( error );
00123 }
00124
00125 Range melems, msets, selems, ssets;
00126
00127 // Get the partition sets on the master mesh
00128 std::map< int, int > mpartvals;
00129 error = mbCore->get_entities_by_type_and_tag( masterfileset, MBENTITYSET, &parttag, NULL, 1, msets,
00130 moab::Interface::UNION, true );MB_CHK_ERR( error );
00131 if( msets.size() == 0 )
00132 {
00133 std::cout << "No partition sets found in the master mesh. Quitting..." << std::endl;
00134 exit( 1 );
00135 }
00136
00137 for( unsigned i = 0; i < msets.size(); ++i )
00138 {
00139 EntityHandle mset = msets[i];
00140
00141 moab::Range msetelems;
00142 error = mbCore->get_entities_by_dimension( mset, dimension_source, msetelems );MB_CHK_ERR( error );
00143 melems.merge( msetelems );
00144
00145 int partID;
00146 error = mbCore->tag_get_data( parttag, &mset, 1, &partID );MB_CHK_ERR( error );
00147
00148 // Get the global ID and use that as the indicator
00149 std::vector< int > gidMelems( msetelems.size() );
00150 error = mbCore->tag_get_data( gidtag, msetelems, gidMelems.data() );MB_CHK_ERR( error );
00151
00152 for( unsigned j = 0; j < msetelems.size(); ++j )
00153 mpartvals[gidMelems[j]] = partID;
00154 // mpartvals[msetelems[j]]=partID;
00155 #ifdef VERBOSE
00156 std::cout << "Part " << partID << " has " << msetelems.size() << " elements." << std::endl;
00157 #endif
00158 }
00159
00160 // Get information about the slave file set
00161 error = mbCore->get_entities_by_type_and_tag( slavefileset, MBENTITYSET, &parttag, NULL, 1, ssets,
00162 moab::Interface::UNION );MB_CHK_ERR( error );
00163 // TODO: expand and add other dimensional elements
00164 error = mbCore->get_entities_by_dimension( slavefileset, dimension, selems );MB_CHK_ERR( error );
00165
00166 std::cout << "Master (elements, parts) : (" << melems.size() << ", " << msets.size()
00167 << "), Slave (elements, parts) : (" << selems.size() << ", " << ssets.size() << ")" << std::endl;
00168
00169 double master_radius = 1.0, slave_radius = 1.0;
00170 std::vector< double > mastercoords;
00171 Range masterverts, slaveverts;
00172 {
00173 error = mbCore->get_entities_by_dimension( masterfileset, 0, masterverts );MB_CHK_ERR( error );
00174 error = mbCore->get_entities_by_dimension( slavefileset, 0, slaveverts );MB_CHK_ERR( error );
00175 }
00176 if( use_spherical )
00177 {
00178 double points[6];
00179 EntityHandle mfrontback[2] = { masterverts[0], masterverts[masterverts.size() - 1] };
00180 error = mbCore->get_coords( &mfrontback[0], 2, points );MB_CHK_ERR( error );
00181 master_radius = 0.5 * ( std::sqrt( points[0] * points[0] + points[1] * points[1] + points[2] * points[2] ) +
00182 std::sqrt( points[3] * points[3] + points[4] * points[4] + points[5] * points[5] ) );
00183 EntityHandle sfrontback[2] = { slaveverts[0], slaveverts[slaveverts.size() - 1] };
00184 error = mbCore->get_coords( &sfrontback[0], 2, points );MB_CHK_ERR( error );
00185 slave_radius = 0.5 * ( std::sqrt( points[0] * points[0] + points[1] * points[1] + points[2] * points[2] ) +
00186 std::sqrt( points[3] * points[3] + points[4] * points[4] + points[5] * points[5] ) );
00187 // Let us rescale both master and slave meshes to a unit sphere
00188 error = moab::IntxUtils::ScaleToRadius( mbCore, masterfileset, 1.0 );MB_CHK_ERR( error );
00189 error = moab::IntxUtils::ScaleToRadius( mbCore, slavefileset, 1.0 );MB_CHK_ERR( error );
00190 }
00191
00192 try
00193 {
00194 std::map< int, moab::Range > spartvals;
00195 int npoints_notfound = 0;
00196 {
00197 FileOptions fopts( ( use_spherical ? "SPHERICAL" : "" ) );
00198 moab::EntityHandle tree_root = masterfileset;
00199
00200 moab::AdaptiveKDTree tree( mbCore );
00201 error = tree.build_tree( melems, &tree_root, &fopts );
00202
00203 // moab::BVHTree tree(mbCore);
00204 // error = tree.build_tree(melems, &tree_root);MB_CHK_ERR(error);
00205
00206 for( size_t ie = 0; ie < selems.size(); ie++ )
00207 {
00208 moab::EntityHandle selem, leaf;
00209 double point[3];
00210 selem = selems[ie];
00211
00212 // Get the element centroid to be queried
00213 error = mbCore->get_coords( &selem, 1, point );MB_CHK_ERR( error );
00214
00215 std::vector< moab::EntityHandle > leaf_elems;
00216
00217 // Search for the closest source element in the master mesh corresponding
00218 // to the target element centroid in the slave mesh
00219 error = tree.point_search( point, leaf, treetolerance, btolerance );MB_CHK_ERR( error );
00220
00221 // We only care about the dimension that the user specified.
00222 // MOAB partitions are ordered by elements anyway.
00223 error = mbCore->get_entities_by_dimension( leaf, dimension_source, leaf_elems, true );MB_CHK_ERR( error );
00224
00225 if( leaf != 0 && leaf_elems.size() )
00226 {
00227
00228 // Now get the master element centroids so that we can compute
00229 // the minimum distance to the target point
00230 std::vector< double > centroids( leaf_elems.size() * 3 );
00231 error = mbCore->get_coords( &leaf_elems[0], leaf_elems.size(), ¢roids[0] );MB_CHK_ERR( error );
00232
00233 if( !leaf_elems.size() )
00234 std::cout << ie << ": "
00235 << " No leaf elements found." << std::endl;
00236 // else std::cout << ie << " found " << leaf_elems.size() << " leaves for
00237 // current point " << std::endl;
00238
00239 double dist = 1e10;
00240 int pinelem = -1;
00241 for( size_t il = 0; il < leaf_elems.size(); ++il )
00242 {
00243 const double* centroid = ¢roids[il * 3];
00244 const double locdist = std::pow( point[0] - centroid[0], 2 ) +
00245 std::pow( point[1] - centroid[1], 2 ) +
00246 std::pow( point[2] - centroid[2], 2 );
00247 if( locdist < dist && locdist < 1.0E-2 )
00248 {
00249 dist = locdist;
00250 pinelem = il;
00251
00252 #ifdef VERBOSE
00253 int gidMelem;
00254 error = mbCore->tag_get_data( gidtag, &leaf_elems[il], 1, &gidMelem );MB_CHK_ERR( error );
00255 std::cout << "\t Trial leaf " << il << " set " << gidMelem
00256 << " and part = " << get_map_value( mpartvals, gidMelem, -1 )
00257 << " with distance = " << locdist << std::endl;
00258 #endif
00259 }
00260 }
00261
00262 if( pinelem < 0 )
00263 {
00264 #ifdef VERBOSE
00265 std::cout << ie
00266 << ": [Error] - Could not find a minimum distance within the "
00267 "leaf nodes."
00268 << std::endl;
00269 #endif
00270 npoints_notfound++;
00271 spartvals[defaultpart].insert( selems[ie] );
00272 }
00273 else
00274 {
00275 int gidMelem;
00276 error = mbCore->tag_get_data( gidtag, &leaf_elems[pinelem], 1, &gidMelem );MB_CHK_ERR( error );
00277
00278 int mpartid = get_map_value( mpartvals, gidMelem, -1 );
00279 if( mpartid < 0 )
00280 std::cout << "[WARNING]: Part number for element " << leaf_elems[pinelem]
00281 << " with global ID = " << gidMelem << " not found.\n";
00282
00283 #ifdef VERBOSE
00284 std::cout << "Adding element " << ie << " set " << mpartid << " with distance = " << dist
00285 << std::endl;
00286 #endif
00287 spartvals[mpartid].insert( selems[ie] );
00288 }
00289 }
00290 else
00291 {
00292 #ifdef VERBOSE
00293 std::cout << "[WARNING]: Adding element " << ie << " to default (part) set " << defaultpart
00294 << std::endl;
00295 #endif
00296 spartvals[defaultpart].insert( selems[ie] );
00297 }
00298 }
00299 error = tree.reset_tree();MB_CHK_ERR( error );
00300 }
00301 if( npoints_notfound )
00302 std::cout << "Could not find " << npoints_notfound
00303 << " points in the master mesh. Added to defaultpart set = " << defaultpart << std::endl;
00304
00305 if( use_spherical )
00306 {
00307 error = moab::IntxUtils::ScaleToRadius( mbCore, slavefileset, slave_radius );MB_CHK_ERR( error );
00308 }
00309
00310 error = mbCore->delete_entities( &masterfileset, 1 );MB_CHK_ERR( error );
00311 // Find parallel partition sets in the slave mesh - and delete it since we are going to
00312 // overwrite the sets
00313 if( !keepsparts )
00314 {
00315 std::cout << "Deleting " << ssets.size() << " sets in the slave mesh" << std::endl;
00316 error = mbCore->remove_entities( slavefileset, ssets );MB_CHK_ERR( error );
00317 ssets.clear();
00318 }
00319
00320 size_t ntotslave_elems = 0, ntotslave_parts = 0;
00321 for( std::map< int, moab::Range >::iterator it = spartvals.begin(); it != spartvals.end(); ++it )
00322 {
00323 int partID = it->first;
00324 moab::EntityHandle pset;
00325 error = mbCore->create_meshset( moab::MESHSET_SET, pset );MB_CHK_ERR( error );
00326 error = mbCore->add_entities( pset, it->second );MB_CHK_ERR( error );
00327 error = mbCore->add_parent_child( slavefileset, pset );MB_CHK_ERR( error );
00328
00329 #ifdef VERBOSE
00330 std::cout << "Slave Part " << partID << " has " << it->second.size() << " elements." << std::endl;
00331 #endif
00332 ntotslave_elems += it->second.size();
00333 ntotslave_parts++;
00334
00335 if( keepsparts )
00336 {
00337 error = mbCore->tag_set_data( sparttag, &pset, 1, &partID );MB_CHK_ERR( error );
00338 }
00339 else
00340 {
00341 error = mbCore->tag_set_data( parttag, &pset, 1, &partID );MB_CHK_ERR( error );
00342 }
00343 }
00344 std::cout << "Slave mesh: given " << selems.size() << " elements, and assigned " << ntotslave_elems
00345 << " elements to " << ntotslave_parts << " parts.\n";
00346 assert( ntotslave_elems == selems.size() );
00347
00348 // mbCore->print_database();
00349
00350 // Write the re-partitioned slave mesh to disk
00351 if( nprocs == 1 )
00352 {
00353 error = mbCore->write_file( "slavemesh.vtk", "VTK", NULL, &slavefileset, 1 );MB_CHK_ERR( error );
00354 }
00355 error = mbCore->write_file( outfile.c_str(), NULL, write_options.c_str(), &slavefileset, 1 );MB_CHK_ERR( error );
00356 // error = mbCore->write_file(outfile.c_str(), NULL,
00357 // write_options.c_str());MB_CHK_ERR(error);
00358 }
00359 catch( std::exception& e )
00360 {
00361 std::cout << " exception caught during tree initialization " << e.what() << std::endl;
00362 }
00363 delete mbCore;
00364
00365 #ifdef MOAB_HAVE_MPI
00366 MPI_Finalize();
00367 #endif
00368 exit( 0 );
00369 }