foamlib 0.4.3__py3-none-any.whl → 0.4.4__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 CHANGED
@@ -1,6 +1,6 @@
1
1
  """A Python interface for interacting with OpenFOAM."""
2
2
 
3
- __version__ = "0.4.3"
3
+ __version__ = "0.4.4"
4
4
 
5
5
  from ._cases import (
6
6
  AsyncFoamCase,
foamlib/_cases/_async.py CHANGED
@@ -4,14 +4,15 @@ import sys
4
4
  from contextlib import asynccontextmanager
5
5
  from pathlib import Path
6
6
  from typing import (
7
+ Callable,
7
8
  Optional,
8
9
  Union,
9
10
  )
10
11
 
11
12
  if sys.version_info >= (3, 9):
12
- from collections.abc import AsyncGenerator, Sequence
13
+ from collections.abc import AsyncGenerator, Collection, Sequence
13
14
  else:
14
- from typing import AsyncGenerator, Sequence
15
+ from typing import AsyncGenerator, Collection, Sequence
15
16
 
16
17
  import aioshutil
17
18
 
@@ -61,6 +62,22 @@ class AsyncFoamCase(FoamCaseBase):
61
62
  AsyncFoamCase._reserved_cpus -= cpus
62
63
  AsyncFoamCase._cpus_cond.notify(cpus)
63
64
 
65
+ @staticmethod
66
+ async def _rmtree(path: Path, ignore_errors: bool = False) -> None:
67
+ await aioshutil.rmtree(path, ignore_errors=ignore_errors) # type: ignore [call-arg]
68
+
69
+ @staticmethod
70
+ async def _copytree(
71
+ src: Path,
72
+ dest: Path,
73
+ *,
74
+ symlinks: bool = False,
75
+ ignore: Optional[
76
+ Callable[[Union[Path, str], Collection[str]], Collection[str]]
77
+ ] = None,
78
+ ) -> None:
79
+ await aioshutil.copytree(src, dest, symlinks=symlinks, ignore=ignore)
80
+
64
81
  async def clean(
65
82
  self,
66
83
  *,
@@ -73,50 +90,55 @@ class AsyncFoamCase(FoamCaseBase):
73
90
  :param script: If True, use an (All)clean script if it exists. If False, ignore any clean scripts.
74
91
  :param check: If True, raise a CalledProcessError if the clean script returns a non-zero exit code.
75
92
  """
76
- script_path = self._clean_script() if script else None
77
-
78
- if script_path is not None:
79
- await self.run([script_path], check=check)
80
- else:
81
- for p in self._clean_paths():
82
- if p.is_dir():
83
- await aioshutil.rmtree(p) # type: ignore [call-arg]
84
- else:
85
- p.unlink()
93
+ for name, args, kwargs in self._clean_cmds(script=script, check=check):
94
+ await getattr(self, name)(*args, **kwargs)
86
95
 
87
96
  async def _run(
88
97
  self,
89
98
  cmd: Union[Sequence[Union[str, Path]], str, Path],
90
99
  *,
100
+ parallel: bool = False,
101
+ cpus: int = 1,
91
102
  check: bool = True,
92
103
  ) -> None:
93
- if not is_sequence(cmd):
94
- proc = await asyncio.create_subprocess_shell(
95
- str(cmd),
96
- cwd=self.path,
97
- env=self._env(shell=True),
98
- stdout=asyncio.subprocess.DEVNULL,
99
- stderr=asyncio.subprocess.PIPE if check else asyncio.subprocess.DEVNULL,
100
- )
101
-
102
- else:
103
- if sys.version_info < (3, 8):
104
- cmd = (str(arg) for arg in cmd)
105
- proc = await asyncio.create_subprocess_exec(
106
- *cmd,
107
- cwd=self.path,
108
- env=self._env(shell=False),
109
- stdout=asyncio.subprocess.DEVNULL,
110
- stderr=asyncio.subprocess.PIPE if check else asyncio.subprocess.DEVNULL,
111
- )
112
-
113
- stdout, stderr = await proc.communicate()
114
-
115
- assert stdout is None
116
- assert proc.returncode is not None
117
-
118
- if check:
119
- check_returncode(proc.returncode, cmd, stderr.decode())
104
+ async with self._cpus(cpus):
105
+ if not is_sequence(cmd):
106
+ if parallel:
107
+ cmd = f"mpiexec -np {cpus} {cmd} -parallel"
108
+
109
+ proc = await asyncio.create_subprocess_shell(
110
+ str(cmd),
111
+ cwd=self.path,
112
+ env=self._env(shell=True),
113
+ stdout=asyncio.subprocess.DEVNULL,
114
+ stderr=asyncio.subprocess.PIPE
115
+ if check
116
+ else asyncio.subprocess.DEVNULL,
117
+ )
118
+
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())
120
142
 
121
143
  async def run(
122
144
  self,
@@ -128,19 +150,9 @@ class AsyncFoamCase(FoamCaseBase):
128
150
  check: bool = True,
129
151
  ) -> None:
130
152
  for name, args, kwargs in self._run_cmds(
131
- cmd=cmd, script=script, parallel=parallel, check=check
153
+ cmd=cmd, script=script, parallel=parallel, cpus=cpus, check=check
132
154
  ):
133
- if cpus is None:
134
- if name == "run":
135
- if kwargs.get("parallel", False):
136
- cpus = max(self._nprocessors, 1)
137
- else:
138
- cpus = 1
139
- else:
140
- cpus = 0
141
-
142
- async with self._cpus(cpus):
143
- await getattr(self, name)(*args, **kwargs)
155
+ await getattr(self, name)(*args, **kwargs)
144
156
 
145
157
  async def block_mesh(self, *, check: bool = True) -> None:
146
158
  """Run blockMesh on this case."""
@@ -156,8 +168,8 @@ class AsyncFoamCase(FoamCaseBase):
156
168
 
157
169
  async def restore_0_dir(self) -> None:
158
170
  """Restore the 0 directory from the 0.orig directory."""
159
- await aioshutil.rmtree(self.path / "0", ignore_errors=True) # type: ignore [call-arg]
160
- await aioshutil.copytree(self.path / "0.orig", self.path / "0")
171
+ for name, args, kwargs in self._restore_0_dir_cmds():
172
+ await getattr(self, name)(*args, **kwargs)
161
173
 
162
174
  async def copy(self, dest: Union[Path, str]) -> "AsyncFoamCase":
163
175
  """
@@ -165,7 +177,10 @@ class AsyncFoamCase(FoamCaseBase):
165
177
 
166
178
  :param dest: The destination path.
167
179
  """
168
- return AsyncFoamCase(await aioshutil.copytree(self.path, dest, symlinks=True))
180
+ for name, args, kwargs in self._copy_cmds(dest):
181
+ await getattr(self, name)(*args, **kwargs)
182
+
183
+ return AsyncFoamCase(dest)
169
184
 
170
185
  async def clone(self, dest: Union[Path, str]) -> "AsyncFoamCase":
171
186
  """
@@ -173,15 +188,7 @@ class AsyncFoamCase(FoamCaseBase):
173
188
 
174
189
  :param dest: The destination path.
175
190
  """
176
- if self._clean_script() is not None:
177
- copy = await self.copy(dest)
178
- await copy.clean()
179
- return copy
180
-
181
- dest = Path(dest)
182
-
183
- await aioshutil.copytree(
184
- self.path, dest, symlinks=True, ignore=self._clone_ignore()
185
- )
191
+ for name, args, kwargs in self._clone_cmds(dest):
192
+ await getattr(self, name)(*args, **kwargs)
186
193
 
187
194
  return AsyncFoamCase(dest)
foamlib/_cases/_base.py CHANGED
@@ -33,11 +33,10 @@ else:
33
33
 
34
34
 
35
35
  from .._files import FoamFieldFile, FoamFile
36
- from .._util import is_sequence
37
36
 
38
37
 
39
38
  class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
40
- def __init__(self, path: Union[Path, str] = Path()):
39
+ def __init__(self, path: Union[Path, str, "FoamCaseBase"] = Path()):
41
40
  self.path = Path(path).absolute()
42
41
 
43
42
  class TimeDirectory(Set[FoamFieldFile]):
@@ -254,24 +253,102 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
254
253
  else:
255
254
  return None
256
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
+
257
311
  def _run_cmds(
258
312
  self,
259
313
  cmd: Optional[Union[Sequence[Union[str, Path]], str, Path]] = None,
260
314
  *,
261
315
  script: bool = True,
262
316
  parallel: Optional[bool] = None,
317
+ cpus: Optional[int] = None,
263
318
  check: bool = True,
264
319
  ) -> Generator[Tuple[str, Sequence[Any], Mapping[str, Any]], None, None]:
265
320
  if cmd is not None:
266
321
  if parallel:
267
- cmd = self._parallel_cmd(cmd)
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})
268
330
 
269
- yield ("_run", (cmd,), {"check": check})
270
331
  else:
271
332
  script_path = self._run_script(parallel=parallel) if script else None
272
333
 
273
334
  if script_path is not None:
274
- yield ("_run", ([script_path],), {"check": check})
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
+ )
275
352
 
276
353
  else:
277
354
  if not self and (self.path / "0.orig").is_dir():
@@ -282,7 +359,8 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
282
359
 
283
360
  if parallel is None:
284
361
  parallel = (
285
- self._nprocessors > 0
362
+ (cpus is not None and cpus > 1)
363
+ or self._nprocessors > 0
286
364
  or (self.path / "system" / "decomposeParDict").is_file()
287
365
  )
288
366
 
@@ -293,27 +371,18 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
293
371
  ):
294
372
  yield ("decompose_par", (), {"check": check})
295
373
 
374
+ if cpus is None:
375
+ cpus = max(self._nprocessors, 1)
376
+ else:
377
+ if cpus is None:
378
+ cpus = 1
379
+
296
380
  yield (
297
- "run",
381
+ "_run",
298
382
  ([self.application],),
299
- {"parallel": parallel, "check": check},
383
+ {"parallel": parallel, "cpus": cpus, "check": check},
300
384
  )
301
385
 
302
- def _parallel_cmd(
303
- self, cmd: Union[Sequence[Union[str, Path]], str, Path]
304
- ) -> Union[Sequence[Union[str, Path]], str]:
305
- if not is_sequence(cmd):
306
- return f"mpiexec -np {self._nprocessors} {cmd} -parallel"
307
- else:
308
- return [
309
- "mpiexec",
310
- "-np",
311
- str(self._nprocessors),
312
- cmd[0],
313
- "-parallel",
314
- *cmd[1:],
315
- ]
316
-
317
386
  @property
318
387
  def name(self) -> str:
319
388
  """The name of the case."""
foamlib/_cases/_sync.py CHANGED
@@ -3,14 +3,15 @@ import subprocess
3
3
  import sys
4
4
  from pathlib import Path
5
5
  from typing import (
6
+ Callable,
6
7
  Optional,
7
8
  Union,
8
9
  )
9
10
 
10
11
  if sys.version_info >= (3, 9):
11
- from collections.abc import Sequence
12
+ from collections.abc import Collection, Sequence
12
13
  else:
13
- from typing import Sequence
14
+ from typing import Collection, Sequence
14
15
 
15
16
  from .._util import is_sequence
16
17
  from ._base import FoamCaseBase
@@ -28,6 +29,22 @@ class FoamCase(FoamCaseBase):
28
29
  :param path: The path to the case directory.
29
30
  """
30
31
 
32
+ @staticmethod
33
+ def _rmtree(path: Path, *, ignore_errors: bool = False) -> None:
34
+ shutil.rmtree(path, ignore_errors=ignore_errors)
35
+
36
+ @staticmethod
37
+ def _copytree(
38
+ src: Path,
39
+ dest: Path,
40
+ *,
41
+ symlinks: bool = False,
42
+ ignore: Optional[
43
+ Callable[[Union[Path, str], Collection[str]], Collection[str]]
44
+ ] = None,
45
+ ) -> None:
46
+ shutil.copytree(src, dest, symlinks=symlinks, ignore=ignore)
47
+
31
48
  def clean(
32
49
  self,
33
50
  *,
@@ -40,25 +57,26 @@ class FoamCase(FoamCaseBase):
40
57
  :param script: If True, use an (All)clean script if it exists. If False, ignore any clean scripts.
41
58
  :param check: If True, raise a CalledProcessError if the clean script returns a non-zero exit code.
42
59
  """
43
- script_path = self._clean_script() if script else None
44
-
45
- if script_path is not None:
46
- self.run([script_path], check=check)
47
- else:
48
- for p in self._clean_paths():
49
- if p.is_dir():
50
- shutil.rmtree(p)
51
- else:
52
- p.unlink()
60
+ for name, args, kwargs in self._clean_cmds(script=script, check=check):
61
+ getattr(self, name)(*args, **kwargs)
53
62
 
54
63
  def _run(
55
64
  self,
56
65
  cmd: Union[Sequence[Union[str, Path]], str, Path],
57
66
  *,
67
+ parallel: bool = False,
68
+ cpus: int = 1,
58
69
  check: bool = True,
59
70
  ) -> None:
60
71
  shell = not is_sequence(cmd)
61
72
 
73
+ if parallel:
74
+ if shell:
75
+ cmd = f"mpiexec -np {cpus} {cmd} -parallel"
76
+ else:
77
+ assert is_sequence(cmd)
78
+ cmd = ["mpiexec", "-np", str(cpus), *cmd, "-parallel"]
79
+
62
80
  if sys.version_info < (3, 8):
63
81
  if shell:
64
82
  cmd = str(cmd)
@@ -113,8 +131,8 @@ class FoamCase(FoamCaseBase):
113
131
 
114
132
  def restore_0_dir(self) -> None:
115
133
  """Restore the 0 directory from the 0.orig directory."""
116
- shutil.rmtree(self.path / "0", ignore_errors=True)
117
- shutil.copytree(self.path / "0.orig", self.path / "0")
134
+ for name, args, kwargs in self._restore_0_dir_cmds():
135
+ getattr(self, name)(*args, **kwargs)
118
136
 
119
137
  def copy(self, dest: Union[Path, str]) -> "FoamCase":
120
138
  """
@@ -122,7 +140,10 @@ class FoamCase(FoamCaseBase):
122
140
 
123
141
  :param dest: The destination path.
124
142
  """
125
- return FoamCase(shutil.copytree(self.path, dest, symlinks=True))
143
+ for name, args, kwargs in self._copy_cmds(dest):
144
+ getattr(self, name)(*args, **kwargs)
145
+
146
+ return FoamCase(dest)
126
147
 
127
148
  def clone(self, dest: Union[Path, str]) -> "FoamCase":
128
149
  """
@@ -130,13 +151,7 @@ class FoamCase(FoamCaseBase):
130
151
 
131
152
  :param dest: The destination path.
132
153
  """
133
- if self._clean_script() is not None:
134
- copy = self.copy(dest)
135
- copy.clean()
136
- return copy
137
-
138
- dest = Path(dest)
139
-
140
- shutil.copytree(self.path, dest, symlinks=True, ignore=self._clone_ignore())
154
+ for name, args, kwargs in self._clone_cmds(dest):
155
+ getattr(self, name)(*args, **kwargs)
141
156
 
142
157
  return FoamCase(dest)
@@ -29,6 +29,7 @@ from pyparsing import (
29
29
  Word,
30
30
  c_style_comment,
31
31
  common,
32
+ counted_array,
32
33
  cpp_style_comment,
33
34
  identchars,
34
35
  printables,
@@ -42,12 +43,13 @@ def _list_of(entry: ParserElement) -> ParserElement:
42
43
  Literal("List") + Literal("<") + common.identifier + Literal(">")
43
44
  ).suppress() + (
44
45
  (
45
- Opt(common.integer).suppress()
46
- + (
47
- Literal("(").suppress()
48
- + Group((entry)[...], aslist=True)
49
- + Literal(")").suppress()
50
- )
46
+ counted_array(entry, common.integer + Literal("(").suppress())
47
+ + Literal(")").suppress()
48
+ ).set_parse_action(lambda tks: [tks.as_list()])
49
+ | (
50
+ Literal("(").suppress()
51
+ + Group((entry)[...], aslist=True)
52
+ + Literal(")").suppress()
51
53
  )
52
54
  | (
53
55
  common.integer + Literal("{").suppress() + entry + Literal("}").suppress()
@@ -76,54 +78,59 @@ def _keyword_entry_of(
76
78
  return keyword_entry
77
79
 
78
80
 
79
- _binary_contents = Forward()
80
-
81
-
82
- def _binary_field_parse_action(tks: ParseResults) -> None:
83
- global _binary_contents
84
-
85
- kind, count = tks
86
- if kind == "scalar":
87
- elsize = 1
88
- elif kind == "vector":
89
- elsize = 3
90
- elif kind == "symmTensor":
91
- elsize = 6
92
- elif kind == "tensor":
93
- elsize = 9
94
-
95
- def unpack(
96
- tks: ParseResults,
97
- ) -> Sequence[Union[Sequence[float], Sequence[Sequence[float]]]]:
98
- bytes_ = tks[0].encode("latin-1")
99
-
100
- arr = array.array("d", bytes_)
81
+ def _unpack_binary_field(
82
+ tks: ParseResults,
83
+ ) -> Sequence[Union[Sequence[float], Sequence[Sequence[float]]]]:
84
+ elsize = len(tks[0]) // 8
101
85
 
102
- if elsize != 1:
103
- all = [arr[i : i + elsize].tolist() for i in range(0, len(arr), elsize)]
104
- else:
105
- all = arr.tolist()
86
+ arr = array.array("d", "".join(tks).encode("latin-1"))
106
87
 
107
- return [all]
88
+ all: Union[Sequence[float], Sequence[Sequence[float]]]
108
89
 
109
- _binary_contents <<= CharsNotIn(exact=count * elsize * 8).set_parse_action(unpack)
90
+ if elsize != 1:
91
+ all = [arr[i : i + elsize].tolist() for i in range(0, len(arr), elsize)]
92
+ else:
93
+ all = arr.tolist()
110
94
 
111
- tks.clear() # type: ignore [no-untyped-call]
95
+ return [all]
112
96
 
113
97
 
114
98
  _BINARY_FIELD = (
115
- (
116
- Keyword("nonuniform").suppress()
117
- + Literal("List").suppress()
118
- + Literal("<").suppress()
119
- + common.identifier
120
- + Literal(">").suppress()
121
- + common.integer
122
- + Literal("(").suppress()
123
- ).set_parse_action(_binary_field_parse_action, call_during_try=True)
124
- + _binary_contents
99
+ Keyword("nonuniform").suppress()
100
+ + Literal("List").suppress()
101
+ + Literal("<").suppress()
102
+ + (
103
+ counted_array(
104
+ CharsNotIn(exact=8),
105
+ Literal("scalar").suppress()
106
+ + Literal(">").suppress()
107
+ + common.integer
108
+ + Literal("(").suppress(),
109
+ )
110
+ | counted_array(
111
+ CharsNotIn(exact=8 * 3),
112
+ Literal("vector").suppress()
113
+ + Literal(">").suppress()
114
+ + common.integer
115
+ + Literal("(").suppress(),
116
+ )
117
+ | counted_array(
118
+ CharsNotIn(exact=8 * 6),
119
+ Literal("symmTensor").suppress()
120
+ + Literal(">").suppress()
121
+ + common.integer
122
+ + Literal("(").suppress(),
123
+ )
124
+ | counted_array(
125
+ CharsNotIn(exact=8 * 9),
126
+ Literal("tensor").suppress()
127
+ + Literal(">").suppress()
128
+ + common.integer
129
+ + Literal("(").suppress(),
130
+ )
131
+ )
125
132
  + Literal(")").suppress()
126
- )
133
+ ).set_parse_action(_unpack_binary_field)
127
134
 
128
135
 
129
136
  _SWITCH = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.4.3
3
+ Version: 0.4.4
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
@@ -67,9 +67,9 @@ Requires-Dist: mypy <2,>=1 ; extra == 'typing'
67
67
 
68
68
  It offers the following classes:
69
69
 
70
- * [`FoamFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFile) (and [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#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.
71
- * [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
72
- * [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
70
+ * [`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.
71
+ * [`FoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
72
+ * [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/cases.html#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
73
73
 
74
74
  ## Get started
75
75
 
@@ -131,7 +131,6 @@ from foamlib import AsyncFoamCase
131
131
 
132
132
  async def run_case():
133
133
  my_pitz_async = AsyncFoamCase(my_pitz)
134
-
135
134
  await my_pitz_async.run()
136
135
 
137
136
  asyncio.run(run_case())
@@ -1,19 +1,19 @@
1
- foamlib/__init__.py,sha256=EfoThBRk5flPnxHT6JVA0jF01z42YT0I3RxCZR3fPp8,446
1
+ foamlib/__init__.py,sha256=r8VZ1cNvef7NfWWxf7GzPuveJO3LrXVwrF5pwgok-eg,446
2
2
  foamlib/_util.py,sha256=UMzXmTFgvbp46w6k3oEZJoYC98pFgEK6LN5uLOwrlCg,397
3
3
  foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  foamlib/_cases/__init__.py,sha256=xnQpR64EvFtCh07qnSz7kjQ1IhJXjRDwaZWwQGZhGv4,280
5
- foamlib/_cases/_async.py,sha256=ehmAedDepDXaRdf8f0IznxDMYAQxoUWSIxbhxG_17Rw,6035
6
- foamlib/_cases/_base.py,sha256=JrYJplmXV84qwgerdVSCHz2rCI-KWB4IvTBPMkYpecw,12657
7
- foamlib/_cases/_sync.py,sha256=CloQgd-93jxfSXIt7J5NxcAu3N_iF3eXMKO-NfNOgi4,4522
5
+ foamlib/_cases/_async.py,sha256=WgEunau8GvkI-k4amS98Uxz8O0fZBxLWqzUY3uiAmQQ,6345
6
+ foamlib/_cases/_base.py,sha256=4sndDYfXPWhkSel41e8d00xX3PX22wMrYniA_zb0luo,14958
7
+ foamlib/_cases/_sync.py,sha256=S-9-TOK7PTC3NMKgIdvKWTn4fS34FPccedvm-lpjpH8,5037
8
8
  foamlib/_cases/_util.py,sha256=v6sHxHCEgagsVuup0S1xJW-x9py5xj3bUye8PiFfb3o,925
9
9
  foamlib/_files/__init__.py,sha256=-UqB9YTH6mrJfXCX00kPTAAY20XG64u1MGPw_1ewLVs,148
10
10
  foamlib/_files/_base.py,sha256=zaFDjLE6jB7WtGWk8hfKusjLtlGu6CZV16AHJpRUibs,1929
11
11
  foamlib/_files/_files.py,sha256=-3mDRIsaQaxHF74q0Zfzlrhfieb7w_EPOFScSx8wRPE,16245
12
12
  foamlib/_files/_io.py,sha256=f_tYI7AqaFsQ8mtK__fEoIUqpYb3YmrI8X5D8updmNM,2084
13
- foamlib/_files/_parsing.py,sha256=ZDEnMdLfTCn82I5E-IOv-PxGv4w7N2Nvtc4NX7-m0MA,8383
13
+ foamlib/_files/_parsing.py,sha256=8V2CKZ45mKE3f9fP8lAfexIdhPGrq7elIZkpBkkGB6Q,8773
14
14
  foamlib/_files/_serialization.py,sha256=3yb9fgjCpDoRfZoLsbZaIFrkZ3vGBzleFRw6IbaZuuY,3408
15
- foamlib-0.4.3.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
16
- foamlib-0.4.3.dist-info/METADATA,sha256=M-Cy5LK8xxGL-jEtA7jZ0p5y_7iZ-Co6yTePRg1czb0,5457
17
- foamlib-0.4.3.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
18
- foamlib-0.4.3.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
19
- foamlib-0.4.3.dist-info/RECORD,,
15
+ foamlib-0.4.4.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
16
+ foamlib-0.4.4.dist-info/METADATA,sha256=i9qq7ZU7oFhmn1BO0rz-53wueFfOvEziP4am3x3qBA4,5496
17
+ foamlib-0.4.4.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
18
+ foamlib-0.4.4.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
19
+ foamlib-0.4.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.1.2)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5