foamlib 0.4.4__py3-none-any.whl → 0.5.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.
- foamlib/__init__.py +1 -3
- foamlib/_cases/__init__.py +1 -2
- foamlib/_cases/_async.py +112 -61
- foamlib/_cases/_base.py +3 -253
- foamlib/_cases/_recipes.py +299 -0
- foamlib/_cases/_subprocess.py +86 -0
- foamlib/_cases/_sync.py +100 -46
- foamlib/_cases/_util.py +38 -24
- foamlib/_files/_files.py +4 -8
- foamlib/_files/_serialization.py +1 -1
- {foamlib-0.4.4.dist-info → foamlib-0.5.1.dist-info}/METADATA +29 -1
- foamlib-0.5.1.dist-info/RECORD +21 -0
- foamlib-0.4.4.dist-info/RECORD +0 -19
- /foamlib/{_util.py → _files/_util.py} +0 -0
- {foamlib-0.4.4.dist-info → foamlib-0.5.1.dist-info}/LICENSE.txt +0 -0
- {foamlib-0.4.4.dist-info → foamlib-0.5.1.dist-info}/WHEEL +0 -0
- {foamlib-0.4.4.dist-info → foamlib-0.5.1.dist-info}/top_level.txt +0 -0
foamlib/__init__.py
CHANGED
@@ -1,11 +1,10 @@
|
|
1
1
|
"""A Python interface for interacting with OpenFOAM."""
|
2
2
|
|
3
|
-
__version__ = "0.
|
3
|
+
__version__ = "0.5.1"
|
4
4
|
|
5
5
|
from ._cases import (
|
6
6
|
AsyncFoamCase,
|
7
7
|
CalledProcessError,
|
8
|
-
CalledProcessWarning,
|
9
8
|
FoamCase,
|
10
9
|
FoamCaseBase,
|
11
10
|
)
|
@@ -19,5 +18,4 @@ __all__ = [
|
|
19
18
|
"FoamFieldFile",
|
20
19
|
"FoamFileBase",
|
21
20
|
"CalledProcessError",
|
22
|
-
"CalledProcessWarning",
|
23
21
|
]
|
foamlib/_cases/__init__.py
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
from ._async import AsyncFoamCase
|
2
2
|
from ._base import FoamCaseBase
|
3
|
+
from ._subprocess import CalledProcessError
|
3
4
|
from ._sync import FoamCase
|
4
|
-
from ._util import CalledProcessError, CalledProcessWarning
|
5
5
|
|
6
6
|
__all__ = [
|
7
7
|
"FoamCaseBase",
|
8
8
|
"FoamCase",
|
9
9
|
"AsyncFoamCase",
|
10
10
|
"CalledProcessError",
|
11
|
-
"CalledProcessWarning",
|
12
11
|
]
|
foamlib/_cases/_async.py
CHANGED
@@ -1,27 +1,39 @@
|
|
1
1
|
import asyncio
|
2
2
|
import multiprocessing
|
3
|
+
import os
|
3
4
|
import sys
|
5
|
+
import tempfile
|
4
6
|
from contextlib import asynccontextmanager
|
5
7
|
from pathlib import Path
|
6
|
-
from typing import
|
7
|
-
Callable,
|
8
|
-
Optional,
|
9
|
-
Union,
|
10
|
-
)
|
8
|
+
from typing import Callable, Optional, TypeVar, Union
|
11
9
|
|
12
10
|
if sys.version_info >= (3, 9):
|
13
|
-
from collections.abc import
|
11
|
+
from collections.abc import (
|
12
|
+
AsyncGenerator,
|
13
|
+
Awaitable,
|
14
|
+
Collection,
|
15
|
+
Iterable,
|
16
|
+
Sequence,
|
17
|
+
)
|
14
18
|
else:
|
15
|
-
from typing import AsyncGenerator, Collection, Sequence
|
19
|
+
from typing import AsyncGenerator, Awaitable, Collection, Iterable, Sequence
|
20
|
+
|
21
|
+
if sys.version_info >= (3, 11):
|
22
|
+
from typing import Self
|
23
|
+
else:
|
24
|
+
from typing_extensions import Self
|
16
25
|
|
17
26
|
import aioshutil
|
18
27
|
|
19
|
-
from
|
20
|
-
from .
|
21
|
-
from ._util import
|
28
|
+
from ._recipes import _FoamCaseRecipes
|
29
|
+
from ._subprocess import run_async
|
30
|
+
from ._util import awaitableasynccontextmanager
|
22
31
|
|
32
|
+
X = TypeVar("X")
|
33
|
+
Y = TypeVar("Y")
|
23
34
|
|
24
|
-
|
35
|
+
|
36
|
+
class AsyncFoamCase(_FoamCaseRecipes):
|
25
37
|
"""
|
26
38
|
An OpenFOAM case with asynchronous support.
|
27
39
|
|
@@ -63,17 +75,19 @@ class AsyncFoamCase(FoamCaseBase):
|
|
63
75
|
AsyncFoamCase._cpus_cond.notify(cpus)
|
64
76
|
|
65
77
|
@staticmethod
|
66
|
-
async def _rmtree(
|
78
|
+
async def _rmtree(
|
79
|
+
path: Union["os.PathLike[str]", str], ignore_errors: bool = False
|
80
|
+
) -> None:
|
67
81
|
await aioshutil.rmtree(path, ignore_errors=ignore_errors) # type: ignore [call-arg]
|
68
82
|
|
69
83
|
@staticmethod
|
70
84
|
async def _copytree(
|
71
|
-
src:
|
72
|
-
dest:
|
85
|
+
src: Union["os.PathLike[str]", str],
|
86
|
+
dest: Union["os.PathLike[str]", str],
|
73
87
|
*,
|
74
88
|
symlinks: bool = False,
|
75
89
|
ignore: Optional[
|
76
|
-
Callable[[Union[
|
90
|
+
Callable[[Union["os.PathLike[str]", str], Collection[str]], Collection[str]]
|
77
91
|
] = None,
|
78
92
|
) -> None:
|
79
93
|
await aioshutil.copytree(src, dest, symlinks=symlinks, ignore=ignore)
|
@@ -95,60 +109,54 @@ class AsyncFoamCase(FoamCaseBase):
|
|
95
109
|
|
96
110
|
async def _run(
|
97
111
|
self,
|
98
|
-
cmd: Union[Sequence[Union[str,
|
112
|
+
cmd: Union[Sequence[Union[str, "os.PathLike[str]"]], str],
|
99
113
|
*,
|
100
114
|
parallel: bool = False,
|
101
115
|
cpus: int = 1,
|
102
116
|
check: bool = True,
|
117
|
+
log: bool = True,
|
103
118
|
) -> None:
|
104
|
-
|
105
|
-
if
|
106
|
-
if
|
107
|
-
cmd =
|
108
|
-
|
109
|
-
|
110
|
-
|
119
|
+
with self._output(cmd, log=log) as (stdout, stderr):
|
120
|
+
if parallel:
|
121
|
+
if isinstance(cmd, str):
|
122
|
+
cmd = [
|
123
|
+
"mpiexec",
|
124
|
+
"-n",
|
125
|
+
str(cpus),
|
126
|
+
"/bin/sh",
|
127
|
+
"-c",
|
128
|
+
f"{cmd} -parallel",
|
129
|
+
]
|
130
|
+
else:
|
131
|
+
cmd = ["mpiexec", "-n", str(cpus), *cmd, "-parallel"]
|
132
|
+
|
133
|
+
async with self._cpus(cpus):
|
134
|
+
await run_async(
|
135
|
+
cmd,
|
136
|
+
check=check,
|
111
137
|
cwd=self.path,
|
112
|
-
env=self._env(shell=
|
113
|
-
stdout=
|
114
|
-
stderr=
|
115
|
-
if check
|
116
|
-
else asyncio.subprocess.DEVNULL,
|
138
|
+
env=self._env(shell=isinstance(cmd, str)),
|
139
|
+
stdout=stdout,
|
140
|
+
stderr=stderr,
|
117
141
|
)
|
118
142
|
|
119
|
-
else:
|
120
|
-
if parallel:
|
121
|
-
cmd = ["mpiexec", "-np", str(cpus), *cmd, "-parallel"]
|
122
|
-
|
123
|
-
if sys.version_info < (3, 8):
|
124
|
-
cmd = (str(arg) for arg in cmd)
|
125
|
-
proc = await asyncio.create_subprocess_exec(
|
126
|
-
*cmd,
|
127
|
-
cwd=self.path,
|
128
|
-
env=self._env(shell=False),
|
129
|
-
stdout=asyncio.subprocess.DEVNULL,
|
130
|
-
stderr=asyncio.subprocess.PIPE
|
131
|
-
if check
|
132
|
-
else asyncio.subprocess.DEVNULL,
|
133
|
-
)
|
134
|
-
|
135
|
-
stdout, stderr = await proc.communicate()
|
136
|
-
|
137
|
-
assert stdout is None
|
138
|
-
assert proc.returncode is not None
|
139
|
-
|
140
|
-
if check:
|
141
|
-
check_returncode(proc.returncode, cmd, stderr.decode())
|
142
|
-
|
143
143
|
async def run(
|
144
144
|
self,
|
145
|
-
cmd: Optional[Union[Sequence[Union[str,
|
145
|
+
cmd: Optional[Union[Sequence[Union[str, "os.PathLike[str]"]], str]] = None,
|
146
146
|
*,
|
147
147
|
script: bool = True,
|
148
148
|
parallel: Optional[bool] = None,
|
149
149
|
cpus: Optional[int] = None,
|
150
150
|
check: bool = True,
|
151
151
|
) -> None:
|
152
|
+
"""
|
153
|
+
Run this case, or a specified command in the context of this case.
|
154
|
+
|
155
|
+
: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.
|
156
|
+
:param script: If True and `cmd` is None, use an (All)run(-parallel) script if it exists for running the case. If False or no run script is found, autodetermine the command(s) needed to run the case.
|
157
|
+
:param parallel: If True, run in parallel using MPI. If None, autodetect whether to run in parallel.
|
158
|
+
:param check: If True, raise a CalledProcessError if any command returns a non-zero exit code.
|
159
|
+
"""
|
152
160
|
for name, args, kwargs in self._run_cmds(
|
153
161
|
cmd=cmd, script=script, parallel=parallel, cpus=cpus, check=check
|
154
162
|
):
|
@@ -171,24 +179,67 @@ class AsyncFoamCase(FoamCaseBase):
|
|
171
179
|
for name, args, kwargs in self._restore_0_dir_cmds():
|
172
180
|
await getattr(self, name)(*args, **kwargs)
|
173
181
|
|
174
|
-
|
182
|
+
@awaitableasynccontextmanager
|
183
|
+
@asynccontextmanager
|
184
|
+
async def copy(
|
185
|
+
self, dst: Optional[Union["os.PathLike[str]", str]] = None
|
186
|
+
) -> "AsyncGenerator[Self]":
|
175
187
|
"""
|
176
188
|
Make a copy of this case.
|
177
189
|
|
178
|
-
|
190
|
+
Use as an async context manager to automatically delete the copy when done.
|
191
|
+
|
192
|
+
:param dst: The destination path. If None, copy to a temporary directory.
|
179
193
|
"""
|
180
|
-
|
194
|
+
if dst is None:
|
195
|
+
dst = Path(tempfile.mkdtemp(), self.name)
|
196
|
+
tmp = True
|
197
|
+
else:
|
198
|
+
tmp = False
|
199
|
+
|
200
|
+
for name, args, kwargs in self._copy_cmds(dst):
|
181
201
|
await getattr(self, name)(*args, **kwargs)
|
182
202
|
|
183
|
-
|
203
|
+
yield type(self)(dst)
|
204
|
+
|
205
|
+
if tmp:
|
206
|
+
assert isinstance(dst, Path)
|
207
|
+
await self._rmtree(dst.parent)
|
208
|
+
else:
|
209
|
+
await self._rmtree(dst)
|
184
210
|
|
185
|
-
|
211
|
+
@awaitableasynccontextmanager
|
212
|
+
@asynccontextmanager
|
213
|
+
async def clone(
|
214
|
+
self, dst: Optional[Union["os.PathLike[str]", str]] = None
|
215
|
+
) -> "AsyncGenerator[Self]":
|
186
216
|
"""
|
187
217
|
Clone this case (make a clean copy).
|
188
218
|
|
189
|
-
|
219
|
+
Use as an async context manager to automatically delete the clone when done.
|
220
|
+
|
221
|
+
:param dst: The destination path. If None, clone to a temporary directory.
|
190
222
|
"""
|
191
|
-
|
223
|
+
if dst is None:
|
224
|
+
dst = Path(tempfile.mkdtemp(), self.name)
|
225
|
+
tmp = True
|
226
|
+
else:
|
227
|
+
tmp = False
|
228
|
+
|
229
|
+
for name, args, kwargs in self._clone_cmds(dst):
|
192
230
|
await getattr(self, name)(*args, **kwargs)
|
193
231
|
|
194
|
-
|
232
|
+
yield type(self)(dst)
|
233
|
+
|
234
|
+
if tmp:
|
235
|
+
assert isinstance(dst, Path)
|
236
|
+
await self._rmtree(dst.parent)
|
237
|
+
else:
|
238
|
+
await self._rmtree(dst)
|
239
|
+
|
240
|
+
@staticmethod
|
241
|
+
def map(coro: Callable[[X], Awaitable[Y]], iterable: Iterable[X]) -> Iterable[Y]:
|
242
|
+
"""Run an async function on each element of an iterable concurrently."""
|
243
|
+
return asyncio.get_event_loop().run_until_complete(
|
244
|
+
asyncio.gather(*(coro(arg) for arg in iterable))
|
245
|
+
)
|
foamlib/_cases/_base.py
CHANGED
@@ -3,40 +3,29 @@ import shutil
|
|
3
3
|
import sys
|
4
4
|
from pathlib import Path
|
5
5
|
from typing import (
|
6
|
-
Any,
|
7
6
|
Optional,
|
8
|
-
Tuple,
|
9
7
|
Union,
|
10
8
|
overload,
|
11
9
|
)
|
12
10
|
|
13
11
|
if sys.version_info >= (3, 9):
|
14
12
|
from collections.abc import (
|
15
|
-
Callable,
|
16
|
-
Collection,
|
17
|
-
Generator,
|
18
13
|
Iterator,
|
19
|
-
Mapping,
|
20
14
|
Sequence,
|
21
15
|
Set,
|
22
16
|
)
|
23
17
|
else:
|
24
18
|
from typing import AbstractSet as Set
|
25
19
|
from typing import (
|
26
|
-
Callable,
|
27
|
-
Collection,
|
28
|
-
Generator,
|
29
20
|
Iterator,
|
30
|
-
Mapping,
|
31
21
|
Sequence,
|
32
22
|
)
|
33
23
|
|
34
|
-
|
35
24
|
from .._files import FoamFieldFile, FoamFile
|
36
25
|
|
37
26
|
|
38
27
|
class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
39
|
-
def __init__(self, path: Union[
|
28
|
+
def __init__(self, path: Union["os.PathLike[str]", str] = Path()):
|
40
29
|
self.path = Path(path).absolute()
|
41
30
|
|
42
31
|
class TimeDirectory(Set[FoamFieldFile]):
|
@@ -48,7 +37,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
48
37
|
:param path: The path to the time directory.
|
49
38
|
"""
|
50
39
|
|
51
|
-
def __init__(self, path: Union[
|
40
|
+
def __init__(self, path: Union["os.PathLike[str]", str]):
|
52
41
|
self.path = Path(path).absolute()
|
53
42
|
|
54
43
|
@property
|
@@ -141,254 +130,15 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
141
130
|
def __len__(self) -> int:
|
142
131
|
return len(self._times)
|
143
132
|
|
144
|
-
def _clean_paths(self) -> Set[Path]:
|
145
|
-
has_decompose_par_dict = (self.path / "system" / "decomposeParDict").is_file()
|
146
|
-
has_block_mesh_dict = (self.path / "system" / "blockMeshDict").is_file()
|
147
|
-
|
148
|
-
paths = set()
|
149
|
-
|
150
|
-
for p in self.path.iterdir():
|
151
|
-
if p.is_dir():
|
152
|
-
try:
|
153
|
-
t = float(p.name)
|
154
|
-
except ValueError:
|
155
|
-
pass
|
156
|
-
else:
|
157
|
-
if t != 0:
|
158
|
-
paths.add(p)
|
159
|
-
|
160
|
-
if has_decompose_par_dict and p.name.startswith("processor"):
|
161
|
-
paths.add(p)
|
162
|
-
|
163
|
-
if (self.path / "0.orig").is_dir() and (self.path / "0").is_dir():
|
164
|
-
paths.add(self.path / "0")
|
165
|
-
|
166
|
-
if has_block_mesh_dict and (self.path / "constant" / "polyMesh").exists():
|
167
|
-
paths.add(self.path / "constant" / "polyMesh")
|
168
|
-
|
169
|
-
if self._run_script() is not None:
|
170
|
-
paths.update(self.path.glob("log.*"))
|
171
|
-
|
172
|
-
return paths
|
173
|
-
|
174
133
|
def __delitem__(self, key: Union[int, float, str]) -> None:
|
175
134
|
shutil.rmtree(self[key].path)
|
176
135
|
|
177
|
-
def _clone_ignore(
|
178
|
-
self,
|
179
|
-
) -> Callable[[Union[Path, str], Collection[str]], Collection[str]]:
|
180
|
-
clean_paths = self._clean_paths()
|
181
|
-
|
182
|
-
def ignore(path: Union[Path, str], names: Collection[str]) -> Collection[str]:
|
183
|
-
paths = {Path(path) / name for name in names}
|
184
|
-
return {p.name for p in paths.intersection(clean_paths)}
|
185
|
-
|
186
|
-
return ignore
|
187
|
-
|
188
|
-
def _clean_script(self) -> Optional[Path]:
|
189
|
-
"""Return the path to the (All)clean script, or None if no clean script is found."""
|
190
|
-
clean = self.path / "clean"
|
191
|
-
all_clean = self.path / "Allclean"
|
192
|
-
|
193
|
-
if clean.is_file():
|
194
|
-
script = clean
|
195
|
-
elif all_clean.is_file():
|
196
|
-
script = all_clean
|
197
|
-
else:
|
198
|
-
return None
|
199
|
-
|
200
|
-
if sys.argv and Path(sys.argv[0]).absolute() == script.absolute():
|
201
|
-
return None
|
202
|
-
|
203
|
-
return script if Path(sys.argv[0]).absolute() != script.absolute() else None
|
204
|
-
|
205
|
-
def _run_script(self, *, parallel: Optional[bool] = None) -> Optional[Path]:
|
206
|
-
"""Return the path to the (All)run script, or None if no run script is found."""
|
207
|
-
run = self.path / "run"
|
208
|
-
run_parallel = self.path / "run-parallel"
|
209
|
-
all_run = self.path / "Allrun"
|
210
|
-
all_run_parallel = self.path / "Allrun-parallel"
|
211
|
-
|
212
|
-
if run.is_file() or all_run.is_file():
|
213
|
-
if run_parallel.is_file() or all_run_parallel.is_file():
|
214
|
-
if parallel:
|
215
|
-
script = (
|
216
|
-
run_parallel if run_parallel.is_file() else all_run_parallel
|
217
|
-
)
|
218
|
-
elif parallel is False:
|
219
|
-
script = run if run.is_file() else all_run
|
220
|
-
else:
|
221
|
-
raise ValueError(
|
222
|
-
"Both (All)run and (All)run-parallel scripts are present. Please specify parallel argument."
|
223
|
-
)
|
224
|
-
else:
|
225
|
-
script = run if run.is_file() else all_run
|
226
|
-
elif parallel is not False and (
|
227
|
-
run_parallel.is_file() or all_run_parallel.is_file()
|
228
|
-
):
|
229
|
-
script = run_parallel if run_parallel.is_file() else all_run_parallel
|
230
|
-
else:
|
231
|
-
return None
|
232
|
-
|
233
|
-
if sys.argv and Path(sys.argv[0]).absolute() == script.absolute():
|
234
|
-
return None
|
235
|
-
|
236
|
-
return script
|
237
|
-
|
238
|
-
def _env(self, *, shell: bool) -> Optional[Mapping[str, str]]:
|
239
|
-
sip_workaround = os.environ.get(
|
240
|
-
"FOAM_LD_LIBRARY_PATH", ""
|
241
|
-
) and not os.environ.get("DYLD_LIBRARY_PATH", "")
|
242
|
-
|
243
|
-
if not shell or sip_workaround:
|
244
|
-
env = os.environ.copy()
|
245
|
-
|
246
|
-
if not shell:
|
247
|
-
env["PWD"] = str(self.path)
|
248
|
-
|
249
|
-
if sip_workaround:
|
250
|
-
env["DYLD_LIBRARY_PATH"] = env["FOAM_LD_LIBRARY_PATH"]
|
251
|
-
|
252
|
-
return env
|
253
|
-
else:
|
254
|
-
return None
|
255
|
-
|
256
|
-
def _copy_cmds(
|
257
|
-
self, dest: Union[Path, str]
|
258
|
-
) -> Generator[Tuple[str, Sequence[Any], Mapping[str, Any]], None, None]:
|
259
|
-
yield (
|
260
|
-
"_copytree",
|
261
|
-
(
|
262
|
-
self.path,
|
263
|
-
dest,
|
264
|
-
),
|
265
|
-
{"symlinks": True},
|
266
|
-
)
|
267
|
-
|
268
|
-
def _clean_cmds(
|
269
|
-
self, *, script: bool = True, check: bool = False
|
270
|
-
) -> Generator[Tuple[str, Sequence[Any], Mapping[str, Any]], None, None]:
|
271
|
-
script_path = self._clean_script() if script else None
|
272
|
-
|
273
|
-
if script_path is not None:
|
274
|
-
yield ("_run", ([script_path],), {"cpus": 0, "check": check})
|
275
|
-
else:
|
276
|
-
for p in self._clean_paths():
|
277
|
-
if p.is_dir():
|
278
|
-
yield ("_rmtree", (p,), {})
|
279
|
-
else:
|
280
|
-
p.unlink()
|
281
|
-
|
282
|
-
def _clone_cmds(
|
283
|
-
self, dest: Union[Path, str]
|
284
|
-
) -> Generator[Tuple[str, Sequence[Any], Mapping[str, Any]], None, None]:
|
285
|
-
if self._clean_script() is not None:
|
286
|
-
yield ("copy", (dest,), {})
|
287
|
-
yield ("clean", (), {})
|
288
|
-
else:
|
289
|
-
yield (
|
290
|
-
"_copytree",
|
291
|
-
(
|
292
|
-
self.path,
|
293
|
-
dest,
|
294
|
-
),
|
295
|
-
{"symlinks": True, "ignore": self._clone_ignore()},
|
296
|
-
)
|
297
|
-
|
298
|
-
def _restore_0_dir_cmds(
|
299
|
-
self,
|
300
|
-
) -> Generator[Tuple[str, Sequence[Any], Mapping[str, Any]], None, None]:
|
301
|
-
yield ("_rmtree", (self.path / "0",), {"ignore_errors": True})
|
302
|
-
yield (
|
303
|
-
"_copytree",
|
304
|
-
(
|
305
|
-
self.path / "0.orig",
|
306
|
-
self.path / "0",
|
307
|
-
),
|
308
|
-
{"symlinks": True},
|
309
|
-
)
|
310
|
-
|
311
|
-
def _run_cmds(
|
312
|
-
self,
|
313
|
-
cmd: Optional[Union[Sequence[Union[str, Path]], str, Path]] = None,
|
314
|
-
*,
|
315
|
-
script: bool = True,
|
316
|
-
parallel: Optional[bool] = None,
|
317
|
-
cpus: Optional[int] = None,
|
318
|
-
check: bool = True,
|
319
|
-
) -> Generator[Tuple[str, Sequence[Any], Mapping[str, Any]], None, None]:
|
320
|
-
if cmd is not None:
|
321
|
-
if parallel:
|
322
|
-
if cpus is None:
|
323
|
-
cpus = max(self._nprocessors, 1)
|
324
|
-
else:
|
325
|
-
parallel = False
|
326
|
-
if cpus is None:
|
327
|
-
cpus = 1
|
328
|
-
|
329
|
-
yield ("_run", (cmd,), {"parallel": parallel, "cpus": cpus, "check": check})
|
330
|
-
|
331
|
-
else:
|
332
|
-
script_path = self._run_script(parallel=parallel) if script else None
|
333
|
-
|
334
|
-
if script_path is not None:
|
335
|
-
if parallel or parallel is None:
|
336
|
-
if cpus is None:
|
337
|
-
if self._nprocessors > 0:
|
338
|
-
cpus = self._nprocessors
|
339
|
-
elif (self.path / "system" / "decomposeParDict").is_file():
|
340
|
-
cpus = self._nsubdomains
|
341
|
-
else:
|
342
|
-
cpus = 1
|
343
|
-
else:
|
344
|
-
if cpus is None:
|
345
|
-
cpus = 1
|
346
|
-
|
347
|
-
yield (
|
348
|
-
"_run",
|
349
|
-
([script_path],),
|
350
|
-
{"parallel": False, "cpus": cpus, "check": check},
|
351
|
-
)
|
352
|
-
|
353
|
-
else:
|
354
|
-
if not self and (self.path / "0.orig").is_dir():
|
355
|
-
yield ("restore_0_dir", (), {})
|
356
|
-
|
357
|
-
if (self.path / "system" / "blockMeshDict").is_file():
|
358
|
-
yield ("block_mesh", (), {"check": check})
|
359
|
-
|
360
|
-
if parallel is None:
|
361
|
-
parallel = (
|
362
|
-
(cpus is not None and cpus > 1)
|
363
|
-
or self._nprocessors > 0
|
364
|
-
or (self.path / "system" / "decomposeParDict").is_file()
|
365
|
-
)
|
366
|
-
|
367
|
-
if parallel:
|
368
|
-
if (
|
369
|
-
self._nprocessors == 0
|
370
|
-
and (self.path / "system" / "decomposeParDict").is_file()
|
371
|
-
):
|
372
|
-
yield ("decompose_par", (), {"check": check})
|
373
|
-
|
374
|
-
if cpus is None:
|
375
|
-
cpus = max(self._nprocessors, 1)
|
376
|
-
else:
|
377
|
-
if cpus is None:
|
378
|
-
cpus = 1
|
379
|
-
|
380
|
-
yield (
|
381
|
-
"_run",
|
382
|
-
([self.application],),
|
383
|
-
{"parallel": parallel, "cpus": cpus, "check": check},
|
384
|
-
)
|
385
|
-
|
386
136
|
@property
|
387
137
|
def name(self) -> str:
|
388
138
|
"""The name of the case."""
|
389
139
|
return self.path.name
|
390
140
|
|
391
|
-
def file(self, path: Union[
|
141
|
+
def file(self, path: Union["os.PathLike[str]", str]) -> FoamFile:
|
392
142
|
"""Return a FoamFile object for the given path in the case."""
|
393
143
|
return FoamFile(self.path / path)
|
394
144
|
|