foamlib 0.8.7__tar.gz → 0.8.9__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.
Files changed (64) hide show
  1. {foamlib-0.8.7 → foamlib-0.8.9}/.github/workflows/ci.yml +5 -5
  2. {foamlib-0.8.7 → foamlib-0.8.9}/.github/workflows/pypi-publish.yml +1 -1
  3. foamlib-0.8.9/CONTRIBUTING.md +93 -0
  4. {foamlib-0.8.7 → foamlib-0.8.9}/PKG-INFO +179 -13
  5. foamlib-0.8.9/README.md +316 -0
  6. foamlib-0.8.9/benchmark/benchmark.py +17 -0
  7. foamlib-0.8.9/benchmark/requirements.txt +2 -0
  8. foamlib-0.8.9/benchmark/ruff.toml +4 -0
  9. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/__init__.py +1 -1
  10. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_async.py +93 -12
  11. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_base.py +21 -5
  12. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_run.py +17 -12
  13. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_slurm.py +10 -1
  14. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_sync.py +94 -12
  15. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_files/_files.py +110 -16
  16. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_files/_parsing.py +8 -4
  17. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_files/_serialization.py +20 -8
  18. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_files/_types.py +43 -17
  19. {foamlib-0.8.7 → foamlib-0.8.9}/pyproject.toml +14 -7
  20. foamlib-0.8.9/tests/test_example.py +154 -0
  21. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_files/test_files.py +6 -1
  22. foamlib-0.8.9/tests/test_files/test_parsing/__init__.py +0 -0
  23. foamlib-0.8.9/tests/test_files/test_parsing/test_advanced.py +364 -0
  24. foamlib-0.8.7/tests/test_files/test_parsing.py → foamlib-0.8.9/tests/test_files/test_parsing/test_basic.py +1 -0
  25. foamlib-0.8.9/tests/test_files/test_parsing/test_decompose_par.py +74 -0
  26. foamlib-0.8.9/tests/test_files/test_parsing/test_fields.py +302 -0
  27. foamlib-0.8.9/tests/test_files/test_parsing/test_fv_schemes.py +72 -0
  28. foamlib-0.8.9/tests/test_files/test_parsing/test_intermediate.py +718 -0
  29. foamlib-0.8.9/tests/test_files/test_parsing/test_poly_mesh.py +66 -0
  30. foamlib-0.8.7/README.md +0 -156
  31. {foamlib-0.8.7 → foamlib-0.8.9}/.devcontainer.json +0 -0
  32. {foamlib-0.8.7 → foamlib-0.8.9}/.dockerignore +0 -0
  33. {foamlib-0.8.7 → foamlib-0.8.9}/.git-blame-ignore-revs +0 -0
  34. {foamlib-0.8.7 → foamlib-0.8.9}/.github/dependabot.yml +0 -0
  35. {foamlib-0.8.7 → foamlib-0.8.9}/.github/workflows/docker.yml +0 -0
  36. {foamlib-0.8.7 → foamlib-0.8.9}/.github/workflows/dockerhub-description.yml +0 -0
  37. {foamlib-0.8.7 → foamlib-0.8.9}/.gitignore +0 -0
  38. {foamlib-0.8.7 → foamlib-0.8.9}/.readthedocs.yaml +0 -0
  39. {foamlib-0.8.7 → foamlib-0.8.9}/Dockerfile +0 -0
  40. {foamlib-0.8.7 → foamlib-0.8.9}/LICENSE.txt +0 -0
  41. {foamlib-0.8.7 → foamlib-0.8.9/benchmark}/benchmark.png +0 -0
  42. {foamlib-0.8.7 → foamlib-0.8.9}/docs/Makefile +0 -0
  43. {foamlib-0.8.7 → foamlib-0.8.9}/docs/cases.rst +0 -0
  44. {foamlib-0.8.7 → foamlib-0.8.9}/docs/conf.py +0 -0
  45. {foamlib-0.8.7 → foamlib-0.8.9}/docs/files.rst +0 -0
  46. {foamlib-0.8.7 → foamlib-0.8.9}/docs/index.rst +0 -0
  47. {foamlib-0.8.7 → foamlib-0.8.9}/docs/make.bat +0 -0
  48. {foamlib-0.8.7 → foamlib-0.8.9}/docs/ruff.toml +0 -0
  49. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/__init__.py +0 -0
  50. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_subprocess.py +0 -0
  51. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_cases/_util.py +0 -0
  52. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_files/__init__.py +0 -0
  53. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/_files/_io.py +0 -0
  54. {foamlib-0.8.7 → foamlib-0.8.9}/foamlib/py.typed +0 -0
  55. {foamlib-0.8.7 → foamlib-0.8.9}/logo.png +0 -0
  56. {foamlib-0.8.7 → foamlib-0.8.9}/tests/__init__.py +0 -0
  57. {foamlib-0.8.7 → foamlib-0.8.9}/tests/ruff.toml +0 -0
  58. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_cases/__init__.py +0 -0
  59. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_cases/test_cavity.py +0 -0
  60. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_cases/test_cavity_async.py +0 -0
  61. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_cases/test_flange.py +0 -0
  62. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_cases/test_flange_async.py +0 -0
  63. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_files/__init__.py +0 -0
  64. {foamlib-0.8.7 → foamlib-0.8.9}/tests/test_files/test_dumps.py +0 -0
