foamlib 0.3.4__tar.gz → 0.3.5__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.3.4 → foamlib-0.3.5}/PKG-INFO +13 -3
- {foamlib-0.3.4 → foamlib-0.3.5}/README.md +12 -2
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/__init__.py +1 -1
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_cases.py +3 -13
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_files/__init__.py +1 -2
- foamlib-0.3.5/foamlib/_files/_files.py +340 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_files/_io.py +1 -1
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_files/_serialization.py +28 -49
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_util.py +14 -6
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib.egg-info/PKG-INFO +13 -3
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib.egg-info/SOURCES.txt +0 -1
- foamlib-0.3.4/foamlib/_files/_fields.py +0 -170
- foamlib-0.3.4/foamlib/_files/_files.py +0 -217
- {foamlib-0.3.4 → foamlib-0.3.5}/LICENSE.txt +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_files/_base.py +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/_files/_parsing.py +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib/py.typed +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib.egg-info/dependency_links.txt +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib.egg-info/requires.txt +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/foamlib.egg-info/top_level.txt +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/pyproject.toml +0 -0
- {foamlib-0.3.4 → foamlib-0.3.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.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
|
@@ -58,11 +58,11 @@ Requires-Dist: numpy<2,>=1; extra == "docs"
|
|
58
58
|
|
59
59
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
60
60
|
|
61
|
-
It offers the following classes
|
61
|
+
It offers the following classes:
|
62
62
|
|
63
|
+
* [`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.
|
63
64
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
64
65
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
65
|
-
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFile): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s.
|
66
66
|
|
67
67
|
## Get started
|
68
68
|
|
@@ -130,6 +130,16 @@ async def run_case():
|
|
130
130
|
asyncio.run(run_case())
|
131
131
|
```
|
132
132
|
|
133
|
+
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
134
|
+
|
135
|
+
```python
|
136
|
+
from foamlib import FoamFieldFile
|
137
|
+
|
138
|
+
U = FoamFieldFile(Path(my_pitz) / "0/U")
|
139
|
+
|
140
|
+
print(U.internal_field)
|
141
|
+
```
|
142
|
+
|
133
143
|
## Documentation
|
134
144
|
|
135
145
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -11,11 +11,11 @@
|
|
11
11
|
|
12
12
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
13
13
|
|
14
|
-
It offers the following classes
|
14
|
+
It offers the following classes:
|
15
15
|
|
16
|
+
* [`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.
|
16
17
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
17
18
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
18
|
-
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFile): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s.
|
19
19
|
|
20
20
|
## Get started
|
21
21
|
|
@@ -83,6 +83,16 @@ async def run_case():
|
|
83
83
|
asyncio.run(run_case())
|
84
84
|
```
|
85
85
|
|
86
|
+
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
87
|
+
|
88
|
+
```python
|
89
|
+
from foamlib import FoamFieldFile
|
90
|
+
|
91
|
+
U = FoamFieldFile(Path(my_pitz) / "0/U")
|
92
|
+
|
93
|
+
print(U.internal_field)
|
94
|
+
```
|
95
|
+
|
86
96
|
## Documentation
|
87
97
|
|
88
98
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import asyncio
|
2
2
|
import multiprocessing
|
3
|
-
import os
|
4
3
|
import shutil
|
5
4
|
import sys
|
6
5
|
from contextlib import asynccontextmanager
|
@@ -17,13 +16,12 @@ if sys.version_info >= (3, 9):
|
|
17
16
|
Callable,
|
18
17
|
Collection,
|
19
18
|
Iterator,
|
20
|
-
Mapping,
|
21
19
|
Sequence,
|
22
20
|
Set,
|
23
21
|
)
|
24
22
|
else:
|
25
23
|
from typing import AbstractSet as Set
|
26
|
-
from typing import AsyncGenerator, Callable, Collection, Iterator,
|
24
|
+
from typing import AsyncGenerator, Callable, Collection, Iterator, Sequence
|
27
25
|
|
28
26
|
import aioshutil
|
29
27
|
|
@@ -87,7 +85,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
87
85
|
return str(self.path)
|
88
86
|
|
89
87
|
def __repr__(self) -> str:
|
90
|
-
return f"{type(self).
|
88
|
+
return f"{type(self).__qualname__}('{self.path}')"
|
91
89
|
|
92
90
|
def __str__(self) -> str:
|
93
91
|
return str(self.path)
|
@@ -203,12 +201,6 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
203
201
|
else:
|
204
202
|
return None
|
205
203
|
|
206
|
-
def _env(self) -> Mapping[str, str]:
|
207
|
-
"""Return the environment variables for this case."""
|
208
|
-
env = os.environ.copy()
|
209
|
-
env["PWD"] = str(self.path)
|
210
|
-
return env
|
211
|
-
|
212
204
|
def _parallel_cmd(
|
213
205
|
self, cmd: Union[Sequence[Union[str, Path]], str, Path]
|
214
206
|
) -> Union[Sequence[Union[str, Path]], str]:
|
@@ -298,7 +290,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
|
298
290
|
return str(self.path)
|
299
291
|
|
300
292
|
def __repr__(self) -> str:
|
301
|
-
return f"{type(self).
|
293
|
+
return f"{type(self).__qualname__}('{self.path}')"
|
302
294
|
|
303
295
|
def __str__(self) -> str:
|
304
296
|
return str(self.path)
|
@@ -359,7 +351,6 @@ class FoamCase(FoamCaseBase):
|
|
359
351
|
cmd,
|
360
352
|
check=check,
|
361
353
|
cwd=self.path,
|
362
|
-
env=self._env(),
|
363
354
|
)
|
364
355
|
else:
|
365
356
|
script_path = self._run_script(parallel=parallel) if script else None
|
@@ -522,7 +513,6 @@ class AsyncFoamCase(FoamCaseBase):
|
|
522
513
|
cmd,
|
523
514
|
check=check,
|
524
515
|
cwd=self.path,
|
525
|
-
env=self._env(),
|
526
516
|
)
|
527
517
|
else:
|
528
518
|
script_path = self._run_script(parallel=parallel) if script else None
|
@@ -0,0 +1,340 @@
|
|
1
|
+
import sys
|
2
|
+
from typing import Any, Tuple, Union, cast
|
3
|
+
|
4
|
+
if sys.version_info >= (3, 9):
|
5
|
+
from collections.abc import Iterator, Mapping, MutableMapping, Sequence
|
6
|
+
else:
|
7
|
+
from typing import Iterator, Mapping, MutableMapping, Sequence
|
8
|
+
|
9
|
+
from ._base import FoamDict
|
10
|
+
from ._io import FoamFileIO
|
11
|
+
from ._serialization import Kind, dumpb
|
12
|
+
|
13
|
+
try:
|
14
|
+
import numpy as np
|
15
|
+
except ModuleNotFoundError:
|
16
|
+
pass
|
17
|
+
|
18
|
+
|
19
|
+
class FoamFile(
|
20
|
+
FoamDict,
|
21
|
+
MutableMapping[
|
22
|
+
Union[str, Tuple[str, ...]], Union["FoamFile.Data", "FoamFile.SubDict"]
|
23
|
+
],
|
24
|
+
FoamFileIO,
|
25
|
+
):
|
26
|
+
"""
|
27
|
+
An OpenFOAM dictionary file.
|
28
|
+
|
29
|
+
Use as a mutable mapping (i.e., like a dict) to access and modify entries.
|
30
|
+
|
31
|
+
Use as a context manager to make multiple changes to the file while saving all changes only once at the end.
|
32
|
+
"""
|
33
|
+
|
34
|
+
class SubDict(
|
35
|
+
FoamDict,
|
36
|
+
MutableMapping[str, Union["FoamFile.Data", "FoamFile.SubDict"]],
|
37
|
+
):
|
38
|
+
"""An OpenFOAM dictionary within a file as a mutable mapping."""
|
39
|
+
|
40
|
+
def __init__(self, _file: "FoamFile", _keywords: Tuple[str, ...]) -> None:
|
41
|
+
self._file = _file
|
42
|
+
self._keywords = _keywords
|
43
|
+
|
44
|
+
def __getitem__(
|
45
|
+
self, keyword: str
|
46
|
+
) -> Union["FoamFile.Data", "FoamFile.SubDict"]:
|
47
|
+
return self._file[(*self._keywords, keyword)]
|
48
|
+
|
49
|
+
def __setitem__(
|
50
|
+
self,
|
51
|
+
keyword: str,
|
52
|
+
data: "FoamFile._SetData",
|
53
|
+
) -> None:
|
54
|
+
self._file[(*self._keywords, keyword)] = data
|
55
|
+
|
56
|
+
def __delitem__(self, keyword: str) -> None:
|
57
|
+
del self._file[(*self._keywords, keyword)]
|
58
|
+
|
59
|
+
def __iter__(self) -> Iterator[str]:
|
60
|
+
return self._file._iter(self._keywords)
|
61
|
+
|
62
|
+
def __contains__(self, keyword: object) -> bool:
|
63
|
+
return (*self._keywords, keyword) in self._file
|
64
|
+
|
65
|
+
def __len__(self) -> int:
|
66
|
+
return len(list(iter(self)))
|
67
|
+
|
68
|
+
def update(self, *args: Any, **kwargs: Any) -> None:
|
69
|
+
with self._file:
|
70
|
+
super().update(*args, **kwargs)
|
71
|
+
|
72
|
+
def clear(self) -> None:
|
73
|
+
with self._file:
|
74
|
+
super().clear()
|
75
|
+
|
76
|
+
def __repr__(self) -> str:
|
77
|
+
return f"{type(self).__qualname__}('{self._file}', {self._keywords})"
|
78
|
+
|
79
|
+
def as_dict(self) -> FoamDict._Dict:
|
80
|
+
"""Return a nested dict representation of the dictionary."""
|
81
|
+
ret = self._file.as_dict()
|
82
|
+
|
83
|
+
for k in self._keywords:
|
84
|
+
assert isinstance(ret, dict)
|
85
|
+
v = ret[k]
|
86
|
+
assert isinstance(v, dict)
|
87
|
+
ret = v
|
88
|
+
|
89
|
+
return ret
|
90
|
+
|
91
|
+
def __getitem__(
|
92
|
+
self, keywords: Union[str, Tuple[str, ...]]
|
93
|
+
) -> Union["FoamFile.Data", "FoamFile.SubDict"]:
|
94
|
+
if not isinstance(keywords, tuple):
|
95
|
+
keywords = (keywords,)
|
96
|
+
|
97
|
+
_, parsed = self._read()
|
98
|
+
|
99
|
+
value = parsed[keywords]
|
100
|
+
|
101
|
+
if value is ...:
|
102
|
+
return FoamFile.SubDict(self, keywords)
|
103
|
+
else:
|
104
|
+
return value # type: ignore [return-value]
|
105
|
+
|
106
|
+
@property
|
107
|
+
def _binary(self) -> bool:
|
108
|
+
return self.get(("FoamFile", "format"), None) == "binary"
|
109
|
+
|
110
|
+
def __setitem__(
|
111
|
+
self,
|
112
|
+
keywords: Union[str, Tuple[str, ...]],
|
113
|
+
data: "FoamFile._SetData",
|
114
|
+
*,
|
115
|
+
assume_field: bool = False,
|
116
|
+
assume_dimensions: bool = False,
|
117
|
+
) -> None:
|
118
|
+
if not isinstance(keywords, tuple):
|
119
|
+
keywords = (keywords,)
|
120
|
+
|
121
|
+
kind = Kind.DEFAULT
|
122
|
+
if keywords == ("internalField",) or (
|
123
|
+
len(keywords) == 3
|
124
|
+
and keywords[0] == "boundaryField"
|
125
|
+
and keywords[2] == "value"
|
126
|
+
):
|
127
|
+
kind = Kind.BINARY_FIELD if self._binary else Kind.FIELD
|
128
|
+
elif keywords == ("dimensions",):
|
129
|
+
kind = Kind.DIMENSIONS
|
130
|
+
|
131
|
+
contents, parsed = self._read()
|
132
|
+
|
133
|
+
if isinstance(data, Mapping):
|
134
|
+
with self:
|
135
|
+
if isinstance(data, FoamDict):
|
136
|
+
data = data.as_dict()
|
137
|
+
|
138
|
+
start, end = parsed.entry_location(keywords, missing_ok=True)
|
139
|
+
|
140
|
+
self._write(
|
141
|
+
contents[:start]
|
142
|
+
+ b"\n"
|
143
|
+
+ dumpb({keywords[-1]: {}})
|
144
|
+
+ b"\n"
|
145
|
+
+ contents[end:]
|
146
|
+
)
|
147
|
+
|
148
|
+
for k, v in data.items():
|
149
|
+
self[(*keywords, k)] = v
|
150
|
+
else:
|
151
|
+
start, end = parsed.entry_location(keywords, missing_ok=True)
|
152
|
+
|
153
|
+
self._write(
|
154
|
+
contents[:start]
|
155
|
+
+ b"\n"
|
156
|
+
+ dumpb({keywords[-1]: data}, kind=kind)
|
157
|
+
+ b"\n"
|
158
|
+
+ contents[end:]
|
159
|
+
)
|
160
|
+
|
161
|
+
def __delitem__(self, keywords: Union[str, Tuple[str, ...]]) -> None:
|
162
|
+
if not isinstance(keywords, tuple):
|
163
|
+
keywords = (keywords,)
|
164
|
+
|
165
|
+
contents, parsed = self._read()
|
166
|
+
|
167
|
+
start, end = parsed.entry_location(keywords)
|
168
|
+
|
169
|
+
self._write(contents[:start] + contents[end:])
|
170
|
+
|
171
|
+
def _iter(self, keywords: Union[str, Tuple[str, ...]] = ()) -> Iterator[str]:
|
172
|
+
if not isinstance(keywords, tuple):
|
173
|
+
keywords = (keywords,)
|
174
|
+
|
175
|
+
_, parsed = self._read()
|
176
|
+
|
177
|
+
yield from (k[-1] for k in parsed if k[:-1] == keywords)
|
178
|
+
|
179
|
+
def __iter__(self) -> Iterator[str]:
|
180
|
+
return self._iter()
|
181
|
+
|
182
|
+
def __contains__(self, keywords: object) -> bool:
|
183
|
+
if not isinstance(keywords, tuple):
|
184
|
+
keywords = (keywords,)
|
185
|
+
_, parsed = self._read()
|
186
|
+
return keywords in parsed
|
187
|
+
|
188
|
+
def __len__(self) -> int:
|
189
|
+
return len(list(iter(self)))
|
190
|
+
|
191
|
+
def update(self, *args: Any, **kwargs: Any) -> None:
|
192
|
+
with self:
|
193
|
+
super().update(*args, **kwargs)
|
194
|
+
|
195
|
+
def clear(self) -> None:
|
196
|
+
with self:
|
197
|
+
super().clear()
|
198
|
+
|
199
|
+
def __fspath__(self) -> str:
|
200
|
+
return str(self.path)
|
201
|
+
|
202
|
+
def as_dict(self) -> FoamDict._Dict:
|
203
|
+
"""Return a nested dict representation of the file."""
|
204
|
+
_, parsed = self._read()
|
205
|
+
return parsed.as_dict()
|
206
|
+
|
207
|
+
|
208
|
+
class FoamFieldFile(FoamFile):
|
209
|
+
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
210
|
+
|
211
|
+
class BoundariesSubDict(FoamFile.SubDict):
|
212
|
+
def __getitem__(self, keyword: str) -> "FoamFieldFile.BoundarySubDict":
|
213
|
+
value = super().__getitem__(keyword)
|
214
|
+
if not isinstance(value, FoamFieldFile.BoundarySubDict):
|
215
|
+
assert not isinstance(value, FoamFile.SubDict)
|
216
|
+
raise TypeError(f"boundary {keyword} is not a dictionary")
|
217
|
+
return value
|
218
|
+
|
219
|
+
class BoundarySubDict(FoamFile.SubDict):
|
220
|
+
"""An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
|
221
|
+
|
222
|
+
@property
|
223
|
+
def type(self) -> str:
|
224
|
+
"""Alias of `self["type"]`."""
|
225
|
+
ret = self["type"]
|
226
|
+
if not isinstance(ret, str):
|
227
|
+
raise TypeError("type is not a string")
|
228
|
+
return ret
|
229
|
+
|
230
|
+
@type.setter
|
231
|
+
def type(self, data: str) -> None:
|
232
|
+
self["type"] = data
|
233
|
+
|
234
|
+
@property
|
235
|
+
def value(
|
236
|
+
self,
|
237
|
+
) -> Union[
|
238
|
+
int,
|
239
|
+
float,
|
240
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
241
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
242
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
243
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
244
|
+
]:
|
245
|
+
"""Alias of `self["value"]`."""
|
246
|
+
ret = self["value"]
|
247
|
+
if not isinstance(ret, (int, float, Sequence)):
|
248
|
+
raise TypeError("value is not a field")
|
249
|
+
return cast(
|
250
|
+
Union[
|
251
|
+
int, float, Sequence[Union[int, float, Sequence[Union[int, float]]]]
|
252
|
+
],
|
253
|
+
ret,
|
254
|
+
)
|
255
|
+
|
256
|
+
@value.setter
|
257
|
+
def value(
|
258
|
+
self,
|
259
|
+
value: Union[
|
260
|
+
int,
|
261
|
+
float,
|
262
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
263
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
264
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
265
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
266
|
+
],
|
267
|
+
) -> None:
|
268
|
+
self["value"] = value
|
269
|
+
|
270
|
+
@value.deleter
|
271
|
+
def value(self) -> None:
|
272
|
+
del self["value"]
|
273
|
+
|
274
|
+
def __getitem__(
|
275
|
+
self, keywords: Union[str, Tuple[str, ...]]
|
276
|
+
) -> Union[FoamFile.Data, FoamFile.SubDict]:
|
277
|
+
if not isinstance(keywords, tuple):
|
278
|
+
keywords = (keywords,)
|
279
|
+
|
280
|
+
ret = super().__getitem__(keywords)
|
281
|
+
if keywords[0] == "boundaryField" and isinstance(ret, FoamFile.SubDict):
|
282
|
+
if len(keywords) == 1:
|
283
|
+
ret = FoamFieldFile.BoundariesSubDict(self, keywords)
|
284
|
+
elif len(keywords) == 2:
|
285
|
+
ret = FoamFieldFile.BoundarySubDict(self, keywords)
|
286
|
+
return ret
|
287
|
+
|
288
|
+
@property
|
289
|
+
def dimensions(self) -> Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]:
|
290
|
+
"""Alias of `self["dimensions"]`."""
|
291
|
+
ret = self["dimensions"]
|
292
|
+
if not isinstance(ret, FoamFile.DimensionSet):
|
293
|
+
raise TypeError("dimensions is not a DimensionSet")
|
294
|
+
return ret
|
295
|
+
|
296
|
+
@dimensions.setter
|
297
|
+
def dimensions(
|
298
|
+
self, value: Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]
|
299
|
+
) -> None:
|
300
|
+
self["dimensions"] = value
|
301
|
+
|
302
|
+
@property
|
303
|
+
def internal_field(
|
304
|
+
self,
|
305
|
+
) -> Union[
|
306
|
+
int,
|
307
|
+
float,
|
308
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
309
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
310
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
311
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
312
|
+
]:
|
313
|
+
"""Alias of `self["internalField"]`."""
|
314
|
+
ret = self["internalField"]
|
315
|
+
if not isinstance(ret, (int, float, Sequence)):
|
316
|
+
raise TypeError("internalField is not a field")
|
317
|
+
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
318
|
+
|
319
|
+
@internal_field.setter
|
320
|
+
def internal_field(
|
321
|
+
self,
|
322
|
+
value: Union[
|
323
|
+
int,
|
324
|
+
float,
|
325
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
326
|
+
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
327
|
+
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
328
|
+
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
329
|
+
],
|
330
|
+
) -> None:
|
331
|
+
self["internalField"] = value
|
332
|
+
|
333
|
+
@property
|
334
|
+
def boundary_field(self) -> "FoamFieldFile.BoundariesSubDict":
|
335
|
+
"""Alias of `self["boundaryField"]`."""
|
336
|
+
ret = self["boundaryField"]
|
337
|
+
if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
|
338
|
+
assert not isinstance(ret, FoamFile.SubDict)
|
339
|
+
raise TypeError("boundaryField is not a dictionary")
|
340
|
+
return ret
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import array
|
2
2
|
import itertools
|
3
3
|
import sys
|
4
|
+
from enum import Enum, auto
|
4
5
|
|
5
6
|
if sys.version_info >= (3, 9):
|
6
7
|
from collections.abc import Mapping
|
@@ -18,33 +19,26 @@ except ModuleNotFoundError:
|
|
18
19
|
numpy = False
|
19
20
|
|
20
21
|
|
22
|
+
class Kind(Enum):
|
23
|
+
DEFAULT = auto()
|
24
|
+
LIST_ENTRY = auto()
|
25
|
+
FIELD = auto()
|
26
|
+
BINARY_FIELD = auto()
|
27
|
+
DIMENSIONS = auto()
|
28
|
+
|
29
|
+
|
21
30
|
def dumpb(
|
22
31
|
data: FoamDict._SetData,
|
23
32
|
*,
|
24
|
-
|
25
|
-
assume_dimensions: bool = False,
|
26
|
-
assume_data_entries: bool = False,
|
27
|
-
binary_fields: bool = False,
|
33
|
+
kind: Kind = Kind.DEFAULT,
|
28
34
|
) -> bytes:
|
29
35
|
if numpy and isinstance(data, np.ndarray):
|
30
|
-
return dumpb(
|
31
|
-
data.tolist(),
|
32
|
-
assume_field=assume_field,
|
33
|
-
assume_dimensions=assume_dimensions,
|
34
|
-
assume_data_entries=assume_data_entries,
|
35
|
-
binary_fields=binary_fields,
|
36
|
-
)
|
36
|
+
return dumpb(data.tolist(), kind=kind)
|
37
37
|
|
38
38
|
elif isinstance(data, Mapping):
|
39
39
|
entries = []
|
40
40
|
for k, v in data.items():
|
41
|
-
b = dumpb(
|
42
|
-
v,
|
43
|
-
assume_field=assume_field,
|
44
|
-
assume_dimensions=assume_dimensions,
|
45
|
-
assume_data_entries=True,
|
46
|
-
binary_fields=binary_fields,
|
47
|
-
)
|
41
|
+
b = dumpb(v, kind=kind)
|
48
42
|
if isinstance(v, Mapping):
|
49
43
|
entries.append(dumpb(k) + b"\n" + b"{\n" + b + b"\n}")
|
50
44
|
elif b:
|
@@ -55,11 +49,11 @@ def dumpb(
|
|
55
49
|
return b"\n".join(entries)
|
56
50
|
|
57
51
|
elif isinstance(data, FoamDict.DimensionSet) or (
|
58
|
-
|
52
|
+
kind == Kind.DIMENSIONS and is_sequence(data) and len(data) == 7
|
59
53
|
):
|
60
54
|
return b"[" + b" ".join(dumpb(v) for v in data) + b"]"
|
61
55
|
|
62
|
-
elif
|
56
|
+
elif (kind == Kind.FIELD or kind == Kind.BINARY_FIELD) and (
|
63
57
|
isinstance(data, (int, float))
|
64
58
|
or is_sequence(data)
|
65
59
|
and data
|
@@ -68,25 +62,20 @@ def dumpb(
|
|
68
62
|
):
|
69
63
|
return b"uniform " + dumpb(data)
|
70
64
|
|
71
|
-
elif
|
65
|
+
elif (kind == Kind.FIELD or kind == Kind.BINARY_FIELD) and is_sequence(data):
|
72
66
|
if isinstance(data[0], (int, float)):
|
73
|
-
|
67
|
+
tensor_kind = b"scalar"
|
74
68
|
elif len(data[0]) == 3:
|
75
|
-
|
69
|
+
tensor_kind = b"vector"
|
76
70
|
elif len(data[0]) == 6:
|
77
|
-
|
71
|
+
tensor_kind = b"symmTensor"
|
78
72
|
elif len(data[0]) == 9:
|
79
|
-
|
73
|
+
tensor_kind = b"tensor"
|
80
74
|
else:
|
81
|
-
return dumpb(
|
82
|
-
data,
|
83
|
-
assume_dimensions=assume_dimensions,
|
84
|
-
assume_data_entries=assume_data_entries,
|
85
|
-
binary_fields=binary_fields,
|
86
|
-
)
|
75
|
+
return dumpb(data)
|
87
76
|
|
88
|
-
if
|
89
|
-
if
|
77
|
+
if kind == Kind.BINARY_FIELD:
|
78
|
+
if tensor_kind == b"scalar":
|
90
79
|
contents = b"(" + array.array("d", data).tobytes() + b")"
|
91
80
|
else:
|
92
81
|
contents = (
|
@@ -97,37 +86,27 @@ def dumpb(
|
|
97
86
|
else:
|
98
87
|
contents = dumpb(data)
|
99
88
|
|
100
|
-
return b"nonuniform List<" +
|
89
|
+
return b"nonuniform List<" + tensor_kind + b"> " + dumpb(len(data)) + contents
|
101
90
|
|
102
|
-
elif
|
103
|
-
return b" ".join(
|
104
|
-
dumpb(
|
105
|
-
v,
|
106
|
-
assume_field=assume_field,
|
107
|
-
assume_dimensions=assume_dimensions,
|
108
|
-
binary_fields=binary_fields,
|
109
|
-
)
|
110
|
-
for v in data
|
111
|
-
)
|
91
|
+
elif kind != Kind.LIST_ENTRY and isinstance(data, tuple):
|
92
|
+
return b" ".join(dumpb(v) for v in data)
|
112
93
|
|
113
94
|
elif isinstance(data, FoamDict.Dimensioned):
|
114
95
|
if data.name is not None:
|
115
96
|
return (
|
116
97
|
dumpb(data.name)
|
117
98
|
+ b" "
|
118
|
-
+ dumpb(data.dimensions,
|
99
|
+
+ dumpb(data.dimensions, kind=Kind.DIMENSIONS)
|
119
100
|
+ b" "
|
120
101
|
+ dumpb(data.value)
|
121
102
|
)
|
122
103
|
else:
|
123
104
|
return (
|
124
|
-
dumpb(data.dimensions,
|
125
|
-
+ b" "
|
126
|
-
+ dumpb(data.value)
|
105
|
+
dumpb(data.dimensions, kind=Kind.DIMENSIONS) + b" " + dumpb(data.value)
|
127
106
|
)
|
128
107
|
|
129
108
|
elif is_sequence(data):
|
130
|
-
return b"(" + b" ".join(dumpb(v) for v in data) + b")"
|
109
|
+
return b"(" + b" ".join(dumpb(v, kind=Kind.LIST_ENTRY) for v in data) + b")"
|
131
110
|
|
132
111
|
elif data is True:
|
133
112
|
return b"yes"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import asyncio
|
2
|
+
import os
|
2
3
|
import subprocess
|
3
4
|
import sys
|
4
5
|
from pathlib import Path
|
@@ -47,12 +48,20 @@ def _check(
|
|
47
48
|
warn(f"Command {cmd} printed to stderr.\n{stderr}", CalledProcessWarning)
|
48
49
|
|
49
50
|
|
51
|
+
def _env(cwd: Optional[Union[str, Path]] = None) -> Optional[Mapping[str, str]]:
|
52
|
+
if cwd is not None:
|
53
|
+
env = os.environ.copy()
|
54
|
+
env["PWD"] = str(cwd)
|
55
|
+
return env
|
56
|
+
else:
|
57
|
+
return None
|
58
|
+
|
59
|
+
|
50
60
|
def run_process(
|
51
61
|
cmd: Union[Sequence[Union[str, Path]], str, Path],
|
52
62
|
*,
|
53
63
|
check: bool = True,
|
54
64
|
cwd: Union[None, str, Path] = None,
|
55
|
-
env: Union[None, Mapping[str, str]] = None,
|
56
65
|
) -> None:
|
57
66
|
shell = not is_sequence(cmd)
|
58
67
|
|
@@ -65,8 +74,8 @@ def run_process(
|
|
65
74
|
proc = subprocess.run(
|
66
75
|
cmd,
|
67
76
|
cwd=cwd,
|
68
|
-
env=
|
69
|
-
stdout=
|
77
|
+
env=_env(cwd),
|
78
|
+
stdout=None,
|
70
79
|
stderr=subprocess.PIPE if check else subprocess.DEVNULL,
|
71
80
|
text=True,
|
72
81
|
shell=shell,
|
@@ -81,13 +90,12 @@ async def run_process_async(
|
|
81
90
|
*,
|
82
91
|
check: bool = True,
|
83
92
|
cwd: Union[None, str, Path] = None,
|
84
|
-
env: Union[None, Mapping[str, str]] = None,
|
85
93
|
) -> None:
|
86
94
|
if not is_sequence(cmd):
|
87
95
|
proc = await asyncio.create_subprocess_shell(
|
88
96
|
str(cmd),
|
89
97
|
cwd=cwd,
|
90
|
-
env=
|
98
|
+
env=_env(cwd),
|
91
99
|
stdout=asyncio.subprocess.DEVNULL,
|
92
100
|
stderr=asyncio.subprocess.PIPE if check else asyncio.subprocess.DEVNULL,
|
93
101
|
)
|
@@ -98,7 +106,7 @@ async def run_process_async(
|
|
98
106
|
proc = await asyncio.create_subprocess_exec(
|
99
107
|
*cmd,
|
100
108
|
cwd=cwd,
|
101
|
-
env=
|
109
|
+
env=_env(cwd),
|
102
110
|
stdout=asyncio.subprocess.DEVNULL,
|
103
111
|
stderr=asyncio.subprocess.PIPE if check else asyncio.subprocess.DEVNULL,
|
104
112
|
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.3.
|
3
|
+
Version: 0.3.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
|
@@ -58,11 +58,11 @@ Requires-Dist: numpy<2,>=1; extra == "docs"
|
|
58
58
|
|
59
59
|
**foamlib** provides a simple, modern and ergonomic Python interface for interacting with [OpenFOAM](https://www.openfoam.com).
|
60
60
|
|
61
|
-
It offers the following classes
|
61
|
+
It offers the following classes:
|
62
62
|
|
63
|
+
* [`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.
|
63
64
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
64
65
|
* [`AsyncFoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.AsyncFoamCase): variant of `FoamCase` with asynchronous methods for running multiple cases at once.
|
65
|
-
* [`FoamFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFile): read-write access to OpenFOAM configuration and field files as if they were Python `dict`s.
|
66
66
|
|
67
67
|
## Get started
|
68
68
|
|
@@ -130,6 +130,16 @@ async def run_case():
|
|
130
130
|
asyncio.run(run_case())
|
131
131
|
```
|
132
132
|
|
133
|
+
### Parse a field using the [`FoamFieldFile`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamFieldFile) class directly
|
134
|
+
|
135
|
+
```python
|
136
|
+
from foamlib import FoamFieldFile
|
137
|
+
|
138
|
+
U = FoamFieldFile(Path(my_pitz) / "0/U")
|
139
|
+
|
140
|
+
print(U.internal_field)
|
141
|
+
```
|
142
|
+
|
133
143
|
## Documentation
|
134
144
|
|
135
145
|
For more information, check out the [documentation](https://foamlib.readthedocs.io/).
|
@@ -1,170 +0,0 @@
|
|
1
|
-
import sys
|
2
|
-
from typing import Any, Tuple, Union, cast
|
3
|
-
|
4
|
-
if sys.version_info >= (3, 9):
|
5
|
-
from collections.abc import Sequence
|
6
|
-
else:
|
7
|
-
from typing import Sequence
|
8
|
-
|
9
|
-
from ._files import FoamFile
|
10
|
-
|
11
|
-
try:
|
12
|
-
import numpy as np
|
13
|
-
except ModuleNotFoundError:
|
14
|
-
pass
|
15
|
-
|
16
|
-
|
17
|
-
class FoamFieldFile(FoamFile):
|
18
|
-
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
19
|
-
|
20
|
-
class BoundariesSubDict(FoamFile.SubDict):
|
21
|
-
def __getitem__(self, keyword: str) -> "FoamFieldFile.BoundarySubDict":
|
22
|
-
value = super().__getitem__(keyword)
|
23
|
-
if not isinstance(value, FoamFieldFile.BoundarySubDict):
|
24
|
-
assert not isinstance(value, FoamFile.SubDict)
|
25
|
-
raise TypeError(f"boundary {keyword} is not a dictionary")
|
26
|
-
return value
|
27
|
-
|
28
|
-
class BoundarySubDict(FoamFile.SubDict):
|
29
|
-
"""An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
|
30
|
-
|
31
|
-
def __setitem__(
|
32
|
-
self,
|
33
|
-
keyword: str,
|
34
|
-
data: FoamFile._SetData,
|
35
|
-
) -> None:
|
36
|
-
if keyword == "value":
|
37
|
-
self._setitem(keyword, data, assume_field=True)
|
38
|
-
else:
|
39
|
-
self._setitem(keyword, data)
|
40
|
-
|
41
|
-
@property
|
42
|
-
def type(self) -> str:
|
43
|
-
"""Alias of `self["type"]`."""
|
44
|
-
ret = self["type"]
|
45
|
-
if not isinstance(ret, str):
|
46
|
-
raise TypeError("type is not a string")
|
47
|
-
return ret
|
48
|
-
|
49
|
-
@type.setter
|
50
|
-
def type(self, data: str) -> None:
|
51
|
-
self["type"] = data
|
52
|
-
|
53
|
-
@property
|
54
|
-
def value(
|
55
|
-
self,
|
56
|
-
) -> Union[
|
57
|
-
int,
|
58
|
-
float,
|
59
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
60
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
61
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
62
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
63
|
-
]:
|
64
|
-
"""Alias of `self["value"]`."""
|
65
|
-
ret = self["value"]
|
66
|
-
if not isinstance(ret, (int, float, Sequence)):
|
67
|
-
raise TypeError("value is not a field")
|
68
|
-
return cast(
|
69
|
-
Union[
|
70
|
-
int, float, Sequence[Union[int, float, Sequence[Union[int, float]]]]
|
71
|
-
],
|
72
|
-
ret,
|
73
|
-
)
|
74
|
-
|
75
|
-
@value.setter
|
76
|
-
def value(
|
77
|
-
self,
|
78
|
-
value: Union[
|
79
|
-
int,
|
80
|
-
float,
|
81
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
82
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
83
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
84
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
85
|
-
],
|
86
|
-
) -> None:
|
87
|
-
self["value"] = value
|
88
|
-
|
89
|
-
@value.deleter
|
90
|
-
def value(self) -> None:
|
91
|
-
del self["value"]
|
92
|
-
|
93
|
-
def __getitem__(
|
94
|
-
self, keywords: Union[str, Tuple[str, ...]]
|
95
|
-
) -> Union[FoamFile.Data, FoamFile.SubDict]:
|
96
|
-
if not isinstance(keywords, tuple):
|
97
|
-
keywords = (keywords,)
|
98
|
-
|
99
|
-
ret = super().__getitem__(keywords)
|
100
|
-
if keywords[0] == "boundaryField" and isinstance(ret, FoamFile.SubDict):
|
101
|
-
if len(keywords) == 1:
|
102
|
-
ret = FoamFieldFile.BoundariesSubDict(self, keywords)
|
103
|
-
elif len(keywords) == 2:
|
104
|
-
ret = FoamFieldFile.BoundarySubDict(self, keywords)
|
105
|
-
return ret
|
106
|
-
|
107
|
-
def __setitem__(self, keywords: Union[str, Tuple[str, ...]], value: Any) -> None:
|
108
|
-
if not isinstance(keywords, tuple):
|
109
|
-
keywords = (keywords,)
|
110
|
-
|
111
|
-
if keywords == ("internalField",):
|
112
|
-
self._setitem(keywords, value, assume_field=True)
|
113
|
-
elif keywords == ("dimensions",):
|
114
|
-
self._setitem(keywords, value, assume_dimensions=True)
|
115
|
-
else:
|
116
|
-
self._setitem(keywords, value)
|
117
|
-
|
118
|
-
@property
|
119
|
-
def dimensions(self) -> Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]:
|
120
|
-
"""Alias of `self["dimensions"]`."""
|
121
|
-
ret = self["dimensions"]
|
122
|
-
if not isinstance(ret, FoamFile.DimensionSet):
|
123
|
-
raise TypeError("dimensions is not a DimensionSet")
|
124
|
-
return ret
|
125
|
-
|
126
|
-
@dimensions.setter
|
127
|
-
def dimensions(
|
128
|
-
self, value: Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]
|
129
|
-
) -> None:
|
130
|
-
self["dimensions"] = value
|
131
|
-
|
132
|
-
@property
|
133
|
-
def internal_field(
|
134
|
-
self,
|
135
|
-
) -> Union[
|
136
|
-
int,
|
137
|
-
float,
|
138
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
139
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
140
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
141
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
142
|
-
]:
|
143
|
-
"""Alias of `self["internalField"]`."""
|
144
|
-
ret = self["internalField"]
|
145
|
-
if not isinstance(ret, (int, float, Sequence)):
|
146
|
-
raise TypeError("internalField is not a field")
|
147
|
-
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
148
|
-
|
149
|
-
@internal_field.setter
|
150
|
-
def internal_field(
|
151
|
-
self,
|
152
|
-
value: Union[
|
153
|
-
int,
|
154
|
-
float,
|
155
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
156
|
-
"np.ndarray[Tuple[()], np.dtype[np.generic]]",
|
157
|
-
"np.ndarray[Tuple[int], np.dtype[np.generic]]",
|
158
|
-
"np.ndarray[Tuple[int, int], np.dtype[np.generic]]",
|
159
|
-
],
|
160
|
-
) -> None:
|
161
|
-
self["internalField"] = value
|
162
|
-
|
163
|
-
@property
|
164
|
-
def boundary_field(self) -> "FoamFieldFile.BoundariesSubDict":
|
165
|
-
"""Alias of `self["boundaryField"]`."""
|
166
|
-
ret = self["boundaryField"]
|
167
|
-
if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
|
168
|
-
assert not isinstance(ret, FoamFile.SubDict)
|
169
|
-
raise TypeError("boundaryField is not a dictionary")
|
170
|
-
return ret
|
@@ -1,217 +0,0 @@
|
|
1
|
-
import sys
|
2
|
-
from typing import (
|
3
|
-
Any,
|
4
|
-
Tuple,
|
5
|
-
Union,
|
6
|
-
)
|
7
|
-
|
8
|
-
if sys.version_info >= (3, 9):
|
9
|
-
from collections.abc import Iterator, Mapping, MutableMapping
|
10
|
-
else:
|
11
|
-
from typing import Iterator, Mapping, MutableMapping
|
12
|
-
|
13
|
-
from ._base import FoamDict
|
14
|
-
from ._io import FoamFileIO
|
15
|
-
from ._serialization import dumpb
|
16
|
-
|
17
|
-
|
18
|
-
class FoamFile(
|
19
|
-
FoamDict,
|
20
|
-
MutableMapping[
|
21
|
-
Union[str, Tuple[str, ...]], Union["FoamFile.Data", "FoamFile.SubDict"]
|
22
|
-
],
|
23
|
-
FoamFileIO,
|
24
|
-
):
|
25
|
-
"""
|
26
|
-
An OpenFOAM dictionary file.
|
27
|
-
|
28
|
-
Use as a mutable mapping (i.e., like a dict) to access and modify entries.
|
29
|
-
|
30
|
-
Use as a context manager to make multiple changes to the file while saving all changes only once at the end.
|
31
|
-
"""
|
32
|
-
|
33
|
-
class SubDict(
|
34
|
-
FoamDict,
|
35
|
-
MutableMapping[str, Union["FoamFile.Data", "FoamFile.SubDict"]],
|
36
|
-
):
|
37
|
-
"""An OpenFOAM dictionary within a file as a mutable mapping."""
|
38
|
-
|
39
|
-
def __init__(self, _file: "FoamFile", _keywords: Tuple[str, ...]) -> None:
|
40
|
-
self._file = _file
|
41
|
-
self._keywords = _keywords
|
42
|
-
|
43
|
-
def __getitem__(
|
44
|
-
self, keyword: str
|
45
|
-
) -> Union["FoamFile.Data", "FoamFile.SubDict"]:
|
46
|
-
return self._file[(*self._keywords, keyword)]
|
47
|
-
|
48
|
-
def _setitem(
|
49
|
-
self,
|
50
|
-
keyword: str,
|
51
|
-
data: Any,
|
52
|
-
*,
|
53
|
-
assume_field: bool = False,
|
54
|
-
assume_dimensions: bool = False,
|
55
|
-
) -> None:
|
56
|
-
self._file._setitem(
|
57
|
-
(*self._keywords, keyword),
|
58
|
-
data,
|
59
|
-
assume_field=assume_field,
|
60
|
-
assume_dimensions=assume_dimensions,
|
61
|
-
)
|
62
|
-
|
63
|
-
def __setitem__(self, keyword: str, value: "FoamFile._SetData") -> None:
|
64
|
-
self._setitem(keyword, value)
|
65
|
-
|
66
|
-
def __delitem__(self, keyword: str) -> None:
|
67
|
-
del self._file[(*self._keywords, keyword)]
|
68
|
-
|
69
|
-
def __iter__(self) -> Iterator[str]:
|
70
|
-
return self._file._iter(self._keywords)
|
71
|
-
|
72
|
-
def __contains__(self, keyword: object) -> bool:
|
73
|
-
return (*self._keywords, keyword) in self._file
|
74
|
-
|
75
|
-
def __len__(self) -> int:
|
76
|
-
return len(list(iter(self)))
|
77
|
-
|
78
|
-
def update(self, *args: Any, **kwargs: Any) -> None:
|
79
|
-
with self._file:
|
80
|
-
super().update(*args, **kwargs)
|
81
|
-
|
82
|
-
def clear(self) -> None:
|
83
|
-
with self._file:
|
84
|
-
super().clear()
|
85
|
-
|
86
|
-
def __repr__(self) -> str:
|
87
|
-
return f"{type(self).__qualname__}('{self._file}', {self._keywords})"
|
88
|
-
|
89
|
-
def as_dict(self) -> FoamDict._Dict:
|
90
|
-
"""Return a nested dict representation of the dictionary."""
|
91
|
-
ret = self._file.as_dict()
|
92
|
-
|
93
|
-
for k in self._keywords:
|
94
|
-
assert isinstance(ret, dict)
|
95
|
-
v = ret[k]
|
96
|
-
assert isinstance(v, dict)
|
97
|
-
ret = v
|
98
|
-
|
99
|
-
return ret
|
100
|
-
|
101
|
-
def __getitem__(
|
102
|
-
self, keywords: Union[str, Tuple[str, ...]]
|
103
|
-
) -> Union["FoamFile.Data", "FoamFile.SubDict"]:
|
104
|
-
if not isinstance(keywords, tuple):
|
105
|
-
keywords = (keywords,)
|
106
|
-
|
107
|
-
_, parsed = self._read()
|
108
|
-
|
109
|
-
value = parsed[keywords]
|
110
|
-
|
111
|
-
if value is ...:
|
112
|
-
return FoamFile.SubDict(self, keywords)
|
113
|
-
else:
|
114
|
-
return value # type: ignore [return-value]
|
115
|
-
|
116
|
-
@property
|
117
|
-
def _binary(self) -> bool:
|
118
|
-
return self.get(("FoamFile", "format"), None) == "binary"
|
119
|
-
|
120
|
-
def _setitem(
|
121
|
-
self,
|
122
|
-
keywords: Union[str, Tuple[str, ...]],
|
123
|
-
data: "FoamFile._SetData",
|
124
|
-
*,
|
125
|
-
assume_field: bool = False,
|
126
|
-
assume_dimensions: bool = False,
|
127
|
-
) -> None:
|
128
|
-
if not isinstance(keywords, tuple):
|
129
|
-
keywords = (keywords,)
|
130
|
-
|
131
|
-
contents, parsed = self._read()
|
132
|
-
|
133
|
-
if isinstance(data, Mapping):
|
134
|
-
with self:
|
135
|
-
if isinstance(data, FoamDict):
|
136
|
-
data = data.as_dict()
|
137
|
-
|
138
|
-
start, end = parsed.entry_location(keywords, missing_ok=True)
|
139
|
-
|
140
|
-
self._write(
|
141
|
-
contents[:start]
|
142
|
-
+ b"\n"
|
143
|
-
+ dumpb({keywords[-1]: {}})
|
144
|
-
+ b"\n"
|
145
|
-
+ contents[end:]
|
146
|
-
)
|
147
|
-
|
148
|
-
for k, v in data.items():
|
149
|
-
self[(*keywords, k)] = v
|
150
|
-
else:
|
151
|
-
start, end = parsed.entry_location(keywords, missing_ok=True)
|
152
|
-
|
153
|
-
self._write(
|
154
|
-
contents[:start]
|
155
|
-
+ b"\n"
|
156
|
-
+ dumpb(
|
157
|
-
{keywords[-1]: data},
|
158
|
-
assume_field=assume_field,
|
159
|
-
assume_dimensions=assume_dimensions,
|
160
|
-
binary_fields=self._binary,
|
161
|
-
)
|
162
|
-
+ b"\n"
|
163
|
-
+ contents[end:]
|
164
|
-
)
|
165
|
-
|
166
|
-
def __setitem__(
|
167
|
-
self,
|
168
|
-
keywords: Union[str, Tuple[str, ...]],
|
169
|
-
data: "FoamFile._SetData",
|
170
|
-
) -> None:
|
171
|
-
self._setitem(keywords, data)
|
172
|
-
|
173
|
-
def __delitem__(self, keywords: Union[str, Tuple[str, ...]]) -> None:
|
174
|
-
if not isinstance(keywords, tuple):
|
175
|
-
keywords = (keywords,)
|
176
|
-
|
177
|
-
contents, parsed = self._read()
|
178
|
-
|
179
|
-
start, end = parsed.entry_location(keywords)
|
180
|
-
|
181
|
-
self._write(contents[:start] + contents[end:])
|
182
|
-
|
183
|
-
def _iter(self, keywords: Union[str, Tuple[str, ...]] = ()) -> Iterator[str]:
|
184
|
-
if not isinstance(keywords, tuple):
|
185
|
-
keywords = (keywords,)
|
186
|
-
|
187
|
-
_, parsed = self._read()
|
188
|
-
|
189
|
-
yield from (k[-1] for k in parsed if k[:-1] == keywords)
|
190
|
-
|
191
|
-
def __iter__(self) -> Iterator[str]:
|
192
|
-
return self._iter()
|
193
|
-
|
194
|
-
def __contains__(self, keywords: object) -> bool:
|
195
|
-
if not isinstance(keywords, tuple):
|
196
|
-
keywords = (keywords,)
|
197
|
-
_, parsed = self._read()
|
198
|
-
return keywords in parsed
|
199
|
-
|
200
|
-
def __len__(self) -> int:
|
201
|
-
return len(list(iter(self)))
|
202
|
-
|
203
|
-
def update(self, *args: Any, **kwargs: Any) -> None:
|
204
|
-
with self:
|
205
|
-
super().update(*args, **kwargs)
|
206
|
-
|
207
|
-
def clear(self) -> None:
|
208
|
-
with self:
|
209
|
-
super().clear()
|
210
|
-
|
211
|
-
def __fspath__(self) -> str:
|
212
|
-
return str(self.path)
|
213
|
-
|
214
|
-
def as_dict(self) -> FoamDict._Dict:
|
215
|
-
"""Return a nested dict representation of the file."""
|
216
|
-
_, parsed = self._read()
|
217
|
-
return parsed.as_dict()
|
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
|