首页 > 其他分享 >Openfoam Pstream类探索

Openfoam Pstream类探索

时间:2023-02-23 20:25:05浏览次数:34  
标签:const 探索 int List Openfoam static Pstream label

对于数值仿真而言,无论是商软或者开源并行计算都是非常重要的,而且想把自身数值仿真能力提升一个层次,必须对并行计算有很好的理解与应用


openfoam并行通信主要通过Pstream类完成

本篇文章进行说明解释
Pstream类,类如其名,parallel_stream,并行计算时使用的信息流
类似的命名方法我们在c++文件读取时说过,std有fstream类读取写入文件/二进制文件,比如说我们要读取文件,会把读取内容放入缓存区内进行操作

#include <iostream>
#include <fstream>  // ifstream类需要包含的头文件。
#include <string>     // getline()函数需要包含的头文件。
using  namespace std;
 
int main()
{
    string filename = R"(./test.txt)";
 
    //ifstream fin(filename, ios::in);
    ifstream fin;
    fin.open(filename , ios::in);
 
    // 判断打开文件是否成功。
    // 失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux平台下很常见。
    if (fin.is_open() == false)
    {
        cout << "打开文件" << filename << "失败。\n";  return 0;
    }
 
    string buffer;
    while (fin >> buffer)
    {
        cout << buffer << endl;
    }
 
    fin.close();	   // 关闭文件,fin对象失效前会自动调用close()。
 
    cout << "操作文件完成。\n";
}

类似的openfoam也有PstreamBuffers类进行并行通信缓冲
可以这样使用:

PstreamBuffers pBuffers(Pstream::commsTypes::nonBlocking);

for (label proci = 0; proci < Pstream::nProcs(); proci++)
    { 
        if (proci != Pstream::myProcNo()) 
            {
                someObject vals;
                UOPstream str(proci, pBuffers);
                str << vals; 
            } 
    }

pBuffers.finishedSends(); // no-op for blocking

for (label proci = 0; proci < Pstream::nProcs(); proci++)
    { 
            if (proci != Pstream::myProcNo())
            { 
                UIPstream str(proci, pBuffers);
                someObject vals(str); 
            } 
    }

上面这个程序可以看到,先后使用UOPstream与UIPstream进行缓冲区的文件输出与读取,这就很像ofstream类与ifstream类,甚至命名方式上都有几分相似,我们打开相应的继承关系图

image
image

二者分别服务于IPstream类与OPstream类,我们再打开今天文章的主角,Pstream类继承关系图
image
发现IPstream类与OPstream类是Pstream类的衍生类,Pstream类是其基础
打开Pstream类的源码:

