foamToPython 0.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,205 @@
1
+ import numpy as np
2
+ import sys
3
+ import re
4
+ from typing import List, Tuple, Optional
5
+ from .headerEnd import *
6
+
7
+
8
+ def _num_list(subcontent: List[bytes]) -> Tuple[int, int]:
9
+ for idx, line in enumerate(subcontent):
10
+ try:
11
+ return int(line), idx
12
+ except ValueError:
13
+ continue
14
+
15
+
16
+ def _check_data_type(data: bytes) -> str:
17
+ data = data.decode("utf-8").strip()
18
+ if re.match(r"^\(\s*-?\d+(\.\d+)?\s+-?\d+(\.\d+)?\s+-?\d+(\.\d+)?\s*\)$", data):
19
+ return "vector"
20
+ elif re.match(r"^-?\d+(\.\d+)?([eE][-+]?\d+)?$", data):
21
+ return "scalar"
22
+ elif re.match(r"^\d+$", data):
23
+ return "label"
24
+ else:
25
+ sys.exit("Unknown data_type. please use 'label', 'scalar' or 'vector'.")
26
+
27
+
28
+ def _extractList(content: List[bytes], data_type: Optional[str]) -> np.ndarray:
29
+ num_data_, data_idx = _num_list(content)
30
+ data_start_idx = data_idx + 2
31
+ # Extract relevant lines containing coordinates
32
+ string_coords = content[data_start_idx : data_start_idx + num_data_]
33
+
34
+ if data_type is None:
35
+ data_type = _check_data_type(string_coords[0])
36
+
37
+ if data_type == "label":
38
+ # Join all lines and replace unwanted characters once
39
+ joined_coords = b" ".join(string_coords).replace(b"\n", b"")
40
+ # Convert to a numpy array in one go
41
+ data_array = np.fromstring(joined_coords, sep=" ", dtype=int)
42
+
43
+ elif data_type == "scalar":
44
+ # Join all lines and replace unwanted characters once
45
+ joined_coords = b" ".join(string_coords).replace(b"\n", b"")
46
+ # Convert to a numpy array in one go
47
+ data_array = np.fromstring(joined_coords, sep=" ", dtype=float)
48
+
49
+ elif data_type == "vector":
50
+ # Join all lines and replace unwanted characters once
51
+ joined_coords = (
52
+ b" ".join(string_coords)
53
+ .replace(b")", b"")
54
+ .replace(b"(", b"")
55
+ .replace(b"\n", b"")
56
+ )
57
+ # Convert to a numpy array in one go
58
+ data_array = np.fromstring(joined_coords, sep=" ", dtype=float).reshape(
59
+ num_data_, 3
60
+ )
61
+
62
+ else:
63
+ sys.exit("Unknown data_type. please use 'label', 'scalar' or 'vector'.")
64
+
65
+ return data_array
66
+
67
+
68
+ def _extractListList(content: List[bytes], data_type: str) -> np.ndarray:
69
+ num_list_, start_idx = _num_list(content)
70
+ # print(f"The number of list is: {num_list_}")
71
+ subcontent = content[start_idx + 1 :]
72
+ data_list = []
73
+ for i in range(num_list_):
74
+ num_data_, data_idx = _num_list(subcontent)
75
+ data_start_idx = data_idx + 2
76
+ # Extract relevant lines containing coordinates
77
+ string_coords = subcontent[data_start_idx : data_start_idx + num_data_]
78
+
79
+ if data_type == "label":
80
+ # Join all lines and replace unwanted characters once
81
+ joined_coords = b" ".join(string_coords).replace(b"\n", b"")
82
+ # Convert to a numpy array in one go
83
+ data_list.append(np.fromstring(joined_coords, sep=" ", dtype=int))
84
+
85
+ elif data_type == "scalar":
86
+ # Join all lines and replace unwanted characters once
87
+ joined_coords = b" ".join(string_coords).replace(b"\n", b"")
88
+ # Convert to a numpy array in one go
89
+ data_list.append(np.fromstring(joined_coords, sep=" ", dtype=float))
90
+
91
+ elif data_type == "vector":
92
+ # Join all lines and replace unwanted characters once
93
+ joined_coords = (
94
+ b" ".join(string_coords)
95
+ .replace(b")", b"")
96
+ .replace(b"(", b"")
97
+ .replace(b"\n", b"")
98
+ )
99
+ # Convert to a numpy array in one go
100
+ data_list.append(
101
+ np.fromstring(joined_coords, sep=" ", dtype=float).reshape(num_data_, 3)
102
+ )
103
+ else:
104
+ sys.exit("Unknown data_type. please use 'label', 'scalar' or 'vector'.")
105
+
106
+ subcontent = subcontent[data_start_idx + num_data_ + 1 :]
107
+
108
+ return np.array(data_list)
109
+
110
+
111
+ def readListList(fileName: str, data_type: str) -> np.ndarray:
112
+ try:
113
+ with open(fileName, "rb") as f:
114
+ pass
115
+ except FileNotFoundError:
116
+ sys.exit(f"File {fileName} not found. Please check the file path.")
117
+ with open(f"{fileName}", "rb") as f:
118
+ return _extractListList(f.readlines(), data_type)
119
+
120
+
121
+ def _extractUniformList(file: List[bytes], data_type: str) -> Tuple[int, np.ndarray]:
122
+ for line in file:
123
+ line = line.decode("utf-8").strip()
124
+ if "{" in line and "}" in line:
125
+ length, data = line.split("{")
126
+ length = int(length.strip())
127
+ data = data.replace("}", "").strip()
128
+ if data_type == "label":
129
+ return length, np.array(int(data))
130
+ elif data_type == "scalar":
131
+ return length, np.array(float(data))
132
+ elif data_type == "vector":
133
+ vector_values = data.strip("()").split()
134
+ return length, np.array(
135
+ [
136
+ float(vector_values[0]),
137
+ float(vector_values[1]),
138
+ float(vector_values[2]),
139
+ ]
140
+ )
141
+ else:
142
+ sys.exit("Unknown data_type. please use 'label', 'scalar' or 'vector'.")
143
+
144
+
145
+ def readList(fileName: str, data_type: str, fullLength: bool = True) -> np.ndarray:
146
+ try:
147
+ with open(fileName, "rb") as f:
148
+ pass
149
+ except FileNotFoundError:
150
+ sys.exit(f"File {fileName} not found. Please check the file path.")
151
+ with open(f"{fileName}", "rb") as f:
152
+ file_content = f.readlines()
153
+ file_length = len(file_content)
154
+ if file_length == 1:
155
+ length, data = _extractUniformList(file_content, data_type)
156
+ if fullLength:
157
+ if data_type == "vector":
158
+ return np.tile(data, (length, 1))
159
+ else:
160
+ return np.repeat(data, length, axis=0)
161
+ else:
162
+ return data
163
+ else:
164
+ return _extractList(file_content, data_type)
165
+
166
+
167
+ def writeList(
168
+ data: np.ndarray, data_type: str, fileName: str, object_name: str = "None"
169
+ ) -> None:
170
+ """
171
+ Write data to a file
172
+ :param data: data to write
173
+ :param data_type: data type
174
+ :param fileName: file name
175
+ :return: None
176
+ """
177
+
178
+ with open(fileName, "w") as f:
179
+ output = []
180
+
181
+ thisHeader = header.replace("className;", f"{data_type}List;")
182
+ if object_name != "None":
183
+ thisHeader = thisHeader.replace(
184
+ "object data;", f"object {object_name};"
185
+ )
186
+ output.append(thisHeader + "\n\n")
187
+ else:
188
+ output.append(thisHeader + "\n\n")
189
+
190
+ output.append(f"{data.shape[0]}\n")
191
+ output.append("(\n")
192
+ if data_type == "label":
193
+ for point in data:
194
+ output.append(f"{point:d}\n")
195
+ elif data_type == "scalar":
196
+ for point in data:
197
+ output.append(f"{point:.8e}\n")
198
+ elif data_type == "vector":
199
+ for point in data:
200
+ output.append(f"({point[0]:.8e} {point[1]:.8e} {point[2]:.8e})\n")
201
+ else:
202
+ sys.exit("Unknown data_type. please use 'label', 'scalar' or 'vector'.")
203
+ output.append(")\n")
204
+ output.append(ender)
205
+ f.write("".join(output))
@@ -0,0 +1,111 @@
1
+ Metadata-Version: 2.4
2
+ Name: foamToPython
3
+ Version: 0.0.1
4
+ Summary: A py package to read and write OpenFOAM data
5
+ Author-email: Shenhui_Ruan <shenhui.ruan@kit.edu>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+
10
+ [foamToPython](https://github.com/Ruansh233/foamToPython.git) is an ongoing repository to read and write the OpenFOAM field and numpy array. You can also perform Proper Orthogonal Decomposition (POD) to OpenFOAM fields with this package. It can handle both serial and parallel OpenFOAM case. The package is developed in Python 3.8+ and depends on numpy.
11
+
12
+ ## Features
13
+ It is about __10 times faster__ than two widely used packages, [FluidFoam](https://github.com/fluiddyn/fluidfoam) and [foamlib](https://github.com/gerlero/foamlib), in reading fields. Moreover, it is capable to read and write parallel OpenFOAM case. The comparison of the performance is shown in the following figure.
14
+
15
+ ![Performance Comparison](https://raw.githubusercontent.com/Ruansh233/foamToPython/main/foamToPython_comparison.png)
16
+
17
+ The comparsion is performed for 4 conditions.
18
+ 1. Scalar fields with 5 million cells.
19
+ 2. Vector fields with 5 million cells.
20
+ 3. Scalar fields with 36 million cells.
21
+ 4. Vector fields with 36 million cells.
22
+
23
+ This test is performed on a cluster node with Intel Xeon Platinum 8358 CPU 64 cores @ 2.60GHz, 256GB RAM, and Red Hat Enterprise Linux.
24
+
25
+ foamToPython is ten times faster than FluidFoam and foamlib when reading parallel case with 36 million cells. Note that the aforementioned packages have more functions compared to the current library. [PyFoam](https://pypi.org/project/PyFoam/) is not involved in the comparsion due to the problem of version compatibility.
26
+
27
+ ## Installation
28
+ You can install the package via pip:
29
+ ```bash
30
+ pip install foamToPython
31
+ ```
32
+ Or you can clone the repository and install it manually:
33
+ ```bash
34
+ pip install git+https://github.com/Ruansh233/foamToPython.git
35
+ ```
36
+
37
+ ## Usage and Examples
38
+
39
+ ### <span style="color:blue;">OFField</span> class
40
+ The class could read OpenFOAM fields.
41
+ It can process volScalarField or volVectorField, either uniform or non-uniform internalField.
42
+
43
+ #### read field, e.g., U
44
+ `U = readOFData.OFField('case/1/U', 'vector', read_data=True)`
45
+
46
+ The arguments are:
47
+ 1. _filename_: the path of the field file.
48
+ 2. _data_type_: the type of the field, e.g., "scalar", "vector", "label".
49
+ 3. _read_data_: whether to read the field when initializing the class.
50
+ 4. _parallel_: whether the case is run in parallel.
51
+
52
+ If read_data is False, the field will not be read when initializing the class. You can use `U._readField()` to read it later, or access `U.internalField` or `U.boundaryField`, which will trigger the reading of the field.
53
+
54
+ The package can read parallel case, e.g., `U = readOFData.OFField('case/1/U', 'vector', parallel=True)`.
55
+
56
+ #### load <span style="color:blue;">internalField</span> and <span style="color:blue;">boundaryField</span>
57
+
58
+ `U_cell = U.internalField`
59
+ `U_boundary = U.boundaryField`
60
+
61
+ 1. _U_cell_ is a numpy array, store the fields values. The length is 1 for the uniform internal field.
62
+ 2. _U_boundary_ is a dict store each patches. For each patch, it contain _type_ for the type of boundary. If the _type_ is _fixedValue_, the numpy array can be accessed by the key _value_. For example: `U.boundaryField['velocityInlet']['value']`
63
+
64
+ For parallel case, both internalField and boundaryField are read from all processors and stored as lists. For example, `U.internalField[0]` is the internalField from processor 0.
65
+
66
+ #### <span style="color:blue;">writeField</span>
67
+ You can modify the data of _U_ and then write it as OF field.
68
+
69
+ The arguments are:
70
+ 1. _path_: the path to write the field. It can contain `<timeDir>` and `<fieldName>`, which will be replaced by the arguments `timeDir` and `fieldName` if provided.
71
+ 2. _timeDir_: the time directory to write the field. Default is `None`.
72
+ 3. _fieldName_: the name of the field to write. Default is `None`.
73
+
74
+ Same function can be used to write parallel case, e.g., `U.writeField('case/<timeDir>/<fieldName>')`.
75
+
76
+ Therefore, you can use two types of inputs, e.g.,
77
+ 1. `U.writeField('case/<timeDir>/<fieldName>')`.
78
+ 2. `U.writeField('case/test', timeDir=<timeDir>, fieldName=<fieldName>)`. Note that `timeDir` and `fieldName` are needed when using **Paraview** to read the fields.
79
+
80
+ ### <span style="color:blue;">readList</span> function
81
+ The function could read field value like velocity and pressure.
82
+ The data type are: "lable", "scalar", "vector".
83
+
84
+ For example: `U = readList("1/U", "vector").`
85
+
86
+ ### <span style="color:blue;">readListList</span> function
87
+ The function could read ListList, like the cellZones file.
88
+ The data type are: "lable", "scalar", "vector".
89
+
90
+ For example: `cellZones = readList("constant/polyMesh/cellZones", "label")`.
91
+
92
+ ### Perform <span style="color:blue;">POD</span> to openfoam fields.
93
+ Please check the submodule _PODopenFOAM_ and the class under it _PODmodes_, which can be called `foamToPython.PODmodes`. It can be created as,
94
+
95
+ `pod = PODmodes(U, POD_algo=<POD_algo>, rank=<rank>)`.
96
+
97
+ The arguments are:
98
+ 1. _U_: the OFField class instance, which contains the data to perform POD.
99
+ 2. _POD_algo_: the algorithm to perform POD, can be "svd" or "eigen". Default is "eigen".
100
+ 3. _rank_: the number of modes to compute. Default is 10, which means 10 modes are computed.
101
+
102
+ The modes can be exported with OpenFOAM format using
103
+ `pod.writeModes(outputDir, fieldName=<fieldName>)`.
104
+
105
+ The arguments are:
106
+ 1. _outputDir_: the directory to write the modes. The modes will be written in folders `outputDir/1`, `outputDir/2`, ..., `outputDir/rank`.
107
+ 2. _fieldName_: the name of the field to write. Default is `None`.
108
+
109
+ ### Parallel case
110
+ The package can read and write parallel case.
111
+ However, the speed is slower than the serial case, and it will be improved in the future.
@@ -0,0 +1,10 @@
1
+ PODopenFOAM/__init__.py,sha256=b69xkbdteJB1NKD0pzbvpZlv5XecgG6rMWqCufjWtvc,88
2
+ PODopenFOAM/ofmodes.py,sha256=ijbToWofpoAS1IH6NZ-ukcIIS2NzJPzexSi7tgha9BI,45123
3
+ foamToPython/__init__.py,sha256=gkxoBFtrheK7_4ypMfvNpzTtuxODXgC14O59nUrtRo8,202
4
+ foamToPython/headerEnd.py,sha256=71YKtxBeTVvNVqwesjTPyN9UUFdLRVnaQrdme5RFp2I,931
5
+ foamToPython/readOFField.py,sha256=YVn40Z7p305rPVhohs7vIuuOb2ee6o_Vh6rI8roiPVA,47006
6
+ foamToPython/readOFList.py,sha256=Vj5viT3NFnCOhKY_rDbohrvgxu2Trt81rR_K1zMmU5w,7384
7
+ foamtopython-0.0.1.dist-info/METADATA,sha256=ufh0PkLQyKfHDvRZX9M_MqudqwhsxM2e0bszFcHF-SM,5823
8
+ foamtopython-0.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
9
+ foamtopython-0.0.1.dist-info/top_level.txt,sha256=MK_8dURMuIU0_VSaR3Z0upsnsFKlfvgeAd2gqXURjRM,25
10
+ foamtopython-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ PODopenFOAM
2
+ foamToPython