读取OpenFOAM二进制polyMesh格式的C/C++程序
文章目录
- 读取OpenFOAM二进制polymesh格式的C/C++程序
- 1. 理解OpenFOAM二进制格式
- 2. 基本读取步骤
- 2.1 读取FoamFile头部
- 2.2 读取二进制数据
- 2.3 读取faces文件(面数据)
- 2.4 读取owner/neighbour文件
- 2.5 读取cellZones数据
- 3. 注意事项
- 4. 完整示例
- 5. 替代方案
- OpenFOAM网格数据文本格式和二进制格式比较
- 1. **文件体积对比**
- 2. **读写性能**
- 3. **典型文件对比**
- 4. **何时使用哪种格式**
- 5. **转换方法**
- 总结
读取OpenFOAM二进制polymesh格式的C/C++程序
OpenFOAM使用自定义的二进制格式存储网格数据(polymesh),主要包括points、faces、owner、neighbour等文件。以下是编写C/C++程序读取这些二进制文件的方法:
1. 理解OpenFOAM二进制格式
OpenFOAM的二进制polymesh文件具有以下特点:
- 文件开头有FoamFile头部信息(ASCII格式)
- 实际数据部分采用二进制格式
- 数据通常以列表形式存储,前面有列表长度
- 数值通常采用IEEE浮点格式或整型格式
2. 基本读取步骤
2.1 读取FoamFile头部
首先需要跳过ASCII头部,直到找到第一个左花括号{
之后的数据。
void skipHeader(FILE* fp) {char line[256];while (fgets(line, sizeof(line), fp)) {if (strstr(line, "FoamFile")) {// 跳过FoamFile块while (fgets(line, sizeof(line), fp) && !strstr(line, "}"));}if (strchr(line, '{')) {break; // 找到数据开始位置}}
}
2.2 读取二进制数据
对于points文件(存储顶点坐标):
struct Point { float x, y, z; };std::vector<Point> readPoints(const char* filename) {FILE* fp = fopen(filename, "rb");if (!fp) throw std::runtime_error("Cannot open file");skipHeader(fp);// 读取点数int32_t nPoints;fread(&nPoints, sizeof(int32_t), 1, fp);std::vector<Point> points(nPoints);fread(points.data(), sizeof(Point), nPoints, fp);fclose(fp);return points;
}
2.3 读取faces文件(面数据)
struct Face {std::vector<int32_t> vertices; // 面的顶点索引
};std::vector<Face> readFaces(const char* filename) {FILE* fp = fopen(filename, "rb");if (!fp) throw std::runtime_error("Cannot open file");skipHeader(fp);// 读取面数int32_t nFaces;fread(&nFaces, sizeof(int32_t), 1, fp);std::vector<Face> faces(nFaces);for (auto& face : faces) {int32_t nVertices;fread(&nVertices, sizeof(int32_t), 1, fp);face.vertices.resize(nVertices);fread(face.vertices.data(), sizeof(int32_t), nVertices, fp);}fclose(fp);return faces;
}
2.4 读取owner/neighbour文件
std::vector<int32_t> readCellList(const char* filename) {FILE* fp = fopen(filename, "rb");if (!fp) throw std::runtime_error("Cannot open file");skipHeader(fp);// 读取单元数int32_t nCells;fread(&nCells, sizeof(int32_t), 1, fp);std::vector<int32_t> cells(nCells);fread(cells.data(), sizeof(int32_t), nCells, fp);fclose(fp);return cells;
}
2.5 读取cellZones数据
cellZones文件存储了网格中特定区域的单元分组信息。以下是读取方法:
#include <string>
#include <vector>
#include <map>struct ZoneInfo {std::string name;std::vector<int> cells;
};std::vector<ZoneInfo> readCellZones(const std::string& filename) {std::ifstream file(filename, std::ios::binary);if (!file) {throw std::runtime_error("Cannot open cellZones file");}// 跳过FoamFile头部int32_t numZones;file.read(reinterpret_cast<char*>(&numZones), sizeof(numZones));std::vector<ZoneInfo> zones(numZones);for (auto& zone : zones) {// 读取区域名称长度和名称int32_t nameLength;file.read(reinterpret_cast<char*>(&nameLength), sizeof(nameLength));zone.name.resize(nameLength);file.read(&zone.name[0], nameLength);// 读取单元数量int32_t numCells;file.read(reinterpret_cast<char*>(&numCells), sizeof(numCells));zone.cells.resize(numCells);file.read(reinterpret_cast<char*>(zone.cells.data()), numCells * sizeof(int32_t));}return zones;
}
3. 注意事项
-
字节序:OpenFOAM二进制文件通常使用处理器原生字节序,但如果你在不同架构的机器上读取,可能需要处理字节序转换。
-
精度:OpenFOAM可以使用单精度(float)或双精度(double)存储数据,通常由
writePrecision
设置决定。 -
边界条件:边界条件信息存储在
boundary
文件中,需要额外解析。 -
并行计算:对于并行计算案例,网格被分割为多个处理器目录(processorN),每个都有自己的polyMesh。
-
调试:可以使用
foamFormatConvert
工具将二进制格式转换为ASCII格式进行调试。
4. 完整示例
#include <iostream>
#include <vector>
#include <fstream>
#include <stdexcept>struct Point { float x, y, z; };
struct Face { std::vector<int32_t> vertices; };void skipHeader(std::ifstream& is) {std::string line;while (std::getline(is, line)) {if (line.find("FoamFile") != std::string::npos) {while (std::getline(is, line) && line.find('}') == std::string::npos);}if (line.find('{') != std::string::npos) break;}
}std::vector<Point> readPoints(const std::string& filename) {std::ifstream is(filename, std::ios::binary);if (!is) throw std::runtime_error("Cannot open file: " + filename);skipHeader(is);int32_t nPoints;is.read(reinterpret_cast<char*>(&nPoints), sizeof(int32_t));std::vector<Point> points(nPoints);is.read(reinterpret_cast<char*>(points.data()), nPoints * sizeof(Point));return points;
}int main() {try {auto points = readPoints("constant/polyMesh/points");std::cout << "Read " << points.size() << " points" << std::endl;return 0;} catch (const std::exception& e) {std::cerr << "Error: " << e.what() << std::endl;return 1;}
}
5. 替代方案
如果不想手动解析二进制格式,可以考虑:
- 使用OpenFOAM自带的库函数(需要链接OpenFOAM库)
- 先将二进制格式转换为ASCII格式再读取
- 使用第三方库如CGNS或VTK的OpenFOAM读取器
以上代码提供了读取OpenFOAM二进制polymesh的基本框架,实际应用中可能需要根据具体情况进行调整。
OpenFOAM网格数据文本格式和二进制格式比较
在OpenFOAM中,网格数据可以以文本(ASCII)或二进制(binary)格式存储,两种格式在文件大小和读写性能上有显著差异,尤其对于大网格数据。以下是关键对比:
1. 文件体积对比
- 二进制格式:
数据以紧凑的二进制形式存储,通常比文本格式小 3-5倍。例如,一个文本格式的points
文件为100 MB,二进制版本可能仅20-30 MB。 - 文本格式:
数据以人类可读的ASCII形式存储,数值(如浮点数)以字符串形式保存,占用更多空间。
2. 读写性能
- 二进制格式:
- 读取更快:无需解析文本,直接加载二进制数据。
- 写入更快:减少磁盘I/O操作。
- 对大网格(如百万级网格),二进制格式的加载时间可缩短数倍。
- 文本格式:
- 可手动查看/编辑,但读写速度慢,尤其在大数据量时。
3. 典型文件对比
points
(节点坐标):二进制体积约为文本的 1/4-1/5。faces
(面连接性):二进制体积约为文本的 1/3-1/4(因整数存储更高效)。owner
/neighbour
:二进制体积约为文本的 1/3。
4. 何时使用哪种格式
- 二进制:默认选择,尤其适用于大规模仿真(如CFD、DEM)。
- 文本:仅需调试或手动修改网格时使用(如
polyMesh/convertToASCII
转换)。
5. 转换方法
- 文本→二进制:
foamFormatConvert -constant -format binary
- 二进制→文本:
foamFormatConvert -constant -format ascii
总结
对于大网格数据,二进制格式的文件体积通常为文本格式的1/3到1/5,且读写效率更高。建议仅在调试时使用文本格式。