Openfoam UPstream类探索

时间:2023-02-25 07:15:20

前言

上篇文章我们大体捋顺了Pstream类,但上篇没有讲到的是Pstream类很多东西是从UPstream类继承来的
这次我们大体看一下UPstream类,以避免Pstream类内很多继承来的东西不会用


简述几个常用的函数如下:

Pstream::myProcNo()

//- Number of this process (starting from masterNo() = 0)
static int myProcNo(const label communicator = 0)
{
    return myProcNo_[communicator];
}

就像我们提到的,静态成员变量一般有两种初始化方式,一种是全局区直接定义,另一种是利用静态成员函数进行值的返回,Pstream::myProcNo()是后者
输入参数默认从零开始计算进程数量,返回值类型为static DynamicList < int >,容器初始大小是10

//- My processor number
        static DynamicList<int> myProcNo_;
Foam::DynamicList<int> Foam::UPstream::myProcNo_(10);

这里我觉得有必要扩展解释下Foam::DynamicList,Foam内非常常见的一种数据类型


Foam::DynamicList,公有继承于Foam::List的vector容器

Openfoam UPstream类探索
openfoam对其的描述为:

A 1D vector of objects of type < T > that resizes itself as necessary to accept the new objects.
Internal storage is a compact array and the list can be shrunk to compact storage. The increase of list size is controlled by three template parameters, which allows the list storage to either increase by the given increment or by the given multiplier and divider (allowing non-integer multiples).

Foam::DynamicList的介绍里说是一个可以根据需要调整自身大小以接受新对象的一维容器,内部存储是一个紧凑的数组
讲实话看解释并没有怎么理解,直接阅读相关实现程序

#include "DynamicList.H"
 
 // * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
 
 
 template<class T, unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
 Foam::DynamicList<T, SizeInc, SizeMult, SizeDiv>::DynamicList(Istream& is)
 :
     List<T>(is),
     capacity_(List<T>::size())
 {}
 
 
 template<class T, unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
 Foam::Ostream& Foam::operator<<
 (
     Ostream& os,
     const DynamicList<T, SizeInc, SizeMult, SizeDiv>& lst
 )
 {
     os << static_cast<const List<T>&>(lst);
     return os;
 }
 
 
 template<class T, unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
 Foam::Istream& Foam::operator>>
 (
     Istream& is,
     DynamicList<T, SizeInc, SizeMult, SizeDiv>& lst
 )
 {
     is >> static_cast<List<T>&>(lst);
     lst.capacity_ = lst.List<T>::size();
 
     return is;
 }

首先看Foam::DynamicList的构造函数,利用初始化列表创建了大小为输入参数的List< T >,随后又把这个大小给了相关的成员变量,后续是两个重载,其他构造大同小异
那这就很清晰了,Foam::DynamicList本质上还是List,
但又有新的问题了,那为什么在openfoam释义中提及vector或者array呢
能看到Foam::DynamicList并没有重载[],写到这里我原以为只是一个类似数组一样可以拓展内存的List时,无法像vector一样随机存储,但无意间发现Foam::DynamicList重载了(),我把重载那部分给大家看一下哈

template<class T, unsigned SizeInc, unsigned SizeMult, unsigned SizeDiv>
inline T& Foam::DynamicList<T, SizeInc, SizeMult, SizeDiv>::operator()
(
    const label elemI
)
{
    if (elemI >= List<T>::size())
    {
        setSize(elemI + 1);
    }

    return this->operator[](elemI);
}

能看到是可以随机存储的,并且调用的this指针,说明内部是List< T > ,但是外壳是数组
此刻我们就明白了Foam::DynamicList为什么说自己是一维容器,有两种情况:

  1. 如果不超过数组大小,在插入和读取时,使用的List进行插入,复杂度仅是O(1)
  2. 但是超过数组大小,进行插入操作,需要类似vector一样重新分配空间,但又好在是List,重新分配空间无需复制粘贴折腾,只需要传地址即可

并且在以上基础上可以类似vector进行随机访问元素,兼顾了两者优点

写到这里不由得感慨,openfoam作为数值计算程序,在数据类型选择上还是有自己独到之处的,不仅要考虑安全性还要考虑效率
如果我需要插入或弹出一个数据,传list地址即可,但是我还有随机存储需求,那就外边套一层数组的壳吧,扩容也方便

讲到这里多提一嘴
类似的还有Foam::DLList,

 namespace Foam
 {
     template<class T>
     using DLList = LList<DLListBase, T>;
 }

大概是包着List外壳的List容器,如果是这样,插入复杂度是O(1),读取复杂度是O(n)

那我们再回到问题的开始,为什么的类型是Foam::DynamicList
因为myProcNo_需要动态变化,如果出现进程的增加和删减,可以类似数组进行扩容,
所以在并行计算中,Foam::DynamicList使用的非常频繁,后续会发现经常出现在其他并行函数的返回值中


后续还有
Pstream::nProcs()
Pstream::myProcNo()
Pstream::parRun()
UPstream::exit(0)
这些函数需要去说下,今天有点累了,下期再聊
后续探索一定会有更多惊喜等待着我们


结语

一起探索openfoam也是相当有趣的一件事,非常欢迎私信讨论
指正的价值要比打赏更重要,下面是个人联系方式,能结交到志同道合的朋友是我的荣幸
Openfoam UPstream类探索