k-Wave-python 0.3.2__tar.gz → 0.3.4__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 (85) hide show
  1. k_wave_python-0.3.4/.gitignore +46 -0
  2. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pre-commit-config.yaml +9 -0
  3. k_wave_python-0.3.4/.ruff_cache/0.2.2/11727547499557932880 +0 -0
  4. k_wave_python-0.3.4/.ruff_cache/0.2.2/15979114690223248129 +0 -0
  5. k_wave_python-0.3.4/.ruff_cache/0.2.2/2528246142718653170 +0 -0
  6. k_wave_python-0.3.4/.ruff_cache/0.2.2/3142013637658215183 +0 -0
  7. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/CITATION.cff +6 -5
  8. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/PKG-INFO +28 -41
  9. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/docs/README.md +12 -25
  10. k_wave_python-0.3.4/kwave/__init__.py +203 -0
  11. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/data.py +1 -0
  12. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/executor.py +28 -25
  13. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation.py +273 -299
  14. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/__init__.py +0 -2
  15. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/create_absorption_variables.py +7 -7
  16. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/display_simulation_params.py +26 -17
  17. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/expand_grid_matrices.py +35 -31
  18. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/retract_transducer_grid_size.py +0 -2
  19. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/save_to_disk_func.py +153 -138
  20. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/scale_source_terms_func.py +40 -45
  21. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/set_sound_speed_ref.py +7 -11
  22. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kgrid.py +40 -47
  23. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kmedium.py +46 -44
  24. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/ksensor.py +5 -6
  25. k_wave_python-0.3.4/kwave/ksource.py +382 -0
  26. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kspaceFirstOrder2D.py +93 -102
  27. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kspaceFirstOrder3D.py +94 -103
  28. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kspaceFirstOrderAS.py +89 -88
  29. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/ktransducer.py +118 -113
  30. k_wave_python-0.3.4/kwave/options/simulation_execution_options.py +145 -0
  31. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/options/simulation_options.py +61 -57
  32. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/reconstruction/beamform.py +9 -19
  33. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/reconstruction/tools.py +26 -23
  34. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/recorder.py +41 -26
  35. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/angular_spectrum.py +64 -72
  36. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/angular_spectrum_cw.py +53 -63
  37. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/atten_comp.py +78 -87
  38. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/checks.py +67 -86
  39. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/colormap.py +12 -12
  40. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/conversion.py +59 -70
  41. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/data.py +37 -43
  42. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/filters.py +97 -93
  43. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/interp.py +76 -85
  44. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/io.py +139 -145
  45. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/kwave_array.py +197 -199
  46. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/mapgen.py +284 -409
  47. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/math.py +47 -66
  48. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/matlab.py +15 -16
  49. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/matrix.py +32 -37
  50. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/plot.py +5 -5
  51. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/pml.py +16 -13
  52. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/signals.py +116 -125
  53. k_wave_python-0.3.4/kwave/utils/typing.py +35 -0
  54. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/pyproject.toml +23 -21
  55. k_wave_python-0.3.2/.gitignore +0 -23
  56. k_wave_python-0.3.2/.pytest_cache/v/cache/lastfailed +0 -1
  57. k_wave_python-0.3.2/.pytest_cache/v/cache/nodeids +0 -160
  58. k_wave_python-0.3.2/kwave/__init__.py +0 -148
  59. k_wave_python-0.3.2/kwave/kWaveSimulation_helper/create_storage_variables.py +0 -399
  60. k_wave_python-0.3.2/kwave/kWaveSimulation_helper/data_cast.py +0 -188
  61. k_wave_python-0.3.2/kwave/ksource.py +0 -375
  62. k_wave_python-0.3.2/kwave/options/simulation_execution_options.py +0 -155
  63. k_wave_python-0.3.2/kwave/utils/typing.py +0 -22
  64. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/.gitignore +0 -0
  65. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/CACHEDIR.TAG +0 -0
  66. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/README.md +0 -0
  67. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/v/cache/stepwise +0 -0
  68. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.readthedocs.yaml +0 -0
  69. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/.gitignore +0 -0
  70. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/CACHEDIR.TAG +0 -0
  71. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/13487435192755641643 +0 -0
  72. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/1921099194987439213 +0 -0
  73. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/5526710289020645422 +0 -0
  74. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/5950811561636507670 +0 -0
  75. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/655415607675938108 +0 -0
  76. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/Dockerfile +0 -0
  77. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/LICENSE +0 -0
  78. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/enums.py +0 -0
  79. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/options/__init__.py +0 -0
  80. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/reconstruction/__init__.py +0 -0
  81. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/__init__.py +0 -0
  82. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/dotdictionary.py +0 -0
  83. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/tictoc.py +0 -0
  84. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/make_docs.sh +0 -0
  85. {k_wave_python-0.3.2 → k_wave_python-0.3.4}/run_tests.sh +0 -0
