OpenLB 1.7
Loading...
Searching...
No Matches
utilities.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2022-2023 Nicolas Hafen, Jan E. Marquardt, Mathias J. Krause
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24
25#ifndef PARTICLE_COMMUNICATION_UTILITIES_H
26#define PARTICLE_COMMUNICATION_UTILITIES_H
27
29
30namespace olb {
31
32namespace particles {
33
34namespace communication {
35
36
38template<typename T, unsigned D, bool verbose=false>
39std::vector<int> getNeighborCuboids(
40 CuboidGeometry<T,D>& cuboidGeometry, unsigned offset, int globiC )
41{
42 std::vector<int> neighbors;
43 cuboidGeometry.getNeighbourhood(globiC, neighbors, offset);
44
45 //Print, if desired
46 if constexpr(verbose){
47 std::cout << globiC << ": " << neighbors << std::endl;
48 }
49
50 return neighbors;
51}
52
54template<typename T, unsigned D, bool verbose=false>
56 SuperStructure<T,D>& superStructure, int rank, std::map<int,std::vector<int>> neighbourhood )
57{
58 std::unordered_set<int> rankNeighbours;
59
60#ifdef PARALLEL_MODE_MPI
61 auto& loadBalancer = superStructure.getLoadBalancer();
62
63 for ( auto cuboidNeighbourPair : neighbourhood){
64 int globiC = cuboidNeighbourPair.first;
65 if (loadBalancer.rank(globiC) == rank) {
66 std::vector<int>& neighbours = cuboidNeighbourPair.second;
67 for (int globiCN : neighbours ){
68 rankNeighbours.insert( loadBalancer.rank(globiCN));
69 }
70 }
71 }
72
73 if constexpr(verbose){
74 std::cout << rank << ": " << rankNeighbours << std::endl;
75 }
76#endif
77
78 return rankNeighbours;
79}
80
81
83template<typename T, unsigned D, bool verbose=false>
85 SuperStructure<T,D>& superStructure, int rank, const std::vector<std::unordered_set<int>>& neighbourhood )
86{
87 std::map<int,std::vector<int>> neighbourhoodMap;
88
89 for(unsigned i=0; i<neighbourhood.size(); ++i) {
90 neighbourhoodMap[i] = std::vector<int>();
91 for(int iC : neighbourhood[i]) {
92 neighbourhoodMap[i].push_back(iC);
93 }
94 }
95
96 return getNeighbourRanksFromCuboidNeighbourhood<T,D,verbose>(
97 superStructure, rank, neighbourhoodMap );
98}
99
101template<typename T, unsigned D, bool verbose=false>
103 SuperStructure<T,D>& superStructure, const std::vector<std::unordered_set<int>>& neighbourhood )
104{
105 const int rank = singleton::mpi().getRank();
106 return getNeighbourRanksFromCuboidNeighbourhood<T,D,verbose>(
107 superStructure, rank, neighbourhood);
108}
109
110
112template<typename T, unsigned D, bool verbose=false>
113std::unordered_set<int> getNeighbourRanks(
114 SuperStructure<T,D>& superStructure, unsigned offset, int rank )
115{
116 std::unordered_set<int> rankNeighbours;
117
118#ifdef PARALLEL_MODE_MPI
119 auto& loadBalancer = superStructure.getLoadBalancer();
120 auto& cuboidGeometry = superStructure.getCuboidGeometry();
121
123 // 1. sample complete neighbourhood
124 std::map<int,std::vector<int>> neighbourhood;
125 evaluateCuboidGeometryNeighbourhood( cuboidGeometry, neighbourhood, offset);
126
127 //2. check consistency
128 constexpr bool correctFaultyNeighbourhood = true;
129 checkCuboidNeighbourhoodConsistency( neighbourhood, correctFaultyNeighbourhood );
130
131 //3. evaluate relevant ranks
132 rankNeighbours = getNeighbourRanksFromCuboidNeighbourhood<T,D,verbose>(
133 superStructure, rank, neighbourhood );
134#endif
135
136 return rankNeighbours;
137}
138
140template<typename T, unsigned D, bool verbose=false>
141std::unordered_set<int> getNeighbourRanks(
142 SuperStructure<T,D>& superStructure, unsigned offset)
143{
144 //Retrive parallization infos
145 const int rank = singleton::mpi().getRank();
146 return getNeighbourRanks<T,D,false>(superStructure, offset, rank);
147}
148
149
150template<typename T, typename PARTICLETYPE>
151std::size_t serializeIcDest( int globiCdest,
152 std::uint8_t* bufferiCandParticle )
153{
154 //Define iC field as FieldArrayD with single entry
156 fieldiC.setField(0, globiCdest);
157 const std::vector<unsigned int> index{0};
158 auto communicatable = ConcreteCommunicatable(fieldiC);
159 //Serialize iC
160 communicatable.serialize(index, bufferiCandParticle);
161 //Return communicatable size
162 return communicatable.size(index);
163}
164
165template<typename T, typename PARTICLETYPE>
166void serializeIcDestAndParticle( int globiCdest,
167 Particle<T,PARTICLETYPE>& particle,
168 std::uint8_t* bufferiCandParticle )
169{
170 //Serialize iC and retrieve particle buffer
171 std::size_t serialSizeField =
172 serializeIcDest<T,PARTICLETYPE>( globiCdest, bufferiCandParticle );
173 std::uint8_t* bufferRawParticle = &bufferiCandParticle[serialSizeField];
174 //Serialize particle
175 particle.serialize(bufferRawParticle);
176}
177
178template<typename T, typename PARTICLETYPE>
179std::size_t deserializeIcDest( int& globiCdest,
180 std::uint8_t* bufferRaw )
181{
182 //Define iC field as FieldArrayD with single entry
184 const std::vector<unsigned int> index{0};
185 auto communicatable = ConcreteCommunicatable(fieldiC);
186 //Deserialice iC
187 communicatable.deserialize(index, bufferRaw);
188 globiCdest = fieldiC.getField(0);
189 //Return communicatable size
190 return communicatable.size(index);
191}
192
193
194template<typename T, typename PARTICLETYPE>
195void deserializeIcDestAndParticle( int& globiCdest,
196 Particle<T,PARTICLETYPE>& particle,
197 std::uint8_t* bufferiCandParticle )
198{
199 //Deserialize iC and retrieve particle buffer
200 std::size_t serialSizeField =
201 deserializeIcDest<T,PARTICLETYPE>(globiCdest,bufferiCandParticle);
202 std::uint8_t* bufferRawParticle = &bufferiCandParticle[serialSizeField];
203 //Deserialize particle
204 particle.deserialize(bufferRawParticle);
205}
206
207
208/*
209 * The function provides a check if the cuboids fit the constraints from the
210 * implementation of the particle parallization
211 */
212template<typename T, typename PARTICLETYPE>
214{
215 constexpr unsigned D = PARTICLETYPE::d;
216 auto& cuboidGeometry = sParticleSystem.getSuperStructure().getCuboidGeometry();
217
218 const T physDeltaX = cuboidGeometry.getMotherCuboid().getDeltaR();
219
220 T maxCircumRadius{0};
222 sParticleSystem,
223 [&](Particle<T, PARTICLETYPE>& particle,
224 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
225 maxCircumRadius = util::max(maxCircumRadius,
226 particles::contact::evalCircumRadius(particle, physDeltaX));
227 });
228#ifdef PARALLEL_MODE_MPI
229 singleton::mpi().reduceAndBcast(maxCircumRadius, MPI_MAX,
230 singleton::mpi().bossId());
231#endif
232
233 int minCuboidExtent{std::numeric_limits<int>::max()};
234 for (int iC=0; iC<cuboidGeometry.getNc(); ++iC){
235 for(unsigned iD=0; iD<D; ++iD){
236 minCuboidExtent = util::min(minCuboidExtent,
237 cuboidGeometry.get(iC).getExtent()[iD]);
238 }
239 }
240#ifdef PARALLEL_MODE_MPI
241 singleton::mpi().reduceAndBcast(minCuboidExtent, MPI_MIN,
242 singleton::mpi().bossId());
243#endif
244
245 // It's enough that one rank checks for an error
246 if (singleton::mpi().getRank() == 0) {
247 OLB_ASSERT(minCuboidExtent*physDeltaX > maxCircumRadius,
248 "At least one cuboid too small so that the currently implemented "
249 "particle parallelization strategy does not work.");
250 }
251}
252
253template<typename T>
254T movePositionToStart(const T position, const T max, const T min)
255{
256 return min + (position - max);
257}
258
259template<typename T>
260T movePositionToEnd(const T position, const T max, const T min)
261{
262 return max - (min - position);
263}
264
265template<typename T>
266T applyPeriodicityToPosition(const bool isPeriodic, T position, const T max, const T min)
267{
268 if(isPeriodic) {
269 if(position < min) {
270 position = movePositionToEnd(position, max, min);
271 }
272 else if(position > max) {
273 position = movePositionToStart(position, max, min);
274 }
275 }
276 return position;
277}
278
279// The following functions use an offset of 0.5 * physDeltaX, because there is
280// a distance of 1 * physDeltaX between the maximal coordinate and minimal coordinate
281
283template<typename T, unsigned D>
285{
286 const T physDeltaX = cuboidGeometry.getMotherCuboid().getDeltaR();
287 return (cuboidGeometry.getMotherCuboid().getOrigin() - 0.5 * physDeltaX);
288
289}
290
292template<typename T, unsigned D>
294 const PhysR<T,D>& min)
295{
296 const T physDeltaX = cuboidGeometry.getMotherCuboid().getDeltaR();
297 return min + physDeltaX * cuboidGeometry.getMotherCuboid().getExtent();
298}
299
301template<typename T, unsigned D>
303 const CuboidGeometry<T,D>& cuboidGeometry,
304 const Vector<bool,D>& periodicity,
305 PhysR<T,D> position)
306{
307 const PhysR<T,D> min = getCuboidMin<T,D>(cuboidGeometry);
308 const PhysR<T,D> max = getCuboidMax<T,D>(cuboidGeometry, min);
309
310 for(unsigned iD=0; iD<D; ++iD) {
311 position[iD] = applyPeriodicityToPosition(periodicity[iD],
312 position[iD], max[iD], min[iD]);
313 }
314
315 return position;
316}
317
319template<typename T, unsigned D>
320bool getCuboid(const CuboidGeometry<T,D>& cuboidGeometry,
321 const Vector<bool,D>& periodicity,
322 const PhysR<T,D>& position, int& iC)
323{
324 PhysR<T,D> newPosition(
325 applyPeriodicityToPosition(cuboidGeometry, periodicity, position));
326 return cuboidGeometry.getC(newPosition, iC);
327}
328
329
330} //namespace communication
331
332} //namespace particles
333
334} //namespace olb
335
336
337#endif
SoA storage for instances of a single FIELD.
auto getField(std::size_t iCell) const
Return copy of FIELD data for cell iCell.
void setField(std::size_t iCell, const FieldD< T, DESCRIPTOR, FIELD > &v)
Set FIELD data at cell iCell.
CuboidGeometry< T, D > & getCuboidGeometry()
Read and write access to cuboid geometry.
LoadBalancer< T > & getLoadBalancer()
Read and write access to the load balancer.
Plain old scalar vector.
Definition vector.h:47
std::size_t deserialize(const std::uint8_t *buffer)
Deserialize data.
Definition particle.h:146
std::size_t serialize(std::uint8_t *buffer) const
Serialize data.
Definition particle.h:141
SuperStructure< T, PARTICLETYPE::d > & getSuperStructure()
void reduceAndBcast(T &reductVal, MPI_Op op, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
Reduction operation, followed by a broadcast.
int getRank() const
Returns the process ID.
T movePositionToEnd(const T position, const T max, const T min)
Definition utilities.h:260
std::size_t serializeIcDest(int globiCdest, std::uint8_t *bufferiCandParticle)
Definition utilities.h:151
std::vector< int > getNeighborCuboids(CuboidGeometry< T, D > &cuboidGeometry, unsigned offset, int globiC)
Get neighbour cuboids.
Definition utilities.h:39
std::unordered_set< int > getNeighbourRanksFromCuboidNeighbourhood(SuperStructure< T, D > &superStructure, int rank, std::map< int, std::vector< int > > neighbourhood)
Get neighbour ranks.
Definition utilities.h:55
Vector< T, D > getCuboidMin(const CuboidGeometry< T, D > &cuboidGeometry)
Returns minimal coordinate of domain for periodic particle boundaries.
Definition utilities.h:284
std::size_t deserializeIcDest(int &globiCdest, std::uint8_t *bufferRaw)
Definition utilities.h:179
bool getCuboid(const CuboidGeometry< T, D > &cuboidGeometry, const Vector< bool, D > &periodicity, const PhysR< T, D > &position, int &iC)
Function returns true if cuboid was found and gives iC.
Definition utilities.h:320
void checkCuboidSizes(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem)
Definition utilities.h:213
void forParticlesInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
std::unordered_set< int > getNeighbourRanks(SuperStructure< T, D > &superStructure, unsigned offset, int rank)
Get neighbour ranks.
Definition utilities.h:113
Vector< T, D > getCuboidMax(const CuboidGeometry< T, D > &cuboidGeometry, const PhysR< T, D > &min)
Returns maximal coordinate of domain for periodic particle boundaries.
Definition utilities.h:293
T movePositionToStart(const T position, const T max, const T min)
Definition utilities.h:254
void deserializeIcDestAndParticle(int &globiCdest, Particle< T, PARTICLETYPE > &particle, std::uint8_t *bufferiCandParticle)
Definition utilities.h:195
T applyPeriodicityToPosition(const bool isPeriodic, T position, const T max, const T min)
Definition utilities.h:266
void serializeIcDestAndParticle(int globiCdest, Particle< T, PARTICLETYPE > &particle, std::uint8_t *bufferiCandParticle)
Definition utilities.h:166
T evalCircumRadius(T const contactDetectionDistance, T const circumRadius, T const epsilon)
constexpr bool isPeriodic(const Vector< bool, D > &periodic)
MpiManager & mpi()
cpu::simd::Pack< T > min(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
Definition pack.h:124
cpu::simd::Pack< T > max(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
Definition pack.h:130
Top level namespace for all of OpenLB.
std::conditional_t< D==2, CuboidGeometry2D< T >, CuboidGeometry3D< T > > CuboidGeometry
Definition aliases.h:47
void evaluateCuboidGeometryNeighbourhood(CuboidGeometry2D< T > &cuboidGeometry, std::map< int, std::vector< int > > &neighbourhood, int offset=0)
Evaluate complete neighbourhood and store in std::map.
bool checkCuboidNeighbourhoodConsistency(std::map< int, std::vector< int > > &neighbourhood, bool correct=false, bool verbose=false)
Consistency check for neighbour retrieval.
#define OLB_ASSERT(COND, MESSAGE)
Definition olbDebug.h:45