foamlib 0.6.6__tar.gz → 0.6.8__tar.gz
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.
- {foamlib-0.6.6 → foamlib-0.6.8}/PKG-INFO +34 -21
- {foamlib-0.6.6 → foamlib-0.6.8}/README.md +31 -19
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/__init__.py +1 -1
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_async.py +12 -7
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_base.py +8 -7
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_run.py +31 -9
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_slurm.py +4 -2
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_subprocess.py +5 -3
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_sync.py +9 -6
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/_base.py +4 -6
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/_files.py +14 -17
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/_io.py +5 -3
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/_parsing.py +21 -4
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/_serialization.py +15 -17
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib.egg-info/PKG-INFO +34 -21
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib.egg-info/requires.txt +4 -1
- {foamlib-0.6.6 → foamlib-0.6.8}/pyproject.toml +35 -3
- {foamlib-0.6.6 → foamlib-0.6.8}/LICENSE.txt +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/__init__.py +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_cases/_util.py +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/__init__.py +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/_files/_util.py +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib/py.typed +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib.egg-info/SOURCES.txt +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib.egg-info/dependency_links.txt +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/foamlib.egg-info/top_level.txt +0 -0
- {foamlib-0.6.6 → foamlib-0.6.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.8
|
4
4
|
Summary: A Python interface for interacting with OpenFOAM
|
5
5
|
Author-email: "Gabriel S. Gerlero" <ggerlero@cimec.unl.edu.ar>
|
6
6
|
Project-URL: Homepage, https://github.com/gerlero/foamlib
|
@@ -30,6 +30,7 @@ Requires-Dist: aioshutil<2,>=1
|
|
30
30
|
Requires-Dist: pyparsing<4,>=3
|
31
31
|
Requires-Dist: typing-extensions<5,>=4; python_version < "3.11"
|
32
32
|
Provides-Extra: numpy
|
33
|
+
Requires-Dist: numpy<3,>=1.25.0; python_version >= "3.10" and extra == "numpy"
|
33
34
|
Requires-Dist: numpy<3,>=1; extra == "numpy"
|
34
35
|
Provides-Extra: lint
|
35
36
|
Requires-Dist: ruff; extra == "lint"
|
@@ -43,7 +44,7 @@ Requires-Dist: foamlib[test]; extra == "typing"
|
|
43
44
|
Requires-Dist: mypy<2,>=1; extra == "typing"
|
44
45
|
Provides-Extra: docs
|
45
46
|
Requires-Dist: foamlib[numpy]; extra == "docs"
|
46
|
-
Requires-Dist: sphinx<9,>=
|
47
|
+
Requires-Dist: sphinx<9,>=5; extra == "docs"
|
47
48
|
Requires-Dist: sphinx_rtd_theme; extra == "docs"
|
48
49
|
Provides-Extra: dev
|
49
50
|
Requires-Dist: foamlib[numpy]; extra == "dev"
|
@@ -52,38 +53,50 @@ Requires-Dist: foamlib[test]; extra == "dev"
|
|
52
53
|
Requires-Dist: foamlib[typing]; extra == "dev"
|
53
54
|
Requires-Dist: foamlib[docs]; extra == "dev"
|
54
55
|
|
55
|
-
[<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="
|
56
|
+
[<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="65">](https://github.com/gerlero/foamlib)
|
56
57
|
|
57
58
|
[](https://foamlib.readthedocs.io/)
|
58
59
|
[](https://github.com/gerlero/foamlib/actions/workflows/ci.yml)
|
59
60
|
[](https://codecov.io/gh/gerlero/foamlib)
|
60
61
|
[](http://mypy-lang.org/)
|
61
62
|
[](https://github.com/astral-sh/ruff)
|
63
|
+
[](https://github.com/astral-sh/uv)
|
64
|
+
[](https://github.com/gerlero/foamlib/actions/workflows/pypi-publish.yml)
|
62
65
|
[](https://pypi.org/project/foamlib/)
|
66
|
+
[](https://anaconda.org/conda-forge/foamlib)
|
63
67
|
[](https://pypi.org/project/foamlib/)
|
64
68
|

|
69
|
+
[](https://github.com/gerlero/foamlib/actions/workflows/docker.yml)
|
65
70
|
[](https://hub.docker.com/r/microfluidica/foamlib/)
|
66
71
|
|
72
|
+
## 👋 Basics
|
73
|
+
|
67
74
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
68
75
|
|
69
|
-
It offers the following classes:
|
76
|
+
It offers the following Python classes:
|
70
77
|
|
71
78
|
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/files.html#foamlib.FoamFile) (and [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/files.html#foamlib.FoamFieldFile)): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s, using `foamlib`'s own parser. Supports ASCII and binary field formats (with or without compression).
|
72
79
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.FoamCase): a class for configuring, running, and accessing the results of OpenFOAM cases.
|
73
80
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
74
81
|
* [`AsyncSlurmFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncSlurmFoamCase): subclass of `AsyncFoamCase` used for running cases on a Slurm cluster.
|
75
82
|
|
76
|
-
## Get started
|
83
|
+
## ☑️ Get started
|
77
84
|
|
78
|
-
### Install
|
85
|
+
### 📦 Install
|
79
86
|
|
80
|
-
|
87
|
+
* With [pip](https://pypi.org/project/pip/):
|
81
88
|
|
82
|
-
```bash
|
83
|
-
pip install foamlib
|
84
|
-
```
|
89
|
+
```bash
|
90
|
+
pip install foamlib
|
91
|
+
```
|
92
|
+
|
93
|
+
* With [conda](https://docs.conda.io/en/latest/):
|
94
|
+
|
95
|
+
```bash
|
96
|
+
conda install -c conda-forge foamlib
|
97
|
+
```
|
85
98
|
|
86
|
-
### Clone a case
|
99
|
+
### 🐑 Clone a case
|
87
100
|
|
88
101
|
```python
|
89
102
|
import os
|
@@ -95,13 +108,13 @@ pitz_tutorial = FoamCase(Path(os.environ["FOAM_TUTORIALS"]) / "incompressible/si
|
|
95
108
|
my_pitz = pitz_tutorial.clone("myPitz")
|
96
109
|
```
|
97
110
|
|
98
|
-
### Run the case
|
111
|
+
### 🏃 Run the case
|
99
112
|
|
100
113
|
```python
|
101
114
|
my_pitz.run()
|
102
115
|
```
|
103
116
|
|
104
|
-
### Access the results
|
117
|
+
### 🔎 Access the results
|
105
118
|
|
106
119
|
```python
|
107
120
|
latest_time = my_pitz[-1]
|
@@ -113,19 +126,19 @@ print(p.internal_field)
|
|
113
126
|
print(U.internal_field)
|
114
127
|
```
|
115
128
|
|
116
|
-
### Clean the case
|
129
|
+
### 🧹 Clean the case
|
117
130
|
|
118
131
|
```python
|
119
132
|
my_pitz.clean()
|
120
133
|
```
|
121
134
|
|
122
|
-
### Edit the `controlDict` file
|
135
|
+
### ⚙️ Edit the `controlDict` file
|
123
136
|
|
124
137
|
```python
|
125
138
|
my_pitz.control_dict["writeInterval"] = 10
|
126
139
|
```
|
127
140
|
|
128
|
-
### Make multiple file reads and writes in a single go
|
141
|
+
### 📝 Make multiple file reads and writes in a single go
|
129
142
|
|
130
143
|
```python
|
131
144
|
with my_pitz.fv_schemes as f:
|
@@ -133,7 +146,7 @@ with my_pitz.fv_schemes as f:
|
|
133
146
|
f["snGradSchemes"]["default"] = "uncorrected"
|
134
147
|
```
|
135
148
|
|
136
|
-
### Run a case asynchronously
|
149
|
+
### ⏳ Run a case asynchronously
|
137
150
|
|
138
151
|
```python
|
139
152
|
import asyncio
|
@@ -146,7 +159,7 @@ async def run_case():
|
|
146
159
|
asyncio.run(run_case())
|
147
160
|
```
|
148
161
|
|
149
|
-
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
162
|
+
### 🔢 Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
150
163
|
|
151
164
|
```python
|
152
165
|
from foamlib import FoamFieldFile
|
@@ -156,7 +169,7 @@ U = FoamFieldFile(Path(my_pitz) / "0/U")
|
|
156
169
|
print(U.internal_field)
|
157
170
|
```
|
158
171
|
|
159
|
-
### Run an optimization loop in parallel
|
172
|
+
### 🔁 Run an optimization loop in parallel
|
160
173
|
|
161
174
|
```python
|
162
175
|
import os
|
@@ -176,7 +189,7 @@ async def cost(x):
|
|
176
189
|
result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
|
177
190
|
```
|
178
191
|
|
179
|
-
### Use it to create a `run` (or `clean`) script
|
192
|
+
### 📄 Use it to create a `run` (or `clean`) script
|
180
193
|
|
181
194
|
```python
|
182
195
|
#!/usr/bin/env python3
|
@@ -188,6 +201,6 @@ case = FoamCase(Path(__file__).parent)
|
|
188
201
|
case.run()
|
189
202
|
```
|
190
203
|
|
191
|
-
## Documentation
|
204
|
+
## 📘 Documentation
|
192
205
|
|
193
206
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -1,35 +1,47 @@
|
|
1
|
-
[<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="
|
1
|
+
[<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="65">](https://github.com/gerlero/foamlib)
|
2
2
|
|
3
3
|
[](https://foamlib.readthedocs.io/)
|
4
4
|
[](https://github.com/gerlero/foamlib/actions/workflows/ci.yml)
|
5
5
|
[](https://codecov.io/gh/gerlero/foamlib)
|
6
6
|
[](http://mypy-lang.org/)
|
7
7
|
[](https://github.com/astral-sh/ruff)
|
8
|
+
[](https://github.com/astral-sh/uv)
|
9
|
+
[](https://github.com/gerlero/foamlib/actions/workflows/pypi-publish.yml)
|
8
10
|
[](https://pypi.org/project/foamlib/)
|
11
|
+
[](https://anaconda.org/conda-forge/foamlib)
|
9
12
|
[](https://pypi.org/project/foamlib/)
|
10
13
|

|
14
|
+
[](https://github.com/gerlero/foamlib/actions/workflows/docker.yml)
|
11
15
|
[](https://hub.docker.com/r/microfluidica/foamlib/)
|
12
16
|
|
17
|
+
## 👋 Basics
|
18
|
+
|
13
19
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
14
20
|
|
15
|
-
It offers the following classes:
|
21
|
+
It offers the following Python classes:
|
16
22
|
|
17
23
|
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/files.html#foamlib.FoamFile) (and [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/files.html#foamlib.FoamFieldFile)): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s, using `foamlib`'s own parser. Supports ASCII and binary field formats (with or without compression).
|
18
24
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.FoamCase): a class for configuring, running, and accessing the results of OpenFOAM cases.
|
19
25
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
20
26
|
* [`AsyncSlurmFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncSlurmFoamCase): subclass of `AsyncFoamCase` used for running cases on a Slurm cluster.
|
21
27
|
|
22
|
-
## Get started
|
28
|
+
## ☑️ Get started
|
23
29
|
|
24
|
-
### Install
|
30
|
+
### 📦 Install
|
25
31
|
|
26
|
-
|
32
|
+
* With [pip](https://pypi.org/project/pip/):
|
27
33
|
|
28
|
-
```bash
|
29
|
-
pip install foamlib
|
30
|
-
```
|
34
|
+
```bash
|
35
|
+
pip install foamlib
|
36
|
+
```
|
37
|
+
|
38
|
+
* With [conda](https://docs.conda.io/en/latest/):
|
39
|
+
|
40
|
+
```bash
|
41
|
+
conda install -c conda-forge foamlib
|
42
|
+
```
|
31
43
|
|
32
|
-
### Clone a case
|
44
|
+
### 🐑 Clone a case
|
33
45
|
|
34
46
|
```python
|
35
47
|
import os
|
@@ -41,13 +53,13 @@ pitz_tutorial = FoamCase(Path(os.environ["FOAM_TUTORIALS"]) / "incompressible/si
|
|
41
53
|
my_pitz = pitz_tutorial.clone("myPitz")
|
42
54
|
```
|
43
55
|
|
44
|
-
### Run the case
|
56
|
+
### 🏃 Run the case
|
45
57
|
|
46
58
|
```python
|
47
59
|
my_pitz.run()
|
48
60
|
```
|
49
61
|
|
50
|
-
### Access the results
|
62
|
+
### 🔎 Access the results
|
51
63
|
|
52
64
|
```python
|
53
65
|
latest_time = my_pitz[-1]
|
@@ -59,19 +71,19 @@ print(p.internal_field)
|
|
59
71
|
print(U.internal_field)
|
60
72
|
```
|
61
73
|
|
62
|
-
### Clean the case
|
74
|
+
### 🧹 Clean the case
|
63
75
|
|
64
76
|
```python
|
65
77
|
my_pitz.clean()
|
66
78
|
```
|
67
79
|
|
68
|
-
### Edit the `controlDict` file
|
80
|
+
### ⚙️ Edit the `controlDict` file
|
69
81
|
|
70
82
|
```python
|
71
83
|
my_pitz.control_dict["writeInterval"] = 10
|
72
84
|
```
|
73
85
|
|
74
|
-
### Make multiple file reads and writes in a single go
|
86
|
+
### 📝 Make multiple file reads and writes in a single go
|
75
87
|
|
76
88
|
```python
|
77
89
|
with my_pitz.fv_schemes as f:
|
@@ -79,7 +91,7 @@ with my_pitz.fv_schemes as f:
|
|
79
91
|
f["snGradSchemes"]["default"] = "uncorrected"
|
80
92
|
```
|
81
93
|
|
82
|
-
### Run a case asynchronously
|
94
|
+
### ⏳ Run a case asynchronously
|
83
95
|
|
84
96
|
```python
|
85
97
|
import asyncio
|
@@ -92,7 +104,7 @@ async def run_case():
|
|
92
104
|
asyncio.run(run_case())
|
93
105
|
```
|
94
106
|
|
95
|
-
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
107
|
+
### 🔢 Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
96
108
|
|
97
109
|
```python
|
98
110
|
from foamlib import FoamFieldFile
|
@@ -102,7 +114,7 @@ U = FoamFieldFile(Path(my_pitz) / "0/U")
|
|
102
114
|
print(U.internal_field)
|
103
115
|
```
|
104
116
|
|
105
|
-
### Run an optimization loop in parallel
|
117
|
+
### 🔁 Run an optimization loop in parallel
|
106
118
|
|
107
119
|
```python
|
108
120
|
import os
|
@@ -122,7 +134,7 @@ async def cost(x):
|
|
122
134
|
result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
|
123
135
|
```
|
124
136
|
|
125
|
-
### Use it to create a `run` (or `clean`) script
|
137
|
+
### 📄 Use it to create a `run` (or `clean`) script
|
126
138
|
|
127
139
|
```python
|
128
140
|
#!/usr/bin/env python3
|
@@ -134,6 +146,6 @@ case = FoamCase(Path(__file__).parent)
|
|
134
146
|
case.run()
|
135
147
|
```
|
136
148
|
|
137
|
-
## Documentation
|
149
|
+
## 📘 Documentation
|
138
150
|
|
139
151
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -1,9 +1,8 @@
|
|
1
1
|
import asyncio
|
2
2
|
import multiprocessing
|
3
|
-
import os
|
4
3
|
import sys
|
5
4
|
from contextlib import asynccontextmanager
|
6
|
-
from typing import Any, Callable, Optional, TypeVar, Union, overload
|
5
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, TypeVar, Union, overload
|
7
6
|
|
8
7
|
if sys.version_info >= (3, 9):
|
9
8
|
from collections.abc import (
|
@@ -29,6 +28,9 @@ from ._run import FoamCaseRunBase
|
|
29
28
|
from ._subprocess import run_async
|
30
29
|
from ._util import ValuedGenerator, awaitableasynccontextmanager
|
31
30
|
|
31
|
+
if TYPE_CHECKING:
|
32
|
+
import os
|
33
|
+
|
32
34
|
X = TypeVar("X")
|
33
35
|
Y = TypeVar("Y")
|
34
36
|
|
@@ -101,7 +103,7 @@ class AsyncFoamCase(FoamCaseRunBase):
|
|
101
103
|
async def _rmtree(
|
102
104
|
path: Union["os.PathLike[str]", str], ignore_errors: bool = False
|
103
105
|
) -> None:
|
104
|
-
await aioshutil.rmtree(path, ignore_errors=ignore_errors)
|
106
|
+
await aioshutil.rmtree(path, ignore_errors=ignore_errors)
|
105
107
|
|
106
108
|
@staticmethod
|
107
109
|
async def _copytree(
|
@@ -138,8 +140,11 @@ class AsyncFoamCase(FoamCaseRunBase):
|
|
138
140
|
ret = super().__getitem__(index)
|
139
141
|
if isinstance(ret, FoamCaseBase.TimeDirectory):
|
140
142
|
return AsyncFoamCase.TimeDirectory(ret)
|
141
|
-
|
142
|
-
|
143
|
+
return [AsyncFoamCase.TimeDirectory(r) for r in ret]
|
144
|
+
|
145
|
+
async def _prepare(self, *, check: bool = True, log: bool = True) -> None:
|
146
|
+
for coro in self._prepare_calls(check=check, log=log):
|
147
|
+
await coro
|
143
148
|
|
144
149
|
async def run(
|
145
150
|
self,
|
@@ -188,7 +193,7 @@ class AsyncFoamCase(FoamCaseRunBase):
|
|
188
193
|
@asynccontextmanager
|
189
194
|
async def copy(
|
190
195
|
self, dst: Optional[Union["os.PathLike[str]", str]] = None
|
191
|
-
) ->
|
196
|
+
) -> AsyncGenerator[Self, None]:
|
192
197
|
"""
|
193
198
|
Make a copy of this case.
|
194
199
|
|
@@ -209,7 +214,7 @@ class AsyncFoamCase(FoamCaseRunBase):
|
|
209
214
|
@asynccontextmanager
|
210
215
|
async def clone(
|
211
216
|
self, dst: Optional[Union["os.PathLike[str]", str]] = None
|
212
|
-
) ->
|
217
|
+
) -> AsyncGenerator[Self, None]:
|
213
218
|
"""
|
214
219
|
Clone this case (make a clean copy).
|
215
220
|
|
@@ -1,8 +1,8 @@
|
|
1
|
-
import os
|
2
1
|
import shutil
|
3
2
|
import sys
|
4
3
|
from pathlib import Path
|
5
4
|
from typing import (
|
5
|
+
TYPE_CHECKING,
|
6
6
|
Optional,
|
7
7
|
Union,
|
8
8
|
overload,
|
@@ -23,6 +23,9 @@ else:
|
|
23
23
|
|
24
24
|
from .._files import FoamFieldFile, FoamFile
|
25
25
|
|
26
|
+
if TYPE_CHECKING:
|
27
|
+
import os
|
28
|
+
|
26
29
|
|
27
30
|
class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
28
31
|
def __init__(self, path: Union["os.PathLike[str]", str] = Path()):
|
@@ -57,18 +60,16 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
57
60
|
def __getitem__(self, key: str) -> FoamFieldFile:
|
58
61
|
if (self.path / f"{key}.gz").is_file() and not (self.path / key).is_file():
|
59
62
|
return FoamFieldFile(self.path / f"{key}.gz")
|
60
|
-
|
61
|
-
return FoamFieldFile(self.path / key)
|
63
|
+
return FoamFieldFile(self.path / key)
|
62
64
|
|
63
65
|
def __contains__(self, obj: object) -> bool:
|
64
66
|
if isinstance(obj, FoamFieldFile):
|
65
67
|
return obj.path.parent == self.path and obj.path.is_file()
|
66
|
-
|
68
|
+
if isinstance(obj, str):
|
67
69
|
return (self.path / obj).is_file() or (
|
68
70
|
self.path / f"{obj}.gz"
|
69
71
|
).is_file()
|
70
|
-
|
71
|
-
return False
|
72
|
+
return False
|
72
73
|
|
73
74
|
def __iter__(self) -> Iterator[FoamFieldFile]:
|
74
75
|
for p in self.path.iterdir():
|
@@ -124,7 +125,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
124
125
|
) -> Union["FoamCaseBase.TimeDirectory", Sequence["FoamCaseBase.TimeDirectory"]]:
|
125
126
|
if isinstance(index, str):
|
126
127
|
return FoamCaseBase.TimeDirectory(self.path / index)
|
127
|
-
|
128
|
+
if isinstance(index, float):
|
128
129
|
for time in self._times:
|
129
130
|
if time.time == index:
|
130
131
|
return time
|
@@ -115,6 +115,12 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
115
115
|
def clone(self, dst: Optional[Union["os.PathLike[str]", str]] = None) -> Any:
|
116
116
|
raise NotImplementedError
|
117
117
|
|
118
|
+
@abstractmethod
|
119
|
+
def _prepare(
|
120
|
+
self, *, check: bool = True, log: bool = True
|
121
|
+
) -> Union[None, Coroutine[None, None, None]]:
|
122
|
+
raise NotImplementedError
|
123
|
+
|
118
124
|
@abstractmethod
|
119
125
|
def run(
|
120
126
|
self,
|
@@ -208,6 +214,18 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
208
214
|
|
209
215
|
return script
|
210
216
|
|
217
|
+
def __prepare_script(self) -> Optional[Path]:
|
218
|
+
"""Return the path to the Allrun.pre script, or None if no prepare script is found."""
|
219
|
+
script = self.path / "Allrun.pre"
|
220
|
+
|
221
|
+
if not script.is_file():
|
222
|
+
return None
|
223
|
+
|
224
|
+
if sys.argv and Path(sys.argv[0]).absolute() == script.absolute():
|
225
|
+
return None
|
226
|
+
|
227
|
+
return script
|
228
|
+
|
211
229
|
def __run_script(self, *, parallel: Optional[bool]) -> Optional[Path]:
|
212
230
|
"""Return the path to the (All)run script, or None if no run script is found."""
|
213
231
|
run = self.path / "run"
|
@@ -256,8 +274,7 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
256
274
|
env["DYLD_LIBRARY_PATH"] = env["FOAM_LD_LIBRARY_PATH"]
|
257
275
|
|
258
276
|
return env
|
259
|
-
|
260
|
-
return None
|
277
|
+
return None
|
261
278
|
|
262
279
|
@contextmanager
|
263
280
|
def __output(
|
@@ -267,10 +284,7 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
267
284
|
if isinstance(cmd, str):
|
268
285
|
name = shlex.split(cmd)[0]
|
269
286
|
else:
|
270
|
-
if isinstance(cmd[0], os.PathLike)
|
271
|
-
name = Path(cmd[0]).name
|
272
|
-
else:
|
273
|
-
name = cmd[0]
|
287
|
+
name = Path(cmd[0]).name if isinstance(cmd[0], os.PathLike) else cmd[0]
|
274
288
|
|
275
289
|
with (self.path / f"log.{name}").open("ab") as stdout:
|
276
290
|
yield stdout, STDOUT
|
@@ -341,6 +355,15 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
341
355
|
) -> Generator[Any, None, None]:
|
342
356
|
yield self.run(["reconstructPar"], cpus=0, check=check, log=log)
|
343
357
|
|
358
|
+
def _prepare_calls(self, *, check: bool, log: bool) -> Generator[Any, None, None]:
|
359
|
+
script_path = self.__prepare_script()
|
360
|
+
|
361
|
+
if script_path is not None:
|
362
|
+
yield self.run([script_path], log=log, check=check)
|
363
|
+
|
364
|
+
elif (self.path / "system" / "blockMeshDict").is_file():
|
365
|
+
yield self.block_mesh(check=check, log=log)
|
366
|
+
|
344
367
|
def _run_calls(
|
345
368
|
self,
|
346
369
|
cmd: Optional[Union[Sequence[Union[str, "os.PathLike[str]"]], str]] = None,
|
@@ -406,12 +429,11 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
406
429
|
)
|
407
430
|
|
408
431
|
else:
|
432
|
+
yield self._prepare(check=check, log=log)
|
433
|
+
|
409
434
|
if not self and (self.path / "0.orig").is_dir():
|
410
435
|
yield self.restore_0_dir()
|
411
436
|
|
412
|
-
if (self.path / "system" / "blockMeshDict").is_file():
|
413
|
-
yield self.block_mesh(check=check)
|
414
|
-
|
415
437
|
if parallel is None:
|
416
438
|
parallel = (
|
417
439
|
(cpus is not None and cpus > 1)
|
@@ -1,7 +1,6 @@
|
|
1
|
-
import os
|
2
1
|
import shutil
|
3
2
|
import sys
|
4
|
-
from typing import Any, Optional, Union
|
3
|
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
5
4
|
|
6
5
|
if sys.version_info >= (3, 9):
|
7
6
|
from collections.abc import Sequence
|
@@ -11,6 +10,9 @@ else:
|
|
11
10
|
from ._async import AsyncFoamCase
|
12
11
|
from ._subprocess import run_async
|
13
12
|
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
import os
|
15
|
+
|
14
16
|
|
15
17
|
class AsyncSlurmFoamCase(AsyncFoamCase):
|
16
18
|
"""An asynchronous OpenFOAM case that launches jobs on a Slurm cluster."""
|
@@ -1,9 +1,11 @@
|
|
1
1
|
import asyncio
|
2
|
-
import os
|
3
2
|
import subprocess
|
4
3
|
import sys
|
5
4
|
from io import BytesIO
|
6
|
-
from typing import IO, Optional, Union
|
5
|
+
from typing import IO, TYPE_CHECKING, Optional, Union
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
import os
|
7
9
|
|
8
10
|
if sys.version_info >= (3, 9):
|
9
11
|
from collections.abc import Mapping, Sequence
|
@@ -18,7 +20,7 @@ class CalledProcessError(subprocess.CalledProcessError):
|
|
18
20
|
if self.stderr:
|
19
21
|
if isinstance(self.stderr, bytes):
|
20
22
|
return super().__str__() + "\n" + self.stderr.decode()
|
21
|
-
|
23
|
+
if isinstance(self.stderr, str):
|
22
24
|
return super().__str__() + "\n" + self.stderr
|
23
25
|
return super().__str__()
|
24
26
|
|
@@ -1,8 +1,7 @@
|
|
1
|
-
import os
|
2
1
|
import shutil
|
3
2
|
import sys
|
4
3
|
from types import TracebackType
|
5
|
-
from typing import Any, Callable, Optional, Type, Union, overload
|
4
|
+
from typing import TYPE_CHECKING, Any, Callable, Optional, Type, Union, overload
|
6
5
|
|
7
6
|
if sys.version_info >= (3, 9):
|
8
7
|
from collections.abc import Collection, Sequence
|
@@ -20,6 +19,9 @@ from ._run import FoamCaseRunBase
|
|
20
19
|
from ._subprocess import run_sync
|
21
20
|
from ._util import ValuedGenerator
|
22
21
|
|
22
|
+
if TYPE_CHECKING:
|
23
|
+
import os
|
24
|
+
|
23
25
|
|
24
26
|
class FoamCase(FoamCaseRunBase):
|
25
27
|
"""
|
@@ -44,8 +46,6 @@ class FoamCase(FoamCaseRunBase):
|
|
44
46
|
for _ in calls:
|
45
47
|
pass
|
46
48
|
|
47
|
-
print(calls.value)
|
48
|
-
|
49
49
|
return calls.value
|
50
50
|
|
51
51
|
@staticmethod
|
@@ -89,8 +89,7 @@ class FoamCase(FoamCaseRunBase):
|
|
89
89
|
ret = super().__getitem__(index)
|
90
90
|
if isinstance(ret, FoamCaseBase.TimeDirectory):
|
91
91
|
return FoamCase.TimeDirectory(ret)
|
92
|
-
|
93
|
-
return [FoamCase.TimeDirectory(r) for r in ret]
|
92
|
+
return [FoamCase.TimeDirectory(r) for r in ret]
|
94
93
|
|
95
94
|
def __enter__(self) -> Self:
|
96
95
|
return self
|
@@ -112,6 +111,10 @@ class FoamCase(FoamCaseRunBase):
|
|
112
111
|
for _ in self._clean_calls(check=check):
|
113
112
|
pass
|
114
113
|
|
114
|
+
def _prepare(self, *, check: bool = True, log: bool = True) -> None:
|
115
|
+
for _ in self._prepare_calls(check=check, log=log):
|
116
|
+
pass
|
117
|
+
|
115
118
|
def run(
|
116
119
|
self,
|
117
120
|
cmd: Optional[Union[Sequence[Union[str, "os.PathLike[str]"]], str]] = None,
|
@@ -1,17 +1,15 @@
|
|
1
1
|
import sys
|
2
2
|
from dataclasses import dataclass
|
3
|
-
from typing import Dict, NamedTuple, Optional, Tuple, Union
|
3
|
+
from typing import TYPE_CHECKING, Dict, NamedTuple, Optional, Tuple, Union
|
4
|
+
|
5
|
+
if TYPE_CHECKING:
|
6
|
+
import numpy as np
|
4
7
|
|
5
8
|
if sys.version_info >= (3, 9):
|
6
9
|
from collections.abc import Mapping, Sequence
|
7
10
|
else:
|
8
11
|
from typing import Mapping, Sequence
|
9
12
|
|
10
|
-
try:
|
11
|
-
import numpy as np
|
12
|
-
except ModuleNotFoundError:
|
13
|
-
pass
|
14
|
-
|
15
13
|
|
16
14
|
class FoamFileBase:
|
17
15
|
class DimensionSet(NamedTuple):
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import sys
|
2
|
-
from typing import Any, Optional, Tuple, Union, cast
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional, Tuple, Union, cast
|
3
3
|
|
4
4
|
if sys.version_info >= (3, 8):
|
5
5
|
from typing import Literal
|
@@ -16,10 +16,8 @@ from ._io import FoamFileIO
|
|
16
16
|
from ._serialization import Kind, dumpb
|
17
17
|
from ._util import is_sequence
|
18
18
|
|
19
|
-
|
19
|
+
if TYPE_CHECKING:
|
20
20
|
import numpy as np
|
21
|
-
except ModuleNotFoundError:
|
22
|
-
pass
|
23
21
|
|
24
22
|
|
25
23
|
class FoamFile(
|
@@ -86,7 +84,7 @@ class FoamFile(
|
|
86
84
|
|
87
85
|
def as_dict(self) -> FoamFileBase._Dict:
|
88
86
|
"""Return a nested dict representation of the dictionary."""
|
89
|
-
ret = self._file.as_dict()
|
87
|
+
ret = self._file.as_dict(include_header=True)
|
90
88
|
|
91
89
|
for k in self._keywords:
|
92
90
|
assert isinstance(ret, dict)
|
@@ -172,8 +170,7 @@ class FoamFile(
|
|
172
170
|
|
173
171
|
if value is ...:
|
174
172
|
return FoamFile.SubDict(self, keywords)
|
175
|
-
|
176
|
-
return value
|
173
|
+
return value
|
177
174
|
|
178
175
|
def __setitem__(
|
179
176
|
self, keywords: Optional[Union[str, Tuple[str, ...]]], data: "FoamFile._SetData"
|
@@ -294,15 +291,10 @@ class FoamFile(
|
|
294
291
|
|
295
292
|
def _iter(self, keywords: Tuple[str, ...] = ()) -> Iterator[Optional[str]]:
|
296
293
|
_, parsed = self._read()
|
297
|
-
|
298
|
-
yield from (
|
299
|
-
k[-1] if k else None
|
300
|
-
for k in parsed
|
301
|
-
if k != ("FoamFile",) and k[:-1] == keywords
|
302
|
-
)
|
294
|
+
yield from (k[-1] if k else None for k in parsed if k[:-1] == keywords)
|
303
295
|
|
304
296
|
def __iter__(self) -> Iterator[Optional[str]]:
|
305
|
-
|
297
|
+
yield from (k for k in self._iter() if k != "FoamFile")
|
306
298
|
|
307
299
|
def __contains__(self, keywords: object) -> bool:
|
308
300
|
if not keywords:
|
@@ -328,11 +320,16 @@ class FoamFile(
|
|
328
320
|
def __fspath__(self) -> str:
|
329
321
|
return str(self.path)
|
330
322
|
|
331
|
-
def as_dict(self) -> FoamFileBase._File:
|
332
|
-
"""
|
323
|
+
def as_dict(self, *, include_header: bool = False) -> FoamFileBase._File:
|
324
|
+
"""
|
325
|
+
Return a nested dict representation of the file.
|
326
|
+
|
327
|
+
:param include_header: Whether to include the "FoamFile" header in the output.
|
328
|
+
"""
|
333
329
|
_, parsed = self._read()
|
334
330
|
d = parsed.as_dict()
|
335
|
-
|
331
|
+
if not include_header:
|
332
|
+
d.pop("FoamFile", None)
|
336
333
|
return d
|
337
334
|
|
338
335
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
import gzip
|
2
|
-
import os
|
3
2
|
import sys
|
4
3
|
from copy import deepcopy
|
5
4
|
from pathlib import Path
|
6
5
|
from types import TracebackType
|
7
6
|
from typing import (
|
7
|
+
TYPE_CHECKING,
|
8
8
|
Optional,
|
9
9
|
Tuple,
|
10
10
|
Type,
|
@@ -18,6 +18,9 @@ else:
|
|
18
18
|
|
19
19
|
from ._parsing import Parsed
|
20
20
|
|
21
|
+
if TYPE_CHECKING:
|
22
|
+
import os
|
23
|
+
|
21
24
|
|
22
25
|
class FoamFileIO:
|
23
26
|
def __init__(self, path: Union["os.PathLike[str]", str]) -> None:
|
@@ -63,8 +66,7 @@ class FoamFileIO:
|
|
63
66
|
if self.__contents is None:
|
64
67
|
if missing_ok:
|
65
68
|
return b"", Parsed(b"")
|
66
|
-
|
67
|
-
raise FileNotFoundError(self.path)
|
69
|
+
raise FileNotFoundError(self.path)
|
68
70
|
|
69
71
|
if self.__parsed is None:
|
70
72
|
parsed = Parsed(self.__contents)
|
@@ -95,18 +95,35 @@ def _unpack_binary_field(
|
|
95
95
|
return [all]
|
96
96
|
|
97
97
|
|
98
|
+
_IDENTCHARS = identchars + "$"
|
99
|
+
_IDENTBODYCHARS = (
|
100
|
+
printables.replace(";", "")
|
101
|
+
.replace("{", "")
|
102
|
+
.replace("}", "")
|
103
|
+
.replace("[", "")
|
104
|
+
.replace("]", "")
|
105
|
+
)
|
106
|
+
|
98
107
|
_SWITCH = (
|
99
|
-
Keyword("yes"
|
108
|
+
Keyword("yes", _IDENTBODYCHARS)
|
109
|
+
| Keyword("true", _IDENTBODYCHARS)
|
110
|
+
| Keyword("on", _IDENTBODYCHARS)
|
111
|
+
| Keyword("y", _IDENTBODYCHARS)
|
112
|
+
| Keyword("t", _IDENTBODYCHARS)
|
100
113
|
).set_parse_action(lambda: True) | (
|
101
|
-
Keyword("no"
|
114
|
+
Keyword("no", _IDENTBODYCHARS)
|
115
|
+
| Keyword("false", _IDENTBODYCHARS)
|
116
|
+
| Keyword("off", _IDENTBODYCHARS)
|
117
|
+
| Keyword("n", _IDENTBODYCHARS)
|
118
|
+
| Keyword("f", _IDENTBODYCHARS)
|
102
119
|
).set_parse_action(lambda: False)
|
103
120
|
_DIMENSIONS = (
|
104
121
|
Literal("[").suppress() + common.number[0, 7] + Literal("]").suppress()
|
105
122
|
).set_parse_action(lambda tks: FoamFileBase.DimensionSet(*tks))
|
106
123
|
_TENSOR = _list_of(common.number) | common.number
|
107
124
|
_IDENTIFIER = Combine(
|
108
|
-
Word(
|
109
|
-
+ Opt(Literal("(") + Word(
|
125
|
+
Word(_IDENTCHARS, _IDENTBODYCHARS, exclude_chars="()")
|
126
|
+
+ Opt(Literal("(") + Word(_IDENTBODYCHARS, exclude_chars="()") + Literal(")"))
|
110
127
|
)
|
111
128
|
_DIMENSIONED = (Opt(_IDENTIFIER) + _DIMENSIONS + _TENSOR).set_parse_action(
|
112
129
|
lambda tks: FoamFileBase.Dimensioned(*reversed(tks.as_list()))
|
@@ -35,7 +35,7 @@ def dumpb(
|
|
35
35
|
if numpy and isinstance(data, np.ndarray):
|
36
36
|
return dumpb(data.tolist(), kind=kind)
|
37
37
|
|
38
|
-
|
38
|
+
if isinstance(data, Mapping):
|
39
39
|
entries = []
|
40
40
|
for k, v in data.items():
|
41
41
|
b = dumpb(v, kind=kind)
|
@@ -48,12 +48,12 @@ def dumpb(
|
|
48
48
|
|
49
49
|
return b" ".join(entries)
|
50
50
|
|
51
|
-
|
51
|
+
if isinstance(data, FoamFileBase.DimensionSet) or (
|
52
52
|
kind == Kind.DIMENSIONS and is_sequence(data) and len(data) == 7
|
53
53
|
):
|
54
54
|
return b"[" + b" ".join(dumpb(v) for v in data) + b"]"
|
55
55
|
|
56
|
-
|
56
|
+
if (kind == Kind.FIELD or kind == Kind.BINARY_FIELD) and (
|
57
57
|
isinstance(data, (int, float))
|
58
58
|
or is_sequence(data)
|
59
59
|
and data
|
@@ -62,7 +62,7 @@ def dumpb(
|
|
62
62
|
):
|
63
63
|
return b"uniform " + dumpb(data, kind=Kind.SINGLE_ENTRY)
|
64
64
|
|
65
|
-
|
65
|
+
if (kind == Kind.FIELD or kind == Kind.BINARY_FIELD) and is_sequence(data):
|
66
66
|
if isinstance(data[0], (int, float)):
|
67
67
|
tensor_kind = b"scalar"
|
68
68
|
elif len(data[0]) == 3:
|
@@ -88,10 +88,10 @@ def dumpb(
|
|
88
88
|
|
89
89
|
return b"nonuniform List<" + tensor_kind + b"> " + dumpb(len(data)) + contents
|
90
90
|
|
91
|
-
|
91
|
+
if kind != Kind.SINGLE_ENTRY and isinstance(data, tuple):
|
92
92
|
return b" ".join(dumpb(v) for v in data)
|
93
93
|
|
94
|
-
|
94
|
+
if isinstance(data, FoamFileBase.Dimensioned):
|
95
95
|
if data.name is not None:
|
96
96
|
return (
|
97
97
|
dumpb(data.name)
|
@@ -100,20 +100,18 @@ def dumpb(
|
|
100
100
|
+ b" "
|
101
101
|
+ dumpb(data.value, kind=Kind.SINGLE_ENTRY)
|
102
102
|
)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
)
|
103
|
+
return (
|
104
|
+
dumpb(data.dimensions, kind=Kind.DIMENSIONS)
|
105
|
+
+ b" "
|
106
|
+
+ dumpb(data.value, kind=Kind.SINGLE_ENTRY)
|
107
|
+
)
|
109
108
|
|
110
|
-
|
109
|
+
if is_sequence(data):
|
111
110
|
return b"(" + b" ".join(dumpb(v, kind=Kind.SINGLE_ENTRY) for v in data) + b")"
|
112
111
|
|
113
|
-
|
112
|
+
if data is True:
|
114
113
|
return b"yes"
|
115
|
-
|
114
|
+
if data is False:
|
116
115
|
return b"no"
|
117
116
|
|
118
|
-
|
119
|
-
return str(data).encode("latin-1")
|
117
|
+
return str(data).encode("latin-1")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.8
|
4
4
|
Summary: A Python interface for interacting with OpenFOAM
|
5
5
|
Author-email: "Gabriel S. Gerlero" <ggerlero@cimec.unl.edu.ar>
|
6
6
|
Project-URL: Homepage, https://github.com/gerlero/foamlib
|
@@ -30,6 +30,7 @@ Requires-Dist: aioshutil<2,>=1
|
|
30
30
|
Requires-Dist: pyparsing<4,>=3
|
31
31
|
Requires-Dist: typing-extensions<5,>=4; python_version < "3.11"
|
32
32
|
Provides-Extra: numpy
|
33
|
+
Requires-Dist: numpy<3,>=1.25.0; python_version >= "3.10" and extra == "numpy"
|
33
34
|
Requires-Dist: numpy<3,>=1; extra == "numpy"
|
34
35
|
Provides-Extra: lint
|
35
36
|
Requires-Dist: ruff; extra == "lint"
|
@@ -43,7 +44,7 @@ Requires-Dist: foamlib[test]; extra == "typing"
|
|
43
44
|
Requires-Dist: mypy<2,>=1; extra == "typing"
|
44
45
|
Provides-Extra: docs
|
45
46
|
Requires-Dist: foamlib[numpy]; extra == "docs"
|
46
|
-
Requires-Dist: sphinx<9,>=
|
47
|
+
Requires-Dist: sphinx<9,>=5; extra == "docs"
|
47
48
|
Requires-Dist: sphinx_rtd_theme; extra == "docs"
|
48
49
|
Provides-Extra: dev
|
49
50
|
Requires-Dist: foamlib[numpy]; extra == "dev"
|
@@ -52,38 +53,50 @@ Requires-Dist: foamlib[test]; extra == "dev"
|
|
52
53
|
Requires-Dist: foamlib[typing]; extra == "dev"
|
53
54
|
Requires-Dist: foamlib[docs]; extra == "dev"
|
54
55
|
|
55
|
-
[<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="
|
56
|
+
[<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="65">](https://github.com/gerlero/foamlib)
|
56
57
|
|
57
58
|
[](https://foamlib.readthedocs.io/)
|
58
59
|
[](https://github.com/gerlero/foamlib/actions/workflows/ci.yml)
|
59
60
|
[](https://codecov.io/gh/gerlero/foamlib)
|
60
61
|
[](http://mypy-lang.org/)
|
61
62
|
[](https://github.com/astral-sh/ruff)
|
63
|
+
[](https://github.com/astral-sh/uv)
|
64
|
+
[](https://github.com/gerlero/foamlib/actions/workflows/pypi-publish.yml)
|
62
65
|
[](https://pypi.org/project/foamlib/)
|
66
|
+
[](https://anaconda.org/conda-forge/foamlib)
|
63
67
|
[](https://pypi.org/project/foamlib/)
|
64
68
|

|
69
|
+
[](https://github.com/gerlero/foamlib/actions/workflows/docker.yml)
|
65
70
|
[](https://hub.docker.com/r/microfluidica/foamlib/)
|
66
71
|
|
72
|
+
## 👋 Basics
|
73
|
+
|
67
74
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
68
75
|
|
69
|
-
It offers the following classes:
|
76
|
+
It offers the following Python classes:
|
70
77
|
|
71
78
|
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/files.html#foamlib.FoamFile) (and [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/files.html#foamlib.FoamFieldFile)): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s, using `foamlib`'s own parser. Supports ASCII and binary field formats (with or without compression).
|
72
79
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.FoamCase): a class for configuring, running, and accessing the results of OpenFOAM cases.
|
73
80
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
74
81
|
* [`AsyncSlurmFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncSlurmFoamCase): subclass of `AsyncFoamCase` used for running cases on a Slurm cluster.
|
75
82
|
|
76
|
-
## Get started
|
83
|
+
## ☑️ Get started
|
77
84
|
|
78
|
-
### Install
|
85
|
+
### 📦 Install
|
79
86
|
|
80
|
-
|
87
|
+
* With [pip](https://pypi.org/project/pip/):
|
81
88
|
|
82
|
-
```bash
|
83
|
-
pip install foamlib
|
84
|
-
```
|
89
|
+
```bash
|
90
|
+
pip install foamlib
|
91
|
+
```
|
92
|
+
|
93
|
+
* With [conda](https://docs.conda.io/en/latest/):
|
94
|
+
|
95
|
+
```bash
|
96
|
+
conda install -c conda-forge foamlib
|
97
|
+
```
|
85
98
|
|
86
|
-
### Clone a case
|
99
|
+
### 🐑 Clone a case
|
87
100
|
|
88
101
|
```python
|
89
102
|
import os
|
@@ -95,13 +108,13 @@ pitz_tutorial = FoamCase(Path(os.environ["FOAM_TUTORIALS"]) / "incompressible/si
|
|
95
108
|
my_pitz = pitz_tutorial.clone("myPitz")
|
96
109
|
```
|
97
110
|
|
98
|
-
### Run the case
|
111
|
+
### 🏃 Run the case
|
99
112
|
|
100
113
|
```python
|
101
114
|
my_pitz.run()
|
102
115
|
```
|
103
116
|
|
104
|
-
### Access the results
|
117
|
+
### 🔎 Access the results
|
105
118
|
|
106
119
|
```python
|
107
120
|
latest_time = my_pitz[-1]
|
@@ -113,19 +126,19 @@ print(p.internal_field)
|
|
113
126
|
print(U.internal_field)
|
114
127
|
```
|
115
128
|
|
116
|
-
### Clean the case
|
129
|
+
### 🧹 Clean the case
|
117
130
|
|
118
131
|
```python
|
119
132
|
my_pitz.clean()
|
120
133
|
```
|
121
134
|
|
122
|
-
### Edit the `controlDict` file
|
135
|
+
### ⚙️ Edit the `controlDict` file
|
123
136
|
|
124
137
|
```python
|
125
138
|
my_pitz.control_dict["writeInterval"] = 10
|
126
139
|
```
|
127
140
|
|
128
|
-
### Make multiple file reads and writes in a single go
|
141
|
+
### 📝 Make multiple file reads and writes in a single go
|
129
142
|
|
130
143
|
```python
|
131
144
|
with my_pitz.fv_schemes as f:
|
@@ -133,7 +146,7 @@ with my_pitz.fv_schemes as f:
|
|
133
146
|
f["snGradSchemes"]["default"] = "uncorrected"
|
134
147
|
```
|
135
148
|
|
136
|
-
### Run a case asynchronously
|
149
|
+
### ⏳ Run a case asynchronously
|
137
150
|
|
138
151
|
```python
|
139
152
|
import asyncio
|
@@ -146,7 +159,7 @@ async def run_case():
|
|
146
159
|
asyncio.run(run_case())
|
147
160
|
```
|
148
161
|
|
149
|
-
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
162
|
+
### 🔢 Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
150
163
|
|
151
164
|
```python
|
152
165
|
from foamlib import FoamFieldFile
|
@@ -156,7 +169,7 @@ U = FoamFieldFile(Path(my_pitz) / "0/U")
|
|
156
169
|
print(U.internal_field)
|
157
170
|
```
|
158
171
|
|
159
|
-
### Run an optimization loop in parallel
|
172
|
+
### 🔁 Run an optimization loop in parallel
|
160
173
|
|
161
174
|
```python
|
162
175
|
import os
|
@@ -176,7 +189,7 @@ async def cost(x):
|
|
176
189
|
result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
|
177
190
|
```
|
178
191
|
|
179
|
-
### Use it to create a `run` (or `clean`) script
|
192
|
+
### 📄 Use it to create a `run` (or `clean`) script
|
180
193
|
|
181
194
|
```python
|
182
195
|
#!/usr/bin/env python3
|
@@ -188,6 +201,6 @@ case = FoamCase(Path(__file__).parent)
|
|
188
201
|
case.run()
|
189
202
|
```
|
190
203
|
|
191
|
-
## Documentation
|
204
|
+
## 📘 Documentation
|
192
205
|
|
193
206
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -13,7 +13,7 @@ foamlib[docs]
|
|
13
13
|
|
14
14
|
[docs]
|
15
15
|
foamlib[numpy]
|
16
|
-
sphinx<9,>=
|
16
|
+
sphinx<9,>=5
|
17
17
|
sphinx_rtd_theme
|
18
18
|
|
19
19
|
[lint]
|
@@ -22,6 +22,9 @@ ruff
|
|
22
22
|
[numpy]
|
23
23
|
numpy<3,>=1
|
24
24
|
|
25
|
+
[numpy:python_version >= "3.10"]
|
26
|
+
numpy<3,>=1.25.0
|
27
|
+
|
25
28
|
[test]
|
26
29
|
foamlib[numpy]
|
27
30
|
pytest<9,>=7
|
@@ -37,7 +37,10 @@ dependencies = [
|
|
37
37
|
dynamic = ["version"]
|
38
38
|
|
39
39
|
[project.optional-dependencies]
|
40
|
-
numpy = [
|
40
|
+
numpy = [
|
41
|
+
"numpy>=1.25.0,<3; python_version>='3.10'",
|
42
|
+
"numpy>=1,<3"
|
43
|
+
]
|
41
44
|
lint = ["ruff"]
|
42
45
|
test = [
|
43
46
|
"foamlib[numpy]",
|
@@ -51,7 +54,7 @@ typing = [
|
|
51
54
|
]
|
52
55
|
docs = [
|
53
56
|
"foamlib[numpy]",
|
54
|
-
"sphinx>=
|
57
|
+
"sphinx>=5,<9",
|
55
58
|
"sphinx_rtd_theme",
|
56
59
|
]
|
57
60
|
dev = [
|
@@ -84,7 +87,36 @@ packages = [
|
|
84
87
|
strict = true
|
85
88
|
|
86
89
|
[tool.ruff.lint]
|
87
|
-
extend-select = [
|
90
|
+
extend-select = [
|
91
|
+
"ASYNC",
|
92
|
+
"B",
|
93
|
+
"C4",
|
94
|
+
"D",
|
95
|
+
"ERA",
|
96
|
+
"F",
|
97
|
+
"FLY",
|
98
|
+
"FURB",
|
99
|
+
"I",
|
100
|
+
"ICN",
|
101
|
+
"INT",
|
102
|
+
"NPY",
|
103
|
+
"PERF",
|
104
|
+
"PIE",
|
105
|
+
"PLC",
|
106
|
+
"PLE",
|
107
|
+
"PLW",
|
108
|
+
"PT",
|
109
|
+
"PTH",
|
110
|
+
"Q",
|
111
|
+
"RET",
|
112
|
+
"RSE",
|
113
|
+
"RUF",
|
114
|
+
"SIM",
|
115
|
+
"T20",
|
116
|
+
"TCH",
|
117
|
+
"UP",
|
118
|
+
"YTT",
|
119
|
+
]
|
88
120
|
|
89
121
|
[tool.ruff.lint.pydocstyle]
|
90
122
|
convention = "pep257"
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|