@@ -0,0 +1,46 @@
1
+ # IDE specific files
2
+ .idea/
3
+ .vscode/
4
+
5
+ # Virtual environments
6
+ .venv/
7
+
8
+ # Compiled files
9
+ *.pyc
10
+ examples/__pycache__/
11
+
12
+ # System files
13
+ .DS_Store
14
+
15
+ # Python egg files
16
+ /k_Wave_python.egg-info/
17
+
18
+ # Build directories
19
+ build/
20
+ src/
21
+ transfer_temp/
22
+ docs/_build/
23
+ kwave/bin/
24
+
25
+ # Package manager files
26
+ Pipfile.lock
27
+
28
+ # Coverage reports
29
+ /.coverage
30
+
31
+ # Test and temporary files
32
+ difference.py
33
+ test_local.sh
34
+ tests/reference_outputs
35
+
36
+ # Data and output files
37
+ *.mat
38
+ *.mp4
39
+ *.h5
40
+ *.png
41
+ *.tar.gz
42
+ *.whl
43
+ *.asv
44
+ kspaceFirstOrder-*_metadata.json
45
+
46
+
@@ -8,6 +8,15 @@ repos:
8
8
  language: python
9
9
  types_or: [jupyter]
10
10
  minimum_pre_commit_version: 2.9.2
11
+ - repo: https://github.com/astral-sh/ruff-pre-commit
12
+ # Ruff version.
13
+ rev: v0.2.2
14
+ hooks:
15
+ # Run the linter.
16
+ - id: ruff
17
+ args: [ --fix ]
18
+ # Run the formatter.
19
+ - id: ruff-format
11
20
  # - repo: https://github.com/pre-commit/pre-commit-hooks
12
21
  # rev: v4.5.0 # Use the ref you want to point at
13
22
  # hooks:
@@ -1,8 +1,5 @@
1
1
  cff-version: 1.2.0
2
- title: k-Wave-Python
3
- message: >-
4
- If you use this software, please cite it using the
5
- metadata from this file.
2
+ title: k-Wave-python
6
3
  type: software
7
4
  authors:
8
5
  - given-names: Farid
@@ -10,12 +7,16 @@ authors:
10
7
  email: farid.yagubbayli@tum.de
11
8
  - given-names: David
12
9
  family-names: Sinden
13
- affiliation: Fraunhofer Institute for Digital Medicine
10
+ affiliation: Fraunhofer Institute for Digital Medicine MEVIS
14
11
  orcid: 'https://orcid.org/0000-0002-8514-8279'
15
12
  - family-names: Simson
16
13
  given-names: Walter
17
14
  email: wsimson@stanford.edu
18
15
  affiliation: Stanford University
19
16
  orcid: 'https://orcid.org/0000-0002-2801-8646'
