foamlib 0.1.14__tar.gz → 0.2.0__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.1.14 → foamlib-0.2.0}/PKG-INFO +2 -2
- {foamlib-0.1.14 → foamlib-0.2.0}/README.md +1 -1
- foamlib-0.2.0/foamlib/__init__.py +12 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib/_cases.py +60 -59
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib/_dictionaries.py +306 -266
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib.egg-info/PKG-INFO +2 -2
- {foamlib-0.1.14 → foamlib-0.2.0}/pyproject.toml +0 -3
- {foamlib-0.1.14 → foamlib-0.2.0}/tests/test_dictionaries.py +52 -38
- foamlib-0.1.14/foamlib/__init__.py +0 -26
- {foamlib-0.1.14 → foamlib-0.2.0}/LICENSE.txt +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib/_subprocesses.py +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib/py.typed +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib.egg-info/SOURCES.txt +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib.egg-info/dependency_links.txt +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib.egg-info/requires.txt +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/foamlib.egg-info/top_level.txt +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/setup.cfg +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/tests/test_basic.py +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/tests/test_flange.py +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/tests/test_flange_async.py +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/tests/test_pitz.py +0 -0
- {foamlib-0.1.14 → foamlib-0.2.0}/tests/test_pitz_async.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
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
|
@@ -62,7 +62,7 @@ It offers the following classes (among a few others):
|
|
62
62
|
|
63
63
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
64
64
|
* [`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
|
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
|
|
@@ -15,7 +15,7 @@ It offers the following classes (among a few others):
|
|
15
15
|
|
16
16
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
17
17
|
* [`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
|
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
|
|
@@ -24,14 +24,65 @@ from ._subprocesses import run_process, run_process_async, CalledProcessError
|
|
24
24
|
from ._dictionaries import FoamFile, FoamFieldFile
|
25
25
|
|
26
26
|
|
27
|
-
class FoamCaseBase(Sequence["
|
27
|
+
class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
|
28
28
|
def __init__(self, path: Union[Path, str]):
|
29
29
|
self.path = Path(path).absolute()
|
30
30
|
if not self.path.is_dir():
|
31
31
|
raise NotADirectoryError(f"{self.path} is not a directory")
|
32
32
|
|
33
|
+
class TimeDirectory(Set[FoamFieldFile]):
|
34
|
+
"""
|
35
|
+
An OpenFOAM time directory in a case.
|
36
|
+
|
37
|
+
Use to access field files in the directory, e.g. `time["U"]`.
|
38
|
+
|
39
|
+
:param path: The path to the time directory.
|
40
|
+
"""
|
41
|
+
|
42
|
+
def __init__(self, path: Union[Path, str]):
|
43
|
+
self.path = Path(path).absolute()
|
44
|
+
if not self.path.is_dir():
|
45
|
+
raise NotADirectoryError(f"{self.path} is not a directory")
|
46
|
+
|
47
|
+
@property
|
48
|
+
def time(self) -> float:
|
49
|
+
"""
|
50
|
+
The time that corresponds to this directory.
|
51
|
+
"""
|
52
|
+
return float(self.path.name)
|
53
|
+
|
54
|
+
@property
|
55
|
+
def name(self) -> str:
|
56
|
+
"""
|
57
|
+
The name of this time directory.
|
58
|
+
"""
|
59
|
+
return self.path.name
|
60
|
+
|
61
|
+
def __getitem__(self, key: str) -> FoamFieldFile:
|
62
|
+
try:
|
63
|
+
return FoamFieldFile(self.path / key)
|
64
|
+
except FileNotFoundError as e:
|
65
|
+
raise KeyError(key) from e
|
66
|
+
|
67
|
+
def __iter__(self) -> Iterator[FoamFieldFile]:
|
68
|
+
for p in self.path.iterdir():
|
69
|
+
if p.is_file():
|
70
|
+
yield FoamFieldFile(p.name)
|
71
|
+
|
72
|
+
def __len__(self) -> int:
|
73
|
+
return len(list(iter(self)))
|
74
|
+
|
75
|
+
def __fspath__(self) -> str:
|
76
|
+
return str(self.path)
|
77
|
+
|
78
|
+
def __repr__(self) -> str:
|
79
|
+
return f"{type(self).__name__}({self.path})"
|
80
|
+
|
81
|
+
def __str__(self) -> str:
|
82
|
+
return str(self.path)
|
83
|
+
|
33
84
|
@property
|
34
|
-
def _times(self) -> Sequence["
|
85
|
+
def _times(self) -> Sequence["FoamCaseBase.TimeDirectory"]:
|
35
86
|
times = []
|
36
87
|
for p in self.path.iterdir():
|
37
88
|
if p.is_dir():
|
@@ -40,23 +91,25 @@ class FoamCaseBase(Sequence["FoamTimeDirectory"]):
|
|
40
91
|
except ValueError:
|
41
92
|
pass
|
42
93
|
else:
|
43
|
-
times.append(
|
94
|
+
times.append(FoamCaseBase.TimeDirectory(p))
|
44
95
|
|
45
96
|
times.sort(key=lambda t: t.time)
|
46
97
|
|
47
98
|
return times
|
48
99
|
|
49
100
|
@overload
|
50
|
-
def __getitem__(
|
101
|
+
def __getitem__(
|
102
|
+
self, index: Union[int, float, str]
|
103
|
+
) -> "FoamCaseBase.TimeDirectory": ...
|
51
104
|
|
52
105
|
@overload
|
53
|
-
def __getitem__(self, index: slice) -> Sequence["
|
106
|
+
def __getitem__(self, index: slice) -> Sequence["FoamCaseBase.TimeDirectory"]: ...
|
54
107
|
|
55
108
|
def __getitem__(
|
56
109
|
self, index: Union[int, slice, float, str]
|
57
|
-
) -> Union["
|
110
|
+
) -> Union["FoamCaseBase.TimeDirectory", Sequence["FoamCaseBase.TimeDirectory"]]:
|
58
111
|
if isinstance(index, str):
|
59
|
-
return
|
112
|
+
return FoamCaseBase.TimeDirectory(self.path / str(index))
|
60
113
|
elif isinstance(index, float):
|
61
114
|
for time in self._times:
|
62
115
|
if time.time == index:
|
@@ -598,55 +651,3 @@ class AsyncFoamCase(FoamCaseBase):
|
|
598
651
|
)
|
599
652
|
|
600
653
|
return AsyncFoamCase(dest)
|
601
|
-
|
602
|
-
|
603
|
-
class FoamTimeDirectory(Mapping[str, FoamFieldFile]):
|
604
|
-
"""
|
605
|
-
An OpenFOAM time directory in a case.
|
606
|
-
|
607
|
-
Use as a mapping to access field files in the directory, e.g. `time["U"]`.
|
608
|
-
|
609
|
-
:param path: The path to the time directory.
|
610
|
-
"""
|
611
|
-
|
612
|
-
def __init__(self, path: Union[Path, str]):
|
613
|
-
self.path = Path(path).absolute()
|
614
|
-
if not self.path.is_dir():
|
615
|
-
raise NotADirectoryError(f"{self.path} is not a directory")
|
616
|
-
|
617
|
-
@property
|
618
|
-
def time(self) -> float:
|
619
|
-
"""
|
620
|
-
The time that corresponds to this directory.
|
621
|
-
"""
|
622
|
-
return float(self.path.name)
|
623
|
-
|
624
|
-
@property
|
625
|
-
def name(self) -> str:
|
626
|
-
"""
|
627
|
-
The name of this time directory.
|
628
|
-
"""
|
629
|
-
return self.path.name
|
630
|
-
|
631
|
-
def __getitem__(self, key: str) -> FoamFieldFile:
|
632
|
-
try:
|
633
|
-
return FoamFieldFile(self.path / key)
|
634
|
-
except FileNotFoundError as e:
|
635
|
-
raise KeyError(key) from e
|
636
|
-
|
637
|
-
def __iter__(self) -> Iterator[str]:
|
638
|
-
for p in self.path.iterdir():
|
639
|
-
if p.is_file():
|
640
|
-
yield p.name
|
641
|
-
|
642
|
-
def __len__(self) -> int:
|
643
|
-
return len(list(iter(self)))
|
644
|
-
|
645
|
-
def __fspath__(self) -> str:
|
646
|
-
return str(self.path)
|
647
|
-
|
648
|
-
def __repr__(self) -> str:
|
649
|
-
return f"{type(self).__name__}({self.path})"
|
650
|
-
|
651
|
-
def __str__(self) -> str:
|
652
|
-
return str(self.path)
|
@@ -1,4 +1,7 @@
|
|
1
1
|
from pathlib import Path
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from collections import namedtuple
|
4
|
+
from contextlib import suppress
|
2
5
|
from typing import (
|
3
6
|
Any,
|
4
7
|
Union,
|
@@ -9,204 +12,38 @@ from typing import (
|
|
9
12
|
MutableMapping,
|
10
13
|
cast,
|
11
14
|
)
|
12
|
-
from collections import namedtuple
|
13
|
-
from dataclasses import dataclass
|
14
|
-
from contextlib import suppress
|
15
|
-
|
16
|
-
from ._subprocesses import run_process, CalledProcessError
|
17
|
-
|
18
|
-
try:
|
19
|
-
import numpy as np
|
20
|
-
from numpy.typing import NDArray
|
21
|
-
except ModuleNotFoundError:
|
22
|
-
numpy = False
|
23
|
-
else:
|
24
|
-
numpy = True
|
25
15
|
|
26
16
|
from pyparsing import (
|
17
|
+
Dict,
|
27
18
|
Forward,
|
28
19
|
Group,
|
29
20
|
Keyword,
|
21
|
+
LineEnd,
|
30
22
|
Literal,
|
23
|
+
Located,
|
31
24
|
Opt,
|
32
25
|
QuotedString,
|
33
26
|
Word,
|
27
|
+
c_style_comment,
|
34
28
|
common,
|
29
|
+
cpp_style_comment,
|
35
30
|
printables,
|
31
|
+
identchars,
|
32
|
+
identbodychars,
|
36
33
|
)
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
"moles",
|
46
|
-
"current",
|
47
|
-
"luminous_intensity",
|
48
|
-
],
|
49
|
-
defaults=(0, 0, 0, 0, 0, 0, 0),
|
50
|
-
)
|
51
|
-
|
52
|
-
|
53
|
-
@dataclass
|
54
|
-
class FoamDimensioned:
|
55
|
-
value: Union[int, float, Sequence[Union[int, float]]] = 0
|
56
|
-
dimensions: Union[FoamDimensionSet, Sequence[Union[int, float]]] = (
|
57
|
-
FoamDimensionSet()
|
58
|
-
)
|
59
|
-
name: Optional[str] = None
|
60
|
-
|
61
|
-
def __post_init__(self) -> None:
|
62
|
-
if not isinstance(self.dimensions, FoamDimensionSet):
|
63
|
-
self.dimensions = FoamDimensionSet(*self.dimensions)
|
64
|
-
|
65
|
-
|
66
|
-
FoamValue = Union[
|
67
|
-
str, int, float, bool, FoamDimensioned, FoamDimensionSet, Sequence["FoamValue"]
|
68
|
-
]
|
69
|
-
"""
|
70
|
-
A value that can be stored in an OpenFOAM dictionary.
|
71
|
-
"""
|
72
|
-
|
73
|
-
_YES = Keyword("yes").set_parse_action(lambda s, loc, tks: True)
|
74
|
-
_NO = Keyword("no").set_parse_action(lambda s, loc, tks: False)
|
75
|
-
_DIMENSIONS = (
|
76
|
-
Literal("[").suppress() + common.number * 7 + Literal("]").suppress()
|
77
|
-
).set_parse_action(lambda s, loc, tks: FoamDimensionSet(*tks))
|
78
|
-
_TOKEN = common.identifier | QuotedString('"', unquote_results=False)
|
79
|
-
_ITEM = Forward()
|
80
|
-
_LIST = Opt(
|
81
|
-
Literal("List") + Literal("<") + common.identifier + Literal(">")
|
82
|
-
).suppress() + (
|
83
|
-
(
|
84
|
-
Opt(common.integer).suppress()
|
85
|
-
+ Literal("(").suppress()
|
86
|
-
+ Group(_ITEM[...])
|
87
|
-
+ Literal(")").suppress()
|
88
|
-
)
|
89
|
-
| (
|
90
|
-
common.integer + Literal("{").suppress() + _ITEM + Literal("}").suppress()
|
91
|
-
).set_parse_action(lambda s, loc, tks: [tks[1]] * tks[0])
|
92
|
-
)
|
93
|
-
_FIELD = (Keyword("uniform").suppress() + _ITEM) | (
|
94
|
-
Keyword("nonuniform").suppress() + _LIST
|
95
|
-
)
|
96
|
-
_DIMENSIONED = (Opt(common.identifier) + _DIMENSIONS + _ITEM).set_parse_action(
|
97
|
-
lambda s, loc, tks: FoamDimensioned(*reversed(tks.as_list()))
|
98
|
-
)
|
99
|
-
_ITEM <<= (
|
100
|
-
_FIELD | _LIST | _DIMENSIONED | _DIMENSIONS | common.number | _YES | _NO | _TOKEN
|
101
|
-
)
|
102
|
-
|
103
|
-
_TOKENS = (QuotedString('"', unquote_results=False) | Word(printables))[
|
104
|
-
1, ...
|
105
|
-
].set_parse_action(lambda s, loc, tks: " ".join(tks))
|
106
|
-
|
107
|
-
_VALUE = _ITEM ^ _TOKENS
|
108
|
-
|
109
|
-
|
110
|
-
def _parse(value: str) -> FoamValue:
|
111
|
-
return cast(FoamValue, _VALUE.parse_string(value, parse_all=True).as_list()[0])
|
112
|
-
|
113
|
-
|
114
|
-
def _serialize_bool(value: Any) -> str:
|
115
|
-
if value is True:
|
116
|
-
return "yes"
|
117
|
-
elif value is False:
|
118
|
-
return "no"
|
119
|
-
else:
|
120
|
-
raise TypeError(f"Not a bool: {type(value)}")
|
121
|
-
|
122
|
-
|
123
|
-
def _is_sequence(value: Any) -> bool:
|
124
|
-
return (
|
125
|
-
isinstance(value, Sequence)
|
126
|
-
and not isinstance(value, str)
|
127
|
-
or numpy
|
128
|
-
and isinstance(value, np.ndarray)
|
129
|
-
)
|
130
|
-
|
131
|
-
|
132
|
-
def _serialize_list(value: Any) -> str:
|
133
|
-
if _is_sequence(value):
|
134
|
-
return f"({' '.join(_serialize(v) for v in value)})"
|
135
|
-
else:
|
136
|
-
raise TypeError(f"Not a valid sequence: {type(value)}")
|
137
|
-
|
138
|
-
|
139
|
-
def _serialize_field(value: Any) -> str:
|
140
|
-
if _is_sequence(value):
|
141
|
-
try:
|
142
|
-
s = _serialize_list(value)
|
143
|
-
except TypeError:
|
144
|
-
raise TypeError(f"Not a valid field: {type(value)}") from None
|
145
|
-
else:
|
146
|
-
if len(value) < 10:
|
147
|
-
return f"uniform {s}"
|
148
|
-
else:
|
149
|
-
if isinstance(value[0], (int, float)):
|
150
|
-
kind = "scalar"
|
151
|
-
elif len(value[0]) == 3:
|
152
|
-
kind = "vector"
|
153
|
-
elif len(value[0]) == 6:
|
154
|
-
kind = "symmTensor"
|
155
|
-
elif len(value[0]) == 9:
|
156
|
-
kind = "tensor"
|
157
|
-
else:
|
158
|
-
raise TypeError(
|
159
|
-
f"Unsupported sequence length for field: {len(value[0])}"
|
160
|
-
)
|
161
|
-
return f"nonuniform List<{kind}> {len(value)}{s}"
|
162
|
-
else:
|
163
|
-
return f"uniform {value}"
|
164
|
-
|
165
|
-
|
166
|
-
def _serialize_dimensions(value: Any) -> str:
|
167
|
-
if _is_sequence(value) and len(value) == 7:
|
168
|
-
return f"[{' '.join(str(v) for v in value)}]"
|
169
|
-
else:
|
170
|
-
raise TypeError(f"Not a valid dimension set: {type(value)}")
|
171
|
-
|
172
|
-
|
173
|
-
def _serialize_dimensioned(value: Any) -> str:
|
174
|
-
if isinstance(value, FoamDimensioned):
|
175
|
-
if value.name is not None:
|
176
|
-
return f"{value.name} {_serialize_dimensions(value.dimensions)} {_serialize(value.value)}"
|
177
|
-
else:
|
178
|
-
return (
|
179
|
-
f"{_serialize_dimensions(value.dimensions)} {_serialize(value.value)}"
|
180
|
-
)
|
181
|
-
else:
|
182
|
-
raise TypeError(f"Not a valid dimensioned value: {type(value)}")
|
183
|
-
|
184
|
-
|
185
|
-
def _serialize(
|
186
|
-
value: Any, *, assume_field: bool = False, assume_dimensions: bool = False
|
187
|
-
) -> str:
|
188
|
-
if isinstance(value, FoamDimensionSet) or assume_dimensions:
|
189
|
-
with suppress(TypeError):
|
190
|
-
return _serialize_dimensions(value)
|
191
|
-
|
192
|
-
if assume_field:
|
193
|
-
with suppress(TypeError):
|
194
|
-
return _serialize_field(value)
|
195
|
-
|
196
|
-
with suppress(TypeError):
|
197
|
-
return _serialize_dimensioned(value)
|
198
|
-
|
199
|
-
with suppress(TypeError):
|
200
|
-
return _serialize_list(value)
|
201
|
-
|
202
|
-
with suppress(TypeError):
|
203
|
-
return _serialize_bool(value)
|
35
|
+
try:
|
36
|
+
import numpy as np
|
37
|
+
from numpy.typing import NDArray
|
38
|
+
except ModuleNotFoundError:
|
39
|
+
numpy = False
|
40
|
+
else:
|
41
|
+
numpy = True
|
204
42
|
|
205
|
-
|
43
|
+
from ._subprocesses import run_process, CalledProcessError
|
206
44
|
|
207
45
|
|
208
|
-
class
|
209
|
-
Value = FoamValue # for backwards compatibility
|
46
|
+
class _FoamDictionary(MutableMapping[str, Union["FoamFile.Value", "_FoamDictionary"]]):
|
210
47
|
|
211
48
|
def __init__(self, _file: "FoamFile", _keywords: Sequence[str]) -> None:
|
212
49
|
self._file = _file
|
@@ -238,14 +75,18 @@ class FoamDictionary(MutableMapping[str, Union[FoamValue, "FoamDictionary"]]):
|
|
238
75
|
f"{e.cmd} failed with return code {e.returncode}\n{e.stderr.decode()}"
|
239
76
|
) from None
|
240
77
|
|
241
|
-
def __getitem__(self, key: str) -> Union[
|
242
|
-
|
78
|
+
def __getitem__(self, key: str) -> Union["FoamFile.Value", "_FoamDictionary"]:
|
79
|
+
contents = self._file.path.read_text()
|
80
|
+
value = _DICTIONARY.parse_string(contents, parse_all=True).as_dict()
|
81
|
+
|
82
|
+
for key in [*self._keywords, key]:
|
83
|
+
value = value[key]
|
243
84
|
|
244
|
-
if value
|
245
|
-
|
246
|
-
return FoamDictionary(self._file, [*self._keywords, key])
|
85
|
+
if isinstance(value, dict):
|
86
|
+
return _FoamDictionary(self._file, [*self._keywords, key])
|
247
87
|
else:
|
248
|
-
|
88
|
+
start, end = value
|
89
|
+
return _VALUE.parse_string(contents[start:end], parse_all=True).as_list()[0]
|
249
90
|
|
250
91
|
def _setitem(
|
251
92
|
self,
|
@@ -255,17 +96,18 @@ class FoamDictionary(MutableMapping[str, Union[FoamValue, "FoamDictionary"]]):
|
|
255
96
|
assume_field: bool = False,
|
256
97
|
assume_dimensions: bool = False,
|
257
98
|
) -> None:
|
258
|
-
if isinstance(value,
|
99
|
+
if isinstance(value, _FoamDictionary):
|
259
100
|
value = value._cmd(["-value"])
|
260
101
|
elif isinstance(value, Mapping):
|
261
102
|
self._cmd(["-set", "{}"], key=key)
|
262
103
|
subdict = self[key]
|
263
|
-
|
104
|
+
print(subdict)
|
105
|
+
assert isinstance(subdict, _FoamDictionary)
|
264
106
|
for k, v in value.items():
|
265
107
|
subdict[k] = v
|
266
108
|
return
|
267
109
|
else:
|
268
|
-
value =
|
110
|
+
value = serialize(
|
269
111
|
value, assume_field=assume_field, assume_dimensions=assume_dimensions
|
270
112
|
)
|
271
113
|
|
@@ -286,84 +128,53 @@ class FoamDictionary(MutableMapping[str, Union[FoamValue, "FoamDictionary"]]):
|
|
286
128
|
self._cmd(["-remove"], key=key)
|
287
129
|
|
288
130
|
def __iter__(self) -> Iterator[str]:
|
289
|
-
|
290
|
-
|
291
|
-
|
131
|
+
value = _DICTIONARY.parse_file(self._file.path, parse_all=True).as_dict()
|
132
|
+
|
133
|
+
for key in self._keywords:
|
134
|
+
value = value[key]
|
135
|
+
|
136
|
+
yield from value
|
292
137
|
|
293
138
|
def __len__(self) -> int:
|
294
139
|
return len(list(iter(self)))
|
295
140
|
|
296
141
|
def __repr__(self) -> str:
|
297
|
-
return
|
298
|
-
|
299
|
-
|
300
|
-
class FoamBoundaryDictionary(FoamDictionary):
|
301
|
-
"""An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
|
302
|
-
|
303
|
-
def __setitem__(self, key: str, value: Any) -> None:
|
304
|
-
if key == "value":
|
305
|
-
self._setitem(key, value, assume_field=True)
|
306
|
-
else:
|
307
|
-
self._setitem(key, value)
|
308
|
-
|
309
|
-
@property
|
310
|
-
def type(self) -> str:
|
311
|
-
"""
|
312
|
-
Alias of `self["type"]`.
|
313
|
-
"""
|
314
|
-
ret = self["type"]
|
315
|
-
if not isinstance(ret, str):
|
316
|
-
raise TypeError("type is not a string")
|
317
|
-
return ret
|
142
|
+
return "FoamFile.Dictionary"
|
318
143
|
|
319
|
-
@type.setter
|
320
|
-
def type(self, value: str) -> None:
|
321
|
-
self["type"] = value
|
322
144
|
|
323
|
-
|
324
|
-
|
325
|
-
self,
|
326
|
-
) -> Union[
|
327
|
-
int,
|
328
|
-
float,
|
329
|
-
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
330
|
-
"NDArray[np.generic]",
|
331
|
-
]:
|
332
|
-
"""
|
333
|
-
Alias of `self["value"]`.
|
334
|
-
"""
|
335
|
-
ret = self["value"]
|
336
|
-
if not isinstance(ret, (int, float, Sequence)):
|
337
|
-
raise TypeError("value is not a field")
|
338
|
-
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
145
|
+
class FoamFile(_FoamDictionary):
|
146
|
+
"""An OpenFOAM dictionary file as a mutable mapping."""
|
339
147
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
"
|
148
|
+
Dictionary = _FoamDictionary
|
149
|
+
|
150
|
+
DimensionSet = namedtuple(
|
151
|
+
"DimensionSet",
|
152
|
+
[
|
153
|
+
"mass",
|
154
|
+
"length",
|
155
|
+
"time",
|
156
|
+
"temperature",
|
157
|
+
"moles",
|
158
|
+
"current",
|
159
|
+
"luminous_intensity",
|
348
160
|
],
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
@value.deleter
|
353
|
-
def value(self) -> None:
|
354
|
-
del self["value"]
|
355
|
-
|
161
|
+
defaults=(0, 0, 0, 0, 0, 0, 0),
|
162
|
+
)
|
356
163
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
return ret
|
164
|
+
@dataclass
|
165
|
+
class Dimensioned:
|
166
|
+
value: Union[int, float, Sequence[Union[int, float]]] = 0
|
167
|
+
dimensions: Union["FoamFile.DimensionSet", Sequence[Union[int, float]]] = ()
|
168
|
+
name: Optional[str] = None
|
363
169
|
|
170
|
+
def __post_init__(self) -> None:
|
171
|
+
if not isinstance(self.dimensions, FoamFile.DimensionSet):
|
172
|
+
self.dimensions = FoamFile.DimensionSet(*self.dimensions)
|
364
173
|
|
365
|
-
|
366
|
-
"""
|
174
|
+
Value = Union[str, int, float, bool, Dimensioned, DimensionSet, Sequence["Value"]]
|
175
|
+
"""
|
176
|
+
A value that can be stored in an OpenFOAM dictionary.
|
177
|
+
"""
|
367
178
|
|
368
179
|
def __init__(self, path: Union[str, Path]) -> None:
|
369
180
|
super().__init__(self, [])
|
@@ -383,10 +194,80 @@ class FoamFile(FoamDictionary):
|
|
383
194
|
class FoamFieldFile(FoamFile):
|
384
195
|
"""An OpenFOAM dictionary file representing a field as a mutable mapping."""
|
385
196
|
|
386
|
-
|
197
|
+
class BoundariesDictionary(_FoamDictionary):
|
198
|
+
def __getitem__(
|
199
|
+
self, key: str
|
200
|
+
) -> Union["FoamFile.Value", "FoamFieldFile.BoundaryDictionary"]:
|
201
|
+
ret = super().__getitem__(key)
|
202
|
+
if isinstance(ret, _FoamDictionary):
|
203
|
+
ret = FoamFieldFile.BoundaryDictionary(
|
204
|
+
self._file, [*self._keywords, key]
|
205
|
+
)
|
206
|
+
return ret
|
207
|
+
|
208
|
+
class BoundaryDictionary(_FoamDictionary):
|
209
|
+
"""An OpenFOAM dictionary representing a boundary condition as a mutable mapping."""
|
210
|
+
|
211
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
212
|
+
if key == "value":
|
213
|
+
self._setitem(key, value, assume_field=True)
|
214
|
+
else:
|
215
|
+
self._setitem(key, value)
|
216
|
+
|
217
|
+
@property
|
218
|
+
def type(self) -> str:
|
219
|
+
"""
|
220
|
+
Alias of `self["type"]`.
|
221
|
+
"""
|
222
|
+
ret = self["type"]
|
223
|
+
if not isinstance(ret, str):
|
224
|
+
raise TypeError("type is not a string")
|
225
|
+
return ret
|
226
|
+
|
227
|
+
@type.setter
|
228
|
+
def type(self, value: str) -> None:
|
229
|
+
self["type"] = value
|
230
|
+
|
231
|
+
@property
|
232
|
+
def value(
|
233
|
+
self,
|
234
|
+
) -> Union[
|
235
|
+
int,
|
236
|
+
float,
|
237
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
238
|
+
"NDArray[np.generic]",
|
239
|
+
]:
|
240
|
+
"""
|
241
|
+
Alias of `self["value"]`.
|
242
|
+
"""
|
243
|
+
ret = self["value"]
|
244
|
+
if not isinstance(ret, (int, float, Sequence)):
|
245
|
+
raise TypeError("value is not a field")
|
246
|
+
return cast(Union[int, float, Sequence[Union[int, float]]], ret)
|
247
|
+
|
248
|
+
@value.setter
|
249
|
+
def value(
|
250
|
+
self,
|
251
|
+
value: Union[
|
252
|
+
int,
|
253
|
+
float,
|
254
|
+
Sequence[Union[int, float, Sequence[Union[int, float]]]],
|
255
|
+
"NDArray[np.generic]",
|
256
|
+
],
|
257
|
+
) -> None:
|
258
|
+
self["value"] = value
|
259
|
+
|
260
|
+
@value.deleter
|
261
|
+
def value(self) -> None:
|
262
|
+
del self["value"]
|
263
|
+
|
264
|
+
def __repr__(self) -> str:
|
265
|
+
return "FoamFieldFile.BoundaryDictionary"
|
266
|
+
|
267
|
+
def __getitem__(self, key: str) -> Union[FoamFile.Value, _FoamDictionary]:
|
387
268
|
ret = super().__getitem__(key)
|
388
|
-
if key == "boundaryField" and isinstance(ret,
|
389
|
-
ret =
|
269
|
+
if key == "boundaryField" and isinstance(ret, _FoamDictionary):
|
270
|
+
ret = FoamFieldFile.BoundariesDictionary(self, [key])
|
390
271
|
return ret
|
391
272
|
|
392
273
|
def __setitem__(self, key: str, value: Any) -> None:
|
@@ -397,19 +278,22 @@ class FoamFieldFile(FoamFile):
|
|
397
278
|
else:
|
398
279
|
self._setitem(key, value)
|
399
280
|
|
281
|
+
def __repr__(self) -> str:
|
282
|
+
return "FoamFieldFile.BoundariesDictionary"
|
283
|
+
|
400
284
|
@property
|
401
|
-
def dimensions(self) ->
|
285
|
+
def dimensions(self) -> FoamFile.DimensionSet:
|
402
286
|
"""
|
403
287
|
Alias of `self["dimensions"]`.
|
404
288
|
"""
|
405
289
|
ret = self["dimensions"]
|
406
|
-
if not isinstance(ret,
|
290
|
+
if not isinstance(ret, FoamFile.DimensionSet):
|
407
291
|
raise TypeError("dimensions is not a DimensionSet")
|
408
292
|
return ret
|
409
293
|
|
410
294
|
@dimensions.setter
|
411
295
|
def dimensions(
|
412
|
-
self, value: Union[
|
296
|
+
self, value: Union[FoamFile.DimensionSet, Sequence[Union[int, float]]]
|
413
297
|
) -> None:
|
414
298
|
self["dimensions"] = value
|
415
299
|
|
@@ -443,12 +327,168 @@ class FoamFieldFile(FoamFile):
|
|
443
327
|
self["internalField"] = value
|
444
328
|
|
445
329
|
@property
|
446
|
-
def boundary_field(self) ->
|
330
|
+
def boundary_field(self) -> "FoamFieldFile.BoundariesDictionary":
|
447
331
|
"""
|
448
332
|
Alias of `self["boundaryField"]`.
|
449
333
|
"""
|
450
334
|
ret = self["boundaryField"]
|
451
|
-
if not isinstance(ret,
|
452
|
-
assert not isinstance(ret,
|
335
|
+
if not isinstance(ret, FoamFieldFile.BoundariesDictionary):
|
336
|
+
assert not isinstance(ret, _FoamDictionary)
|
453
337
|
raise TypeError("boundaryField is not a dictionary")
|
454
338
|
return ret
|
339
|
+
|
340
|
+
|
341
|
+
_YES = Keyword("yes").set_parse_action(lambda: True)
|
342
|
+
_NO = Keyword("no").set_parse_action(lambda: False)
|
343
|
+
_DIMENSIONS = (
|
344
|
+
Literal("[").suppress() + common.number * 7 + Literal("]").suppress()
|
345
|
+
).set_parse_action(lambda tks: FoamFile.DimensionSet(*tks))
|
346
|
+
_TOKEN = QuotedString('"', unquote_results=False) | Word(
|
347
|
+
identchars + "$", identbodychars
|
348
|
+
)
|
349
|
+
_ITEM = Forward()
|
350
|
+
_LIST = Opt(
|
351
|
+
Literal("List") + Literal("<") + common.identifier + Literal(">")
|
352
|
+
).suppress() + (
|
353
|
+
(
|
354
|
+
Opt(common.integer).suppress()
|
355
|
+
+ Literal("(").suppress()
|
356
|
+
+ Group(_ITEM[...])
|
357
|
+
+ Literal(")").suppress()
|
358
|
+
)
|
359
|
+
| (
|
360
|
+
common.integer + Literal("{").suppress() + _ITEM + Literal("}").suppress()
|
361
|
+
).set_parse_action(lambda tks: [tks[1]] * tks[0])
|
362
|
+
)
|
363
|
+
_FIELD = (Keyword("uniform").suppress() + _ITEM) | (
|
364
|
+
Keyword("nonuniform").suppress() + _LIST
|
365
|
+
)
|
366
|
+
_DIMENSIONED = (Opt(common.identifier) + _DIMENSIONS + _ITEM).set_parse_action(
|
367
|
+
lambda tks: FoamFile.Dimensioned(*reversed(tks.as_list()))
|
368
|
+
)
|
369
|
+
_ITEM <<= (
|
370
|
+
_FIELD | _LIST | _DIMENSIONED | _DIMENSIONS | common.number | _YES | _NO | _TOKEN
|
371
|
+
)
|
372
|
+
|
373
|
+
_TOKENS = (
|
374
|
+
QuotedString('"', unquote_results=False)
|
375
|
+
| Word(printables.replace(";", "").replace("{", "").replace("}", ""))
|
376
|
+
)[2, ...].set_parse_action(lambda tks: " ".join(tks))
|
377
|
+
|
378
|
+
_VALUE = (_ITEM ^ _TOKENS).ignore(c_style_comment).ignore(cpp_style_comment)
|
379
|
+
|
380
|
+
|
381
|
+
_UNPARSED_VALUE = (
|
382
|
+
QuotedString('"', unquote_results=False)
|
383
|
+
| Word(printables.replace(";", "").replace("{", "").replace("}", ""))
|
384
|
+
)[...]
|
385
|
+
_KEYWORD = QuotedString('"', unquote_results=False) | Word(
|
386
|
+
identchars + "$(,.)", identbodychars + "$(,.)"
|
387
|
+
)
|
388
|
+
_DICTIONARY = Forward()
|
389
|
+
_ENTRY = _KEYWORD + (
|
390
|
+
(
|
391
|
+
Located(_UNPARSED_VALUE).set_parse_action(lambda tks: (tks[0], tks[2]))
|
392
|
+
+ Literal(";").suppress()
|
393
|
+
)
|
394
|
+
| (Literal("{").suppress() + _DICTIONARY + Literal("}").suppress())
|
395
|
+
)
|
396
|
+
_DICTIONARY <<= (
|
397
|
+
Dict(Group(_ENTRY)[...])
|
398
|
+
.set_parse_action(lambda tks: {} if not tks else tks)
|
399
|
+
.ignore(c_style_comment)
|
400
|
+
.ignore(cpp_style_comment)
|
401
|
+
.ignore(Literal("#include") + ... + LineEnd()) # type: ignore
|
402
|
+
)
|
403
|
+
|
404
|
+
|
405
|
+
def _serialize_bool(value: Any) -> str:
|
406
|
+
if value is True:
|
407
|
+
return "yes"
|
408
|
+
elif value is False:
|
409
|
+
return "no"
|
410
|
+
else:
|
411
|
+
raise TypeError(f"Not a bool: {type(value)}")
|
412
|
+
|
413
|
+
|
414
|
+
def _is_sequence(value: Any) -> bool:
|
415
|
+
return (
|
416
|
+
isinstance(value, Sequence)
|
417
|
+
and not isinstance(value, str)
|
418
|
+
or numpy
|
419
|
+
and isinstance(value, np.ndarray)
|
420
|
+
)
|
421
|
+
|
422
|
+
|
423
|
+
def _serialize_list(value: Any) -> str:
|
424
|
+
if _is_sequence(value):
|
425
|
+
return f"({' '.join(serialize(v) for v in value)})"
|
426
|
+
else:
|
427
|
+
raise TypeError(f"Not a valid sequence: {type(value)}")
|
428
|
+
|
429
|
+
|
430
|
+
def _serialize_field(value: Any) -> str:
|
431
|
+
if _is_sequence(value):
|
432
|
+
try:
|
433
|
+
s = _serialize_list(value)
|
434
|
+
except TypeError:
|
435
|
+
raise TypeError(f"Not a valid field: {type(value)}") from None
|
436
|
+
else:
|
437
|
+
if len(value) < 10:
|
438
|
+
return f"uniform {s}"
|
439
|
+
else:
|
440
|
+
if isinstance(value[0], (int, float)):
|
441
|
+
kind = "scalar"
|
442
|
+
elif len(value[0]) == 3:
|
443
|
+
kind = "vector"
|
444
|
+
elif len(value[0]) == 6:
|
445
|
+
kind = "symmTensor"
|
446
|
+
elif len(value[0]) == 9:
|
447
|
+
kind = "tensor"
|
448
|
+
else:
|
449
|
+
raise TypeError(
|
450
|
+
f"Unsupported sequence length for field: {len(value[0])}"
|
451
|
+
)
|
452
|
+
return f"nonuniform List<{kind}> {len(value)}{s}"
|
453
|
+
else:
|
454
|
+
return f"uniform {value}"
|
455
|
+
|
456
|
+
|
457
|
+
def _serialize_dimensions(value: Any) -> str:
|
458
|
+
if _is_sequence(value) and len(value) == 7:
|
459
|
+
return f"[{' '.join(str(v) for v in value)}]"
|
460
|
+
else:
|
461
|
+
raise TypeError(f"Not a valid dimension set: {type(value)}")
|
462
|
+
|
463
|
+
|
464
|
+
def _serialize_dimensioned(value: Any) -> str:
|
465
|
+
if isinstance(value, FoamFile.Dimensioned):
|
466
|
+
if value.name is not None:
|
467
|
+
return f"{value.name} {_serialize_dimensions(value.dimensions)} {serialize(value.value)}"
|
468
|
+
else:
|
469
|
+
return f"{_serialize_dimensions(value.dimensions)} {serialize(value.value)}"
|
470
|
+
else:
|
471
|
+
raise TypeError(f"Not a valid dimensioned value: {type(value)}")
|
472
|
+
|
473
|
+
|
474
|
+
def serialize(
|
475
|
+
value: Any, *, assume_field: bool = False, assume_dimensions: bool = False
|
476
|
+
) -> str:
|
477
|
+
if isinstance(value, FoamFile.DimensionSet) or assume_dimensions:
|
478
|
+
with suppress(TypeError):
|
479
|
+
return _serialize_dimensions(value)
|
480
|
+
|
481
|
+
if assume_field:
|
482
|
+
with suppress(TypeError):
|
483
|
+
return _serialize_field(value)
|
484
|
+
|
485
|
+
with suppress(TypeError):
|
486
|
+
return _serialize_dimensioned(value)
|
487
|
+
|
488
|
+
with suppress(TypeError):
|
489
|
+
return _serialize_list(value)
|
490
|
+
|
491
|
+
with suppress(TypeError):
|
492
|
+
return _serialize_bool(value)
|
493
|
+
|
494
|
+
return str(value)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: foamlib
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0
|
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
|
@@ -62,7 +62,7 @@ It offers the following classes (among a few others):
|
|
62
62
|
|
63
63
|
* [`FoamCase`](https://foamlib.readthedocs.io/en/stable/#foamlib.FoamCase): a class for manipulating, executing and accessing the results of OpenFOAM cases.
|
64
64
|
* [`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
|
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
|
|
@@ -61,9 +61,6 @@ Homepage = "https://github.com/gerlero/foamlib"
|
|
61
61
|
Repository = "https://github.com/gerlero/foamlib"
|
62
62
|
Documentation = "https://foamlib.readthedocs.io"
|
63
63
|
|
64
|
-
[tool.setuptools]
|
65
|
-
packages = ["foamlib"]
|
66
|
-
|
67
64
|
[tool.setuptools.dynamic]
|
68
65
|
version = {attr = "foamlib.__version__"}
|
69
66
|
|
@@ -7,40 +7,54 @@ from typing import Sequence
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
9
|
from foamlib import *
|
10
|
-
from foamlib._dictionaries import
|
11
|
-
|
12
|
-
|
13
|
-
def
|
14
|
-
assert
|
15
|
-
assert
|
16
|
-
assert
|
17
|
-
assert
|
18
|
-
assert
|
19
|
-
assert
|
20
|
-
assert
|
21
|
-
assert
|
22
|
-
assert
|
23
|
-
assert
|
24
|
-
assert
|
25
|
-
assert
|
26
|
-
assert
|
27
|
-
assert
|
28
|
-
assert
|
29
|
-
assert
|
10
|
+
from foamlib._dictionaries import _VALUE
|
11
|
+
|
12
|
+
|
13
|
+
def test_parse_value() -> None:
|
14
|
+
assert _VALUE.parse_string("1").as_list()[0] == 1
|
15
|
+
assert _VALUE.parse_string("1.0").as_list()[0] == 1.0
|
16
|
+
assert _VALUE.parse_string("1.0e-3").as_list()[0] == 1.0e-3
|
17
|
+
assert _VALUE.parse_string("yes").as_list()[0] is True
|
18
|
+
assert _VALUE.parse_string("no").as_list()[0] is False
|
19
|
+
assert _VALUE.parse_string("word").as_list()[0] == "word"
|
20
|
+
assert _VALUE.parse_string("word word").as_list()[0] == "word word"
|
21
|
+
assert _VALUE.parse_string('"a string"').as_list()[0] == '"a string"'
|
22
|
+
assert _VALUE.parse_string("uniform 1").as_list()[0] == 1
|
23
|
+
assert _VALUE.parse_string("uniform 1.0").as_list()[0] == 1.0
|
24
|
+
assert _VALUE.parse_string("uniform 1.0e-3").as_list()[0] == 1.0e-3
|
25
|
+
assert _VALUE.parse_string("(1.0 2.0 3.0)").as_list()[0] == [1.0, 2.0, 3.0]
|
26
|
+
assert _VALUE.parse_string("uniform (1 2 3)").as_list()[0] == [1, 2, 3]
|
27
|
+
assert _VALUE.parse_string("nonuniform List<scalar> 2(1 2)").as_list()[0] == [1, 2]
|
28
|
+
assert _VALUE.parse_string("3(1 2 3)").as_list()[0] == [1, 2, 3]
|
29
|
+
assert _VALUE.parse_string("2((1 2 3) (4 5 6))").as_list()[0] == [
|
30
30
|
[1, 2, 3],
|
31
31
|
[4, 5, 6],
|
32
32
|
]
|
33
|
-
assert
|
34
|
-
|
33
|
+
assert _VALUE.parse_string("nonuniform List<vector> 2((1 2 3) (4 5 6))").as_list()[
|
34
|
+
0
|
35
|
+
] == [
|
36
|
+
[1, 2, 3],
|
37
|
+
[4, 5, 6],
|
38
|
+
]
|
39
|
+
assert _VALUE.parse_string("[1 1 -2 0 0 0 0]").as_list()[
|
40
|
+
0
|
41
|
+
] == FoamFile.DimensionSet(mass=1, length=1, time=-2)
|
42
|
+
assert _VALUE.parse_string("g [1 1 -2 0 0 0 0] (0 0 -9.81)").as_list()[
|
43
|
+
0
|
44
|
+
] == FoamFile.Dimensioned(
|
35
45
|
name="g",
|
36
|
-
dimensions=
|
46
|
+
dimensions=FoamFile.DimensionSet(mass=1, length=1, time=-2),
|
37
47
|
value=[0, 0, -9.81],
|
38
48
|
)
|
39
|
-
assert
|
40
|
-
|
49
|
+
assert _VALUE.parse_string("[1 1 -2 0 0 0 0] 9.81").as_list()[
|
50
|
+
0
|
51
|
+
] == FoamFile.Dimensioned(
|
52
|
+
dimensions=FoamFile.DimensionSet(mass=1, length=1, time=-2), value=9.81
|
41
53
|
)
|
42
54
|
assert (
|
43
|
-
|
55
|
+
_VALUE.parse_string(
|
56
|
+
"hex (0 1 2 3 4 5 6 7) (1 1 1) simpleGrading (1 1 1)"
|
57
|
+
).as_list()[0]
|
44
58
|
== "hex (0 1 2 3 4 5 6 7) (1 1 1) simpleGrading (1 1 1)"
|
45
59
|
)
|
46
60
|
|
@@ -70,21 +84,21 @@ def test_write_read(tmp_path: Path) -> None:
|
|
70
84
|
|
71
85
|
d["subdict"] = {"key": "value"}
|
72
86
|
sd = d["subdict"]
|
73
|
-
assert isinstance(sd,
|
87
|
+
assert isinstance(sd, FoamFile.Dictionary)
|
74
88
|
assert sd["key"] == "value"
|
75
89
|
assert len(sd) == 1
|
76
90
|
assert list(sd) == ["key"]
|
77
91
|
|
78
92
|
d["subdict2"] = d["subdict"]
|
79
93
|
sd2 = d["subdict2"]
|
80
|
-
assert isinstance(sd2,
|
94
|
+
assert isinstance(sd2, FoamFile.Dictionary)
|
81
95
|
assert sd2["key"] == "value"
|
82
96
|
assert len(sd) == 1
|
83
97
|
assert list(sd) == ["key"]
|
84
98
|
|
85
99
|
sd["subsubdict"] = d["subdict"]
|
86
100
|
ssd = sd["subsubdict"]
|
87
|
-
assert isinstance(ssd,
|
101
|
+
assert isinstance(ssd, FoamFile.Dictionary)
|
88
102
|
assert ssd["key"] == "value"
|
89
103
|
|
90
104
|
sd["list"] = [1, 2, 3]
|
@@ -93,12 +107,12 @@ def test_write_read(tmp_path: Path) -> None:
|
|
93
107
|
sd["nestedList"] = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
94
108
|
assert sd["nestedList"] == [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
95
109
|
|
96
|
-
sd["g"] =
|
110
|
+
sd["g"] = FoamFile.Dimensioned(
|
97
111
|
name="g", dimensions=[1, 1, -2, 0, 0, 0, 0], value=[0, 0, -9.81]
|
98
112
|
)
|
99
|
-
assert sd["g"] ==
|
113
|
+
assert sd["g"] == FoamFile.Dimensioned(
|
100
114
|
name="g",
|
101
|
-
dimensions=
|
115
|
+
dimensions=FoamFile.DimensionSet(mass=1, length=1, time=-2),
|
102
116
|
value=[0, 0, -9.81],
|
103
117
|
)
|
104
118
|
|
@@ -114,17 +128,17 @@ def pitz(tmp_path: Path) -> FoamCase:
|
|
114
128
|
|
115
129
|
|
116
130
|
def test_dimensions(pitz: FoamCase) -> None:
|
117
|
-
assert pitz[0]["p"].dimensions ==
|
118
|
-
assert pitz[0]["U"].dimensions ==
|
131
|
+
assert pitz[0]["p"].dimensions == FoamFile.DimensionSet(length=2, time=-2)
|
132
|
+
assert pitz[0]["U"].dimensions == FoamFile.DimensionSet(length=1, time=-1)
|
119
133
|
|
120
|
-
pitz[0]["p"].dimensions =
|
134
|
+
pitz[0]["p"].dimensions = FoamFile.DimensionSet(mass=1, length=1, time=-2)
|
121
135
|
|
122
|
-
assert pitz[0]["p"].dimensions ==
|
136
|
+
assert pitz[0]["p"].dimensions == FoamFile.DimensionSet(mass=1, length=1, time=-2)
|
123
137
|
|
124
138
|
|
125
139
|
def test_boundary_field(pitz: FoamCase) -> None:
|
126
140
|
outlet = pitz[0]["p"].boundary_field["outlet"]
|
127
|
-
assert isinstance(outlet,
|
141
|
+
assert isinstance(outlet, FoamFieldFile.BoundaryDictionary)
|
128
142
|
assert outlet.type == "fixedValue"
|
129
143
|
assert outlet.value == 0
|
130
144
|
|
@@ -182,7 +196,7 @@ def test_internal_field(pitz: FoamCase) -> None:
|
|
182
196
|
|
183
197
|
def test_fv_schemes(pitz: FoamCase) -> None:
|
184
198
|
div_schemes = pitz.fv_schemes["divSchemes"]
|
185
|
-
assert isinstance(div_schemes,
|
199
|
+
assert isinstance(div_schemes, FoamFile.Dictionary)
|
186
200
|
scheme = div_schemes["div(phi,U)"]
|
187
201
|
assert isinstance(scheme, str)
|
188
202
|
assert scheme == "bounded Gauss linearUpwind grad(U)"
|
@@ -1,26 +0,0 @@
|
|
1
|
-
__version__ = "0.1.14"
|
2
|
-
|
3
|
-
from ._cases import FoamCase, AsyncFoamCase, FoamTimeDirectory, FoamCaseBase
|
4
|
-
from ._dictionaries import (
|
5
|
-
FoamFile,
|
6
|
-
FoamFieldFile,
|
7
|
-
FoamDictionary,
|
8
|
-
FoamBoundariesDictionary,
|
9
|
-
FoamBoundaryDictionary,
|
10
|
-
FoamDimensioned,
|
11
|
-
FoamDimensionSet,
|
12
|
-
)
|
13
|
-
|
14
|
-
__all__ = [
|
15
|
-
"FoamCase",
|
16
|
-
"AsyncFoamCase",
|
17
|
-
"FoamTimeDirectory",
|
18
|
-
"FoamCaseBase",
|
19
|
-
"FoamFile",
|
20
|
-
"FoamFieldFile",
|
21
|
-
"FoamDictionary",
|
22
|
-
"FoamBoundariesDictionary",
|
23
|
-
"FoamBoundaryDictionary",
|
24
|
-
"FoamDimensioned",
|
25
|
-
"FoamDimensionSet",
|
26
|
-
]
|
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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|