Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_Grid_Partitioner.hpp
Go to the documentation of this file.
1/****************************************************************************
2 * Copyright (c) 2018-2023 by the Cabana authors *
3 * All rights reserved. *
4 * *
5 * This file is part of the Cabana library. Cabana is distributed under a *
6 * BSD 3-clause license. For the licensing terms see the LICENSE file in *
7 * the top-level directory. *
8 * *
9 * SPDX-License-Identifier: BSD-3-Clause *
10 ****************************************************************************/
11
16#ifndef CABANA_GRID_PARTITIONER_HPP
17#define CABANA_GRID_PARTITIONER_HPP
18
19#include <array>
20#include <stdexcept>
21
22#include <mpi.h>
23
24namespace Cabana
25{
26namespace Grid
27{
28//---------------------------------------------------------------------------//
35template <std::size_t NumSpaceDim>
37{
38 public:
40 static constexpr std::size_t num_space_dim = NumSpaceDim;
41
42 ~BlockPartitioner() = default;
43
50 virtual std::array<int, num_space_dim> ranksPerDimension(
51 MPI_Comm comm,
52 const std::array<int, num_space_dim>& global_cells_per_dim ) const = 0;
53
64 virtual void ownedCellInfo(
65 MPI_Comm cart_comm,
66 const std::array<int, num_space_dim>& global_cells_per_dim,
67 std::array<int, num_space_dim>& owned_num_cell,
68 std::array<int, num_space_dim>& global_cell_offset ) const = 0;
69};
70
71//---------------------------------------------------------------------------//
77template <std::size_t NumSpaceDim>
78class ManualBlockPartitioner : public BlockPartitioner<NumSpaceDim>
79{
80 public:
82 static constexpr std::size_t num_space_dim = NumSpaceDim;
83
88 ManualBlockPartitioner( const std::array<int, NumSpaceDim>& ranks_per_dim )
89 : _ranks_per_dim( ranks_per_dim )
90 {
91 }
92
97 std::array<int, NumSpaceDim>
98 ranksPerDimension( MPI_Comm comm,
99 const std::array<int, NumSpaceDim>& ) const override
100 {
101 int comm_size;
102 MPI_Comm_size( comm, &comm_size );
103 int nrank = 1;
104 for ( std::size_t d = 0; d < num_space_dim; ++d )
105 nrank *= _ranks_per_dim[d];
106 if ( comm_size != nrank )
107 throw std::runtime_error(
108 "Cabana::Grid::ManualBlockPartitioner::ranksPerDimension: "
109 "ManualBlockPartitioner ranks do not match comm size" );
110 return _ranks_per_dim;
111 }
112
124 MPI_Comm cart_comm,
125 const std::array<int, num_space_dim>& global_cells_per_dim,
126 std::array<int, num_space_dim>& owned_num_cell,
127 std::array<int, num_space_dim>& global_cell_offset ) const override
128 {
129 // Get the cells per dimension and the remainder.
130 std::array<int, num_space_dim> cells_per_dim;
131 std::array<int, num_space_dim> dim_remainder;
132 std::array<int, num_space_dim> cart_rank;
133 averageCellInfo( cart_comm, global_cells_per_dim, cart_rank,
134 cells_per_dim, dim_remainder );
135
136 // Compute the global cell offset and the local low corner on this rank
137 // by computing the starting global cell index via exclusive scan.
138 global_cell_offset =
139 globalCellOffsetHelper( cart_rank, cells_per_dim, dim_remainder );
140
141 // Compute the number of local cells in this rank in each dimension.
142 owned_num_cell =
143 ownedCellsHelper( cart_rank, cells_per_dim, dim_remainder );
144 }
145
153 std::array<int, num_space_dim> ownedCellsPerDimension(
154 MPI_Comm cart_comm,
155 const std::array<int, num_space_dim>& global_cells_per_dim ) const
156 {
157 // Get the cells per dimension and the remainder.
158 std::array<int, num_space_dim> cells_per_dim;
159 std::array<int, num_space_dim> dim_remainder;
160 std::array<int, num_space_dim> cart_rank;
161 averageCellInfo( cart_comm, global_cells_per_dim, cart_rank,
162 cells_per_dim, dim_remainder );
163
164 // Compute the number of local cells in this rank in each dimension.
165 return ownedCellsHelper( cart_rank, cells_per_dim, dim_remainder );
166 }
167
168 private:
179 inline void
180 averageCellInfo( MPI_Comm cart_comm,
181 const std::array<int, num_space_dim>& global_cells_per_dim,
182 std::array<int, num_space_dim>& cart_rank,
183 std::array<int, num_space_dim>& cells_per_dim,
184 std::array<int, num_space_dim>& dim_remainder ) const
185 {
186 // Get the Cartesian size and topology index of this rank.
187 int linear_rank;
188 MPI_Comm_rank( cart_comm, &linear_rank );
189 MPI_Cart_coords( cart_comm, linear_rank, num_space_dim,
190 cart_rank.data() );
191 // Get the cells per dimension and the remainder.
192 for ( std::size_t d = 0; d < num_space_dim; ++d )
193 {
194 cells_per_dim[d] = global_cells_per_dim[d] / _ranks_per_dim[d];
195 dim_remainder[d] = global_cells_per_dim[d] % _ranks_per_dim[d];
196 }
197 }
198
208 inline std::array<int, num_space_dim> ownedCellsHelper(
209 const std::array<int, num_space_dim>& cart_rank,
210 const std::array<int, num_space_dim>& cells_per_dim,
211 const std::array<int, num_space_dim>& dim_remainder ) const
212 {
213 std::array<int, num_space_dim> owned_num_cell;
214 // Compute the number of local cells in this rank in each dimension.
215 for ( std::size_t d = 0; d < num_space_dim; ++d )
216 {
217 owned_num_cell[d] = cells_per_dim[d];
218 if ( dim_remainder[d] > cart_rank[d] )
219 ++owned_num_cell[d];
220 }
221 return owned_num_cell;
222 }
223
233 inline std::array<int, num_space_dim> globalCellOffsetHelper(
234 const std::array<int, num_space_dim>& cart_rank,
235 const std::array<int, num_space_dim>& cells_per_dim,
236 const std::array<int, num_space_dim>& dim_remainder ) const
237 {
238 std::array<int, num_space_dim> global_cell_offset;
239 // Compute the global cell offset and the local low corner on this rank
240 // by computing the starting global cell index via exclusive scan.
241 for ( std::size_t d = 0; d < num_space_dim; ++d )
242 {
243 global_cell_offset[d] = 0;
244 for ( int r = 0; r < cart_rank[d]; ++r )
245 {
246 global_cell_offset[d] += cells_per_dim[d];
247 if ( dim_remainder[d] > r )
248 ++global_cell_offset[d];
249 }
250 }
251 return global_cell_offset;
252 }
253
254 private:
255 std::array<int, NumSpaceDim> _ranks_per_dim;
256};
257
258//---------------------------------------------------------------------------//
270template <std::size_t NumSpaceDim>
271class DimBlockPartitioner : public BlockPartitioner<NumSpaceDim>
272{
273 public:
275 static constexpr std::size_t num_space_dim = NumSpaceDim;
276
279 {
280 // Initialize so that all ranks will be modified when requested.
281 initUnpartitionedDims();
282 };
283
288 DimBlockPartitioner( const int dim )
289 {
290 initUnpartitionedDims();
291
292 // Only partition in the other dimensions.
293 _unpartitioned_dim[dim] = 1;
294 };
295
301 DimBlockPartitioner( const int dim_1, const int dim_2 )
302 {
303 static_assert(
304 NumSpaceDim > 2,
305 "Cannot partition 2d system with 2 unpartitioned dimensions." );
306
307 initUnpartitionedDims();
308
309 // Only partition in the third dimension.
310 _unpartitioned_dim[dim_1] = 1;
311 _unpartitioned_dim[dim_2] = 1;
312 };
313
318 std::array<int, NumSpaceDim>
319 ranksPerDimension( MPI_Comm comm,
320 const std::array<int, NumSpaceDim>& ) const override
321 {
322 int comm_size;
323 MPI_Comm_size( comm, &comm_size );
324 auto ranks_per_dim = _unpartitioned_dim;
325 MPI_Dims_create( comm_size, NumSpaceDim, ranks_per_dim.data() );
326
327 return ranks_per_dim;
328 }
329
341 MPI_Comm cart_comm,
342 const std::array<int, num_space_dim>& global_cells_per_dim,
343 std::array<int, num_space_dim>& owned_num_cell,
344 std::array<int, num_space_dim>& global_cell_offset ) const override
345 {
346 // Get the cells per dimension and the remainder.
347 std::array<int, num_space_dim> cells_per_dim;
348 std::array<int, num_space_dim> dim_remainder;
349 std::array<int, num_space_dim> cart_rank;
350 averageCellInfo( cart_comm, global_cells_per_dim, cart_rank,
351 cells_per_dim, dim_remainder );
352
353 // Compute the global cell offset and the local low corner on this rank
354 // by computing the starting global cell index via exclusive scan.
355 global_cell_offset =
356 globalCellOffsetHelper( cart_rank, cells_per_dim, dim_remainder );
357
358 // Compute the number of local cells in this rank in each dimension.
359 owned_num_cell =
360 ownedCellsHelper( cart_rank, cells_per_dim, dim_remainder );
361 }
362
371 std::array<int, num_space_dim> ownedCellsPerDimension(
372 MPI_Comm cart_comm,
373 const std::array<int, num_space_dim>& global_cells_per_dim ) const
374 {
375 // Get the cells per dimension and the remainder.
376 std::array<int, num_space_dim> cells_per_dim;
377 std::array<int, num_space_dim> dim_remainder;
378 std::array<int, num_space_dim> cart_rank;
379 averageCellInfo( cart_comm, global_cells_per_dim, cart_rank,
380 cells_per_dim, dim_remainder );
381
382 // Compute the number of local cells in this rank in each dimension.
383 return ownedCellsHelper( cart_rank, cells_per_dim, dim_remainder );
384 }
385
386 private:
387 std::array<int, NumSpaceDim> _unpartitioned_dim;
388
390 void initUnpartitionedDims()
391 {
392 for ( std::size_t d = 0; d < NumSpaceDim; ++d )
393 _unpartitioned_dim[d] = 0;
394 }
395
406 inline void
407 averageCellInfo( MPI_Comm cart_comm,
408 const std::array<int, num_space_dim>& global_cells_per_dim,
409 std::array<int, num_space_dim>& cart_rank,
410 std::array<int, num_space_dim>& cells_per_dim,
411 std::array<int, num_space_dim>& dim_remainder ) const
412 {
413 // Get the Cartesian size and topology index of this rank.
414 std::array<int, num_space_dim> ranks_per_dim;
415 std::array<int, num_space_dim> cart_period;
416 MPI_Cart_get( cart_comm, num_space_dim, ranks_per_dim.data(),
417 cart_period.data(), cart_rank.data() );
418
419 // Get the cells per dimension and the remainder.
420 for ( std::size_t d = 0; d < num_space_dim; ++d )
421 {
422 cells_per_dim[d] = global_cells_per_dim[d] / ranks_per_dim[d];
423 dim_remainder[d] = global_cells_per_dim[d] % ranks_per_dim[d];
424 }
425 }
426
436 inline std::array<int, num_space_dim> ownedCellsHelper(
437 const std::array<int, num_space_dim>& cart_rank,
438 const std::array<int, num_space_dim>& cells_per_dim,
439 const std::array<int, num_space_dim>& dim_remainder ) const
440 {
441 std::array<int, num_space_dim> owned_num_cell;
442 // Compute the number of local cells in this rank in each dimension.
443 for ( std::size_t d = 0; d < num_space_dim; ++d )
444 {
445 owned_num_cell[d] = cells_per_dim[d];
446 if ( dim_remainder[d] > cart_rank[d] )
447 ++owned_num_cell[d];
448 }
449 return owned_num_cell;
450 }
451
461 inline std::array<int, num_space_dim> globalCellOffsetHelper(
462 const std::array<int, num_space_dim>& cart_rank,
463 const std::array<int, num_space_dim>& cells_per_dim,
464 const std::array<int, num_space_dim>& dim_remainder ) const
465 {
466 std::array<int, num_space_dim> global_cell_offset;
467 // Compute the global cell offset and the local low corner on this rank
468 // by computing the starting global cell index via exclusive scan.
469 for ( std::size_t d = 0; d < num_space_dim; ++d )
470 {
471 global_cell_offset[d] = 0;
472 for ( int r = 0; r < cart_rank[d]; ++r )
473 {
474 global_cell_offset[d] += cells_per_dim[d];
475 if ( dim_remainder[d] > r )
476 ++global_cell_offset[d];
477 }
478 }
479 return global_cell_offset;
480 }
481};
482
483//---------------------------------------------------------------------------//
484
485} // namespace Grid
486} // namespace Cabana
487
488#endif // end CABANA_GRID_PARTITIONER_HPP
Block partitioner base class.
Definition Cabana_Grid_Partitioner.hpp:37
virtual void ownedCellInfo(MPI_Comm cart_comm, const std::array< int, num_space_dim > &global_cells_per_dim, std::array< int, num_space_dim > &owned_num_cell, std::array< int, num_space_dim > &global_cell_offset) const =0
Get the owned number of cells and global cell offset of the current MPI rank.
static constexpr std::size_t num_space_dim
Spatial dimension.
Definition Cabana_Grid_Partitioner.hpp:40
virtual std::array< int, num_space_dim > ranksPerDimension(MPI_Comm comm, const std::array< int, num_space_dim > &global_cells_per_dim) const =0
Get the number of MPI ranks in each dimension of the grid.
static constexpr std::size_t num_space_dim
Spatial dimension.
Definition Cabana_Grid_Partitioner.hpp:275
void ownedCellInfo(MPI_Comm cart_comm, const std::array< int, num_space_dim > &global_cells_per_dim, std::array< int, num_space_dim > &owned_num_cell, std::array< int, num_space_dim > &global_cell_offset) const override
Get the owned number of cells and the global cell offset of the current MPI rank.
Definition Cabana_Grid_Partitioner.hpp:340
DimBlockPartitioner(const int dim)
Constructor for NumSpaceDim-1 (1d for 2d system).
Definition Cabana_Grid_Partitioner.hpp:288
DimBlockPartitioner()
Default constructor (automatically partitioned in all dimensions).
Definition Cabana_Grid_Partitioner.hpp:278
DimBlockPartitioner(const int dim_1, const int dim_2)
Constructor for 1d decomposition (3d systems only).
Definition Cabana_Grid_Partitioner.hpp:301
std::array< int, num_space_dim > ownedCellsPerDimension(MPI_Comm cart_comm, const std::array< int, num_space_dim > &global_cells_per_dim) const
Get the owned number of cells of the current MPI rank.
Definition Cabana_Grid_Partitioner.hpp:371
std::array< int, NumSpaceDim > ranksPerDimension(MPI_Comm comm, const std::array< int, NumSpaceDim > &) const override
Get the MPI ranks per dimension.
Definition Cabana_Grid_Partitioner.hpp:319
ManualBlockPartitioner(const std::array< int, NumSpaceDim > &ranks_per_dim)
Constructor.
Definition Cabana_Grid_Partitioner.hpp:88
static constexpr std::size_t num_space_dim
Spatial dimension.
Definition Cabana_Grid_Partitioner.hpp:82
std::array< int, num_space_dim > ownedCellsPerDimension(MPI_Comm cart_comm, const std::array< int, num_space_dim > &global_cells_per_dim) const
Get the owned number of cells of the current MPI rank.
Definition Cabana_Grid_Partitioner.hpp:153
void ownedCellInfo(MPI_Comm cart_comm, const std::array< int, num_space_dim > &global_cells_per_dim, std::array< int, num_space_dim > &owned_num_cell, std::array< int, num_space_dim > &global_cell_offset) const override
Get the owned number of cells of the current MPI rank.
Definition Cabana_Grid_Partitioner.hpp:123
std::array< int, NumSpaceDim > ranksPerDimension(MPI_Comm comm, const std::array< int, NumSpaceDim > &) const override
Get the MPI ranks per dimension.
Definition Cabana_Grid_Partitioner.hpp:98
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36