foamlib 0.6.12__py3-none-any.whl → 0.6.13__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.6.12"
3
+ __version__ = "0.6.13"
4
4
 
5
5
  from ._cases import (
6
6
  AsyncFoamCase,
foamlib/_files/_files.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  import sys
4
5
  from copy import deepcopy
5
6
  from typing import Any, Optional, Tuple, Union, cast
@@ -16,7 +17,7 @@ else:
16
17
 
17
18
  from ._base import FoamFileBase
18
19
  from ._io import FoamFileIO
19
- from ._serialization import Kind, dumps
20
+ from ._serialization import Kind, dumps, normalize
20
21
  from ._util import is_sequence
21
22
 
22
23
 
@@ -216,12 +217,28 @@ class FoamFile(
216
217
  or keywords[2].endswith("Gradient")
217
218
  )
218
219
  ):
219
- kind = Kind.BINARY_FIELD if self.format == "binary" else Kind.FIELD
220
+ if self.format == "binary":
221
+ arch = self.get(("FoamFile", "arch"), default=None)
222
+ assert arch is None or isinstance(arch, str)
223
+ if (arch is not None and "scalar=32" in arch) or (
224
+ arch is None
225
+ and os.environ.get("WM_PRECISION_OPTION", default="DP") == "SP"
226
+ ):
227
+ kind = Kind.SINGLE_PRECISION_BINARY_FIELD
228
+ else:
229
+ kind = Kind.DOUBLE_PRECISION_BINARY_FIELD
230
+ else:
231
+ kind = Kind.ASCII_FIELD
220
232
  elif keywords == ("dimensions",):
221
233
  kind = Kind.DIMENSIONS
222
234
 
223
235
  if (
224
- kind in (Kind.FIELD, Kind.BINARY_FIELD)
236
+ kind
237
+ in (
238
+ Kind.ASCII_FIELD,
239
+ Kind.DOUBLE_PRECISION_BINARY_FIELD,
240
+ Kind.SINGLE_PRECISION_BINARY_FIELD,
241
+ )
225
242
  ) and self.class_ == "dictionary":
226
243
  if isinstance(data, (int, float)):
227
244
  self.class_ = "volScalarField"