17
+ identifiers:
18
+ - type: doi
19
+ value: 10.5281/zenodo.10719460
20
+ description: Zenodo DOI
20
21
  repository-code: 'https://github.com/waltsims/k-wave-python'
21
22
  license: GPL-3.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: k-Wave-python
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Acoustics toolbox for time domain acoustic and ultrasound simulations in complex and tissue-realistic media.
5
5
  Project-URL: Homepage, http://www.k-wave.org/
6
6
  Project-URL: Documentation, https://waltersimson.com/k-wave-python/
@@ -687,32 +687,34 @@ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
687
687
  Classifier: Operating System :: OS Independent
688
688
  Classifier: Programming Language :: Python :: 3
689
689
  Requires-Python: >=3.9
690
- Requires-Dist: beartype==0.16.4
691
- Requires-Dist: deepdiff==6.7.1
692
- Requires-Dist: h5py==3.10.0
693
- Requires-Dist: matplotlib==3.8.3
694
- Requires-Dist: nptyping==2.5.0
690
+ Requires-Dist: beartype==0.18.5
691
+ Requires-Dist: deepdiff==7.0.1
692
+ Requires-Dist: h5py==3.11.0
693
+ Requires-Dist: jaxtyping==0.2.31
694
+ Requires-Dist: matplotlib==3.9.0
695
695
  Requires-Dist: numpy<1.27.0,>=1.22.2
696
- Requires-Dist: opencv-python==4.9.0.80
697
- Requires-Dist: scipy==1.12.0
696
+ Requires-Dist: opencv-python==4.10.0.84
697
+ Requires-Dist: scipy==1.13.1
698
698
  Provides-Extra: dev
699
- Requires-Dist: pre-commit==3.6.2; extra == 'dev'
699
+ Requires-Dist: pre-commit==3.7.1; extra == 'dev'
700
700
  Provides-Extra: docs
701
- Requires-Dist: furo==2024.1.29; extra == 'docs'
702
- Requires-Dist: m2r2==0.3.2; extra == 'docs'
701
+ Requires-Dist: furo==2024.5.6; extra == 'docs'
703
702
  Requires-Dist: sphinx-copybutton==0.5.2; extra == 'docs'
704
- Requires-Dist: sphinx-tabs==3.4.4; extra == 'docs'
705
- Requires-Dist: sphinx-toolbox==3.5.0; extra == 'docs'
703
+ Requires-Dist: sphinx-mdinclude==0.6.1; extra == 'docs'
704
+ Requires-Dist: sphinx-tabs==3.4.5; extra == 'docs'
705
+ Requires-Dist: sphinx-toolbox==3.6.0; extra == 'docs'
706
706
  Provides-Extra: example
707
- Requires-Dist: gdown==4.6.0; extra == 'example'
707
+ Requires-Dist: gdown==5.2.0; extra == 'example'
708
708
  Provides-Extra: test
709
- Requires-Dist: coverage==7.4.3; extra == 'test'
709
+ Requires-Dist: coverage==7.5.4; extra == 'test'
710
710
  Requires-Dist: phantominator; extra == 'test'
711
711
  Requires-Dist: pytest; extra == 'test'
712
- Requires-Dist: requests==2.31.0; extra == 'test'
712
+ Requires-Dist: requests==2.32.3; extra == 'test'
713
713
  Description-Content-Type: text/markdown
714
714
 
715
715
  # k-Wave-python
