Collisions operators in LBM_Saclay
The collision operators are defined as C++ structures in the source file src/kernels/Collision_operators.h
. The most popular are implemented in LBM_Saclay: BGK, TRT, MRT and Central Moment (CM).
Batnaghar-Gross-Krook (BGK) operator
In LBM_Saclay, that collision operator is performed in BGKCollider
and writes
That collision operator requires four inputs:
BGKCollider
Inputs
\(f_i\): distribution function for current time \(t\) and position contained in
f
.\(f_i^{eq}\): equilibrium distribution function for current time \(t\) and position contained in
feq
.\(\tau\): relaxation rate contained in
tau
.\(\mathcal{S}_i\) is the force or source term contained in
S0
.
Output
\(f_i^{\star}=f_i+\Omega_i^{BGK}+\mathcal{S}_i\): post-collision distribution function
BGK in LBM_Saclay
template <int dim, int npop> struct BGKCollider {
public:
using FState = typename Kokkos::Array<real_t, npop>;
FState f;
FState feq;
FState S0;
//~ FState S1;
real_t tau;
KOKKOS_INLINE_FUNCTION
BGKCollider(const LBMLattice<dim, npop> &lattice){};
KOKKOS_INLINE_FUNCTION
real_t collide(int ipop) const {
return (f[ipop] * (1.0 - 1.0 / tau) + feq[ipop] / tau + S0[ipop]);
};
KOKKOS_INLINE_FUNCTION
real_t get_feq(int ipop) const { return feq[ipop]; };
};
Two-Relaxation-Times (TRT) operator
The TRT collision operator is performed in TRTCollider
and writes
where the symmetric parts of \(f_{i}\) and \(f_{i}^{eq}\) are defined by
and the anti-symmetric parts by
In Eqs. (151) and (152), the bar notation means the opposite directions \(\boldsymbol{c}_{\overline{i}}=-\boldsymbol{c}_{i}\). Example on the standard D2Q9 lattice \(\boldsymbol{c}_{\overline{1}}=-\boldsymbol{c}_{1}=\boldsymbol{c}_{3}\) . The TRT collision operator considers the collision stage with two relaxation parameters \(\tau^{+}\) and \(\tau^{-}\) acting respectively on the symmetric part and the anti-symmetric part. When the equilibrium distribution function is defined such as the Navier-Stokes equations are recovered, the kinematic viscosity is related to the parameter \(\tau^{-}\) by:
and \(\tau^{+}\) is a free paramater to tune to improve accuracy and stability. In practice, the parameter \(\Lambda\) is often used for that purpose:
That collision operator requires five inputs:
TRTCollider
Inputs
\(f_i\): distribution function for current time \(t\) and position contained in
f
.\(f_i^{eq}\): equilibrium distribution function for current time \(t\) and position contained in
feq
.\(\tau^{+}\): symmetric relaxation rate contained in
tauS
.\(\tau^{-}\): anti-symmetric relaxation rate contained in
tauA
.\(\mathcal{S}_i\) is the force or source term contained in
S0
.
Output
\(f_i^{\star}=f_i+\Omega_i^{TRT}+\mathcal{S}_i\): post-collision distribution function
The C++ structure TRTCollider is shown below:
TRT in LBM_Saclay
template <int dim, int npop> struct TRTCollider {
using FState = typename Kokkos::Array<real_t, npop>;
using LBM_speeds_opposite =
typename LBMBaseFunctor<dim, npop>::LBM_speeds_opposite;
LBM_speeds_opposite Ebar;
FState f, feq;
real_t tauS, tauA;
FState S0;
KOKKOS_INLINE_FUNCTION
void setTau(real_t tau, int TRT_tauMethod) { tauA = tau; };
KOKKOS_INLINE_FUNCTION
TRTCollider(const LBMLattice<dim, npop> &lattice) { Ebar = lattice.Ebar; };
//~ FState S1;
KOKKOS_INLINE_FUNCTION
real_t collide(int ipop) const {
const int ipopb = Ebar[ipop];
const real_t fi = f[ipop];
const real_t fib = f[ipopb];
const real_t feqi = feq[ipop];
const real_t feqib = feq[ipopb];
//~ real_t pS=0.5*((f[ipop]+f[ipopb])-(feq[ipop]+feq[ipopb]));
//~ real_t pA=0.5*((f[ipop]-f[ipopb])-(feq[ipop]-feq[ipopb]));
return (f[ipop] - 0.5 * (((fi + fib) - (feqi + feqib)) / tauS +
((fi - fib) - (feqi - feqib)) / tauA) + S0[ipop]);
}
KOKKOS_INLINE_FUNCTION
real_t get_feq(int ipop) const { return feq[ipop]; }
};
Multiple-Relaxation-Times (MRT) operator
LBE with vector notations
If we consider the space of distribution functions of dimension \(N_{pop}+1\), the vector notations can be used:
and the LBE writes
MRT collision operator
The MRT collision operator considers the relaxation in the space of moments instead of the space of distribution functions. For that purpose a matrix \(\boldsymbol{M}\) is used:
where
\(\boldsymbol{M}\) represents a change of basis from “space of distribution functions” to \(\rightarrow\) “space of moments”
\(\boldsymbol{S}\) contains the relaxation coefficients
\(\boldsymbol{M}\) and \(\boldsymbol{S}\) are two invertible matrices of dim \((N_{pop}+1)\times(N_{pop}+1)\)
Relaxation in space of moments
Eq. (157) means that a change of basis is first done:
Next, in the space of moments, the relaxation occurs by applying the matrix \(\boldsymbol{S}\):
Finally, we go back in the space of distribution functions by applying \(\boldsymbol{M}^{-1}\)
Example for lattice D2Q9
To construct the matrix \(\boldsymbol{M}\), two main procedures exist (see [1]): Gram-Schmidt and Hermite. In LBM_Saclay, the first one is applied. One example is given with the D2Q9 lattice where the nine moving vectors are defined by \(\boldsymbol{e}_i\) (for \(i=0,...,8\)):
In vector notations, the moment of order 0 (density) can be obtained by
where the vector \(\boldsymbol{v}_{\rho}\) must be defined by \(\boldsymbol{v}_{\rho}=(1,1,1,1,1,1,1,1,1)\). The moment of order 1 (impulsion) can be obtained by
where the vector \(\boldsymbol{v}_{j_{x}}=(0,1,0,-1,0,1,-1,-1,1)\) is defined by the first line of the lattice D2Q9 and \(\boldsymbol{v}_{j_{y}}=(0,0,1,0,-1,1,1,-1,-1)\) is the second line. To obtain the matrix \(\boldsymbol{M}\) of dimension \(9\times9\), six supplementary orthogonal vectors must be defined. After application of the Gram-Schmidt procedure, the matrix \(\boldsymbol{M}\) is
and its inverse is:
For that definition of matrix \(\boldsymbol{M}\), we see that vector \(\boldsymbol{v}_{\rho}\) is the first line of the matrix, \(\boldsymbol{v}_{j_{x}}\) is the fourth line and \(\boldsymbol{v}_{j_{y}}\) is the sixth line. The corresponding moment vector is:
One advantage of the Gram-Schmidt procedure is that the matrix \(\boldsymbol{S}\) is diagonal:
MRTCollider
Inputs
\(f_i\): distribution function for current time \(t\) and position contained in
f
.\(f_i^{eq}\): equilibrium distribution function for current time \(t\) and position contained in
feq
.\(\tau\): relaxation rate contained in
tau
and involved in matrix \(\boldsymbol{S}\) below.\(\mathcal{S}_i\) is the force or source term contained in
S0
.\(\boldsymbol{M}\) is the matrix contained in
M
.\(\boldsymbol{M}^{-1}\) is the inverse matrix contained in
Minv
.\(\boldsymbol{S}\) is the diagonal matrix contained in
S
.
Output
\(\boldsymbol{f}^{\star}=\boldsymbol{f}+\boldsymbol{\Omega}^{MRT}+\boldsymbol{\mathcal{S}}\): post-collision distribution function
Central moments collision operator
In LBM_Saclay, the “central moment” collision operator is tested in NSAC_Comp
kernel. In that kernel the equilibrium distribution function is formulated with a dimensionless pressure and the first-order moment is the velocity (and not the impulsion). The central moment method is inspired from reference [2].
General definition of moments
The general definition of 2D central moment is
and discrete moments in velocity space:
where \(\alpha\) and \(\beta\) are two positive integers. Eq. (170) means for
\(\alpha=0\) and \(\beta=0\):
\(\alpha=1\) and \(\beta=0\):
\(\alpha=0\) and \(\beta=1\):
and so on. As done in MRT collision operator, the vector of moments can be obtained with a transformation matrix \(\mathbb{M}\) from space of distribution functions to space of moments. The matrix \(\mathbb{M}\) is defined below.
Definition of central moments
The central moment definition is an extension of moment Eq. (169) with macroscopic velocity components \(u_x\) and \(u_y\):
and its discrete version writes:
The central moment collision operator adds a new matrix of transformation \(\mathbb{N}\) which contains the supplementary shift with velocity components \(u_x\) and \(u_y\). The matrix \(\mathbb{N}\) is defined below.
Collision in space of central moments
Collision stage
The collision stage is performed in the space of central moments which writes:
The central moment \(\boldsymbol{\kappa}\) is obtained from distribution function \(\boldsymbol{f}\) by applying successive matrix transformations:
where the matrices \(\mathbb{M}\) and \(\mathbb{M}_p\) are defined by
The matrix \(\mathbb{N}:=\mathbb{N}(u_x,u_y)\) depends on components of velocity \(u_x\) and \(u_y\):
Matrix \(\mathbb{T}\) in LBM_Saclay
In LBM_Saclay, matrices \(\mathbb{M}\), \(\mathbb{N}\) and \(\mathbb{M}_{p}\) are not explicitely defined. Only the result of their product \(\mathbb{T}=\mathbb{M}_{p}\mathbb{N}\mathbb{M}\) is written in Collision_operators.h
. All matrices are written inside a python script CMLBM_Sympy.py
which performs the product and generates the C++ code. The output \(\mathbb{T}\) is “copy-paste” in function Matrix get_T(real_t u, real_t v)
of struct CMCollider
.
KOKKOS_INLINE_FUNCTION
Matrix get_T(real_t u, real_t v) const {
if constexpr(npop==NPOP_D2Q9){
...
}
Collision matrix \(\mathbb{S}\)
The collision matrix \(\mathbb{S}\) is diagonal and contains the relaxation rates:
The collision frequencies \(s_{0}\) and \(s_{1}\) are fixed equal to 1 to ensure conservation of corresponding moments. The following two frequencies \(s_{b}\) and \(s_{\nu}\) are related to bulk and kinematic viscosities by:
Finally \(s_{3}\) and \(s_{4}\) are tunable relaxation frequencies. Let us mention that here, the matrix \(\mathbb{S}\) is diagonal compared to Eq. (16) of the reference. This is because we used a supplementary matrix \(\mathbb{M}_p\) defined above to use a diagonal matrix in collision stage.
Matrix \(\mathbb{S}\) in LBM_Saclay
In LBM_Saclay, the diagonal matrix \(\mathbb{S}\) is written in file LBMScheme_NS_AC_Comp.h
// Remplissage de la matrice S
for (int i = 0; i < npop; i++) {
if (Model.tauMatrixNS[i] != -1.0){
collider.S[i] = Model.tauMatrixNS[i];
} else {
collider.S[i] = tauInv;
}
}
Equilibrium and force in central moments framework
In central moment framework, the equilibrium central moment \(\boldsymbol{\kappa}^{eq}\) and the force term are respectively defined by
\(\boldsymbol{\kappa}^{eq}\) and \(\tilde{\boldsymbol{F}}\) in LBM_Saclay
In LBM_Salcay, all components of equilibrium central moment \(\boldsymbol{\kappa}^{eq}\) are written in LBMScheme_NS_AC_Comp.h
// Equilibrium moment
collider.CMeq[0] = m00;
collider.CMeq[1] = (1.0-m00)*lbmState[IU];
collider.CMeq[2] = (1.0-m00)*lbmState[IV];
collider.CMeq[3] = (m00-1.0)*(SQR(lbmState[IU]) + SQR(lbmState[IV])+2*cs2)+2*cs2;
collider.CMeq[4] = (m00-1.0)*(SQR(lbmState[IU]) - SQR(lbmState[IV]));
collider.CMeq[5] = (m00-1.0)*lbmState[IU]*lbmState[IV];
collider.CMeq[6] = (1.0-m00)*lbmState[IV]*(SQR(lbmState[IU])+cs2);
collider.CMeq[7] = (1.0-m00)*lbmState[IU]*(SQR(lbmState[IV])+cs2);
collider.CMeq[8] = (m00-1.0)*(SQR(lbmState[IU]*lbmState[IV])+cs2*(SQR(lbmState[IU])+SQR(lbmState[IV]))+cs2*cs2)+cs2*cs2;
...
// Forcing term
collider.Ft[0] = 0.0;
collider.Ft[1] = ForceTot[IX]*rhoinv;
collider.Ft[2] = ForceTot[IY]*rhoinv;
collider.Ft[3] = 0.0;
collider.Ft[4] = 0.0;
collider.Ft[5] = 0.0;
collider.Ft[6] = cs2*ForceTot[IY]*rhoinv;
collider.Ft[7] = cs2*ForceTot[IX]*rhoinv;
collider.Ft[8] = 0.0;
Streaming
The streaming stage is performed, as usual, in space of distribution functions. After collision, the central moment \(\boldsymbol{\kappa}^{\star}\) is transformed back by
where the matrices are defined by
and the standard streaming stage can be applied:
Matrix \(\mathbb{T}^{-1}\) in LBM_Saclay
Once again, in LBM_Saclay, matrices \(\mathbb{M}^{-1}\), \(\mathbb{N}^{-1}\) and \(\mathbb{M}_{p}^{-1}\) are not explicitely defined. Only the result of their product \(\mathbb{T}^{-1}=\mathbb{M}^{-1}\mathbb{N}^{-1}\mathbb{M}^{-1}_{p}\) is written in Collision_operators.h
. All inverse matrices are written inside the same python script CMLBM_Sympy.py
which performs the product and generates the C++ code. The output \(\mathbb{T}^{-1}\) is “copy-paste” in function Matrix get_Tinv(real_t u, real_t v)
of struct CMCollider
.
KOKKOS_INLINE_FUNCTION
Matrix get_Tinv(real_t u, real_t v) const {
if constexpr(npop==NPOP_D2Q9){
...
}
Bibliography
Section author: Alain Cartalade