Skip to content

BounceBack boundary

Viewing 11 posts - 1 through 11 (of 11 total)
  • Author
    Posts
  • #5843
    Gloriousface
    Participant

    Hello ,everyone

    Is the BounceBack scheme in bstep2d flow standard BounceBack?

    #5844
    Adrian
    Keymaster

    How 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).

    #5845
    Gloriousface
    Participant

    Thank 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.
    #5847
    Adrian
    Keymaster

    Bounce 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.

    #7695
    Mike
    Participant

    Hello 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,
    Mike

    #7699
    Adrian
    Keymaster

    Yes, 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 the PostStreaming stage you can then copy the streamed populations back to the opposite directions of the non-solid cell they came from.

    #7701
    Mike
    Participant

    Thank 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.

    • This reply was modified 1 year, 3 months ago by Mike.
    • This reply was modified 1 year, 3 months ago by Mike.
    #7704
    Mike
    Participant

    Sorry, 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…

    #7708
    Adrian
    Keymaster

    The 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 deprecated processSubDomain 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?

    #7709
    Mike
    Participant

    Here 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);

    }
    }
    }

    }

    #7723
    Adrian
    Keymaster

    Ok, 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?

Viewing 11 posts - 1 through 11 (of 11 total)
  • You must be logged in to reply to this topic.