@@ -28,14 +28,14 @@ jobs:
28
28
  - name: Checkout
29
29
  uses: actions/checkout@v4
30
30
  - name: Install uv
31
- uses: astral-sh/setup-uv@v5
31
+ uses: astral-sh/setup-uv@v6
32
32
  - name: Set up Python
33
33
  uses: actions/setup-python@v5
34
34
  with:
35
35
  python-version-file: pyproject.toml
36
36
  - name: Check types with mypy
37
37
  run: |
38
- uv run --extra typing mypy
38
+ uv run mypy
39
39
 
40
40
  test:
41
41
  runs-on: ubuntu-22.04
@@ -74,7 +74,7 @@ jobs:
74
74
  with:
75
75
  openfoam-version: ${{ matrix.openfoam-version }}
76
76
  - name: Install uv
77
- uses: astral-sh/setup-uv@v5
77
+ uses: astral-sh/setup-uv@v6
78
78
  - name: Set up Python ${{ matrix.python-version }}
79
79
  uses: actions/setup-python@v5
80
80
  with:
@@ -84,7 +84,7 @@ jobs:
84
84
  uses: koesterlab/setup-slurm-action@v1
85
85
  - name: Install test dependencies
86
86
  run: |
87
- uv sync --extra test
87
+ uv sync
88
88
  - name: Test with pytest
89
89
  run: |
90
90
  uv run pytest --cov=foamlib --cov-report xml
@@ -103,7 +103,7 @@ jobs:
103
103
  - name: Checkout
104
104
  uses: actions/checkout@v4
105
105
  - name: Install uv
106
- uses: astral-sh/setup-uv@v5
106
+ uses: astral-sh/setup-uv@v6
107
107
  - name: Check package build
108
108
  run: |
109
109
  uv build
@@ -17,7 +17,7 @@ jobs:
17
17
  - name: Checkout
18
18
  uses: actions/checkout@v4
19
19
  - name: Install uv
20
- uses: astral-sh/setup-uv@v5
20
+ uses: astral-sh/setup-uv@v6
21
21
  - name: Build
22
22
  run: uv build
23
23
  - name: Publish to PyPI
