initializeAtEquilibrium() in Palabos
I've discussed the structure of the data processor execution in a previous article. Today let's take a look at a certain type of the data processors: data initializer.
There are many data initializers implemented in src/dataProcessors/dataInitializerWrapperXD.h/hh. I'll take one of them, initializeAtEquilibrium(), as an example here.
Overloads of initializeAtEquilibrium()
Taking the 2D version as an example, there are four overloads that are categorized into two types.
- Two of them accept constant
densityandvelocityand applied constants to all cells.1
2
3
4
5template<typename T, template<class U> class Descriptor>
void initializeAtEquilibrium(BlockLattice2D<T,Descriptor>& lattice, Box2D domain,T density, Array<T,2> velocity, T temperature = (T)1);
template<typename T, template<class U> class Descriptor>
void initializeAtEquilibrium(MultiBlockLattice2D<T,Descriptor>& lattice, Box2D domain, T density, Array<T,2> velocity, T temperature = (T)1);- It calls
applyProcessingFunctional() - It is based on the functional
IniConstEquilibriumFunctional2D
- It calls
- Two of them accept a function object
RhoUFunctionand provides a cell-dependent initialization.1
2
3
4
5template<typename T, template<class U> class Descriptor, class RhoUFunction>
void initializeAtEquilibrium(BlockLattice2D<T,Descriptor>& lattice, Box2D domain, RhoUFunction f)
template<typename T, template<class U> class Descriptor, class RhoUFunction>
void initializeAtEquilibrium(MultiBlockLattice2D<T,Descriptor>& lattice, Box2D domain, RhoUFunction f)- It calls
applyIndexed(), a wrapper ofapplyProcessingFunctional() - It is based on the functional
IniCustomEquilibriumFunctional2D
- It calls
- Two of them accept constant
- For each type, there are two versions, one for
MultiblockLattice2Dand one forBlockLattice2D. As I've discussed a lot about the general
applyProcessingFunctionalin the previous article, I will focus on the more interesting cell-dependent version initializer.
Function Object
- For the cell-dependent version, it needs to initialize each cell of the domain with a cell (position)-dependent value. This is achieved by passing a function object
RhoUFunctioninto theinitializeAtEquilibrium()function.1
2
3// This function is implemented in-place, because it cannot be precompiled due to its generic nature.
template<typename T, template<class U> class Descriptor, class RhoUFunction>
void initializeAtEquilibrium(MultiBlockLattice2D<T,Descriptor>& lattice, Box2D domain, RhoUFunction f) RhoUFunction fis an function objectA function object, or functor, is any type that implements operator(). This operator is referred to as the call operator or sometimes the application operator. The C++ Standard Library uses function objects primarily as sorting criteria for containers and in algorithms.
Function objects provide two main advantages over a straight function call. The first is that a function object can contain state. The second is that a function object is a type and therefore can be used as a template parameter.
- As mentioned above, the function object can be used as a template parameter as it is shown in the above snippet.
- The
RhoUFunctionis a class member of the functionalIniCustomEquilibriumFunctional2D, is called in sidefunctional->execute(). - A typical functor
1
2
3
4
5
6
7
8/// A functional, used to create an initial condition for the density and velocity
template<typename T>
class PoiseuilleVelocityAndDensity {
public:
void operator()(plint iX, plint iY, T& rho, Array<T,2>& u) const {
// assign values to rho and u.
}
};
Cell-dependent functional
IniCustomEquilibriumFunctional2Dis- declared in src/dataProcessors/dataInitializerFunctional2D.h
- implemented in src/dataProcessors/dataInitializerGenerics2D.h (the file name sounds weird though, I guess "generic" means cell-dependent?)
IniCustomEquilibriumFunctional2D : OneCellIndexedFunctional2DOneCellIndexedFunctional2Dhas the member functionexecute(iX, iY, cell)which is overridden in the subclass.- where: src/dataProcessors/dataInitializerFunctional2D.h/hh
execute()is the place to implement the algorithm.
applyIndexed a wrapper of applyProcessingFunctional
applyIndexedis a wrapper ofapplyProcessingFunctional- It builds a
GenericIndexedLatticeFunctional2Dthat is inherited fromBoxProcessingFunctional2D_L GenericIndexedLatticeFunctional2Dincludes the private class memberOneCellIndexedFunctional2D* f, which isIniCustomEquilibriumFunctional2D- The key idea of
GenericIndexedLatticeFunctional2Dis the overriddenprocess()loops through the domain and call thef->execute()at each cell. - where
src/dataProcessors/dataInitializerWrappers2D.hh
More about the structure: three cell-related functionals
- One-cell functional
OneCellFunctional2DOneCellIndexedFunctional2DOneCellIndexedWithRandFunctional2D
- Generic lattice functional, which takes one-cell functional as a private class member
f. Such a functional overrides theprocess()so that executef->execute()at each cell of the domainGenericLatticeFunctional2DGenericIndexedLatticeFunctional2DGenericIndexedWithRandLatticeFunctional2D
- Functional Wrapper, that calls
applyProcessingFunctional()with the functionalapply()applyIndexed()- take
GenericIndexedLatticeFunctional2D - take
GenericIndexedWithRandLatticeFunctional2D
- take