OpenLB 1.7
Loading...
Searching...
No Matches
particleCreatorFunctions.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2021 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#ifndef PARTICLE_CREATOR_FUNCTIONS_H
25#define PARTICLE_CREATOR_FUNCTIONS_H
26
27#include <sstream>
28#include <string>
29#include <vector>
30
35#include "particles/particles.h"
36
37namespace olb {
38
39namespace particles {
40
41namespace creators {
42
43template <typename T, unsigned D>
55
56template <typename T, unsigned D>
58 const std::vector<SpawnData<T, D>>& spawnData,
59 const std::function<T(const std::size_t&)>& getParticleVolume)
60{
61 T particleVolume(0);
62 std::size_t pID(0);
63
64 // Use with C++20:
65 //for(std::size_t pID = 0; [[maybe_unused]] const SpawnData<T,D>& entry : spawnData) {
66 for ([[maybe_unused]] const SpawnData<T, D>& entry : spawnData) {
67 particleVolume += getParticleVolume(pID++);
68 }
69 return particleVolume;
70}
71
72template <typename T, unsigned D>
74 const std::vector<SpawnData<T, D>>& spawnData, const T fluidVolume,
75 const std::function<T(const std::size_t&)>& getParticleVolume)
76{
77 return calcParticleVolume(spawnData, getParticleVolume) / fluidVolume;
78}
79
80template <typename T, unsigned D>
82 std::vector<SpawnData<T, D>>& spawnData,
83 const T wantedParticleVolumeFraction, IndicatorF<T, D>& fluidDomain,
84 const T fluidDomainVolume,
85 const std::function<T(const std::size_t&)>& getCircumRadius,
86 const std::function<T(const std::size_t&)>& getParticleVolume)
87{
88 constexpr unsigned maxTries = 1e6;
89
90 OstreamManager clout(std::cout, "ParticleSeeding");
91 //Create randomizer
92 util::Randomizer<T> randomizer;
93
94 std::size_t pID = spawnData.size();
95 unsigned count = 0;
96 T currVolumeOfParticles = calcParticleVolume(spawnData, getParticleVolume);
97 bool isPositionValid;
98
99 const Vector<T, D> extent = fluidDomain.getMax() - fluidDomain.getMin();
100
101 while (currVolumeOfParticles / fluidDomainVolume <
102 wantedParticleVolumeFraction &&
103 count < maxTries) {
104 const T circumRadius = getCircumRadius(pID);
105 isPositionValid = true;
106
107 // Randomize position
108 PhysR<T, D> randomPosition = randomizer.template generate<PhysR<T, D>>();
109 randomPosition *= extent;
110 randomPosition += fluidDomain.getMin();
111
112 // check overlap with other particles
113 std::size_t i = 0;
114 for (const SpawnData<T, D>& entry : spawnData) {
115 const T distanceCenterOfMass = norm(entry.position - randomPosition);
116 if (distanceCenterOfMass <= circumRadius + getCircumRadius(i++)) {
117 ++count;
118 isPositionValid = false;
119 break;
120 }
121 }
122 if (!isPositionValid) {
123 continue;
124 }
125
126 // check overlap with boundaries (should work for convex geometries)
127 // for better results an iteration over the whole volume could be added
129 randomPosition, circumRadius);
130 for (const PhysR<T, D>& pointOnHull : pointsOnHull) {
131 bool isInside;
132 fluidDomain(&isInside, pointOnHull.data());
133 if (!isInside) {
134 isPositionValid = false;
135 break;
136 }
137 }
138
139 if (isPositionValid) {
140 spawnData.push_back(SpawnData<T, D>(
141 randomPosition,
143 count = 0;
144 currVolumeOfParticles += getParticleVolume(pID++);
145 }
146 else {
147 ++count;
148 }
149 }
150 if (count >= maxTries) {
151 clout << "WARNING: Could not set a particle volume fraction of "
152 << wantedParticleVolumeFraction
153 << ", only a particle volume fraction of "
154 << currVolumeOfParticles / fluidDomainVolume << " was possible."
155 << std::endl;
156 }
157
158 return;
159}
160
161template <typename T, unsigned D>
162std::vector<SpawnData<T, D>> setParticles(
163 const T wantedParticleVolumeFraction, IndicatorF<T, D>& fluidDomain,
164 const T fluidDomainVolume,
165 const std::function<T(const std::size_t&)>& getCircumRadius,
166 const std::function<T(const std::size_t&)>& getParticleVolume,
167 const std::function<void(const SpawnData<T, D>&, const std::size_t&)>
168 createParticle)
169{
170 std::vector<SpawnData<T, D>> spawnData;
171 extendSpawnData<T, D>(spawnData, wantedParticleVolumeFraction, fluidDomain,
172 fluidDomainVolume, getCircumRadius, getParticleVolume);
173
174 std::size_t pID = 0;
175 for (const SpawnData<T, D>& entry : spawnData) {
176 createParticle(entry, pID++);
177 }
178
179 return spawnData;
180}
181
182std::vector<std::vector<std::string>>
183readParticlePositions(const std::string& filename)
184{
185 std::vector<std::vector<std::string>> content;
186 std::vector<std::string> row;
187 std::string line, word;
188
189 std::fstream file(filename, std::ios::in);
190 if (file.is_open()) {
191 while (getline(file, line)) {
192 row.clear();
193
194 std::stringstream str(line);
195
196 while (getline(str, word, ';')) {
197 row.push_back(word);
198 }
199 content.push_back(row);
200 }
201 }
202 else {
203 std::cerr << "Could not open the file " << filename << std::endl;
204 }
205
206 return content;
207}
208
209template <typename T, unsigned D>
211 const std::string& filename, const std::vector<SpawnData<T, D>>& spawnData,
212 const std::function<std::string(const std::size_t&)>& evalIdentifier)
213{
214 std::ofstream file;
215 file.open(filename.c_str(), std::ios::trunc);
216 std::size_t pID = 0;
217 for (const SpawnData<T, D>& entry : spawnData) {
218 for (unsigned iD = 0; iD < D; ++iD) {
219 file << std::setprecision(16) << entry.position[iD] << ';';
220 }
221 for (unsigned iD = 0; iD < utilities::dimensions::convert<D>::rotation;
222 ++iD) {
223 file << std::setprecision(16) << entry.angleInDegree[iD] << ';';
224 }
225 file << evalIdentifier(pID++) << std::endl;
226 }
227 file.close();
228}
229
230template <typename T, unsigned D>
231std::vector<SpawnData<T, D>> setParticles(
232 const std::string& filename, const T wantedParticleVolumeFraction,
233 IndicatorF<T, D>& fluidDomain, const T fluidDomainVolume,
234 const std::function<T(const std::size_t&)>& getParticleVolume,
235 const std::function<void(const SpawnData<T, D>&, const std::string&)>
236 createParticle)
237{
238 std::vector<SpawnData<T, D>> spawnData;
239 std::vector<std::vector<std::string>> filecontent =
241 for (const std::vector<std::string>& line : filecontent) {
242 PhysR<T, D> particlePosition;
244 unsigned iD = 0;
245 for (; iD < D; ++iD) {
246 particlePosition[iD] = std::stod(line[iD]);
247 }
248 for (; iD < (D + utilities::dimensions::convert<D>::rotation); ++iD) {
249 particleAngle[iD - D] = std::stod(line[iD]);
250 }
251 SpawnData<T, D> tmpSpawnData(particlePosition, particleAngle);
252 spawnData.push_back(tmpSpawnData);
253 createParticle(tmpSpawnData, line[iD]);
254 }
255
256 return spawnData;
257}
258
259// Should only work if the particles have a similar size
260// otherwise a bigger bounding box might overlap a smaller one without detection
261// (could be improved by using a finer lattice / using much more points to check)
262template <typename T, unsigned D>
264 std::vector<SpawnData<T, D>>& spawnData,
265 const T wantedParticleVolumeFraction, IndicatorF<T, D>& fluidDomain,
266 const T fluidDomainVolume,
267 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
268 getMin,
269 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
270 getMax,
271 const std::function<T(const std::size_t&)>& getParticleVolume)
272{
273 constexpr unsigned maxTries = 1e6;
274 const auto getPoints = [&](const PhysR<T, D>& position,
275 const PhysR<T, D>& min, const PhysR<T, D>& max) {
276 std::vector<PhysR<T, D>> points;
277 if constexpr (D == 3) {
278 points.reserve(9);
279 points.push_back(PhysR<T, D>(min[0], min[1], min[2]));
280 points.push_back(PhysR<T, D>(min[0], min[1], max[2]));
281 points.push_back(PhysR<T, D>(min[0], max[1], min[2]));
282 points.push_back(PhysR<T, D>(min[0], max[1], max[2]));
283 points.push_back(PhysR<T, D>(max[0], min[1], max[2]));
284 points.push_back(PhysR<T, D>(max[0], min[1], min[2]));
285 points.push_back(PhysR<T, D>(max[0], max[1], min[2]));
286 points.push_back(PhysR<T, D>(max[0], max[1], max[2]));
287 }
288 else {
289 points.reserve(5);
290 points.push_back(PhysR<T, D>(min[0], min[1]));
291 points.push_back(PhysR<T, D>(min[0], max[1]));
292 points.push_back(PhysR<T, D>(max[0], min[1]));
293 points.push_back(PhysR<T, D>(max[0], max[1]));
294 }
295 points.push_back(position);
296 return points;
297 };
298
299 OstreamManager clout(std::cout, "ParticleSeeding");
300 //Create randomizer
301 util::Randomizer<T> randomizer;
302
303 std::size_t pID = spawnData.size();
304 unsigned count = 0;
305 T currVolumeOfParticles = calcParticleVolume(spawnData, getParticleVolume);
306 bool isPositionValid;
307
308 const Vector<T, D> extent = fluidDomain.getMax() - fluidDomain.getMin();
309
310 while (currVolumeOfParticles / fluidDomainVolume <
311 wantedParticleVolumeFraction &&
312 count < maxTries) {
313 isPositionValid = true;
314
315 // Randomize position
316 PhysR<T, D> randomPosition = randomizer.template generate<PhysR<T, D>>();
317 randomPosition *= extent;
318 randomPosition += fluidDomain.getMin();
319 const std::vector<PhysR<T, D>> pointsToCheck =
320 getPoints(randomPosition, getMin(pID, randomPosition),
321 getMax(pID, randomPosition));
322
323 // check overlap with other particles
324 for (std::size_t iP = 0; iP < spawnData.size(); ++iP) {
325 const PhysR<T, D> min = getMin(iP, spawnData[iP].position);
326 const PhysR<T, D> max = getMax(iP, spawnData[iP].position);
327
328 for (const PhysR<T, D>& point : pointsToCheck) {
329 /*
330 const int count = std::count(cornerPoints.begin(), cornerPoints.end(), corner);
331 if (count > 1) {
332 clout<< "WARNING: Same point was checked twice during the particle seeding";
333 }
334 */
335
336 bool overlap = true;
337 for (unsigned iD = 0; iD < D; ++iD) {
338 overlap = overlap && min[iD] <= point[iD] && max[iD] >= point[iD];
339 }
340 if (overlap) {
341 isPositionValid = false;
342 break;
343 }
344 }
345
346 if (!isPositionValid) {
347 break;
348 }
349 }
350 if (!isPositionValid) {
351 ++count;
352 continue;
353 }
354
355 // check overlap with boundaries (should work for convex geometries)
356 // for better results an iteration over the whole volume could be added
357 for (const PhysR<T, D>& point : pointsToCheck) {
358 bool isInside;
359 fluidDomain(&isInside, point.data());
360 if (!isInside) {
361 isPositionValid = false;
362 break;
363 }
364 }
365
366 if (isPositionValid) {
367 spawnData.push_back(SpawnData<T, D>(
368 randomPosition,
370 count = 0;
371 currVolumeOfParticles += getParticleVolume(pID++);
372 }
373 else {
374 ++count;
375 }
376 }
377 if (count >= maxTries) {
378 clout << "WARNING: Could not set a particle volume fraction of "
379 << wantedParticleVolumeFraction
380 << ", only a particle volume fraction of "
381 << currVolumeOfParticles / fluidDomainVolume << " was possible."
382 << std::endl;
383 }
384
385 return;
386}
387
388template <typename T, unsigned D>
389std::vector<SpawnData<T, D>> setParticles(
390 const T wantedParticleVolumeFraction, IndicatorF<T, D>& fluidDomain,
391 const T fluidDomainVolume,
392 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
393 getMin,
394 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
395 getMax,
396 const std::function<T(const std::size_t&)>& getParticleVolume,
397 const std::function<void(const SpawnData<T, D>&, const std::size_t&)>
398 createParticle)
399{
400 std::vector<SpawnData<T, D>> spawnData;
401 extendSpawnData<T, D>(spawnData, wantedParticleVolumeFraction, fluidDomain,
402 fluidDomainVolume, getMin, getMax, getParticleVolume);
403
404 for (std::size_t pID = 0; pID < spawnData.size(); ++pID) {
405 createParticle(spawnData[pID], pID);
406 }
407 return spawnData;
408}
409
410template <typename T, unsigned D>
412 std::vector<SpawnData<T, D>>& spawnData,
413 const T wantedParticleVolumeFraction, IndicatorF<T, D>& fluidDomain,
414 const T fluidDomainVolume, const T deltaX, const T contactDetectionDistance,
415 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
416 getMin,
417 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
418 getMax,
419 const std::function<T(const std::size_t&, const SpawnData<T, D>&,
420 const PhysR<T, D>&)>& signedDistanceToParticle,
421 const std::function<T(const std::size_t&)>& getParticleVolume)
422{
423 OstreamManager clout(std::cout, "ParticleSeeding");
424 constexpr unsigned maxTries = 1e6;
425
426 //Create randomizer
427 util::Randomizer<T> randomizer;
428
429 std::size_t pID = spawnData.size();
430 unsigned count = 0;
431 T currVolumeOfParticles = calcParticleVolume(spawnData, getParticleVolume);
432
433 const Vector<T, D> extent = fluidDomain.getMax() - fluidDomain.getMin();
434
435 while (currVolumeOfParticles / fluidDomainVolume <
436 wantedParticleVolumeFraction &&
437 count < maxTries) {
438 bool isPositionValid = true;
439
440 // Randomize position
441 PhysR<T, D> randomPosition = randomizer.template generate<PhysR<T, D>>();
442 randomPosition *= extent;
443 randomPosition += fluidDomain.getMin();
444
445 const PhysR<T, D> min = getMin(pID, randomPosition);
446 const PhysR<T, D> max = getMax(pID, randomPosition);
447 Vector<int, D> start;
448 Vector<int, D> end;
449 for (unsigned iD = 0; iD < D; ++iD) {
450 start[iD] = util::floor(min[iD] / deltaX);
451 end[iD] = util::ceil(max[iD] / deltaX);
452 }
453
454 const auto evalCurrentPosition = [&](const Vector<int, D>& pos,
455 bool& breakLoop) {
456 const PhysR<T, D> physPos = deltaX * pos;
457 if (signedDistanceToParticle(
458 pID,
460 randomPosition,
462 T {0.})),
463 physPos) < contactDetectionDistance) {
464
465 // Check wall intersection
466 if (fluidDomain.signedDistance(physPos) > -contactDetectionDistance) {
467 breakLoop = true;
468 isPositionValid = false;
469 return;
470 }
471
472 // Check intersection with particles
473 for (std::size_t i = 0; i < spawnData.size(); ++i) {
474 if (signedDistanceToParticle(i, spawnData[i], physPos) <
475 contactDetectionDistance) {
476 breakLoop = true;
477 isPositionValid = false;
478 return;
479 }
480 }
481 }
482 };
483
485 evalCurrentPosition);
486
487 if (!isPositionValid) {
488 ++count;
489 }
490 else {
491 spawnData.push_back(SpawnData<T, D>(
492 randomPosition,
494 currVolumeOfParticles += getParticleVolume(pID++);
495 count = 0;
496 }
497 }
498
499 if (count >= maxTries) {
500 clout << "WARNING: Could not set a particle volume fraction of "
501 << wantedParticleVolumeFraction
502 << ", only a particle volume fraction of "
503 << currVolumeOfParticles / fluidDomainVolume << " was possible."
504 << std::endl;
505 }
506
507 return;
508}
509
510template <typename T, unsigned D>
511std::vector<SpawnData<T, D>> setParticles(
512 const T wantedParticleVolumeFraction, IndicatorF<T, D>& fluidDomain,
513 const T fluidDomainVolume, const T deltaX, const T contactDetectionDistance,
514 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
515 getMin,
516 const std::function<PhysR<T, D>(const std::size_t&, const PhysR<T, D>&)>&
517 getMax,
518 const std::function<T(const std::size_t&, const SpawnData<T, D>&,
519 const PhysR<T, D>&)>& signedDistanceToParticle,
520 const std::function<T(const std::size_t&)>& getParticleVolume,
521 const std::function<void(const SpawnData<T, D>&, const std::size_t&)>
522 createParticle)
523
524{
525 std::vector<SpawnData<T, D>> spawnData;
526 extendSpawnData<T, D>(spawnData, wantedParticleVolumeFraction, fluidDomain,
527 fluidDomainVolume, deltaX, contactDetectionDistance,
528 getMin, getMax, signedDistanceToParticle,
529 getParticleVolume);
530
531 for (std::size_t pID = 0; pID < spawnData.size(); ++pID) {
532 createParticle(spawnData[pID], pID);
533 }
534 return spawnData;
535}
536
538// TODO: Needs testing
539template <typename T, typename PARTICLETYPE>
540std::vector<SpawnData<T, PARTICLETYPE::d>>
543#ifdef PARALLEL_MODE_MPI
544 ,
545 MPI_Comm particleCreatorComm = MPI_COMM_WORLD
546#endif
547)
548{
549 using namespace descriptors;
550
551#ifdef PARALLEL_MODE_MPI
552 // Prepare a set of destination ranks from all other ranks
553 // -> every rank will know the position
554 auto& cuboidGeometry = particleSystem.getSuperStructure().getCuboidGeometry();
555 auto& loadBalancer = particleSystem.getSuperStructure().getLoadBalancer();
556 std::unordered_set<int> destRanksSet;
557 for (int iC = 0; iC < cuboidGeometry.getNc(); ++iC) {
558 int rank = loadBalancer.rank(iC);
559 if (rank != singleton::mpi().getRank()) {
560 destRanksSet.insert(rank);
561 }
562 }
563
564 // Preparations
565 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
566 using GENERAL_EVAL =
567 typename PARTICLETYPE ::template derivedField<descriptors::GENERAL>;
568 using POSITION_EVAL =
569 typename GENERAL_EVAL ::template derivedField<descriptors::POSITION>;
570 using SURFACE_EVAL =
571 typename PARTICLETYPE ::template derivedField<descriptors::SURFACE>;
572 using ANGLE_EVAL =
573 typename SURFACE_EVAL ::template derivedField<descriptors::ANGLE>;
574
577 1);
579
580 auto communicatableID = ConcreteCommunicatable(fieldID);
581 auto communicatablePosition = ConcreteCommunicatable(fieldPosition);
582 auto communicatableAngle = ConcreteCommunicatable(fieldAngle);
583 const std::vector<unsigned int> indices {0};
584 const std::size_t serialSize = communicatableID.size(indices) +
585 communicatablePosition.size(indices) +
586 communicatableAngle.size(indices);
587
588 // Obtain data for communication
590 T, PARTICLETYPE,
591 conditions::valid_particle_centres //only consider center for resolved
592 >(particleSystem, [&](Particle<T, PARTICLETYPE>& particle,
593 ParticleSystem<T, PARTICLETYPE>& bParticleSystem,
594 int globiC) {
595 fieldID.setField(0, particle.template getField<PARALLELIZATION, ID>());
596 fieldPosition.setField(0, access::getPosition(particle));
597 fieldAngle.setField(0, access::getAngle(particle));
598 spawnData[fieldID.getField(0)].position = fieldPosition.getField(0);
599 spawnData[fieldID.getField(0)].angleInDegree =
600 util::radianToDegree(fieldAngle.getField(0));
601 for (const int destRank : destRanksSet) {
602 std::unique_ptr<std::uint8_t[]> buffer(new std::uint8_t[serialSize] {});
603 std::uint8_t* bufferRaw = buffer.get();
604 std::size_t serialIdx = communicatableID.serialize(indices, bufferRaw);
605 serialIdx +=
606 communicatablePosition.serialize(indices, &bufferRaw[serialIdx]);
607 serialIdx +=
608 communicatableAngle.serialize(indices, &bufferRaw[serialIdx]);
609 dataMap.insert(std::make_pair(destRank, std::move(buffer)));
610 }
611 });
612
613 //Create non blocking mpi helper
615
616 std::map<int, std::vector<std::uint8_t>> rankDataMapSorted;
617 communication::fillSendBuffer(dataMap, rankDataMapSorted, serialSize);
618
619 // Send mapped data
620 communication::sendMappedData(rankDataMapSorted, destRanksSet, serialSize,
621 particleCreatorComm, mpiNbHelper);
622
623 // Receive positions from all other ranks
625 destRanksSet, serialSize, particleCreatorComm, mpiNbHelper,
626 [&](int rankOrig, std::uint8_t* buffer) {
627 std::size_t serialIdx = communicatableID.deserialize(indices, buffer);
628 serialIdx +=
629 communicatablePosition.deserialize(indices, &buffer[serialIdx]);
630 serialIdx +=
631 communicatableAngle.deserialize(indices, &buffer[serialIdx]);
632
633 spawnData[fieldID.getField(0)].position = fieldPosition.getField(0);
634 spawnData[fieldID.getField(0)].angleInDegree =
635 util::radianToDegree(fieldAngle.getField(0));
636 });
637
638#else
639 for (int i = 0; i < particleSystem.size(); ++i) {
640 spawnData[i].position = access::getPosition(particleSystem.get(i));
641 spawnData[i].angleInDegree =
642 util::radianToDegree(access::getAngle(particleSystem.get(i)));
643 }
644#endif
645
646 return spawnData;
647}
648
649template <typename T, typename PARTICLETYPE>
650std::vector<SpawnData<T, PARTICLETYPE::d>> saveUpdatedParticlePositions(
651 const std::string& filename,
652 const std::vector<SpawnData<T, PARTICLETYPE::d>>& originalSpawnData,
653 const std::function<std::string(const std::size_t&)>& evalIdentifier,
655#ifdef PARALLEL_MODE_MPI
656 ,
657 MPI_Comm particleCreatorComm = MPI_COMM_WORLD
658#endif
659)
660{
661 std::vector<SpawnData<T, PARTICLETYPE::d>> spawnData =
662 updateParticlePositions<T, PARTICLETYPE>(originalSpawnData, particleSystem
663#ifdef PARALLEL_MODE_MPI
664 ,
665 particleCreatorComm
666#endif
667 );
668 saveParticlePositions(filename, spawnData, evalIdentifier);
669 return spawnData;
670}
671
672} //namespace creators
673
674} //namespace particles
675
676} //namespace olb
677
678#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.
class for marking output with some text
Plain old scalar vector.
Definition vector.h:47
Helper class for non blocking MPI communication.
Definition mpiManager.h:51
Vector< T, utilities::dimensions::convert< PARTICLETYPE::d >::rotation > getAngle(Particle< T, PARTICLETYPE > particle)
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 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 forParticlesInSuperParticleSystem(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, F f)
constexpr void forEachPositionWithBreak(Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)
T calcParticleVolumeFraction(const std::vector< SpawnData< T, D > > &spawnData, const T fluidVolume, const std::function< T(const std::size_t &)> &getParticleVolume)
std::vector< SpawnData< T, D > > setParticles(const T wantedParticleVolumeFraction, IndicatorF< T, D > &fluidDomain, const T fluidDomainVolume, const std::function< T(const std::size_t &)> &getCircumRadius, const std::function< T(const std::size_t &)> &getParticleVolume, const std::function< void(const SpawnData< T, D > &, const std::size_t &)> createParticle)
std::vector< SpawnData< T, PARTICLETYPE::d > > saveUpdatedParticlePositions(const std::string &filename, const std::vector< SpawnData< T, PARTICLETYPE::d > > &originalSpawnData, const std::function< std::string(const std::size_t &)> &evalIdentifier, XParticleSystem< T, PARTICLETYPE > &particleSystem, MPI_Comm particleCreatorComm=MPI_COMM_WORLD)
T calcParticleVolume(const std::vector< SpawnData< T, D > > &spawnData, const std::function< T(const std::size_t &)> &getParticleVolume)
void extendSpawnData(std::vector< SpawnData< T, D > > &spawnData, const T wantedParticleVolumeFraction, IndicatorF< T, D > &fluidDomain, const T fluidDomainVolume, const std::function< T(const std::size_t &)> &getCircumRadius, const std::function< T(const std::size_t &)> &getParticleVolume)
std::vector< SpawnData< T, PARTICLETYPE::d > > updateParticlePositions(std::vector< SpawnData< T, PARTICLETYPE::d > > spawnData, XParticleSystem< T, PARTICLETYPE > &particleSystem, MPI_Comm particleCreatorComm=MPI_COMM_WORLD)
Updates particle positions so that they can be easily written to a txt file with the function above.
std::vector< std::vector< std::string > > readParticlePositions(const std::string &filename)
void saveParticlePositions(const std::string &filename, const std::vector< SpawnData< T, D > > &spawnData, const std::function< std::string(const std::size_t &)> &evalIdentifier)
std::conditional_t< PARTICLETYPE::template providesNested< descriptors::PARALLELIZATION >(), SuperParticleSystem< T, PARTICLETYPE >, ParticleSystem< T, PARTICLETYPE > > XParticleSystem
MpiManager & mpi()
decltype(Vector< decltype(util::sqrt(T())), D >()) radianToDegree(const Vector< T, D > &angle)
ADf< T, DIM > ceil(const ADf< T, DIM > &a)
Definition aDiff.h:900
ADf< T, DIM > floor(const ADf< T, DIM > &a)
Definition aDiff.h:869
Top level namespace for all of OpenLB.
constexpr T norm(const ScalarVector< T, D, IMPL > &a)
Euclidean vector norm.
std::conditional_t< D==2, IndicatorF2D< T >, IndicatorF3D< T > > IndicatorF
Definition aliases.h:258
Vector< T, utilities::dimensions::convert< D >::rotation > angleInDegree
SpawnData(const PhysR< T, D > &_position, const Vector< T, utilities::dimensions::convert< D >::rotation > &_angleInDegree)
static constexpr auto calculate(Vector< T, D > position, T radius)
Converts dimensions by deriving from given cartesian dimension D.