Cabana 0.8.0-dev
 
Loading...
Searching...
No Matches
Cabana_Grid_GlobalParticleComm.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_GLOBALPARTICLECOMM_HPP
17#define CABANA_GRID_GLOBALPARTICLECOMM_HPP
18
20#include <Cabana_Grid_Types.hpp>
21
23#include <Cabana_Slice.hpp>
24
25#include <memory>
26#include <stdexcept>
27#include <type_traits>
28
29namespace Cabana
30{
31namespace Grid
32{
33//---------------------------------------------------------------------------//
37template <class MemorySpace, class LocalGridType>
39{
40 public:
42 static constexpr std::size_t num_space_dim = LocalGridType::num_space_dim;
44 using mesh_type = typename LocalGridType::mesh_type;
48 using memory_space = MemorySpace;
49
52 Kokkos::View<double* [num_space_dim][2], memory_space>;
54 using destination_view_type = Kokkos::View<int*, memory_space>;
57 Kokkos::View<int***, Kokkos::LayoutRight, memory_space>;
60 Kokkos::View<int***, Kokkos::LayoutRight, Kokkos::HostSpace>;
61
63 GlobalParticleComm( const LocalGridType local_grid )
64 {
65 auto global_grid = local_grid.globalGrid();
67 Kokkos::ViewAllocateWithoutInitializing( "global_destination" ),
68 0 );
69
70 int max_ranks_per_dim = -1;
71 for ( std::size_t d = 0; d < num_space_dim; ++d )
72 {
73 _ranks_per_dim[d] = global_grid.dimNumBlock( d );
74 if ( _ranks_per_dim[d] > max_ranks_per_dim )
75 max_ranks_per_dim = _ranks_per_dim[d];
76 }
77 copyRanks( global_grid );
78
79 // Purposely using zero-init. Some entries unused in non-cubic
80 // decompositions.
82 corner_view_type( "local_mpi_boundaries", max_ranks_per_dim );
83
84 _rank_1d = global_grid.blockId();
85 for ( std::size_t d = 0; d < num_space_dim; ++d )
86 _rank[d] = global_grid.dimBlockId( d );
87
88 auto local_mesh = createLocalMesh<memory_space>( local_grid );
89 storeRanks( local_mesh );
90
91 // Update local boundaries from all ranks.
92 auto comm = global_grid.comm();
93 // TODO: Could use subcommunicators instead.
94 MPI_Allreduce( MPI_IN_PLACE, _local_corners.data(),
95 _local_corners.size(), MPI_DOUBLE, MPI_SUM, comm );
96
97 scaleRanks();
98 }
99
101 template <class LocalMeshType>
102 void storeRanks( LocalMeshType local_mesh )
103 {
104 auto local_corners = _local_corners;
105 auto rank = _rank;
106 auto store_corners = KOKKOS_LAMBDA( const std::size_t d )
107 {
108 local_corners( rank[d], d, 0 ) =
109 local_mesh.lowCorner( Cabana::Grid::Own(), d );
110 local_corners( rank[d], d, 1 ) =
111 local_mesh.highCorner( Cabana::Grid::Own(), d );
112 };
113 using exec_space = typename memory_space::execution_space;
114 Kokkos::RangePolicy<exec_space> policy( 0, num_space_dim );
115 Kokkos::parallel_for( "Cabana::Grid::GlobalParticleComm::storeCorners",
116 policy, store_corners );
117 Kokkos::fence();
118 }
119
122 {
123 auto scale = getScaling();
124
125 auto local_corners = _local_corners;
126 auto ranks_per_dim = _ranks_per_dim;
127 auto scale_corners = KOKKOS_LAMBDA( const std::size_t d )
128 {
129 for ( int r = 0; r < ranks_per_dim[d]; ++r )
130 {
131 local_corners( r, d, 0 ) /= scale[d];
132 local_corners( r, d, 1 ) /= scale[d];
133 }
134 };
135 using exec_space = typename memory_space::execution_space;
136 Kokkos::RangePolicy<exec_space> policy( 0, num_space_dim );
137 Kokkos::parallel_for( "Cabana::Grid::GlobalParticleComm::scaleCorners",
138 policy, scale_corners );
139 Kokkos::fence();
140 }
141
143 template <std::size_t NSD = num_space_dim>
144 std::enable_if_t<3 == NSD, Kokkos::Array<int, num_space_dim>> getScaling()
145 {
146 Kokkos::Array<int, num_space_dim> scale;
147 scale[0] = _ranks_per_dim[1] * _ranks_per_dim[2];
148 scale[1] = _ranks_per_dim[0] * _ranks_per_dim[2];
149 scale[2] = _ranks_per_dim[0] * _ranks_per_dim[1];
150 return scale;
151 }
152
154 template <std::size_t NSD = num_space_dim>
155 std::enable_if_t<2 == NSD, Kokkos::Array<int, num_space_dim>> getScaling()
156 {
157 Kokkos::Array<int, num_space_dim> scale;
158 scale[0] = _ranks_per_dim[1];
159 scale[1] = _ranks_per_dim[0];
160 return scale;
161 }
162
164 template <class GlobalGridType, std::size_t NSD = num_space_dim>
165 std::enable_if_t<3 == NSD, void> copyRanks( GlobalGridType global_grid )
166 {
167 host_rank_view_type global_ranks_host(
168 Kokkos::ViewAllocateWithoutInitializing( "ranks_host" ),
170 for ( int i = 0; i < _ranks_per_dim[0]; ++i )
171 for ( int j = 0; j < _ranks_per_dim[1]; ++j )
172 for ( int k = 0; k < _ranks_per_dim[2]; ++k )
173 // Not device accessible (uses MPI), so must be copied.
174 global_ranks_host( i, j, k ) =
175 global_grid.blockRank( i, j, k );
176
177 _global_ranks = Kokkos::create_mirror_view_and_copy(
178 memory_space(), global_ranks_host );
179 }
180
182 template <class GlobalGridType, std::size_t NSD = num_space_dim>
183 std::enable_if_t<2 == NSD, void> copyRanks( GlobalGridType global_grid )
184 {
185 // Storing as 3d for convenience.
186 host_rank_view_type global_ranks_host(
187 Kokkos::ViewAllocateWithoutInitializing( "ranks_host" ),
188 _ranks_per_dim[0], _ranks_per_dim[1], 1 );
189 for ( int i = 0; i < _ranks_per_dim[0]; ++i )
190 for ( int j = 0; j < _ranks_per_dim[1]; ++j )
191 // Not device accessible (uses MPI), so must be copied.
192 global_ranks_host( i, j, 0 ) = global_grid.blockRank( i, j );
193
194 _global_ranks = Kokkos::create_mirror_view_and_copy(
195 memory_space(), global_ranks_host );
196 }
197
205 template <class ExecutionSpace, class PositionType>
206 void build( ExecutionSpace exec_space, PositionType positions,
207 const std::size_t begin, const std::size_t end )
208 {
209 Kokkos::Profiling::ScopedRegion region(
210 "Cabana::Grid::GlobalParticleComm::build" );
211
213 assert( end >= begin );
214 assert( end <= positions.size() );
215
216 // Must match the size of all particles, even if some can be ignored in
217 // this search.
218 Kokkos::resize( _destinations, positions.size() );
219 // Start with everything staying on this rank.
220 Kokkos::deep_copy( _destinations, _rank_1d );
221
222 // Local copies for lambda capture.
223 auto local_corners = _local_corners;
224 auto ranks_per_dim = _ranks_per_dim;
225 auto destinations = _destinations;
226 auto global_ranks = _global_ranks;
227 auto build_migrate = KOKKOS_LAMBDA( const std::size_t p )
228 {
229 // This is not num_space_dim because global_ranks is always rank-3
230 // out of convenience.
231 int ijk[3] = { 0, 0, 0 };
232
233 // Find the rank this particle should be moved to.
234 for ( std::size_t d = 0; d < num_space_dim; ++d )
235 {
236 int min = 0;
237 int max = ranks_per_dim[d];
238
239 // Check if outside the box in this dimension.
240 if ( ( positions( p, d ) < local_corners( min, d, 0 ) ) ||
241 ( positions( p, d ) > local_corners( max - 1, d, 1 ) ) )
242 destinations( p ) = -1;
243
244 // Do a binary search for this particle in this dimension.
245 while ( max - min > 1 )
246 {
247 int center = Kokkos::floor( ( max + min ) / 2.0 );
248 if ( positions( p, d ) < local_corners( center, d, 0 ) )
249 max = center;
250 else
251 min = center;
252 }
253 ijk[d] = min;
254 }
255 // Keep the destination rank for eventual migration.
256 destinations( p ) = global_ranks( ijk[0], ijk[1], ijk[2] );
257 };
258
259 Kokkos::RangePolicy<ExecutionSpace> policy( exec_space, begin, end );
260 Kokkos::parallel_for( "Cabana::Grid::GlobalParticleComm::build", policy,
261 build_migrate );
262 Kokkos::fence();
263 }
264
266 template <class ExecutionSpace, class PositionType>
267 void build( ExecutionSpace exec_space, PositionType positions )
268 {
269 build( exec_space, positions, 0, positions.size() );
270 }
271
273 template <class PositionType>
274 void build( PositionType positions )
275 {
276 using execution_space = typename memory_space::execution_space;
277 // TODO: enable views.
278 build( execution_space{}, positions, 0, positions.size() );
279 }
280
282 template <class AoSoAType>
283 void migrate( MPI_Comm comm, AoSoAType& aosoa )
284 {
286 Cabana::migrate( distributor, aosoa );
287 }
288
289 protected:
293 Kokkos::Array<int, num_space_dim> _rank;
295 Kokkos::Array<int, num_space_dim> _ranks_per_dim;
302};
303
308template <class MemorySpace, class LocalGridType>
309auto createGlobalParticleComm( const LocalGridType& local_grid )
310{
311 return std::make_shared<GlobalParticleComm<MemorySpace, LocalGridType>>(
312 local_grid );
313}
314
315//---------------------------------------------------------------------------//
316
317} // namespace Grid
318} // namespace Cabana
319
320#endif // end CABANA_GRID_GLOBALPARTICLECOMM_HPP
Multi-node particle redistribution.
auto createGlobalParticleComm(const LocalGridType &local_grid)
Create global linked cell binning.
Definition Cabana_Grid_GlobalParticleComm.hpp:309
LocalMesh< MemorySpace, MeshType > createLocalMesh(const LocalGrid< MeshType > &local_grid)
Creation function for local mesh.
Definition Cabana_Grid_LocalMesh.hpp:791
Grid type tags.
Slice a single particle property from an AoSoA.
A communication plan for migrating data from one uniquely-owned decomposition to another uniquely own...
Definition Cabana_Distributor.hpp:63
Global logical grid.
Definition Cabana_Grid_GlobalGrid.hpp:39
void build(ExecutionSpace exec_space, PositionType positions)
Bin particles across the global grid.
Definition Cabana_Grid_GlobalParticleComm.hpp:267
Cabana::Grid::GlobalGrid< mesh_type > global_grid_type
Global grid.
Definition Cabana_Grid_GlobalParticleComm.hpp:46
Kokkos::View< int ***, Kokkos::LayoutRight, memory_space > rank_view_type
Cartesian rank View type.
Definition Cabana_Grid_GlobalParticleComm.hpp:56
Kokkos::View< int ***, Kokkos::LayoutRight, Kokkos::HostSpace > host_rank_view_type
Cartesian rank View type (host).
Definition Cabana_Grid_GlobalParticleComm.hpp:59
Kokkos::Array< int, num_space_dim > _rank
Current cartesian rank.
Definition Cabana_Grid_GlobalParticleComm.hpp:293
static constexpr std::size_t num_space_dim
Spatial dimension.
Definition Cabana_Grid_GlobalParticleComm.hpp:42
void storeRanks(LocalMeshType local_mesh)
Store local rank boundaries from the local mesh.
Definition Cabana_Grid_GlobalParticleComm.hpp:102
void build(ExecutionSpace exec_space, PositionType positions, const std::size_t begin, const std::size_t end)
Bin particles across the global grid.
Definition Cabana_Grid_GlobalParticleComm.hpp:206
std::enable_if_t< 2==NSD, void > copyRanks(GlobalGridType global_grid)
Store all cartesian MPI ranks.
Definition Cabana_Grid_GlobalParticleComm.hpp:183
destination_view_type _destinations
Particle destination ranks.
Definition Cabana_Grid_GlobalParticleComm.hpp:301
typename LocalGridType::mesh_type mesh_type
Mesh type.
Definition Cabana_Grid_GlobalParticleComm.hpp:44
MemorySpace memory_space
Kokkos memory space.
Definition Cabana_Grid_GlobalParticleComm.hpp:48
std::enable_if_t< 2==NSD, Kokkos::Array< int, num_space_dim > > getScaling()
Scaling factors due to double counting from MPI reduction.
Definition Cabana_Grid_GlobalParticleComm.hpp:155
Kokkos::View< double *[num_space_dim][2], memory_space > corner_view_type
Local boundary View type.
Definition Cabana_Grid_GlobalParticleComm.hpp:51
int _rank_1d
Current rank.
Definition Cabana_Grid_GlobalParticleComm.hpp:291
corner_view_type _local_corners
Local boundaries.
Definition Cabana_Grid_GlobalParticleComm.hpp:297
GlobalParticleComm(const LocalGridType local_grid)
Constructor.
Definition Cabana_Grid_GlobalParticleComm.hpp:63
Kokkos::Array< int, num_space_dim > _ranks_per_dim
Total ranks per dimension.
Definition Cabana_Grid_GlobalParticleComm.hpp:295
rank_view_type _global_ranks
All cartesian ranks.
Definition Cabana_Grid_GlobalParticleComm.hpp:299
void migrate(MPI_Comm comm, AoSoAType &aosoa)
Migrate particles to the correct rank.
Definition Cabana_Grid_GlobalParticleComm.hpp:283
void build(PositionType positions)
Bin particles across the global grid.
Definition Cabana_Grid_GlobalParticleComm.hpp:274
Kokkos::View< int *, memory_space > destination_view_type
Particle destination ranks View type.
Definition Cabana_Grid_GlobalParticleComm.hpp:54
void scaleRanks()
Scale local rank boundaries based on double counting from MPI reduction.
Definition Cabana_Grid_GlobalParticleComm.hpp:121
std::enable_if_t< 3==NSD, void > copyRanks(GlobalGridType global_grid)
Store all cartesian MPI ranks.
Definition Cabana_Grid_GlobalParticleComm.hpp:165
std::enable_if_t< 3==NSD, Kokkos::Array< int, num_space_dim > > getScaling()
Scaling factors due to double counting from MPI reduction.
Definition Cabana_Grid_GlobalParticleComm.hpp:144
Core: particle data structures and algorithms.
Definition Cabana_AoSoA.hpp:36
void migrate(ExecutionSpace exec_space, const Distributor_t &distributor, const AoSoA_t &src, AoSoA_t &dst, typename std::enable_if<(is_distributor< Distributor_t >::value &&is_aosoa< AoSoA_t >::value), int >::type *=0)
Synchronously migrate data between two different decompositions using the distributor forward communi...
Definition Cabana_Distributor.hpp:335
Owned decomposition tag.
Definition Cabana_Grid_Types.hpp:190
Definition Cabana_Types.hpp:88