fullwave25 1.2.2.dev0__py3-none-any.whl → 1.2.3.dev1__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.
Files changed (23) hide show
  1. fullwave/__init__.py +1 -1
  2. fullwave/solver/binary_manager.py +145 -0
  3. fullwave/solver/solver.py +3 -1
  4. {fullwave25-1.2.2.dev0.dist-info → fullwave25-1.2.3.dev1.dist-info}/METADATA +1 -1
  5. {fullwave25-1.2.2.dev0.dist-info → fullwave25-1.2.3.dev1.dist-info}/RECORD +15 -22
  6. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda118 +0 -0
  7. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124 +0 -0
  8. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda129 +0 -0
  9. fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda130 +0 -0
  10. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda118 +0 -0
  11. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124 +0 -0
  12. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda129 +0 -0
  13. fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda130 +0 -0
  14. /fullwave/solver/bins/{gpu → _gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118 +0 -0
  15. /fullwave/solver/bins/{gpu → _gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124 +0 -0
  16. /fullwave/solver/bins/{gpu → _gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129 +0 -0
  17. /fullwave/solver/bins/{gpu → _gpu}/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130 +0 -0
  18. /fullwave/solver/bins/{gpu → _gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118 +0 -0
  19. /fullwave/solver/bins/{gpu → _gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124 +0 -0
  20. /fullwave/solver/bins/{gpu → _gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129 +0 -0
  21. /fullwave/solver/bins/{gpu → _gpu}/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130 +0 -0
  22. {fullwave25-1.2.2.dev0.dist-info → fullwave25-1.2.3.dev1.dist-info}/WHEEL +0 -0
  23. {fullwave25-1.2.2.dev0.dist-info → fullwave25-1.2.3.dev1.dist-info}/licenses/LICENSE +0 -0
fullwave/__init__.py CHANGED
@@ -60,7 +60,7 @@ try:
60
60
  __version__ = version("fullwave")
61
61
  except PackageNotFoundError:
62
62
  # Update via bump-my-version, not manually
63
- __version__ = "1.2.2-dev0"
63
+ __version__ = "1.2.3-dev1"
64
64
 
65
65
  VERSION = __version__ # for convenience
66
66
  logger.info("Fullwave version: %s", __version__)
@@ -0,0 +1,145 @@
1
+ """Binary manager for fullwave solver executables.
2
+
3
+ Handles locating, caching, and downloading solver binaries from GitHub releases.
4
+
5
+ Priority order when resolving a binary:
6
+ 1. Bundled binary (shipped with the package or dev install).
7
+ 2. Local cache at ``~/.cache/fullwave25/bins/``.
8
+ 3. Download from the GitHub release pinned by ``BINARY_RELEASE_TAG``.
9
+
10
+ Binaries are versioned independently from the Python package — update
11
+ ``BINARY_RELEASE_TAG`` only when new binaries are published.
12
+
13
+ The release tag can be overridden at runtime with the environment variable
14
+ ``FULLWAVE25_BINARY_TAG`` (e.g. ``export FULLWAVE25_BINARY_TAG=v1.2.2``).
15
+ """
16
+
17
+ import logging
18
+ import os
19
+ import stat
20
+ import urllib.error
21
+ import urllib.request
22
+ from pathlib import Path
23
+
24
+ logger = logging.getLogger("__main__." + __name__)
25
+
26
+ GITHUB_REPO = "pinton-lab/fullwave25"
27
+ CACHE_DIR = Path.home() / ".cache" / "fullwave25" / "bins"
28
+
29
+ # Pinned release tag for the solver binaries.
30
+ # Update this only when new binaries are uploaded to a GitHub release.
31
+ BINARY_RELEASE_TAG = "v1.2.2"
32
+
33
+
34
+ def _download_url(filename: str, tag: str) -> str:
35
+ return f"https://github.com/{GITHUB_REPO}/releases/download/{tag}/{filename}"
36
+
37
+
38
+ def _download_binary(url: str, dest: Path) -> None:
39
+ """Download *url* to *dest*, showing a tqdm progress bar when available."""
40
+ dest.parent.mkdir(parents=True, exist_ok=True)
41
+ tmp = dest.with_suffix(".download_tmp")
42
+ try:
43
+ try:
44
+ from tqdm import tqdm
45
+
46
+ class _Hook:
47
+ def __init__(self) -> None:
48
+ self._bar: tqdm | None = None
49
+
50
+ def __call__(self, block: int, block_size: int, total: int) -> None: # noqa: ARG002
51
+ if self._bar is None:
52
+ self._bar = tqdm(
53
+ total=total if total > 0 else None,
54
+ unit="B",
55
+ unit_scale=True,
56
+ desc=dest.name,
57
+ )
58
+ self._bar.update(block_size)
59
+
60
+ def close(self) -> None:
61
+ if self._bar is not None:
62
+ self._bar.close()
63
+
64
+ hook = _Hook()
65
+ try:
66
+ urllib.request.urlretrieve(url, tmp, reporthook=hook) # noqa: S310
67
+ finally:
68
+ hook.close()
69
+
70
+ except ImportError:
71
+ urllib.request.urlretrieve(url, tmp) # noqa: S310
72
+
73
+ tmp.rename(dest)
74
+ dest.chmod(dest.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
75
+ logger.info("Binary saved to %s", dest)
76
+
77
+ except Exception:
78
+ tmp.unlink(missing_ok=True)
79
+ raise
80
+
81
+
82
+ def ensure_binary(local_path: Path) -> Path:
83
+ """Return an executable path for the solver binary.
84
+
85
+ Parameters
86
+ ----------
87
+ local_path:
88
+ The expected bundled path (as computed by ``_retrieve_fullwave_simulation_path``).
89
+
90
+ Returns
91
+ -------
92
+ Path
93
+ Resolved path to an executable binary.
94
+
95
+ Raises
96
+ ------
97
+ RuntimeError
98
+ If the binary cannot be found locally and the download fails.
99
+
100
+ """
101
+ # 1. Bundled binary present (dev install or package that still ships binaries).
102
+ if local_path.exists():
103
+ logger.debug("Using bundled binary: %s", local_path)
104
+ return local_path
105
+
106
+ filename = local_path.name
107
+ cached = CACHE_DIR / filename
108
+
109
+ # 2. Previously downloaded and cached.
110
+ if cached.exists():
111
+ logger.debug("Using cached binary: %s", cached)
112
+ return cached
113
+
114
+ # 3. Download from GitHub releases.
115
+ tag = os.environ.get("FULLWAVE25_BINARY_TAG", BINARY_RELEASE_TAG)
116
+ url = _download_url(filename, tag)
117
+
118
+ logger.info(
119
+ "Binary '%s' not found locally. Downloading from GitHub release '%s' …",
120
+ filename,
121
+ tag,
122
+ )
123
+
124
+ try:
125
+ _download_binary(url, cached)
126
+ except urllib.error.HTTPError as e:
127
+ msg = (
128
+ f"Could not download binary '{filename}' from:\n {url}\n"
129
+ f"HTTP error: {e.code} {e.reason}\n\n"
130
+ "Possible fixes:\n"
131
+ f" • Check that release '{tag}' exists and contains '{filename}'.\n"
132
+ f" • Override the tag: export FULLWAVE25_BINARY_TAG=<tag>\n"
133
+ f" • Place the binary manually at: {cached}\n"
134
+ )
135
+ raise RuntimeError(msg) from e
136
+ except Exception as e:
137
+ msg = (
138
+ f"Failed to download binary '{filename}' from:\n {url}\n"
139
+ f"Error: {e}\n\n"
140
+ f" • Place the binary manually at: {cached}\n"
141
+ f" • Or override the tag: export FULLWAVE25_BINARY_TAG=<tag>\n"
142
+ )
143
+ raise RuntimeError(msg) from e
144
+
145
+ return cached
fullwave/solver/solver.py CHANGED
@@ -16,6 +16,7 @@ from fullwave.utils import (
16
16
  check_functions,
17
17
  )
18
18
 
19
+ from .binary_manager import ensure_binary
19
20
  from .cuda_utils import get_cuda_architecture, retrieve_cuda_version
20
21
 
21
22
  logger = logging.getLogger("__main__." + __name__)
@@ -461,13 +462,14 @@ class Solver:
461
462
  self.n_relax_mechanisms = medium.n_relaxation_mechanisms
462
463
 
463
464
  if path_fullwave_simulation_bin is None:
464
- path_fullwave_simulation_bin = _retrieve_fullwave_simulation_path(
465
+ local_path = _retrieve_fullwave_simulation_path(
465
466
  use_gpu=use_gpu,
466
467
  is_3d=self.is_3d,
467
468
  use_exponential_attenuation=self.use_exponential_attenuation,
468
469
  use_isotropic_relaxation=use_isotropic_relaxation,
469
470
  n_relax_mechanisms=self.n_relax_mechanisms,
470
471
  )
472
+ path_fullwave_simulation_bin = ensure_binary(local_path)
471
473
  else:
472
474
  check_functions.check_path_exists(path_fullwave_simulation_bin)
473
475
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fullwave25
3
- Version: 1.2.2.dev0
3
+ Version: 1.2.3.dev1
4
4
  Summary: Fullwave 2.5: Ultrasound wave propagation simulation with heterogeneous power law attenuation modelling capabilities
5
5
  Author: Masashi Sode, Gianmarco Pinton
6
6
  Maintainer: Masashi Sode
@@ -1,4 +1,4 @@
1
- fullwave/__init__.py,sha256=sCTjrPFtcpd38ER6lMHSyzBiigVgo-CFpnlSMdJRC3E,1780
1
+ fullwave/__init__.py,sha256=VGy3UMrnjXs3DCBIfhYFDQoGcoQAdR3vyd0mVypwVno,1780
2
2
  fullwave/grid.py,sha256=4bLb5_PKmR3KSRcamsT-3feRSACF7-jJKnpCjeoRGDY,7429
3
3
  fullwave/medium.py,sha256=NPg3NxLhR6roeroHM32lv-7rk0CALIExHrhSXpHh9MI,48302
4
4
  fullwave/sensor.py,sha256=WzLvOpQBBRmQT8nZUw1Xv_-qytjtN9ohkfMTjqMYkuc,6056
@@ -20,29 +20,22 @@ fullwave/medium_builder/presets/domain_water_gel.py,sha256=nFiL0CkmDeJWo7aR2Khn0
20
20
  fullwave/medium_builder/presets/data/.keep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  fullwave/medium_builder/presets/data/abdominal_wall/i2365f_etfw1.mat,sha256=N3JFFxc9HW1S-NaTPcPlFgXWGIzlrr9X40JbDapTo4g,67348
22
22
  fullwave/solver/__init__.py,sha256=E0Jg5akBpicqTjku1puw9rAIoKiw7TwtYNDPiv8G5IY,30
23
+ fullwave/solver/binary_manager.py,sha256=mIT8Lwrh62BGqkwaVhsF3xU21YYy7sbZpZ5CdghqopQ,4696
23
24
  fullwave/solver/cuda_utils.py,sha256=iWa_6bicQwSsKGyp47hfAlyGBRZAGfN-sg2frzrQaVU,11352
24
25
  fullwave/solver/input_file_writer.py,sha256=MtJXzGsyvPNZqH9PaB2Chi11ocxprm6kk3o9foluaOo,41626
25
26
  fullwave/solver/launcher.py,sha256=TOOxupqk_OUxUk24GqozM9VDBl-5KVB6E7t4ojbbTU4,8864
26
27
  fullwave/solver/pml_builder.py,sha256=ClMbD1HL-p16hYMAkkG6i23gH2Q04aXZ9aKRiG1UBaA,67445
27
- fullwave/solver/solver.py,sha256=oDZ0JXD11XvB3pxFa84RDtggtjxYPUISATwuFwtLggo,35462
28
+ fullwave/solver/solver.py,sha256=CrlbrEmdMAKq7TvPq92TpRg7MCqsbYff_Cg8BexJI58,35555
28
29
  fullwave/solver/utils.py,sha256=3lota1TDzwAo5kxlrvy30CEnSEyVe4Iqxnh4bpCBHiw,5389
30
+ fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118,sha256=Ldpn-5DTno02ujPuKhJMAPkbjbVBzrhAH1YZWFExWjg,1179928
31
+ fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124,sha256=1ztSYqa_JpstPyE7AFvpOh06xS4-aIV2XZF2nuZoIIc,1342432
32
+ fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129,sha256=-R41oSO5pMsbGs4uuD_nCkgJs-Wvu621cBJhLEhAKes,1644856
33
+ fullwave/solver/bins/_gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130,sha256=n3zIQThNSsV0pZUeIh9RpQKGoBoyV6UeaVdLCQnxcSg,1410320
34
+ fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118,sha256=waTmRPVyhK13DCSMXOuIwe_uCMV8WTcp8oboiro9dFs,1233416
35
+ fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124,sha256=qY64iz4wi62dvrcFsS68ks3qwfpiUaplfVn9r0jqS9o,1404112
36
+ fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129,sha256=PhGpNRxTGLXbBm55GKxn_uA_lRThENDJNfLtqUlheRM,1755688
37
+ fullwave/solver/bins/_gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130,sha256=Qjr2mg59dC6xDz2QWbSkf2-DU_uOj7sZbOJ_XaaQ_lo,1480392
29
38
  fullwave/solver/bins/database/relaxation_params_database_num_relax=2_20260113_0957.mat,sha256=Fei5ie9wgAAN43pIdSFf6xVaPPDgOaBBZodi3qK6WtQ,168056
30
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda118,sha256=6rjAflxVI_P1BDu2KXGH9yDnavQE5ugKwA9TJsLYm_s,1134736
31
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda124,sha256=9RDXKvwvPfykPNuKDUlYpy6wZ9-7oPLlRA0M4rkPSqg,1309560
32
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda129,sha256=gLqGY5QsUyRo1R3gvx2Pb4ORwME5UoA3iy4lHNM1ok0,1587408
33
- fullwave/solver/bins/exponential_attenuation/gpu/2d/fullwave2_2d_exponential_attenuation_multi_gpu_cuda130,sha256=p8MQ4S5X9DgZCeQaS2pP_l1JYE8UTo_P2E7pAJ2XLGg,1373064
34
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda118,sha256=R5JjENS6ekfTDz831BGYvkuvC_c_J7IUko6RvZVrVJ8,1151184
35
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda124,sha256=ZhmqHz4fgd_1z5_M7_3D0QaFZxypTS-Erzr6y3jY-jI,1321912
36
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda129,sha256=NZKmatMOs3ZDBV_AsaqoKgz4lzNwyM3ZYYlgPtc-r5c,1624336
37
- fullwave/solver/bins/exponential_attenuation/gpu/3d/fullwave2_3d_exponential_attenuation_multi_gpu_cuda130,sha256=imUmx4NoPcWd9hMI_yMtx_I9HaiZnIRvO-Z_i9WhTuY,1392776
38
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda118,sha256=Ldpn-5DTno02ujPuKhJMAPkbjbVBzrhAH1YZWFExWjg,1179928
39
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda124,sha256=1ztSYqa_JpstPyE7AFvpOh06xS4-aIV2XZF2nuZoIIc,1342432
40
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda129,sha256=-R41oSO5pMsbGs4uuD_nCkgJs-Wvu621cBJhLEhAKes,1644856
41
- fullwave/solver/bins/gpu/2d/num_relax=2/fullwave2_2d_2_relax_multi_gpu_cuda130,sha256=n3zIQThNSsV0pZUeIh9RpQKGoBoyV6UeaVdLCQnxcSg,1410320
42
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda118,sha256=waTmRPVyhK13DCSMXOuIwe_uCMV8WTcp8oboiro9dFs,1233416
43
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda124,sha256=qY64iz4wi62dvrcFsS68ks3qwfpiUaplfVn9r0jqS9o,1404112
44
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda129,sha256=PhGpNRxTGLXbBm55GKxn_uA_lRThENDJNfLtqUlheRM,1755688
45
- fullwave/solver/bins/gpu/3d/num_relax=2/fullwave2_3d_2_relax_multi_gpu_cuda130,sha256=Qjr2mg59dC6xDz2QWbSkf2-DU_uOj7sZbOJ_XaaQ_lo,1480392
46
39
  fullwave/utils/__init__.py,sha256=qjVO8bJRJjZL0NrAH2qn55GZi6OXtcmWT-wiJbvjVbk,425
47
40
  fullwave/utils/check_functions.py,sha256=ezpwLvTSpriIfguvoWvdiVKjZxMy1m9diP6XZWDIL5E,1484
48
41
  fullwave/utils/coordinates.py,sha256=iIfvfrTQ1DA_WG6o2DbCtrjOY3wk076pKOmv7KsLIBs,4358
@@ -53,7 +46,7 @@ fullwave/utils/pulse.py,sha256=aqnCdBxivACouIGlot1aE2k4V9nctUxNCEPzdBpsupg,2811
53
46
  fullwave/utils/relaxation_parameters.py,sha256=DEHjr67eHGR-DqEaNsQViokseIsDywtjBjB1DvF4-OM,14106
54
47
  fullwave/utils/scatterer.py,sha256=CLqD085f9pqX4cF1YiT2IkzT5P0o1xp45Do7lf5BLnM,24049
55
48
  fullwave/utils/signal_process.py,sha256=MP38r37JSPHN4sT-lIReXS5BT2GT_tkRxD0Y1wQ-lNs,5153
56
- fullwave25-1.2.2.dev0.dist-info/METADATA,sha256=F4HOUeR4Dz91MqWWY05ATXNNpK-yDZ3idlBU4VhBBoc,19027
57
- fullwave25-1.2.2.dev0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
58
- fullwave25-1.2.2.dev0.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
59
- fullwave25-1.2.2.dev0.dist-info/RECORD,,
49
+ fullwave25-1.2.3.dev1.dist-info/METADATA,sha256=nM0bbLSvmjGIj7eHXAJe39OQ4BOoouGg6WPh0JgXmo8,19027
50
+ fullwave25-1.2.3.dev1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
51
+ fullwave25-1.2.3.dev1.dist-info/licenses/LICENSE,sha256=46mU2C5kSwOnkqkw9XQAJlhBL2JAf1_uCD8lVcXyMRg,7652
52
+ fullwave25-1.2.3.dev1.dist-info/RECORD,,