Eastsheng's Wiki

LBM/PALABOS:shanChenMultiPhase例子

2024-05-28 18:37:28

[toc]

ShanChen模型

image-20240616151314055

  • Shan-Chen模型是一种常用的多相流模型,它可以很好地描述流体中的相变现象和界面运动。
  • Shan/Chen模型在Palabos中实现了2D和3D,广泛用于非混相多组分流体和单组分多相流体的。
  • 可以有效地模拟多相流体系统中的各种复杂现象,比如气液两相流、固液两相流等
  • Shan-Chen模型在空气动力学仿真、燃料电池、宇宙暗能量等领域得到了广泛应用;

算法的步骤和原理

  • 对流体系统进行离散化处理,将其分解成一个个小的格子;

  • 利用格子玻尔兹曼方法来模拟流体在格子上的运动和相互作用;

  • 在Shan-Chen模型中,需要引入一个色散力场来描述流体分子之间的相互作用,这样可以很好地模拟出流体中的相变现象和界面运动;

  • 利用格子玻尔兹曼方法中的碰撞步骤来模拟流体分子之间的碰撞和能量转移,在碰撞步骤中,根据色散力场的作用来更新流体分子的速度和密度分布;

  • 最后,利用格子玻尔兹曼方法中的流动步骤来模拟流体在格子中的流动和扩散,在流动步骤中,根据色散力场的作用来更新流体分子的速度和密度分布,从而模拟出流体在格子中的流动和扩散行为。

  • 总的来说,基于格子玻尔兹曼方法模拟Shan-Chen模型的两相流算法步骤包括离散化处理、碰撞步骤和流动步骤。

代码分析

代码位置

1
2
3
4
5
6
7
palabos/examples/codesByTopic/shanChenMultiPhase
├── build
├── CMakeLists.txt
├── segregation2D.cpp
├── test
│   └── ref.dat
└── tmp

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <cstdlib>
#include <iostream>

#include "palabos2D.h"
#include "palabos2D.hh"

using namespace plb;
using namespace std;

// 将 double 类型定义为一个新的类型别名 T。可以使用 T 代替 double,从而提高代码的可读性和可维护性。
typedef double T;

#define DESCRIPTOR descriptors::ShanChenD2Q9Descriptor //定义二维9速度ShanChen描述符

// 定义一个模板类,该模板有两个参数,T 是一个类型参数。Descriptor 是一个模板类,需要一个类型参数 U。
template <typename T, template <typename U> class Descriptor>
class RandomInitializer : public BoxProcessingFunctional2D_L<T, Descriptor> {
public:
RandomInitializer(T rho0_, T maxRho_, Box2D const &boundingBox_, uint32_t const *seed_) : // 初始化函数
rho0(rho0_), maxRho(maxRho_), nY(boundingBox_.getNy()), seed(seed_) {};
virtual void process(Box2D domain, BlockLattice2D<T, Descriptor> &lattice)
{
Dot2D location = lattice.getLocation();
sitmo::prng_engine eng(*seed);
plint rng_index = 0;
for (plint iX = domain.x0; iX <= domain.x1; ++iX) {
plint globalX = nY * (iX + location.x);
for (plint iY = domain.y0; iY <= domain.y1; ++iY) {
plint globalY = iY + location.y + globalX;
PLB_ASSERT(globalY >= rng_index);
if (globalY > rng_index) {
eng.discard(globalY - rng_index);
rng_index = globalY;
}
T randNumber = (T)eng() / (T)sitmo::prng_engine::max();
++rng_index;

T rho = rho0 + randNumber * maxRho;
Array<T, 2> zeroVelocity(0., 0.);

iniCellAtEquilibrium(lattice.get(iX, iY), rho, zeroVelocity); // 随机二维密度

lattice.get(iX, iY).setExternalField(
Descriptor<T>::ExternalField::densityBeginsAt,
Descriptor<T>::ExternalField::sizeOfDensity, &rho);
lattice.get(iX, iY).setExternalField(
Descriptor<T>::ExternalField::momentumBeginsAt,
Descriptor<T>::ExternalField::sizeOfMomentum, &zeroVelocity[0]);
}
}
};
virtual RandomInitializer<T, Descriptor> *clone() const
{
return new RandomInitializer<T, Descriptor>(*this);
};
virtual void getTypeOfModification(std::vector<modif::ModifT> &modified) const
{
modified[0] = modif::staticVariables;
};

private:
T rho0, maxRho;
plint nY;
uint32_t const *seed;
};