点击查看代码
namespace Foam
{

/*---------------------------------------------------------------------------*\
                           Class Pstream Declaration
\*---------------------------------------------------------------------------*/

class Pstream
:
    public UPstream
{

protected:

    // Protected data

        //- Transfer buffer
        DynamicList<char> buf_;

public:

    // Declare name of the class and its debug switch
    ClassName("Pstream");


    // Constructors

        //- Construct given optional buffer size
        Pstream
        (
            const commsTypes commsType,
            const label bufSize = 0
        )
        :
            UPstream(commsType),
            buf_(0)
        {
            if (bufSize)
            {
                buf_.setCapacity(bufSize + 2*sizeof(scalar) + 1);
            }
        }


        // Gather and scatter

            //- Gather data. Apply bop to combine Value
            //  from different processors
            template<class T, class BinaryOp>
            static void gather
            (
                const List<commsStruct>& comms,
                T& Value,
                const BinaryOp& bop,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T, class BinaryOp>
            static void gather
            (
                T& Value,
                const BinaryOp& bop,
                const int tag = Pstream::msgType(),
                const label comm = Pstream::worldComm
            );

            //- Scatter data. Distribute without modification. Reverse of gather
            template<class T>
            static void scatter
            (
                const List<commsStruct>& comms,
                T& Value,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T>
            static void scatter
            (
                T& Value,
                const int tag = Pstream::msgType(),
                const label comm = Pstream::worldComm
            );

        // Combine variants. Inplace combine values from processors.
        // (Uses construct from Istream instead of <<)

            template<class T, class CombineOp>
            static void combineGather
            (
                const List<commsStruct>& comms,
                T& Value,
                const CombineOp& cop,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T, class CombineOp>
            static void combineGather
            (
                T& Value,
                const CombineOp& cop,
                const int tag = Pstream::msgType(),
                const label comm = Pstream::worldComm
            );

            //- Scatter data. Reverse of combineGather
            template<class T>
            static void combineScatter
            (
                const List<commsStruct>& comms,
                T& Value,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T>
            static void combineScatter
            (
                T& Value,
                const int tag = Pstream::msgType(),
                const label comm = Pstream::worldComm
            );

        // Combine variants working on whole List at a time.

            template<class T, class CombineOp>
            static void listCombineGather
            (
                const List<commsStruct>& comms,
                List<T>& Value,
                const CombineOp& cop,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T, class CombineOp>
            static void listCombineGather
            (
                List<T>& Value,
                const CombineOp& cop,
                const int tag = Pstream::msgType(),
                const label comm = Pstream::worldComm
            );

            //- Scatter data. Reverse of combineGather
            template<class T>
            static void listCombineScatter
            (
                const List<commsStruct>& comms,
                List<T>& Value,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T>
            static void listCombineScatter
            (
                List<T>& Value,
                const int tag = Pstream::msgType(),
                const label comm = Pstream::worldComm
            );

        // Combine variants working on whole map at a time. Container needs to
        // have iterators and find() defined.

            template<class Container, class CombineOp>
            static void mapCombineGather
            (
                const List<commsStruct>& comms,
                Container& Values,
                const CombineOp& cop,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class Container, class CombineOp>
            static void mapCombineGather
            (
                Container& Values,
                const CombineOp& cop,
                const int tag = Pstream::msgType(),
                const label comm = UPstream::worldComm
            );

            //- Scatter data. Reverse of combineGather
            template<class Container>
            static void mapCombineScatter
            (
                const List<commsStruct>& comms,
                Container& Values,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class Container>
            static void mapCombineScatter
            (
                Container& Values,
                const int tag = Pstream::msgType(),
                const label comm = UPstream::worldComm
            );



        // Gather/scatter keeping the individual processor data separate.
        // Values is a List of size UPstream::nProcs() where
        // Values[UPstream::myProcNo()] is the data for the current processor.

            //- Gather data but keep individual values separate
            template<class T>
            static void gatherList
            (
                const List<commsStruct>& comms,
                List<T>& Values,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T>
            static void gatherList
            (
                List<T>& Values,
                const int tag = Pstream::msgType(),
                const label comm = UPstream::worldComm
            );

            //- Scatter data. Reverse of gatherList
            template<class T>
            static void scatterList
            (
                const List<commsStruct>& comms,
                List<T>& Values,
                const int tag,
                const label comm
            );

            //- Like above but switches between linear/tree communication
            template<class T>
            static void scatterList
            (
                List<T>& Values,
                const int tag = Pstream::msgType(),
                const label comm = UPstream::worldComm
            );


        // Exchange

            //- Helper: exchange contiguous data. Sends sendData, receives into
            //  recvData. If block=true will wait for all transfers to finish.
            template<class Container, class T>
            static void exchange
            (
                const UList<Container>& sendData,
                const labelUList& recvSizes,
                List<Container>& recvData,
                const int tag = UPstream::msgType(),
                const label comm = UPstream::worldComm,
                const bool block = true
            );

            //- Helper: exchange sizes of sendData. sendData is the data per
            //  processor (in the communicator). Returns sizes of sendData
            //  on the sending processor.
            template<class Container>
            static void exchangeSizes
            (
                const Container& sendData,
                labelList& sizes,
                const label comm = UPstream::worldComm
            );

            //- Exchange contiguous data. Sends sendData, receives into
            //  recvData. Determines sizes to receive.
            //  If block=true will wait for all transfers to finish.
            template<class Container, class T>
            static void exchange
            (
                const UList<Container>& sendData,
                List<Container>& recvData,
                const int tag = UPstream::msgType(),
                const label comm = UPstream::worldComm,
                const bool block = true
            );
};

我们看到Pstream类有一个构造函数,剩下的都是静态成员函数,而这些成员函数就是并行通讯的工具箱
这里多问一句,为什么工具箱的函数都是静态成员函数


为什么这里用静态成员函数呢

用静态成员可以变量实现多个对象间的数据共享,比全局变量更安全
这里我详细说下,举个例子

Time mytime1;
mytime1.hour=2;
Time mytime2;
mytime2.hour=4;

这段程序中成员变量是跟着对象走的,他们的对象各自占用不同的内存地址,彼此互不影响
那我们想做类内的全局变量满足相互通信需求,在不同对象mytime1和mytime2中共享一个副本,怎么办
这时static关键字就派上用场了,增加了static关键字或成员函数不隶属整个对象,而隶属于整个类
因为这个变量跟着类走,所以调用时用“类名::成员变量名”或“类名::成员变量函数”进行调用(当然也可用“对象名.静态函数名”),表示明确的隶属关系,不创建对象也可进行访问编辑
在Pstream类调用工具箱中函数时,我们常见到这样的调用方式,而且不创建Pstream对象也可进行调用

// 在head节点收集信息
Pstream::gatherList(nInternalFaces);
Pstream::gatherList(nBoundaries);

因为类的静态成员脱离了与对象的关系,普通成员变量的内存分配是在对象初始化时完成的,对于静态成员必须在程序的全局区进行清晰的初始化
全局区的初始化过程可由某个.cpp源文件的开头的静态成员函数完成,如下所示:

void Time::func(int testValue)
{
	mystatic = testValue ;
}

或者在全局区这样写:

int Time::mystatic=10;

这样能保证这个静态成员变量能够被正常使用。
此外静态成员函数只能调用静态成员变量,也没有this指针可以使用
这里上一张图可能更方便理解
image

C++程序运行时,静态变量和全局变量存储在数据段,所以需要在全局区通过直接分配内存或者静态函数进行分配内存
因而静态成员的生命周期与程序运行周期相同,在程序中只有一份,无论创建对象与否,或者创建多少对象
说到这里可能大家对Openfoam的并行通信多了一些理解,只要开始了并行计算那么就可以通过Pstream类内的成员函数进行通信调用,在同样的数据段副本上进行信息流沟通


接下来依次说下各个工具的使用

收发数据
Pstream::gather()与Pstream::scatter()分别有两个重载,分别是收集以及散布数据,不如后面Pstream::gatherList()与Pstream::scatterList()常用,这里不细说了
Pstream::combineGather()、Pstream::combineScatter()重载情况与上同,用于就地集中收集或散布的数据,不太常用

Pstream::listCombineGather()、Pstream::listCombineScatter()重载情况与上同,用于一次整合list容器中的变量
Pstream::mapCombineGather()、Pstream::mapCombineScatter()重载情况与上同,用于一次整合整个map容器中的变量

Pstream::gatherList()以及Pstream::scatterList()的第二个重载比较常用,

template<class T>
            static void gatherList
            (
                List<T>& Values,
                const int tag = Pstream::msgType(),
                const label comm = UPstream::worldComm
            );
template<class T>
            static void scatterList
            (
                List<T>& Values,
                const int tag = Pstream::msgType(),
                const label comm = UPstream::worldComm
            );

Pstream::gatherList()以及Pstream::scatterList()的输入第一个参数是Values
这个Values需要自己整合下,Values是UPstream::nProcs()数量大小的List,比如说我要收集内部面可以这样创建需要收集的List

List<label> nIternalFaces(Pstream::nProcs());
nIternalFaces[Pstream::myProcNo()] = mesh.Cf().size();//比如说看看每个节点分到了多少网格
Pstream::gatherList(nIternalFaces);//在头结点收集数据

Pstream::scatterList()与之类似
Pstream::gatherList()以及Pstream::scatterList()的输入第二个参数是Pstream::msgType(),默认为1,可以不输入

int Foam::UPstream::msgType_(1);

Pstream::gatherList()以及Pstream::scatterList()的输入第三个参数是Pstream::msgType(),默认为0,可以不输入

Foam::label Foam::UPstream::worldComm(0);

交换数据
Pstream::exchange()有两个重载,用于交换连续的数据,一般情况下等待其他所有传输完成再传输,可通过默认参数block()修改优先权
Pstream::exchangeSizes()用于交换数据的大小


下面是Pstream类函数相互关系
image


结语

并行开发远不止收发数据这么简单,还有很多类可说的,后续会一一进行介绍,并对openfoam并行计算进行优化
自从这个月15号找到人生支点后,基本上每天都在肝一篇说明书,逐渐开启这个季度的狂飙
一起探索openfoam也是相当有趣的一件事,非常欢迎私信讨论
指正的价值要比打赏更重要,下面是个人联系方式,能结交到志同道合的朋友是我的荣幸
image

标签:const,探索,int,List,Openfoam,static,Pstream,label
From: https://www.cnblogs.com/heloveHe/p/17148332.html

相关文章

  • 我的博客的探索与熟悉
    我的博客的探索与熟悉作为一个博客园新手,写博客的过程是一次探索和熟悉的过程。MarkdownMarkdown是一种轻量级的标记语言,它能够让你以简单的方式编写格式化的文本。使用......
  • 【Go】使用Go语言打造定时提醒小工具,从基础到优化全方位探索
    一、引言1.目的和背景本文和大家分享编程语言对于时间和日期的处理方式,以及代码的优化思路。2.选择GO语言的原因简单易学:GO语言的语法简单易学,这使得初学者能够快速上......
  • 如何阅读openfoam帮助文档不同类别框图
    看完of的帮助文档,会非常怀念fluent的帮助文档或是matlab的帮助文档比如我要解决一个matlab问题,基本上看帮助文档一分钟就知道我要如何取用我想要的东西,of帮助文档不光做不......
  • Go 管道关闭引发的探索
    前言在日常开发中,经常会使用chan来进行协程之间的通信.对chan的操作也无外乎读写关.而本次,就是从chan的关闭而来.假设我们对外提供的方法如下:typeChanstruct{......
  • 【每日随笔】手指训练 ( 产品需求探索、技术无关 | 手指训练作用 | 哪些人需要手指训
    文章目录​​一、手指训练作用​​​​二、哪些人需要手指训练​​​​三、手指操​​​​四、手指康复训练器材​​产品需求探索,研究下手指训练的市场,前景,是否可......
  • odoo手动提交事务问题探索
    背景:在做项目时,发现数据库中几百条数据的修改时间都是相同的。寻找其中原因,在代码层面为了避免大数据量放在一次修改数据,特意做了分页查询,每一页执行一次更新方法,所有数据......
  • 深入探索Android 启动优化(七) - JetPack App Startup 使用及源码浅析
    本文首发我的微信公众号:徐公,想成为一名优秀的Android开发者,需要一份完备的知识体系,在这里,让我们一起成长,变得更好~。前言前一阵子,写了几篇Android启动优化的文章......
  • 探索JS混淆加解密技术
    JavaScript混淆是保护您的代码免受未经授权的访问的有效方法。然而,当您需要修改或扩展混淆代码时,混淆可以使代码难以理解和修改。解决这个问题的方法是使用JS混淆解密技术。......
  • 百万级别的空间数据可视化探索
    1.引言空间数据往往很大,将其渲染在前端页面存在一定的难度本文使用开源数据集,基于PostGIS、GeoServer、OpenLayers,探索并实验了一些百万级别的空间数据可视化方法2.数......
  • upstream和proxy模块
    nginx负载均衡-upstream和proxy模块(1)Cloud研习社 Cloud研习社 2023-01-1007:31 发表于北京收录于合集#一站式教程195个#云计算148个#计算机137个#nginx37......