49 int err = MPI_Init( &argc, &argv );
52 std::cerr <<
"MPI_Init failed. Aborting." << std::endl;
58 std::vector< int > set_l;
60 #ifdef MOAB_HAVE_ZOLTAN
61 bool moab_use_zoltan =
false;
63 #ifdef MOAB_HAVE_METIS
64 bool moab_use_metis =
false;
67 LONG_DESC <<
"This utility invokes the ZoltanPartitioner or MetisPartitioner component of MOAB"
68 "to partition a mesh/geometry."
70 <<
"If no partitioning method is specified, the defaults are: "
77 opts.addOpt<
int >(
"dimension",
78 "Specify dimension of entities to partition."
79 " Default is largest in file.",
82 std::string zoltan_method, parm_method, oct_method, metis_method;
83 #ifdef MOAB_HAVE_ZOLTAN
84 opts.addOpt< std::string >(
"zoltan,z",
85 "(Zoltan) Specify Zoltan partition method. "
86 "One of RR, RCB, RIB, HFSC, PHG, or Hypergraph (PHG and Hypergraph "
89 #ifdef MOAB_HAVE_PARMETIS
90 opts.addOpt< std::string >(
"parmetis,p",
"(Zoltan+PARMetis) Specify PARMetis partition method.", &parm_method );
92 opts.addOpt< std::string >(
"octpart,o",
"(Zoltan) Specify OctPart partition method.", &oct_method );
94 bool incl_closure =
false;
95 opts.addOpt<
void >(
"include_closure,c",
"Include element closure for part sets.", &incl_closure );
97 bool recompute_box_rcb =
false;
98 opts.addOpt<
void >(
"recompute_rcb_box,b",
"recompute box in rcb cuts", &recompute_box_rcb );
101 double imbal_tol = 1.03;
102 opts.addOpt<
double >(
"imbalance,i",
"Imbalance tolerance (used in PHG/Hypergraph method)", &imbal_tol );
104 #ifdef MOAB_HAVE_METIS
105 opts.addOpt< std::string >(
"metis,m",
"(Metis) Specify Metis partition method. One of ML_RB or ML_KWAY.",
109 bool write_sets =
true, write_tags =
false;
110 opts.addOpt<
void >(
"sets,s",
"Write partition as tagged sets (Default)", &write_sets );
111 opts.addOpt<
void >(
"tags,t",
"Write partition by tagging entities", &write_tags );
114 opts.addOpt<
int >(
"power,M",
"Generate multiple partitions, in powers of 2, up to 2^(pow)", &power );
116 bool reorder =
false;
117 opts.addOpt<
void >(
"reorder,R",
"Reorder mesh to group entities by partition", &reorder );
119 double part_geom_mesh_size = -1.0;
120 #ifdef MOAB_HAVE_ZOLTAN
122 opts.addOpt<
int >(
"vertex_w,v",
"(Zoltan) Number of weights associated with a graph vertex." );
125 opts.addOpt<
int >(
"edge_w,e",
"(Zoltan) Number of weights associated with an edge." );
127 bool moab_partition_slave =
false;
128 std::string slave_file_name =
"";
129 opts.addOpt< std::string >(
"inferred",
130 "(Zoltan) Specify inferred slave mesh file name to impose "
131 "partition based on cuts computed for original master mesh.",
134 bool rescale_spherical_radius =
false;
135 opts.addOpt<
void >(
"scale_sphere",
136 "(Zoltan) If the meshes are defined on a sphere, rescale radius as needed "
137 "(in combination with --inferred)",
138 &rescale_spherical_radius );
143 opts.addOpt< std::vector< int > >(
"set_l,l",
144 "Load material set(s) with specified ids (comma separated) for partition" );
146 opts.addRequiredArg<
int >(
"#parts",
"Number of parts in partition" );
149 opts.addRequiredArg< std::string >(
"input_file",
"Mesh/geometry to partition", &
input_file );
150 opts.addRequiredArg< std::string >(
"output_file",
"File to which to write partitioned mesh/geometry",
154 opts.addOpt<
void >(
",T",
"Print CPU time for each phase.", &
print_time );
156 int projection_type = 0;
157 opts.addOpt<
int >(
"project_on_sphere,p",
158 "use spherical coordinates (1) or gnomonic projection (2) for partitioning ",
160 #ifdef MOAB_HAVE_METIS
161 bool partition_tagged_sets =
false;
162 opts.addOpt<
void >(
"taggedsets,x",
"(Metis) Partition tagged sets.", &partition_tagged_sets );
164 bool partition_tagged_ents =
false;
165 opts.addOpt<
void >(
"taggedents,y",
"(Metis) Partition tagged ents.", &partition_tagged_ents );
167 std::string aggregating_tag;
168 opts.addOpt< std::string >(
"aggregatingtag,a",
169 "(Metis) Specify aggregating tag to partion tagged sets or tagged entities.",
172 std::string aggregating_bc_tag;
173 opts.addOpt< std::string >(
"aggregatingBCtag,B",
174 "(Metis) Specify boundary id tag name used to group cells with same boundary ids.",
175 &aggregating_bc_tag );
177 std::string boundaryIds;
178 std::vector< int > BCids;
179 opts.addOpt< std::string >(
"aggregatingBCids,I",
180 " (Metis) Specify id or ids of boundaries to be aggregated before "
181 "partitioning (all elements with same boundary id will be in the "
182 "same partition). Comma separated e.g. -I 1,2,5 ",
186 bool assign_global_ids =
false;
187 opts.addOpt<
void >(
"globalIds,j",
"Assign GLOBAL_ID tag to entities", &assign_global_ids );
189 opts.parseCommandLine( argc, argv );
191 #ifdef MOAB_HAVE_ZOLTAN
192 if( !zoltan_method.empty() )
193 moab_use_zoltan =
true;
196 #ifdef MOAB_HAVE_METIS
197 if( !metis_method.empty() )
198 moab_use_metis =
true;
201 MB_SET_ERR( MB_FAILURE,
"Specify either Zoltan or Metis partitioner type" );
203 #ifdef MOAB_HAVE_ZOLTAN
206 if( part_geom_mesh_size != -1.0 && part_geom_mesh_size <= 0.0 )
208 std::cerr << part_geom_mesh_size <<
": invalid geometry partition mesh size." << std::endl << std::endl;
213 if( slave_file_name.size() ) moab_partition_slave =
true;
215 if( moab_use_zoltan )
217 if( part_geom_mesh_size < 0. )
225 MB_CHK_SET_ERR( MB_FAILURE,
"Geometry will not be partitioned.\n" );
230 if( zoltan_method.empty() && parm_method.empty() && oct_method.empty() ) zoltan_method =
DEFAULT_ZOLTAN_METHOD;
231 if( !parm_method.empty() ) zoltan_method = ZOLTAN_PARMETIS_METHOD;
232 if( !oct_method.empty() ) zoltan_method = ZOLTAN_OCTPART_METHOD;
235 #ifdef MOAB_HAVE_METIS
237 if( moab_use_metis && !metis_tool )
243 if( ( aggregating_tag.empty() && partition_tagged_sets ) || ( aggregating_tag.empty() && partition_tagged_ents ) )
245 if( !write_sets && !write_tags ) write_sets =
true;
247 if( !boundaryIds.empty() )
249 std::vector< std::string > ids;
250 std::stringstream ss( boundaryIds );
252 while( std::getline( ss, item,
',' ) )
254 ids.push_back( item );
256 for(
unsigned int i = 0; i < ids.size(); i++ )
257 BCids.push_back( std::atoi( ids[i].c_str() ) );
260 if( metis_method.empty() )
267 if( !write_sets && !write_tags ) write_sets =
true;
271 num_parts = opts.getReqArg<
int >(
"#parts" );
274 else if( power < 1 || power > 18 )
276 std::cerr << power <<
": invalid power for multiple partitions. Expected value in [1,18]" << std::endl
286 if( part_dim < 0 || part_dim > 3 )
288 std::cerr << part_dim <<
" : invalid dimension" << std::endl << std::endl;
293 if( imbal_tol < 0.0 )
295 std::cerr << imbal_tol <<
": invalid imbalance tolerance" << std::endl << std::endl;
300 bool load_msets =
false;
301 if( opts.getOpt(
"set_l,l", &set_l ) )
304 if( set_l.size() <= 0 )
306 std::cerr <<
" No material set id's to load" << std::endl << std::endl;
314 std::cerr <<
"** Please specify #parts = " << num_parts <<
" to be greater than 1." << std::endl << std::endl;
321 const char* options = NULL;
323 #ifdef MOAB_HAVE_ZOLTAN
324 if( part_geom_mesh_size > 0. ) options =
"FACET_DISTANCE_TOLERANCE=0.1";
327 std::cout <<
"Loading file " <<
input_file <<
"..." << std::endl;
328 if( load_msets ==
false )
337 std::cout <<
"Read input file in " << ( clock() - t ) / (
double)CLOCKS_PER_SEC <<
" seconds" << std::endl;
339 for(
int dim = part_dim;
dim >= 0; --
dim )
351 std::cerr <<
input_file <<
" : file does not contain any mesh entities" << std::endl;
357 for(
int p = 0; p < power; p++ )
360 #ifdef MOAB_HAVE_ZOLTAN
361 if( moab_use_zoltan )
364 part_geom_mesh_size, num_parts, zoltan_method.c_str(),
365 ( !parm_method.empty() ? parm_method.c_str() : oct_method.c_str() ), imbal_tol, part_dim, write_sets,
366 write_tags, obj_weight, edge_weight, projection_type, recompute_box_rcb,
print_time );
MB_CHK_SET_ERR( rval,
"Zoltan partitioner failed." );
369 #ifdef MOAB_HAVE_METIS
372 rval = metis_tool->
partition_mesh( num_parts, metis_method.c_str(), part_dim, write_sets, write_tags,
373 partition_tagged_sets, partition_tagged_ents, aggregating_tag.c_str(),
379 std::cout <<
"Generated " << num_parts <<
" part partitioning in "
380 << ( clock() - t ) / (
double)CLOCKS_PER_SEC <<
" seconds" << std::endl;
382 if( reorder && part_geom_mesh_size < 0. )
384 std::cout <<
"Reordering mesh for partition..." << std::endl;
394 rval = reorder_tool.handle_order_from_sets_and_adj( sets, order );
MB_CHK_SET_ERR( rval,
"Failed to calculate reordering." );
398 rval = reorder_tool.handle_order_from_int_tag( tag, -1, order );
MB_CHK_SET_ERR( rval,
"Failed to calculate reordering." );
401 rval = reorder_tool.reorder_entities( order );
MB_CHK_SET_ERR( rval,
"Failed to perform reordering." );
405 std::cout <<
"Reordered mesh in " << ( clock() - t ) / (
double)CLOCKS_PER_SEC <<
" seconds"
409 #ifdef MOAB_HAVE_ZOLTAN
416 std::ostringstream tmp_output_file;
421 std::string::size_type idx = output_file.find_last_of(
"." );
422 if( idx == std::string::npos )
424 tmp_output_file << output_file <<
"_" << num_parts;
425 if( part_geom_mesh_size < 0. )
426 tmp_output_file <<
".h5m";
429 std::cerr <<
"output file type is not specified." << std::endl;
435 tmp_output_file << output_file.substr( 0, idx ) <<
"_" << num_parts << output_file.substr( idx );
439 tmp_output_file << output_file;
442 std::cout <<
"Saving file to " << output_file <<
"..." << std::endl;
443 if( part_geom_mesh_size < 0. )
445 rval =
mb.
write_file( tmp_output_file.str().c_str() );
MB_CHK_SET_ERR( rval, tmp_output_file.str() <<
" : failed to write file." << std::endl );
449 MB_CHK_SET_ERR( MB_FAILURE,
"Geometry will not be partitioned.\n" );
453 std::cout <<
"Wrote \"" << tmp_output_file.str() <<
"\" in " << ( clock() - t ) / (
double)CLOCKS_PER_SEC
454 <<
" seconds" << std::endl;
456 #ifdef MOAB_HAVE_ZOLTAN
458 if( moab_use_zoltan && moab_partition_slave && p == 0 )
461 double master_radius, slave_radius;
462 if( rescale_spherical_radius )
468 EntityHandle mfrontback[2] = { masterverts[0], masterverts[masterverts.
size() - 1] };
470 const double mr1 = std::sqrt( points[0] * points[0] + points[1] * points[1] + points[2] * points[2] );
471 const double mr2 = std::sqrt( points[3] * points[3] + points[4] * points[4] + points[5] * points[5] );
472 master_radius = 0.5 * ( mr1 + mr2 );
477 if( rescale_spherical_radius )
482 EntityHandle sfrontback[2] = { slaveverts[0], slaveverts[slaveverts.
size() - 1] };
484 const double sr1 = std::sqrt( points[0] * points[0] + points[1] * points[1] + points[2] * points[2] );
485 const double sr2 = std::sqrt( points[3] * points[3] + points[4] * points[4] + points[5] * points[5] );
486 slave_radius = 0.5 * ( sr1 + sr2 );
493 if( rescale_spherical_radius )
501 std::cout <<
"Time taken to infer slave mesh partitions = " << ( clock() - t ) / (
double)CLOCKS_PER_SEC
502 <<
" seconds" << std::endl;
505 size_t lastindex = slave_file_name.find_last_of(
"." );
506 std::string inferred_output_file = slave_file_name.substr( 0, lastindex ) +
"_inferred" +
507 slave_file_name.substr( lastindex, slave_file_name.size() );
510 std::cout <<
"Saving inferred file to " << inferred_output_file <<
"..." << std::endl;
511 rval =
mb.
write_file( inferred_output_file.c_str(), 0, 0, &slaveset, 1 );
MB_CHK_SET_ERR( rval, inferred_output_file <<
" : failed to write file." << std::endl );
518 #ifdef MOAB_HAVE_ZOLTAN
521 #ifdef MOAB_HAVE_METIS
526 err = MPI_Finalize();
527 assert( MPI_SUCCESS == err );