OpenLB 1.7
Loading...
Searching...
No Matches
setBouzidiBoundary.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2022 Michael Crocoll, Adrian Kummerlaender, Shota Ito
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 SET_BOUZIDI_BOUNDARY_H
25#define SET_BOUZIDI_BOUNDARY_H
26
27// M. Bouzidi, M. Firdaouss, and P. Lallemand.
28// Momentum transfer of a Boltzmann-lattice fluid with boundaries.
29// Physics of Fluids 13, 3452 (2001).
30// DOI: 10.1063/1.1399290
31
32// D. Yu, R. Mei, and W. Shyy.
33// A Unified Boundary Treatment in Lattice Boltzmann Method.
34// Session: FD-27: CFD Methodology III (2012)
35// DOI: 10.2514/6.2003-953
36
37namespace olb {
38
39namespace descriptors {
40
43 template <typename T, typename DESCRIPTOR>
44 static constexpr auto getInitialValue() {
45 return Vector<value_type<T>,DESCRIPTOR::template size<BOUZIDI_DISTANCE>()>(-1);
46 }
47};
48
51 template <typename T, typename DESCRIPTOR>
52 static constexpr auto getInitialValue() {
53 return Vector<value_type<T>,DESCRIPTOR::template size<BOUZIDI_VELOCITY>()>(0);
54 }
55};
56
59 template <typename T, typename DESCRIPTOR>
60 static constexpr auto getInitialValue() {
61 return Vector<value_type<T>,DESCRIPTOR::template size<BOUZIDI_ADE_DIRICHLET>()>(0);
62 }
63};
64}
65
68public:
70
71 int getPriority() const {
72 return -1;
73 }
74
75 template <typename CELL, typename V = typename CELL::value_t>
76 void apply(CELL& x_b) any_platform {
77 using DESCRIPTOR = typename CELL::descriptor_t;
78 const auto q = x_b.template getFieldPointer<descriptors::BOUZIDI_DISTANCE>();
79 for (int iPop = 1; iPop < descriptors::q<DESCRIPTOR>(); ++iPop) {
80 // update missing population if valid bouzidi distance
81 if (q[iPop] > V{0}) {
82 const auto c = descriptors::c<DESCRIPTOR>(iPop);
83 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
84 auto x_s = x_b.neighbor(c); // solid side neighbor
85 auto x_f = x_b.neighbor(descriptors::c<DESCRIPTOR>(iPop_opposite)); // fluid side neighbor opposite to the missing population
86
87 x_b[iPop_opposite] = (q[iPop] <= V{0.5}) // cut is closer to the fluid cell
88 * (V{2} * q[iPop] * x_s[iPop] + (V{1} - V{2} * q[iPop]) * x_b[iPop])
89 + (q[iPop] > V{0.5}) // cut is closer to the solid cell
90 * (V{0.5} / q[iPop] * x_s[iPop] + V{0.5} * (V{2} * q[iPop] - V{1}) / q[iPop] * x_f[iPop_opposite]);
91 }
92 // if intersection point is on the cell then fall back to full-way bounce back
93 else if (q[iPop] == V{0}) {
94 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
95 x_b[iPop_opposite] = x_b[iPop];
96 }
97 }
98 }
99};
100
102public:
104
105 int getPriority() const {
106 return -1;
107 }
108
109 template <typename CELL, typename V = typename CELL::value_t>
110 void apply(CELL& x_b) any_platform {
111 using DESCRIPTOR = typename CELL::descriptor_t;
112 const auto q = x_b.template getFieldPointer<descriptors::BOUZIDI_DISTANCE>();
113 const auto phi_d = x_b.template getFieldPointer<descriptors::BOUZIDI_ADE_DIRICHLET>();
114 V f = V{1/3}; // D2Q5
115 if (descriptors::q<DESCRIPTOR>() == 7) {
116 f = V{0.25}; // D3Q7
117 }
118 for (int iPop = 1; iPop < descriptors::q<DESCRIPTOR>(); ++iPop) {
119 // update missing population if valid bouzidi distance
120 if (q[iPop] > V{0}) {
121 const auto c = descriptors::c<DESCRIPTOR>(iPop);
122 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
123 auto x_s = x_b.neighbor(c); // solid side neighbor
124 auto x_f = x_b.neighbor(descriptors::c<DESCRIPTOR>(iPop_opposite)); // fluid side neighbor opposite to the missing population
125 auto source_d = phi_d[iPop] * f; // source term set by the dirichlet condition
126 auto t_i = descriptors::t<V,DESCRIPTOR>(iPop);
127 auto t_iopp = descriptors::t<V,DESCRIPTOR>(iPop_opposite);
128
129 x_b[iPop_opposite] = (q[iPop] <= V{0.5}) // cut is closer to the fluid cell
130 * (V{-2} * q[iPop] * (x_s[iPop] + t_i) + (V{2} * q[iPop] - V{1}) * (x_b[iPop] + t_i) + source_d)
131 + (q[iPop] > V{0.5}) // cut is closer to the solid cell
132 * (V{-1} / (V{2} * q[iPop]) * (x_s[iPop] + t_i) + (V{1} - V{1} / (V{2} * q[iPop])) * (x_f[iPop_opposite] + t_iopp) + (V{1} / (V{2} * q[iPop])) * source_d)
133 - t_iopp;
134 }
135 // if intersection point is on the cell then fall back to full-way bounce back
136 else if (q[iPop] == V{0}) {
137 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
138 auto source_d = phi_d[iPop] * f;
139 auto t_i = descriptors::t<V,DESCRIPTOR>(iPop);
140 auto t_iopp = descriptors::t<V,DESCRIPTOR>(iPop_opposite);
141 x_b[iPop_opposite] = -(x_b[iPop] + t_i) + source_d - t_iopp;
142 }
143 }
144 }
145};
146
149public:
151
152 int getPriority() const {
153 return -1;
154 }
155
156 template <typename CELL, typename V = typename CELL::value_t>
157 void apply(CELL& x_b) any_platform {
158 using DESCRIPTOR = typename CELL::descriptor_t;
159 const auto q = x_b.template getFieldPointer<descriptors::BOUZIDI_DISTANCE>();
160 const auto veloCoeff = x_b.template getFieldPointer<descriptors::BOUZIDI_VELOCITY>();
161 for (int iPop=1; iPop < descriptors::q<DESCRIPTOR>(); ++iPop) {
162 // update missing population if valid bouzidi distance
163 if (q[iPop] > 0) {
164 const auto c = descriptors::c<DESCRIPTOR>(iPop);
165 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
166 auto x_s = x_b.neighbor(c); // solid side neighbor
167 auto x_f = x_b.neighbor(descriptors::c<DESCRIPTOR>(iPop_opposite)); // fluid side neighbor opposite to the missing population
168 auto veloTerm = veloCoeff[iPop] * (descriptors::t<V,DESCRIPTOR>(iPop)) * (descriptors::invCs2<V,DESCRIPTOR>());
169
170 x_b[iPop_opposite] = (q[iPop] <= V{0.5}) // cut is closer to the fluid cell
171 * (V{2} * q[iPop] * x_s[iPop] + (V{1} - V{2} * q[iPop]) * x_b[iPop] - V{2} * veloTerm)
172 + (q[iPop] > V{0.5}) // cut is closer to the solid cell
173 * (V{0.5} / q[iPop] * x_s[iPop] + V{0.5} * (V{2} * q[iPop] - V{1}) / q[iPop] * x_f[iPop_opposite] - V{1}/q[iPop] * veloTerm);
174 }
175 // if intersection point is on the cell then fall back to full-way bounce back
176 else if (q[iPop] == V{0}) {
177 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
178 auto veloTerm = veloCoeff[iPop] * (descriptors::t<V,DESCRIPTOR>(iPop)) * (descriptors::invCs2<V,DESCRIPTOR>());
179 x_b[iPop_opposite] = x_b[iPop] - V{2} * veloTerm;
180 }
181 }
182 }
183};
184
185// Post processor for the zero-velocity Yu IBB scheme
187public:
189
190 int getPriority() const {
191 return -1;
192 }
193
194 template <typename CELL, typename V = typename CELL::value_t>
195 void apply(CELL& x_b) any_platform {
196 using DESCRIPTOR = typename CELL::descriptor_t;
197 const auto q = x_b.template getFieldPointer<descriptors::BOUZIDI_DISTANCE>();
198 for (int iPop=1; iPop < descriptors::q<DESCRIPTOR>(); ++iPop) {
199 if (q[iPop] >= 0) {
200 const auto c = descriptors::c<DESCRIPTOR>(iPop);
201 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
202 auto x_s = x_b.neighbor(c); // solid cell inside obstacle material
203 auto x_f = x_b.neighbor(descriptors::c<DESCRIPTOR>(iPop_opposite)); // fluid boundary cell
204 auto f_tmp = x_b[iPop] + q[iPop]*(x_s[iPop] - x_b[iPop]); // population at fictitious ghost particle
205 x_b[iPop_opposite] = f_tmp + q[iPop]/(V{1}+q[iPop]) * (x_f[iPop_opposite] - f_tmp);
206 }
207 }
208 }
209};
210
212template<typename T, typename DESCRIPTOR, typename OPERATOR = BouzidiPostProcessor>
214 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
216 IndicatorF<T,DESCRIPTOR::d>& indicatorAnalyticalBoundary)
217{
218 int _overlap = 1;
219 OstreamManager clout(std::cout, "BouzidiBoundarySetter");
220 auto& load = sLattice.getLoadBalancer();
221 for (int iC=0; iC < load.size(); ++iC) {
222 setBouzidiBoundary<T,DESCRIPTOR,OPERATOR>(sLattice.getBlock(iC),
223 (bulkIndicator->getBlockIndicatorF(iC)).getBlockGeometry(),
224 boundaryIndicator->getBlockIndicatorF(iC),
225 bulkIndicator->getBlockIndicatorF(iC),
226 indicatorAnalyticalBoundary);
227 }
228 addPoints2CommBC<T,DESCRIPTOR>(sLattice, std::forward<decltype(boundaryIndicator)>(boundaryIndicator), _overlap);
229 clout.setMultiOutput(false);
230}
231
233template<typename T, typename DESCRIPTOR, typename OPERATOR = BouzidiPostProcessor>
235 SuperGeometry<T,DESCRIPTOR::d>& superGeometry,
236 int materialOfSolidObstacle,
237 IndicatorF<T,DESCRIPTOR::d>& indicatorAnalyticalBoundary,
238 std::vector<int> bulkMaterials = std::vector<int>(1,1))
239{
240 //Getting the indicators by material numbers and calling the superLattice method via the indicators:
241 setBouzidiBoundary<T,DESCRIPTOR,OPERATOR>(sLattice,
242 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>(superGeometry.getMaterialIndicator(materialOfSolidObstacle)),
243 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>(superGeometry.getMaterialIndicator(std::move(bulkMaterials))),
244 indicatorAnalyticalBoundary);
245}
246
247
249template<typename T, typename DESCRIPTOR, typename OPERATOR = BouzidiPostProcessor>
251 BlockGeometry<T,DESCRIPTOR::d>& blockGeometry,
252 BlockIndicatorF<T,DESCRIPTOR::d>& boundaryIndicator,
254 IndicatorF<T,DESCRIPTOR::d>& indicatorAnalyticalBoundary,
255 bool verbose = false)
256{
257 OstreamManager clout(std::cout, "BouzidiBoundarySetter");
258 clout.setMultiOutput(true);
259
260 const T deltaR = blockGeometry.getDeltaR();
261 // for each solid cell: all of its fluid neighbors need population updates
262 block.forSpatialLocations([&](LatticeR<DESCRIPTOR::d> solidLatticeR) {
263 // Check if cell is solid cell
264 if (boundaryIndicator(solidLatticeR)) {
265 for (int iPop=1; iPop < DESCRIPTOR::q; ++iPop) {
266 Vector<T,DESCRIPTOR::d> boundaryLatticeR(solidLatticeR + descriptors::c<DESCRIPTOR>(iPop));
267 const auto c = descriptors::c<DESCRIPTOR>(iPop);
268 const auto iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
269
270 if (blockGeometry.isInside(boundaryLatticeR)) {
271 T boundaryPhysR[DESCRIPTOR::d] { };
272 blockGeometry.getPhysR(boundaryPhysR,boundaryLatticeR);
273 // check if neighbor is fluid cell
274 if (bulkIndicator(boundaryLatticeR)) {
275 T dist = -1; // distance to boundary
276 T qIpop = -1; // normed distance (Bouzidi distance) to boundary
277 const T norm = deltaR * util::norm<DESCRIPTOR::d>(descriptors::c<DESCRIPTOR>(iPop));
278 auto direction = -deltaR * c; // vector pointing from the boundary cell to the solid cell
279
280 // Check if distance calculation was performed correctly
281 if (indicatorAnalyticalBoundary.distance(dist, boundaryPhysR, direction, blockGeometry.getIcGlob())) {
282 qIpop = dist / norm;
283
284 // if distance function returned a dist. not suitable for Bouzidi -> fall-back
285 if ((qIpop < 0) || (qIpop > 1)) {
286 if(verbose) {
287 clout << "Error, non suitable dist. at lattice: (" << boundaryLatticeR << "), physical: (" << blockGeometry.getPhysR(boundaryLatticeR) << "), direction " << iPop << ". Fall-back to bounce-back." << std::endl;
288 }
289
290 // fall-back: half-way bounce back
291 qIpop = 0.5;
292 }
293 }
294 // if distance function couldn't compute any distance -> fall-back
295 else {
296 if(verbose) {
297 clout << "Error, no boundary found at lattice:(" << boundaryLatticeR << "), physical: (" << blockGeometry.getPhysR(boundaryLatticeR) << "), direction: " << iPop << ".Fall-back to bounce-back." << std::endl;
298 }
299
300 // fall-back: half-way bounce back
301 qIpop = 0.5;
302 }
303
304 // double check
305 if (qIpop >= 0) {
306 // Bouzidi require the fluid side neighbor of the boundary cell also to be fluid
307 if (bulkIndicator(boundaryLatticeR + descriptors::c<DESCRIPTOR>(iPop))) {
308 // Standard case, c.f. Bouzidi paper, setting Bouzidi-distance
309 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_DISTANCE>(iPop_opposite, qIpop);
310 }
311 else {
312 // If no fluid cell found: fall-back to bounce-back
313 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_DISTANCE>(iPop_opposite, T{0.5});
314 }
315 // Initialize velocity coefficients if necessary
316 if constexpr (std::is_same_v<OPERATOR, BouzidiVelocityPostProcessor>) {
317 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_VELOCITY>(iPop_opposite, 0);
318 }
319 // Initialize ade dirichlet coefficients if necessary
320 if constexpr (std::is_same_v<OPERATOR, BouzidiAdeDirichletPostProcessor>) {
321 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_ADE_DIRICHLET>(iPop_opposite, 0);
322 }
323 // Setting up the post processor, if this cell does not have one yet.
324 if (!block.isPadding(boundaryLatticeR)) {
326 boundaryLatticeR,
328 }
329 }
330 }
331 // if neigbour cell is not fluid
332 else {
333 // check if neighbor cell is not solid
334 if (blockGeometry.getMaterial(boundaryLatticeR) != 0) {
335 // fall-back to half-way bounce-back
336 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_DISTANCE>(iPop_opposite, T{0.5});
337 // Initialize velocity coefficients if necessary
338 if constexpr (std::is_same_v<OPERATOR, BouzidiVelocityPostProcessor>) {
339 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_VELOCITY>(iPop_opposite, 0);
340 }
341 // Initialize velocity coefficients if necessary
342 if constexpr (std::is_same_v<OPERATOR, BouzidiAdeDirichletPostProcessor>) {
343 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_ADE_DIRICHLET>(iPop_opposite, 0);
344 }
345 if (!block.isPadding(boundaryLatticeR)) {
347 boundaryLatticeR,
349 }
350 }
351 }
352 }
353 }
354 }
355 });
356}
357
359template<typename T, typename DESCRIPTOR>
361 SuperGeometry<T,DESCRIPTOR::d>& superGeometry, int material,
363 std::vector<int> bulkMaterials = std::vector<int>(1,1))
364{
365 setBouzidiVelocity<T,DESCRIPTOR>(sLattice, superGeometry.getMaterialIndicator(material), u, bulkMaterials);
366}
367
369template<typename T, typename DESCRIPTOR>
371 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
373 std::vector<int> bulkMaterials = std::vector<int>(1,1))
374{
375 setBouzidiVelocity<T,DESCRIPTOR>(sLattice, std::forward<decltype(boundaryIndicator)>(boundaryIndicator),
376 boundaryIndicator->getSuperGeometry().getMaterialIndicator(std::move(bulkMaterials)),
377 u);
378}
379
381template<typename T, typename DESCRIPTOR>
383 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
386{
387 auto& load = sLattice.getLoadBalancer();
388 auto& cuboidGeometry = boundaryIndicator->getSuperGeometry().getCuboidGeometry();
389 for (int iCloc = 0; iCloc < load.size(); ++iCloc) {
390 auto& cuboid = cuboidGeometry.get(load.glob(iCloc));
391 setBouzidiVelocity<T,DESCRIPTOR>(sLattice.getBlock(iCloc),
392 boundaryIndicator->getBlockIndicatorF(iCloc),
393 bulkIndicator->getBlockIndicatorF(iCloc),
394 u,
395 cuboid);
396 }
397}
398
400template<typename T, typename DESCRIPTOR>
402 BlockIndicatorF<T,DESCRIPTOR::d>& boundaryIndicator,
406{
407 const T deltaR = cuboid.getDeltaR();
408 block.forSpatialLocations([&](LatticeR<DESCRIPTOR::d> solidLatticeR) {
409 if (boundaryIndicator(solidLatticeR)) {
410 for (int iPop = 1; iPop < DESCRIPTOR::q; ++iPop) {
411 Vector<T,DESCRIPTOR::d> boundaryLatticeR(solidLatticeR + descriptors::c<DESCRIPTOR>(iPop));
412 if (block.isInside(boundaryLatticeR)) {
413 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
414 auto x_b = block.get(boundaryLatticeR);
415 const auto opp_bouzidi_dist = x_b.template getFieldComponent<descriptors::BOUZIDI_DISTANCE>(iPop_opposite);
416
417 // check if distance from the fluid cell to the solid cell is a valid bouzidi distance
418 if (opp_bouzidi_dist >= 0) {
419 T wallVelocity[DESCRIPTOR::d] = { };
420 T physicalIntersection[DESCRIPTOR::d] = { };
421 T boundaryPhysR[DESCRIPTOR::d] { };
422 cuboid.getPhysR(boundaryPhysR, boundaryLatticeR);
423
424 // calculating the intersection of the boundary with the missing link in physical coordinates
425 for ( int i = 0; i< DESCRIPTOR::d; ++i) {
426 physicalIntersection[i] = boundaryPhysR[i] + opp_bouzidi_dist * deltaR * descriptors::c<DESCRIPTOR>(iPop_opposite,i);
427 }
428
429 //Calculating the velocity at the wall intersection
430 u(wallVelocity, physicalIntersection);
431 const auto c = descriptors::c<DESCRIPTOR>(iPop_opposite);
432 T vel_coeff = c * Vector<T,DESCRIPTOR::d>(wallVelocity);
433
434 // set computed velocity into the bouzidi velocity field
435 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_VELOCITY>(iPop_opposite, vel_coeff);
436 }
437 }
438 }
439 }
440 });
441}
442
443template<typename T, typename DESCRIPTOR>
445 SuperGeometry<T,DESCRIPTOR::d>& superGeometry, int material,
446 T phi_d,
447 std::vector<int> bulkMaterials = std::vector<int>(1,1))
448{
449 setBouzidiAdeDirichlet<T,DESCRIPTOR>(sLattice, superGeometry.getMaterialIndicator(material), phi_d, bulkMaterials);
450}
451
452template<typename T, typename DESCRIPTOR>
454 SuperGeometry<T,DESCRIPTOR::d>& superGeometry, int material,
456 std::vector<int> bulkMaterials = std::vector<int>(1,1))
457{
458 setBouzidiAdeDirichlet<T,DESCRIPTOR>(sLattice, superGeometry.getMaterialIndicator(material), phi_d, bulkMaterials);
459}
460
461template<typename T, typename DESCRIPTOR>
463 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
465 T phi_d)
466{
467 auto& load = sLattice.getLoadBalancer();
468 auto& cuboidGeometry = boundaryIndicator->getSuperGeometry().getCuboidGeometry();
469 for (int iCloc = 0; iCloc < load.size(); ++iCloc) {
470 auto& cuboid = cuboidGeometry.get(load.glob(iCloc));
471 setBouzidiAdeDirichlet<T,DESCRIPTOR>(sLattice.getBlock(iCloc),
472 boundaryIndicator->getBlockIndicatorF(iCloc),
473 bulkIndicator->getBlockIndicatorF(iCloc),
474 phi_d,
475 cuboid);
476 }
477}
478
479template<typename T, typename DESCRIPTOR>
481 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
484{
485 auto& load = sLattice.getLoadBalancer();
486 auto& cuboidGeometry = boundaryIndicator->getSuperGeometry().getCuboidGeometry();
487 for (int iCloc = 0; iCloc < load.size(); ++iCloc) {
488 auto& cuboid = cuboidGeometry.get(load.glob(iCloc));
489 setBouzidiAdeDirichlet<T,DESCRIPTOR>(sLattice.getBlock(iCloc),
490 boundaryIndicator->getBlockIndicatorF(iCloc),
491 bulkIndicator->getBlockIndicatorF(iCloc),
492 phi_d,
493 cuboid);
494 }
495}
496
497template<typename T, typename DESCRIPTOR>
499 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
500 T phi_d,
501 std::vector<int> bulkMaterials = std::vector<int>(1,1))
502{
503 setBouzidiAdeDirichlet<T,DESCRIPTOR>(sLattice, std::forward<decltype(boundaryIndicator)>(boundaryIndicator),
504 boundaryIndicator->getSuperGeometry().getMaterialIndicator(std::move(bulkMaterials)),
505 phi_d);
506}
507
508template<typename T, typename DESCRIPTOR>
510 FunctorPtr<SuperIndicatorF<T,DESCRIPTOR::d>>&& boundaryIndicator,
512 std::vector<int> bulkMaterials = std::vector<int>(1,1))
513{
514 setBouzidiAdeDirichlet<T,DESCRIPTOR>(sLattice, std::forward<decltype(boundaryIndicator)>(boundaryIndicator),
515 boundaryIndicator->getSuperGeometry().getMaterialIndicator(std::move(bulkMaterials)),
516 phi_d);
517}
518
519template<typename T, typename DESCRIPTOR>
521 BlockIndicatorF<T,DESCRIPTOR::d>& boundaryIndicator,
523 T phi_d,
525{
526 block.forSpatialLocations([&](LatticeR<DESCRIPTOR::d> solidLatticeR) {
527 if (boundaryIndicator(solidLatticeR)) {
528 for (int iPop = 1; iPop < DESCRIPTOR::q; ++iPop) {
529 Vector<T,DESCRIPTOR::d> boundaryLatticeR(solidLatticeR + descriptors::c<DESCRIPTOR>(iPop));
530 if (block.isInside(boundaryLatticeR)) {
531 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
532 auto x_b = block.get(boundaryLatticeR);
533 const auto opp_bouzidi_dist = x_b.template getFieldComponent<descriptors::BOUZIDI_DISTANCE>(iPop_opposite);
534
535 // check if distance from the fluid cell to the solid cell is a valid bouzidi distance
536 if (opp_bouzidi_dist >= 0) {
537 // set computed velocity into the bouzidi velocity field
538 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_ADE_DIRICHLET>(iPop_opposite, phi_d);
539 }
540 }
541 }
542 }
543 });
544}
545
546template<typename T, typename DESCRIPTOR>
548 BlockIndicatorF<T,DESCRIPTOR::d>& boundaryIndicator,
552{
553 block.forSpatialLocations([&](LatticeR<DESCRIPTOR::d> solidLatticeR) {
554 if (boundaryIndicator(solidLatticeR)) {
555 for (int iPop = 1; iPop < DESCRIPTOR::q; ++iPop) {
556 Vector<T,DESCRIPTOR::d> boundaryLatticeR(solidLatticeR + descriptors::c<DESCRIPTOR>(iPop));
557 if (block.isInside(boundaryLatticeR)) {
558 const int iPop_opposite = descriptors::opposite<DESCRIPTOR>(iPop);
559 auto x_b = block.get(boundaryLatticeR);
560 const auto opp_bouzidi_dist = x_b.template getFieldComponent<descriptors::BOUZIDI_DISTANCE>(iPop_opposite);
561
562 // check if distance from the fluid cell to the solid cell is a valid bouzidi distance
563 if (opp_bouzidi_dist >= 0) {
564 T boundaryPhysR[DESCRIPTOR::d] { };
565 T phi_at_cell[1] { };
566 cuboid.getPhysR(boundaryPhysR, boundaryLatticeR);
567
568 phi_d(phi_at_cell, boundaryPhysR);
569
570 // set computed velocity into the bouzidi velocity field
571 block.get(boundaryLatticeR).template setFieldComponent<descriptors::BOUZIDI_ADE_DIRICHLET>(iPop_opposite, phi_at_cell[0]);
572 }
573 }
574 }
575 }
576 });
577}
578}
579
580#endif
AnalyticalF are applications from DD to XD, where X is set by the constructor.
Representation of a block geometry.
Vector< T, D > getPhysR(LatticeR< D > latticeR)
int getMaterial(LatticeR< D > latticeR) const
returns the (iX,iY) entry in the 2D scalar field
int getIcGlob() const
Read only access to the global iC number which is given !=-1 if the block geometries are part of a su...
T getDeltaR() const
Read only access to the voxel size given in SI units (meter)
Platform-abstracted block lattice for external access and inter-block interaction.
virtual void addPostProcessor(std::type_index stage, LatticeR< DESCRIPTOR::d > latticeR, PostProcessorPromise< T, DESCRIPTOR > &&promise)=0
Schedule post processor for application to latticeR in stage.
Cell< T, DESCRIPTOR > get(CellID iCell)
Get Cell interface for index iCell.
void forSpatialLocations(F f) const
bool isPadding(LatticeR< D > latticeR) const
Return whether location is valid.
bool isInside(LatticeR< D > latticeR) const
Return whether location is valid.
static constexpr OperatorScope scope
Post processor for the zero-velocity Bouzidi boundary.
static constexpr OperatorScope scope
void apply(CELL &x_b) any_platform
Post processor for the velocity Bouzidi boundary.
static constexpr OperatorScope scope
void apply(CELL &x_b) any_platform
Smart pointer for managing the various ways of passing functors around.
Definition functorPtr.h:60
class for marking output with some text
void setMultiOutput(bool b)
enable message output for all MPI processes, disabled by default
Representation of a statistic for a parallel 2D geometry.
std::unique_ptr< SuperIndicatorF< T, D > > getMaterialIndicator(std::vector< int > &&materials)
Returns a material indicator using the given vector of materials.
Super class maintaining block lattices for a cuboid decomposition.
BlockLattice< T, DESCRIPTOR > & getBlock(int locC)
Return BlockLattice with local index locC.
LoadBalancer< T > & getLoadBalancer()
Read and write access to the load balancer.
Plain old scalar vector.
Definition vector.h:47
void apply(CELL &x_b) any_platform
static constexpr OperatorScope scope
Top level namespace for all of OpenLB.
void setBouzidiVelocity(SuperLattice< T, DESCRIPTOR > &sLattice, SuperGeometry< T, DESCRIPTOR::d > &superGeometry, int material, AnalyticalF< DESCRIPTOR::d, T, T > &u, std::vector< int > bulkMaterials=std::vector< int >(1, 1))
Set Bouzidi velocity boundary on material cells of sLattice.
void setBouzidiBoundary(SuperLattice< T, DESCRIPTOR > &sLattice, FunctorPtr< SuperIndicatorF< T, DESCRIPTOR::d > > &&boundaryIndicator, FunctorPtr< SuperIndicatorF< T, DESCRIPTOR::d > > &&bulkIndicator, IndicatorF< T, DESCRIPTOR::d > &indicatorAnalyticalBoundary)
Set Bouzidi boundary on indicated cells of sLattice.
std::conditional_t< D==2, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
Definition aliases.h:218
constexpr T norm(const ScalarVector< T, D, IMPL > &a)
Euclidean vector norm.
std::conditional_t< D==2, IndicatorF2D< T >, IndicatorF3D< T > > IndicatorF
Definition aliases.h:258
OperatorScope
Block-wide operator application scopes.
Definition operator.h:54
@ PerCell
Per-cell application, i.e. OPERATOR::apply is passed a CELL concept implementation.
std::conditional_t< D==2, SuperIndicatorF2D< T >, SuperIndicatorF3D< T > > SuperIndicatorF
Definition aliases.h:208
std::conditional_t< D==2, Cuboid2D< T >, Cuboid3D< T > > Cuboid
Definition aliases.h:37
void setBouzidiAdeDirichlet(SuperLattice< T, DESCRIPTOR > &sLattice, SuperGeometry< T, DESCRIPTOR::d > &superGeometry, int material, T phi_d, std::vector< int > bulkMaterials=std::vector< int >(1, 1))
#define any_platform
Define preprocessor macros for device-side functions, constant storage.
Definition platform.h:78
Interpolated Bounce Back (Bouzidi) for ADE Dirichlet field.
Interpolated Bounce Back (Bouzidi) distance field.
static constexpr auto getInitialValue()
Interpolated Bounce Back (Bouzidi) velocity coefficient field.
static constexpr auto getInitialValue()
Base of a field whose size is defined by [C,U_1,...,U_N]^T * [1,V_1,...V_N].
Identity type to pass non-constructible types as value.
Definition meta.h:79
Communication after propagation.
Definition stages.h:36