Palabos User Guide中文解读 | 第五章 | Palabos编程 (跳过了第四章Palabos-Java接口)

作者的话:本人在学习palabos时,发现国内中文资料甚少,恰好网上可以直接搜到palabos user guide这种英文资料,加之时间充裕,便打算开始翻译,翻了一节后发现这可能算侵权,就比较伤脑筋,突然想到自己写中文解读即可,便有了下面的博客。

Palabos User Guide
Release 1.0 r1
Copyright © 2019 University of Geneva
Jul 05, 2019

Chapter Five
Palabos编程

想了解palabos编程,知道c++是不够的,你还需了解一些算法和palabos的指南。

5.1.1 基本的数据类型

结论1:基本上所有情况下,int和unsigned int都被替换为plint与pluint。

原因:因为32位系统无法计算太大,超过2g的数据集不太够了,这样的替换都是为了方便在64位下计算的。而64位系统下,输入int还会定义32字节的类型。所以就用plint和pluint来表示64字节类型。

结论2:输入缓冲cout都被替换为pcout,cerr被替换成pcerr,clog被替换成pclog,对于文件输出ofstream,被替换成plb_ofstream。

原因:在MPI并行计算时,每一条线路都使用cout输出,为了保持程序运行的连贯性,才替换的。

5.1.2 内存管理

在palabos里,没有专门的垃圾收集器{garbage collector},但是palabos里运用了一个指针一个对象的方法,每当同时访问对象的时候,对象会自己复制自己,所以所有palabos的类都有一个clone方法:

A* object1 = new A;
A* object2 = object1->clone();

假如你自己写palabos型号的类,你就需要用到这种方法,好在clone方法都差不多:

A* A::clone() const {
return new A(*this);
}

为了程序可读性和统一性,不建议你通过别的方法定义clone方法。
有些类还需要你写一个复制构造函数来确保clone方法可用。

5.1.3 数组

选择什么数据类型来存储数组值呢?答案是看数组值的大小。
像LBM的粒子群这种大的数据集,则使用palabos的 BlockLattice 类型。这类程序差不多长这样:

// Instantiate a nxnynz D3Q19 lattice with double-precision
// floating point numbers.
MultiBlockLattice3D<double,D3Q19descriptor> lattice(nx,ny,nz);
// Instantiate a nxnynz matrix of double-precision floating
// point scalars.
MultiScalarField3D field(nx,ny,nz);

像小的非并行计算的,比如说存储计算参数这样的不是巨大的数据集,C++标准库的数据类型 _vector_即可初始化动态尺寸的数组。差不多长这样:

plint numspecies = 5;
// Instantiate a vector of double-precision floating point
// numbers with 5 elements.
vector viscosities(numSpecies);
viscosities[3] = 0.63;

强烈推荐使用 vector 而不是 new [ ] 来操作,避免程序发送小意外。

对于非常小的非并行计算的而且确定尺寸的数组,palabos定义了array,通常用于存储小的物理向量,比如说速度。大概长这样:

// Instantiate a fixed-size array of type double and with
// 3 elements. The values can be initialized directly in
// the constructor for arrays of size 2 and 3.
Array<double,3> velocity(0., 0., 0.5);
velocity[0] = 0.1;

对于确定的数组就该偏向使用C语言下的Array,其本身就是c语言的模板机制,二者相同,但特别的是,在palabos以debug模式下编译时,会进行范围检查,debug或许会节省时间。(感觉这里没有讲得很清楚,日后有机会回来补坑。)

5.1.4 速度和密度

1)LB中V和ρ在宏观尺度上是最常见的变量,但在palabos代码里你会发现,这两个量很少见。在palabos里面,常用到的是 rhoBarj

变量 j :first-order velocity moment,一阶速度矩,大部分模型下,流体动量 jrho * u
变量 rhoBar :这个可以自定义,默认情况下它被定义为 rhoBar=rho-1 ,用于提升计算精度。因为液体密度经常接近1,这样密度减去1的话,数值就是在0上下,表达双精度点的变量的字节也更有意义。

下面是一些rho/u和rhoBar/j之间切换的规则。

