- A+
对于openfoam或其他c++程序而言,文件的读取是尤为重要的
我们最开始学习C++时,会学到类的初始化,或者是变量定义为某个值,再对某个值进行遍历,,,
类似如下:
点击查看代码
#include <iostream> // 包含头文件。 using namespace std; // 指定缺省的命名空间。 int main() { int a = 10; int b = (10); int c(10); int e = {10}; int f{ 10 }; cout << "a=" << a << endl; cout << "b=" << b << endl; cout << "c=" << c << endl; cout << "e=" << e << endl; cout << "f=" << f << endl; }
尤其c++,初学时候内心非常感慨,怎么这么多初始化方式,我该用哪个
现在回头看,其实能熟悉一个,其他看懂就行,看不懂都没关系,毕竟我们还有gdb或者typeid()帮忙,可以看看这个变量类型具体是什么
说到底我们要问题导向目标导向,我们学习C++是为了类似openfoam这样的大工程服务的
那学这么多初始化赋值,有必要吗
如果是个大工程或者大程序是完全没必要的,
因为大工程的数据都是从文件或者数据库中获得的
你想想,要计算一个流体问题,如果有一万个网格,手打一万个三维位置就已经非常让人头疼了,更不要说上百个组分和压力等参数了,不现实
所以又回到了问题的起点,读取文件很重要,那么如何从文件中初始化程序,如何读取文件
在看of源码之前,不妨复习下C++是怎么读取文件的,进行下知识巩固
C++多使用fstream类或ifstream类
点击查看代码
#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的文件读写,主要是用IOdictionary类
打开IOdictionary类的头文件,并不复杂
点击查看代码
class IOdictionary : public baseIOdictionary { public: // Constructors //- Construct given an IOobject IOdictionary(const IOobject&); //- Construct given an IOobject and dictionary IOdictionary(const IOobject&, const dictionary&); //- Construct given an IOobject and Istream IOdictionary(const IOobject&, Istream&); //- Copy constructor IOdictionary(const IOdictionary&); //- Move constructor IOdictionary(IOdictionary&&); //- Destructor virtual ~IOdictionary(); // Member Functions //- Is object global virtual bool global() const { return true; } //- Return complete path + object name if the file exists // either in the case/processor or case otherwise null virtual fileName filePath() const { return globalFilePath(type()); } // Member Operators //- Move assignment void operator=(IOdictionary&&); };
继承于baseIOdictionary类,借助于IOobject接口有五个构造函数,这五个中一个移动构造一个拷贝构造,其他类继承可以创建自己成员函数global()和filePath(),头文件还对移动构造创建了等号赋值运算符
我们再看IOdictionary类的关键先生IOobject
IOobject就稍显复杂了,我们先看openfoam对其的描述:
IOobject defines the attributes of an object for which implicit objectRegistry management is supported, and provides the infrastructure for performing stream I/O.
An IOobject is constructed with an object name, a class name, an instance path, a reference to a objectRegistry, and parameters determining its storage status.
下面这张图是openfoam与该接口有关的类谱图
打开regIOobject类,这是个抽象类,openfoam对regIOobject的描述为:
regIOobject is an abstract class derived from IOobject to handle automatic object registration with the objectRegistry.
这里不赘述了,最后查了好半天,大概是哈希表来的,方便查询读取。openfoam中/0,/constant以及/system文件夹中那种奇怪的文件格式肯定有适合自己的读取方法。
那我们看看IOobject类相关源码,
IOobject类有四个枚举控制读取权限以及文件检查
点击查看代码
//- Enumeration defining the valid states of an IOobject enum objectState { GOOD, BAD }; //- Enumeration defining the read options enum readOption { MUST_READ, MUST_READ_IF_MODIFIED, READ_IF_PRESENT, NO_READ }; //- Enumeration defining the write options enum writeOption { AUTO_WRITE = 0, NO_WRITE = 1 }; //- Enumeration defining the file checking options enum fileCheckTypes { timeStamp, timeStampMaster, inotify, inotifyMaster };
内共有六个构造函数,其中一个拷贝构造
点击查看代码
// Constructors //- Construct from name, instance, registry, io options IOobject ( const word& name, const fileName& instance, const objectRegistry& registry, readOption r=NO_READ, writeOption w=NO_WRITE, bool registerObject=true ); //- Construct from name, instance, local, registry, io options IOobject ( const word& name, const fileName& instance, const fileName& local, const objectRegistry& registry, readOption r=NO_READ, writeOption w=NO_WRITE, bool registerObject=true ); //- Construct from path, registry, io options // Uses fileNameComponents() to split path into components. IOobject ( const fileName& path, const objectRegistry& registry, readOption r=NO_READ, writeOption w=NO_WRITE, bool registerObject=true ); //- Construct from copy resetting registry IOobject ( const IOobject& io, const objectRegistry& registry ); //- Construct from copy resetting name IOobject ( const IOobject& io, const word& name ); //- Copy constructor IOobject(const IOobject& io) = default;
我们举个例子,基于这些构造函数可以这样写类似这样的读取端口:
点击查看代码
IOobject dicName( "dicName", runTime.timeName(), //runTime.constant(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ) ;
再回到IOdictionary类,
通过查看IOdictionary类的构造函数,我们了解到可以在创建好的IOobject端口基础上构建,也可以直接构建IOobject端口
点击查看代码
IOdictionary dicName( IOobject ( "dicName", //runTime.constant(), runTime.system(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ) ) ;
那么我们如何通过IOdictionary类读取openfoam内文件呢,
以openfoam内置icoFoam为例
$ ls cavity/
0 constant system
$ tree cavity/
cavity/
├── 0
│ ├── U
│ └── p
├── constant
│ ├── polyMesh
│ │ ├── boundary
│ │ ├── faces
│ │ ├── neighbour
│ │ ├── owner
│ │ └── points
│ └── transportProperties
└── system
├── blockMeshDict
├── controlDict
├── fvSchemes
└── fvSolution
$ head cavity/0/* -n15
-
cavity/0/U *
/--------------------------------- C++ -----------------------------------
========= |
/ F ield | OpenFOAM: The Open Source CFD Toolbox
/ O peration | Website: https://openfoam.org
/ A nd | Version: 8
/ M anipulation |
*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class ** volVectorField;**
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -
cavity/0/p *
/--------------------------------- C++ -----------------------------------
========= |
/ F ield | OpenFOAM: The Open Source CFD Toolbox
/ O peration | Website: https://openfoam.org
/ A nd | Version: 8
/ M anipulation |
*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class ** volScalarField;**
object p;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
从以上内容可以看到,U和v分别属于volVectorField类以及volScalarField类,那么就利用IOobject接口分别创建相关类如下所示:
点击查看代码
volVectorField U( IOobject( "U" , runTime.timeName() , mesh , IOobject::MUST_READ , IOobject::AUTO_WRITE ) , mesh ); volScalarField p( IOobject( "p" , runTime.timeName() , mesh , IOobject::MUST_READ , IOobject::AUTO_WRITE ) , mesh );
再看其他两个文件夹
$ grep -rn "dicti" .
./cavity/constant/transportProperties:12: class dictionary;
./cavity/system/controlDict:12: class dictionary;
./cavity/system/fvSolution:12: class dictionary;
./cavity/system/blockMeshDict:12: class dictionary;
./cavity/system/fvSchemes:12: class dictionary;
./constant/transportProperties:12: class dictionary;
./system/controlDict:12: class dictionary;
./system/fvSolution:12: class dictionary;
./system/blockMeshDict:12: class dictionary;
./system/fvSchemes:12: class dictionary;
都是dictionary类,那创建起来更方便了,比如说contorlDict文件
点击查看代码
IOdictionary controlDict( IOobject ( "controlDict", runTime.constant(), //runTime.system(), mesh, IOobject::MUST_READ, IOobject::AUTO_WRITE ) ) ;
有了dictionary这个字典类,顾名思义,字典当然是很方便查找啊,而且本身也是在链表以及哈希列表基础上建立的,能用的函数就很丰富了,如lookup()等。
综上,openfoam创建了一个读取方便查找容易的类支持of进行数据处理,寻根溯源很麻烦,但是用起来还是很简单的。
正因为文件读取占用很大的比重,这篇文章写了三个多小时,我们也是借此机会对openfoam内部略窥一二,这样我们就知道我们的程序在写什么,知道其所能为与不能为。
最后奉上自己编写的openfoam codesnip ,节约大家时间
点击查看代码
//***********************************************// //openfoam "Foam_IOobject": { "prefix": "IOobject_Foam_", "body": [ "IOobject ${1|U,p,T,dicName|}(", // "t${2|"U","p","T"|}", "t"${1}",", "t//runTime.timeName(),", "t//runTime.constant(),", "tmesh,", "tIOobject::MUST_READ,", "tIOobject::AUTO_WRITE", ") ;" ], "description": "FOAM::IOobject" }, "Foam::IOdictionary": { "prefix": "IOdictionary_Foam_", "body": [ "IOdictionary ${1:dicName}(", "tIOobject (", // "t${2|"U","p","T"|}", "tt"${1}",", "tt//runTime.constant(),", "tt//runTime.system(),", "ttmesh,", "ttIOobject::MUST_READ,", "ttIOobject::AUTO_WRITE", "t)", ") ;" ], "description": "Foam::IOdictionary" }, "Foam::volVectorField": { "prefix": "volVectorField_Foam_", "body": [ "volVectorField ${U}(", "tIOobject (", "tt"${U}",", "ttrunTime.timeName(),", "ttmesh,", "ttIOobject::MUST_READ,", "ttIOobject::AUTO_WRITE", "t),", "tmesh", ") ;" ], "description": "Foam::volVectorField" }, "Foam::volScalarField": { "prefix": "volScalarField_Foam_", "body": [ "volScalarField ${p}(", "tIOobject (", "tt"${p}",", "ttrunTime.timeName(),", "ttmesh,", "ttIOobject::MUST_READ,", "ttIOobject::AUTO_WRITE", "t),", "tmesh", ") ;" ], "description": "Foam::volScalarField" }, "Foam::scalar": { "prefix": "scalar", "body": [ "scalar " ], "description": "Foam::scalar" }, //***********************************************//
创作不易,如若喜欢,不胜感激,欢迎支持,欢迎指正