716
+
717
+ [![Support](https://dcbadge.vercel.app/api/server/Yq5Qj6D9vN?style=flat)](https://discord.gg/Yq5Qj6D9vN)
716
718
  [![Documentation Status](https://readthedocs.org/projects/k-wave-python/badge/?version=latest)](https://k-wave-python.readthedocs.io/en/latest/?badge=latest)
717
719
  [![codecov](https://codecov.io/gh/waltsims/k-wave-python/graph/badge.svg?token=6ofwtPiDNG)](https://codecov.io/gh/waltsims/k-wave-python)
718
720
  [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/waltsims/k-wave-python/master)
@@ -727,30 +729,11 @@ for medical imaging, algorithmic prototyping, and testing. Many tools and method
727
729
  be found here, but this project has and will continue to diverge from the original [k-Wave](http://www.k-wave.org/) APIs
728
730
  to leverage pythonic practices.
729
731
 
730
- ## Installation
731
-
732
- To install the most recent build of k-Wave-python from PyPI, run:
733
-
734
- ```bash
735
- pip install k-wave-python
736
- ```
737
-
738
- After installing the Python package, the required binaries will be downloaded and installed the first time you run a
739
- simulation.
740
-
741
732
  ## Getting started
742
733
 
743
734
  ![](_static/example_bmode.png)
744
735
 
745
- After installation, run the B-mode reconstruction example in the `examples` directory of the repository:
746
-
747
- ```bash
748
- git clone https://github.com/waltsims/k-wave-python
749
- cd k-wave-python
750
- git checkout v0.3.2
751
- pip install '.[example]'
752
- python3 examples/us_bmode_linear_transducer/us_bmode_linear_transducer.py
753
- ```
736
+ A large [collection of examples](../examples/) exists to get started with k-wave-python. All examples can be run in Google Colab notebooks with a few clicks. One can begin with e.g. the [B-mode reconstruction example notebook](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_bmode_linear_transducer/us_bmode_linear_transducer.ipynb).
754
737
 
755
738
  This example file steps through the process of:
756
739
  1. Generating a simulation medium
@@ -758,12 +741,16 @@ This example file steps through the process of:
758
741
  3. Running the simulation
759
742
  4. Reconstructing the simulation
760
743
 
761
- ### Requirements
762
- This example expects an NVIDIA GPU by default to simulate with k-Wave.
744
+ ## Installation
745
+
746
+ To install the most recent build of k-Wave-python from PyPI, run:
747
+
748
+ ```bash
749
+ pip install k-wave-python
750
+ ```
763
751
 
764
- To test the reconstruction on a machine with a GPU,
765
- set `RUN_SIMULATION` [on line 29 of `us_bmode_linear_transducer.py`](https://github.com/waltsims/k-wave-python/blob/6d2ee982bece84fc6980da99b23600f5675d2fc5/examples/us_bmode_linear_transducer/us_bmode_linear_transducer.py#L29)
766
- to `True`, and the example will run without the pre-computed data.
752
+ After installing the Python package, the required binaries will be downloaded and installed the first time you run a
753
+ simulation.
767
754
 
768
755
  ## Development
769
756
 
@@ -1,4 +1,6 @@
1
1
  # k-Wave-python
2
+
3
+ [![Support](https://dcbadge.vercel.app/api/server/Yq5Qj6D9vN?style=flat)](https://discord.gg/Yq5Qj6D9vN)
2
4
  [![Documentation Status](https://readthedocs.org/projects/k-wave-python/badge/?version=latest)](https://k-wave-python.readthedocs.io/en/latest/?badge=latest)
3
5
  [![codecov](https://codecov.io/gh/waltsims/k-wave-python/graph/badge.svg?token=6ofwtPiDNG)](https://codecov.io/gh/waltsims/k-wave-python)
4
6
  [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/waltsims/k-wave-python/master)
@@ -13,30 +15,11 @@ for medical imaging, algorithmic prototyping, and testing. Many tools and method
13
15
  be found here, but this project has and will continue to diverge from the original [k-Wave](http://www.k-wave.org/) APIs
14
16
  to leverage pythonic practices.
15
17
 
16
- ## Installation
17
-
18
- To install the most recent build of k-Wave-python from PyPI, run:
19
-
20
- ```bash
21
- pip install k-wave-python
22
- ```
23
-
24
- After installing the Python package, the required binaries will be downloaded and installed the first time you run a
25
- simulation.
26
-
27
18
  ## Getting started
28
19
 
29
20
  ![](_static/example_bmode.png)
30
21
 
31
- After installation, run the B-mode reconstruction example in the `examples` directory of the repository:
32
-
33
- ```bash
34
- git clone https://github.com/waltsims/k-wave-python
35
- cd k-wave-python
36
- git checkout v0.3.2
37
- pip install '.[example]'
38
- python3 examples/us_bmode_linear_transducer/us_bmode_linear_transducer.py
39
- ```
22
+ A large [collection of examples](../examples/) exists to get started with k-wave-python. All examples can be run in Google Colab notebooks with a few clicks. One can begin with e.g. the [B-mode reconstruction example notebook](https://colab.research.google.com/github/waltsims/k-wave-python/blob/master/examples/us_bmode_linear_transducer/us_bmode_linear_transducer.ipynb).
40
23
 
41
24
  This example file steps through the process of:
42
25
  1. Generating a simulation medium
@@ -44,12 +27,16 @@ This example file steps through the process of:
44
27
  3. Running the simulation
45
28
  4. Reconstructing the simulation
46
29
 
47
- ### Requirements
48
- This example expects an NVIDIA GPU by default to simulate with k-Wave.
30
+ ## Installation
31
+
32
+ To install the most recent build of k-Wave-python from PyPI, run:
33
+
34
+ ```bash
35
+ pip install k-wave-python
36
+ ```
49
37
 
50
- To test the reconstruction on a machine with a GPU,
51
- set `RUN_SIMULATION` [on line 29 of `us_bmode_linear_transducer.py`](https://github.com/waltsims/k-wave-python/blob/6d2ee982bece84fc6980da99b23600f5675d2fc5/examples/us_bmode_linear_transducer/us_bmode_linear_transducer.py#L29)
52
- to `True`, and the example will run without the pre-computed data.
38
+ After installing the Python package, the required binaries will be downloaded and installed the first time you run a
39
+ simulation.
53
40
 
54
41
  ## Development
55
42
 
@@ -0,0 +1,203 @@
1
+ import logging
2
+ import os
3
+ import platform
4
+ from urllib.request import urlretrieve
5
+ from pathlib import Path
6
+ from typing import List
7
+ import hashlib
8
+ import json
9
+
10
+ # Test installation with:
11
+ # python3 -m pip install -i https://test.pypi.org/simple/ --extra-index-url=https://pypi.org/simple/ k-Wave-python==0.3.0
12
+ VERSION = "0.3.4"
13
+
14
+ # Constants and Configurations
15
+ URL_BASE = "https://github.com/waltsims/"
16
+ BINARY_VERSION = "v1.3.0"
17
+ PREFIX = f"{URL_BASE}kspaceFirstOrder-{{}}-{{}}/releases/download/{BINARY_VERSION}/"
18
+ PLATFORM = platform.system().lower()
19
+
20
+ if PLATFORM not in ["linux", "windows", "darwin"]:
21
+ raise NotImplementedError(f"k-wave-python is currently unsupported on this operating system: {PLATFORM}.")
22
+
23
+ # TODO: install directly in to /bin/ directory system directory is no longer needed
24
+ BINARY_PATH = Path(__file__).parent / "bin" / PLATFORM
25
+
26
+
27
+ WINDOWS_DLLS = [
28
+ "cufft64_10.dll",
29
+ "hdf5.dll",
30
+ "hdf5_hl.dll",
31
+ "libiomp5md.dll",
32
+ "libmmd.dll",
33
+ "msvcp140.dll",
34
+ "svml_dispmd.dll",
35
+ "szip.dll",
36
+ "vcruntime140.dll",
37
+ "zlib.dll",
38
+ ]
39
+
40
+ EXECUTABLE_PREFIX = "kspaceFirstOrder-"
41
+ ARCHITECTURES = ["omp", "cuda"]
42
+
43
+
44
+ def get_windows_release_urls(architecture: str) -> list:
45
+ specific_filenames = [EXECUTABLE_PREFIX + architecture + ".exe"]
46
+ if architecture == "omp":
47
+ specific_filenames += WINDOWS_DLLS
48
+ release_urls = [PREFIX.format(architecture.upper(), PLATFORM.lower()) + filename for filename in specific_filenames]
49
+ return release_urls
50
+
51
+
52
+ URL_DICT = {
53
+ "linux": {
54
+ "cuda": [URL_BASE + f"kspaceFirstOrder-CUDA-{PLATFORM}/releases/download/v1.3.1/{EXECUTABLE_PREFIX}CUDA"],
55
+ "omp": [URL_BASE + f"kspaceFirstOrder-OMP-{PLATFORM}/releases/download/{BINARY_VERSION}/{EXECUTABLE_PREFIX}OMP"],
56
+ },
57
+ "darwin": {
58
+ "cuda": [],
59
+ "omp": [URL_BASE + f"k-wave-omp-{PLATFORM}/releases/download/v0.3.0rc2/{EXECUTABLE_PREFIX}OMP"],
60
+ },
61
+ "windows": {architecture: get_windows_release_urls(architecture) for architecture in ARCHITECTURES},
62
+ }
63
+
64
+
65
+ def _hash_file(filepath: str) -> str:
66
+ buf_size = 65536 # 64kb chunks
67
+ md5 = hashlib.md5()
68
+
69
+ with open(filepath, "rb") as f:
70
+ while True:
71
+ data = f.read(buf_size)
72
+ if not data:
73
+ break
74
+ md5.update(data)
75
+ return md5.hexdigest()
76
+
77
+
78
+ def _is_binary_present(binary_name: str, binary_type: str) -> bool:
79
+ binary_filepath = BINARY_PATH / binary_name
80
+ binary_file_exists = os.path.exists(binary_filepath)
81
+ if not binary_file_exists:
82
+ return False
83
+
84
+ if binary_type is None:
85
+ # this is non-kwave windows binary
86
+ # it already exists according to the check above
87
+ return True
88
+ existing_metadata_path = BINARY_PATH / f"{binary_name}_metadata.json"
89
+
90
+ if not os.path.exists(existing_metadata_path):
91
+ # metadata does not exist => binaries may or may not exist
92
+ # Let's play safe and claim they don't exist
93
+ # This will trigger binary download and generation of binary metadata
94
+ return False
95
+ existing_metadata = json.loads(Path(existing_metadata_path).read_text())
96
+
97
+ # If metadata was somehow corrupted
98
+ file_hash = _hash_file(binary_filepath)
99
+ if existing_metadata["file_hash"] != file_hash:
100
+ return False
101
+
102
+ # If there is a new binary
103
+ latest_urls = URL_DICT[PLATFORM][binary_type]
104
+ if existing_metadata["url"] not in latest_urls:
105
+ return False
106
+
107
+ # No need to check `version` field for now
108
+ # because we version is already present in the URL
109
+ return True
110
+
111
+
112
+ def binaries_present() -> bool:
113
+ """
114
+ Check if binaries are present
115
+ Returns:
116
+ bool, True if binaries are present, False otherwise
117
+
118
+ """
119
+ binary_list = []
120
+ for binary_type in ARCHITECTURES:
121
+ for binary_name in URL_DICT[PLATFORM][binary_type]:
122
+ binary_list.append((binary_name.split("/")[-1], binary_type))
123
+
124
+ missing_binaries: List[str] = []
125
+
126
+ for binary_name, binary_type in binary_list:
127
+ if not _is_binary_present(binary_name, binary_type):
128
+ missing_binaries.append(binary_name)
129
+
130
+ if len(missing_binaries) > 0:
131
+ missing_binaries_str = ", ".join(missing_binaries)
132
+ logging.log(
133
+ logging.INFO,
134
+ f"Following binaries were not found: {missing_binaries_str}"
135
+ "If this is first time you're running k-wave-python, "
136
+ "binaries will be downloaded automatically.",
137
+ )
138
+
139
+ return len(missing_binaries) == 0
140
+
141
+
142
+ def _record_binary_metadata(binary_version: str, binary_filepath: str, binary_url: str, filename: str) -> None:
143
+ # note: version is not immediately useful at the moment
144
+ # because it is already present in the url and we use url to understand if versions match
145
+ # However, let's record it anyway. Maybe it will be useful in the future.
146
+ metadata = {"url": binary_url, "version": binary_version, "file_hash": _hash_file(binary_filepath)}
147
+ metadata_filename = f"{filename}_metadata.json"
148
+ metadata_filepath = BINARY_PATH / metadata_filename
149
+ with open(metadata_filepath, "w") as outfile:
150
+ json.dump(metadata, outfile, indent=4)
151
+
152
+
153
+ def download_binaries(system_os: str, bin_type: str):
154
+ """
155
+ Download binary from release url
156
+ Args:
157
+ system_os: string, current system type
158
+ bin_type: string of "OMP" or "CUDA"
159
+
160
+ Returns:
161
+ None
162
+
163
+ """
164
+ for url in URL_DICT[system_os][bin_type]:
165
+ # Extract the file name from the GitHub release URL
166
+ binary_version, filename = url.split("/")[-2:]
167
+
168
+ logging.log(logging.INFO, f"Downloading {filename} to {BINARY_PATH}...")
169
+
170
+ # Create the directory if it does not yet exist
171
+ os.makedirs(BINARY_PATH, exist_ok=True)
172
+
173
+ # Download the binary file
174
+ try:
175
+ binary_filepath = os.path.join(BINARY_PATH, filename)
176
+ urlretrieve(url, binary_filepath)
177
+ _record_binary_metadata(binary_version=binary_version, binary_filepath=binary_filepath, binary_url=url, filename=filename)
178
+
179
+ except TimeoutError:
180
+ logging.log(
181
+ logging.WARN,
182
+ f"Download of {filename} timed out. "
183
+ "This can be due to slow internet connection. "
184
+ "Partially downloaded files will be removed.",
185
+ )
186
+ try:
187
+ os.remove(BINARY_PATH)
188
+ except Exception:
189
+ folder_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
190
+ logging.warning(
191
+ "Error occurred while removing partially downloaded binary. "
192
+ f"Please manually delete the `{folder_path}` folder which "
193
+ "can be found in your virtual environment."
194
+ )
195
+
196
+
197
+ def install_binaries():
198
+ for binary_type in ARCHITECTURES:
199
+ download_binaries(PLATFORM, binary_type)
200
+
201
+
202
+ if not binaries_present():
203
+ install_binaries()
@@ -60,6 +60,7 @@ class FlexibleVector(object):
60
60
 
61
61
  WARNING: The class will be deprecated once we refactor the kWaveGrid class to use the Vector class instead!
62
62
  """
63
+
63
64
  data: list
64
65
 
65
66
  def __post_init__(self):
@@ -1,32 +1,39 @@
1
- import logging
2
1
  import stat
3
2
  import subprocess
4
- import unittest.mock
3
+ import sys
5
4
 
6
5
  import h5py
7
6
 
7
+ import kwave
8
8
  from kwave.utils.dotdictionary import dotdict
9
9
 
10
10
 
11
11
  class Executor:
12
-
13
12
  def __init__(self, execution_options, simulation_options):
14
-
15
13
  self.execution_options = execution_options
16
14
  self.simulation_options = simulation_options
17
15
 
18
16
  self._make_binary_executable()
19
17
 
20
18
  def _make_binary_executable(self):
21
- self.execution_options.binary_path.chmod(self.execution_options.binary_path.stat().st_mode | stat.S_IEXEC)
19
+ try:
20
+ self.execution_options.binary_path.chmod(self.execution_options.binary_path.stat().st_mode | stat.S_IEXEC)
21
+ except FileNotFoundError as e:
22
+ if kwave.PLATFORM == "darwin" and self.execution_options.is_gpu_simulation:
23
+ raise ValueError(
24
+ "GPU simulations are currently not supported on MacOS. Try running the simulation on CPU by setting is_gpu_simulation=False."
25
+ ) from e
26
+ else:
27
+ raise e
22
28
 
23
29
  def run_simulation(self, input_filename: str, output_filename: str, options: str):
24
-
25
- command = f'{self.execution_options.system_string} ' \
26
- f'{self.execution_options.binary_path} ' \
27
- f'-i {input_filename} ' \
28
- f'-o {output_filename} ' \
29
- f'{options}'
30
+ command = (
31
+ f"{self.execution_options.system_string} "
32
+ f"{self.execution_options.binary_path} "
33
+ f"-i {input_filename} "
34
+ f"-o {output_filename} "
35
+ f"{options}"
36
+ )
30
37
 
31
38
  try:
32
39
  with subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, text=True) as proc:
@@ -34,22 +41,19 @@ class Executor:
34
41
  if self.execution_options.show_sim_log:
35
42
  # Stream stdout in real-time
36
43
  for line in proc.stdout:
37
- print(line, end='')
38
- else:
39
- stdout, stderr = proc.communicate()
44
+ print(line, end="")
45
+
46
+ stdout, stderr = proc.communicate()
40
47
 
41
- proc.wait() # wait for process to finish before checking return code
48
+ proc.wait() # wait for process to finish before checking return code
42
49
  if proc.returncode != 0:
43
50
  raise subprocess.CalledProcessError(proc.returncode, command, stdout, stderr)
44
51
 
45
52
  except subprocess.CalledProcessError as e:
46
- # Special handling for MagicMock during testing
47
- if isinstance(e.returncode, unittest.mock.MagicMock):
48
- logging.info('Skipping AssertionError in testing.')
49
- else:
50
- # This ensures stdout is printed regardless of show_sim_logs value if an error occurs
51
- print(e.stdout)
52
- raise
53
+ # This ensures stdout is printed regardless of show_sim_logs value if an error occurs
54
+ print(e.stdout)
55
+ print(e.stderr, file=sys.stderr)
56
+ raise
53
57
 
54
58
  sensor_data = self.parse_executable_output(output_filename)
55
59
 
@@ -57,7 +61,6 @@ class Executor:
57
61
 
58
62
  @staticmethod
59
63
  def parse_executable_output(output_filename: str) -> dotdict:
60
-
61
64
  # Load the simulation and pml sizes from the output file
62
65
  # with h5py.File(output_filename, 'r') as output_file:
63
66
  # Nx, Ny, Nz = output_file['/Nx'][0].item(), output_file['/Ny'][0].item(), output_file['/Nz'][0].item()
@@ -79,10 +82,10 @@ class Executor:
79
82
  # z1, z2 = 1 + pml_z_size, Nz - pml_z_size if Nz > 1 else (1, Nz)
80
83
 
81
84
  # Load the C++ data back from disk using h5py
82
- with h5py.File(output_filename, 'r') as output_file:
85
+ with h5py.File(output_filename, "r") as output_file:
83
86
  sensor_data = {}
84
87
  for key in output_file.keys():
85
- sensor_data[key] = output_file[f'/{key}'][0].squeeze()
88
+ sensor_data[key] = output_file[f"/{key}"][0].squeeze()
86
89
  # if self.simulation_options.cuboid_corners:
87
90
  # sensor_data = [output_file[f'/p/{index}'][()] for index in range(1, len(key['mask']) + 1)]
88
91
  #