int main(int argc, char *argv[]) // 主程序
{
plbInit(&argc, &argv); // 初始化函数,用于设置和配置 Palabos 环境
global::directories().setOutputDir("./tmp/"); // 设置输出文件夹

uint32_t seed = 1;

// For the choice of the parameters G, rho0, and psi0, we refer to the book
// Michael C. Sukop and Daniel T. Thorne (2006),
// Lattice Boltzmann Modeling; an Introduction for Geoscientists and Engineers.
// Springer-Verlag Berlin/Heidelberg.

const T omega = 1.0; // 松弛参数?
const int nx = 400; // x方向格子数目
const int ny = 400; // y方向格子数目
const T G = -120; // G为相互作用强度
#ifndef PLB_REGRESSION
const int maxIter = 100001;
const int saveIter = 100;
#else
const int maxIter = 1001;
#endif
const int statIter = 100;

const T rho0 = 200.0; // 初始密度
const T deltaRho = 1.0; // 用在了随机初始化密度上的参数
const T psi0 = 4.0; // 粒子间势初始值

MultiBlockLattice2D<T, DESCRIPTOR> lattice( // 拥有外力(色散力?)的BGKdynamics 二维晶格
nx, ny, new ExternalMomentBGKdynamics<T, DESCRIPTOR>(omega)); // 为了避免计算变量两次,确保在碰撞过程中从外部标量中读取宏观变量

lattice.periodicity().toggleAll(true); // 所有方向采用周期性边界

// 使用随机初始条件,激活相分离。
applyProcessingFunctional(
new RandomInitializer<T, DESCRIPTOR>(rho0, deltaRho, lattice.getBoundingBox(), &seed),
lattice.getBoundingBox(), lattice);

// 添加数据处理器,实现Shan/Chen相互作用势。
plint processorLevel = 1;
integrateProcessingFunctional(
new ShanChenSingleComponentProcessor2D<T, DESCRIPTOR>( // 二维单相ShanChen
G, new interparticlePotential::PsiShanChen94<T>(psi0, rho0)), // 采用PsiShanChen94(Psi0,rho0)粒子间势
lattice.getBoundingBox(), lattice, processorLevel);

lattice.initialize(); // 初始化格子

pcout << "Starting simulation" << endl;
for (int iT = 0; iT < maxIter; ++iT) {
if (iT % statIter == 0) { // 输出到屏幕
std::unique_ptr<MultiScalarField2D<T> > rho(computeDensity(lattice)); // 计算密度场
pcout << iT << ": Average rho fluid one = " << computeAverage(*rho) << endl; // 平均密度
pcout << "Minimum density: " << computeMin(*rho) << endl; // 最小密度
pcout << "Maximum density: " << computeMax(*rho) << endl; // 最大密度
}
#ifndef PLB_REGRESSION
if (iT % saveIter == 0) { // 保存图片
ImageWriter<T>("leeloo").writeScaledGif(
createFileName("rho", iT, 6), *computeDensity(lattice));
}
#endif

lattice.collideAndStream(); // 每个算例里都会有这一行代码, 碰撞和流动
}
}

模拟与结果

模拟

1
2
3
4
5
cd build
cmake ..
make
cd ..
mpirun -np 4 ./segregation2D

密度结果

rho000000 rho001000 rho010000 rho050000 rho100000
rho000000 rho001000 rho010000 rho050000 rho100000

参考

[1]【热力学】基于格子玻尔兹曼方法模拟Shan-Chen模型的两相流附matlab代码

[2] 使用Palabos的自由表面流模型仿复杂多孔介质中的液滴渗透