24#ifndef BOUNDARIES_VORTEX_METHOD_H
25#define BOUNDARIES_VORTEX_METHOD_H
31struct VortexMethodPreProcessor;
32struct VortexMethodPostProcessor;
53template <
typename T,
typename DESCRIPTOR>
58 std::shared_ptr<AnalyticalF3D<T,T>> _profileF;
72 std::vector<int> _NiC;
78 void updateSeedsVorticity(std::size_t iT);
94 void apply(std::size_t iT);
98template <
typename T,
typename DESCRIPTOR>
109 : _inletLatticeI(std::move(inletLatticeI)),
110 _inletPhysI(std::move(inletPhysI)),
111 _converter(converter),
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())
127 sLattice.template addPostProcessor<stage::VortexMethod>(*_inletLatticeI,
130 sLattice.template addPostProcessor<stage::VortexMethod>(extendedLatticeInletI,
133 if (_sigma < _converter.getPhysDeltaX()) {
134 _sigma = _converter.getPhysDeltaX();
140 Cuboid3D<T> indicatorCuboid(*inletPhysI, _converter.getPhysDeltaX());
142 auto& load = _sLattice.getLoadBalancer();
143 for (
int iC=0; iC < load.size(); ++iC) {
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};
153 cuboid.getPhysR(physR, latticeR);
154 block.get(iX,iY,iZ).template setField<descriptors::LOCATION>(physR);
156 _inletPhysI(&inInlet, physR);
158 _AiC[iC] +=
util::pow(_converter.getPhysDeltaX(), 2.);
164 _inletArea += _AiC[iC];
167 #ifdef PARALLEL_MODE_MPI
171 clout <<
"inletArea=" << _inletArea << std::endl;
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]);
180 for (
int iC=0; iC < load.size(); ++iC) {
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>();
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);
201template <
typename T,
typename DESCRIPTOR>
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);
211 auto& load = _sLattice.getLoadBalancer();
212 for (
int iC=0; iC < load.size(); ++iC) {
213 auto& seeds = _seeds.getBlock(iC);
215 #ifdef PARALLEL_MODE_OMP
216 #pragma omp parallel for schedule(static)
218 for (
int j = 0; j < _NiC[iC]; j++) {
219 auto seed = _inletPhysI->getSample(randomness);
228template <
typename T,
typename DESCRIPTOR>
229void VortexMethodTurbulentVelocityBoundary<T,DESCRIPTOR>::updateSeedsVorticity(std::size_t iT)
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) {
237 auto& seeds = _seeds.getBlock(iC);
238 auto& seedsVorticity = _seedsVorticity.getBlock(iC);
239 #ifdef PARALLEL_MODE_OMP
240 #pragma omp parallel for schedule(static)
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());
247 T kinE = 3./2. *
util::pow(normVel * _intensity, 2. );
252 T tau = _nTime * _sigma / normVel;
253 if(iT == _converter.getLatticeTime(tau)) {
254 sign *= distrib(gen);
258 seedsVorticity.set(i,vorticity);
265template <
typename T,
typename DESCRIPTOR>
268 _profileF = profileF;
269 _sLattice.template defineField<U_PROFILE>(*_inletLatticeI, *_profileF);
273template <
typename T,
typename DESCRIPTOR>
277 updateSeedsVorticity(iT);
280 auto& load = _sLattice.getLoadBalancer();
281 for (
int iC=0; iC < load.size(); ++iC) {
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));
289 _sLattice.template setParameter<SIGMA>(_sigma);
290 _sLattice.template setParameter<AXIS_DIRECTION>(_axisDirection);
313 template <
typename CELL,
typename PARAMETERS,
typename V=
typename CELL::value_t>
316 const V dx =
parameters.template get<CONVERSION_FACTOR_LENGTH>();
317 Vector<V,3> actVel = cell.template getField<VELOCITY_OLD>();
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>();
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;
335 template <
typename CELL,
typename PARAMETERS>
337 using V =
typename CELL::value_t;
338 using DESCRIPTOR =
typename CELL::descriptor_t;
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>();
347 const V conversionFactorVelocity =
parameters.template get<CONVERSION_FACTOR_VELOCITY>();
348 output /= conversionFactorVelocity;
352 for (std::size_t j=0; j <
parameters.template get<SEEDS_COUNT>(); ++j) {
354 for (
int iD = 0; iD < DESCRIPTOR::d; ++iD) {
355 diffX[iD] = seeds[iD][j] - x[iD];
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;
366 if (normGrad == V{0}) {
369 V streamFluct = -(uVortex*grad);
370 streamFluct /= normGrad;
372 output += uVortex + streamFluct * axisDirection;
374 cell.defineU(output.
data());
385 return std::numeric_limits<int>::max();
388 template <
typename CELL,
typename PARAMETERS>
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);
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.
Smart pointer for managing the various ways of passing functors around.
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.
constexpr const T * data() const any_platform
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 apply(std::size_t iT)
void reduceAndBcast(T &reductVal, MPI_Op op, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
Reduction operation, followed by a broadcast.
cpu::simd::Pack< T > sqrt(cpu::simd::Pack< T > value)
cpu::simd::Pack< T > min(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
ADf< T, DIM > log(const ADf< T, DIM > &a)
cpu::simd::Pack< T > max(cpu::simd::Pack< T > rhs, cpu::simd::Pack< T > lhs)
cpu::simd::Pack< T > pow(cpu::simd::Pack< T > base, cpu::simd::Pack< T > exp)
ADf< T, DIM > exp(const ADf< T, DIM > &a)
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.
@ 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
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS ¶meters) any_platform
Vector< V, 3 > computeVelocityGradient(CELL &cell, PARAMETERS ¶meters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS ¶meters) 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.