BounceBack boundary
OpenLB – Open Source Lattice Boltzmann Code › Forums › on OpenLB › General Topics › BounceBack boundary
- This topic has 10 replies, 3 voices, and was last updated 1 year, 3 months ago by Adrian.
-
AuthorPosts
-
July 22, 2021 at 12:40 pm #5843GloriousfaceParticipant
Hello ,everyone
Is the BounceBack scheme in bstep2d flow standard BounceBack?
July 22, 2021 at 12:49 pm #5844AdrianKeymasterHow do you define standard Bounce Back? OpenLB’s bounce back dynamics implement fullway bounce back (i.e. the populations are locally reverted during collision and not at streaming time).
July 23, 2021 at 4:31 am #5845GloriousfaceParticipantThank you very much for your reply. What I mean by the standard BounceBack is that the particles bounce directly at the boundary, and the boundary is at the grid point, rather than half step bounce by pushing half of the grid inward. I don’t know whether the standard BounceBack realized in OpenLB is what I mean ?
- This reply was modified 3 years, 4 months ago by Gloriousface.
July 23, 2021 at 10:01 am #5847AdrianKeymasterBounce back implemented as dynamics in OpenLB (i.e. as a local collision step) provide “fullway” bounce back. “Halfway” bounce back (implemented using a PostProcessor / Streaming modification) reflects the populations during streaming and e.g. requires no solid nodes. Both of them model a boundary mid way between grid points.
You can read more details in e.g. Krüger et al. “The Lattice Boltzmann Method: Principles and Practice” Section 5.3.3.2.
August 15, 2023 at 9:43 am #7695MikeParticipantHello Adian,
Does the class BounceBack in olb-1.4 means full-way bounce back? I am running transient cases, and I learned that half-way bounce back is more accurate than full-way in time. so I wonder how to implement it in openlb.
since you have mentioned postprocessor previously, then I tried with that but it didn’t work well. Could you elaborate how to implement it? Thank you in advance.
Here is my plan, since half-way only change streaming process, I define walls with bulk dynamics and use a postprocessor to make modifications, which basically implement bounce-back rules according to their directions.
Yours,
MikeAugust 22, 2023 at 9:59 am #7699AdrianKeymasterYes, the BounceBack dynamics in OpenLB model full-way bounce back in all releases, including 1.4.
Can you show your post processor attempt that did not work well?
In any case, the solid nodes where the populations are streamed to prior to executing half-way bounce back do not need to collide (i.e. you can use the
NoDynamics
). During thePostStreaming
stage you can then copy the streamed populations back to the opposite directions of the non-solid cell they came from.August 23, 2023 at 2:24 am #7701MikeParticipantThank you for your reply!
I agree with your idea.
Below is my code :
std::vector<int> unknownIndexes;
// east-top
// I change the oritation in self-defined sethalfbbboundary.hh
if(orientation == 8){unknownIndexes = {3};
}
//east bottom
else if(orientation == -8){unknownIndexes = {1};
}
// west top
else if(orientation == 9){unknownIndexes = {5};
}
// west bottom
else if(orientation == -9){
unknownIndexes = {7};}
else{
unknownIndexes = util::subIndexOutgoing<DESCRIPTOR, direction,
orientation>();
}
auto cell = blockLattice.get(x, y);for (unsigned i = 0; i < unknownIndexes.size(); ++i) {
cell[unknownIndexes[i]] = cell.neighbor(descriptors::c<DESCRIPTOR>(unknownIndexes[i]))[util::opposite<DESCRIPTOR>(unknownIndexes[i])];
}
as in main function, I define solid boundaries nodynamics.
August 23, 2023 at 2:57 am #7704MikeParticipantSorry, I answered too fast and has used up my modified limit…
your idea seems different from what I thought before, yours in code is:
cell.neighbor(descriptors::c<DESCRIPTOR>(unknownIndexes[i]))[util::opposite<DESCRIPTOR>(unknownIndexes[i])] = cell[unknownIndexes[i]];am I right?
I will change code and see if the result is fine. Thank you and sorry to bother again…August 24, 2023 at 10:23 am #7708AdrianKeymasterThe specifics depend on which cells you assign the post processor to. If you show me your entire post processor and setter code this should become clear (In any case I recommend using the new style operators with
apply
method templates instead of the deprecatedprocessSubDomain
style (unclear what you are using, just to make sure))The common approach in OpenLB is to templatize the boundary operators on the discrete normal directions. Of course you can also read this information from cell-local fields instead – where do you get your
unknownIndexes
array from?August 24, 2023 at 11:23 am #7709MikeParticipantHere is my code, I do use discretnormal directions to get unknownIndexes.
As for setter code, it is like:
setHalfBounceBackBoundary(NSlattice, omega, supergeometry, 4);
4 means solid node, which is implemented with nodynamics.template<typename T, typename DESCRIPTOR, class MixinDynamics>
void setHalfBounceBackBoundary(BlockLatticeStructure2D<T,DESCRIPTOR>& block, T omega, BlockIndicatorF2D<T>& indicator, bool includeOuterCells)
{
OstreamManager clout(std::cout, “setHalfBounceBackBoundary2D”);
auto& blockGeometryStructure = indicator.getBlockGeometryStructure();
const int margin = includeOuterCells ? 0 : 1;
/*
*x0,x1,y0,y1 Range of cells to be traversed
**/
int x0 = margin;
int y0 = margin;
int x1 = blockGeometryStructure.getNx()-1 -margin;
int y1 = blockGeometryStructure.getNy()-1 -margin;
std::vector<int> discreteNormal(3, 0);
for (int iX = x0; iX <= x1; ++iX) {
for (int iY = y0; iY <= y1; ++iY) {
//momenta vector provisionally inside src/core/blockLatticeStructure3D.h
Momenta<T, DESCRIPTOR>* momenta = nullptr;
Dynamics<T, DESCRIPTOR>* dynamics = nullptr;
// Momenta<T, DESCRIPTOR>* momenta = new BulkMomenta<T, DESCRIPTOR>();
// Dynamics<T, DESCRIPTOR>* dynamics = new NoDynamics<T, DESCRIPTOR>();
PostProcessorGenerator2D<T, DESCRIPTOR>* postProcessor = nullptr;
if (indicator(iX, iY)) {
discreteNormal = indicator.getBlockGeometryStructure().getStatistics().getType(iX, iY);
clout << discreteNormal[0] << ” ” << discreteNormal[1] << ” ” << discreteNormal[2] << std::endl;if (discreteNormal[0] == 0) {
//set the momenta,dynamics and post processor on the indicated local velocity boundary cells
if (discreteNormal[1] == 1) {
postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 0, 1>(iX, iY);
}
else if (discreteNormal[1] == -1) {postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 0, -1>(iX, iY);
}
else if (discreteNormal[2] == 1) {postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, 1>(iX, iY);
}
else if (discreteNormal[2] == -1) {postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, -1>(iX, iY);
}
else {
clout << “here “<< “Could not setHalfBounceBackBoundary2D (” << iX
<< “, ” << iY << “)” << std::endl;
clout << discreteNormal[0] << ” ” << discreteNormal[1] << ” ” << discreteNormal[2] << std::endl;
}
}
else if (discreteNormal[0] == 1) {
//sets the momenta, dynamics and post processors on indicated localVelocityCornerBoundary cells
if (discreteNormal[1] == 1) {
if (discreteNormal[2] == 1) {
postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, 8>(iX, iY);
}
else if (discreteNormal[2] == -1) {
// clout << “5” << endl;postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, -8>(iX, iY);
}
else {
clout << “Could not setHalfBounceBackBoundary2D (” << iX
<< “, ” << iY << “)” << std::endl;
}
}
else if (discreteNormal[1] == -1) {
if (discreteNormal[2] == 1) {
postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, 9>(iX, iY);
}
else if (discreteNormal[2] == -1) {
postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, -9>(iX, iY);
}
else {
clout << “Could not setHalfBounceBackBoundary2D (” << iX
<< “, ” << iY << “)” << std::endl;
}
}
}
//sets momenta, dynamics and postProcessors on local InnerVelocityCornerBoundary Cells
else if (discreteNormal[0] == 2) {
if (discreteNormal[1] == 1) {
if (discreteNormal[2] == 1) {postProcessor = nullptr;
}
else if (discreteNormal[2] == -1) {postProcessor = nullptr;
}
else {
clout << “Could not setHalfBounceBackBoundary2D (” << iX
<< “, ” << iY << “)” << std::endl;
}
}
else if (discreteNormal[1] == -1) {
if (discreteNormal[2] == 1) {postProcessor = nullptr;
}
else if (discreteNormal[2] == -1) {
clout << “6” << endl;// postProcessor = new BoundaryStreamPostProcessorGenerator2D<T, DESCRIPTOR, 1, 8>(iX, iY);
}
else {
clout << “Could not setHalfBounceBackBoundary2D (” << iX
<< “, ” << iY << “)” << std::endl;
}
}
}setBoundary<T, DESCRIPTOR, MixinDynamics>(block, omega, iX,iY, momenta, dynamics, postProcessor);
}
}
}}
September 4, 2023 at 10:33 am #7723AdrianKeymasterOk, this is a setter function for a legacy-style BC (i.e. this won’t work on GPUs. I recommend writing all new models in the new “operator” style. You can check out e.g. the local/interpolated velocity/pressure BCs and the user guide FAQ for an introduction. The code will also be much more compact).
Did you already implement the
BoundaryStreamPostProcessorGenerator2D
“generator” and its post processor?What is your specific question?
-
AuthorPosts
- You must be logged in to reply to this topic.