https://mooseframework.inl.gov
Loading...
Searching...
No Matches
PetscExternalPartitioner.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11
12#include "GeneratedMesh.h"
13#include "MooseApp.h"
14
15#include "libmesh/mesh_tools.h"
16#include "libmesh/linear_partitioner.h"
17#include "libmesh/elem.h"
18#include "libmesh/mesh_base.h"
19#include "libmesh/petsc_solver_exception.h"
20
22
23#include <memory>
24
27{
29
30 MooseEnum partPackage("parmetis ptscotch chaco party hierarch", "parmetis", false);
31
32 params.addParam<MooseEnum>("part_package",
33 partPackage,
34 "The external package is used for partitioning the mesh via PETSc");
35
36 params.addParam<processor_id_type>(
37 "num_cores_per_compute_node",
38 1,
39 "Number of cores per compute node for hierarchical partitioning");
40
41 params.addParam<bool>("apply_element_weight",
42 false,
43 "Indicate if we are going to apply element weights to partitioners");
44
45 params.addParam<bool>(
46 "apply_side_weight", false, "Indicate if we are going to apply side weights to partitioners");
47
49 "Partition mesh using external packages via PETSc MatPartitioning interface");
50
51 return params;
52}
53
55 : MoosePartitioner(params),
56 _part_package(params.get<MooseEnum>("part_package")),
57 _apply_element_weight(params.get<bool>("apply_element_weight")),
58 _apply_side_weight(params.get<bool>("apply_side_weight")),
59 _num_parts_per_compute_node(params.get<processor_id_type>("num_cores_per_compute_node"))
60{
62 (_part_package == "chaco" || _part_package == "party"))
63 mooseError(_part_package, " does not support weighted graph");
64}
65
66std::unique_ptr<Partitioner>
68{
69 return _app.getFactory().clone(*this);
70}
71
72void
74{
75 // Temporarily cache the old partition method
76 auto old_partitioner = std::move(mesh.partitioner());
77 // Create a linear partitioner
78 mesh.partitioner() = std::make_unique<libMesh::LinearPartitioner>();
79 // Partition mesh
80 mesh.partition(n_processors());
81 // Restore the old partition
82 mesh.partitioner() = std::move(old_partitioner);
83}
84
85void
86PetscExternalPartitioner::partition(MeshBase & mesh, const unsigned int n_parts)
87{
88 // We want to use a parallel partitioner that requires a distributed graph
89 // Simply calling a linear partitioner provides us the distributed graph
90 // We should not do anything when using a distributed mesh since the mesh itself
91 // is already distributed
92 // When n_parts=1, we do not need to run any partitioner, instead, let libmesh
93 // handle this
94 if (mesh.is_replicated() && n_parts > 1)
96
97 if (!isParamSetByUser("part_package") && (mesh.n_elem() / n_parts < 28) &&
98 _part_package == "parmetis")
99 {
100 Moose::out
101 << "Average number of elements per partition (" << mesh.n_elem() / n_parts
102 << ") is less than 28. We are switching from ParMETIS to PTScotch for the partitioning."
103 << std::endl;
104 _part_package = "ptscotch";
105 }
106
107 Partitioner::partition(mesh, n_parts);
108}
109
110void
111PetscExternalPartitioner::_do_partition(MeshBase & mesh, const unsigned int n_parts)
112{
114
115 dof_id_type num_edges, num_local_elems, local_elem_id, nj, side;
116 std::vector<dof_id_type> side_weights;
117 std::vector<dof_id_type> elem_weights;
118
119 // Call libmesh to build the dual graph of mesh
121 num_local_elems = _dual_graph.size();
122
123 elem_weights.clear();
125 elem_weights.resize(num_local_elems);
126
127 num_edges = 0;
128 // compute element weight
129 for (dof_id_type k = 0; k < num_local_elems; k++)
130 {
131 num_edges += _dual_graph[k].size();
133 {
134 // Get the original element
135 mooseAssert(k < static_cast<dof_id_type>(_local_id_to_elem.size()),
136 "Local element id " << k << " is not smaller than " << _local_id_to_elem.size());
137 auto elem = _local_id_to_elem[k];
138
139 elem_weights[k] = computeElementWeight(*elem);
140 }
141 }
142
143 side_weights.clear();
144 // Edge weights represent the communication
146 side_weights.resize(num_edges);
147
148 local_elem_id = 0;
149 nj = 0;
150 for (auto & row : _dual_graph)
151 {
152 mooseAssert(local_elem_id < static_cast<dof_id_type>(_local_id_to_elem.size()),
153 "Local element id " << local_elem_id << " is not smaller than "
154 << _local_id_to_elem.size());
155 auto elem = _local_id_to_elem[local_elem_id];
156 unsigned int n_neighbors = 0;
157
158 side = 0;
159 for (auto neighbor : elem->neighbor_ptr_range())
160 {
161 // Skip boundary sides since they do not connect to
162 // anything.
163 if (neighbor != nullptr && neighbor->active())
164 {
166 side_weights[nj] = computeSideWeight(*elem, side);
167
168 nj++;
169 n_neighbors++;
170 }
171
172 side++;
173 }
174 if (n_neighbors != row.size())
176 "Cannot construct dual graph correctly since the number of neighbors is inconsistent");
177
178 local_elem_id++;
179 }
180
181 std::vector<dof_id_type> partition;
182 // Partition graph
185 elem_weights,
186 side_weights,
187 n_parts,
190 partition);
191 // Assign partition to mesh
193}
194
195void
197 const std::vector<std::vector<dof_id_type>> & graph,
198 const std::vector<dof_id_type> & elem_weights,
199 const std::vector<dof_id_type> & side_weights,
200 const dof_id_type num_parts,
201 const dof_id_type num_parts_per_compute_node,
202 const std::string & part_package,
203 std::vector<dof_id_type> & partition)
204{
205 Mat dual;
206 PetscInt num_local_elems, num_elems, *xadj = nullptr, *adjncy = nullptr, i, *values = nullptr,
207 *petsc_elem_weights = nullptr;
208 const PetscInt * parts;
209 MatPartitioning part;
210 IS is;
211
212 // Number of local elements
213 num_elems = num_local_elems = graph.size();
214 // Figure out the total of elements
215 comm.sum(num_elems);
216
217 LibmeshPetscCallA(comm.get(), PetscCalloc1(num_local_elems + 1, &xadj));
218
219 num_local_elems = 0;
220 xadj[0] = 0;
221 for (auto & row : graph)
222 {
223 num_local_elems++;
224 xadj[num_local_elems] = xadj[num_local_elems - 1] + row.size();
225 }
226
227 LibmeshPetscCallA(comm.get(), PetscCalloc1(xadj[num_local_elems], &adjncy));
228
229 // Fill up adjacency
230 i = 0;
231 for (auto & row : graph)
232 for (auto elem : row)
233 adjncy[i++] = elem;
234
235 // If there are no neighbors at all, no side weights should be proivded
236 if (!i)
237 {
238 mooseAssert(!side_weights.size(),
239 "No side weights should be provided since there are no neighbors at all");
240 }
241
242 // Copy over weights
243 if (side_weights.size())
244 {
245 mooseAssert((PetscInt)side_weights.size() == i,
246 "Side weight size " << side_weights.size()
247 << " does not match with adjacency matrix size " << i);
248 LibmeshPetscCallA(comm.get(), PetscCalloc1(side_weights.size(), &values));
249 i = 0;
250 for (auto weight : side_weights)
251 values[i++] = weight;
252 }
253
254 LibmeshPetscCallA(
255 comm.get(),
256 MatCreateMPIAdj(comm.get(), num_local_elems, num_elems, xadj, adjncy, values, &dual));
257
258 LibmeshPetscCallA(comm.get(), MatPartitioningCreate(comm.get(), &part));
259#if !PETSC_VERSION_LESS_THAN(3, 12, 3)
260 LibmeshPetscCallA(comm.get(), MatPartitioningSetUseEdgeWeights(part, PETSC_TRUE));
261#endif
262 LibmeshPetscCallA(comm.get(), MatPartitioningSetAdjacency(part, dual));
263
264 if (!num_local_elems)
265 {
266 mooseAssert(!elem_weights.size(),
267 "No element weights should be provided since there are no elements at all");
268 }
269
270 // Handle element weights
271 if (elem_weights.size())
272 {
273 mooseAssert((PetscInt)elem_weights.size() == num_local_elems,
274 "Element weight size " << elem_weights.size()
275 << " does not match with the number of local elements"
276 << num_local_elems);
277
278 LibmeshPetscCallA(comm.get(), PetscCalloc1(elem_weights.size(), &petsc_elem_weights));
279 i = 0;
280 for (auto weight : elem_weights)
281 petsc_elem_weights[i++] = weight;
282
283 LibmeshPetscCallA(comm.get(), MatPartitioningSetVertexWeights(part, petsc_elem_weights));
284 }
285
286 LibmeshPetscCallA(comm.get(), MatPartitioningSetNParts(part, num_parts));
287#if PETSC_VERSION_LESS_THAN(3, 9, 2)
288 mooseAssert(part_package != "party", "PETSc-3.9.3 or higher is required for using party");
289#endif
290#if PETSC_VERSION_LESS_THAN(3, 9, 0)
291 mooseAssert(part_package != "chaco", "PETSc-3.9.0 or higher is required for using chaco");
292#endif
293 LibmeshPetscCallA(comm.get(), MatPartitioningSetType(part, part_package.c_str()));
294 if (part_package == "hierarch")
295 LibmeshPetscCallA(comm.get(),
296 MatPartitioningHierarchicalSetNfineparts(part, num_parts_per_compute_node));
297
298 LibmeshPetscCallA(comm.get(), MatPartitioningSetFromOptions(part));
299 LibmeshPetscCallA(comm.get(), MatPartitioningApply(part, &is));
300
301 LibmeshPetscCallA(comm.get(), ISGetIndices(is, &parts));
302
303 partition.resize(num_local_elems);
304 for (i = 0; i < num_local_elems; i++)
305 partition[i] = parts[i];
306
307 LibmeshPetscCallA(comm.get(), ISRestoreIndices(is, &parts));
308 LibmeshPetscCallA(comm.get(), MatPartitioningDestroy(&part));
309 LibmeshPetscCallA(comm.get(), MatDestroy(&dual));
310 LibmeshPetscCallA(comm.get(), ISDestroy(&is));
311}
312
313dof_id_type
315{
316 return 1;
317}
318
319dof_id_type
320PetscExternalPartitioner::computeSideWeight(Elem & /*elem*/, unsigned int /*side*/)
321{
322 return 1;
323}
std::array< Real, 2 > values
Definition MortarUtils.C:52
registerMooseObject("MooseApp", PetscExternalPartitioner)
std::unique_ptr< T > clone(const T &object)
Clones the object object.
Definition Factory.h:323
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
Factory & getFactory()
Retrieve a writable reference to the Factory associated with this App.
Definition MooseApp.h:407
bool isParamSetByUser(const std::string &name) const
Test if the supplied parameter is set by a user, as opposed to not set or set to default.
Definition MooseBase.h:205
void mooseError(Args &&... args) const
Emits an error prefixed with object name and type and optionally a file path to the top-level block p...
Definition MooseBase.h:271
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type It sho...
Definition MooseEnum.h:55
MooseApp & _app
The MOOSE application this is associated with.
Definition MooseBase.h:375
Base class for MOOSE partitioner.
static InputParameters validParams()
Partitions a mesh using external petsc partitioners such as parmetis, ptscotch, chaco,...
void preLinearPartition(MeshBase &mesh)
PetscExternalPartitioner(const InputParameters &params)
virtual void initialize(MeshBase &)
Called immediately before partitioning.
virtual void _do_partition(MeshBase &mesh, const unsigned int n) override
virtual void partition(MeshBase &mesh, const unsigned int n) override
virtual dof_id_type computeElementWeight(Elem &elm)
static void partitionGraph(const Parallel::Communicator &comm, const std::vector< std::vector< dof_id_type > > &graph, const std::vector< dof_id_type > &elem_weights, const std::vector< dof_id_type > &side_weights, const dof_id_type num_parts, const dof_id_type num_parts_per_compute_node, const std::string &part_package, std::vector< dof_id_type > &partition)
processor_id_type _num_parts_per_compute_node
static InputParameters validParams()
virtual std::unique_ptr< Partitioner > clone() const override
virtual dof_id_type computeSideWeight(Elem &elem, unsigned int side)
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
std::vector< std::vector< dof_id_type > > _dual_graph
virtual void build_graph(const MeshBase &mesh)
void assign_partitioning(MeshBase &mesh, const std::vector< dof_id_type > &parts)
std::vector< Elem * > _local_id_to_elem
MeshBase & mesh