24#ifndef PARTICLE_CREATOR_FUNCTIONS_H
25#define PARTICLE_CREATOR_FUNCTIONS_H
43template <
typename T,
unsigned D>
56template <
typename T,
unsigned D>
59 const std::function<T(
const std::size_t&)>& getParticleVolume)
67 particleVolume += getParticleVolume(pID++);
69 return particleVolume;
72template <
typename T,
unsigned D>
75 const std::function<T(
const std::size_t&)>& getParticleVolume)
80template <
typename T,
unsigned D>
84 const T fluidDomainVolume,
85 const std::function<T(
const std::size_t&)>& getCircumRadius,
86 const std::function<T(
const std::size_t&)>& getParticleVolume)
88 constexpr unsigned maxTries = 1e6;
94 std::size_t pID = spawnData.size();
99 const Vector<T, D> extent = fluidDomain.getMax() - fluidDomain.getMin();
101 while (currVolumeOfParticles / fluidDomainVolume <
102 wantedParticleVolumeFraction &&
104 const T circumRadius = getCircumRadius(pID);
105 isPositionValid =
true;
108 PhysR<T, D> randomPosition = randomizer.template generate<PhysR<T, D>>();
109 randomPosition *= extent;
110 randomPosition += fluidDomain.getMin();
115 const T distanceCenterOfMass =
norm(entry.position - randomPosition);
116 if (distanceCenterOfMass <= circumRadius + getCircumRadius(i++)) {
118 isPositionValid =
false;
122 if (!isPositionValid) {
129 randomPosition, circumRadius);
130 for (
const PhysR<T, D>& pointOnHull : pointsOnHull) {
132 fluidDomain(&isInside, pointOnHull.data());
134 isPositionValid =
false;
139 if (isPositionValid) {
144 currVolumeOfParticles += getParticleVolume(pID++);
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."
161template <
typename T,
unsigned D>
164 const T fluidDomainVolume,
165 const std::function<T(
const std::size_t&)>& getCircumRadius,
166 const std::function<T(
const std::size_t&)>& getParticleVolume,
170 std::vector<SpawnData<T, D>> spawnData;
171 extendSpawnData<T, D>(spawnData, wantedParticleVolumeFraction, fluidDomain,
172 fluidDomainVolume, getCircumRadius, getParticleVolume);
176 createParticle(entry, pID++);
182std::vector<std::vector<std::string>>
185 std::vector<std::vector<std::string>> content;
186 std::vector<std::string> row;
187 std::string line, word;
189 std::fstream file(filename, std::ios::in);
190 if (file.is_open()) {
191 while (getline(file, line)) {
194 std::stringstream str(line);
196 while (getline(str, word,
';')) {
199 content.push_back(row);
203 std::cerr <<
"Could not open the file " << filename << std::endl;
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)
215 file.open(filename.c_str(), std::ios::trunc);
218 for (
unsigned iD = 0; iD < D; ++iD) {
219 file << std::setprecision(16) << entry.position[iD] <<
';';
221 for (
unsigned iD = 0; iD < utilities::dimensions::convert<D>::rotation;
223 file << std::setprecision(16) << entry.angleInDegree[iD] <<
';';
225 file << evalIdentifier(pID++) << std::endl;
230template <
typename T,
unsigned D>
232 const std::string& filename,
const T wantedParticleVolumeFraction,
234 const std::function<T(
const std::size_t&)>& getParticleVolume,
238 std::vector<SpawnData<T, D>> spawnData;
239 std::vector<std::vector<std::string>> filecontent =
241 for (
const std::vector<std::string>& line : filecontent) {
245 for (; iD < D; ++iD) {
246 particlePosition[iD] = std::stod(line[iD]);
249 particleAngle[iD - D] = std::stod(line[iD]);
252 spawnData.push_back(tmpSpawnData);
253 createParticle(tmpSpawnData, line[iD]);
262template <
typename T,
unsigned D>
266 const T fluidDomainVolume,
271 const std::function<T(
const std::size_t&)>& getParticleVolume)
273 constexpr unsigned maxTries = 1e6;
274 const auto getPoints = [&](
const PhysR<T, D>& position,
276 std::vector<PhysR<T, D>> points;
277 if constexpr (D == 3) {
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]));
295 points.push_back(position);
303 std::size_t pID = spawnData.size();
306 bool isPositionValid;
308 const Vector<T, D> extent = fluidDomain.getMax() - fluidDomain.getMin();
310 while (currVolumeOfParticles / fluidDomainVolume <
311 wantedParticleVolumeFraction &&
313 isPositionValid =
true;
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));
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);
337 for (
unsigned iD = 0; iD < D; ++iD) {
338 overlap = overlap && min[iD] <= point[iD] && max[iD] >= point[iD];
341 isPositionValid =
false;
346 if (!isPositionValid) {
350 if (!isPositionValid) {
359 fluidDomain(&isInside, point.data());
361 isPositionValid =
false;
366 if (isPositionValid) {
371 currVolumeOfParticles += getParticleVolume(pID++);
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."
388template <
typename T,
unsigned D>
391 const T fluidDomainVolume,
396 const std::function<T(
const std::size_t&)>& getParticleVolume,
400 std::vector<SpawnData<T, D>> spawnData;
401 extendSpawnData<T, D>(spawnData, wantedParticleVolumeFraction, fluidDomain,
402 fluidDomainVolume, getMin, getMax, getParticleVolume);
404 for (std::size_t pID = 0; pID < spawnData.size(); ++pID) {
405 createParticle(spawnData[pID], pID);
410template <
typename T,
unsigned D>
414 const T fluidDomainVolume,
const T deltaX,
const T contactDetectionDistance,
421 const std::function<T(
const std::size_t&)>& getParticleVolume)
424 constexpr unsigned maxTries = 1e6;
429 std::size_t pID = spawnData.size();
433 const Vector<T, D> extent = fluidDomain.getMax() - fluidDomain.getMin();
435 while (currVolumeOfParticles / fluidDomainVolume <
436 wantedParticleVolumeFraction &&
438 bool isPositionValid =
true;
441 PhysR<T, D> randomPosition = randomizer.template generate<PhysR<T, D>>();
442 randomPosition *= extent;
443 randomPosition += fluidDomain.getMin();
445 const PhysR<T, D> min = getMin(pID, randomPosition);
446 const PhysR<T, D> max = getMax(pID, randomPosition);
449 for (
unsigned iD = 0; iD < D; ++iD) {
457 if (signedDistanceToParticle(
463 physPos) < contactDetectionDistance) {
466 if (fluidDomain.signedDistance(physPos) > -contactDetectionDistance) {
468 isPositionValid =
false;
473 for (std::size_t i = 0; i < spawnData.size(); ++i) {
474 if (signedDistanceToParticle(i, spawnData[i], physPos) <
475 contactDetectionDistance) {
477 isPositionValid =
false;
485 evalCurrentPosition);
487 if (!isPositionValid) {
494 currVolumeOfParticles += getParticleVolume(pID++);
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."
510template <
typename T,
unsigned D>
513 const T fluidDomainVolume,
const T deltaX,
const T contactDetectionDistance,
520 const std::function<T(
const std::size_t&)>& getParticleVolume,
525 std::vector<SpawnData<T, D>> spawnData;
526 extendSpawnData<T, D>(spawnData, wantedParticleVolumeFraction, fluidDomain,
527 fluidDomainVolume, deltaX, contactDetectionDistance,
528 getMin, getMax, signedDistanceToParticle,
531 for (std::size_t pID = 0; pID < spawnData.size(); ++pID) {
532 createParticle(spawnData[pID], pID);
539template <
typename T,
typename PARTICLETYPE>
540std::vector<SpawnData<T, PARTICLETYPE::d>>
543#ifdef PARALLEL_MODE_MPI
545 MPI_Comm particleCreatorComm = MPI_COMM_WORLD
549 using namespace descriptors;
551#ifdef PARALLEL_MODE_MPI
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);
560 destRanksSet.insert(rank);
565 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
567 typename PARTICLETYPE ::template derivedField<descriptors::GENERAL>;
568 using POSITION_EVAL =
569 typename GENERAL_EVAL ::template derivedField<descriptors::POSITION>;
571 typename PARTICLETYPE ::template derivedField<descriptors::SURFACE>;
573 typename SURFACE_EVAL ::template derivedField<descriptors::ANGLE>;
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);
595 fieldID.
setField(0, particle.template getField<PARALLELIZATION, ID>());
599 spawnData[fieldID.
getField(0)].angleInDegree =
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);
606 communicatablePosition.serialize(indices, &bufferRaw[serialIdx]);
608 communicatableAngle.serialize(indices, &bufferRaw[serialIdx]);
609 dataMap.insert(std::make_pair(destRank, std::move(buffer)));
616 std::map<int, std::vector<std::uint8_t>> rankDataMapSorted;
621 particleCreatorComm, mpiNbHelper);
625 destRanksSet, serialSize, particleCreatorComm, mpiNbHelper,
626 [&](
int rankOrig, std::uint8_t* buffer) {
627 std::size_t serialIdx = communicatableID.deserialize(indices, buffer);
629 communicatablePosition.deserialize(indices, &buffer[serialIdx]);
631 communicatableAngle.deserialize(indices, &buffer[serialIdx]);
634 spawnData[fieldID.
getField(0)].angleInDegree =
639 for (
int i = 0; i < particleSystem.size(); ++i) {
641 spawnData[i].angleInDegree =
649template <
typename T,
typename PARTICLETYPE>
651 const std::string& filename,
653 const std::function<std::string(
const std::size_t&)>& evalIdentifier,
655#ifdef PARALLEL_MODE_MPI
657 MPI_Comm particleCreatorComm = MPI_COMM_WORLD
661 std::vector<SpawnData<T, PARTICLETYPE::d>> spawnData =
662 updateParticlePositions<T, PARTICLETYPE>(originalSpawnData, particleSystem
663#ifdef PARALLEL_MODE_MPI
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
Helper class for non blocking MPI communication.
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)
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)
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)
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
decltype(Vector< decltype(util::sqrt(T())), D >()) radianToDegree(const Vector< T, D > &angle)
ADf< T, DIM > ceil(const ADf< T, DIM > &a)
ADf< T, DIM > floor(const ADf< T, DIM > &a)
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
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.