OpenLB – Open Source Lattice Boltzmann Code › Forums › on Lattice Boltzmann Methods › General Topics › Disappearing internal boundary conditions with periodicity
 This topic has 0 replies, 1 voice, and was last updated 3 weeks ago by loganrk.

AuthorPosts

October 28, 2019 at 8:12 pm #4654loganrkParticipant
I am using Electron with TypeScript to prototype some fluid simulation code which will eventually go into a game. So far, I have been using static boundary conditions (with simulation calculations only occurring on the interior of the grid, and values for the boundary cells remaining fixed), and everything appears to work fine in that regime. In particular, I can impose internal boundary conditions (for example, enforcing that a certain density of fluid always exits a certain lattice site on every frame, to simulate a hose/rocket nozzle/whatever) by just manually setting the cell values in between each simulation step.
However, if I switch to using periodic boundary conditions, the whole simulation become static. I just get constant fluid density everywhere, for all time, and it’s like all of my internal boundary conditions are erased, no matter where in the simulation cycle (before streaming or before collision) I choose to assert them. I am not sure if periodic boundary conditions will end up being relevant for the game, but this failure makes me think there must be some other subtle bug somewhere in the simulation.
The complete code is available at https://github.com/gliese1337/balloonprototype/tree/deopt , but what I expect are the relevant portions are as follows:
class LatticeBoltzmann { private streamed: Float32Array; // microscopic densities along each lattice direction private collided: Float32Array; public rho: Float32Array; // macroscopic density; cached for rendering ... public stream(barriers: boolean[]) { const { xdim, ydim, collided, streamed } = this; const index = (x: number, y: number) => (x%xdim)+(y%ydim)*xdim; const cIndex = (x: number, y: number, s: 11, j: number) => 9*(((x+s*cxs[j])%xdim)+((y+s*cys[j])%ydim)*xdim)+j; // Move particles along their directions of motion: for (let y=1; y<ydim1; y++) { for (let x=1; x<xdim1; x++) { const i = index(x, y); const i9 = i*9; for (let j=0;j<9;j++) { streamed[i9 + j] = collided[cIndex(x, y, 1, j)]; } } } // Handle bounceback from barriers for (let y=0; y<ydim; y++) { for (let x=0; x<xdim; x++) { const i = index(x, y); const i9 = i*9; if (barriers[i]) { for (let j=1;j<9;j++) { streamed[cIndex(x, y, 1, j)] = collided[i9 + opp[j]]; } } } } } // Set all densities in a cell to their equilibrium values for a given velocity and density: public setEquilibrium(x: number, y: number, ux: number, uy: number, rho: number) { const { xdim, streamed } = this; const i = x + y*xdim; this.rho[i] = rho; const i9 = i*9; const u2 = 1  1.5 * (ux * ux + uy * uy); for (let j = 0; j < 9; j++) { const dir = cxs[j]*ux + cys[j]*uy; streamed[i9+j] = weights[j] * rho * (u2 + 3 * dir + 4.5 * dir * dir); } } }
Lattice data is stored in two flat arrays,
collided
which holds the end states after the collision step and serves as input to the streaming step, andstreamed
, which holds the end states after the streaming step and serves as input to the next collision step. The 9 vector components for the D2Q9 lattice are stored in contiguous blocks, which are then grouped into rows. Note that I am already using mod operations to calculate array indices from lattice coordinates; this is completely irrelevant as long as the simulation calculations only range over the interior of the lattice, but it should make periodic boundaries readytogo as soon as thefor (let y=1; y<ydim1; y++)
andfor (let x=1; x<xdim1; x++)
loops have their bounds changed tofor (let y=0; y<ydim; y++)
andfor (let x=0; x<xdim; x++)
, respectively. And indeed it is that specific 6character change that I am having trouble with.The
setEquilibrium
method is used to impose boundary conditions. In the driver code, it is currently being called like this, once per frame:// Make fluid flow in from the left edge and out through the right edge function setBoundaries(LB: LatticeBoltzmann, ux: number) { for (let y=0; y<ydim; y++) { LB.setEquilibrium(0, y, ux, 0, 1); LB.setEquilibrium(xdim1, y, ux, 0, 1); } }
With static boundary conditions, calling that once per frame happens to be superfluous, because it only alters the boundary lattice sites. Shifting the hardcoded xvalues to the interior of the lattice, however, (where reasserting the boundary conditions once per frame is in fact necessary) does exactly what you would expect–it makes fluid appear or disappear at specific locations. Switching to periodic boundary conditions, however, results in that code ceasing to have any visible effect.
So… anybody know what I might be doing wrong?

AuthorPosts
 You must be logged in to reply to this topic.