OpenLB 1.7
Loading...
Searching...
No Matches
vortexMethod.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2022 Fedor Bukreev, Adrian Kummerlaender
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 BOUNDARIES_VORTEX_METHOD_H
25#define BOUNDARIES_VORTEX_METHOD_H
26
28
29namespace olb {
30
31struct VortexMethodPreProcessor;
32struct VortexMethodPostProcessor;
33
34struct U_PROFILE : public descriptors::FIELD_BASE<0,1> { };
35struct VELOCITY_OLD : public descriptors::FIELD_BASE<0,1> { };
36
39
40struct SEEDS_COUNT : public descriptors::TYPED_FIELD_BASE<std::size_t,1> { };
41struct SEEDS : public descriptors::TEMPLATE_FIELD_BASE<std::add_pointer_t,0,1> { };
42struct SEEDS_VORTICITY : public descriptors::TEMPLATE_FIELD_BASE<std::add_pointer_t,1> { };
43
44struct AXIS_DIRECTION : public descriptors::FIELD_BASE<0,1> { };
45struct SIGMA : public descriptors::FIELD_BASE<1> { };
46
47namespace stage {
48
49struct VortexMethod { };
50
51}
52
53template <typename T, typename DESCRIPTOR>
55private:
56 FunctorPtr<SuperIndicatorF3D<T>> _inletLatticeI;
57 FunctorPtr<IndicatorF3D<T>> _inletPhysI;
58 std::shared_ptr<AnalyticalF3D<T,T>> _profileF;
59
62
63 const int _nSeeds;
64 int _nTime;
65 T _inletArea;
66 T _sigma;
67 T _intensity;
68
69 Vector<T,3> _axisDirection;
70
71 std::vector<T> _AiC;
72 std::vector<int> _NiC;
73
76
77 void generateSeeds();
78 void updateSeedsVorticity(std::size_t iT);
79
80public:
82 FunctorPtr<SuperIndicatorF3D<T>>&& inletLatticeI,
83 FunctorPtr<IndicatorF3D<T>>&& inletPhysI,
86 int nSeeds,
87 int nTime,
88 T sigma,
89 T intensity,
90 Vector<T,3> axisDirection);
91
92 void setProfile(std::shared_ptr<AnalyticalF3D<T,T>> profileF);
93
94 void apply(std::size_t iT);
95
96};
97
98template <typename T, typename DESCRIPTOR>
100 FunctorPtr<SuperIndicatorF3D<T>>&& inletLatticeI,
101 FunctorPtr<IndicatorF3D<T>>&& inletPhysI,
104 int nSeeds,
105 int nTime,
106 T sigma,
107 T intensity,
108 Vector<T,3> axisDirection)
109 : _inletLatticeI(std::move(inletLatticeI)),
110 _inletPhysI(std::move(inletPhysI)),
111 _converter(converter),
112 _sLattice(sLattice),
113 _nSeeds(nSeeds),
114 _nTime(nTime),
115 _sigma(sigma),
116 _intensity(intensity),
117 _axisDirection(axisDirection),
118 _AiC(_sLattice.getLoadBalancer().size()),
119 _NiC(_sLattice.getLoadBalancer().size()),
120 _seeds(sLattice.getCuboidGeometry(),
121 sLattice.getLoadBalancer()),
122 _seedsVorticity(sLattice.getCuboidGeometry(),
123 sLattice.getLoadBalancer())
124{
125 OstreamManager clout(std::cout, "VortexMethod");
126
127 sLattice.template addPostProcessor<stage::VortexMethod>(*_inletLatticeI,
129 SuperIndicatorLayer3D<T> extendedLatticeInletI(*_inletLatticeI);
130 sLattice.template addPostProcessor<stage::VortexMethod>(extendedLatticeInletI,
132
133 if (_sigma < _converter.getPhysDeltaX()) {
134 _sigma = _converter.getPhysDeltaX();
135 }
136
137 _inletArea = 0.;
138
139 auto& cGeometry = sLattice.getCuboidGeometry();
140 Cuboid3D<T> indicatorCuboid(*inletPhysI, _converter.getPhysDeltaX());
141
142 auto& load = _sLattice.getLoadBalancer();
143 for (int iC=0; iC < load.size(); ++iC) {
144 _AiC[iC] = 0.;
145 auto& cuboid = cGeometry.get(load.glob(iC));
146 if (cuboid.checkInters(indicatorCuboid)) {
147 auto& block = _sLattice.getBlock(iC);
148 for (int iX=0; iX < block.getNx(); ++iX) {
149 for (int iY=0; iY < block.getNy(); ++iY) {
150 for (int iZ=0; iZ < block.getNz(); ++iZ) {
151 int latticeR[3] {iX, iY, iZ};
152 T physR[3] { };
153 cuboid.getPhysR(physR, latticeR);
154 block.get(iX,iY,iZ).template setField<descriptors::LOCATION>(physR);
155 bool inInlet{};
156 _inletPhysI(&inInlet, physR);
157 if (inInlet) {
158 _AiC[iC] += util::pow(_converter.getPhysDeltaX(), 2.);
159 }
160 }
161 }
162 }
163 }
164 _inletArea += _AiC[iC];
165 }
166
167 #ifdef PARALLEL_MODE_MPI
168 singleton::mpi().reduceAndBcast(_inletArea, MPI_SUM);
169 #endif
170
171 clout << "inletArea=" << _inletArea << std::endl;
172
173 // initial seeding of random vortex points of number N
174 for (int iC=0; iC < load.size(); ++iC) {
175 _NiC[iC] = int(_nSeeds*_AiC[iC] / _inletArea);
176 _seeds.getBlock(iC).resize(_NiC[iC]);
177 _seedsVorticity.getBlock(iC).resize(_NiC[iC]);
178 }
179
180 for (int iC=0; iC < load.size(); ++iC) {
181 if (_NiC[iC] > 0) {
182 auto& block = _sLattice.getBlock(iC);
183 block.template setParameter<SEEDS_COUNT>(_NiC[iC]);
184 block.template setParameter<SEEDS>(_seeds.getBlock(iC));
185 block.template setParameter<SEEDS_VORTICITY>(_seedsVorticity.getBlock(iC));
186 block.template getField<VELOCITY_OLD>();
187 block.template getField<U_PROFILE>();
188 }
189 }
190
191 _sLattice.template setParameter<CONVERSION_FACTOR_LENGTH>(_converter.getConversionFactorLength());
192 _sLattice.template setParameter<CONVERSION_FACTOR_VELOCITY>(_converter.getConversionFactorVelocity());
193 _sLattice.template setParameter<SIGMA>(_sigma);
194 _sLattice.template setParameter<AXIS_DIRECTION>(axisDirection);
195
196 _sLattice.setProcessingContext(ProcessingContext::Simulation);
197}
198
199
200// random points seed each time step
201template <typename T, typename DESCRIPTOR>
203{
204 std::random_device seed;
205 std::mt19937 generator(seed());
206 std::uniform_real_distribution<T> distribution(0, 1);
207 auto randomness = [&distribution,&generator]() -> T {
208 return distribution(generator);
209 };
210
211 auto& load = _sLattice.getLoadBalancer();
212 for (int iC=0; iC < load.size(); ++iC) {
213 auto& seeds = _seeds.getBlock(iC);
214 if (_NiC[iC] > 0) {
215 #ifdef PARALLEL_MODE_OMP
216 #pragma omp parallel for schedule(static)
217 #endif
218 for (int j = 0; j < _NiC[iC]; j++) {
219 auto seed = _inletPhysI->getSample(randomness);
220 seeds.set(j, seed);
221 }
222 seeds.setProcessingContext(ProcessingContext::Simulation);
223 }
224 }
225}
226
227// vorticity calculation
228template <typename T, typename DESCRIPTOR>
229void VortexMethodTurbulentVelocityBoundary<T,DESCRIPTOR>::updateSeedsVorticity(std::size_t iT)
230{
231 std::random_device rd;
232 std::mt19937 gen(rd());
233 std::uniform_int_distribution<> distrib(-1, 1);
234 auto& load = _sLattice.getLoadBalancer();
235 for (int iC=0; iC < load.size(); ++iC) {
236 if (_NiC[iC] > 0) {
237 auto& seeds = _seeds.getBlock(iC);
238 auto& seedsVorticity = _seedsVorticity.getBlock(iC);
239 #ifdef PARALLEL_MODE_OMP
240 #pragma omp parallel for schedule(static)
241 #endif
242 for(int i = 0; i<_NiC[iC]; i++) {
243 Vector<T,3> inlet = seeds.get(i);
244 Vector<T,3> velocity;
245 _profileF->operator()(velocity.data(), inlet.data());
246 T normVel = olb::norm(velocity);
247 T kinE = 3./2. * util::pow(normVel * _intensity, 2. );
248 T vorticity = 4. * util::sqrt( M_PI * _AiC[iC] * kinE / 3. / _NiC[iC] / (2.*util::log(3.) - 3.*util::log(2.)) );
249
250 // random vorticity sign change
251 T sign = 1.;
252 T tau = _nTime * _sigma / normVel;
253 if(iT == _converter.getLatticeTime(tau)) {
254 sign *= distrib(gen);
255 }
256 vorticity *= sign;
257
258 seedsVorticity.set(i,vorticity);
259 }
260 seedsVorticity.setProcessingContext(ProcessingContext::Simulation);
261 }
262 }
263}
264
265template <typename T, typename DESCRIPTOR>
267{
268 _profileF = profileF;
269 _sLattice.template defineField<U_PROFILE>(*_inletLatticeI, *_profileF);
270 //_sLattice.template setProcessingContext<Array<U_PROFILE>>(ProcessingContext::Simulation);
271}
272
273template <typename T, typename DESCRIPTOR>
275{
276 generateSeeds();
277 updateSeedsVorticity(iT);
278
279 {
280 auto& load = _sLattice.getLoadBalancer();
281 for (int iC=0; iC < load.size(); ++iC) {
282 if (_NiC[iC] > 0) {
283 auto& block = _sLattice.getBlock(iC);
284 block.template setParameter<SEEDS_COUNT>(_NiC[iC]);
285 block.template setParameter<SEEDS>(_seeds.getBlock(iC));
286 block.template setParameter<SEEDS_VORTICITY>(_seedsVorticity.getBlock(iC));
287 }
288 }
289 _sLattice.template setParameter<SIGMA>(_sigma);
290 _sLattice.template setParameter<AXIS_DIRECTION>(_axisDirection);
291 }
292 _sLattice.executePostProcessors(stage::VortexMethod{});
293}
294
295
299 SEEDS,
304 SIGMA
305 >;
306
308
309 int getPriority() const {
310 return 0;
311 }
312
313 template <typename CELL, typename PARAMETERS, typename V=typename CELL::value_t>
315 {
316 const V dx = parameters.template get<CONVERSION_FACTOR_LENGTH>();
317 Vector<V,3> actVel = cell.template getField<VELOCITY_OLD>();
318 V aXPlus = util::max(actVel[0], 0); V aXMinus = util::min(actVel[0], 0);
319 V aYPlus = util::max(actVel[1], 0); V aYMinus = util::min(actVel[1], 0);
320 V aZPlus = util::max(actVel[2], 0); V aZMinus = util::min(actVel[2], 0);
321 Vector<V,3> uXPlus = cell.neighbor({ 1, 0, 0}).template getField<VELOCITY_OLD>();
322 Vector<V,3> uXMinus = cell.neighbor({-1, 0, 0}).template getField<VELOCITY_OLD>();
323 Vector<V,3> uYPlus = cell.neighbor({ 0, 1, 0}).template getField<VELOCITY_OLD>();
324 Vector<V,3> uYMinus = cell.neighbor({ 0, -1, 0}).template getField<VELOCITY_OLD>();
325 Vector<V,3> uZPlus = cell.neighbor({ 0, 0, 1}).template getField<VELOCITY_OLD>();
326 Vector<V,3> uZMinus = cell.neighbor({ 0, 0, -1}).template getField<VELOCITY_OLD>();
327 Vector<V,3> grad;
328 const V actVelNorm = olb::norm(actVel);
329 grad[0] = -aXPlus*(actVelNorm - olb::norm(uXMinus))/dx - aXMinus*(olb::norm(uXPlus) - actVelNorm)/dx;
330 grad[1] = -aYPlus*(actVelNorm - olb::norm(uYMinus))/dx - aYMinus*(olb::norm(uYPlus) - actVelNorm)/dx;
331 grad[2] = -aZPlus*(actVelNorm - olb::norm(uZMinus))/dx - aZMinus*(olb::norm(uZPlus) - actVelNorm)/dx;
332 return grad;
333 }
334
335 template <typename CELL, typename PARAMETERS>
336 void apply(CELL& cell, PARAMETERS& parameters) any_platform {
337 using V = typename CELL::value_t;
338 using DESCRIPTOR = typename CELL::descriptor_t;
339
340 const auto seeds = parameters.template get<SEEDS>();
341 const auto seedsVorticity = parameters.template get<SEEDS_VORTICITY>();
342 const auto axisDirection = parameters.template get<AXIS_DIRECTION>();
343 const auto sigma = parameters.template get<SIGMA>();
344
345 Vector<V,DESCRIPTOR::d> x = cell.template getField<descriptors::LOCATION>();
346 Vector<V,DESCRIPTOR::d> output = cell.template getField<U_PROFILE>();
347 const V conversionFactorVelocity = parameters.template get<CONVERSION_FACTOR_VELOCITY>();
348 output /= conversionFactorVelocity;
349
350 // calculation of velocities from the placed vortexes
351 Vector<V,3> uVortex {0, 0, 0};
352 for (std::size_t j=0; j < parameters.template get<SEEDS_COUNT>(); ++j) {
353 Vector<V,DESCRIPTOR::d> diffX = {0,0,0};
354 for (int iD = 0; iD < DESCRIPTOR::d; ++iD) {
355 diffX[iD] = seeds[iD][j] - x[iD];
356 }
357 Vector<V,3> crossP = crossProduct3D(diffX, axisDirection);
358 V norm2 = diffX[0]*diffX[0] + diffX[1]*diffX[1] + diffX[2]*diffX[2];
359 V expTerm = util::exp(V{-0.5}*norm2/(sigma*sigma));
360 uVortex += (V{0.5}/M_PI * seedsVorticity[j] * crossP / norm2 * (V{1} - expTerm)*expTerm) / conversionFactorVelocity;
361 }
362
363 // calculation of the fluctuation streamwise with Langevin equation
364 auto grad = computeVelocityGradient(cell, parameters);
365 V normGrad = olb::norm(grad);
366 if (normGrad == V{0}) {
367 normGrad = 1;
368 }
369 V streamFluct = -(uVortex*grad);
370 streamFluct /= normGrad;
371
372 output += uVortex + streamFluct * axisDirection;
373
374 cell.defineU(output.data());
375 }
376
377};
378
381
383
384 int getPriority() const {
385 return std::numeric_limits<int>::max();
386 }
387
388 template <typename CELL, typename PARAMETERS>
389 void apply(CELL& cell, PARAMETERS& parameters) any_platform {
390 using V = typename CELL::value_t;
391 using DESCRIPTOR = typename CELL::descriptor_t;
393 cell.computeU(u.data());
394 u *= parameters.template get<CONVERSION_FACTOR_VELOCITY>();
395 cell.template setField<VELOCITY_OLD>(u);
396 }
397
398};
399
400}
401
402#endif
#define M_PI
AnalyticalF are applications from DD to XD, where X is set by the constructor.
A regular single 3D cuboid is the basic component of a 3D cuboid structure which defines the grid.
Definition cuboid3D.h:58
Smart pointer for managing the various ways of passing functors around.
Definition functorPtr.h:60
IndicatorF3D is an application from .
class for marking output with some text
Base indicator functor (discrete)
Indicator extended by a layer.
Super class maintaining block lattices for a cuboid decomposition.
CuboidGeometry< T, D > & getCuboidGeometry()
Read and write access to cuboid geometry.
Conversion between physical and lattice units, as well as discretization.
Plain old scalar vector.
Definition vector.h:47
constexpr const T * data() const any_platform
Definition vector.h:161
void setProfile(std::shared_ptr< AnalyticalF3D< T, T > > profileF)
VortexMethodTurbulentVelocityBoundary(FunctorPtr< SuperIndicatorF3D< T > > &&inletLatticeI, FunctorPtr< IndicatorF3D< T > > &&inletPhysI, UnitConverter< T, DESCRIPTOR > &converter, SuperLattice< T, DESCRIPTOR > &sLattice, int nSeeds, int nTime, T sigma, T intensity, Vector< T, 3 > axisDirection)
void reduceAndBcast(T &reductVal, MPI_Op op, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
Reduction operation, followed by a broadcast.
MpiManager & mpi()
cpu::simd::Pack< T > sqrt(cpu::simd::Pack< T > value)
Definition pack.h:100
cpu::simd::Pack< T > min(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
Definition pack.h:124
ADf< T, DIM > log(const ADf< T, DIM > &a)
Definition aDiff.h:475
cpu::simd::Pack< T > max(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
Definition pack.h:130
cpu::simd::Pack< T > pow(cpu::simd::Pack< T > base, cpu::simd::Pack< T > exp)
Definition pack.h:112
int sign(T val)
Definition util.h:54
ADf< T, DIM > exp(const ADf< T, DIM > &a)
Definition aDiff.h:455
Top level namespace for all of OpenLB.
@ Simulation
Data available on host for e.g. functor evaluation.
constexpr T norm(const ScalarVector< T, D, IMPL > &a)
Euclidean vector norm.
OperatorScope
Block-wide operator application scopes.
Definition operator.h:54
@ PerCellWithParameters
Per-cell application with parameters, i.e. OPERATOR::apply is passed a CELL concept implementation an...
constexpr Vector< T, 3 > crossProduct3D(const ScalarVector< T, 3, IMPL > &a, const ScalarVector< T, 3, IMPL_ > &b) any_platform
Definition vector.h:224
#define any_platform
Define preprocessor macros for device-side functions, constant storage.
Definition platform.h:78
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
Vector< V, 3 > computeVelocityGradient(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
Base of a field whose size is defined by [C,U_1,...,U_N]^T * [1,V_1,...V_N].
Base of a descriptor field of scalar TYPE with dimensions A*B + B*Q + C.
Identity type to pass non-constructible types as value.
Definition meta.h:79
Plain wrapper for list of types.
Definition meta.h:276