1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "InflationInjection.H"
27 #include "mathematicalConstants.H"
28 #include "PackedBoolList.H"
30 #include "ListListOps.H"
32 using namespace Foam::constant::mathematical;
34 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
36 template<class CloudType>
37 Foam::InflationInjection<CloudType>::InflationInjection
39 const dictionary& dict,
43 InjectionModel<CloudType>(dict, owner, typeName),
44 generationSetName_(this->coeffDict().lookup("generationCellSet")),
45 inflationSetName_(this->coeffDict().lookup("inflationCellSet")),
48 duration_(readScalar(this->coeffDict().lookup("duration"))),
51 DataEntry<scalar>::New
59 DataEntry<scalar>::New
66 volumeAccumulator_(0.0),
68 selfSeed_(this->coeffDict().lookupOrDefault("selfSeed", false)),
72 distributionModels::distributionModel::New
74 this->coeffDict().subDict("sizeDistribution"),
81 dSeed_ = readScalar(this->coeffDict().lookup("dSeed"));
84 cellSet generationCells(this->owner().mesh(), generationSetName_);
86 generationCells_ = generationCells.toc();
88 cellSet inflationCells(this->owner().mesh(), inflationSetName_);
91 inflationCells |= generationCells;
93 inflationCells_ = inflationCells.toc();
95 if (Pstream::parRun())
97 scalar generationVolume = 0.0;
99 forAll(generationCells_, gCI)
101 label cI = generationCells_[gCI];
103 generationVolume += this->owner().mesh().cellVolumes()[cI];
106 scalar totalGenerationVolume = generationVolume;
108 reduce(totalGenerationVolume, sumOp<scalar>());
110 fraction_ = generationVolume/totalGenerationVolume;
113 // Set total volume/mass to inject
114 this->volumeTotal_ = fraction_*flowRateProfile_().integrate(0.0, duration_);
115 this->massTotal_ *= fraction_;
119 template<class CloudType>
120 Foam::InflationInjection<CloudType>::InflationInjection
122 const Foam::InflationInjection<CloudType>& im
125 InjectionModel<CloudType>(im),
126 generationSetName_(im.generationSetName_),
127 inflationSetName_(im.inflationSetName_),
128 generationCells_(im.generationCells_),
129 inflationCells_(im.inflationCells_),
130 duration_(im.duration_),
131 flowRateProfile_(im.flowRateProfile_().clone().ptr()),
132 growthRate_(im.growthRate_().clone().ptr()),
133 newParticles_(im.newParticles_),
134 volumeAccumulator_(im.volumeAccumulator_),
135 fraction_(im.fraction_),
136 selfSeed_(im.selfSeed_),
138 sizeDistribution_(im.sizeDistribution_().clone().ptr())
142 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
144 template<class CloudType>
145 Foam::InflationInjection<CloudType>::~InflationInjection()
149 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
151 template<class CloudType>
152 Foam::scalar Foam::InflationInjection<CloudType>::timeEnd() const
154 return this->SOI_ + duration_;
158 template<class CloudType>
159 Foam::label Foam::InflationInjection<CloudType>::parcelsToInject
165 const polyMesh& mesh = this->owner().mesh();
167 List<DynamicList<typename CloudType::parcelType*> >& cellOccupancy =
168 this->owner().cellOccupancy();
170 scalar gR = growthRate_().value(time1);
172 scalar dT = time1 - time0;
174 // Inflate existing particles
176 forAll(inflationCells_, iCI)
178 label cI = inflationCells_[iCI];
180 typename CloudType::parcelType* pPtr = NULL;
182 forAll(cellOccupancy[cI], cPI)
184 pPtr = cellOccupancy[cI][cPI];
186 scalar dTarget = pPtr->dTarget();
188 pPtr->d() = min(dTarget, pPtr->d() + gR*dT);
192 // Generate new particles
194 newParticles_.clear();
196 cachedRandom& rnd = this->owner().rndGen();
198 // Diameter factor, when splitting particles into 4, this is the
199 // factor that modifies the diameter.
200 scalar dFact = sqrt(2.0)/(sqrt(3.0) + sqrt(2.0));
202 if ((time0 >= 0.0) && (time0 < duration_))
204 volumeAccumulator_ +=
205 fraction_*flowRateProfile_().integrate(time0, time1);
208 labelHashSet cellCentresUsed;
210 // Loop escape counter
211 label maxIterations = max
214 (10*volumeAccumulator_)
215 /CloudType::parcelType::volume(sizeDistribution_().minValue())
218 label iterationNo = 0;
220 // Info<< "Accumulated volume to inject: "
221 // << returnReduce(volumeAccumulator_, sumOp<scalar>()) << endl;
223 while (!generationCells_.empty() && volumeAccumulator_ > 0)
225 if (iterationNo > maxIterations)
230 "Foam::InflationInjection<CloudType>::parcelsToInject"
232 "const scalar time0, "
236 << "Maximum particle split iterations ("
237 << maxIterations << ") exceeded" << endl;
243 generationCells_[rnd.position(0, generationCells_.size() - 1)];
245 // Pick a particle at random from the cell - if there are
246 // none, insert one at the cell centre. Otherwise, split an
247 // existing particle into four new ones.
249 if (cellOccupancy[cI].empty())
251 if (selfSeed_ && !cellCentresUsed.found(cI))
253 scalar dNew = sizeDistribution_().sample();
259 Pair<vector>(mesh.cellCentres()[cI], vector::zero),
260 Pair<scalar>(dSeed_, dNew)
264 volumeAccumulator_ -= CloudType::parcelType::volume(dNew);
266 cellCentresUsed.insert(cI);
271 label cPI = rnd.position(0, cellOccupancy[cI].size() - 1);
273 // This has to be a reference to the pointer so that it
274 // can be set to NULL when the particle is deleted.
275 typename CloudType::parcelType*& pPtr = cellOccupancy[cI][cPI];
279 scalar pD = pPtr->d();
281 // Select bigger particles by preference
282 if ((pD/pPtr->dTarget()) < rnd.sample01<scalar>())
287 const point& pP = pPtr->position();
288 const vector& pU = pPtr->U();
290 // Generate a tetrahedron of new positions with the
291 // four new spheres fitting inside the old one, where
292 // a is the diameter of the new spheres, and is
293 // related to the diameter of the enclosing sphere, A,
294 // by a = sqrt(2)*A/(sqrt(3) + sqrt(2));
296 // Positions around the origin, which is the
297 // tetrahedron centroid (centre of old sphere).
301 // R = sqrt(3)*a/(2*sqrt(2))
311 scalar x = a/sqrt(3.0);
312 scalar r = a/(2.0*sqrt(6.0));
313 scalar R = sqrt(3.0)*a/(2.0*sqrt(2.0));
314 scalar d = a/(2.0*sqrt(3.0));
316 scalar dNew = sizeDistribution_().sample();
317 scalar volNew = CloudType::parcelType::volume(dNew);
323 Pair<vector>(vector(x, 0, -r) + pP, pU),
324 Pair<scalar>(a, dNew)
327 volumeAccumulator_ -= volNew;
329 dNew = sizeDistribution_().sample();
334 Pair<vector>(vector(-d, a/2, -r) + pP, pU),
335 Pair<scalar>(a, dNew)
338 volumeAccumulator_ -= volNew;
340 dNew = sizeDistribution_().sample();
345 Pair<vector>(vector(-d, -a/2, -r) + pP, pU),
346 Pair<scalar>(a, dNew)
349 volumeAccumulator_ -= volNew;
351 dNew = sizeDistribution_().sample();
356 Pair<vector>(vector(0, 0, R) + pP, pU),
357 Pair<scalar>(a, dNew)
360 volumeAccumulator_ -= volNew;
362 // Account for the lost volume of the particle which
364 volumeAccumulator_ += CloudType::parcelType::volume
369 this->owner().deleteParticle(*pPtr);
378 if (Pstream::parRun())
380 List<List<vectorPairScalarPair> > gatheredNewParticles
385 gatheredNewParticles[Pstream::myProcNo()] = newParticles_;
387 // Gather data onto master
388 Pstream::gatherList(gatheredNewParticles);
391 List<vectorPairScalarPair> combinedNewParticles
393 ListListOps::combine<List<vectorPairScalarPair> >
395 gatheredNewParticles,
396 accessOp<List<vectorPairScalarPair> >()
400 if (Pstream::master())
402 newParticles_ = combinedNewParticles;
405 Pstream::scatter(newParticles_);
408 return newParticles_.size();
412 template<class CloudType>
413 Foam::scalar Foam::InflationInjection<CloudType>::volumeToInject
419 if ((time0 >= 0.0) && (time0 < duration_))
421 return fraction_*flowRateProfile_().integrate(time0, time1);
430 template<class CloudType>
431 void Foam::InflationInjection<CloudType>::setPositionAndCell
442 position = newParticles_[parcelI].first().first();
444 this->findCellAtPosition
455 template<class CloudType>
456 void Foam::InflationInjection<CloudType>::setProperties
461 typename CloudType::parcelType& parcel
464 parcel.U() = newParticles_[parcelI].first().second();
466 parcel.d() = newParticles_[parcelI].second().first();
468 parcel.dTarget() = newParticles_[parcelI].second().second();
472 template<class CloudType>
473 bool Foam::InflationInjection<CloudType>::fullyDescribed() const
479 template<class CloudType>
480 bool Foam::InflationInjection<CloudType>::validInjection(const label)
486 // ************************************************************************* //