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.
- k_wave_python-0.3.4/.gitignore +46 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pre-commit-config.yaml +9 -0
- k_wave_python-0.3.4/.ruff_cache/0.2.2/11727547499557932880 +0 -0
- k_wave_python-0.3.4/.ruff_cache/0.2.2/15979114690223248129 +0 -0
- k_wave_python-0.3.4/.ruff_cache/0.2.2/2528246142718653170 +0 -0
- k_wave_python-0.3.4/.ruff_cache/0.2.2/3142013637658215183 +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/CITATION.cff +6 -5
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/PKG-INFO +28 -41
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/docs/README.md +12 -25
- k_wave_python-0.3.4/kwave/__init__.py +203 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/data.py +1 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/executor.py +28 -25
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation.py +273 -299
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/__init__.py +0 -2
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/create_absorption_variables.py +7 -7
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/display_simulation_params.py +26 -17
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/expand_grid_matrices.py +35 -31
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/retract_transducer_grid_size.py +0 -2
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/save_to_disk_func.py +153 -138
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/scale_source_terms_func.py +40 -45
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kWaveSimulation_helper/set_sound_speed_ref.py +7 -11
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kgrid.py +40 -47
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kmedium.py +46 -44
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/ksensor.py +5 -6
- k_wave_python-0.3.4/kwave/ksource.py +382 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kspaceFirstOrder2D.py +93 -102
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kspaceFirstOrder3D.py +94 -103
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/kspaceFirstOrderAS.py +89 -88
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/ktransducer.py +118 -113
- k_wave_python-0.3.4/kwave/options/simulation_execution_options.py +145 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/options/simulation_options.py +61 -57
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/reconstruction/beamform.py +9 -19
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/reconstruction/tools.py +26 -23
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/recorder.py +41 -26
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/angular_spectrum.py +64 -72
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/angular_spectrum_cw.py +53 -63
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/atten_comp.py +78 -87
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/checks.py +67 -86
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/colormap.py +12 -12
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/conversion.py +59 -70
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/data.py +37 -43
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/filters.py +97 -93
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/interp.py +76 -85
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/io.py +139 -145
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/kwave_array.py +197 -199
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/mapgen.py +284 -409
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/math.py +47 -66
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/matlab.py +15 -16
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/matrix.py +32 -37
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/plot.py +5 -5
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/pml.py +16 -13
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/signals.py +116 -125
- k_wave_python-0.3.4/kwave/utils/typing.py +35 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/pyproject.toml +23 -21
- k_wave_python-0.3.2/.gitignore +0 -23
- k_wave_python-0.3.2/.pytest_cache/v/cache/lastfailed +0 -1
- k_wave_python-0.3.2/.pytest_cache/v/cache/nodeids +0 -160
- k_wave_python-0.3.2/kwave/__init__.py +0 -148
- k_wave_python-0.3.2/kwave/kWaveSimulation_helper/create_storage_variables.py +0 -399
- k_wave_python-0.3.2/kwave/kWaveSimulation_helper/data_cast.py +0 -188
- k_wave_python-0.3.2/kwave/ksource.py +0 -375
- k_wave_python-0.3.2/kwave/options/simulation_execution_options.py +0 -155
- k_wave_python-0.3.2/kwave/utils/typing.py +0 -22
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/.gitignore +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/CACHEDIR.TAG +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/README.md +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.pytest_cache/v/cache/stepwise +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.readthedocs.yaml +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/.gitignore +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/CACHEDIR.TAG +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/13487435192755641643 +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/1921099194987439213 +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/5526710289020645422 +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/5950811561636507670 +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/.ruff_cache/content/655415607675938108 +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/Dockerfile +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/LICENSE +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/enums.py +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/options/__init__.py +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/reconstruction/__init__.py +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/__init__.py +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/dotdictionary.py +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/kwave/utils/tictoc.py +0 -0
- {k_wave_python-0.3.2 → k_wave_python-0.3.4}/make_docs.sh +0 -0
- {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:
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
cff-version: 1.2.0
|
|
2
|
-
title: k-Wave-
|
|
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.
|
|
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.
|
|
691
|
-
Requires-Dist: deepdiff==
|
|
692
|
-
Requires-Dist: h5py==3.
|
|
693
|
-
Requires-Dist:
|
|
694
|
-
Requires-Dist:
|
|
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.
|
|
697
|
-
Requires-Dist: scipy==1.
|
|
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.
|
|
699
|
+
Requires-Dist: pre-commit==3.7.1; extra == 'dev'
|
|
700
700
|
Provides-Extra: docs
|
|
701
|
-
Requires-Dist: furo==2024.
|
|
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-
|
|
705
|
-
Requires-Dist: sphinx-
|
|
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==
|
|
707
|
+
Requires-Dist: gdown==5.2.0; extra == 'example'
|
|
708
708
|
Provides-Extra: test
|
|
709
|
-
Requires-Dist: coverage==7.4
|
|
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.
|
|
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
|
+
[](https://discord.gg/Yq5Qj6D9vN)
|
|
716
718
|
[](https://k-wave-python.readthedocs.io/en/latest/?badge=latest)
|
|
717
719
|
[](https://codecov.io/gh/waltsims/k-wave-python)
|
|
718
720
|
[](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
|

|
|
744
735
|
|
|
745
|
-
|
|
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
|
-
|
|
762
|
-
|
|
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
|
-
|
|
765
|
-
|
|
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
|
+
[](https://discord.gg/Yq5Qj6D9vN)
|
|
2
4
|
[](https://k-wave-python.readthedocs.io/en/latest/?badge=latest)
|
|
3
5
|
[](https://codecov.io/gh/waltsims/k-wave-python)
|
|
4
6
|
[](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
|

|
|
30
21
|
|
|
31
|
-
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
|
|
51
|
-
|
|
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()
|
|
@@ -1,32 +1,39 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
import stat
|
|
3
2
|
import subprocess
|
|
4
|
-
import
|
|
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
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
39
|
-
|
|
44
|
+
print(line, end="")
|
|
45
|
+
|
|
46
|
+
stdout, stderr = proc.communicate()
|
|
40
47
|
|
|
41
|
-
proc.wait()
|
|
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
|
-
#
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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,
|
|
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
|
|
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
|
#
|