Descriptor and External Field of Palabos
For the lattice Boltzmann method, the descriptor has to be defined in advance. Here we briefly discuss the descriptor structure in Palabos.
Descriptor
In palabos, the descriptors are stored in /src/latticeBoltzmann/nearestNeighborLatticesXD.h
, where \(X=2,3\).
Each descriptor is a combination of the lattice schema and the external field, so that must inherit from at least two DescriptorBase
including the basic DdQqDescriptorBase
defining the lattice-related variables, and a EXTERNALVARLISTDescriptorBase
with external variables or NoExternalFieldBase
if the problem involves no external variables. (DdQqDescriptorBase
could be D2Q9DescriptorBase
, and EXTERNALVARLISTDescriptorBase
could be RhoBarVelocityPiNeqOmegaDescriptorBase2D
).
In
DdQqDescriptorBase
, it defines thed
, theq
, the lattice velocityc[q][d]
, lattice weightt[q]
, square speed of soundcs2
and so on by means ofDdQqConstants
.The
EXTERNALVARLISTDescriptorBaseXD
is written in/src/latticeBoltzmann/externalFields.h
. InEXTERNALVARLISTDescriptorBaseXD
, it defines the problem-specificExternalField
asEXTERNALVARLISTDescriptorXD
. Here theDdQq
ofEXTERNALVARLISTDdQqDescriptor
must correspond to the one inDdQqDescriptorBase
. Here aboveEXTERNALVARLIST-
represents the name list of the external variables, e.g.,EXTERNALVARLIST=RhoBarVelocityPiNeqOmega
andEXTERNALVARLIST=ForcedRhoBarJ
forRhoBarVelocityPiNeqOmegaD2Q9Descriptor
andForcedRhoBarJD2Q9Descriptor
, respectively.
Example
- Take the
RhoBarVelocityPiNeqOmegaD2Q9Descriptor
as an example to illustrate the structure, it inherits fromD2Q9DescriptorBase
andRhoBarVelocityPiNeqOmegaDescriptorBase2D
.### DdQqDescriptorBase1
2
3
4
5
6template <typename T> struct RhoBarVelocityPiNeqOmegaD2Q9Descriptor
: public D2Q9DescriptorBase<T>,
public RhoBarVelocityPiNeqOmegaDescriptorBase2D
{
static const char name[];
}; - The
D2Q9DescriptorBase
is defined as1
2
3
4
5
6template <typename T> struct D2Q9DescriptorBase
: public D2Q9Constants<T>, public DefaultRoundOffPolicy<T>
{
typedef D2Q9DescriptorBase<T> BaseDescriptor;
enum { numPop=D2Q9Constants<T>::q };
}; - where the lattce-related variables are defined in ### EXTERNALVARLISTDescriptorBaseXD
1
2
3
4
5
6
7
8
9
10
11template <typename T> struct D2Q9Constants
{
enum { d = 2, q = 9 }; ///< number of dimensions/distr. functions
static const T invD; ///< 1 / (number of dimensions)
static const int vicinity; ///< size of neighborhood
static const int c[q][d]; ///< lattice directions
static const int cNormSqr[q]; ///< norm-square of the vector c
static const T t[q]; ///< lattice weights
static const T cs2; ///< lattice constant cs2 (in BGK, this is the square-speed-of-sound)
static const T invCs2; ///< 1 / cs2
}; - The
RhoBarVelocityPiNeqOmegaDescriptorBase2D
has a componentExternalField
1
2
3struct RhoBarVelocityPiNeqOmegaDescriptorBase2D {
typedef RhoBarVelocityPiNeqOmegaDescriptor2D ExternalField;
}; - and the
RhoBarVelocityPiNeqOmegaDescriptor2D
would store - the number of scalars,
- the number of the species,
- the index each variable starts,
the size of each variable (2 for 2d and 3 for 3d tensors),
1
2
3
4
5
6
7
8
9
10
11
12
13struct RhoBarVelocityPiNeqOmegaDescriptor2D {
static const int numScalars = 7;
static const int numSpecies = 4;
static const int rhoBarBeginsAt = 0;
static const int sizeOfRhoBar = 1;
static const int velocityBeginsAt = 1;
static const int sizeOfVelocity = 2;
static const int piNeqBeginsAt = 3;
static const int sizeOfPiNeq = 3;
static const int omegaBeginsAt = 6;
static const int sizeOfOmega = 1;
static const int sizeOfForce = 0;
};meaning
ForcedRhoBarJdescriptor3DRhoBarVelocityPiNeqOmegaDescriptor2D
have 4 species includingrhoBar
,velocity
,piNeq
andomega
, with 1, 2, 3 and 1 as the sizes, respectively. So the scalar number would be \(1+2+3+1=7\) in total.
Setting up the external field
Once the descriptor with an external field is defined, the memory of external
inside the cell
is allocated (see src/core/cell.h
). For initializing or simply setting values to the external field, one would use the data processor, i.e., setExternalVector
or setExternalScalar
with the variable start index like DESCRIPTOR<T>::ExternalField::rhoBarBeginsAt
.
An example of external force flow would be found in the project
/examples/showCases/womersley/
. Where the external forces is set by an array, i.e., the force is uniformally deployed in the domain.1
2Array<T,NSDESCRIPTOR<T>::d> force(womersleyForce((T)0, amplitude, frequency, parameters),0.);
setExternalVector(lattice,lattice.getBoundingBox(),NSDESCRIPTOR<T>::ExternalField::forceBeginsAt,force);For position-dependent external variables, one could use a
MultiScalarFieldXD
orMultiTensorFieldXD
, initialized from a functional, as the input ofsetExternalVector
orsetExternalScalar
and use a functional to initialize theMultiXXXXFieldXD
. For the setup of the absorbing layers, I use1
2
3
4
5MultiScalarField2D<T> sigma(lattice);
WaveAbsorptionSigmaFunction2D<T> sigmaFunction2D(lattice.getBoundingBox(), numSpongeCells ,bulkValue);
setToFunction(sigma, lattice.getBoundingBox(), sigmaFunction2D);
setExternalScalar(lattice, lattice.getBoundingBox(),
DESCRIPTOR<T>::ExternalField::sigmaBeginsAt, sigma );