// Copyright (c) 2017 GeometryFactory (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); 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 3 of the License, // or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0+ // // Author(s) : Mael Rouxel-Labbé #ifndef CGAL_BGL_PARTITION_GRAPH_H #define CGAL_BGL_PARTITION_GRAPH_H #include #include #include #include #include #include #include #include #include #include namespace CGAL { namespace METIS { struct Output_vertex_partition_ids { template void operator()(const TriangleMesh&, const Indices, idx_t const * const, internal_np::Param_not_found) { } template void operator()(const TriangleMesh& tm, const Indices indices, idx_t const * const npart, VertexPartitionIDPmap vertex_partition_id_map) { typename boost::graph_traits::vertex_iterator vit, ve; boost::tie(vit, ve) = vertices(tm); for(; vit!=ve; ++vit) put(vertex_partition_id_map, *vit, npart[get(indices, *vit)]); } }; struct Output_face_partition_ids { template void operator()(const TriangleMesh&, idx_t const * const, internal_np::Param_not_found) { } template void operator()(const TriangleMesh& tm, idx_t const * const epart, FacePartitionIDPmap face_partition_id_map) { typename boost::graph_traits::face_iterator fit, fe; boost::tie(fit, fe) = faces(tm); for(int i=0; fit!=fe; ++fit, ++i) put(face_partition_id_map, *fit, epart[i]); } }; template void partition_graph(const TriangleMesh& tm, int nparts, METIS_options options, // pointer to the options array const NamedParameters& np) { CGAL_precondition(CGAL::is_triangle_mesh(tm)); CGAL_precondition_msg(nparts > 1, ("Partitioning requires a number of parts > 1")); using parameters::choose_parameter; using parameters::get_parameter; typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; typedef typename boost::graph_traits::face_iterator face_iterator; //Vertex index map typedef typename CGAL::Polygon_mesh_processing::GetVertexIndexMap::type Indices; Indices indices = choose_parameter(get_parameter(np, internal_np::vertex_index), get_const_property_map(boost::vertex_index, tm)); idx_t nn = static_cast(num_vertices(tm)); idx_t ne = static_cast(num_faces(tm)); idx_t d = 3; // number of nodes per element idx_t* eptr = new idx_t[ne + 1]; idx_t* eind = new idx_t[d * ne]; // fill the adjacency info face_iterator fit, fe; boost::tie(fit, fe) = faces(tm); for(int i=0, j=0; fit!=fe; ++fit, ++i) { eptr[i] = j; halfedge_descriptor h = halfedge(*fit, tm), done = h; do { vertex_descriptor v = target(h, tm); CGAL_assertion(j < d * ne); eind[j++] = static_cast(get(indices, v)); h = next(h, tm); } while (h != done); CGAL_assertion(i < ne); eptr[i + 1] = j; } // either the edgecut or the total communication volume of the dual graph’s partitioning idx_t objval; // partition info for the nodes idx_t* npart = (idx_t*) calloc(num_vertices(tm), sizeof(idx_t)); CGAL_assertion(npart != NULL); // partition info for the elements idx_t* epart = (idx_t*) calloc(num_faces(tm), sizeof(idx_t)); CGAL_assertion(epart != NULL); // do not support Fortran-style arrays CGAL_assertion((*options)[METIS_OPTION_NUMBERING] == -1 || // default initialization is '-1' (*options)[METIS_OPTION_NUMBERING] == 0); CGAL_assertion_code(int ret =) METIS_PartMeshNodal(&ne, &nn, eptr, eind, NULL /* nodes weights */, NULL /* nodes sizes */, &nparts, NULL /* partitions weights */, *options, &objval, epart, npart); CGAL_assertion(ret == METIS_OK); Output_vertex_partition_ids vo; Output_face_partition_ids fo; vo(tm, indices, npart, get_parameter(np, internal_np::vertex_partition_id)); fo(tm, epart, get_parameter(np, internal_np::face_partition_id)); delete[] eptr; delete[] eind; std::free(npart); std::free(epart); } template void partition_graph(const TriangleMesh& tm, int nparts, const internal_np::Param_not_found, // no METIS options were passed const NamedParameters& np) { idx_t options[METIS_NOPTIONS]; METIS_SetDefaultOptions(options); return partition_graph(tm, nparts, &options, np); } /// \ingroup PkgBGLPartition /// /// Computes a partition of the input triangular mesh into `nparts` parts, based on the /// mesh's nodal graph. The resulting partition is stored in the vertex and/or face /// property maps that are passed as parameters using \ref bgl_namedparameters "Named Parameters". /// /// Property map for `CGAL::vertex_index_t` should be either available /// as an internal property map to `tm` or provided as \ref bgl_namedparameters "Named Parameters". /// /// \param tm a triangle mesh /// \param nparts the number of parts in the final partition /// \param np optional \ref bgl_namedparameters "Named Parameters" described below /// /// \tparam TriangleMesh is a model of the `FaceListGraph` concept. /// \tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" /// /// \cgalNamedParamsBegin /// \cgalParamBegin{vertex_index_map} /// is a property map containing the index of each vertex of `tm` intialized from `0` to `num_vertices(tm)-1`. /// \cgalParamEnd /// \cgalParamBegin{METIS_options} /// is a parameter used in to pass options to the METIS mesh /// partitioner. The many options of METIS are not described here. Instead, users /// should refer to the documentation /// of METIS directly. /// \cgalParamEnd /// \cgalParamBegin{vertex_partition_id_map} /// is a property map that contains (after the function has been run) /// the ID of the subpart for each vertex of `tm`. /// \cgalParamEnd /// \cgalParamBegin{face_partition_id_map} /// is a property map that contains (after the function has been run) /// the ID of the subpart for each face of `tm`. /// \cgalParamEnd /// \cgalNamedParamsEnd /// /// \pre `tm` is a pure triangular surface mesh: there are no edges /// without at least one incident face template void partition_graph(const TriangleMesh& tm, int nparts, const NamedParameters& np) { using parameters::get_parameter; return partition_graph(tm, nparts, get_parameter(np, internal_np::METIS_options), np); } template void partition_graph(const TriangleMesh& tm, const int nparts) { return partition_graph(tm, nparts, CGAL::parameters::all_default()); } } // end namespace METIS } // end namespace CGAL #endif // CGAL_BGL_PARTITION_GRAPH_H