OpenLB 1.7
Loading...
Searching...
No Matches
equationsOfMotionResults.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2022 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 * This file contains functions used for the particle-wall and particle-particle communication.
26*/
27
28#ifndef COMMUNICATION_EQUATIONS_OF_MOTION_RESULTS_H
29#define COMMUNICATION_EQUATIONS_OF_MOTION_RESULTS_H
30
31#include <unordered_set>
32
33#include "particles/particles.h"
34
35namespace olb {
36
37namespace particles {
38
39namespace communication {
40
42template <typename T, typename PARTICLECONTACTTYPE, typename WALLCONTACTTYPE>
43std::unordered_set<int>
45 WALLCONTACTTYPE>& contactContainer,
46 const std::size_t globalParticleID)
47{
48 std::unordered_set<int> destRanks;
49
50 for (const PARTICLECONTACTTYPE& contact : contactContainer.particleContacts) {
51 if (
53 (globalParticleID == contact.getIDs()[0] ||
54 globalParticleID == contact.getIDs()[1])) {
55 destRanks.insert(contact.getResponsibleRank());
56 }
57 }
58 for (const WALLCONTACTTYPE& contact : contactContainer.wallContacts) {
59 if (
61 globalParticleID == contact.getParticleID()) {
62 destRanks.insert(contact.getResponsibleRank());
63 }
64 }
65
66 return destRanks;
67}
68
69// Communicate results of equations of motion to blocks on same rank
70template <typename T, typename PARTICLETYPE>
73 const std::size_t& pID, const Vector<T, PARTICLETYPE::d>& position,
74 const Vector<T, PARTICLETYPE::d>& velocity,
76 angle,
78 angVelocity)
79{
80 using namespace descriptors;
81
83 sParticleSystem,
84 [&](Particle<T, PARTICLETYPE>& particle,
85 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
86 const std::size_t currGlobalParticleID =
87 particle.template getField<PARALLELIZATION, ID>();
88
89 if (currGlobalParticleID == pID) {
90 particle.template setField<GENERAL, POSITION>(position);
91 particle.template setField<MOBILITY, VELOCITY>(velocity);
92 particle.template setField<SURFACE, ANGLE>(
94 PARTICLETYPE::d>::serialize_rotation(angle));
95 particle.template setField<MOBILITY, ANG_VELOCITY>(
97 PARTICLETYPE::d>::serialize_rotation(angVelocity));
98 }
99 });
100}
101
102// Communication of results of equation of motion
103#ifdef PARALLEL_MODE_MPI
104template <typename T, typename PARTICLETYPE, typename PARTICLECONTACTTYPE,
105 typename WALLCONTACTTYPE>
109 contactContainer,
110 std::multimap<int, std::unique_ptr<std::uint8_t[]>>& dataMap)
111{
112 using namespace descriptors;
113
114 //Create FieldArrayD for globalID, force and torque
115 using GENERAL_EVAL =
116 typename PARTICLETYPE ::template derivedField<descriptors::GENERAL>;
117 using MOBILITY_EVAL =
118 typename PARTICLETYPE ::template derivedField<descriptors::MOBILITY>;
119 using SURFACE_EVAL =
120 typename PARTICLETYPE ::template derivedField<descriptors::SURFACE>;
121 using POSITION_EVAL =
122 typename GENERAL_EVAL ::template derivedField<descriptors::POSITION>;
123 using VELOCITY_EVAL =
124 typename MOBILITY_EVAL ::template derivedField<descriptors::VELOCITY>;
125 using ANGLE_EVAL =
126 typename SURFACE_EVAL ::template derivedField<descriptors::ANGLE>;
127 using ANGVELOCITY_EVAL =
128 typename MOBILITY_EVAL ::template derivedField<descriptors::ANG_VELOCITY>;
131 1);
133 1);
136 fieldAngVelocity(1);
137
138 //Create communicatables
139 auto communicatableID = ConcreteCommunicatable(fieldID);
140 auto communicatablePosition = ConcreteCommunicatable(fieldPosition);
141 auto communicatableVelocity = ConcreteCommunicatable(fieldVelocity);
142 auto communicatableAngle = ConcreteCommunicatable(fieldAngle);
143 auto communicatableAngVelocity = ConcreteCommunicatable(fieldAngVelocity);
144
145 //Retrieve serial size
146 const std::vector<unsigned int> indices {0};
147 const std::size_t serialSize =
148 communicatableID.size(indices) + communicatablePosition.size(indices) +
149 communicatableVelocity.size(indices) + communicatableAngle.size(indices) +
150 communicatableAngVelocity.size(indices);
151
152 // Fill map with data
154 sParticleSystem,
155 [&](Particle<T, PARTICLETYPE>& particle,
156 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
157 using PCONDITION = std::conditional_t<
158 access::providesSurface<PARTICLETYPE>(),
159 conditions::
160 valid_particle_centres, // only consider center for resolved
161 conditions::valid_particles>; // only consider valid
162
163 if (PCONDITION::value(particle, globiC)) {
164 // Get quantities to package
165 fieldID.setField(0,
166 particle.template getField<PARALLELIZATION, ID>());
167 fieldPosition.setField(0, access::getPosition(particle));
168 fieldVelocity.setField(0, access::getVelocity(particle));
169 fieldAngle.setField(0, access::getAngle(particle));
170 fieldAngVelocity.setField(0, access::getAngularVelocity(particle));
171
173 sParticleSystem,
174 particle.template getField<PARALLELIZATION, ID>(),
175 access::getPosition(particle), access::getVelocity(particle),
176 access::getAngle(particle), access::getAngularVelocity(particle));
177
178 // Evaluate which ranks need to know the data
179 std::unordered_set<int> destRanks {
180 evalDestRanks(contactContainer, fieldID.getField(0))};
181
182 for (const int destRank : destRanks) {
183 std::unique_ptr<std::uint8_t[]> buffer(
184 new std::uint8_t[serialSize] {});
185 std::uint8_t* bufferRaw = buffer.get();
186 std::size_t serialIdx =
187 communicatableID.serialize(indices, bufferRaw);
188 serialIdx += communicatablePosition.serialize(
189 indices, &bufferRaw[serialIdx]);
190 serialIdx += communicatableVelocity.serialize(
191 indices, &bufferRaw[serialIdx]);
192 serialIdx +=
193 communicatableAngle.serialize(indices, &bufferRaw[serialIdx]);
194 serialIdx += communicatableAngVelocity.serialize(
195 indices, &bufferRaw[serialIdx]);
196 dataMap.insert(std::make_pair(destRank, std::move(buffer)));
197 }
198
199#ifdef VERBOSE_CONTACT_COMMUNICATION
200 std::cout << "Rank " << singleton::mpi().getRank()
201 << " sends particle data of ID " << fieldID.getField(0)
202 << " to ";
203 for (const int destRank : destRanks) {
204 std::cout << destRank << " ";
205 }
206 std::cout << std::endl;
207#endif
208 }
209 });
210
211 return serialSize;
212}
213#endif
214
215#ifdef PARALLEL_MODE_MPI
216template <typename T, typename PARTICLETYPE>
219 MPI_Comm equationsOfMotionComm,
221{
222 using namespace descriptors;
223
224 // Retrieve rank of direct neighbours
225 auto& listNeighbourRanks = sParticleSystem.getNeighbourRanks();
226
227 //Create FieldArrayD for globalID, force and torque
228 using GENERAL_EVAL =
229 typename PARTICLETYPE ::template derivedField<descriptors::GENERAL>;
230 using MOBILITY_EVAL =
231 typename PARTICLETYPE ::template derivedField<descriptors::MOBILITY>;
232 using SURFACE_EVAL =
233 typename PARTICLETYPE ::template derivedField<descriptors::SURFACE>;
234 using POSITION_EVAL =
235 typename GENERAL_EVAL ::template derivedField<descriptors::POSITION>;
236 using VELOCITY_EVAL =
237 typename MOBILITY_EVAL ::template derivedField<descriptors::VELOCITY>;
238 using ANGLE_EVAL =
239 typename SURFACE_EVAL ::template derivedField<descriptors::ANGLE>;
240 using ANGVELOCITY_EVAL =
241 typename MOBILITY_EVAL ::template derivedField<descriptors::ANG_VELOCITY>;
244 1);
246 1);
249 fieldAngVelocity(1);
250
251 //Create communicatables
252 auto communicatableID = ConcreteCommunicatable(fieldID);
253 auto communicatablePosition = ConcreteCommunicatable(fieldPosition);
254 auto communicatableVelocity = ConcreteCommunicatable(fieldVelocity);
255 auto communicatableAngle = ConcreteCommunicatable(fieldAngle);
256 auto communicatableAngVelocity = ConcreteCommunicatable(fieldAngVelocity);
257
258 // Retrieve serial size
259 const std::vector<unsigned int> indices {0};
260 const std::size_t serialSize =
261 communicatableID.size(indices) + communicatablePosition.size(indices) +
262 communicatableVelocity.size(indices) + communicatableAngle.size(indices) +
263 communicatableAngVelocity.size(indices);
264
265 // Receive data and iterate buffer
266 // TODO: Improve processing of data, do not iterate through the all particles every time (maybe also add main iC to the communicated data to reduce processed particles)
268 listNeighbourRanks, serialSize, equationsOfMotionComm, mpiNbHelper,
269 [&](int rankOrig, std::uint8_t* buffer) {
270 std::size_t serialIdx = communicatableID.deserialize(indices, buffer);
271 serialIdx +=
272 communicatablePosition.deserialize(indices, &buffer[serialIdx]);
273 serialIdx +=
274 communicatableVelocity.deserialize(indices, &buffer[serialIdx]);
275 serialIdx +=
276 communicatableAngle.deserialize(indices, &buffer[serialIdx]);
277 serialIdx +=
278 communicatableAngVelocity.deserialize(indices, &buffer[serialIdx]);
279
281 sParticleSystem,
282 [&](Particle<T, PARTICLETYPE>& particle,
283 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
284 const std::size_t currentGlobalParticleID =
285 particle.template getField<PARALLELIZATION, ID>();
286 if (fieldID.getField(0) == currentGlobalParticleID) {
287 // Override particle data
288 particle.template setField<GENERAL, POSITION>(
289 fieldPosition.getField(0));
290 particle.template setField<MOBILITY, VELOCITY>(
291 fieldVelocity.getField(0));
292 particle.template setField<SURFACE, ANGLE>(
293 fieldAngle.getField(0));
294 particle.template setField<MOBILITY, ANG_VELOCITY>(
295 fieldAngVelocity.getField(0));
296 }
297 });
298 });
299}
300#endif
301
302template <typename T, typename PARTICLETYPE, typename PARTICLECONTACTTYPE,
303 typename WALLCONTACTTYPE>
307 contactContainer
308#ifdef PARALLEL_MODE_MPI
309 ,
310 MPI_Comm equationsOfMotionComm
311#endif
312)
313{
314 // TODO: Test if it is faster to only send & receive between processors that must exchange data (that way we don't need to synchronize all processors)
315
316#ifdef PARALLEL_MODE_MPI
317 // Create map for data
318 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
319
320 std::size_t serialSize =
321 evalEquationsOfMotionResults(sParticleSystem, contactContainer, dataMap);
322
323 //Create non blocking mpi helper
325
326 std::map<int, std::vector<std::uint8_t>> rankDataMapSorted;
327 communication::fillSendBuffer(dataMap, rankDataMapSorted, serialSize);
328
329 // Send mapped data
330 communication::sendMappedData(rankDataMapSorted,
331 sParticleSystem.getNeighbourRanks(), serialSize,
332 equationsOfMotionComm, mpiNbHelper);
333
334 receiveEquationsOfMotionResults(sParticleSystem, equationsOfMotionComm,
335 mpiNbHelper);
336#endif
337}
338
339} // namespace communication
340
341} // namespace particles
342
343} // namespace olb
344
345#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.
Plain old scalar vector.
Definition vector.h:47
const std::unordered_set< int > & getNeighbourRanks()
int getRank() const
Returns the process ID.
Helper class for non blocking MPI communication.
Definition mpiManager.h:51
Vector< T, PARTICLETYPE::d > getVelocity(Particle< T, PARTICLETYPE > particle)
Vector< T, utilities::dimensions::convert< PARTICLETYPE::d >::rotation > getAngle(Particle< T, PARTICLETYPE > particle)
Vector< T, PARTICLETYPE::d > getPosition(Particle< T, PARTICLETYPE > particle)
Vector< T, utilities::dimensions::convert< PARTICLETYPE::d >::rotation > getAngularVelocity(Particle< T, PARTICLETYPE > particle)
void receiveAndExecuteForData(const std::unordered_set< int > &availableRanks, std::size_t serialSize, MPI_Comm Comm, singleton::MpiNonBlockingHelper &mpiNbHelper, F f)
Definition relocation.h:572
std::size_t evalEquationsOfMotionResults(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap)
void communicateEquationsOfMotionResultsIntra(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const std::size_t &pID, const Vector< T, PARTICLETYPE::d > &position, const Vector< T, PARTICLETYPE::d > &velocity, const Vector< T, utilities::dimensions::convert< PARTICLETYPE::d >::rotation > &angle, const Vector< T, utilities::dimensions::convert< PARTICLETYPE::d >::rotation > &angVelocity)
void communicateEquationsOfMotionResults(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, MPI_Comm equationsOfMotionComm)
void sendMappedData(std::map< int, std::vector< std::uint8_t > > &rankDataMapSorted, const std::unordered_set< int > &availableRanks, const std::size_t serialSize, MPI_Comm Comm, singleton::MpiNonBlockingHelper &mpiNbHelper)
Definition relocation.h:408
void fillSendBuffer(std::multimap< int, std::unique_ptr< std::uint8_t[]> > &rankDataMap, std::map< int, std::vector< std::uint8_t > > &rankDataMapSorted, std::size_t serialSize)
Definition relocation.h:387
std::unordered_set< int > evalDestRanks(contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, const std::size_t globalParticleID)
evaluates ranks that need the new particle data
void receiveEquationsOfMotionResults(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, MPI_Comm equationsOfMotionComm, singleton::MpiNonBlockingHelper &mpiNbHelper)
void forParticlesInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
MpiManager & mpi()
Top level namespace for all of OpenLB.
Converts dimensions by deriving from given cartesian dimension D.