24#ifndef BOUNDARY_POST_PROCESSORS_3D_HH
25#define BOUNDARY_POST_PROCESSORS_3D_HH
39template <
typename T,
typename DESCRIPTOR,
int direction,
int orientation>
40template <CONCEPT(Cell) CELL>
45 T dx_u[DESCRIPTOR::d], dy_u[DESCRIPTOR::d], dz_u[DESCRIPTOR::d];
46 T rho, u[DESCRIPTOR::d];
48 auto& dynamics = cell.getDynamics();
50 cell.computeRhoU(rho,u);
52 interpolateGradients<0>(cell, dx_u);
53 interpolateGradients<1>(cell, dy_u);
54 interpolateGradients<2>(cell, dz_u);
65 T omega = dynamics.getOmegaOrFallback(std::numeric_limits<T>::signaling_NaN());
66 T sToPi = - rho / descriptors::invCs2<T,DESCRIPTOR>() / omega;
68 pi[xx] = (T)2 * dx_ux * sToPi;
69 pi[yy] = (T)2 * dy_uy * sToPi;
70 pi[zz] = (T)2 * dz_uz * sToPi;
71 pi[xy] = (dx_uy + dy_ux) * sToPi;
72 pi[xz] = (dx_uz + dz_ux) * sToPi;
73 pi[yz] = (dy_uz + dz_uy) * sToPi;
77 for (
int iPop = 0; iPop < DESCRIPTOR::q; ++iPop) {
78 cell[iPop] = dynamics.computeEquilibrium(iPop,rho,u)
83template <
typename T,
typename DESCRIPTOR,
int direction,
int orientation>
84template <
int deriveDirection,
typename CELL>
86 CELL& cell, T velDeriv[DESCRIPTOR::d])
const
92template <
typename DESCRIPTOR,
int direction,
int orientation>
93template <CONCEPT(Cell) CELL>
97 auto prevCell = cell.template getFieldPointer<PREV_CELL>();
98 for (
unsigned i=0; i < missing.size(); ++i) {
99 prevCell[i] = cell[missing[i]];
103template <
typename DESCRIPTOR,
int direction,
int orientation>
104template <CONCEPT(Cell) CELL>
107 using V =
typename CELL::value_t;
110 auto prevCell = cell.template getField<PREV_CELL>();
112 for (
unsigned i=0; i < missing.size(); ++i) {
113 cell[missing[i]] = prevCell[i];
120 cell.computeRhoU(rho0, u0);
122 static_assert(direction == 0 || direction == 1 || direction ==2,
123 "Direction must be one of 0, 1 or 2");
124 if constexpr (direction == 0) {
125 cell.neighbor({-orientation ,0,0}).computeRhoU(rho1, u1);
126 cell.neighbor({-orientation*2,0,0}).computeRhoU(rho2, u2);
128 else if constexpr (direction == 1) {
129 cell.neighbor({0,-orientation ,0}).computeRhoU(rho1, u1);
130 cell.neighbor({0,-orientation*2,0}).computeRhoU(rho2, u2);
132 else if constexpr (direction == 2) {
133 cell.neighbor({0,0,-orientation }).computeRhoU(rho1, u1);
134 cell.neighbor({0,0,-orientation*2}).computeRhoU(rho2, u2);
138 V uAverage = rho0*u0[direction];
146 uDelta[0] = -uAverage*0.5*(3*rho0*u0[0]-4*rho1*u1[0]+rho2*u2[0]);
147 uDelta[1] = -uAverage*0.5*(3*rho0*u0[1]-4*rho1*u1[1]+rho2*u2[1]);
148 uDelta[2] = -uAverage*0.5*(3*rho0*u0[2]-4*rho1*u1[2]+rho2*u2[2]);
150 for (
unsigned i=0; i < missing.size(); ++i) {
151 auto iPop = missing[i];
152 prevCell[i] = cell[iPop]
153 + descriptors::invCs2<V,DESCRIPTOR>()*descriptors::t<V,DESCRIPTOR>(iPop)
154 * ( uDelta[0]*descriptors::c<DESCRIPTOR>(iPop,0)
155 + uDelta[1]*descriptors::c<DESCRIPTOR>(iPop,1)
156 + uDelta[2]*descriptors::c<DESCRIPTOR>(iPop,2));
159 cell.template setField<PREV_CELL>(prevCell);
164template <
typename T,
typename DESCRIPTOR,
int plane,
int normal1,
int normal2>
165template <CONCEPT(Cell) CELL>
170 constexpr auto direction1 = (plane+1)%3;
171 constexpr auto direction2 = (plane+2)%3;
173 auto& dynamics = cell.getDynamics();
175 T rho10 = getNeighborRho(cell, 1,0);
176 T rho01 = getNeighborRho(cell, 0,1);
177 T rho20 = getNeighborRho(cell, 2,0);
178 T rho02 = getNeighborRho(cell, 0,2);
179 T rho = (T)2/(T)3*(rho01+rho10)-(T)1/(T)6*(rho02+rho20);
183 interpolateGradients<plane,0> (cell, dA_uB_[0]);
184 interpolateGradients<direction1,normal1>(cell, dA_uB_[1]);
185 interpolateGradients<direction2,normal2>(cell, dA_uB_[2]);
188 for (
int iBeta=0; iBeta<3; ++iBeta) {
189 dA_uB[plane][iBeta] = dA_uB_[0][iBeta];
190 dA_uB[direction1][iBeta] = dA_uB_[1][iBeta];
191 dA_uB[direction2][iBeta] = dA_uB_[2][iBeta];
193 T omega = dynamics.getOmegaOrFallback(std::numeric_limits<T>::signaling_NaN());
194 T sToPi = - rho / descriptors::invCs2<T,DESCRIPTOR>() / omega;
196 pi[xx] = (T)2 * dA_uB[0][0] * sToPi;
197 pi[yy] = (T)2 * dA_uB[1][1] * sToPi;
198 pi[zz] = (T)2 * dA_uB[2][2] * sToPi;
199 pi[xy] = (dA_uB[0][1]+dA_uB[1][0]) * sToPi;
200 pi[xz] = (dA_uB[0][2]+dA_uB[2][0]) * sToPi;
201 pi[yz] = (dA_uB[1][2]+dA_uB[2][1]) * sToPi;
208 for (
int iPop = 0; iPop < DESCRIPTOR::q; ++iPop) {
209 cell[iPop] = dynamics.computeEquilibrium(iPop,rho,u)
214template <
typename T,
typename DESCRIPTOR,
int plane,
int normal1,
int normal2>
215template <
typename CELL>
219 constexpr auto direction1 = (plane+1)%3;
220 constexpr auto direction2 = (plane+2)%3;
222 coords[direction1] = -normal1*step1;
223 coords[direction2] = -normal2*step2;
224 return cell.neighbor(coords).computeRho();
227template <
typename T,
typename DESCRIPTOR,
int plane,
int normal1,
int normal2>
228template <
int deriveDirection,
int orientation,
typename CELL>
238template <
typename T,
typename DESCRIPTOR,
int xNormal,
int yNormal,
int zNormal>
239template <CONCEPT(Cell) CELL>
244 auto& dynamics = cell.getDynamics();
246 T rho100 = cell.neighbor({-1*xNormal, -0*yNormal, -0*zNormal}).computeRho();
247 T rho010 = cell.neighbor({-0*xNormal, -1*yNormal, -0*zNormal}).computeRho();
248 T rho001 = cell.neighbor({-0*xNormal, -0*yNormal, -1*zNormal}).computeRho();
249 T rho200 = cell.neighbor({-2*xNormal, -0*yNormal, -0*zNormal}).computeRho();
250 T rho020 = cell.neighbor({-0*xNormal, -2*yNormal, -0*zNormal}).computeRho();
251 T rho002 = cell.neighbor({-0*xNormal, -0*yNormal, -2*zNormal}).computeRho();
253 T rho = (T)4/(T)9 * (rho001 + rho010 + rho100) - (T)1/(T)9 * (rho002 + rho020 + rho200);
255 T dx_u[DESCRIPTOR::d], dy_u[DESCRIPTOR::d], dz_u[DESCRIPTOR::d];
269 T omega = dynamics.getOmegaOrFallback(std::numeric_limits<T>::signaling_NaN());
270 T sToPi = - rho / descriptors::invCs2<T,DESCRIPTOR>() / omega;
272 pi[xx] = (T)2 * dx_ux * sToPi;
273 pi[yy] = (T)2 * dy_uy * sToPi;
274 pi[zz] = (T)2 * dz_uz * sToPi;
275 pi[xy] = (dx_uy + dy_ux) * sToPi;
276 pi[xz] = (dx_uz + dz_ux) * sToPi;
277 pi[yz] = (dy_uz + dz_uy) * sToPi;
284 for (
int iPop = 0; iPop < DESCRIPTOR::q; ++iPop) {
285 cell[iPop] = dynamics.computeEquilibrium(iPop,rho,u)
292template<
typename T,
typename DESCRIPTOR>
294SlipBoundaryProcessor3D(
int x0_,
int x1_,
int y0_,
int y1_,
int z0_,
int z1_,
int discreteNormalX,
int discreteNormalY,
int discreteNormalZ)
295 : x0(x0_), x1(x1_), y0(y0_), y1(y1_), z0(z0_), z1(z1_)
297 this->
getName() =
"SlipBoundaryProcessor3D";
299 int mirrorDirection0;
300 int mirrorDirection1;
301 int mirrorDirection2;
302 int mult = 2 / (discreteNormalX*discreteNormalX + discreteNormalY*discreteNormalY + discreteNormalZ*discreteNormalZ);
303 reflectionPop[0] = 0;
304 for (
int iPop = 1; iPop < DESCRIPTOR::q; iPop++) {
305 reflectionPop[iPop] = 0;
307 int scalarProduct = descriptors::c<DESCRIPTOR>(iPop,0)*discreteNormalX + descriptors::c<DESCRIPTOR>(iPop,1)*discreteNormalY + descriptors::c<DESCRIPTOR>(iPop,2)*discreteNormalZ;
308 if ( scalarProduct < 0) {
311 mirrorDirection0 = -descriptors::c<DESCRIPTOR>(iPop,0);
312 mirrorDirection1 = -descriptors::c<DESCRIPTOR>(iPop,1);
313 mirrorDirection2 = -descriptors::c<DESCRIPTOR>(iPop,2);
316 mirrorDirection0 = descriptors::c<DESCRIPTOR>(iPop,0) - mult*scalarProduct*discreteNormalX;
317 mirrorDirection1 = descriptors::c<DESCRIPTOR>(iPop,1) - mult*scalarProduct*discreteNormalY;
318 mirrorDirection2 = descriptors::c<DESCRIPTOR>(iPop,2) - mult*scalarProduct*discreteNormalZ;
322 for (
int i = 1; i < DESCRIPTOR::q; i++) {
323 if (descriptors::c<DESCRIPTOR>(i,0)==mirrorDirection0
324 && descriptors::c<DESCRIPTOR>(i,1)==mirrorDirection1
325 && descriptors::c<DESCRIPTOR>(i,2)==mirrorDirection2) {
326 reflectionPop[iPop] = i;
334template<
typename T,
typename DESCRIPTOR>
338 int newX0, newX1, newY0, newY1, newZ0, newZ1;
340 x0, x1, y0, y1, z0, z1,
341 x0_, x1_, y0_, y1_, z0_, z1_,
342 newX0, newX1, newY0, newY1, newZ0, newZ1 ) ) {
345#ifdef PARALLEL_MODE_OMP
346 #pragma omp parallel for
348 for (iX=x0; iX<=x1; ++iX) {
349 for (
int iY=y0; iY<=y1; ++iY) {
350 for (
int iZ=z0; iZ<=z1; ++iZ) {
351 for (
int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) {
352 if (reflectionPop[iPop]!=0) {
354 blockLattice.
get(iX,iY,iZ)[iPop] = blockLattice.
get(iX,iY,iZ)[reflectionPop[iPop]];
363template<
typename T,
typename DESCRIPTOR>
367 processSubDomain(blockLattice, x0, x1, y0, y1, z0, z1);
372template<
typename T,
typename DESCRIPTOR>
375 :
PostProcessorGenerator3D<T,DESCRIPTOR>(x0_, x1_, y0_, y1_, z0_, z1_), discreteNormalX(discreteNormalX_), discreteNormalY(discreteNormalY_), discreteNormalZ(discreteNormalZ_)
378template<
typename T,
typename DESCRIPTOR>
383 ( this->x0, this->x1, this->y0, this->y1, this->z0, this->z1, discreteNormalX, discreteNormalY, discreteNormalZ);
386template<
typename T,
typename DESCRIPTOR>
391 (this->x0, this->x1, this->y0, this->y1, this->z0, this->z1, discreteNormalX, discreteNormalY, discreteNormalZ);
396template<
typename T,
typename DESCRIPTOR>
398PartialSlipBoundaryProcessor3D(T tuner_,
int x0_,
int x1_,
int y0_,
int y1_,
int z0_,
int z1_,
int discreteNormalX,
int discreteNormalY,
int discreteNormalZ)
399 : x0(x0_), x1(x1_), y0(y0_), y1(y1_), z0(z0_), z1(z1_), tuner(tuner_)
401 this->
getName() =
"PartialSlipBoundaryProcessor3D";
403 reflectionPop[0] = 0;
404 for (
int iPop = 1; iPop < DESCRIPTOR::q; iPop++) {
405 reflectionPop[iPop] = 0;
407 if (descriptors::c<DESCRIPTOR>(iPop,0)*discreteNormalX + descriptors::c<DESCRIPTOR>(iPop,1)*discreteNormalY + descriptors::c<DESCRIPTOR>(iPop,2)*discreteNormalZ < 0) {
409 int mirrorDirection0;
410 int mirrorDirection1;
411 int mirrorDirection2;
412 int mult = 2 / (discreteNormalX*discreteNormalX + discreteNormalY*discreteNormalY + discreteNormalZ*discreteNormalZ);
414 mirrorDirection0 = (descriptors::c<DESCRIPTOR>(iPop,0) - mult*(descriptors::c<DESCRIPTOR>(iPop,0)*discreteNormalX + descriptors::c<DESCRIPTOR>(iPop,1)*discreteNormalY + descriptors::c<DESCRIPTOR>(iPop,2)*discreteNormalZ)*discreteNormalX);
416 mirrorDirection1 = (descriptors::c<DESCRIPTOR>(iPop,1) - mult*(descriptors::c<DESCRIPTOR>(iPop,0)*discreteNormalX + descriptors::c<DESCRIPTOR>(iPop,1)*discreteNormalY + descriptors::c<DESCRIPTOR>(iPop,2)*discreteNormalZ)*discreteNormalY);
417 mirrorDirection2 = (descriptors::c<DESCRIPTOR>(iPop,2) - mult*(descriptors::c<DESCRIPTOR>(iPop,0)*discreteNormalX + descriptors::c<DESCRIPTOR>(iPop,1)*discreteNormalY + descriptors::c<DESCRIPTOR>(iPop,2)*discreteNormalZ)*discreteNormalZ);
421 mirrorDirection0 = -descriptors::c<DESCRIPTOR>(iPop,0);
422 mirrorDirection1 = -descriptors::c<DESCRIPTOR>(iPop,1);
423 mirrorDirection2 = -descriptors::c<DESCRIPTOR>(iPop,2);
427 for (reflectionPop[iPop] = 1; reflectionPop[iPop] < DESCRIPTOR::q ; reflectionPop[iPop]++) {
428 if (descriptors::c<DESCRIPTOR>(reflectionPop[iPop],0)==mirrorDirection0 && descriptors::c<DESCRIPTOR>(reflectionPop[iPop],1)==mirrorDirection1 && descriptors::c<DESCRIPTOR>(reflectionPop[iPop],2)==mirrorDirection2) {
437template<
typename T,
typename DESCRIPTOR>
441 int newX0, newX1, newY0, newY1, newZ0, newZ1;
444 x0, x1, y0, y1, z0, z1,
445 x0_, x1_, y0_, y1_, z0_, z1_,
446 newX0, newX1, newY0, newY1, newZ0, newZ1 ) ) {
449#ifdef PARALLEL_MODE_OMP
450 #pragma omp parallel for
452 for (iX=newX0; iX<=newX1; ++iX) {
453 for (
int iY=newY0; iY<=newY1; ++iY) {
454 for (
int iZ=newZ0; iZ<=newZ1; ++iZ) {
455 for (
int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) {
456 if (reflectionPop[iPop]!=0) {
458 blockLattice.
get(iX,iY,iZ)[iPop] = tuner*blockLattice.
get(iX,iY,iZ)[reflectionPop[iPop]];
461 for (
int iPop = 1; iPop < DESCRIPTOR::q/2 ; ++iPop) {
462 T provv = blockLattice.
get(iX,iY,iZ)[descriptors::opposite<DESCRIPTOR>(iPop)];
463 blockLattice.
get(iX,iY,iZ)[descriptors::opposite<DESCRIPTOR>(iPop)] +=
464 (1.-tuner)*blockLattice.
get(iX,iY,iZ)[iPop];
465 blockLattice.
get(iX,iY,iZ)[iPop] += (1.-tuner)*provv;
473template<
typename T,
typename DESCRIPTOR>
477 processSubDomain(blockLattice, x0, x1, y0, y1, z0, z1);
482template<
typename T,
typename DESCRIPTOR>
485 :
PostProcessorGenerator3D<T,DESCRIPTOR>(x0_, x1_, y0_, y1_, z0_, z1_), discreteNormalX(discreteNormalX_), discreteNormalY(discreteNormalY_), discreteNormalZ(discreteNormalZ_), tuner(tuner_)
488template<
typename T,
typename DESCRIPTOR>
493 (tuner, this->x0, this->x1, this->y0, this->y1, this->z0, this->z1, discreteNormalX, discreteNormalY, discreteNormalZ);
496template<
typename T,
typename DESCRIPTOR>
501 (tuner, this->x0, this->x1, this->y0, this->y1, this->z0, this->z1, discreteNormalX, discreteNormalY, discreteNormalZ);
505template<
typename T,
typename DESCRIPTOR,
int NORMAL_X,
int NORMAL_Y,
int NORMAL_Z>
506template <CONCEPT(Cell) CELL,
typename PARAMETERS>
509 T addend = cell.template getField<descriptors::ADDEND>();
511 T rhoBulk = cell.neighbor({-NORMAL_X, -NORMAL_Y, -NORMAL_Z}).computeRho();
514 for (
int iPop = 1; iPop < DESCRIPTOR::q ; ++iPop) {
515 rhoTmp += cell[iPop];
518 T rho = rhoBulk + addend;
527template<
typename T,
typename DESCRIPTOR,
int NORMAL_X,
int NORMAL_Y,
int NORMAL_Z>
528template <CONCEPT(Cell) CELL>
531 cell.template setField<descriptors::CHEM_POTENTIAL>(
532 cell.neighbor({-NORMAL_X,-NORMAL_Y,-NORMAL_Z}).template getField<descriptors::CHEM_POTENTIAL>());
534 T rho0 = cell.computeRho();
535 T rho1 = cell.neighbor({-NORMAL_X,-NORMAL_Y,-NORMAL_Z}).computeRho();
537 cell.template setField<descriptors::CHEM_POTENTIAL>(
538 cell.template getField<descriptors::CHEM_POTENTIAL>() + (rho1 / rho0 - 1) / descriptors::invCs2<T,DESCRIPTOR>());
541template<
typename T,
typename DESCRIPTOR,
int NORMAL_X,
int NORMAL_Y,
int NORMAL_Z>
542template <CONCEPT(Cell) CELL>
545 cell.template setField<descriptors::CHEM_POTENTIAL>(
546 cell.neighbor({-NORMAL_X,-NORMAL_Y,-NORMAL_Z}).template getField<descriptors::CHEM_POTENTIAL>());
551template<
typename T,
typename DESCRIPTOR,
int NORMAL_X,
int NORMAL_Y,
int NORMAL_Z>
552template <CONCEPT(Cell) CELL>
555 T rho, rho0, rho1, u[3];
557 rho0 = cell.computeRho();
559 cell.neighbor({-NORMAL_X,-NORMAL_Y,-NORMAL_Z}).computeRhoU(rho1, u);
565 if (normalVec[2] == 0) {
566 if (normalVec[1] == 0) {
567 if (normalVec[0] < 0) {
572 }
else if (normalVec[0] == 0) {
573 if (normalVec[1] < 0) {
579 uPerp =
util::sqrt(u[0] * u[0] + u[1] * u[1]);
581 }
else if (normalVec[1] == 0) {
582 if (normalVec[0] == 0) {
583 if (normalVec[2] < 0) {
589 uPerp =
util::sqrt(u[0] * u[0] + u[2] * u[2]);
591 }
else if (normalVec[0] == 0) {
592 uPerp =
util::sqrt(u[1] * u[1] + u[2] * u[2]);
594 uPerp =
util::sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
597 rho = (rho0 + uPerp * rho1) / (1. + uPerp);
Platform-abstracted block lattice for external access and inter-block interaction.
Cell< T, DESCRIPTOR > get(CellID iCell)
Get Cell interface for index iCell.
void apply(CELL &cell) any_platform
void apply(CELL &cell) any_platform
void apply(CELL &cell) any_platform
void apply(CELL &cell, PARAMETERS ¶meters) any_platform
This class computes the skordos BC on a convex edge wall in 3D but with a limited number of terms add...
void apply(CELL &cell) any_platform
This class computes a partial slip BC in 3D.
PartialSlipBoundaryProcessor3D(T tuner_, int x0_, int x1_, int y0_, int y1_, int z0_, int z1_, int discreteNormalX_, int discreteNormalY_, int discreteNormalZ_)
void processSubDomain(BlockLattice< T, DESCRIPTOR > &blockLattice, int x0_, int x1_, int y0_, int y1_, int z0_, int z1_) override
Execute post-processing step on a sublattice.
void process(BlockLattice< T, DESCRIPTOR > &blockLattice) override
Execute post-processing step.
PartialSlipBoundaryProcessorGenerator3D(T tuner_, int x0_, int x1_, int y0_, int y1_, int z0_, int z1_, int discreteNormalX_, int discreteNormalY_, int discreteNormalZ_)
PostProcessor3D< T, DESCRIPTOR > * generate() const override
PostProcessorGenerator3D< T, DESCRIPTOR > * clone() const override
This class computes the skordos BC on a plane wall in 3D but with a limited number of terms added to ...
void apply(CELL &cell) any_platform
std::string & getName()
read and write access to name
This class computes a slip BC in 3D.
SlipBoundaryProcessor3D(int x0_, int x1_, int y0_, int y1_, int z0_, int z1_, int discreteNormalX_, int discreteNormalY_, int discreteNormalZ_)
void processSubDomain(BlockLattice< T, DESCRIPTOR > &blockLattice, int x0_, int x1_, int y0_, int y1_, int z0_, int z1_) override
Execute post-processing step on a sublattice.
void process(BlockLattice< T, DESCRIPTOR > &blockLattice) override
Execute post-processing step.
PostProcessorGenerator3D< T, DESCRIPTOR > * clone() const override
SlipBoundaryProcessorGenerator3D(int x0_, int x1_, int y0_, int y1_, int z0_, int z1_, int discreteNormalX_, int discreteNormalY_, int discreteNormalZ_)
PostProcessor3D< T, DESCRIPTOR > * generate() const override
void initialize(CELL &cell) any_platform
void apply(CELL &cell) any_platform
cpu::simd::Pack< T > sqrt(cpu::simd::Pack< T > value)
constexpr auto populationsContributingToVelocity() any_platform
Return array of population indices where c[iVel] == value.
bool intersect(int x0, int x1, int y0, int y1, int x0_, int x1_, int y0_, int y1_, int &newX0, int &newX1, int &newY0, int &newY1)
Top level namespace for all of OpenLB.
#define OLB_PRECONDITION(COND)
void apply(CELL &cell) any_platform
static void interpolateVector(T velDeriv[DESCRIPTOR::d], BlockLattice< T, DESCRIPTOR > const &blockLattice, int iX, int iY, int iZ)
Compute number of elements of a symmetric d-dimensional tensor.
Set of functions commonly used in LB computations – header file.