foamlib 0.6.3__py3-none-any.whl → 0.6.5__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.
- foamlib/__init__.py +4 -2
- foamlib/_cases/__init__.py +2 -0
- foamlib/_cases/_async.py +9 -6
- foamlib/_cases/_run.py +36 -5
- foamlib/_cases/_slurm.py +69 -0
- foamlib/_cases/_sync.py +15 -12
- foamlib/_files/_files.py +2 -4
- {foamlib-0.6.3.dist-info → foamlib-0.6.5.dist-info}/METADATA +14 -2
- {foamlib-0.6.3.dist-info → foamlib-0.6.5.dist-info}/RECORD +12 -11
- {foamlib-0.6.3.dist-info → foamlib-0.6.5.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.6.3.dist-info → foamlib-0.6.5.dist-info}/WHEEL +0 -0
- {foamlib-0.6.3.dist-info → foamlib-0.6.5.dist-info}/top_level.txt +0 -0
foamlib/__init__.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
"""A Python interface for interacting with OpenFOAM."""
|
2
2
|
|
3
|
-
__version__ = "0.6.
|
3
|
+
__version__ = "0.6.5"
|
4
4
|
|
5
5
|
from ._cases import (
|
6
6
|
AsyncFoamCase,
|
7
|
+
AsyncSlurmFoamCase,
|
7
8
|
CalledProcessError,
|
8
9
|
FoamCase,
|
9
10
|
FoamCaseBase,
|
@@ -13,11 +14,12 @@ from ._files import FoamFieldFile, FoamFile, FoamFileBase
|
|
13
14
|
|
14
15
|
__all__ = [
|
15
16
|
"AsyncFoamCase",
|
17
|
+
"AsyncSlurmFoamCase",
|
16
18
|
"CalledProcessError",
|
17
19
|
"FoamFile",
|
18
20
|
"FoamCase",
|
21
|
+
"FoamCaseBase",
|
19
22
|
"FoamCaseRunBase",
|
20
23
|
"FoamFieldFile",
|
21
|
-
"FoamCaseBase",
|
22
24
|
"FoamFileBase",
|
23
25
|
]
|
foamlib/_cases/__init__.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from ._async import AsyncFoamCase
|
2
2
|
from ._base import FoamCaseBase
|
3
3
|
from ._run import FoamCaseRunBase
|
4
|
+
from ._slurm import AsyncSlurmFoamCase
|
4
5
|
from ._subprocess import CalledProcessError
|
5
6
|
from ._sync import FoamCase
|
6
7
|
|
@@ -8,6 +9,7 @@ __all__ = [
|
|
8
9
|
"AsyncFoamCase",
|
9
10
|
"FoamCaseBase",
|
10
11
|
"FoamCaseRunBase",
|
12
|
+
"AsyncSlurmFoamCase",
|
11
13
|
"CalledProcessError",
|
12
14
|
"FoamCase",
|
13
15
|
]
|
foamlib/_cases/_async.py
CHANGED
@@ -164,17 +164,20 @@ class AsyncFoamCase(FoamCaseRunBase):
|
|
164
164
|
):
|
165
165
|
await coro
|
166
166
|
|
167
|
-
async def block_mesh(self, *, check: bool = True) -> None:
|
167
|
+
async def block_mesh(self, *, check: bool = True, log: bool = True) -> None:
|
168
168
|
"""Run blockMesh on this case."""
|
169
|
-
|
169
|
+
for coro in self._block_mesh_calls(check=check, log=log):
|
170
|
+
await coro
|
170
171
|
|
171
|
-
async def decompose_par(self, *, check: bool = True) -> None:
|
172
|
+
async def decompose_par(self, *, check: bool = True, log: bool = True) -> None:
|
172
173
|
"""Decompose this case for parallel running."""
|
173
|
-
|
174
|
+
for coro in self._decompose_par_calls(check=check, log=log):
|
175
|
+
await coro
|
174
176
|
|
175
|
-
async def reconstruct_par(self, *, check: bool = True) -> None:
|
177
|
+
async def reconstruct_par(self, *, check: bool = True, log: bool = True) -> None:
|
176
178
|
"""Reconstruct this case after parallel running."""
|
177
|
-
|
179
|
+
for coro in self._reconstruct_par_calls(check=check, log=log):
|
180
|
+
await coro
|
178
181
|
|
179
182
|
async def restore_0_dir(self) -> None:
|
180
183
|
"""Restore the 0 directory from the 0.orig directory."""
|
foamlib/_cases/_run.py
CHANGED
@@ -63,7 +63,9 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
63
63
|
|
64
64
|
if ret not in self:
|
65
65
|
yield self._case.run(
|
66
|
-
["postProcess", "-func", "writeCellCentres", "-time", self.name]
|
66
|
+
["postProcess", "-func", "writeCellCentres", "-time", self.name],
|
67
|
+
cpus=0,
|
68
|
+
log=False,
|
67
69
|
)
|
68
70
|
|
69
71
|
return ret
|
@@ -127,13 +129,19 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
127
129
|
|
128
130
|
@abstractmethod
|
129
131
|
def block_mesh(
|
130
|
-
self, *, check: bool = True
|
132
|
+
self, *, check: bool = True, log: bool = True
|
131
133
|
) -> Union[None, Coroutine[None, None, None]]:
|
132
134
|
raise NotImplementedError
|
133
135
|
|
134
136
|
@abstractmethod
|
135
137
|
def decompose_par(
|
136
|
-
self, *, check: bool = True
|
138
|
+
self, *, check: bool = True, log: bool = True
|
139
|
+
) -> Union[None, Coroutine[None, None, None]]:
|
140
|
+
raise NotImplementedError
|
141
|
+
|
142
|
+
@abstractmethod
|
143
|
+
def reconstruct_par(
|
144
|
+
self, *, check: bool = True, log: bool = True
|
137
145
|
) -> Union[None, Coroutine[None, None, None]]:
|
138
146
|
raise NotImplementedError
|
139
147
|
|
@@ -318,6 +326,21 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
318
326
|
yield self._rmtree(self.path / "0", ignore_errors=True)
|
319
327
|
yield self._copytree(self.path / "0.orig", self.path / "0", symlinks=True)
|
320
328
|
|
329
|
+
def _block_mesh_calls(
|
330
|
+
self, *, check: bool, log: bool
|
331
|
+
) -> Generator[Any, None, None]:
|
332
|
+
yield self.run(["blockMesh"], cpus=0, check=check, log=log)
|
333
|
+
|
334
|
+
def _decompose_par_calls(
|
335
|
+
self, *, check: bool, log: bool
|
336
|
+
) -> Generator[Any, None, None]:
|
337
|
+
yield self.run(["decomposePar"], cpus=0, check=check, log=log)
|
338
|
+
|
339
|
+
def _reconstruct_par_calls(
|
340
|
+
self, *, check: bool, log: bool
|
341
|
+
) -> Generator[Any, None, None]:
|
342
|
+
yield self.run(["reconstructPar"], cpus=0, check=check, log=log)
|
343
|
+
|
321
344
|
def _run_calls(
|
322
345
|
self,
|
323
346
|
cmd: Optional[Union[Sequence[Union[str, "os.PathLike[str]"]], str]] = None,
|
@@ -326,6 +349,7 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
326
349
|
cpus: Optional[int],
|
327
350
|
check: bool,
|
328
351
|
log: bool,
|
352
|
+
**kwargs: Any,
|
329
353
|
) -> Generator[Any, None, None]:
|
330
354
|
if cmd is not None:
|
331
355
|
if parallel:
|
@@ -358,6 +382,7 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
358
382
|
env=self.__env(shell=isinstance(cmd, str)),
|
359
383
|
stdout=stdout,
|
360
384
|
stderr=stderr,
|
385
|
+
**kwargs,
|
361
386
|
)
|
362
387
|
|
363
388
|
else:
|
@@ -376,7 +401,9 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
376
401
|
if cpus is None:
|
377
402
|
cpus = 1
|
378
403
|
|
379
|
-
yield self.run(
|
404
|
+
yield self.run(
|
405
|
+
[script_path], parallel=False, cpus=cpus, check=check, **kwargs
|
406
|
+
)
|
380
407
|
|
381
408
|
else:
|
382
409
|
if not self and (self.path / "0.orig").is_dir():
|
@@ -406,5 +433,9 @@ class FoamCaseRunBase(FoamCaseBase):
|
|
406
433
|
cpus = 1
|
407
434
|
|
408
435
|
yield self.run(
|
409
|
-
[self.application],
|
436
|
+
[self.application],
|
437
|
+
parallel=parallel,
|
438
|
+
cpus=cpus,
|
439
|
+
check=check,
|
440
|
+
**kwargs,
|
410
441
|
)
|
foamlib/_cases/_slurm.py
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
import os
|
2
|
+
import shutil
|
3
|
+
import sys
|
4
|
+
from typing import Any, Optional, Union
|
5
|
+
|
6
|
+
if sys.version_info >= (3, 9):
|
7
|
+
from collections.abc import Sequence
|
8
|
+
else:
|
9
|
+
from typing import Sequence
|
10
|
+
|
11
|
+
from ._async import AsyncFoamCase
|
12
|
+
from ._subprocess import run_async
|
13
|
+
|
14
|
+
|
15
|
+
class AsyncSlurmFoamCase(AsyncFoamCase):
|
16
|
+
"""An asynchronous OpenFOAM case that launches jobs on a Slurm cluster."""
|
17
|
+
|
18
|
+
@staticmethod
|
19
|
+
async def _run(
|
20
|
+
cmd: Union[Sequence[Union[str, "os.PathLike[str]"]], str],
|
21
|
+
*,
|
22
|
+
cpus: int,
|
23
|
+
fallback: bool = False,
|
24
|
+
**kwargs: Any,
|
25
|
+
) -> None:
|
26
|
+
if fallback and shutil.which("salloc") is None:
|
27
|
+
await AsyncFoamCase._run(cmd, cpus=cpus, **kwargs)
|
28
|
+
return
|
29
|
+
|
30
|
+
if cpus >= 1:
|
31
|
+
if isinstance(cmd, str):
|
32
|
+
cmd = ["/bin/sh", "-c", cmd]
|
33
|
+
|
34
|
+
if cpus == 1:
|
35
|
+
cmd = ["srun", *cmd]
|
36
|
+
|
37
|
+
cmd = ["salloc", "-n", str(cpus), "--job-name", "foamlib", *cmd]
|
38
|
+
|
39
|
+
await run_async(cmd, **kwargs)
|
40
|
+
|
41
|
+
async def run(
|
42
|
+
self,
|
43
|
+
cmd: Optional[Union[Sequence[Union[str, "os.PathLike[str]"]], str]] = None,
|
44
|
+
*,
|
45
|
+
parallel: Optional[bool] = None,
|
46
|
+
cpus: Optional[int] = None,
|
47
|
+
check: bool = True,
|
48
|
+
log: bool = True,
|
49
|
+
fallback: bool = False,
|
50
|
+
) -> None:
|
51
|
+
"""
|
52
|
+
Run this case, or a specified command in the context of this case.
|
53
|
+
|
54
|
+
:param cmd: The command to run. If None, run the case. If a sequence, the first element is the command and the rest are arguments. If a string, `cmd` is executed in a shell.
|
55
|
+
:param parallel: If True, run in parallel using MPI. If None, autodetect whether to run in parallel.
|
56
|
+
:param cpus: The number of CPUs to use. If None, autodetect according to the case. If 0, run locally.
|
57
|
+
:param check: If True, raise a CalledProcessError if any command returns a non-zero exit code.
|
58
|
+
:param log: If True, log the command output to a file.
|
59
|
+
:param fallback: If True, fall back to running the command locally if Slurm is not available.
|
60
|
+
"""
|
61
|
+
for coro in self._run_calls(
|
62
|
+
cmd=cmd,
|
63
|
+
parallel=parallel,
|
64
|
+
cpus=cpus,
|
65
|
+
check=check,
|
66
|
+
log=log,
|
67
|
+
fallback=fallback,
|
68
|
+
):
|
69
|
+
await coro
|
foamlib/_cases/_sync.py
CHANGED
@@ -139,17 +139,20 @@ class FoamCase(FoamCaseRunBase):
|
|
139
139
|
):
|
140
140
|
pass
|
141
141
|
|
142
|
-
def block_mesh(self, *, check: bool = True) -> None:
|
142
|
+
def block_mesh(self, *, check: bool = True, log: bool = True) -> None:
|
143
143
|
"""Run blockMesh on this case."""
|
144
|
-
self.
|
144
|
+
for _ in self._block_mesh_calls(check=check, log=log):
|
145
|
+
pass
|
145
146
|
|
146
|
-
def decompose_par(self, *, check: bool = True) -> None:
|
147
|
+
def decompose_par(self, *, check: bool = True, log: bool = True) -> None:
|
147
148
|
"""Decompose this case for parallel running."""
|
148
|
-
self.
|
149
|
+
for _ in self._decompose_par_calls(check=check, log=log):
|
150
|
+
pass
|
149
151
|
|
150
|
-
def reconstruct_par(self, *, check: bool = True) -> None:
|
152
|
+
def reconstruct_par(self, *, check: bool = True, log: bool = True) -> None:
|
151
153
|
"""Reconstruct this case after parallel running."""
|
152
|
-
self.
|
154
|
+
for _ in self._reconstruct_par_calls(check=check, log=log):
|
155
|
+
pass
|
153
156
|
|
154
157
|
def restore_0_dir(self) -> None:
|
155
158
|
"""Restore the 0 directory from the 0.orig directory."""
|
@@ -164,12 +167,12 @@ class FoamCase(FoamCaseRunBase):
|
|
164
167
|
|
165
168
|
:param dst: The destination path. If None, clone to `$FOAM_RUN/foamlib`.
|
166
169
|
"""
|
167
|
-
|
170
|
+
calls = ValuedGenerator(self._copy_calls(dst))
|
168
171
|
|
169
|
-
for _ in
|
172
|
+
for _ in calls:
|
170
173
|
pass
|
171
174
|
|
172
|
-
return
|
175
|
+
return calls.value
|
173
176
|
|
174
177
|
def clone(self, dst: Optional[Union["os.PathLike[str]", str]] = None) -> Self:
|
175
178
|
"""
|
@@ -179,9 +182,9 @@ class FoamCase(FoamCaseRunBase):
|
|
179
182
|
|
180
183
|
:param dst: The destination path. If None, clone to `$FOAM_RUN/foamlib`.
|
181
184
|
"""
|
182
|
-
|
185
|
+
calls = ValuedGenerator(self._clone_calls(dst))
|
183
186
|
|
184
|
-
for _ in
|
187
|
+
for _ in calls:
|
185
188
|
pass
|
186
189
|
|
187
|
-
return
|
190
|
+
return calls.value
|
foamlib/_files/_files.py
CHANGED
@@ -186,12 +186,10 @@ class FoamFile(
|
|
186
186
|
|
187
187
|
try:
|
188
188
|
write_header = (
|
189
|
-
not self
|
190
|
-
and "FoamFile" not in self
|
191
|
-
and (not keywords or keywords[0] != "FoamFile")
|
189
|
+
not self and "FoamFile" not in self and keywords != ("FoamFile",)
|
192
190
|
)
|
193
191
|
except FileNotFoundError:
|
194
|
-
write_header =
|
192
|
+
write_header = keywords != ("FoamFile",)
|
195
193
|
|
196
194
|
if write_header:
|
197
195
|
self["FoamFile"] = {}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.6.
|
3
|
+
Version: 0.6.5
|
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
|
@@ -69,7 +69,7 @@ Requires-Dist: mypy <2,>=1 ; extra == 'typing'
|
|
69
69
|
It offers the following classes:
|
70
70
|
|
71
71
|
* [`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 both ASCII and binary field formats.
|
72
|
-
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.FoamCase): a class for
|
72
|
+
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.FoamCase): a class for configuring, running, and accessing the results of OpenFOAM cases.
|
73
73
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
74
74
|
|
75
75
|
## Get started
|
@@ -174,6 +174,18 @@ async def cost(x):
|
|
174
174
|
result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
|
175
175
|
```
|
176
176
|
|
177
|
+
### Use it to create a `run` (or `clean`) script
|
178
|
+
|
179
|
+
```python
|
180
|
+
#!/usr/bin/env python3
|
181
|
+
from pathlib import Path
|
182
|
+
from foamlib import FoamCase
|
183
|
+
|
184
|
+
case = FoamCase(Path(__file__).parent)
|
185
|
+
# Any additional configuration here
|
186
|
+
case.run()
|
187
|
+
```
|
188
|
+
|
177
189
|
## Documentation
|
178
190
|
|
179
191
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -1,21 +1,22 @@
|
|
1
|
-
foamlib/__init__.py,sha256=
|
1
|
+
foamlib/__init__.py,sha256=rB9ilpTj2t4pK8NuAdlVahgfFWtBlWld8s2r_oRsW5s,486
|
2
2
|
foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
foamlib/_cases/__init__.py,sha256=
|
4
|
-
foamlib/_cases/_async.py,sha256=
|
3
|
+
foamlib/_cases/__init__.py,sha256=wTUHcUgU1CBgpu0cUMtksQ5VKG6B8CFu9xc3dWwsQuo,358
|
4
|
+
foamlib/_cases/_async.py,sha256=PYODgIkRLHArMf3wtf34jMx7gBGi-K6hoLEhjYK9bOw,7753
|
5
5
|
foamlib/_cases/_base.py,sha256=4VWsu22VockyKgU_5tnSMeNrAkMgBKwZo2KGkV65rRQ,6739
|
6
|
-
foamlib/_cases/_run.py,sha256=
|
6
|
+
foamlib/_cases/_run.py,sha256=SjA-Qux5NhnhcLz7qiph2DcGYpElAAl_PlTGk6kGeuU,13972
|
7
|
+
foamlib/_cases/_slurm.py,sha256=rhGSFJ-3g72TnAYlhECGfs7P7IkeaHL3ysjXfXLdCCc,2308
|
7
8
|
foamlib/_cases/_subprocess.py,sha256=GTmHWy1LRD9ujpXJfSTXU2bf87GncpIA0VOR1rQW2fg,3633
|
8
|
-
foamlib/_cases/_sync.py,sha256=
|
9
|
+
foamlib/_cases/_sync.py,sha256=L1Em9_32zd01RnMvksZ1GU-4okxhcwZgpLQf1c15uAs,6038
|
9
10
|
foamlib/_cases/_util.py,sha256=GNndpqw3Jg_S-Hxzl5vwRgD0czcTNb9NYHMhcfBoMBg,1493
|
10
11
|
foamlib/_files/__init__.py,sha256=-UqB9YTH6mrJfXCX00kPTAAY20XG64u1MGPw_1ewLVs,148
|
11
12
|
foamlib/_files/_base.py,sha256=zaFDjLE6jB7WtGWk8hfKusjLtlGu6CZV16AHJpRUibs,1929
|
12
|
-
foamlib/_files/_files.py,sha256=
|
13
|
+
foamlib/_files/_files.py,sha256=1jV52dZqr-g6P0X0lA80OQcr2yMt4O-mAgERcaU4440,15583
|
13
14
|
foamlib/_files/_io.py,sha256=T8vTEmJDidL03qeX1PUJFND-_vaF0AuC_0lE_zxLz7Q,2447
|
14
15
|
foamlib/_files/_parsing.py,sha256=DzgJ53QnohRQyLXn2zOs52RIQ7bJ_fS_S2Z7rmRyVK4,9023
|
15
16
|
foamlib/_files/_serialization.py,sha256=pb8_cIVgRhGS_ZV2p3x8p5_lK1SS6xzQHscAYYuOgFY,3407
|
16
17
|
foamlib/_files/_util.py,sha256=UMzXmTFgvbp46w6k3oEZJoYC98pFgEK6LN5uLOwrlCg,397
|
17
|
-
foamlib-0.6.
|
18
|
-
foamlib-0.6.
|
19
|
-
foamlib-0.6.
|
20
|
-
foamlib-0.6.
|
21
|
-
foamlib-0.6.
|
18
|
+
foamlib-0.6.5.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
|
19
|
+
foamlib-0.6.5.dist-info/METADATA,sha256=xgpPiDbPfFBJjg09mDarYez95jP5RSw0uGCt9AS9kxk,6569
|
20
|
+
foamlib-0.6.5.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
|
21
|
+
foamlib-0.6.5.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
|
22
|
+
foamlib-0.6.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|