OpenLB 1.7
Loading...
Searching...
No Matches
relocation.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2022 Nicolas Hafen, 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_RELOCATION_H
26#define PARTICLE_RELOCATION_H
27
30
31//Increase verbosity for further development
32//#define VERBOSE_COMMUNICATION
33
34namespace olb {
35
36namespace particles {
37
38namespace communication {
39
40//Update surface pointer by considering SURFACE_ID
41template<typename T, typename PARTICLETYPE>
43 ParticleSystem<T,PARTICLETYPE>& particleSystem, std::size_t iP )
44{
45 using namespace descriptors;
46 static_assert(PARTICLETYPE::template providesNested<SURFACE,SURFACE_ID>(), "Field SURFACE_ID has to be provided");
47 //Retrieve particle
48 auto particle = particleSystem.get(iP);
49 //Retrieve surface id
50 std::size_t idxSurface = particle.template getField<SURFACE,SURFACE_ID>();
51 //Retrieve surface ptr
52 using SIndicatorBaseType = SmoothIndicatorF<T,T,PARTICLETYPE::d,true>;
53 auto& vectorOfIndicators = particleSystem.template getAssociatedData<
54 std::vector<std::unique_ptr<SIndicatorBaseType>>>();
55 auto sIndicatorPtr = vectorOfIndicators.at( idxSurface ).get();
56 //Update particle
57 particle.template setField<SURFACE,SINDICATOR>( sIndicatorPtr );
58}
59
60//Attach serialized particle
61//TODO: Change dynamics treatement, as those cannot be serialized
62template<typename T, typename PARTICLETYPE>
64 ParticleSystem<T,PARTICLETYPE>& particleSystem,
65 std::uint8_t rawBuffer[])
66{
67 //Extend particle container
68 auto& particleContainer = particleSystem.get();
69 particleContainer.push_back();
70 //Retrieve new particle
71 std::size_t idxParticleNew = particleSystem.size()-1;
72 auto particleNew = particleSystem.get(idxParticleNew);
73 //Deserialise particle
74 int globiCdest;
75 deserializeIcDestAndParticle(globiCdest,particleNew,rawBuffer);
76 //Update surface pointer
77 if constexpr( access::providesSurface<PARTICLETYPE>() ){
78 updateSurfacePtr( particleSystem, idxParticleNew );
79 }
80 return particleNew.getId();
81}
82
83//Insert serialized particle at specific idxParticle
84template<typename T, typename PARTICLETYPE>
86 ParticleSystem<T,PARTICLETYPE>& particleSystem,
87 std::size_t idxParticle,
88 std::uint8_t rawBuffer[])
89{
90 using namespace descriptors;
91 //Retrieve particle
92 auto particle = particleSystem.get(idxParticle);
93
94#ifdef VERBOSE_COMMUNICATION
95 auto globiCcentreLast = particle.template getField<PARALLELIZATION,IC>();
96#endif
97
98 //Deserialise particle
99 int globiCdest;
100 deserializeIcDestAndParticle(globiCdest,particle,rawBuffer);
101
102#ifdef VERBOSE_COMMUNICATION
103 auto globiCcentre = particle.template getField<PARALLELIZATION,IC>();
104
105 if(globiCcentre!=globiCcentreLast){
106 int rank = singleton::mpi().getRank();
107 std::cout << std::endl << "[Particle] "
108 << "CENTRE SWITCH("
109 << globiCcentreLast << "->" << globiCcentre << ")"
110 << " at receiving at iC=" << "X"
111 << "(rank=" << rank << ")" << std::endl;
112 }
113#endif
114
115
116 //Update surface pointer
117 if constexpr( access::providesSurface<PARTICLETYPE>() ){
118 updateSurfacePtr( particleSystem, idxParticle );
119 }
120 return particle.getId();
121}
122
123
124
125
126//Attach serializes particle to new ParticleSystem
127template<typename T, typename PARTICLETYPE>
129 ParticleSystem<T,PARTICLETYPE>& particleSystem,
130 std::uint8_t* rawBuffer )
131{
132 using namespace descriptors;
133
134 std::size_t particleID;
135 //Check whether resolved (or subgrid)
136 //- subgrid has to be appended always, as valid particle data will not
137 // be present on new core due to previous direct invalidation
138 //- TODO: Check consistency, as for now, invalidated slots are considered
139 // for resolved, but not for sub grid particles
140 if constexpr( access::providesSurface<PARTICLETYPE>() ){
141 //Attach serialized particle (either at end or at existing index)
142 if (particleSystem.size()==0){
143 particleID = appendSerializedParticle( particleSystem, rawBuffer );
144 } else {
145 //Create temporary particle system to retrieve global id
146 ParticleSystem<T,PARTICLETYPE> particleSystemTmp(1);
147 auto particleTmp = particleSystemTmp.get(0);
148 int globiCdummy;
149 deserializeIcDestAndParticle(globiCdummy,particleTmp,rawBuffer);
150 std::size_t globalID = particleTmp.template getField<PARALLELIZATION,ID>();
151 //Check whether particle already existing
152 // -! Lambda-expression unavailable due to break command
153 bool found=false;
154 //Loop over particles
155 //- including invalid slots, as they are revalidated
156 // anyways when inserting particle data)
157 for (std::size_t iP=0; iP<particleSystem.size(); ++iP){
158 auto particle = particleSystem.get(iP);
159 auto globalIDiP = particle.template getField<PARALLELIZATION,ID>();
160 if (globalIDiP==globalID){
161 particleID = insertSerializedParticle( particleSystem, iP, rawBuffer );
162 found=true;
163 break;
164 }
165 }
166 if (!found){
167 particleID = appendSerializedParticle( particleSystem, rawBuffer );
168 }
169 }
170 } else { //if constexpr ( access::providesSurface<PARTICLETYPE>() )
171 //Attach serialized particle
172 particleID = appendSerializedParticle( particleSystem, rawBuffer );
173 }
174 return particleID;
175}
176
177
178//Prepare inter relocation or intra relocation
179//-inter: separate iCs on different cores
180//-intra: separate iCs on same core
181template<typename T, typename PARTICLETYPE>
184 Particle<T,PARTICLETYPE>& particle,
185 int globiC, int globiCdest,
186 std::multimap<int,std::unique_ptr<std::uint8_t[]>>& rankDataMapRelocationInter,
187 std::vector<std::unique_ptr<std::uint8_t[]>>& dataListRelocationIntra,
188 std::size_t serialSize )
189{
190 //Retrieve loadBalancer
191 auto& loadBalancer = sParticleSystem.getSuperStructure().getLoadBalancer();
192 //Create buffer pointer
193 std::unique_ptr<std::uint8_t[]> buffer(new std::uint8_t[serialSize]{ });
194
195 //Serialize particle content into buffer
196 serializeIcDestAndParticle( globiCdest, particle, buffer.get() );
197
198 //Check, whether iCs are on same core
199 int rank = singleton::mpi().getRank();
200 int rankDest = loadBalancer.rank(globiCdest);
201 if (rank != rankDest){
202 //Add rank-buffer pair to rankDataMapRelocationInter
203 rankDataMapRelocationInter.insert(std::make_pair(rankDest, std::move(buffer)));
204 } else {
205 //If on same core location can be done without mpi
206 dataListRelocationIntra.push_back(std::move(buffer));
207 } //else (rank != rankDest)
208
209#ifdef VERBOSE_COMMUNICATION
210 auto globalID = particle.template getField<
212 std::cout << std::endl << "[Particle] SENDING";
213 if (rank != rankDest){ std::cout << "(inter)"; } else { std::cout << "(intra)"; }
214 std::cout << " Particle"
215 << "(globalID=" << globalID << ") "
216 << "from iC" << globiC << "(rank=" << rank << ") to iC"
217 << globiCdest << "(rank=" << rankDest << ")" << std::endl;
218 particle.template print<true>();
219#endif
220}
221
222
223//Check relocation of discrete surface elements (resolved only)
224template<typename T, typename PARTICLETYPE>
227 const T physDeltaX,
228 Particle<T,PARTICLETYPE>& particle, int globiC,
229 std::multimap<int,std::unique_ptr<std::uint8_t[]>>& rankDataMapRelocationInter,
230 std::vector<std::unique_ptr<std::uint8_t[]>>& dataListRelocationIntra,
231 std::size_t serialSize, const Vector<bool, PARTICLETYPE::d>& periodicity )
232{
233 //Retrieve cuboid geometry
234 /* auto& superStructure = sParticleSystem.getSuperStructure(); */
235 /* auto& cuboidGeometry = superStructure.getCuboidGeometry(); */
236 //Retrieve position and circumRadius
237 auto position = access::getPosition( particle );
238 const T circumRadius = contact::evalCircumRadius(particle, physDeltaX);
239 const int globiCcentre = particle.template getField<descriptors::PARALLELIZATION,descriptors::IC>();
240 //Get unique iCs on surface and prepare relocation
241 getSurfaceTouchingICs(sParticleSystem, position, circumRadius, periodicity, globiCcentre,
242 [&](const int globiCdest){
243 prepareRelocation( sParticleSystem, particle, globiC, globiCdest,
244 rankDataMapRelocationInter, dataListRelocationIntra, serialSize);
245 });
246}
247
248//Check whether relocation necessary
249//Also differentiate between inter- and intra-core relocation
250//Also check domain exit
251template<typename T, typename PARTICLETYPE>
254 const T physDeltaX,
255 std::multimap<int,std::unique_ptr<std::uint8_t[]>>& rankDataMapRelocationInter,
256 std::vector<std::unique_ptr<std::uint8_t[]>>& dataListRelocationIntra,
257 std::size_t serialSize, const Vector<bool, PARTICLETYPE::d>& periodicity )
258{
259 using namespace descriptors;
260 using namespace particles::access;
261 constexpr unsigned D = PARTICLETYPE::d;
262
263 //Retrieve load balancer and cuboid geometry
264 auto& superStructure = sParticleSystem.getSuperStructure();
265 auto& cuboidGeometry = superStructure.getCuboidGeometry();
266
267 //Loop over valid particles
268 forParticlesInSuperParticleSystem( sParticleSystem,
269 [&](Particle<T,PARTICLETYPE>& particle,
270 ParticleSystem<T,PARTICLETYPE>& particleSystem, int globiC){
271
272 //Retrieve centre iC in previous timestep.
273 //- used to detect iC change
274 //- unly updated for resolved particles
275 int globiCcentreLast= -1;
276 if constexpr( providesSurface<PARTICLETYPE>() ){
277 globiCcentreLast = particle.template getField<PARALLELIZATION,IC>();
278 }
279 // Retrieve and update particle position
280 // if a periodic setup is used and the particle is out of bounds
281 const PhysR<T,D> position = applyPeriodicityToPosition(cuboidGeometry,
282 periodicity, particle.template getField<GENERAL,POSITION>());
283 //Find particle system by position
284 int globiCcentre = -1;
285 // getC doesn't treat periodicity! We can only use it because we updated it before
286 const bool particleCentreInDomain = cuboidGeometry.getC(position, globiCcentre);
287 /*
288 // Retrieve particle position
289 PhysR<T,D> position = particle.template getField<GENERAL,POSITION>();
290 //Find particle system by position
291 int globiCcentre = -1;
292 const bool particleCentreInDomain = getCuboid(
293 cuboidGeometry, periodicity, position, globiCcentre);
294 */
295 // Replace the position with the updated position
296 // if no periodicity is used or the particle isn't out of bounds nothing happens
297 // (must be here, because it can be that the particle remains on the same block after crossing the boundary)
298 // TODO: Add constexpr check if the setup is periodic or not before continuously overwriting the position here
299 particle.template setField<GENERAL, POSITION>(position);
300 /*if(isPeriodic(periodicity)) {
301 const PhysR<T,D> min = getCuboidMin<T,D>(cuboidGeometry);
302 const PhysR<T,D> max = getCuboidMax<T,D>(cuboidGeometry, min);
303
304 for(unsigned iD=0; iD<D; ++iD) {
305 position[iD] = applyPeriodicityToPosition(
306 periodicity[iD], position[iD], max[iD], min[iD]);
307 }
308 particle.template setField<GENERAL, POSITION>(position);
309 }*/
310
311 //Update iC, if resolved
312 if constexpr( providesSurface<PARTICLETYPE>() ){
313 particle.template setField<PARALLELIZATION,IC>(globiCcentre);
314 }
315
316 //Check whether particle has lost the global domain
317 if (particleCentreInDomain){
318 //Check whether particle centre resides in current iC
319 //If yes:
320 //- subgrid: no data to be sent
321 //- resolved: check surface
322 if (globiCcentre == globiC){
323 //Check, whether surface parts have to be sent (resolved only)
324 if constexpr( providesSurface<PARTICLETYPE>() ){
325 checkSurfaceRelocation( sParticleSystem, physDeltaX, particle, globiC,
326 rankDataMapRelocationInter, dataListRelocationIntra, serialSize, periodicity );
327 }
328 //If particle centre does not reside in iC
329 } else { // if (globiCcentre == globiC)
330 //Differentiate between resolved and subgrid treatment
331 if constexpr( providesSurface<PARTICLETYPE>() ){
332
333 //Detect center switch
334 //- to send data one last time
335 //- necessary, since new responsible iC can only send at next timestep
336 if(globiCcentre!=globiCcentreLast){
337#ifdef VERBOSE_COMMUNICATION
338 int rank = singleton::mpi().getRank();
339 std::cout << std::endl << "[Particle] "
340 << "CENTRE SWITCH("
341 << globiCcentreLast << "->" << globiCcentre << ")"
342 << " at sending from iC=" << globiC
343 << "(rank=" << rank << ")" << std::endl;
344#endif
345 //Prepare inter relocation or intra relocation
346 //-here: to new responsible ic
347 prepareRelocation( sParticleSystem,
348 particle, globiC, globiCcentre,
349 rankDataMapRelocationInter, dataListRelocationIntra, serialSize);
350
351 if constexpr( providesSurface<PARTICLETYPE>() ){
352 //Sending to self, to avoid invalidation on receiving
353 //- necessary, as responsibility changed
354 prepareRelocation( sParticleSystem,
355 particle, globiCcentre, globiC,
356 rankDataMapRelocationInter, dataListRelocationIntra, serialSize);
357
358 //Check, whether surface parts have to be sent (resolved only)
359 checkSurfaceRelocation( sParticleSystem, physDeltaX, particle, globiC,
360 rankDataMapRelocationInter, dataListRelocationIntra, serialSize, periodicity );
361 }
362
363 } //if(globiCcentre!=globiCcentreLast)
364 } else { //if constexpr( providesSurface<PARTICLETYPE>() )
365 //Prepare inter relocation or intra relocation
366 prepareRelocation( sParticleSystem,
367 particle, globiC, globiCcentre,
368 rankDataMapRelocationInter, dataListRelocationIntra, serialSize);
369 //Immediate invalidation (subgrid only)
370 particle.template setField<GENERAL,INVALID>(true);
371 }
372 } // else (globiCcentre == globiC)
373 } else { //particleCentreInDomain
374 //Invalidate particle
375 particle.template setField<GENERAL,INVALID>(true);
376 //Output warning
377 int rank = singleton::mpi().getRank();
378 auto globalID = particle.template getField<PARALLELIZATION,ID>();
379 std::cout << ">>>> WARNING: Particle " << globalID
380 << " lost domain at iC="<< globiC
381 << " (rank=" << rank << ") <<<<" << std::endl;
382 }
383 }); // forParticlesInSuperParticleSystem
384}
385
386//Fill send buffer with data in rankDataMap (particle agnostic)
388 std::multimap<int,std::unique_ptr<std::uint8_t[]>>& rankDataMap,
389 std::map<int, std::vector<std::uint8_t>>& rankDataMapSorted,
390 std::size_t serialSize )
391{
392 //Iterate over rank data pairs
393 for (auto& rankDataPair : rankDataMap) {
394 //Decompose pair
395 int rankDest = rankDataPair.first;
396 std::uint8_t* buffer = rankDataPair.second.get();
397 //Write data to sorted map
398 // - creates vector via 3-arg initializer list
399 rankDataMapSorted[rankDest].insert(
400 rankDataMapSorted[rankDest].end(),
401 buffer,
402 buffer + serialSize );
403 }
404}
405
406#ifdef PARALLEL_MODE_MPI
407//Send data for inter-core relocation (particle agnostic)
409 std::map<int, std::vector<std::uint8_t> >& rankDataMapSorted,
410 const std::unordered_set<int>& availableRanks,
411 const std::size_t serialSize,
412 MPI_Comm Comm,
414{
415 //Create map with vector holding individual data (of type std::uint8_t)
416 //Iterate over available ranks and retrieve total number of ranks taking part in communication
417 int noRelevantRanks = availableRanks.size();
418 //Check whether any rank is taking part in communication
419 //Allocate mpi requests for relevant ranks
420 mpiNbHelper.allocate(noRelevantRanks);
421 //Iterate over ranks with index iRank
422 int iRank = 0;
423 for (int rankEval : availableRanks) {
424 //Send data via mpi
425 singleton::mpi().iSend<std::uint8_t>(
426 rankDataMapSorted[rankEval].data(), //buffer: pointer to rank section in rankDataMapSorted
427 rankDataMapSorted[rankEval].size(), //count: number of bytes (per rank)
428 rankEval, //dest: destination rank
429 &mpiNbHelper.get_mpiRequest()[iRank], //request: request for iRank (iterator for relevant ranks)
430 1, //tag
431 Comm); //MPI_Comm scope
432 iRank += 1;
433 }
434}
435#endif
436
437//Check wheter invalidation needed on receival
438//General Idea:
439// - Invalidate surface parts, when no information was received from
440// responsible iC
441template<typename T, typename PARTICLETYPE>
444 std::vector<std::vector<std::size_t>>& receivedLocalIDs,
445 const Vector<bool,PARTICLETYPE::d>& periodicity )
446{
447 using namespace descriptors;
448
449 //Retrieve load balancer
450 auto& superStructure = sParticleSystem.getSuperStructure();
451 auto& loadBalancer = superStructure.getLoadBalancer();
452
453 //Loop over valid surfaces and check, whether any data was received
454 forParticlesInSuperParticleSystem<T,PARTICLETYPE,conditions::valid_particle_surfaces>(
455 sParticleSystem,
456 [&](Particle<T,PARTICLETYPE>& particle,
457 ParticleSystem<T,PARTICLETYPE>& particleSystem, int globiC){
458
459 //Retrieve local iC
460 int lociC = loadBalancer.loc(globiC);
461
462 //Retrieve local particle iD
463 std::size_t locId = particle.getId();
464
465#ifdef VERBOSE_COMMUNICATION
466 std::cout << "ReceivedLocalIDs:";
467 for (int i=0; i<receivedLocalIDs[lociC].size(); ++i){
468 auto idPrint = receivedLocalIDs[lociC][i];
469 std::cout << idPrint;
470 if (i<receivedLocalIDs.size()){ std::cout << ","; }
471 }
472 std::cout << std::endl;
473#endif
474
475 //Check wether particle belongs to those having received data (here, if not found)
476 if( std::find(receivedLocalIDs[lociC].begin(),receivedLocalIDs[lociC].end(),
477 locId) == receivedLocalIDs[lociC].end()){
478 //Invalidate particle
479 particle.template setField<GENERAL,INVALID>(true);
480
481#ifdef VERBOSE_COMMUNICATION
482 int rank = singleton::mpi().getRank();
483 std::size_t globalID = particle.template getField<PARALLELIZATION,ID>();
484 std::cout << std::endl << "[Particle] "
485 << "INVALIDATING Particle"
486 << "(globalID=" << globalID << ") "
487 << "on iC" << globiC << "(rank=" << rank << ")" << std::endl;
488 particle.template print<true>();
489#endif
490
491 } // if( std::find() )
492 /* else { */
493 /* // Check if the current block still touches the surface, if not then invalidate the particle */
494 /* auto& cuboidGeometry = superStructure.getCuboidGeometry(); */
495 /* const T physDeltaX = cuboidGeometry.getMotherCuboid().getDeltaR(); */
496 /* const T circumRadius = contact::evalCircumRadius(particle, physDeltaX); */
497 /* const int globiCcenter = particle.template getField<PARALLELIZATION, IC>(); */
498 /* bool touchesSurface = false; */
499 /* communication::getSurfaceTouchingICs( */
500 /* sParticleSystem, access::getPosition(particle), circumRadius, periodicity, globiCcenter, */
501 /* [&](int surfaceTouchingGlobiC){ */
502 /* if(surfaceTouchingGlobiC == globiC) { */
503 /* touchesSurface = true; */
504 /* } */
505 /* }); */
506 /* if(!touchesSurface) { */
507 /* particle.template setField<GENERAL,INVALID>(true); */
508 /* } */
509 /* } */
510 }); //forParticlesInSuperParticleSystem<T,PARTICLETYPE,valid_particle_surfaces>
511}
512
513
514//Assign particle to destination iC
515//- Both inter and intra relocation
516template<typename T, typename PARTICLETYPE>
519 std::vector<std::vector<std::size_t>>& receivedLocalIDs,
520 int rankOrig,
521 std::uint8_t* rawBuffer )
522{
523 using namespace descriptors;
524
525 //Deserialize globiCdest
526 int globiCdest;
527 deserializeIcDest<T,PARTICLETYPE>( globiCdest,rawBuffer );
528
529 //Loop over ParticleSystems in SuperParticleSystem
530 forSystemsInSuperParticleSystem( sParticleSystem,
531 [&](ParticleSystem<T,PARTICLETYPE>& particleSystem, int iC,
532 int globiC){
533
534 if (globiC == globiCdest){
535
536 //Attach serialized particle to new particleSystem
537 [[maybe_unused]] std::size_t particleID =
539 particleSystem, rawBuffer);
540
541 //Add local particle iD to list (resolved only)
542 if constexpr( access::providesSurface<PARTICLETYPE>() ){
543 receivedLocalIDs[iC].push_back(particleID);
544 }
545
546#ifdef VERBOSE_COMMUNICATION
547 int rank = singleton::mpi().getRank();
548 auto particle = particleSystem.get(particleID);
549 std::size_t globalID = particle.template getField<PARALLELIZATION,ID>();
550 std::cout << std::endl << "[Particle] RECEIVING";
551 if (rankOrig != rank){ std::cout << "(inter)"; } else { std::cout << "(intra)"; }
552 std::cout << " Particle"
553 << "(globalID=" << globalID << ") "
554 << "from iC" << "X" << "(rank=" << rankOrig << ") to iC"
555 << globiCdest << "(rank=" << rank << ")" << std::endl;
556 particle.template print<true>();
557#endif
558
559 } //if (globiC == globiCdest)
560 }); //forSystemsInSuperParticleSystem
561}
562
563
564
565
566#ifdef PARALLEL_MODE_MPI
567
568
569//For received data (particle agnostic)
570//WARNING: Expects a message (potentially empty) from all availableRanks
571template<typename F>
573 const std::unordered_set<int>& availableRanks,
574 std::size_t serialSize,
575 MPI_Comm Comm,
577 F f )
578{
579 //Iterate available ranks
580 for (int rankOrig : availableRanks) {
581 //Probe whether incomming data on rank
582 std::size_t noBytesReceived = singleton::mpi().probeReceiveSize(rankOrig, MPI_BYTE, 1, Comm);
583 //Create receive buffer as vector
584 std::vector<std::uint8_t> recv_buffer(noBytesReceived);
585#ifdef VERBOSE_COMMUNICATION
586 int rank = singleton::mpi().getRank();
587 std::cout << "Serial(rank=" << rank << "): "
588 << "noBytesToBeReceived=" << noBytesReceived << "; " << std::endl;
589#endif
590 //Receive data via mpi
591 singleton::mpi().receive<std::uint8_t>(
592 recv_buffer.data(),
593 noBytesReceived,
594 rankOrig,
595 1,
596 Comm);
597 //Loop over bytes in chunks of serialSize
598 for (unsigned iByte=0; iByte < noBytesReceived; iByte += serialSize) {
599 //Define raw buffer
600 std::uint8_t* rawBuffer = &recv_buffer[iByte];
601 //Execute passed function
602 f( rankOrig, rawBuffer );
603#ifdef VERBOSE_COMMUNICATION
604 int rank = singleton::mpi().getRank();
605 std::cout << "Serial(rank=" << rank << "): "
606 << "noBytesReceived=" << noBytesReceived << "; "
607 << "iByte=" << iByte << std::endl;
608#endif
609 //assignParticleToIC( sParticleSystem, receivedLocalIDs, rankOrig, rawBuffer );
610 } // for (int iByte=0; iByte<noBytesReceived; iByte+=serialSize)
611 } // for (auto rankOrig : availableRanks)
612 singleton::mpi().waitAll(mpiNbHelper);
613 //Free mpi helper
614 mpiNbHelper.free();
615}
616
617
618
619//Recieve particles
620template<typename T, typename PARTICLETYPE>
623 std::vector<std::unique_ptr<std::uint8_t[]>>& dataListRelocationIntra,
624 std::size_t serialSize,
625 MPI_Comm particleDistributionComm,
627 const Vector<bool,PARTICLETYPE::d>& periodicity )
628{
629 using namespace particles::access;
630
631 //Retrieve load balancer and cuboid geometry
632 auto& superStructure = sParticleSystem.getSuperStructure();
633 auto& loadBalancer = superStructure.getLoadBalancer();
634
635 //Create list of local particle iDs to check afterwards,
636 // whether data was received (resolved only)
637 std::vector<std::vector<std::size_t>> receivedLocalIDs(
638 loadBalancer.size());
639
640 //Intra core relocations (without MPI)
641 for ( auto& buffer : dataListRelocationIntra ){
642 //Define raw buffer
643 std::uint8_t* rawBuffer = buffer.get();
644 int rankOrig = singleton::mpi().getRank();
645 assignParticleToIC( sParticleSystem, receivedLocalIDs, rankOrig, rawBuffer );
646 }
647
648 //Retrieve neighbour ranks
649 auto& listNeighbourRanks = sParticleSystem.getExtendedNeighbourRanks();
650 //Iterate over inter core received particle data
651 receiveAndExecuteForData( listNeighbourRanks, serialSize,
652 particleDistributionComm, mpiNbHelper,
653 [&](int rankOrig, std::uint8_t* rawBuffer){
654 //Assign particle to destination iC
655 assignParticleToIC( sParticleSystem, receivedLocalIDs, rankOrig, rawBuffer );
656 });
657
658 //Check, whether invalidation nccessary
659 if constexpr( providesSurface<PARTICLETYPE>() ){
660 checkInvalidationOnReceival( sParticleSystem, receivedLocalIDs, periodicity );
661 }
662}
663#endif
664
665//Update particle cuboid distribution
666template<typename T, typename PARTICLETYPE>
669 const T physDeltaX,
670#ifdef PARALLEL_MODE_MPI
671 MPI_Comm particleDistributionComm,
672#endif
673 const Vector<bool,PARTICLETYPE::d>& periodicity
674 )
675{
676 //Retrieve serial size
677 std::size_t serialSize = sParticleSystem.getSerialSize();
678
679 //Increase serial size by Field holding the globiC of the destination
680 // - for that, using FieldArrayD with single entry
681 //TODO: Optimization possible here:
682 // - Necessary for resolved particles
683 // - Not necessary for subgrid: This could be exchanged by on-rank retrieval
684 // of the ic depending on particle position. This would lead to a reduction
685 // in buffer size, which will most likely speed up communication significantly.
686 // A separate treatment will however be very error prone.
688 const ConstSpan<unsigned> index(0, 1);
689 // Workaround for Clang argument deduction bug
690 auto communicatable = ConcreteCommunicatable(fieldiC);
691 std::size_t serialSizeField = communicatable.size(index);
692 serialSize += serialSizeField;
693
694 //Check rankDataMapRelocationInter necessity and create relocation map TODO: adapt description
695 std::multimap<int,std::unique_ptr<std::uint8_t[]>> rankDataMapRelocationInter;
696 std::vector<std::unique_ptr<std::uint8_t[]>> dataListRelocationIntra;
697 checkRelocation( sParticleSystem, physDeltaX, rankDataMapRelocationInter,
698 dataListRelocationIntra, serialSize, periodicity );
699
700#ifdef PARALLEL_MODE_MPI
701
702 //Create non blocking mpi helper
704
705 //Retrieve rank of direct neighbours
706 auto& listNeighbourRanks = sParticleSystem.getExtendedNeighbourRanks();
707
708 //Create ranDataMapSorted (WARNING: has to be existent until all data is received! c.f. #290)
709 std::map<int, std::vector<std::uint8_t> > rankDataMapSorted;
710
711 //Fill send buffer
712 fillSendBuffer( rankDataMapRelocationInter, rankDataMapSorted, serialSize );
713
714 //Send particles in rankDataMapRelocationInter map via mpi().iSend and return global number of bytes
715 sendMappedData( rankDataMapSorted, listNeighbourRanks,
716 serialSize, particleDistributionComm, mpiNbHelper );
717
718 //Receive particles via mpi().receive
719 receiveParticles( sParticleSystem, dataListRelocationIntra,
720 serialSize, particleDistributionComm, mpiNbHelper, periodicity );
721
722#else
723 std::cerr
724 << "ERROR: Invalidation treatement for sequential runs not implemented yet!"
725 << std::endl;
726 throw;
727#endif
728
729}
730
731#ifdef PARALLEL_MODE_MPI
732
733template<typename DATA>
734void collectDataAndAppendVector( std::vector<DATA>& dataVector,
735 std::unordered_set<int>& availableRanks,
737 MPI_Comm commGroup = MPI_COMM_WORLD)
738{
739 DATA data;
740 auto communicatable = ConcreteCommunicatable(data);
741 const int serialSize = communicatable.size();
742 //Receive data
743 receiveAndExecuteForData( availableRanks,
744 serialSize, commGroup, mpiNbHelper,
745 [&](int rankOrig, std::uint8_t* rawBuffer){
746 //Deserialize buffer
747 communicatable.deserialize( rawBuffer );
748 //Append data to std::vector
749 dataVector.push_back(data);
750 });
751}
752
753#endif
754
755
756} //namespace communication
757
758} //namespace particles
759
760} //namespace olb
761
762
763#endif
SoA storage for instances of a single FIELD.
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
auto & get()
Expose container.
constexpr std::size_t size()
Size of ParticleSystem.
std::size_t getId() const
Return memory ID of the currently represented particle.
Definition particle.hh:67
SuperStructure< T, PARTICLETYPE::d > & getSuperStructure()
const std::unordered_set< int > & getExtendedNeighbourRanks()
void iSend(T *buf, int count, int dest, MPI_Request *request, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Sends data at *buf, non blocking.
int getRank() const
Returns the process ID.
std::size_t probeReceiveSize(int source, MPI_Datatype type, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Probe size of incoming message.
void waitAll(MpiNonBlockingHelper &mpiNbHelper)
Complete a series of non-blocking MPI operations.
void receive(T *buf, int count, int source, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Receives data at *buf, blocking.
Helper class for non blocking MPI communication.
Definition mpiManager.h:51
void allocate(unsigned i)
Allocates memory.
MPI_Request * get_mpiRequest(int i=0) const
Get the specified request object.
Vector< T, PARTICLETYPE::d > getPosition(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
void forSystemsInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
std::size_t insertSerializedParticle(ParticleSystem< T, PARTICLETYPE > &particleSystem, std::size_t idxParticle, std::uint8_t rawBuffer[])
Definition relocation.h:85
void assignParticleToIC(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::vector< std::vector< std::size_t > > &receivedLocalIDs, int rankOrig, std::uint8_t *rawBuffer)
Definition relocation.h:517
void collectDataAndAppendVector(std::vector< DATA > &dataVector, std::unordered_set< int > &availableRanks, singleton::MpiNonBlockingHelper &mpiNbHelper, MPI_Comm commGroup=MPI_COMM_WORLD)
Definition relocation.h:734
std::unordered_set< int > getSurfaceTouchingICs(CuboidGeometry< T, D > &cuboidGeometry, Vector< T, D > position, T circumRadius, const Vector< bool, D > &periodicity, int globiC, F f=[](int){})
Get a set of surface touching iCs (that are not globiC) Allows to run an optional function per unique...
void updateParticleCuboidDistribution(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T physDeltaX, MPI_Comm particleDistributionComm, const Vector< bool, PARTICLETYPE::d > &periodicity)
Definition relocation.h:667
std::size_t appendSerializedParticle(ParticleSystem< T, PARTICLETYPE > &particleSystem, std::uint8_t rawBuffer[])
Definition relocation.h:63
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
void updateSurfacePtr(ParticleSystem< T, PARTICLETYPE > &particleSystem, std::size_t iP)
Definition relocation.h:42
void checkInvalidationOnReceival(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::vector< std::vector< std::size_t > > &receivedLocalIDs, const Vector< bool, PARTICLETYPE::d > &periodicity)
Definition relocation.h:442
void receiveParticles(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::vector< std::unique_ptr< std::uint8_t[]> > &dataListRelocationIntra, std::size_t serialSize, MPI_Comm particleDistributionComm, singleton::MpiNonBlockingHelper &mpiNbHelper, const Vector< bool, PARTICLETYPE::d > &periodicity)
Definition relocation.h:621
void forParticlesInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
void prepareRelocation(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, Particle< T, PARTICLETYPE > &particle, int globiC, int globiCdest, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &rankDataMapRelocationInter, std::vector< std::unique_ptr< std::uint8_t[]> > &dataListRelocationIntra, std::size_t serialSize)
Definition relocation.h:182
std::size_t attachSerializedParticle(ParticleSystem< T, PARTICLETYPE > &particleSystem, std::uint8_t *rawBuffer)
Definition relocation.h:128
void checkRelocation(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T physDeltaX, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &rankDataMapRelocationInter, std::vector< std::unique_ptr< std::uint8_t[]> > &dataListRelocationIntra, std::size_t serialSize, const Vector< bool, PARTICLETYPE::d > &periodicity)
Definition relocation.h:252
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
void checkSurfaceRelocation(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T physDeltaX, Particle< T, PARTICLETYPE > &particle, int globiC, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &rankDataMapRelocationInter, std::vector< std::unique_ptr< std::uint8_t[]> > &dataListRelocationIntra, std::size_t serialSize, const Vector< bool, PARTICLETYPE::d > &periodicity)
Definition relocation.h:225
T evalCircumRadius(T const contactDetectionDistance, T const circumRadius, T const epsilon)
MpiManager & mpi()
Top level namespace for all of OpenLB.
std::conditional_t< D==2, SmoothIndicatorF2D< T, T, PARTICLE >, SmoothIndicatorF3D< T, T, PARTICLE > > SmoothIndicatorF
Definition aliases.h:278