@@ -0,0 +1,93 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ 1. [Fork the repository on GitHub](https://github.com/gerlero/foamlib/fork)
6
+
7
+ 1. Clone your fork locally
8
+
9
+ ```bash
10
+ git clone https://github.com/<your_username>/foamlib.git
11
+ ```
12
+
13
+ 2. Install the project in editable mode in a virtual environment
14
+
15
+ ```bash
16
+ cd foamlib
17
+ python3 -m venv .venv
18
+ source .venv/bin/activate
19
+ pip install -e .[dev]
20
+ ```
21
+
22
+ ## Contributing changes via a pull request
23
+
24
+ 1. Create a new branch for your changes
25
+
26
+ ```bash
27
+ git checkout -b my-new-feature
28
+ ```
29
+
30
+ 2. Make your changes
31
+
32
+ 3. Test your changes (see below for instructions)
33
+
34
+ 4. Commit your changes
35
+
36
+ ```bash
37
+ git add .
38
+ git commit -m "Add some feature"
39
+ ```
40
+
41
+ 5. Push your changes to your fork
42
+
43
+ ```bash
44
+ git push origin my-new-feature
45
+ ```
46
+
47
+ 6. [Open a pull request on GitHub](https://github.com/gerlero/foamlib/compare)
48
+
49
+
50
+ ## Checks
51
+
52
+ The following checks will be run by the CI pipeline, so it is recommended to run them locally before opening a pull request.
53
+
54
+ ### Testing
55
+
56
+ Run the tests with:
57
+
58
+ ```bash
59
+ pytest
60
+ ```
61
+
62
+ ### Type checking
63
+
64
+ Type check the code with:
65
+
66
+ ```bash
67
+ mypy
68
+ ```
69
+
70
+ ### Linting
71
+
72
+ Lint the code with:
73
+
74
+ ```bash
75
+ ruff check
76
+ ```
77
+
78
+ ### Formatting
79
+
80
+ Format the code with:
81
+
82
+ ```bash
83
+ ruff format
84
+ ```
85
+
86
+ ### Documentation
87
+
88
+ Generate the documentation locally with:
89
+
90
+ ```bash
91
+ cd docs
92
+ make html
93
+ ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: foamlib
3
- Version: 0.8.7
3
+ Version: 0.8.9
4
4
  Summary: A Python interface for interacting with OpenFOAM
5
5
  Project-URL: Homepage, https://github.com/gerlero/foamlib
6
6
  Project-URL: Repository, https://github.com/gerlero/foamlib
@@ -27,32 +27,38 @@ Classifier: Typing :: Typed
27
27
  Requires-Python: >=3.7
28
28
  Requires-Dist: aioshutil<2,>=1
29
29
  Requires-Dist: numpy<3,>=1
30
- Requires-Dist: numpy<3,>=1.25.0; python_version >= '3.10'
31
30
  Requires-Dist: pyparsing<4,>=3.1.2
32
- Requires-Dist: rich<14,>=13
31
+ Requires-Dist: rich<15,>=13
33
32
  Requires-Dist: typing-extensions<5,>=4; python_version < '3.11'
34
33
  Provides-Extra: dev
35
34
  Requires-Dist: mypy<2,>=1; extra == 'dev'
36
- Requires-Dist: pytest-asyncio<0.26,>=0.21; extra == 'dev'
35
+ Requires-Dist: pytest-asyncio<0.27,>=0.21; extra == 'dev'
37
36
  Requires-Dist: pytest-cov; extra == 'dev'
38
37
  Requires-Dist: pytest<9,>=7; extra == 'dev'
39
38
  Requires-Dist: ruff; extra == 'dev'
39
+ Requires-Dist: scipy-stubs; (python_version >= '3.10') and extra == 'dev'
40
+ Requires-Dist: scipy<2,>=1; extra == 'dev'
40
41
  Requires-Dist: sphinx-rtd-theme; extra == 'dev'
41
42
  Requires-Dist: sphinx<9,>=5; extra == 'dev'
42
43
  Provides-Extra: docs
44
+ Requires-Dist: ruff; extra == 'docs'
43
45
  Requires-Dist: sphinx-rtd-theme; extra == 'docs'
44
46
  Requires-Dist: sphinx<9,>=5; extra == 'docs'
45
47
  Provides-Extra: lint
46
48
  Requires-Dist: ruff; extra == 'lint'
47
49
  Provides-Extra: test
48
- Requires-Dist: pytest-asyncio<0.26,>=0.21; extra == 'test'
50
+ Requires-Dist: mypy<2,>=1; extra == 'test'
51
+ Requires-Dist: pytest-asyncio<0.27,>=0.21; extra == 'test'
49
52
  Requires-Dist: pytest-cov; extra == 'test'
50
53
  Requires-Dist: pytest<9,>=7; extra == 'test'
54
+ Requires-Dist: scipy<2,>=1; extra == 'test'
51
55
  Provides-Extra: typing
52
56
  Requires-Dist: mypy<2,>=1; extra == 'typing'
53
- Requires-Dist: pytest-asyncio<0.26,>=0.21; extra == 'typing'
57
+ Requires-Dist: pytest-asyncio<0.27,>=0.21; extra == 'typing'
54
58
  Requires-Dist: pytest-cov; extra == 'typing'
55
59
  Requires-Dist: pytest<9,>=7; extra == 'typing'
60
+ Requires-Dist: scipy-stubs; (python_version >= '3.10') and extra == 'typing'
61
+ Requires-Dist: scipy<2,>=1; extra == 'typing'
56
62
  Description-Content-Type: text/markdown
57
63
 
58
64
  [<img alt="foamlib" src="https://github.com/gerlero/foamlib/raw/main/logo.png" height="65">](https://github.com/gerlero/foamlib)
@@ -73,11 +79,18 @@ Description-Content-Type: text/markdown
73
79
 
74
80
  **foamlib** provides a simple, modern, ergonomic and fast Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
75
81
 
76
- <p align="center">
77
- <img alt="benchmark" src="https://github.com/gerlero/foamlib/raw/main/benchmark.png" height="250">
78
- <br>
79
- <i>Parsing a </i>volVectorField<i> with 200k cells.</i>
80
- </p>
82
+ <div align="center">
83
+ <img alt="benchmark" src="https://github.com/gerlero/foamlib/raw/main/benchmark/benchmark.png" height="250">
84
+
85
+ Parsing a volVectorField with 200k cells.<sup>[1](#benchmark)</sup>
86
+ </div>
87
+
88
+
89
+ ## 🚀 Introduction
90
+
91
+ **foamlib** is a Python package designed to simplify the manipulation of OpenFOAM cases and files. Its standalone parser makes it easy to work with OpenFOAM’s input/output files from Python, while its case-handling capabilities facilitate various execution workflows—reducing boilerplate code and enabling efficient Python-based pre- and post-processing, as well as simulation management.
92
+
93
+ Compared to [PyFoam](https://openfoamwiki.net/index.php/Contrib/PyFoam) and other similar tools like [fluidfoam](https://github.com/fluiddyn/fluidfoam), [fluidsimfoam](https://foss.heptapod.net/fluiddyn/fluidsimfoam), and [Ofpp](https://github.com/xu-xianghua/ofpp), **foamlib** offers advantages such as modern Python compatibility, support for binary-formatted fields, a fully type-hinted API, and asynchronous operations; making OpenFOAM workflows more accessible and streamlined.
81
94
 
82
95
  ## 👋 Basics
83
96
 
@@ -208,6 +221,159 @@ case = FoamCase(Path(__file__).parent)
208
221
  case.run()
209
222
  ```
210
223
 
211
- ## 📘 Documentation
224
+ ## ▶️ A complete example
225
+
226
+ The following is a fully self-contained example that demonstrates how to create an OpenFOAM case from scratch, run it, and analyze the results.
227
+
228
+ <details>
229
+
230
+ <summary>Example</summary>
231
+
232
+ ```python
233
+ #!/usr/bin/env python3
234
+ """Check the diffusion of a scalar field in a scalarTransportFoam case."""
235
+
236
+ import shutil
237
+ from pathlib import Path
238
+
239
+ import numpy as np
240
+ from scipy.special import erfc
241
+ from foamlib import FoamCase
242
+
243
+ path = Path(__file__).parent / "diffusionCheck"
244
+ shutil.rmtree(path, ignore_errors=True)
245
+ path.mkdir(parents=True)
246
+ (path / "system").mkdir()
247
+ (path / "constant").mkdir()
248
+ (path / "0").mkdir()
249
+
250
+ case = FoamCase(path)
251
+
252
+ with case.control_dict as f:
253
+ f["application"] = "scalarTransportFoam"
254
+ f["startFrom"] = "latestTime"
255
+ f["stopAt"] = "endTime"
256
+ f["endTime"] = 5
257
+ f["deltaT"] = 1e-3
258
+ f["writeControl"] = "adjustableRunTime"
259
+ f["writeInterval"] = 1
260
+ f["purgeWrite"] = 0
261
+ f["writeFormat"] = "ascii"
262
+ f["writePrecision"] = 6
263
+ f["writeCompression"] = False
264
+ f["timeFormat"] = "general"
265
+ f["timePrecision"] = 6
266
+ f["adjustTimeStep"] = False
267
+ f["runTimeModifiable"] = False
268
+
269
+ with case.fv_schemes as f:
270
+ f["ddtSchemes"] = {"default": "Euler"}
271
+ f["gradSchemes"] = {"default": "Gauss linear"}
272
+ f["divSchemes"] = {"default": "none", "div(phi,U)": "Gauss linear", "div(phi,T)": "Gauss linear"}
273
+ f["laplacianSchemes"] = {"default": "Gauss linear corrected"}
274
+
275
+ with case.fv_solution as f:
276
+ f["solvers"] = {"T": {"solver": "PBiCG", "preconditioner": "DILU", "tolerance": 1e-6, "relTol": 0}}
277
+
278
+ with case.block_mesh_dict as f:
279
+ f["scale"] = 1
280
+ f["vertices"] = [
281
+ [0, 0, 0],
282
+ [1, 0, 0],
283
+ [1, 0.5, 0],
284
+ [1, 1, 0],
285
+ [0, 1, 0],
286
+ [0, 0.5, 0],
287
+ [0, 0, 0.1],
288
+ [1, 0, 0.1],
289
+ [1, 0.5, 0.1],
290
+ [1, 1, 0.1],
291
+ [0, 1, 0.1],
292
+ [0, 0.5, 0.1],
293
+ ]
294
+ f["blocks"] = [
295
+ "hex", [0, 1, 2, 5, 6, 7, 8, 11], [400, 20, 1], "simpleGrading", [1, 1, 1],
296
+ "hex", [5, 2, 3, 4, 11, 8, 9, 10], [400, 20, 1], "simpleGrading", [1, 1, 1],
297
+ ]
298
+ f["edges"] = []
299
+ f["boundary"] = [
300
+ ("inletUp", {"type": "patch", "faces": [[5, 4, 10, 11]]}),
301
+ ("inletDown", {"type": "patch", "faces": [[0, 5, 11, 6]]}),
302
+ ("outletUp", {"type": "patch", "faces": [[2, 3, 9, 8]]}),
303
+ ("outletDown", {"type": "patch", "faces": [[1, 2, 8, 7]]}),
304
+ ("walls", {"type": "wall", "faces": [[4, 3, 9, 10], [0, 1, 7, 6]]}),
305
+ ("frontAndBack", {"type": "empty", "faces": [[0, 1, 2, 5], [5, 2, 3, 4], [6, 7, 8, 11], [11, 8, 9, 10]]}),
306
+ ]
307
+ f["mergePatchPairs"] = []
308
+
309
+ with case.transport_properties as f:
310
+ f["DT"] = f.Dimensioned(1e-3, f.DimensionSet(length=2, time=-1), "DT")
311
+
312
+ with case[0]["U"] as f:
313
+ f.dimensions = f.DimensionSet(length=1, time=-1)
314
+ f.internal_field = [1, 0, 0]
315
+ f.boundary_field = {
316
+ "inletUp": {"type": "fixedValue", "value": [1, 0, 0]},
317
+ "inletDown": {"type": "fixedValue", "value": [1, 0, 0]},
318
+ "outletUp": {"type": "zeroGradient"},
319
+ "outletDown": {"type": "zeroGradient"},
320
+ "walls": {"type": "zeroGradient"},
321
+ "frontAndBack": {"type": "empty"},
322
+ }
323
+
324
+ with case[0]["T"] as f:
325
+ f.dimensions = f.DimensionSet(temperature=1)
326
+ f.internal_field = 0
327
+ f.boundary_field = {
328
+ "inletUp": {"type": "fixedValue", "value": 0},
329
+ "inletDown": {"type": "fixedValue", "value": 1},
330
+ "outletUp": {"type": "zeroGradient"},
331
+ "outletDown": {"type": "zeroGradient"},
332
+ "walls": {"type": "zeroGradient"},
333
+ "frontAndBack": {"type": "empty"},
334
+ }
335
+
336
+ case.run()
337
+
338
+ x, y, z = case[0].cell_centers().internal_field.T
339
+
340
+ end = x == x.max()
341
+ x = x[end]
342
+ y = y[end]
343
+ z = z[end]
344
+
345
+ DT = case.transport_properties["DT"].value
346
+ U = case[0]["U"].internal_field[0]
347
+
348
+ for time in case[1:]:
349
+ if U*time.time < 2*x.max():
350
+ continue
351
+
352
+ T = time["T"].internal_field[end]
353
+ analytical = 0.5 * erfc((y - 0.5) / np.sqrt(4 * DT * x/U))
354
+ if np.allclose(T, analytical, atol=0.1):
355
+ print(f"Time {time.time}: OK")
356
+ else:
357
+ raise RuntimeError(f"Time {time.time}: {T} != {analytical}")
358
+ ```
359
+
360
+ </details>
361
+
362
+
363
+ ## 📘 API documentation
364
+
365
+ For more information on how to use **foamlibs**'s classes and methods, check out the [documentation](https://foamlib.readthedocs.io/).
366
+
367
+ ## 🙋 Support
368
+
369
+ If you have any questions or need help, feel free to open a [discussion](https://github.com/gerlero/foamlib/discussions).
370
+
371
+ If you believe you have found a bug in **foamlib**, please open an [issue](https://github.com/gerlero/foamlib/issues).
372
+
373
+ ## 🧑‍💻 Contributing
374
+
375
+ You're welcome to contribute to **foamlib**! Check out the [contributing guidelines](CONTRIBUTING.md) for more information.
376
+
377
+ ## Footnotes
212
378
 
213
- For more information, check out the [documentation](https://foamlib.readthedocs.io/).
379
+ <a id="benchmark">[1]</a> foamlib 0.8.1 vs PyFoam 2023.7 on a MacBook Air (2020, M1) with 8 GB of RAM. [Benchmark script](benchmark/benchmark.py).