// Use custom definitions in lattice descriptor to compute rho from rhoBar
rho = Descriptor::fullRho(rhoBar);
// Use custom definitions in lattice descriptor to compute rhoBar from rho
rhoBar = Descriptor::rhoBar(rho);
// Momentum is equal to density times velocity (component-wise)
j[iD] = rho * u[iD];
// Velocity is equal to inverse-density times momentum (component-wise)
u[iD] = 1./rho * j[iD];
// Inverse-density can be computed right away from rhoBar. Depending on
// the custom definitions in the descriptor, this is substantially more
// efficient than computing 1./rho, because the Taylor expansion of the
// inverse-function is truncated at an appropriate position.
u[iD] = Descriptor::invRho(rhoBar) * j[iD];

5.1.5 并行

这里主要介绍了并行计算时候的原理,大概就是说并行计算或者单线程计算的话,你的程序都长得差不多。并行的时候,MultiBlockLattice, MultiScalarField, and MultiTensorField 都是并行计算的,其他的数据都是复制到每条线路的,仅有很少的例外,默认的操作减少{reduction operations}(如计算一个格子的平均密度)是为了更有效率地把结果存到主线路。

5.2 Palabos非侵入式程序开发

首先需要劝退的是一些研究工作者在分享代码时,用邮件什么的发送部分代码,然后手动整合,造成每个人都拥有一份完整独立的代码,调参来实现特定功能。

这一节劝进你把代码当做库来使用,而不是搞一份模板来自己调参。

原因:Palabos源代码5w多行,改很麻烦,而且你改完源代码后,你这份Palabos几乎是从主要版本中独立出来了。这样后续Palabos出新功能或修正bug什么的,你就跟不上了。更何况这么做你就不太好和同事交换代码交流。
所以吧,不如就弄一个你自己的LB模型,或者算例应用。

5.2.1 不修改代码式扩展

举个例子,如果你想写个只有很小差别的,类似于BGK的LB模型,你应该首先翻到7.1节查看Palabos有没有应用它。

如果没有,
1)打开src/basicDynamics/isothermalDynamics.h 和 .hh
2)你会发现 BGKdynamics类 继承IsoThermalBulkDynamics,实行clone(),
collide(),和 computeEquilibrium()这三个操作
3)放弃调参的想法,创建新文件myNewModel.h和myNewModel.hh,搞一个继承IsoThermalBulkDynamics的MyNewDynamics在里面,把2)中的三个操作加进去,调参成你自己的BGKdynamics。
这样就与新版本更新不冲突了,与同事交换也只需要换两个文件。同时你也不需要把新文件放到Palabos的文件夹里,只需要把Make文件里的路径改对即可。

5.2.2 Palabos里哪些部分可扩展?

大致有三种方法扩展Palabos。
1)写一个新的dynamics类。(dynamics class)主要是定义局部的碰撞步数,
2)写一个新的数据处理器。(data processor)
3)写一个新的格子表示器。(lattice descriptor)主要是新的格子拓扑结构(离散速度,权重等)

假如你写了新的dynamics类,数据处理器,或者格子表示器,你可能还想把它们整合成包装函数。这样方便你自动传递合适的数据处理器给特定的任务,或者把数据处理器添加进网格中。有一个例子代码,就是这样方便的功能,OnLatticeBoundaryConditionXD类,可自动添加动态对象和数据处理器到网格中来创建边界条件。

Palabos的其他地方则无法扩展。作者表示,你若真想的话他也拦不住你重复造轮子,但这么做会破坏Palabos的模块性。简而言之这挺创新,然而自己造的轮子可能不被后续Palabos版本支持。

Palabos中可以扩展的地方就很有操作性了,比如说2D、3D Shan/Chen模型的单组多相流和不互溶多组多相流。这个仅仅是写了新的格子表示器和新的数据处理器,没有修改Palabos任何别的地方。

偶尔程序也会有不尽人意的时候,但做好注释能节省不少大家的时间。比如说运行布辛涅司克近似{Boussinesq approximation}的热流模型,这里温度场遵循LB模型下线性平衡的对流扩散方程。此时,显然需要写一个新的dynamics类来定义对流扩散方程的碰撞步骤,因为palabos的dynamics类接口中,微粒团的0阶矩总是被称作rho,然而在温度模型中,微粒团0阶矩是温度。这种情况就比较尴尬,做好两三处的注释防止别人困惑。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值