Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
mbpart.cpp File Reference
#include "moab/Core.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/ReorderTool.hpp"
#include <iostream>
#include <sstream>
#include <cmath>
#include <cstdlib>
#include <list>
#include <ctime>
#include "moab/IntxMesh/IntxUtils.hpp"
+ Include dependency graph for mbpart.cpp:

Go to the source code of this file.

Typedefs

typedef int PartType
 

Functions

int main (int argc, char *argv[])
 

Variables

std::string DEFAULT_TAGGEDSETS_TAG = "PARALLEL_PARTITION"
 
const char DEFAULT_ZOLTAN_METHOD [] = "RCB"
 
const char METIS_DEFAULT_METHOD [] = "ML_KWAY"
 
const char BRIEF_DESC [] = "Use Zoltan or Metis to partition MOAB meshes for use on parallel computers"
 
std::ostringstream LONG_DESC
 

Typedef Documentation

◆ PartType

typedef int PartType

Definition at line 18 of file mbpart.cpp.

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 46 of file mbpart.cpp.

47 { 48 #ifdef MOAB_HAVE_MPI 49  int err = MPI_Init( &argc, &argv ); 50  if( err ) 51  { 52  std::cerr << "MPI_Init failed. Aborting." << std::endl; 53  return 3; 54  } 55 #endif 56  Core moab; 57  Interface& mb = moab; 58  std::vector< int > set_l; 59  60 #ifdef MOAB_HAVE_ZOLTAN 61  bool moab_use_zoltan = false; 62 #endif 63 #ifdef MOAB_HAVE_METIS 64  bool moab_use_metis = false; 65 #endif 66  67  LONG_DESC << "This utility invokes the ZoltanPartitioner or MetisPartitioner component of MOAB" 68  "to partition a mesh/geometry." 69  << std::endl 70  << "If no partitioning method is specified, the defaults are: " 71  << "for Zoltan=\"" << DEFAULT_ZOLTAN_METHOD << "\" and Metis=\"" << METIS_DEFAULT_METHOD << " method" 72  << std::endl; 73  74  ProgOptions opts( LONG_DESC.str(), BRIEF_DESC ); 75  76  int part_dim = 3; 77  opts.addOpt< int >( "dimension", 78  "Specify dimension of entities to partition." 79  " Default is largest in file.", 80  &part_dim, ProgOptions::int_flag ); 81  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 " 87  "are synonymous).", 88  &zoltan_method ); 89 #ifdef MOAB_HAVE_PARMETIS 90  opts.addOpt< std::string >( "parmetis,p", "(Zoltan+PARMetis) Specify PARMetis partition method.", &parm_method ); 91 #endif // MOAB_HAVE_PARMETIS 92  opts.addOpt< std::string >( "octpart,o", "(Zoltan) Specify OctPart partition method.", &oct_method ); 93  94  bool incl_closure = false; 95  opts.addOpt< void >( "include_closure,c", "Include element closure for part sets.", &incl_closure ); 96  97  bool recompute_box_rcb = false; 98  opts.addOpt< void >( "recompute_rcb_box,b", "recompute box in rcb cuts", &recompute_box_rcb ); 99 #endif // MOAB_HAVE_ZOLTAN 100  101  double imbal_tol = 1.03; 102  opts.addOpt< double >( "imbalance,i", "Imbalance tolerance (used in PHG/Hypergraph method)", &imbal_tol ); 103  104 #ifdef MOAB_HAVE_METIS 105  opts.addOpt< std::string >( "metis,m", "(Metis) Specify Metis partition method. One of ML_RB or ML_KWAY.", 106  &metis_method ); 107 #endif // MOAB_HAVE_METIS 108  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 ); 112  113  int power = -1; 114  opts.addOpt< int >( "power,M", "Generate multiple partitions, in powers of 2, up to 2^(pow)", &power ); 115  116  bool reorder = false; 117  opts.addOpt< void >( "reorder,R", "Reorder mesh to group entities by partition", &reorder ); 118  119  double part_geom_mesh_size = -1.0; 120 #ifdef MOAB_HAVE_ZOLTAN 121  int obj_weight = 0; 122  opts.addOpt< int >( "vertex_w,v", "(Zoltan) Number of weights associated with a graph vertex." ); 123  124  int edge_weight = 0; 125  opts.addOpt< int >( "edge_w,e", "(Zoltan) Number of weights associated with an edge." ); 126  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.", 132  &slave_file_name ); 133  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 ); 139  140 #endif // MOAB_HAVE_ZOLTAN 141  142  long num_parts; 143  opts.addOpt< std::vector< int > >( "set_l,l", 144  "Load material set(s) with specified ids (comma separated) for partition" ); 145  146  opts.addRequiredArg< int >( "#parts", "Number of parts in partition" ); 147  148  std::string input_file, output_file; 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", 151  &output_file ); 152  153  bool print_time = false; 154  opts.addOpt< void >( ",T", "Print CPU time for each phase.", &print_time ); 155  156  int projection_type = 0; 157  opts.addOpt< int >( "project_on_sphere,p", 158  "use spherical coordinates (1) or gnomonic projection (2) for partitioning ", 159  &projection_type ); 160 #ifdef MOAB_HAVE_METIS 161  bool partition_tagged_sets = false; 162  opts.addOpt< void >( "taggedsets,x", "(Metis) Partition tagged sets.", &partition_tagged_sets ); 163  164  bool partition_tagged_ents = false; 165  opts.addOpt< void >( "taggedents,y", "(Metis) Partition tagged ents.", &partition_tagged_ents ); 166  167  std::string aggregating_tag; 168  opts.addOpt< std::string >( "aggregatingtag,a", 169  "(Metis) Specify aggregating tag to partion tagged sets or tagged entities.", 170  &aggregating_tag ); 171  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 ); 176  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 ", 183  &boundaryIds ); 184 #endif // MOAB_HAVE_METIS 185  186  bool assign_global_ids = false; 187  opts.addOpt< void >( "globalIds,j", "Assign GLOBAL_ID tag to entities", &assign_global_ids ); 188  189  opts.parseCommandLine( argc, argv ); 190  191 #ifdef MOAB_HAVE_ZOLTAN 192  if( !zoltan_method.empty() ) 193  moab_use_zoltan = true; 194  else 195 #endif 196 #ifdef MOAB_HAVE_METIS 197  if( !metis_method.empty() ) 198  moab_use_metis = true; 199  else 200 #endif 201  MB_SET_ERR( MB_FAILURE, "Specify either Zoltan or Metis partitioner type" ); 202  203 #ifdef MOAB_HAVE_ZOLTAN 204  ZoltanPartitioner* zoltan_tool = NULL; 205  // check if partition geometry, if it is, should get mesh size for the geometry 206  if( part_geom_mesh_size != -1.0 && part_geom_mesh_size <= 0.0 ) 207  { 208  std::cerr << part_geom_mesh_size << ": invalid geometry partition mesh size." << std::endl << std::endl; 209  opts.printHelp(); 210  return EXIT_FAILURE; 211  } 212  213  if( slave_file_name.size() ) moab_partition_slave = true; 214  215  if( moab_use_zoltan ) 216  { 217  if( part_geom_mesh_size < 0. ) 218  { 219  // partition mesh we have no ParallelComm here, so we will create one later 220  zoltan_tool = new ZoltanPartitioner( &mb, NULL, false, argc, argv ); 221  } 222  else 223  { 224  // partition geometry 225  MB_CHK_SET_ERR( MB_FAILURE, "Geometry will not be partitioned.\n" ); 226  } 227  zoltan_tool->set_global_id_option( assign_global_ids ); 228  } 229  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; 233 #endif // MOAB_HAVE_ZOLTAN 234  235 #ifdef MOAB_HAVE_METIS 236  MetisPartitioner* metis_tool = NULL; 237  if( moab_use_metis && !metis_tool ) 238  { 239  metis_tool = new MetisPartitioner( &mb, false ); 240  metis_tool->set_global_id_option( assign_global_ids ); 241  } 242  243  if( ( aggregating_tag.empty() && partition_tagged_sets ) || ( aggregating_tag.empty() && partition_tagged_ents ) ) 244  aggregating_tag = DEFAULT_TAGGEDSETS_TAG; 245  if( !write_sets && !write_tags ) write_sets = true; 246  247  if( !boundaryIds.empty() ) 248  { 249  std::vector< std::string > ids; 250  std::stringstream ss( boundaryIds ); 251  std::string item; 252  while( std::getline( ss, item, ',' ) ) 253  { 254  ids.push_back( item ); 255  } 256  for( unsigned int i = 0; i < ids.size(); i++ ) 257  BCids.push_back( std::atoi( ids[i].c_str() ) ); 258  } 259  260  if( metis_method.empty() ) 261  { 262  metis_method = METIS_DEFAULT_METHOD; 263  } 264  265 #endif // MOAB_HAVE_METIS 266  267  if( !write_sets && !write_tags ) write_sets = true; 268  269  if( -1 == power ) 270  { 271  num_parts = opts.getReqArg< int >( "#parts" ); 272  power = 1; 273  } 274  else if( power < 1 || power > 18 ) 275  { 276  std::cerr << power << ": invalid power for multiple partitions. Expected value in [1,18]" << std::endl 277  << std::endl; 278  opts.printHelp(); 279  return EXIT_FAILURE; 280  } 281  else 282  { 283  num_parts = 2; 284  } 285  286  if( part_dim < 0 || part_dim > 3 ) 287  { 288  std::cerr << part_dim << " : invalid dimension" << std::endl << std::endl; 289  opts.printHelp(); 290  return EXIT_FAILURE; 291  } 292  293  if( imbal_tol < 0.0 ) 294  { 295  std::cerr << imbal_tol << ": invalid imbalance tolerance" << std::endl << std::endl; 296  opts.printHelp(); 297  return EXIT_FAILURE; 298  } 299  300  bool load_msets = false; 301  if( opts.getOpt( "set_l,l", &set_l ) ) 302  { 303  load_msets = true; 304  if( set_l.size() <= 0 ) 305  { 306  std::cerr << " No material set id's to load" << std::endl << std::endl; 307  opts.printHelp(); 308  return EXIT_FAILURE; 309  } 310  } 311  312  if( num_parts <= 1 ) 313  { 314  std::cerr << "** Please specify #parts = " << num_parts << " to be greater than 1." << std::endl << std::endl; 315  opts.printHelp(); 316  return EXIT_FAILURE; 317  } 318  319  clock_t t = clock(); 320  321  const char* options = NULL; 322  ErrorCode rval; 323 #ifdef MOAB_HAVE_ZOLTAN 324  if( part_geom_mesh_size > 0. ) options = "FACET_DISTANCE_TOLERANCE=0.1"; 325 #endif // MOAB_HAVE_ZOLTAN 326  327  std::cout << "Loading file " << input_file << "..." << std::endl; 328  if( load_msets == false ) 329  { 330  rval = mb.load_file( input_file.c_str(), 0, options );MB_CHK_SET_ERR( rval, "Failed to load input file: " + input_file ); 331  } 332  else // load the material set(s) 333  { 334  rval = mb.load_mesh( input_file.c_str(), &set_l[0], (int)set_l.size() );MB_CHK_SET_ERR( rval, "Failed to load input mesh: " + input_file ); 335  } 336  if( print_time ) 337  std::cout << "Read input file in " << ( clock() - t ) / (double)CLOCKS_PER_SEC << " seconds" << std::endl; 338  339  for( int dim = part_dim; dim >= 0; --dim ) 340  { 341  int n; 342  rval = mb.get_number_entities_by_dimension( 0, dim, n ); 343  if( MB_SUCCESS == rval && 0 != n ) 344  { 345  part_dim = dim; 346  break; 347  } 348  } 349  if( part_dim < 0 ) 350  { 351  std::cerr << input_file << " : file does not contain any mesh entities" << std::endl; 352  return 2; 353  } 354  355  ReorderTool reorder_tool( &moab ); 356  357  for( int p = 0; p < power; p++ ) 358  { 359  t = clock(); 360 #ifdef MOAB_HAVE_ZOLTAN 361  if( moab_use_zoltan ) 362  { 363  rval = zoltan_tool->partition_mesh_and_geometry( 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." ); 367  } 368 #endif 369 #ifdef MOAB_HAVE_METIS 370  if( moab_use_metis ) 371  { 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(), 374  print_time );MB_CHK_SET_ERR( rval, "Metis partitioner failed." ); 375  } 376 #endif 377  378  if( print_time ) 379  std::cout << "Generated " << num_parts << " part partitioning in " 380  << ( clock() - t ) / (double)CLOCKS_PER_SEC << " seconds" << std::endl; 381  382  if( reorder && part_geom_mesh_size < 0. ) 383  { 384  std::cout << "Reordering mesh for partition..." << std::endl; 385  386  Tag tag, order; 387  rval = mb.tag_get_handle( DEFAULT_TAGGEDSETS_TAG.c_str(), 1, MB_TYPE_INTEGER, tag );MB_CHK_SET_ERR( rval, "Partitioner did not create " + DEFAULT_TAGGEDSETS_TAG + " tag" ); 388  389  t = clock(); 390  if( write_sets ) 391  { 392  Range sets; 393  mb.get_entities_by_type_and_tag( 0, MBENTITYSET, &tag, 0, 1, sets ); 394  rval = reorder_tool.handle_order_from_sets_and_adj( sets, order );MB_CHK_SET_ERR( rval, "Failed to calculate reordering." ); 395  } 396  else 397  { 398  rval = reorder_tool.handle_order_from_int_tag( tag, -1, order );MB_CHK_SET_ERR( rval, "Failed to calculate reordering." ); 399  } 400  401  rval = reorder_tool.reorder_entities( order );MB_CHK_SET_ERR( rval, "Failed to perform reordering." ); 402  403  rval = mb.tag_delete( order );MB_CHK_SET_ERR( rval, "Failed to delete tag." ); 404  if( print_time ) 405  std::cout << "Reordered mesh in " << ( clock() - t ) / (double)CLOCKS_PER_SEC << " seconds" 406  << std::endl; 407  } 408  409 #ifdef MOAB_HAVE_ZOLTAN 410  if( incl_closure ) 411  { 412  rval = zoltan_tool->include_closure();MB_CHK_SET_ERR( rval, "Closure inclusion failed." ); 413  } 414 #endif 415  416  std::ostringstream tmp_output_file; 417  418  if( power > 1 ) 419  { 420  // append num_parts to output filename 421  std::string::size_type idx = output_file.find_last_of( "." ); 422  if( idx == std::string::npos ) 423  { 424  tmp_output_file << output_file << "_" << num_parts; 425  if( part_geom_mesh_size < 0. ) 426  tmp_output_file << ".h5m"; 427  else 428  { 429  std::cerr << "output file type is not specified." << std::endl; 430  return 1; 431  } 432  } 433  else 434  { 435  tmp_output_file << output_file.substr( 0, idx ) << "_" << num_parts << output_file.substr( idx ); 436  } 437  } 438  else 439  tmp_output_file << output_file; 440  441  t = clock(); 442  std::cout << "Saving file to " << output_file << "..." << std::endl; 443  if( part_geom_mesh_size < 0. ) 444  { 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 ); 446  } 447  else 448  { 449  MB_CHK_SET_ERR( MB_FAILURE, "Geometry will not be partitioned.\n" ); 450  } 451  452  if( print_time ) 453  std::cout << "Wrote \"" << tmp_output_file.str() << "\" in " << ( clock() - t ) / (double)CLOCKS_PER_SEC 454  << " seconds" << std::endl; 455  456 #ifdef MOAB_HAVE_ZOLTAN 457  458  if( moab_use_zoltan && moab_partition_slave && p == 0 ) 459  { 460  t = clock(); 461  double master_radius, slave_radius; 462  if( rescale_spherical_radius ) 463  { 464  EntityHandle rootset = 0; 465  Range masterverts; 466  rval = mb.get_entities_by_dimension( rootset, 0, masterverts );MB_CHK_SET_ERR( rval, "Can't create vertices on master set" ); 467  double points[6]; 468  EntityHandle mfrontback[2] = { masterverts[0], masterverts[masterverts.size() - 1] }; 469  rval = mb.get_coords( &mfrontback[0], 2, points );MB_CHK_ERR( rval ); 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 ); 473  } 474  EntityHandle slaveset; 475  rval = mb.create_meshset( moab::MESHSET_SET, slaveset );MB_CHK_SET_ERR( rval, "Can't create new set" ); 476  rval = mb.load_file( slave_file_name.c_str(), &slaveset, options );MB_CHK_SET_ERR( rval, "Can't load slave mesh" ); 477  if( rescale_spherical_radius ) 478  { 479  double points[6]; 480  Range slaveverts; 481  rval = mb.get_entities_by_dimension( slaveset, 0, slaveverts );MB_CHK_SET_ERR( rval, "Can't create vertices on master set" ); 482  EntityHandle sfrontback[2] = { slaveverts[0], slaveverts[slaveverts.size() - 1] }; 483  rval = mb.get_coords( &sfrontback[0], 2, points );MB_CHK_ERR( rval ); 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 ); 487  // Let us rescale both master and slave meshes to a unit sphere 488  rval = moab::IntxUtils::ScaleToRadius( &mb, slaveset, master_radius );MB_CHK_ERR( rval ); 489  } 490  491  rval = zoltan_tool->partition_inferred_mesh( slaveset, num_parts, part_dim, write_sets, projection_type );MB_CHK_ERR( rval ); 492  493  if( rescale_spherical_radius ) 494  { 495  // rescale the slave mesh back to its original radius 496  rval = moab::IntxUtils::ScaleToRadius( &mb, slaveset, slave_radius );MB_CHK_ERR( rval ); 497  } 498  499  if( print_time ) 500  { 501  std::cout << "Time taken to infer slave mesh partitions = " << ( clock() - t ) / (double)CLOCKS_PER_SEC 502  << " seconds" << std::endl; 503  } 504  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() ); 508  509  // Save the resulting mesh 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 ); 512  } 513 #endif 514  515  num_parts *= 2; 516  } 517  518 #ifdef MOAB_HAVE_ZOLTAN 519  delete zoltan_tool; 520 #endif 521 #ifdef MOAB_HAVE_METIS 522  delete metis_tool; 523 #endif 524  525 #ifdef MOAB_HAVE_MPI 526  err = MPI_Finalize(); 527  assert( MPI_SUCCESS == err ); 528 #endif 529  return 0; 530 }

References ProgOptions::addOpt(), ProgOptions::addRequiredArg(), BRIEF_DESC, moab::Core::create_meshset(), DEFAULT_TAGGEDSETS_TAG, DEFAULT_ZOLTAN_METHOD, dim, ErrorCode, moab::Core::get_coords(), moab::Core::get_entities_by_dimension(), moab::Core::get_entities_by_type_and_tag(), moab::Core::get_number_entities_by_dimension(), ProgOptions::getOpt(), ProgOptions::getReqArg(), moab::ReorderTool::handle_order_from_int_tag(), moab::ReorderTool::handle_order_from_sets_and_adj(), ZoltanPartitioner::include_closure(), input_file, ProgOptions::int_flag, moab::Core::load_file(), moab::Core::load_mesh(), LONG_DESC, mb, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MB_TYPE_INTEGER, MBENTITYSET, MESHSET_SET, METIS_DEFAULT_METHOD, ProgOptions::parseCommandLine(), ZoltanPartitioner::partition_inferred_mesh(), MetisPartitioner::partition_mesh(), ZoltanPartitioner::partition_mesh_and_geometry(), print_time(), ProgOptions::printHelp(), moab::ReorderTool::reorder_entities(), moab::IntxUtils::ScaleToRadius(), PartitionerBase< T >::set_global_id_option(), moab::Range::size(), moab::Core::tag_delete(), moab::Core::tag_get_handle(), and moab::Core::write_file().

Variable Documentation

◆ BRIEF_DESC

const char BRIEF_DESC[] = "Use Zoltan or Metis to partition MOAB meshes for use on parallel computers"

Definition at line 43 of file mbpart.cpp.

Referenced by main().

◆ DEFAULT_TAGGEDSETS_TAG

std::string DEFAULT_TAGGEDSETS_TAG = "PARALLEL_PARTITION"

Definition at line 32 of file mbpart.cpp.

Referenced by main().

◆ DEFAULT_ZOLTAN_METHOD

const char DEFAULT_ZOLTAN_METHOD[] = "RCB"

Definition at line 34 of file mbpart.cpp.

Referenced by main().

◆ LONG_DESC

std::ostringstream LONG_DESC

Definition at line 44 of file mbpart.cpp.

Referenced by main().

◆ METIS_DEFAULT_METHOD

const char METIS_DEFAULT_METHOD[] = "ML_KWAY"

Definition at line 40 of file mbpart.cpp.

Referenced by main().