@@ -291,7 +308,7 @@ class FoamFile(
291
308
  elif keywords:
292
309
  parsed.put(
293
310
  keywords,
294
- deepcopy(data),
311
+ normalize(data, kind=kind),
295
312
  before
296
313
  + indentation
297
314
  + dumps(keywords[-1])
@@ -302,7 +319,11 @@ class FoamFile(
302
319
  )
303
320
 
304
321
  else:
305
- parsed.put((), deepcopy(data), before + dumps(data, kind=kind) + after)
322
+ parsed.put(
323
+ (),
324
+ normalize(data, kind=kind),
325
+ before + dumps(data, kind=kind) + after,
326
+ )
306
327
 
307
328
  def __delitem__(self, keywords: str | tuple[str, ...] | None) -> None:
308
329
  if not keywords:
@@ -82,10 +82,12 @@ def _keyword_entry_of(
82
82
 
83
83
  def _unpack_binary_field(
84
84
  tks: ParseResults,
85
+ *,
86
+ elsize: int = 1,
85
87
  ) -> Sequence[Sequence[float] | Sequence[Sequence[float]]]:
86
- elsize = len(tks[0]) // 8
88
+ float_size = len(tks[0]) // elsize
87
89
 
88
- arr = array.array("d", "".join(tks).encode("latin-1"))
90
+ arr = array.array("f" if float_size == 4 else "d", "".join(tks).encode("latin-1"))
89
91
 
90
92
  values: Sequence[float] | Sequence[Sequence[float]]
91
93
 
@@ -130,45 +132,92 @@ _IDENTIFIER = Combine(
130
132
  _DIMENSIONED = (Opt(_IDENTIFIER) + _DIMENSIONS + _TENSOR).set_parse_action(
131
133
  lambda tks: FoamFileBase.Dimensioned(*reversed(tks.as_list()))
132
134
  )
133
- _FIELD = (Keyword("uniform").suppress() + _TENSOR) | (
134
- Keyword("nonuniform").suppress()
135
+ _FIELD = (Keyword("uniform", _IDENTBODYCHARS).suppress() + _TENSOR) | (
136
+ Keyword("nonuniform", _IDENTBODYCHARS).suppress()
135
137
  + (
136
138
  _list_of(_TENSOR)
137
139
  | (
138
140
  Literal("List").suppress()
139
141
  + Literal("<").suppress()
140
142
  + (
141
- counted_array(
142
- CharsNotIn(exact=8),
143
+ (
143
144
  Literal("scalar").suppress()
144
145
  + Literal(">").suppress()
145
- + common.integer
146
- + Literal("(").suppress(),
147
- )
148
- | counted_array(
149
- CharsNotIn(exact=8 * 3),
146
+ + (
147
+ (
148
+ counted_array(
149
+ CharsNotIn(exact=8),
150
+ common.integer + Literal("(").suppress(),
151
+ )
152
+ )
153
+ | (
154
+ counted_array(
155
+ CharsNotIn(exact=4),
156
+ common.integer + Literal("(").suppress(),
157
+ )
158
+ )
159
+ )
160
+ + Literal(")").suppress()
161
+ ).set_parse_action(_unpack_binary_field)
162
+ | (
150
163
  Literal("vector").suppress()
151
164
  + Literal(">").suppress()
152
- + common.integer
153
- + Literal("(").suppress(),
154
- )
155
- | counted_array(
156
- CharsNotIn(exact=8 * 6),
165
+ + (
166
+ (
167
+ counted_array(
168
+ CharsNotIn(exact=8 * 3),
169
+ common.integer + Literal("(").suppress(),
170
+ )
171
+ )
172
+ | (
173
+ counted_array(
174
+ CharsNotIn(exact=4 * 3),
175
+ common.integer + Literal("(").suppress(),
176
+ )
177
+ )
178
+ )
179
+ + Literal(")").suppress()
180
+ ).set_parse_action(lambda tks: _unpack_binary_field(tks, elsize=3))
181
+ | (
157
182
  Literal("symmTensor").suppress()
158
183
  + Literal(">").suppress()
159
- + common.integer
160
- + Literal("(").suppress(),
161
- )
162
- | counted_array(
163
- CharsNotIn(exact=8 * 9),
184
+ + (
185
+ (
186
+ counted_array(
187
+ CharsNotIn(exact=8 * 6),
188
+ common.integer + Literal("(").suppress(),
189
+ )
190
+ )
191
+ | (
192
+ counted_array(
193
+ CharsNotIn(exact=4 * 6),
194
+ common.integer + Literal("(").suppress(),
195
+ )
196
+ )
197
+ )
198
+ + Literal(")").suppress()
199
+ ).set_parse_action(lambda tks: _unpack_binary_field(tks, elsize=6))
200
+ | (
164
201
  Literal("tensor").suppress()
165
202
  + Literal(">").suppress()
166
- + common.integer
167
- + Literal("(").suppress(),
168
- )
203
+ + (
204
+ (
205
+ counted_array(
206
+ CharsNotIn(exact=8 * 9),
207
+ common.integer + Literal("(").suppress(),
208
+ )
209
+ )
210
+ | (
211
+ counted_array(
212
+ CharsNotIn(exact=4 * 9),
213
+ common.integer + Literal("(").suppress(),
214
+ )
215
+ )
216
+ )
217
+ + Literal(")").suppress()
218
+ ).set_parse_action(lambda tks: _unpack_binary_field(tks, elsize=9))
169
219
  )
170
- + Literal(")").suppress()
171
- ).set_parse_action(_unpack_binary_field)
220
+ )
172
221
  )
173
222
  )
174
223
  _TOKEN = QuotedString('"', unquote_results=False) | _IDENTIFIER
@@ -1,10 +1,12 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import array
4
+ import contextlib
4
5
  import itertools
6
+ import re
5
7
  import sys
6
8
  from enum import Enum, auto
7
- from typing import cast
9
+ from typing import cast, overload
8
10
 
9
11
  if sys.version_info >= (3, 9):
10
12
  from collections.abc import Mapping, Sequence
@@ -25,38 +27,111 @@ except ModuleNotFoundError:
25
27
  class Kind(Enum):
26
28
  DEFAULT = auto()
27
29
  SINGLE_ENTRY = auto()
28
- FIELD = auto()
29
- BINARY_FIELD = auto()
30
+ ASCII_FIELD = auto()
31
+ DOUBLE_PRECISION_BINARY_FIELD = auto()
32
+ SINGLE_PRECISION_BINARY_FIELD = auto()
30
33
  DIMENSIONS = auto()
31
34
 
32
35
 
36
+ _TOKENS = re.compile(r'(?:[^\s"]|"(?:[^"])*")+')
37
+
38
+
39
+ @overload
40
+ def normalize(
41
+ data: FoamFileBase._DataEntry, *, kind: Kind = Kind.DEFAULT
42
+ ) -> FoamFileBase._DataEntry: ...
43
+
44
+
45
+ @overload
46
+ def normalize(
47
+ data: FoamFileBase.Data, *, kind: Kind = Kind.DEFAULT
48
+ ) -> FoamFileBase.Data: ...
49
+
50
+
51
+ def normalize(
52
+ data: FoamFileBase.Data, *, kind: Kind = Kind.DEFAULT
53
+ ) -> FoamFileBase.Data:
54
+ if numpy and isinstance(data, np.ndarray):
55
+ ret = data.tolist()
56
+ assert isinstance(ret, list)
57
+ return ret
58
+
59
+ if kind == Kind.SINGLE_ENTRY and isinstance(data, tuple):
60
+ ret = normalize(list(data))
61
+ assert isinstance(ret, list)
62
+ return ret
63
+
64
+ if isinstance(data, Mapping):
65
+ return {k: normalize(v, kind=kind) for k, v in data.items()}
66
+
67
+ if (
68
+ kind == Kind.DIMENSIONS
69
+ and is_sequence(data)
70
+ and len(data) <= 7
71
+ and all(isinstance(d, (int, float)) for d in data)
72
+ ):
73
+ data = cast(Sequence[float], data)
74
+ return FoamFileBase.DimensionSet(*data)
75
+
76
+ if is_sequence(data) and not isinstance(data, tuple):
77
+ return [normalize(d, kind=Kind.SINGLE_ENTRY) for d in data]
78
+
79
+ if isinstance(data, str):
80
+ with contextlib.suppress(ValueError):
81
+ return int(data)
82
+
83
+ with contextlib.suppress(ValueError):
84
+ return float(data)
85
+
86
+ tokens: list[str] = re.findall(_TOKENS, data)
87
+
88
+ if len(tokens) == 1:
89
+ return tokens[0]
90
+
91
+ return tuple(tokens) if kind != Kind.SINGLE_ENTRY else " ".join(tokens)
92
+
93
+ if isinstance(data, FoamFileBase.Dimensioned):
94
+ value = normalize(data.value, kind=Kind.SINGLE_ENTRY)
95
+ assert isinstance(value, (int, float, list))
96
+ return FoamFileBase.Dimensioned(value, data.dimensions, data.name)
97
+
98
+ if isinstance(
99
+ data,
100
+ (int, float, bool, tuple, FoamFileBase.DimensionSet),
101
+ ):
102
+ return data
103
+
104
+ msg = f"Unsupported data type: {type(data)}"
105
+ raise TypeError(msg)
106
+
107
+
33
108
  def dumps(
34
109
  data: FoamFileBase.Data,
35
110
  *,
36
111
  kind: Kind = Kind.DEFAULT,
37
112
  ) -> bytes:
38
- if numpy and isinstance(data, np.ndarray):
39
- return dumps(data.tolist(), kind=kind)
113
+ data = normalize(data, kind=kind)
40
114
 
41
115
  if isinstance(data, Mapping):
42
116
  entries = []
43
117
  for k, v in data.items():
44
- b = dumps(v, kind=kind)
45
118
  if isinstance(v, Mapping):
46
- entries.append(dumps(k) + b" {" + b + b"}")
47
- elif not b:
119
+ entries.append(dumps(k) + b" {" + dumps(v) + b"}")
120
+ elif not v:
48
121
  entries.append(dumps(k) + b";")
49
122
  else:
50
- entries.append(dumps(k) + b" " + b + b";")
123
+ entries.append(dumps(k) + b" " + dumps(v) + b";")
51
124
 
52
125
  return b" ".join(entries)
53
126
 
54
- if isinstance(data, FoamFileBase.DimensionSet) or (
55
- kind == Kind.DIMENSIONS and is_sequence(data) and len(data) == 7
56
- ):
127
+ if isinstance(data, FoamFileBase.DimensionSet):
57
128
  return b"[" + b" ".join(dumps(v) for v in data) + b"]"
58
129
 
59
- if kind in (Kind.FIELD, Kind.BINARY_FIELD) and (
130
+ if kind in (
131
+ Kind.ASCII_FIELD,
132
+ Kind.DOUBLE_PRECISION_BINARY_FIELD,
133
+ Kind.SINGLE_PRECISION_BINARY_FIELD,
134
+ ) and (
60
135
  isinstance(data, (int, float))
61
136
  or is_sequence(data)
62
137
  and data
@@ -65,7 +140,11 @@ def dumps(
65
140
  ):
66
141
  return b"uniform " + dumps(data, kind=Kind.SINGLE_ENTRY)
67
142
 
68
- if kind in (Kind.FIELD, Kind.BINARY_FIELD) and is_sequence(data):
143
+ if kind in (
144
+ Kind.ASCII_FIELD,
145
+ Kind.DOUBLE_PRECISION_BINARY_FIELD,
146
+ Kind.SINGLE_PRECISION_BINARY_FIELD,
147
+ ) and is_sequence(data):
69
148
  if data and isinstance(data[0], (int, float)):
70
149
  tensor_kind = b"scalar"
71
150
  elif is_sequence(data[0]) and data[0] and isinstance(data[0][0], (int, float)):
@@ -80,15 +159,21 @@ def dumps(
80
159
  else:
81
160
  return dumps(data)
82
161
 
83
- if kind == Kind.BINARY_FIELD:
162
+ if kind in (
163
+ Kind.DOUBLE_PRECISION_BINARY_FIELD,
164
+ Kind.SINGLE_PRECISION_BINARY_FIELD,
165
+ ):
166
+ typecode = "f" if kind == Kind.SINGLE_PRECISION_BINARY_FIELD else "d"
84
167
  if tensor_kind == b"scalar":
85
168
  data = cast(Sequence[float], data)
86
- contents = b"(" + array.array("d", data).tobytes() + b")"
169
+ contents = b"(" + array.array(typecode, data).tobytes() + b")"
87
170
  else:
88
171
  data = cast(Sequence[Sequence[float]], data)
89
172
  contents = (
90
173
  b"("
91
- + array.array("d", itertools.chain.from_iterable(data)).tobytes()
174
+ + array.array(
175
+ typecode, itertools.chain.from_iterable(data)
176
+ ).tobytes()
92
177
  + b")"
93
178
  )
94
179
  else:
@@ -96,9 +181,6 @@ def dumps(
96
181
 
97
182
  return b"nonuniform List<" + tensor_kind + b"> " + dumps(len(data)) + contents
98
183
 
99
- if kind != Kind.SINGLE_ENTRY and isinstance(data, tuple):
100
- return b" ".join(dumps(v) for v in data)
101
-
102
184
  if isinstance(data, FoamFileBase.Dimensioned):
103
185
  if data.name is not None:
104
186
  return (
@@ -114,6 +196,9 @@ def dumps(
114
196
  + dumps(data.value, kind=Kind.SINGLE_ENTRY)
115
197
  )
116
198
 
199
+ if isinstance(data, tuple):
200
+ return b" ".join(dumps(v) for v in data)
201
+
117
202
  if is_sequence(data):
118
203
  return b"(" + b" ".join(dumps(v, kind=Kind.SINGLE_ENTRY) for v in data) + b")"
119
204
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.6.12
3
+ Version: 0.6.13
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
@@ -1,4 +1,4 @@
1
- foamlib/__init__.py,sha256=fzKDNF8_CX5rU1KVBoVQZHdjJ_nEiRbLv_sfj6-CHAY,487
1
+ foamlib/__init__.py,sha256=QdspvCoifzrxd6lYysyhLGr4QIan-fYuWBPYDol5YgI,487
2
2
  foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  foamlib/_cases/__init__.py,sha256=wTUHcUgU1CBgpu0cUMtksQ5VKG6B8CFu9xc3dWwsQuo,358
4
4
  foamlib/_cases/_async.py,sha256=i6g4EBHqvI-1PkdrxsRto2ynW7sxsOga2bSYk1XVG1U,7795
@@ -10,13 +10,13 @@ foamlib/_cases/_sync.py,sha256=2BJXB7Nzldb4OgPukqupgYqdceUGkI2mYhhtGPWEBrc,5901
10
10
  foamlib/_cases/_util.py,sha256=lhVca3ERY0zwYjDam6W2QMROt0yX5vAF-9_DS5RuMbM,1547
11
11
  foamlib/_files/__init__.py,sha256=-UqB9YTH6mrJfXCX00kPTAAY20XG64u1MGPw_1ewLVs,148
12
12
  foamlib/_files/_base.py,sha256=ZY_6Zxr3LZHVzJEex6SUTi9Pgo7Oi7i3Jo-wre9G3yE,1968
13
- foamlib/_files/_files.py,sha256=WF_FWiDhnkA4dtZ6zR1A0iGrv76eI3SetlQu6Zl6HY8,14949
13
+ foamlib/_files/_files.py,sha256=oYRlMfCUH9oNeu-yf2HAPmLxLHteIe7gHhsWXdn7wU0,15767
14
14
  foamlib/_files/_io.py,sha256=IQLqoqnA1TpHf21NbUho2wsYWevyqC6MKo-wfpaObUU,2226
15
- foamlib/_files/_parsing.py,sha256=qLZx_VZMNEoyfmrkC_r85QBuABa26-6Y0fHnxCq74Q8,10880
16
- foamlib/_files/_serialization.py,sha256=HN9XCDbZ0I-b_UdpEYgDVNX6U4tPd6u-uYBKOoX3uqg,3681
15
+ foamlib/_files/_parsing.py,sha256=vFOKf2Rf3Z8Vr7TtDXOUq-dLxWAQzMeKVyYQcl91P2s,12991
16
+ foamlib/_files/_serialization.py,sha256=p2yRpyyOAOKP7P6T7BLEgRVvORuzQEcv_P6dEsOZ9_8,5981
17
17
  foamlib/_files/_util.py,sha256=VXUTD0B3NbnlaE_KCqWzrFcWvBz_2JfnIWpNp3snX3Y,526
18
- foamlib-0.6.12.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
19
- foamlib-0.6.12.dist-info/METADATA,sha256=fN1pEtQzMHd-yuzMkugYgTtpVwZwV-U0CPxU6rRTnzA,7742
20
- foamlib-0.6.12.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
21
- foamlib-0.6.12.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
22
- foamlib-0.6.12.dist-info/RECORD,,
18
+ foamlib-0.6.13.dist-info/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
19
+ foamlib-0.6.13.dist-info/METADATA,sha256=iWdp-dZBC-MJYEufP-ouDdsp3fy8CMfbXQWXM_EsWYo,7742
20
+ foamlib-0.6.13.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
21
+ foamlib-0.6.13.dist-info/top_level.txt,sha256=ZdVYtetXGwPwyfL-WhlhbTFQGAwKX5P_gXxtH9JYFPI,8
22
+ foamlib-0.6.13.dist-info/RECORD,,