Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 : // C++ includes
19 : #include <algorithm> // for std::stable_sort
20 :
21 : // Local includes
22 : #include "libmesh/centroid_partitioner.h"
23 : #include "libmesh/elem.h"
24 : #include "libmesh/enum_partitioner_type.h"
25 : #include "libmesh/int_range.h"
26 :
27 : namespace libMesh
28 : {
29 :
30 :
31 142 : PartitionerType CentroidPartitioner::type() const
32 : {
33 142 : return CENTROID_PARTITIONER;
34 : }
35 :
36 :
37 301 : void CentroidPartitioner::partition_range(MeshBase & mesh,
38 : MeshBase::element_iterator it,
39 : MeshBase::element_iterator end,
40 : unsigned int n)
41 : {
42 : // Check for easy returns
43 301 : if (it == end)
44 2 : return;
45 :
46 230 : if (n == 1)
47 : {
48 0 : this->single_partition_range (it, end);
49 0 : return;
50 : }
51 :
52 : // Make sure the user has not handed us an
53 : // invalid number of partitions.
54 34 : libmesh_assert_greater (n, 0);
55 :
56 : // We don't yet support distributed meshes with this Partitioner
57 230 : if (!mesh.is_serial())
58 0 : libmesh_not_implemented();
59 :
60 : // Compute the element vertex averages. Note: we used to skip this step
61 : // if the number of elements was unchanged from the last call, but
62 : // that doesn't account for elements that have moved a lot since the
63 : // last time the Partitioner was called...
64 426 : this->compute_vertex_avgs (it, end);
65 :
66 230 : switch (this->sort_method())
67 : {
68 230 : case X:
69 : {
70 230 : std::stable_sort(_elem_vertex_avgs.begin(),
71 : _elem_vertex_avgs.end(),
72 : CentroidPartitioner::sort_x);
73 :
74 230 : break;
75 : }
76 :
77 :
78 0 : case Y:
79 : {
80 0 : std::stable_sort(_elem_vertex_avgs.begin(),
81 : _elem_vertex_avgs.end(),
82 : CentroidPartitioner::sort_y);
83 :
84 0 : break;
85 :
86 : }
87 :
88 :
89 0 : case Z:
90 : {
91 0 : std::stable_sort(_elem_vertex_avgs.begin(),
92 : _elem_vertex_avgs.end(),
93 : CentroidPartitioner::sort_z);
94 :
95 0 : break;
96 : }
97 :
98 :
99 0 : case RADIAL:
100 : {
101 0 : std::stable_sort(_elem_vertex_avgs.begin(),
102 : _elem_vertex_avgs.end(),
103 : CentroidPartitioner::sort_radial);
104 :
105 0 : break;
106 : }
107 0 : default:
108 0 : libmesh_error_msg("Unknown sort method: " << this->sort_method());
109 : }
110 :
111 : // Compute target_size, the approximate number of elements on each processor.
112 : const dof_id_type target_size = cast_int<dof_id_type>
113 264 : (_elem_vertex_avgs.size() / n);
114 :
115 10856 : for (auto i : index_range(_elem_vertex_avgs))
116 : {
117 10626 : Elem * elem = _elem_vertex_avgs[i].second;
118 :
119 : // FIXME: All "extra" elements go on the last processor... this
120 : // could probably be improved.
121 13016 : elem->processor_id() =
122 16472 : std::min (cast_int<processor_id_type>(i / target_size),
123 13449 : cast_int<processor_id_type>(n-1));
124 : }
125 : }
126 :
127 :
128 :
129 301 : void CentroidPartitioner::_do_partition (MeshBase & mesh,
130 : const unsigned int n)
131 : {
132 301 : this->partition_range(mesh,
133 602 : mesh.elements_begin(),
134 337 : mesh.elements_end(),
135 72 : n);
136 301 : }
137 :
138 :
139 :
140 230 : void CentroidPartitioner::compute_vertex_avgs (MeshBase::element_iterator it,
141 : MeshBase::element_iterator end)
142 : {
143 230 : _elem_vertex_avgs.clear();
144 :
145 11052 : for (auto & elem : as_range(it, end))
146 10788 : _elem_vertex_avgs.emplace_back(elem->vertex_average(), elem);
147 230 : }
148 :
149 :
150 :
151 :
152 55508 : bool CentroidPartitioner::sort_x (const std::pair<Point, Elem *> & lhs,
153 : const std::pair<Point, Elem *> & rhs)
154 : {
155 55508 : return (lhs.first(0) < rhs.first(0));
156 : }
157 :
158 :
159 :
160 :
161 0 : bool CentroidPartitioner::sort_y (const std::pair<Point, Elem *> & lhs,
162 : const std::pair<Point, Elem *> & rhs)
163 : {
164 0 : return (lhs.first(1) < rhs.first(1));
165 : }
166 :
167 :
168 :
169 :
170 :
171 0 : bool CentroidPartitioner::sort_z (const std::pair<Point, Elem *> & lhs,
172 : const std::pair<Point, Elem *> & rhs)
173 : {
174 0 : return (lhs.first(2) < rhs.first(2));
175 : }
176 :
177 :
178 :
179 0 : bool CentroidPartitioner::sort_radial (const std::pair<Point, Elem *> & lhs,
180 : const std::pair<Point, Elem *> & rhs)
181 : {
182 0 : return (lhs.first.norm() < rhs.first.norm());
183 : }
184 :
185 : } // namespace libMesh
|