foamlib 0.9.4__py3-none-any.whl → 0.9.6__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.9.4"
3
+ __version__ = "0.9.6"
4
4
 
5
5
  from ._cases import (
6
6
  AsyncFoamCase,
foamlib/_cases/_async.py CHANGED
@@ -44,13 +44,14 @@ class AsyncFoamCase(FoamCaseRunBase):
44
44
 
45
45
  Provides methods for running and cleaning cases, as well as accessing files.
46
46
 
47
- Access the time directories of the case as a sequence, e.g. `case[0]` or `case[-1]`.
48
- These will return `AsyncFoamCase.TimeDirectory` objects.
47
+ Access the time directories of the case as a sequence, e.g. ``case[0]`` or ``case[-1]``.
48
+ These will return :class:`AsyncFoamCase.TimeDirectory` objects.
49
49
 
50
50
  :param path: The path to the case directory. Defaults to the current working
51
51
  directory.
52
52
 
53
53
  Example usage: ::
54
+
54
55
  from foamlib import AsyncFoamCase
55
56
 
56
57
  case = AsyncFoamCase("path/to/case") # Load an OpenFOAM case
@@ -82,7 +83,7 @@ class AsyncFoamCase(FoamCaseRunBase):
82
83
 
83
84
  max_cpus = multiprocessing.cpu_count()
84
85
  """
85
- Maximum number of CPUs to use for running instances of `AsyncFoamCase` concurrently.
86
+ Maximum number of CPUs to use for running instances of :class:`AsyncFoamCase` concurrently.
86
87
 
87
88
  Defaults to the number of CPUs on the system.
88
89
  """
@@ -143,19 +144,23 @@ class AsyncFoamCase(FoamCaseRunBase):
143
144
  """
144
145
  Clean this case.
145
146
 
146
- If a `clean` or `Allclean` script is present in the case directory, it will be invoked.
147
+ If a ``clean`` or ``Allclean`` script is present in the case directory, it will be invoked.
147
148
  Otherwise, the case directory will be cleaned using these rules:
148
149
 
149
- - All time directories except `0` will be deleted.
150
- - The `0` time directory will be deleted if `0.orig` exists.
151
- - `processor*` directories will be deleted if a `system/decomposeParDict` file is present.
152
- - `constant/polyMesh` will be deleted if a `system/blockMeshDict` file is present.
153
- - All `log.*` files will be deleted.
150
+ - All time directories except ``0`` will be deleted.
151
+
152
+ - The ``0`` time directory will be deleted if ``0.orig`` exists.
153
+
154
+ - ``processor*`` directories will be deleted if a ``system/decomposeParDict`` file is present.
155
+
156
+ - ``constant/polyMesh`` will be deleted if a ``system/blockMeshDict`` file is present.
157
+
158
+ - All ``log.*`` files will be deleted.
154
159
 
155
160
  If this behavior is not appropriate for a case, it is recommended to write a custom
156
- `clean` script.
161
+ ``clean`` script.
157
162
 
158
- :param check: If True, raise a `CalledProcessError` if the clean script returns a
163
+ :param check: If True, raise a :class:`CalledProcessError` if the clean script returns a
159
164
  non-zero exit code.
160
165
  """
161
166
  for coro in self._clean_calls(check=check):
@@ -191,35 +196,40 @@ class AsyncFoamCase(FoamCaseRunBase):
191
196
  """
192
197
  Run this case, or a specified command in the context of this case.
193
198
 
194
- If `cmd` is given, this method will run the given command in the context of the case.
199
+ If ``cmd`` is given, this method will run the given command in the context of the case.
195
200
 
196
- If `cmd` is `None`, a series of heuristic rules will be used to run the case. This works as
201
+ If ``cmd`` is ``None``, a series of heuristic rules will be used to run the case. This works as
197
202
  follows:
198
203
 
199
- - If a `run`, `Allrun` or `Allrun-parallel` script is present in the case directory,
200
- it will be invoked. If both `run` and `Allrun` are present, `Allrun` will be used. If
201
- both `Allrun` and `Allrun-parallel` are present and `parallel` is `None`, an error will
202
- be raised.
203
- - If no run script is present but an `Allrun.pre` script exists, it will be invoked.
204
- - Otherwise, if a `system/blockMeshDict` file is present, the method will call
205
- `self.block_mesh()`.
206
- - Then, if a `0.orig` directory is present, it will call `self.restore_0_dir()`.
207
- - Then, if the case is to be run in parallel (see the `parallel` option) and no
208
- `processor*` directories exist but a`system/decomposeParDict` file is present, it will
209
- call `self.decompose_par()`.
204
+ - If a ``run``, ``Allrun`` or ``Allrun-parallel`` script is present in the case directory,
205
+ it will be invoked. If both ``run`` and ``Allrun`` are present, ``Allrun`` will be used. If
206
+ both ``Allrun`` and ``Allrun-parallel`` are present and ``parallel`` is ``None``, an error will
207
+ be raised.
208
+
209
+ - If no run script is present but an ``Allrun.pre`` script exists, it will be invoked.
210
+
211
+ - Otherwise, if a ``system/blockMeshDict`` file is present, the method will call
212
+ :meth:`block_mesh()`.
213
+
214
+ - Then, if a ``0.orig`` directory is present, it will call :meth:`restore_0_dir()`.
215
+
216
+ - Then, if the case is to be run in parallel (see the ``parallel`` option) and no
217
+ ``processor*`` directories exist but a ``system/decomposeParDict`` file is present, it will
218
+ call :meth:`decompose_par()`.
219
+
210
220
  - Then, it will run the case using the application specified in the `controlDict` file.
211
221
 
212
222
  If this behavior is not appropriate for a case, it is recommended to write a custom
213
- `run`, `Allrun`, `Allrun-parallel` or `Allrun.pre` script.
223
+ ``run``, ``Allrun``, ``Allrun-parallel`` or ``Allrun.pre`` script.
214
224
 
215
- :param cmd: The command to run. If `None`, run the case. If a sequence, the first element
216
- is the command and the rest are arguments. If a string, `cmd` is executed in a shell.
217
- :param parallel: If `True`, run in parallel using MPI. If None, autodetect whether to run
225
+ :param cmd: The command to run. If ``None``, run the case. If a sequence, the first element
226
+ is the command and the rest are arguments. If a string, ``cmd`` is executed in a shell.
227
+ :param parallel: If ``True``, run in parallel using MPI. If None, autodetect whether to run
218
228
  in parallel.
219
- :param cpus: The number of CPUs to use. If `None`, autodetect from to the case.
220
- :param check: If `True`, raise a `CalledProcessError` if any command returns a non-zero
229
+ :param cpus: The number of CPUs to use. If ``None``, autodetect from to the case.
230
+ :param check: If ``True``, raise a :class:`CalledProcessError` if any command returns a non-zero
221
231
  exit code.
222
- :param log: If `True`, log the command output to `log.*` files in the case directory.
232
+ :param log: If ``True``, log the command output to ``log.*`` files in the case directory.
223
233
  """
224
234
  for coro in self._run_calls(
225
235
  cmd=cmd, parallel=parallel, cpus=cpus, check=check, log=log
@@ -262,6 +272,7 @@ class AsyncFoamCase(FoamCaseRunBase):
262
272
  :return: The copy of the case.
263
273
 
264
274
  Example usage: ::
275
+
265
276
  import os
266
277
  from pathlib import Path
267
278
  from foamlib import AsyncFoamCase
@@ -298,6 +309,7 @@ class AsyncFoamCase(FoamCaseRunBase):
298
309
  :return: The clone of the case.
299
310
 
300
311
  Example usage: ::
312
+
301
313
  import os
302
314
  from pathlib import Path
303
315
  from foamlib import AsyncFoamCase
foamlib/_cases/_base.py CHANGED
@@ -23,10 +23,10 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
23
23
 
24
24
  Provides methods for accessing files and time directories in the case, but does not
25
25
  provide methods for running the case or any commands. Users are encouraged to use
26
- `FoamCase` or `AsyncFoamCase` instead of this class.
26
+ :class:`FoamCase` or :class:`AsyncFoamCase` instead of this class.
27
27
 
28
- Access the time directories of the case as a sequence, e.g. `case[0]` or `case[-1]`.
29
- These will return `FoamCaseBase.TimeDirectory` objects.
28
+ Access the time directories of the case as a sequence, e.g. ``case[0]`` or ``case[-1]``.
29
+ These will return class:`FoamCaseBase.TimeDirectory` objects.
30
30
 
31
31
  :param path: The path to the case directory. Defaults to the current working
32
32
  directory.
@@ -39,11 +39,11 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
39
39
  """
40
40
  A time directory in an OpenFOAM case.
41
41
 
42
- Use to access field files in the directory (e.g. `time["U"]`). These will be
43
- returned as `FoamFieldFile` objects.
42
+ Use to access field files in the directory (e.g. ``time["U"]``). These will be
43
+ returned as :class:`FoamFieldFile` objects.
44
44
 
45
- It also behaves as a set of `FoamFieldFile` objects (e.g. it can be
46
- iterated over with `for field in time: ...`).
45
+ It also behaves as a set of :class:`FoamFieldFile` objects (e.g. it can be
46
+ iterated over with ``for field in time: ...``).
47
47
  """
48
48
 
49
49
  def __init__(self, path: os.PathLike[str] | str) -> None:
@@ -154,7 +154,7 @@ class FoamCaseBase(Sequence["FoamCaseBase.TimeDirectory"]):
154
154
 
155
155
  @property
156
156
  def _nsubdomains(self) -> int | None:
157
- """Return the number of subdomains as set in the decomposeParDict, or None if no decomposeParDict is found."""
157
+ """Return the number of subdomains as set in the decomposeParDict, or ``None`` if no decomposeParDict is found."""
158
158
  try:
159
159
  nsubdomains = self.decompose_par_dict["numberOfSubdomains"]
160
160
  if not isinstance(nsubdomains, int):
foamlib/_cases/_run.py CHANGED
@@ -47,9 +47,9 @@ if TYPE_CHECKING:
47
47
 
48
48
  class FoamCaseRunBase(FoamCaseBase):
49
49
  """
50
- Abstract base class of `FoamCase` and `AsyncFoamCase`.
50
+ Abstract base class of :class:`FoamCase` and :class:`AsyncFoamCase`.
51
51
 
52
- Do not use this class directly: use `FoamCase` or `AsyncFoamCase` instead.
52
+ Do not use this class directly: use :class:`FoamCase` or :class:`AsyncFoamCase` instead.
53
53
  """
54
54
 
55
55
  class TimeDirectory(FoamCaseBase.TimeDirectory):
foamlib/_cases/_slurm.py CHANGED
@@ -20,9 +20,9 @@ class AsyncSlurmFoamCase(AsyncFoamCase):
20
20
  """
21
21
  An asynchronous OpenFOAM case that launches jobs on a Slurm cluster.
22
22
 
23
- `AsyncSlurmFoamCase` is a subclass of `AsyncFoamCase`. It provides the same interface,
24
- as the latter, except that it will launch jobs on a Slurm cluster (using `salloc` and
25
- `srun`) on the user's behalf when running a case or command.
23
+ :class:`AsyncSlurmFoamCase` is a subclass of :class:`AsyncFoamCase`. It provides the same interface,
24
+ as the latter, except that it will launch jobs on a Slurm cluster (using ``salloc`` and
25
+ ``srun``) on the user's behalf when running a case or command.
26
26
 
27
27
  :param path: The path to the case directory. Defaults to the current working
28
28
  directory.
@@ -64,12 +64,12 @@ class AsyncSlurmFoamCase(AsyncFoamCase):
64
64
  """
65
65
  Run this case, or a specified command in the context of this case.
66
66
 
67
- :param cmd: The command to run. If None, run the case. If a sequence, the first element is the command and the rest are arguments. If a string, `cmd` is executed in a shell.
68
- :param parallel: If True, run in parallel using MPI. If None, autodetect whether to run in parallel.
69
- :param cpus: The number of CPUs to use. If None, autodetect according to the case. If 0, run locally.
70
- :param check: If True, raise a CalledProcessError if any command returns a non-zero exit code.
71
- :param log: If True, log the command output to a file.
72
- :param fallback: If True, fall back to running the command locally if Slurm is not available.
67
+ :param cmd: The command to run. If ``None``, run the case. If a sequence, the first element is the command and the rest are arguments. If a string, `cmd` is executed in a shell.
68
+ :param parallel: If ``True``, run in parallel using MPI. If ``None``, autodetect whether to run in parallel.
69
+ :param cpus: The number of CPUs to use. If ``None``, autodetect according to the case. If ``0``, run locally.
70
+ :param check: If ``True``, raise a :class:`CalledProcessError` if any command returns a non-zero exit code.
71
+ :param log: If ``True``, log the command output to a file.
72
+ :param fallback: If ``True``, fall back to running the command locally if Slurm is not available.
73
73
  """
74
74
  for coro in self._run_calls(
75
75
  cmd=cmd,
foamlib/_cases/_sync.py CHANGED
@@ -32,8 +32,8 @@ class FoamCase(FoamCaseRunBase):
32
32
 
33
33
  Provides methods for running and cleaning cases, as well as accessing files.
34
34
 
35
- Access the time directories of the case as a sequence, e.g. `case[0]` or `case[-1]`.
36
- These will return `FoamCase.TimeDirectory` objects.
35
+ Access the time directories of the case as a sequence, e.g. ``case[0]`` or ``case[-1]``.
36
+ These will return :class:`FoamCase.TimeDirectory` objects.
37
37
 
38
38
  :param path: The path to the case directory. Defaults to the current working
39
39
  directory.
@@ -125,19 +125,23 @@ class FoamCase(FoamCaseRunBase):
125
125
  """
126
126
  Clean this case.
127
127
 
128
- If a `clean` or `Allclean` script is present in the case directory, it will be invoked.
128
+ If a ``clean`` or ``Allclean`` script is present in the case directory, it will be invoked.
129
129
  Otherwise, the case directory will be cleaned using these rules:
130
130
 
131
- - All time directories except `0` will be deleted.
132
- - The `0` time directory will be deleted if `0.orig` exists.
133
- - `processor*` directories will be deleted if a `system/decomposeParDict` file is present.
134
- - `constant/polyMesh` will be deleted if a `system/blockMeshDict` file is present.
135
- - All `log.*` files will be deleted.
131
+ - All time directories except ``0`` will be deleted.
132
+
133
+ - The ``0`` time directory will be deleted if ``0.orig`` exists.
134
+
135
+ - ``processor*`` directories will be deleted if a ``system/decomposeParDict`` file is present.
136
+
137
+ - ``constant/polyMesh`` will be deleted if a ``system/blockMeshDict`` file is present.
138
+
139
+ - All ``log.*`` files will be deleted.
136
140
 
137
141
  If this behavior is not appropriate for a case, it is recommended to write a custom
138
- `clean` script.
142
+ ``clean`` script.
139
143
 
140
- :param check: If True, raise a `CalledProcessError` if the clean script returns a
144
+ :param check: If True, raise a :class:`CalledProcessError` if the clean script returns a
141
145
  non-zero exit code.
142
146
  """
143
147
  for _ in self._clean_calls(check=check):
@@ -159,35 +163,40 @@ class FoamCase(FoamCaseRunBase):
159
163
  """
160
164
  Run this case, or a specified command in the context of this case.
161
165
 
162
- If `cmd` is given, this method will run the given command in the context of the case.
166
+ If ``cmd`` is given, this method will run the given command in the context of the case.
163
167
 
164
- If `cmd` is `None`, a series of heuristic rules will be used to run the case. This works as
168
+ If ``cmd`` is ``None``, a series of heuristic rules will be used to run the case. This works as
165
169
  follows:
166
170
 
167
- - If a `run`, `Allrun` or `Allrun-parallel` script is present in the case directory,
168
- it will be invoked. If both `run` and `Allrun` are present, `Allrun` will be used. If
169
- both `Allrun` and `Allrun-parallel` are present and `parallel` is `None`, an error will
170
- be raised.
171
- - If no run script is present but an `Allrun.pre` script exists, it will be invoked.
172
- - Otherwise, if a `system/blockMeshDict` file is present, the method will call
173
- `self.block_mesh()`.
174
- - Then, if a `0.orig` directory is present, it will call `self.restore_0_dir()`.
175
- - Then, if the case is to be run in parallel (see the `parallel` option) and no
176
- `processor*` directories exist but a`system/decomposeParDict` file is present, it will
177
- call `self.decompose_par()`.
171
+ - If a ``run``, ``Allrun`` or ``Allrun-parallel`` script is present in the case directory,
172
+ it will be invoked. If both ``run`` and ``Allrun`` are present, ``Allrun`` will be used. If
173
+ both ``Allrun`` and ``Allrun-parallel`` are present and :param:`parallel` is ``None``, an error will
174
+ be raised.
175
+
176
+ - If no run script is present but an ``Allrun.pre`` script exists, it will be invoked.
177
+
178
+ - Otherwise, if a ``system/blockMeshDict`` file is present, the method will call
179
+ :meth:`block_mesh()`.
180
+
181
+ - Then, if a ``0.orig`` directory is present, it will call :meth:`restore_0_dir()`.
182
+
183
+ - Then, if the case is to be run in parallel (see the :param:`parallel` option) and no
184
+ ``processor*`` directories exist but a ``system/decomposeParDict`` file is present, it will
185
+ call :meth:`decompose_par()`.
186
+
178
187
  - Then, it will run the case using the application specified in the `controlDict` file.
179
188
 
180
189
  If this behavior is not appropriate for a case, it is recommended to write a custom
181
- `run`, `Allrun`, `Allrun-parallel` or `Allrun.pre` script.
190
+ ``run``, ``Allrun``, ``Allrun-parallel`` or ``Allrun.pre`` script.
182
191
 
183
- :param cmd: The command to run. If `None`, run the case. If a sequence, the first element
184
- is the command and the rest are arguments. If a string, `cmd` is executed in a shell.
185
- :param parallel: If `True`, run in parallel using MPI. If None, autodetect whether to run
192
+ :param cmd: The command to run. If ``None``, run the case. If a sequence, the first element
193
+ is the command and the rest are arguments. If a string, ``cmd`` is executed in a shell.
194
+ :param parallel: If ``True``, run in parallel using MPI. If None, autodetect whether to run
186
195
  in parallel.
187
- :param cpus: The number of CPUs to use. If `None`, autodetect from to the case.
188
- :param check: If `True`, raise a `CalledProcessError` if any command returns a non-zero
196
+ :param cpus: The number of CPUs to use. If ``None``, autodetect from to the case.
197
+ :param check: If ``True``, raise a :class:`CalledProcessError` if any command returns a non-zero
189
198
  exit code.
190
- :param log: If `True`, log the command output to `log.*` files in the case directory.
199
+ :param log: If ``True``, log the command output to ``log.*`` files in the case directory.
191
200
  """
192
201
  for _ in self._run_calls(
193
202
  cmd=cmd, parallel=parallel, cpus=cpus, check=check, log=log
@@ -218,14 +227,15 @@ class FoamCase(FoamCaseRunBase):
218
227
  """
219
228
  Make a copy of this case.
220
229
 
221
- If used as a context manager (i.e., within a `with` block) the copy will be deleted
230
+ If used as a context manager (i.e., within a ``with`` block) the copy will be deleted
222
231
  automatically when exiting the block.
223
232
 
224
- :param dst: The destination path. If `None`, clone to `$FOAM_RUN/foamlib`.
233
+ :param dst: The destination path. If ``None``, clone to ``$FOAM_RUN/foamlib``.
225
234
 
226
235
  :return: The copy of the case.
227
236
 
228
237
  Example usage: ::
238
+
229
239
  import os
230
240
  from pathlib import Path
231
241
  from foamlib import FoamCase
@@ -245,17 +255,18 @@ class FoamCase(FoamCaseRunBase):
245
255
  """
246
256
  Clone this case (make a clean copy).
247
257
 
248
- This is equivalent to running `self.copy().clean()`, but it can be more efficient in cases
258
+ This is equivalent to running ``self.copy().clean()``, but it can be more efficient in cases
249
259
  that do not contain custom clean scripts.
250
260
 
251
- If used as a context manager (i.e., within a `with` block) the cloned copy will be deleted
261
+ If used as a context manager (i.e., within a ``with`` block) the cloned copy will be deleted
252
262
  automatically when exiting the block.
253
263
 
254
- :param dst: The destination path. If `None`, clone to `$FOAM_RUN/foamlib`.
264
+ :param dst: The destination path. If ``None``, clone to ``$FOAM_RUN/foamlib``.
255
265
 
256
266
  :return: The clone of the case.
257
267
 
258
268
  Example usage: ::
269
+
259
270
  import os
260
271
  from pathlib import Path
261
272
  from foamlib import FoamCase
foamlib/_files/_files.py CHANGED
@@ -72,30 +72,31 @@ class FoamFile(
72
72
  """
73
73
  An OpenFOAM data file.
74
74
 
75
- `FoamFile` supports most OpenFOAM data and configuration files (i.e., files with a
75
+ :class:`FoamFile` supports most OpenFOAM data and configuration files (i.e., files with a
76
76
  "FoamFile" header), including those with regular expressions and #-based directives.
77
77
  Notable exceptions are FoamFiles with #codeStreams and those multiple #-directives
78
78
  with the same name, which are currently not supported. Non-FoamFile output files are
79
79
  also not suppored by this class. Regular expressions and #-based directives can be
80
80
  accessed and modified, but they are not evaluated or expanded by this library.
81
81
 
82
- Use `FoamFile` as a mutable mapping (i.e., like a `dict`) to access and modify
82
+ Use :class:`FoamFile` as a mutable mapping (i.e., like a :class:`dict`) to access and modify
83
83
  entries. When accessing a sub-dictionary, the returned value will be a
84
- `FoamFile.SubDict` object, that allows for further access and modification of nested
85
- dictionaries within the `FoamFile` in a single operation.
84
+ :class:`FoamFile.SubDict` object, that allows for further access and modification of nested
85
+ dictionaries within the :class:`FoamFile` in a single operation.
86
86
 
87
- If the `FoamFile` does not store a dictionary, the main stored value can be accessed
88
- and modified by passing `None` as the key (e.g., `file[None]`).
87
+ If the :class:`FoamFile` does not store a dictionary, the main stored value can be accessed
88
+ and modified by passing ``None`` as the key (e.g., ``file[None]``).
89
89
 
90
- You can also use the `FoamFile` as a context manager (i.e., within a `with` block)
90
+ You can also use the :class:`FoamFile` as a context manager (i.e., within a ``with`` block)
91
91
  to make multiple changes to the file while saving any and all changes only once at
92
92
  the end.
93
93
 
94
94
  :param path: The path to the file. If the file does not exist, it will be created
95
95
  when the first change is made. However, if an attempt is made to access entries
96
- in a non-existent file, a `FileNotFoundError` will be raised.
96
+ in a non-existent file, a :class:`FileNotFoundError` will be raised.
97
97
 
98
98
  Example usage: ::
99
+
99
100
  from foamlib import FoamFile
100
101
 
101
102
  file = FoamFile("path/to/case/system/controlDict") # Load a controlDict file
@@ -104,6 +105,7 @@ class FoamFile(
104
105
  file["writeFormat"] = "binary" # Set the write format to binary
105
106
 
106
107
  or (better): ::
108
+
107
109
  from foamlib import FoamCase
108
110
 
109
111
  case = FoamCase("path/to/case")
@@ -123,14 +125,15 @@ class FoamFile(
123
125
  """
124
126
  An OpenFOAM sub-dictionary within a file.
125
127
 
126
- `FoamFile.SubDict` is a mutable mapping that allows for accessing and modifying
127
- nested dictionaries within a `FoamFile` in a single operation. It behaves like a
128
- `dict` and can be used to access and modify entries in the sub-dictionary.
128
+ :class:`FoamFile.SubDict` is a mutable mapping that allows for accessing and modifying
129
+ nested dictionaries within a :class:`FoamFile` in a single operation. It behaves like a
130
+ :class:`dict` and can be used to access and modify entries in the sub-dictionary.
129
131
 
130
- To obtain a `FoamFile.SubDict` object, access a sub-dictionary in a `FoamFile`
131
- object (e.g., `file["subDict"]`).
132
+ To obtain a :class:`FoamFile.SubDict` object, access a sub-dictionary in a :class:`FoamFile`
133
+ object (e.g., ``file["subDict"]``).
132
134
 
133
135
  Example usage: ::
136
+
134
137
  from foamlib import FoamFile
135
138
 
136
139
  file = FoamFile("path/to/case/system/fvSchemes") # Load an fvSchemes file
@@ -138,6 +141,7 @@ class FoamFile(
138
141
  file["ddtSchemes"]["default"] = "Euler" # Set the default ddt scheme
139
142
 
140
143
  or (better): ::
144
+
141
145
  from foamlib import FoamCase
142
146
 
143
147
  case = FoamCase("path/to/case")
@@ -200,7 +204,7 @@ class FoamFile(
200
204
 
201
205
  @property
202
206
  def version(self) -> float:
203
- """Alias of `self["FoamFile", "version"]`."""
207
+ """Alias of ``self["FoamFile"]["version"]``."""
204
208
  ret = self["FoamFile", "version"]
205
209
  if not isinstance(ret, (int, float)):
206
210
  msg = "version is not a number"
@@ -213,7 +217,7 @@ class FoamFile(
213
217
 
214
218
  @property
215
219
  def format(self) -> Literal["ascii", "binary"]:
216
- """Alias of `self["FoamFile", "format"]`."""
220
+ """Alias of ``self["FoamFile"]["format"]``."""
217
221
  ret = self["FoamFile", "format"]
218
222
  if not isinstance(ret, str):
219
223
  msg = "format is not a string"
@@ -229,7 +233,7 @@ class FoamFile(
229
233
 
230
234
  @property
231
235
  def class_(self) -> str:
232
- """Alias of `self["FoamFile", "class"]`."""
236
+ """Alias of ``self["FoamFile"]["class"]``."""
233
237
  ret = self["FoamFile", "class"]
234
238
  if not isinstance(ret, str):
235
239
  msg = "class is not a string"
@@ -242,7 +246,7 @@ class FoamFile(
242
246
 
243
247
  @property
244
248
  def location(self) -> str:
245
- """Alias of `self["FoamFile", "location"]`."""
249
+ """Alias of ``self["FoamFile"]["location"]``."""
246
250
  ret = self["FoamFile", "location"]
247
251
  if not isinstance(ret, str):
248
252
  msg = "location is not a string"
@@ -255,7 +259,7 @@ class FoamFile(
255
259
 
256
260
  @property
257
261
  def object_(self) -> str:
258
- """Alias of `self["FoamFile", "object"]`."""
262
+ """Alias of ``self["FoamFile"]["object"]``."""
259
263
  ret = self["FoamFile", "object"]
260
264
  if not isinstance(ret, str):
261
265
  msg = "object is not a string"
@@ -500,7 +504,7 @@ class FoamFile(
500
504
  :param file: The Python object to serialize. This can be a dictionary, list,
501
505
  or any other object that can be serialized to the OpenFOAM format.
502
506
  :param ensure_header: Whether to include the "FoamFile" header in the output.
503
- If `True`, a header will be included if it is not already present in the
507
+ If ``True``, a header will be included if it is not already present in the
504
508
  input object.
505
509
  """
506
510
  header: SubDict | None
@@ -547,20 +551,21 @@ class FoamFile(
547
551
 
548
552
  class FoamFieldFile(FoamFile):
549
553
  """
550
- Subclass of `FoamFile` for representing OpenFOAM field files specifically.
554
+ Subclass of :class:`FoamFile` for representing OpenFOAM field files specifically.
551
555
 
552
- The difference between `FoamFieldFile` and `FoamFile` is that `FoamFieldFile` has
553
- the additional properties `dimensions`, `internal_field`, and `boundary_field` that
556
+ The difference between :class:`FoamFieldFile` and :class:`FoamFile` is that :class:`FoamFieldFile` has
557
+ the additional properties :attr:`dimensions`, :attr:`internal_field`, and :attr:`boundary_field` that
554
558
  are commonly found in OpenFOAM field files. Note that these are only a shorthand for
555
559
  accessing the corresponding entries in the file.
556
560
 
557
- See `FoamFile` for more information on how to read and edit OpenFOAM files.
561
+ See :class:`FoamFile` for more information on how to read and edit OpenFOAM files.
558
562
 
559
563
  :param path: The path to the file. If the file does not exist, it will be created
560
564
  when the first change is made. However, if an attempt is made to access entries
561
- in a non-existent file, a `FileNotFoundError` will be raised.
565
+ in a non-existent file, a :class:`FileNotFoundError` will be raised.
562
566
 
563
567
  Example usage: ::
568
+
564
569
  from foamlib import FoamFieldFile
565
570
 
566
571
  field = FoamFieldFile("path/to/case/0/U") # Load a field
@@ -569,6 +574,7 @@ class FoamFieldFile(FoamFile):
569
574
  field.internal_field = [0, 0, 0] # Set the internal field
570
575
 
571
576
  or (better): ::
577
+
572
578
  from foamlib import FoamCase
573
579
 
574
580
  case = FoamCase("path/to/case")
@@ -591,7 +597,7 @@ class FoamFieldFile(FoamFile):
591
597
 
592
598
  @property
593
599
  def type(self) -> str:
594
- """Alias of `self["type"]`."""
600
+ """Alias of ``self["type"]``."""
595
601
  ret = self["type"]
596
602
  if not isinstance(ret, str):
597
603
  msg = "type is not a string"
@@ -606,7 +612,7 @@ class FoamFieldFile(FoamFile):
606
612
  def value(
607
613
  self,
608
614
  ) -> Field:
609
- """Alias of `self["value"]`."""
615
+ """Alias of ``self["value"]``."""
610
616
  return cast(
611
617
  "Field",
612
618
  self["value"],
@@ -641,7 +647,7 @@ class FoamFieldFile(FoamFile):
641
647
 
642
648
  @property
643
649
  def dimensions(self) -> DimensionSet | Sequence[float]:
644
- """Alias of `self["dimensions"]`."""
650
+ """Alias of ``self["dimensions"]``."""
645
651
  ret = self["dimensions"]
646
652
  if not isinstance(ret, DimensionSet):
647
653
  msg = "dimensions is not a DimensionSet"
@@ -656,7 +662,7 @@ class FoamFieldFile(FoamFile):
656
662
  def internal_field(
657
663
  self,
658
664
  ) -> Field:
659
- """Alias of `self["internalField"]`."""
665
+ """Alias of ``self["internalField"]``."""
660
666
  return cast("Field", self["internalField"])
661
667
 
662
668
  @internal_field.setter
@@ -668,7 +674,7 @@ class FoamFieldFile(FoamFile):
668
674
 
669
675
  @property
670
676
  def boundary_field(self) -> FoamFieldFile.BoundariesSubDict:
671
- """Alias of `self["boundaryField"]`."""
677
+ """Alias of ``self["boundaryField"]``."""
672
678
  ret = self["boundaryField"]
673
679
  if not isinstance(ret, FoamFieldFile.BoundariesSubDict):
674
680
  assert not isinstance(ret, FoamFile.SubDict)
@@ -363,11 +363,14 @@ _FIELD = (Keyword("uniform", _IDENTBODYCHARS).suppress() + _TENSOR) | (
363
363
  _DIRECTIVE = Word("#", _IDENTBODYCHARS)
364
364
  _TOKEN = dbl_quoted_string | _DIRECTIVE | _IDENTIFIER
365
365
  _DATA = Forward()
366
+ _DATA_ENTRY = Forward()
366
367
  _KEYWORD_ENTRY = _keyword_entry_of(
367
- _TOKEN | _list_of(_IDENTIFIER), Opt(_DATA, default="")
368
+ _TOKEN | _list_of(_IDENTIFIER),
369
+ Opt(_DATA, default=""),
370
+ directive=_DIRECTIVE,
371
+ data_entry=_DATA_ENTRY,
368
372
  )
369
373
  _DICT = _dict_of(_TOKEN, _DATA)
370
- _DATA_ENTRY = Forward()
371
374
  _LIST_ENTRY = _DICT | _KEYWORD_ENTRY | _DATA_ENTRY
372
375
  _LIST = _list_of(_LIST_ENTRY)
373
376
  _NUMBER = (
@@ -388,9 +391,9 @@ _DATA <<= _DATA_ENTRY[1, ...].set_parse_action(
388
391
 
389
392
  _STANDALONE_DATA = (
390
393
  _ascii_numeric_list(dtype=int, ignore=_COMMENT)
394
+ | _ascii_numeric_list(dtype=float, nested=3, ignore=_COMMENT)
391
395
  | _binary_numeric_list(dtype=np.int64)
392
396
  | _binary_numeric_list(dtype=np.int32)
393
- | _ascii_numeric_list(dtype=float, nested=3, ignore=_COMMENT)
394
397
  | _binary_numeric_list(dtype=np.float64, nested=3)
395
398
  | _binary_numeric_list(dtype=np.float32, nested=3)
396
399
  | _DATA
@@ -87,7 +87,7 @@ def normalize_data(
87
87
  if arr.ndim == 1 or (arr.ndim == 2 and arr.shape[1] in (3, 6, 9)):
88
88
  return arr # type: ignore [return-value]
89
89
 
90
- return [normalize_data(d) for d in data] # type: ignore [arg-type]
90
+ return [normalize_data(d) for d in data] # type: ignore [arg-type, misc]
91
91
 
92
92
  if isinstance(data, int):
93
93
  return float(data)
@@ -112,7 +112,7 @@ def normalize_data(
112
112
  if keywords is None and isinstance(data, tuple) and len(data) == 2:
113
113
  k, v = data
114
114
  assert not isinstance(k, Mapping)
115
- return (
115
+ return ( # type: ignore [return-value]
116
116
  normalize_keyword(k), # type: ignore [arg-type]
117
117
  normalize_data(v) if not isinstance(v, Mapping) else v, # type: ignore [arg-type, misc]
118
118
  )
@@ -122,10 +122,10 @@ def normalize_data(
122
122
  and not isinstance(data, DimensionSet)
123
123
  and not isinstance(data, tuple)
124
124
  ):
125
- return [normalize_data(d) for d in data] # type: ignore [arg-type]
125
+ return [normalize_data(d) for d in data] # type: ignore [arg-type, misc]
126
126
 
127
127
  if isinstance(data, tuple) and not isinstance(data, DimensionSet):
128
- return tuple(normalize_data(d) for d in data)
128
+ return tuple(normalize_data(d) for d in data) # type: ignore [misc]
129
129
 
130
130
  if isinstance(data, str):
131
131
  s = loads(data)
@@ -247,7 +247,8 @@ def dumps(
247
247
  if isinstance(data, tuple):
248
248
  if tuple_is_entry:
249
249
  k, v = data
250
- ret = dumps(k)
250
+ ret = b"\n" if isinstance(k, str) and k[0] == "#" else b""
251
+ ret += dumps(k)
251
252
  val = dumps(
252
253
  v,
253
254
  keywords=(*keywords, k)
@@ -256,7 +257,9 @@ def dumps(
256
257
  )
257
258
  if val:
258
259
  ret += b" " + val
259
- if not isinstance(v, Mapping):
260
+ if isinstance(k, str) and k[0] == "#":
261
+ ret += b"\n"
262
+ elif not isinstance(v, Mapping):
260
263
  ret += b";"
261
264
  return ret
262
265
 
foamlib/_files/_types.py CHANGED
@@ -199,25 +199,38 @@ FieldLike = Union[
199
199
  ]
200
200
 
201
201
 
202
- Data = Union[
202
+ DataEntry = Union[
203
203
  str,
204
204
  int,
205
205
  float,
206
206
  bool,
207
207
  Dimensioned,
208
208
  DimensionSet,
209
- Tuple["Data", ...],
210
- List[Union["Data", Tuple["Data", Union["Data", "SubDict"]]]],
209
+ List[Union["DataEntry", Tuple["DataEntry", Union["DataEntry", "SubDict"]]]],
211
210
  Field,
212
211
  ]
213
212
 
214
- DataLike = Union[
215
- Data,
216
- Tuple["DataLike", ...],
217
- Sequence[Union["DataLike", Tuple["DataLike", Union["DataLike", "SubDictLike"]]]],
213
+ DataEntryLike = Union[
214
+ DataEntry,
215
+ Sequence[
216
+ Union[
217
+ "DataEntryLike",
218
+ Tuple["DataEntryLike", Union["DataEntryLike", "SubDictLike"]],
219
+ ]
220
+ ],
218
221
  FieldLike,
219
222
  ]
220
223
 
224
+ Data = Union[
225
+ DataEntry,
226
+ Tuple[DataEntry, ...],
227
+ ]
228
+
229
+ DataLike = Union[
230
+ DataEntryLike,
231
+ Tuple["DataEntryLike", ...],
232
+ ]
233
+
221
234
  StandaloneData = Union[
222
235
  Data,
223
236
  "np.ndarray[tuple[int], np.dtype[np.int64 | np.int32]]",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: foamlib
3
- Version: 0.9.4
3
+ Version: 0.9.6
4
4
  Summary: A Python interface for interacting with OpenFOAM
5
5
  Project-URL: Homepage, https://github.com/gerlero/foamlib
6
6
  Project-URL: Repository, https://github.com/gerlero/foamlib
@@ -196,148 +196,9 @@ case = FoamCase(Path(__file__).parent)
196
196
  case.run()
197
197
  ```
198
198
 
199
- ## ▶️ A complete example
199
+ ## 📘 Documentation
200
200
 
201
- The following is a fully self-contained example that demonstrates how to create an OpenFOAM case from scratch, run it, and analyze the results.
202
-
203
- <details>
204
-
205
- <summary>Example</summary>
206
-
207
- ```python
208
- #!/usr/bin/env python3
209
- """Check the diffusion of a scalar field in a scalarTransportFoam case."""
210
-
211
- import shutil
212
- from pathlib import Path
213
-
214
- import numpy as np
215
- from scipy.special import erfc
216
- from foamlib import FoamCase
217
-
218
- path = Path(__file__).parent / "diffusionCheck"
219
- shutil.rmtree(path, ignore_errors=True)
220
- path.mkdir(parents=True)
221
- (path / "system").mkdir()
222
- (path / "constant").mkdir()
223
- (path / "0").mkdir()
224
-
225
- case = FoamCase(path)
226
-
227
- with case.control_dict as f:
228
- f["application"] = "scalarTransportFoam"
229
- f["startFrom"] = "latestTime"
230
- f["stopAt"] = "endTime"
231
- f["endTime"] = 5
232
- f["deltaT"] = 1e-3
233
- f["writeControl"] = "adjustableRunTime"
234
- f["writeInterval"] = 1
235
- f["purgeWrite"] = 0
236
- f["writeFormat"] = "ascii"
237
- f["writePrecision"] = 6
238
- f["writeCompression"] = False
239
- f["timeFormat"] = "general"
240
- f["timePrecision"] = 6
241
- f["adjustTimeStep"] = False
242
- f["runTimeModifiable"] = False
243
-
244
- with case.fv_schemes as f:
245
- f["ddtSchemes"] = {"default": "Euler"}
246
- f["gradSchemes"] = {"default": "Gauss linear"}
247
- f["divSchemes"] = {"default": "none", "div(phi,U)": "Gauss linear", "div(phi,T)": "Gauss linear"}
248
- f["laplacianSchemes"] = {"default": "Gauss linear corrected"}
249
-
250
- with case.fv_solution as f:
251
- f["solvers"] = {"T": {"solver": "PBiCG", "preconditioner": "DILU", "tolerance": 1e-6, "relTol": 0}}
252
-
253
- with case.block_mesh_dict as f:
254
- f["scale"] = 1
255
- f["vertices"] = [
256
- [0, 0, 0],
257
- [1, 0, 0],
258
- [1, 0.5, 0],
259
- [1, 1, 0],
260
- [0, 1, 0],
261
- [0, 0.5, 0],
262
- [0, 0, 0.1],
263
- [1, 0, 0.1],
264
- [1, 0.5, 0.1],
265
- [1, 1, 0.1],
266
- [0, 1, 0.1],
267
- [0, 0.5, 0.1],
268
- ]
269
- f["blocks"] = [
270
- "hex", [0, 1, 2, 5, 6, 7, 8, 11], [400, 20, 1], "simpleGrading", [1, 1, 1],
271
- "hex", [5, 2, 3, 4, 11, 8, 9, 10], [400, 20, 1], "simpleGrading", [1, 1, 1],
272
- ]
273
- f["edges"] = []
274
- f["boundary"] = [
275
- ("inletUp", {"type": "patch", "faces": [[5, 4, 10, 11]]}),
276
- ("inletDown", {"type": "patch", "faces": [[0, 5, 11, 6]]}),
277
- ("outletUp", {"type": "patch", "faces": [[2, 3, 9, 8]]}),
278
- ("outletDown", {"type": "patch", "faces": [[1, 2, 8, 7]]}),
279
- ("walls", {"type": "wall", "faces": [[4, 3, 9, 10], [0, 1, 7, 6]]}),
280
- ("frontAndBack", {"type": "empty", "faces": [[0, 1, 2, 5], [5, 2, 3, 4], [6, 7, 8, 11], [11, 8, 9, 10]]}),
281
- ]
282
- f["mergePatchPairs"] = []
283
-
284
- with case.transport_properties as f:
285
- f["DT"] = f.Dimensioned(1e-3, f.DimensionSet(length=2, time=-1), "DT")
286
-
287
- with case[0]["U"] as f:
288
- f.dimensions = f.DimensionSet(length=1, time=-1)
289
- f.internal_field = [1, 0, 0]
290
- f.boundary_field = {
291
- "inletUp": {"type": "fixedValue", "value": [1, 0, 0]},
292
- "inletDown": {"type": "fixedValue", "value": [1, 0, 0]},
293
- "outletUp": {"type": "zeroGradient"},
294
- "outletDown": {"type": "zeroGradient"},
295
- "walls": {"type": "zeroGradient"},
296
- "frontAndBack": {"type": "empty"},
297
- }
298
-
299
- with case[0]["T"] as f:
300
- f.dimensions = f.DimensionSet(temperature=1)
301
- f.internal_field = 0
302
- f.boundary_field = {
303
- "inletUp": {"type": "fixedValue", "value": 0},
304
- "inletDown": {"type": "fixedValue", "value": 1},
305
- "outletUp": {"type": "zeroGradient"},
306
- "outletDown": {"type": "zeroGradient"},
307
- "walls": {"type": "zeroGradient"},
308
- "frontAndBack": {"type": "empty"},
309
- }
310
-
311
- case.run()
312
-
313
- x, y, z = case[0].cell_centers().internal_field.T
314
-
315
- end = x == x.max()
316
- x = x[end]
317
- y = y[end]
318
- z = z[end]
319
-
320
- DT = case.transport_properties["DT"].value
321
- U = case[0]["U"].internal_field[0]
322
-
323
- for time in case[1:]:
324
- if U*time.time < 2*x.max():
325
- continue
326
-
327
- T = time["T"].internal_field[end]
328
- analytical = 0.5 * erfc((y - 0.5) / np.sqrt(4 * DT * x/U))
329
- if np.allclose(T, analytical, atol=0.1):
330
- print(f"Time {time.time}: OK")
331
- else:
332
- raise RuntimeError(f"Time {time.time}: {T} != {analytical}")
333
- ```
334
-
335
- </details>
336
-
337
-
338
- ## 📘 API documentation
339
-
340
- For more information on how to use **foamlibs**'s classes and methods, check out the [documentation](https://foamlib.readthedocs.io/).
201
+ For details on how to use **foamlib**, check out the [documentation](https://foamlib.readthedocs.io/).
341
202
 
342
203
  ## 🙋 Support
343
204
 
@@ -0,0 +1,20 @@
1
+ foamlib/__init__.py,sha256=vCYvM91T-aVKjhzaBbxMdeEvOdQ_0dFOLV5vLi7yMoU,452
2
+ foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ foamlib/_cases/__init__.py,sha256=_A1TTHuQfS9FH2_33lSEyLtOJZGFHZBco1tWJCVOHks,358
4
+ foamlib/_cases/_async.py,sha256=1NuBaKa7NC-320SFNYW7JWZ5rAi344br_SoEdl64dmo,11797
5
+ foamlib/_cases/_base.py,sha256=0Bb45FWxxMRnx6njtnJ3Tqh2_NcphrPtVSFjmfYbTjw,7480
6
+ foamlib/_cases/_run.py,sha256=C5sf-PWE73cqyPVmmWDiZU3V9QYVsrhSXpgil7aIp10,15659
7
+ foamlib/_cases/_slurm.py,sha256=X8eSL_tDnip3bPHb2Fot-n1yD0FfiVP5sCxHxjKt1f0,2748
8
+ foamlib/_cases/_subprocess.py,sha256=VHV2SuOLqa711an6kCuvN6UlIkeh4qqFfdrpNoKzQps,5630
9
+ foamlib/_cases/_sync.py,sha256=lsgJV2dMAAmmsiJMtzqy1bhW3yAZQOUMXh3h8jNqyes,9799
10
+ foamlib/_cases/_util.py,sha256=QCizfbuJdOCeF9ogU2R-y-iWX5kfaOA4U2W68t6QlOM,2544
11
+ foamlib/_files/__init__.py,sha256=q1vkjXnjnSZvo45jPAICpWeF2LZv5V6xfzAR6S8fS5A,96
12
+ foamlib/_files/_files.py,sha256=HwK7ptuxmbpymXaAr6Lsd1g-qc6trGZSC1Ch1wVHQFQ,22863
13
+ foamlib/_files/_io.py,sha256=BGbbm6HKxL2ka0YMCmHqZQZ1R4PPQlkvWWb4FHMAS8k,2217
14
+ foamlib/_files/_parsing.py,sha256=AOrAEhX418ExfuX-_gKezQPLpu6B-fZmAVpJ1EVMWGw,17718
15
+ foamlib/_files/_serialization.py,sha256=P7u2EUx0OwvfVYinp46CpzdjGYGXJVN0-xXXuOYogfA,8020
16
+ foamlib/_files/_types.py,sha256=eNVxuK_NDRqh0mrTcseuAD3lqn4VEBGVUYhXn-T1zEU,7884
17
+ foamlib-0.9.6.dist-info/METADATA,sha256=V2i6Gb4Yl07tXbwKGNLNUyi3LN6ozr4cl79CUWeuK-w,8701
18
+ foamlib-0.9.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
+ foamlib-0.9.6.dist-info/licenses/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
20
+ foamlib-0.9.6.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- foamlib/__init__.py,sha256=LQALCtihE20dGUDWlQdYlr_X7vLFUhOExPzWqPtDDAY,452
2
- foamlib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- foamlib/_cases/__init__.py,sha256=_A1TTHuQfS9FH2_33lSEyLtOJZGFHZBco1tWJCVOHks,358
4
- foamlib/_cases/_async.py,sha256=e4lGTcQBbFGwfG6SmJks5aa5LWd_0dy01kgKZWAgTGQ,11655
5
- foamlib/_cases/_base.py,sha256=CNfutRnqniTNS1xQZ2EUeK0n2VXTgRoFHadepWBndKs,7434
6
- foamlib/_cases/_run.py,sha256=aD9JNv7YAs5GJGWXlYQAhr_-QT-46CUxecCPyrCmFA0,15631
7
- foamlib/_cases/_slurm.py,sha256=2nimUWxHSkZdtmRROzcvnLW5urgmkNqxoTkCUmxALVE,2689
8
- foamlib/_cases/_subprocess.py,sha256=VHV2SuOLqa711an6kCuvN6UlIkeh4qqFfdrpNoKzQps,5630
9
- foamlib/_cases/_sync.py,sha256=yhrkwStKri7u41YImYCGBH4REcKn8Ar-32VW_WPa40c,9641
10
- foamlib/_cases/_util.py,sha256=QCizfbuJdOCeF9ogU2R-y-iWX5kfaOA4U2W68t6QlOM,2544
11
- foamlib/_files/__init__.py,sha256=q1vkjXnjnSZvo45jPAICpWeF2LZv5V6xfzAR6S8fS5A,96
12
- foamlib/_files/_files.py,sha256=nbf9SPGH4v4-H4mxiMtiD8YuBJJdGC8RFlV_KLFM6bA,22676
13
- foamlib/_files/_io.py,sha256=BGbbm6HKxL2ka0YMCmHqZQZ1R4PPQlkvWWb4FHMAS8k,2217
14
- foamlib/_files/_parsing.py,sha256=CWALQclNOXUlPylI98h2DxMNz5OE0KZf9Gioc9h3OWU,17659
15
- foamlib/_files/_serialization.py,sha256=R7hnUNWH1McOnu4k7grfbJKvNGhADSSTIOIXrDDtw74,7800
16
- foamlib/_files/_types.py,sha256=SmKA6I1l6Q7JHOlhLFV1s2cU3tkeBQmj13lW3ETlKU0,7710
17
- foamlib-0.9.4.dist-info/METADATA,sha256=jRLgmp_A9dsqH2P_RzhESlkSBLlGB3XeC4xFljDzhRM,12906
18
- foamlib-0.9.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
19
- foamlib-0.9.4.dist-info/licenses/LICENSE.txt,sha256=5Dte9TUnLZzPRs4NQzl-Jc2-Ljd-t_v0ZR5Ng5r0UsY,35131
20
- foamlib-0.9.4.dist-info/RECORD,,