foamlib 0.5.0__tar.gz → 0.5.1__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.
Files changed (27) hide show
  1. {foamlib-0.5.0 → foamlib-0.5.1}/PKG-INFO +20 -1
  2. {foamlib-0.5.0 → foamlib-0.5.1}/README.md +19 -0
  3. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/__init__.py +1 -1
  4. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_cases/_async.py +19 -7
  5. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_cases/_sync.py +31 -3
  6. foamlib-0.5.1/foamlib/_cases/_util.py +49 -0
  7. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib.egg-info/PKG-INFO +20 -1
  8. foamlib-0.5.0/foamlib/_cases/_util.py +0 -27
  9. {foamlib-0.5.0 → foamlib-0.5.1}/LICENSE.txt +0 -0
  10. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_cases/__init__.py +0 -0
  11. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_cases/_base.py +0 -0
  12. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_cases/_recipes.py +0 -0
  13. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_cases/_subprocess.py +0 -0
  14. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/__init__.py +0 -0
  15. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/_base.py +0 -0
  16. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/_files.py +0 -0
  17. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/_io.py +0 -0
  18. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/_parsing.py +0 -0
  19. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/_serialization.py +0 -0
  20. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/_files/_util.py +0 -0
  21. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib/py.typed +0 -0
  22. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib.egg-info/SOURCES.txt +0 -0
  23. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib.egg-info/dependency_links.txt +0 -0
  24. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib.egg-info/requires.txt +0 -0
  25. {foamlib-0.5.0 → foamlib-0.5.1}/foamlib.egg-info/top_level.txt +0 -0
  26. {foamlib-0.5.0 → foamlib-0.5.1}/pyproject.toml +0 -0
  27. {foamlib-0.5.0 → foamlib-0.5.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.5.0
3
+ Version: 0.5.1
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
@@ -155,6 +155,25 @@ U = FoamFieldFile(Path(my_pitz) / "0/U")
155
155
  print(U.internal_field)
156
156
  ```
157
157
 
158
+ ### Run an optimization loop in parallel
159
+
160
+ ```python
161
+ import os
162
+ from pathlib import Path
163
+ from foamlib import AsyncFoamCase
164
+ from scipy.optimize import differential_evolution
165
+
166
+ base = AsyncFoamCase(Path(os.environ["FOAM_TUTORIALS"]) / "incompressible/simpleFoam/pitzDaily")
167
+
168
+ async def cost(x):
169
+ async with base.clone() as clone:
170
+ clone[0]["U"].boundary_field["inlet"].value = [x[0], 0, 0]
171
+ await clone.run()
172
+ return abs(clone[-1]["U"].internal_field[0][0])
173
+
174
+ result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
175
+ ```
176
+
158
177
  ## Documentation
159
178
 
160
179
  For more information, check out the [documentation](https://foamlib.readthedocs.io/).
@@ -101,6 +101,25 @@ U = FoamFieldFile(Path(my_pitz) / "0/U")
101
101
  print(U.internal_field)
102
102
  ```
103
103
 
104
+ ### Run an optimization loop in parallel
105
+
106
+ ```python
107
+ import os
108
+ from pathlib import Path
109
+ from foamlib import AsyncFoamCase
110
+ from scipy.optimize import differential_evolution
111
+
112
+ base = AsyncFoamCase(Path(os.environ["FOAM_TUTORIALS"]) / "incompressible/simpleFoam/pitzDaily")
113
+
114
+ async def cost(x):
115
+ async with base.clone() as clone:
116
+ clone[0]["U"].boundary_field["inlet"].value = [x[0], 0, 0]
117
+ await clone.run()
118
+ return abs(clone[-1]["U"].internal_field[0][0])
119
+
120
+ result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
121
+ ```
122
+
104
123
  ## Documentation
105
124
 
106
125
  For more information, check out the [documentation](https://foamlib.readthedocs.io/).
@@ -1,6 +1,6 @@
1
1
  """A Python interface for interacting with OpenFOAM."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.5.1"
4
4
 
5
5
  from ._cases import (
6
6
  AsyncFoamCase,
@@ -5,16 +5,18 @@ import sys
5
5
  import tempfile
6
6
  from contextlib import asynccontextmanager
7
7
  from pathlib import Path
8
- from typing import (
9
- Callable,
10
- Optional,
11
- Union,
12
- )
8
+ from typing import Callable, Optional, TypeVar, Union
13
9
 
14
10
  if sys.version_info >= (3, 9):
15
- from collections.abc import AsyncGenerator, Collection, Sequence
11
+ from collections.abc import (
12
+ AsyncGenerator,
13
+ Awaitable,
14
+ Collection,
15
+ Iterable,
16
+ Sequence,
17
+ )
16
18
  else:
17
- from typing import AsyncGenerator, Collection, Sequence
19
+ from typing import AsyncGenerator, Awaitable, Collection, Iterable, Sequence
18
20
 
19
21
  if sys.version_info >= (3, 11):
20
22
  from typing import Self
@@ -27,6 +29,9 @@ from ._recipes import _FoamCaseRecipes
27
29
  from ._subprocess import run_async
28
30
  from ._util import awaitableasynccontextmanager
29
31
 
32
+ X = TypeVar("X")
33
+ Y = TypeVar("Y")
34
+
30
35
 
31
36
  class AsyncFoamCase(_FoamCaseRecipes):
32
37
  """
@@ -231,3 +236,10 @@ class AsyncFoamCase(_FoamCaseRecipes):
231
236
  await self._rmtree(dst.parent)
232
237
  else:
233
238
  await self._rmtree(dst)
239
+
240
+ @staticmethod
241
+ def map(coro: Callable[[X], Awaitable[Y]], iterable: Iterable[X]) -> Iterable[Y]:
242
+ """Run an async function on each element of an iterable concurrently."""
243
+ return asyncio.get_event_loop().run_until_complete(
244
+ asyncio.gather(*(coro(arg) for arg in iterable))
245
+ )
@@ -36,6 +36,10 @@ class FoamCase(_FoamCaseRecipes):
36
36
  :param path: The path to the case directory.
37
37
  """
38
38
 
39
+ def __init__(self, path: Union["os.PathLike[str]", str] = Path()):
40
+ super().__init__(path)
41
+ self._tmp: Optional[bool] = None
42
+
39
43
  @staticmethod
40
44
  def _rmtree(
41
45
  path: Union["os.PathLike[str]", str], *, ignore_errors: bool = False
@@ -55,6 +59,10 @@ class FoamCase(_FoamCaseRecipes):
55
59
  shutil.copytree(src, dest, symlinks=symlinks, ignore=ignore)
56
60
 
57
61
  def __enter__(self) -> "FoamCase":
62
+ if self._tmp is None:
63
+ raise RuntimeError(
64
+ "Cannot use a non-copied/cloned case as a context manager"
65
+ )
58
66
  return self
59
67
 
60
68
  def __exit__(
@@ -63,7 +71,15 @@ class FoamCase(_FoamCaseRecipes):
63
71
  exc_val: Optional[BaseException],
64
72
  exc_tb: Optional[TracebackType],
65
73
  ) -> None:
66
- self._rmtree(self.path)
74
+ if self._tmp is not None:
75
+ if self._tmp:
76
+ self._rmtree(self.path.parent)
77
+ else:
78
+ self._rmtree(self.path)
79
+ else:
80
+ raise RuntimeError(
81
+ "Cannot use a non-copied/cloned case as a context manager"
82
+ )
67
83
 
68
84
  def clean(
69
85
  self,
@@ -160,11 +176,17 @@ class FoamCase(_FoamCaseRecipes):
160
176
  """
161
177
  if dst is None:
162
178
  dst = Path(tempfile.mkdtemp(), self.name)
179
+ tmp = True
180
+ else:
181
+ tmp = False
163
182
 
164
183
  for name, args, kwargs in self._copy_cmds(dst):
165
184
  getattr(self, name)(*args, **kwargs)
166
185
 
167
- return type(self)(dst)
186
+ ret = type(self)(dst)
187
+ ret._tmp = tmp
188
+
189
+ return ret
168
190
 
169
191
  def clone(self, dst: Optional[Union["os.PathLike[str]", str]] = None) -> "Self":
170
192
  """
@@ -176,8 +198,14 @@ class FoamCase(_FoamCaseRecipes):
176
198
  """
177
199
  if dst is None:
178
200
  dst = Path(tempfile.mkdtemp(), self.name)
201
+ tmp = True
202
+ else:
203
+ tmp = False
179
204
 
180
205
  for name, args, kwargs in self._clone_cmds(dst):
181
206
  getattr(self, name)(*args, **kwargs)
182
207
 
183
- return type(self)(dst)
208
+ ret = type(self)(dst)
209
+ ret._tmp = tmp
210
+
211
+ return ret
@@ -0,0 +1,49 @@
1
+ import functools
2
+ import sys
3
+ from types import TracebackType
4
+ from typing import (
5
+ Any,
6
+ AsyncContextManager,
7
+ Callable,
8
+ Generic,
9
+ Optional,
10
+ Type,
11
+ TypeVar,
12
+ )
13
+
14
+ if sys.version_info >= (3, 9):
15
+ from collections.abc import Generator
16
+ else:
17
+ from typing import Generator
18
+
19
+
20
+ R = TypeVar("R")
21
+
22
+
23
+ class _AwaitableAsyncContextManager(Generic[R]):
24
+ def __init__(self, cm: "AsyncContextManager[R]"):
25
+ self._cm = cm
26
+
27
+ def __await__(self) -> Generator[Any, Any, R]:
28
+ return self._cm.__aenter__().__await__()
29
+
30
+ async def __aenter__(self) -> R:
31
+ return await self._cm.__aenter__()
32
+
33
+ async def __aexit__(
34
+ self,
35
+ exc_type: Optional[Type[BaseException]],
36
+ exc_val: Optional[BaseException],
37
+ exc_tb: Optional[TracebackType],
38
+ ) -> Optional[bool]:
39
+ return await self._cm.__aexit__(exc_type, exc_val, exc_tb)
40
+
41
+
42
+ def awaitableasynccontextmanager(
43
+ cm: Callable[..., "AsyncContextManager[R]"],
44
+ ) -> Callable[..., _AwaitableAsyncContextManager[R]]:
45
+ @functools.wraps(cm)
46
+ def f(*args: Any, **kwargs: Any) -> _AwaitableAsyncContextManager[R]:
47
+ return _AwaitableAsyncContextManager(cm(*args, **kwargs))
48
+
49
+ return f
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: foamlib
3
- Version: 0.5.0
3
+ Version: 0.5.1
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
@@ -155,6 +155,25 @@ U = FoamFieldFile(Path(my_pitz) / "0/U")
155
155
  print(U.internal_field)
156
156
  ```
157
157
 
158
+ ### Run an optimization loop in parallel
159
+
160
+ ```python
161
+ import os
162
+ from pathlib import Path
163
+ from foamlib import AsyncFoamCase
164
+ from scipy.optimize import differential_evolution
165
+
166
+ base = AsyncFoamCase(Path(os.environ["FOAM_TUTORIALS"]) / "incompressible/simpleFoam/pitzDaily")
167
+
168
+ async def cost(x):
169
+ async with base.clone() as clone:
170
+ clone[0]["U"].boundary_field["inlet"].value = [x[0], 0, 0]
171
+ await clone.run()
172
+ return abs(clone[-1]["U"].internal_field[0][0])
173
+
174
+ result = differential_evolution(cost, bounds=[(-1, 1)], workers=AsyncFoamCase.map, polish=False)
175
+ ```
176
+
158
177
  ## Documentation
159
178
 
160
179
  For more information, check out the [documentation](https://foamlib.readthedocs.io/).
@@ -1,27 +0,0 @@
1
- from types import TracebackType
2
- from typing import Any, AsyncContextManager, Callable, Optional, Type
3
-
4
-
5
- class _AwaitableAsyncContextManager:
6
- def __init__(self, cm: "AsyncContextManager[Any]"):
7
- self._cm = cm
8
-
9
- def __await__(self) -> Any:
10
- return self._cm.__aenter__().__await__()
11
-
12
- async def __aenter__(self) -> Any:
13
- return await self._cm.__aenter__()
14
-
15
- async def __aexit__(
16
- self,
17
- exc_type: Optional[Type[BaseException]],
18
- exc_val: Optional[BaseException],
19
- exc_tb: Optional[TracebackType],
20
- ) -> Any:
21
- return await self._cm.__aexit__(exc_type, exc_val, exc_tb)
22
-
23
-
24
- def awaitableasynccontextmanager(
25
- cm: Callable[..., "AsyncContextManager[Any]"],
26
- ) -> Callable[..., _AwaitableAsyncContextManager]:
27
- return lambda *args, **kwargs: _AwaitableAsyncContextManager(cm(*args, **kwargs))
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes