<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 <NAME>, <NAME>, <NAME>

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA



// C++ Includes   -----------------------------------

// Local Includes -----------------------------------
#include "libmesh_config.h"
#include "mesh_base.h"
#include "parallel.h"    // also includes mpi.h
#include "mesh_serializer.h"
#include "mesh_tools.h"
#include "mesh_communication.h"
#include "parmetis_partitioner.h"
#include "metis_partitioner.h"
#include "libmesh_logging.h"
#include "elem.h"

#ifdef LIBMESH_HAVE_PARMETIS

// Include the ParMETIS header files
namespace Parmetis {
  extern "C" {
#     include "ignore_warnings.h"
#     include "parmetis.h"
#     include "restore_warnings.h"
  }
}

#endif // #ifdef LIBMESH_HAVE_PARMETIS ... else ...

namespace libMesh
{



// ------------------------------------------------------------
// ParmetisPartitioner implementation
void ParmetisPartitioner::_do_partition (MeshBase& mesh,
					 const unsigned int n_sbdmns)
{
  this->_do_repartition (mesh, n_sbdmns);

//   libmesh_assert (n_sbdmns > 0);

//   // Check for an easy return
//   if (n_sbdmns == 1)
//     {
//       this->single_partition (mesh);
//       return;
//     }

//   // This function must be run on all processors at once
//   parallel_only();

// // What to do if the Parmetis library IS NOT present
// #ifndef LIBMESH_HAVE_PARMETIS

//   libmesh_here();
//   libMesh::err << "ERROR: The library has been built without"  << std::endl
// 	    << "Parmetis support.  Using a Metis"           << std::endl
// 	    << "partitioner instead!"                       << std::endl;

//   MetisPartitioner mp;

//   mp.partition (mesh, n_sbdmns);

// // What to do if the Parmetis library IS present
// #else

//   START_LOG("partition()", "ParmetisPartitioner");

//   // Initialize the data structures required by ParMETIS
//   this->initialize (mesh, n_sbdmns);

//   // build the graph corresponding to the mesh
//   this->build_graph (mesh);


//   // Partition the graph
//   MPI_Comm mpi_comm = libMesh::COMM_WORLD;

//   // Call the ParMETIS k-way partitioning algorithm.
//   Parmetis::ParMETIS_V3_PartKway(&_vtxdist[0], &_xadj[0], &_adjncy[0], &_vwgt[0], NULL,
// 				 &_wgtflag, &_numflag, &_ncon, &_nparts, &_tpwgts[0],
// 				 &_ubvec[0], &_options[0], &_edgecut,
// 				 &_part[0],
// 				 &mpi_comm);

//   // Assign the returned processor ids
//   this->assign_partitioning (mesh);


//   STOP_LOG ("partition()", "ParmetisPartitioner");

// #endif // #ifndef LIBMESH_HAVE_PARMETIS ... else ...

}



void ParmetisPartitioner::_do_repartition (MeshBase& mesh,
					   const unsigned int n_sbdmns)
{
  libmesh_assert (n_sbdmns > 0);

  // Check for an easy return
  if (n_sbdmns == 1)
    {
      this->single_partition(mesh);
      return;
    }

  // This function must be run on all processors at once
  parallel_only();

// What to do if the Parmetis library IS NOT present
#ifndef LIBMESH_HAVE_PARMETIS

  libmesh_here();
  libMesh::err << "ERROR: The library has been built without"  << std::endl
	        << "Parmetis support.  Using a Metis"           << std::endl
	        << "partitioner instead!"                       << std::endl;

  MetisPartitioner mp;

  mp.partition (mesh, n_sbdmns);

// What to do if the Parmetis library IS present
#else

  // Revert to METIS on one processor.
  if (libMesh::n_processors() == 1)
    {
      MetisPartitioner mp;
      mp.partition (mesh, n_sbdmns);
      return;
    }

  START_LOG("repartition()", "ParmetisPartitioner");

  // Initialize the data structures required by ParMETIS
  this->initialize (mesh, n_sbdmns);

  // Make sure all processors have some active local elements.
  {
    bool all_have_active_elements = true;
    for (unsigned int pid=0; pid<_n_active_elem_on_proc.size(); pid++)
      if (!_n_active_elem_on_proc[pid]) all_have_active_elements = false;

    // Parmetis will not work unless each processor has some
    // elements. Specifically, it will abort when passed a NULL
    // partition array on *any* of the processors.
    if (!all_have_active_elements)
      {
	// FIXME: revert to METIS, although this requires a serial mesh
        MeshSerializer serialize(mesh);

	STOP_LOG ("repartition()", "ParmetisPartitioner");

	MetisPartitioner mp;
	mp.partition (mesh, n_sbdmns);

	return;
      }
  }

  // build the graph corresponding to the mesh
  this->build_graph (mesh);


  // Partition the graph
  std::vector<int> vsize(_vwgt.size(), 1);
  float itr = 1000000.0;
  MPI_Comm mpi_comm = libMesh::COMM_WORLD;

  // Call the ParMETIS adaptive repartitioning method.  This respects the
  // original partitioning when computing the new partitioning so as to
  // minimize the required data redistribution.
  Parmetis::ParMETIS_V3_AdaptiveRepart(_vtxdist.empty() ? NULL : &_vtxdist[0],
				       _xadj.empty()    ? NULL : &_xadj[0],
				       _adjncy.empty()  ? NULL : &_adjncy[0],
				       _vwgt.empty()    ? NULL : &_vwgt[0],
				       vsize.empty()    ? NULL : &vsize[0],
				       NULL,
				       &_wgtflag,
				       &_numflag,
				       &_ncon,
				       &_nparts,
				       _tpwgts.empty()  ? NULL : &_tpwgts[0],
				       _ubvec.empty()   ? NULL : &_ubvec[0],
				       &itr,
				       &_options[0],
				       &_edgecut,
				       _part.empty()    ? NULL : &_part[0],
				       &mpi_comm);

  // Assign the returned processor ids
  this->assign_partitioning (mesh);


  STOP_LOG ("repartition()", "ParmetisPartitioner");

#endif // #ifndef LIBMESH_HAVE_PARMETIS ... else ...

}



// Only need to compile these methods if ParMETIS is present
#ifdef LIBMESH_HAVE_PARMETIS

void ParmetisPartitioner::initialize (const MeshBase& mesh,
				      const unsigned int n_sbdmns)
{
  const unsigned int n_active_local_elem = mesh.n_active_local_elem();

  // Set parameters.
  _wgtflag = 2;                          // weights on vertices only
  _ncon    = 1;                          // one weight per vertex
  _numflag = 0;                          // C-style 0-based numbering
  _nparts  = static_cast<int>(n_sbdmns); // number of subdomains to create
  _edgecut = 0;                          // the numbers of edges cut by the
                                         //   partition

  // Initialize data structures for ParMETIS
  _vtxdist.resize (libMesh::n_processors()+1); std::fill (_vtxdist.begin(), _vtxdist.end(), 0);
  _tpwgts.resize  (_nparts);                   std::fill (_tpwgts.begin(),  _tpwgts.end(),  1./_nparts);
  _ubvec.resize   (_ncon);                     std::fill (_ubvec.begin(),   _ubvec.end(),   1.);
  _part.resize    (n_active_local_elem);       std::fill (_part.begin(),    _part.end(), 0);
  _options.resize (5);
  _vwgt.resize    (n_active_local_elem);

  // Set the options
  _options[0] = 1;  // don't use default options
  _options[1] = 0;  // default (level of timing)
  _options[2] = 15; // random seed (default)
  _options[3] = 2;  // processor distribution and subdomain distribution are decoupled

  // Find the number of active elements on each processor.  We cannot use
  // mesh.n_active_elem_on_proc(pid) since that only returns the number of
  // elements assigned to pid which are currently stored on the calling
  // processor. This will not in general be correct for parallel meshes
  // when (pid!=libMesh::processor_id()).
  _n_active_elem_on_proc.resize(libMesh::n_processors());
  Parallel::allgather(n_active_local_elem, _n_active_elem_on_proc);

  // count the total number of active elements in the mesh.  Note we cannot
  // use mesh.n_active_elem() in general since this only returns the number
  // of active elements which are stored on the calling processor.
  // We should not use n_active_elem for any allocation because that will
  // be inheritly unscalable, but it can be useful for libmesh_assertions.
  unsigned int n_active_elem=0;<commit_msg>Parmetis manual recommends 1.05 here, and newer parmetis gives an error with 1.0 or less<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 <NAME>, <NAME>, <NAME>

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA



// C++ Includes   -----------------------------------

// Local Includes -----------------------------------
#include "libmesh_config.h"
#include "mesh_base.h"
#include "parallel.h"    // also includes mpi.h
#include "mesh_serializer.h"
#include "mesh_tools.h"
#include "mesh_communication.h"
#include "parmetis_partitioner.h"
#include "metis_partitioner.h"
#include "libmesh_logging.h"
#include "elem.h"

#ifdef LIBMESH_HAVE_PARMETIS

// Include the ParMETIS header files
namespace Parmetis {
  extern "C" {
#     include "ignore_warnings.h"
#     include "parmetis.h"
#     include "restore_warnings.h"
  }
}

#endif // #ifdef LIBMESH_HAVE_PARMETIS ... else ...

namespace libMesh
{



// ------------------------------------------------------------
// ParmetisPartitioner implementation
void ParmetisPartitioner::_do_partition (MeshBase& mesh,
					 const unsigned int n_sbdmns)
{
  this->_do_repartition (mesh, n_sbdmns);

//   libmesh_assert (n_sbdmns > 0);

//   // Check for an easy return
//   if (n_sbdmns == 1)
//     {
//       this->single_partition (mesh);
//       return;
//     }

//   // This function must be run on all processors at once
//   parallel_only();

// // What to do if the Parmetis library IS NOT present
// #ifndef LIBMESH_HAVE_PARMETIS

//   libmesh_here();
//   libMesh::err << "ERROR: The library has been built without"  << std::endl
// 	    << "Parmetis support.  Using a Metis"           << std::endl
// 	    << "partitioner instead!"                       << std::endl;

//   MetisPartitioner mp;

//   mp.partition (mesh, n_sbdmns);

// // What to do if the Parmetis library IS present
// #else

//   START_LOG("partition()", "ParmetisPartitioner");

//   // Initialize the data structures required by ParMETIS
//   this->initialize (mesh, n_sbdmns);

//   // build the graph corresponding to the mesh
//   this->build_graph (mesh);


//   // Partition the graph
//   MPI_Comm mpi_comm = libMesh::COMM_WORLD;

//   // Call the ParMETIS k-way partitioning algorithm.
//   Parmetis::ParMETIS_V3_PartKway(&_vtxdist[0], &_xadj[0], &_adjncy[0], &_vwgt[0], NULL,
// 				 &_wgtflag, &_numflag, &_ncon, &_nparts, &_tpwgts[0],
// 				 &_ubvec[0], &_options[0], &_edgecut,
// 				 &_part[0],
// 				 &mpi_comm);

//   // Assign the returned processor ids
//   this->assign_partitioning (mesh);


//   STOP_LOG ("partition()", "ParmetisPartitioner");

// #endif // #ifndef LIBMESH_HAVE_PARMETIS ... else ...

}



void ParmetisPartitioner::_do_repartition (MeshBase& mesh,
					   const unsigned int n_sbdmns)
{
  libmesh_assert (n_sbdmns > 0);

  // Check for an easy return
  if (n_sbdmns == 1)
    {
      this->single_partition(mesh);
      return;
    }

  // This function must be run on all processors at once
  parallel_only();

// What to do if the Parmetis library IS NOT present
#ifndef LIBMESH_HAVE_PARMETIS

  libmesh_here();
  libMesh::err << "ERROR: The library has been built without"  << std::endl
	        << "Parmetis support.  Using a Metis"           << std::endl
	        << "partitioner instead!"                       << std::endl;

  MetisPartitioner mp;

  mp.partition (mesh, n_sbdmns);

// What to do if the Parmetis library IS present
#else

  // Revert to METIS on one processor.
  if (libMesh::n_processors() == 1)
    {
      MetisPartitioner mp;
      mp.partition (mesh, n_sbdmns);
      return;
    }

  START_LOG("repartition()", "ParmetisPartitioner");

  // Initialize the data structures required by ParMETIS
  this->initialize (mesh, n_sbdmns);

  // Make sure all processors have some active local elements.
  {
    bool all_have_active_elements = true;
    for (unsigned int pid=0; pid<_n_active_elem_on_proc.size(); pid++)
      if (!_n_active_elem_on_proc[pid]) all_have_active_elements = false;

    // Parmetis will not work unless each processor has some
    // elements. Specifically, it will abort when passed a NULL
    // partition array on *any* of the processors.
    if (!all_have_active_elements)
      {
	// FIXME: revert to METIS, although this requires a serial mesh
        MeshSerializer serialize(mesh);

	STOP_LOG ("repartition()", "ParmetisPartitioner");

	MetisPartitioner mp;
	mp.partition (mesh, n_sbdmns);

	return;
      }
  }

  // build the graph corresponding to the mesh
  this->build_graph (mesh);


  // Partition the graph
  std::vector<int> vsize(_vwgt.size(), 1);
  float itr = 1000000.0;
  MPI_Comm mpi_comm = libMesh::COMM_WORLD;

  // Call the ParMETIS adaptive repartitioning method.  This respects the
  // original partitioning when computing the new partitioning so as to
  // minimize the required data redistribution.
  Parmetis::ParMETIS_V3_AdaptiveRepart(_vtxdist.empty() ? NULL : &_vtxdist[0],
				       _xadj.empty()    ? NULL : &_xadj[0],
				       _adjncy.empty()  ? NULL : &_adjncy[0],
				       _vwgt.empty()    ? NULL : &_vwgt[0],
				       vsize.empty()    ? NULL : &vsize[0],
				       NULL,
				       &_wgtflag,
				       &_numflag,
				       &_ncon,
				       &_nparts,
				       _tpwgts.empty()  ? NULL : &_tpwgts[0],
				       _ubvec.empty()   ? NULL : &_ubvec[0],
				       &itr,
				       &_options[0],
				       &_edgecut,
				       _part.empty()    ? NULL : &_part[0],
				       &mpi_comm);

  // Assign the returned processor ids
  this->assign_partitioning (mesh);


  STOP_LOG ("repartition()", "ParmetisPartitioner");

#endif // #ifndef LIBMESH_HAVE_PARMETIS ... else ...

}



// Only need to compile these methods if ParMETIS is present
#ifdef LIBMESH_HAVE_PARMETIS

void ParmetisPartitioner::initialize (const MeshBase& mesh,
				      const unsigned int n_sbdmns)
{
  const unsigned int n_active_local_elem = mesh.n_active_local_elem();

  // Set parameters.
  _wgtflag = 2;                          // weights on vertices only
  _ncon    = 1;                          // one weight per vertex
  _numflag = 0;                          // C-style 0-based numbering
  _nparts  = static_cast<int>(n_sbdmns); // number of subdomains to create
  _edgecut = 0;                          // the numbers of edges cut by the
                                         //   partition

  // Initialize data structures for ParMETIS
  _vtxdist.resize (libMesh::n_processors()+1); std::fill (_vtxdist.begin(), _vtxdist.end(), 0);
  _tpwgts.resize  (_nparts);                   std::fill (_tpwgts.begin(),  _tpwgts.end(),  1./_nparts);
  _ubvec.resize   (_ncon);                     std::fill (_ubvec.begin(),   _ubvec.end(),   1.05);
  _part.resize    (n_active_local_elem);       std::fill (_part.begin(),    _part.end(), 0);
  _options.resize (5);
  _vwgt.resize    (n_active_local_elem);

  // Set the options
  _options[0] = 1;  // don't use default options
  _options[1] = 0;  // default (level of timing)
  _options[2] = 15; // random seed (default)
  _options[3] = 2;  // processor distribution and subdomain distribution are decoupled

  // Find the number of active elements on each processor.  We cannot use
  // mesh.n_active_elem_on_proc(pid) since that only returns the number of
  // elements assigned to pid which are currently stored on the calling
  // processor. This will not in general be correct for parallel meshes
  // when (pid!=libMesh::processor_id()).
  _n_active_elem_on_proc.resize(libMesh::n_processors());
  Parallel::allgather(n_active_local_elem, _n_active_elem_on_proc);

  // count the total number of active elements in the mesh.  Note we cannot
  // use mesh.n_active_elem() in general since this only returns the number
  // of active elements which are stored on the calling processor.
  // We should not use n_active_elem for any allocation because that will
  // be inheritly unscalable, but it can be useful for libmesh_assertions.
  unsigned int n_active_elem=0;
{'fraction_non_alphanumeric': 0.12733800451676414, 'fraction_numerical': 0.009554693381203311, 'mean_word_length': 2.607687486943806, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '246218', 'n_tokens_mistral': 5879, 'n_tokens_neox': 5409, 'n_words': 1655}