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 soundcs2and so on by means ofDdQqConstants.The
EXTERNALVARLISTDescriptorBaseXDis written in/src/latticeBoltzmann/externalFields.h. InEXTERNALVARLISTDescriptorBaseXD, it defines the problem-specificExternalFieldasEXTERNALVARLISTDescriptorXD. Here theDdQqofEXTERNALVARLISTDdQqDescriptormust correspond to the one inDdQqDescriptorBase. Here aboveEXTERNALVARLIST-represents the name list of the external variables, e.g.,EXTERNALVARLIST=RhoBarVelocityPiNeqOmegaandEXTERNALVARLIST=ForcedRhoBarJforRhoBarVelocityPiNeqOmegaD2Q9DescriptorandForcedRhoBarJD2Q9Descriptor, respectively.
Example
- Take the
RhoBarVelocityPiNeqOmegaD2Q9Descriptoras an example to illustrate the structure, it inherits fromD2Q9DescriptorBaseandRhoBarVelocityPiNeqOmegaDescriptorBase2D.### DdQqDescriptorBase1
2
3
4
5
6template <typename T> struct RhoBarVelocityPiNeqOmegaD2Q9Descriptor
: public D2Q9DescriptorBase<T>,
public RhoBarVelocityPiNeqOmegaDescriptorBase2D
{
static const char name[];
}; - The
D2Q9DescriptorBaseis 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
RhoBarVelocityPiNeqOmegaDescriptorBase2Dhas a componentExternalField1
2
3struct RhoBarVelocityPiNeqOmegaDescriptorBase2D {
typedef RhoBarVelocityPiNeqOmegaDescriptor2D ExternalField;
}; - and the
RhoBarVelocityPiNeqOmegaDescriptor2Dwould 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
ForcedRhoBarJdescriptor3DRhoBarVelocityPiNeqOmegaDescriptor2Dhave 4 species includingrhoBar,velocity,piNeqandomega, 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
MultiScalarFieldXDorMultiTensorFieldXD, initialized from a functional, as the input ofsetExternalVectororsetExternalScalarand 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 );