|
1 | 1 | Development Environment |
2 | 2 | ======================= |
3 | 3 |
|
4 | | -Currently, this package serves as an interface to the cpp binaries of k-Wave. |
5 | | -For this reason, binaries are required to run simulations with `k-Wave-python`. |
6 | | -The binaries are downloaded by k-Wave-python when the package is run for the first time. |
| 4 | +Overview |
| 5 | +-------- |
| 6 | +k-Wave-python is a Python interface to the k-Wave C++ binaries, which are required to run simulations. The binaries are automatically downloaded when the package runs for the first time. |
7 | 7 |
|
8 | | -To correctly set up your development environment for this repository, clone the repository from github, and install the project dependencies. |
| 8 | +Environment Setup with uv |
| 9 | +------------------------- |
9 | 10 |
|
| 11 | +1. Install uv |
| 12 | +~~~~~~~~~~~~~ |
| 13 | +.. code-block:: bash |
| 14 | + |
| 15 | + curl -LsSf https://astral.sh/uv/install.sh | sh |
| 16 | + |
| 17 | +2. Clone the Repository |
| 18 | +~~~~~~~~~~~~~~~~~~~~~~~ |
10 | 19 | .. code-block:: bash |
11 | 20 |
|
12 | 21 | git clone https://github.com/waltsims/k-wave-python |
13 | 22 | cd k-wave-python |
14 | | - pip install -e '.[dev,test]' |
15 | 23 |
|
16 | | -This installs all the dependencies for development, and testing. |
| 24 | +3. Create and Activate Virtual Environment |
| 25 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 26 | +.. code-block:: bash |
17 | 27 |
|
18 | | -Ensure pre-commit is configured by running the following command: |
| 28 | + uv venv |
| 29 | + source .venv/bin/activate # On Windows: .venv\Scripts\activate |
| 30 | + |
| 31 | +4. Install Dependencies |
| 32 | +~~~~~~~~~~~~~~~~~~~~~~~ |
| 33 | +Install development and testing dependencies using uv: |
19 | 34 |
|
| 35 | +.. code-block:: bash |
| 36 | + |
| 37 | + uv pip install -e '.[dev,test]' |
| 38 | + |
| 39 | +5. Configure Pre-commit Hooks |
| 40 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | 41 | .. code-block:: bash |
21 | 42 |
|
22 | 43 | pre-commit install |
23 | 44 |
|
24 | | -Running Tests |
25 | | -======================= |
26 | | -Assuming matlab is installed locally, and `k-wave <https://github.com/ucl-bug/k-wave>` is installed in a parallel directory, testing can be performed using the make file located in the project root. |
| 45 | +Testing |
| 46 | +------- |
27 | 47 |
|
28 | | -.. code-block:: bash |
| 48 | +Prerequisites |
| 49 | +~~~~~~~~~~~~~ |
| 50 | +- MATLAB installed locally (see `Alternative to MATLAB`_ if you don't have MATLAB) |
| 51 | +- `k-Wave <https://github.com/ucl-bug/k-wave>`_ installed in a parallel directory to k-wave-python |
29 | 52 |
|
30 | | - make test |
| 53 | +**Directory structure for parallel installation:** |
| 54 | + |
| 55 | +.. code-block:: text |
31 | 56 |
|
32 | | -This process will first generate reference files in matlab and run the complete python test suite against them. |
| 57 | + <parent_dir>/ |
| 58 | + ├── k-wave/ |
| 59 | + │ ├── k-Wave/ |
| 60 | + │ ├── LICENSE.txt |
| 61 | + │ └── README.md |
| 62 | + └── k-wave-python/ |
| 63 | + ├── kwave/ |
| 64 | + └── ... |
33 | 65 |
|
34 | | -To run the tests manually after reference generation, use the following command: |
| 66 | + |
| 67 | +Running Tests |
| 68 | +~~~~~~~~~~~~~ |
| 69 | + |
| 70 | +Full Test Suite |
| 71 | +^^^^^^^^^^^^^^^ |
| 72 | +Generate reference files with MATLAB and run the complete Python test suite: |
35 | 73 |
|
36 | 74 | .. code-block:: bash |
| 75 | + cd k-wave-python/ |
| 76 | + make test |
| 77 | + |
| 78 | +Manual Test Execution |
| 79 | +^^^^^^^^^^^^^^^^^^^^^ |
| 80 | +After reference generation: |
37 | 81 |
|
38 | | - pytest |
| 82 | +.. code-block:: bash |
39 | 83 |
|
40 | | -To run the tests with coverage, use the following command: |
| 84 | + pytest |
41 | 85 |
|
| 86 | +Test Coverage |
| 87 | +^^^^^^^^^^^^^ |
42 | 88 | .. code-block:: bash |
43 | 89 |
|
44 | 90 | coverage run |
45 | 91 |
|
46 | | -To run all examples, to ensure they still run after changes use the following command: |
| 92 | +Running Examples |
| 93 | +~~~~~~~~~~~~~~~~ |
47 | 94 |
|
| 95 | +Default (GPU-enabled) |
| 96 | +^^^^^^^^^^^^^^^^^^^^^ |
48 | 97 | .. code-block:: bash |
49 | 98 |
|
50 | 99 | make run-examples |
| 100 | + # or |
| 101 | + MPLBACKEND=Agg python run_examples.py |
51 | 102 |
|
52 | | -or |
53 | | - |
| 103 | +Force CPU Execution |
| 104 | +^^^^^^^^^^^^^^^^^^ |
54 | 105 | .. code-block:: bash |
55 | 106 |
|
56 | | - MPLBACKEND=Agg python run_examples.py |
| 107 | + MPLBACKEND=Agg KWAVE_FORCE_CPU=1 python run_examples.py |
57 | 108 |
|
| 109 | +Test Architecture |
| 110 | +----------------- |
58 | 111 |
|
| 112 | +The test suite compares Python and MATLAB outputs through two methodologies: |
59 | 113 |
|
60 | | -If you want to force the examples to run on the cpu: |
| 114 | +1. Unit Testing |
| 115 | +~~~~~~~~~~~~~~~ |
| 116 | +- Tests k-Wave-python functions against their MATLAB counterparts |
| 117 | +- Reference outputs stored in ``.mat`` files |
| 118 | +- Generated by MATLAB scripts in ``tests/matlab_test_data_collectors/matlab_collectors/`` |
| 119 | +- Master script: ``tests/matlab_test_data_collectors/run_all_collectors.m`` |
| 120 | +- Output location: ``tests/matlab_test_data_collectors/python_testers/collectedValues/`` |
61 | 121 |
|
62 | | -.. code-block:: bash |
| 122 | +.. _`Alternative to MATLAB`: |
63 | 123 |
|
64 | | - MPLBACKEND=Agg KWAVE_FORCE_CPU=1 python run_examples.py |
| 124 | +.. note:: |
| 125 | + **Alternative to MATLAB:** If you don't have a local MATLAB installation, you can download pre-generated reference artifacts from `GitHub CI <https://nightly.link/waltsims/k-wave-python/workflows/pytest/master/matlab_reference_test_values.zip>`_. |
65 | 126 |
|
66 | 127 |
|
67 | | -Test References |
68 | | -======================= |
| 128 | +.. _`GitHub CI artifacts link`: https://nightly.link/waltsims/k-wave-python/workflows/pytest/master/matlab_reference_test_values.zip |
| 129 | + |
| 130 | +2. Integration Testing |
| 131 | +~~~~~~~~~~~~~~~~~~~~~~ |
| 132 | +- Validates ``.h5`` files produced by k-Wave-python against original k-Wave outputs |
| 133 | +- Uses hash values from MATLAB examples stored in JSON files |
| 134 | +- Hash files location: ``tests/reference_outputs/`` |
| 135 | +- These files are committed to the repository and only require updates for new k-Wave releases |
| 136 | + |
| 137 | +Generating MATLAB Reference Files |
| 138 | +--------------------------------- |
| 139 | + |
| 140 | +Process for Creating Reference Files |
| 141 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 142 | + |
| 143 | +1. Open target MATLAB example (e.g., ``example_pr_2D_TR_directional_sensors.m`` from the `k-Wave repository <https://github.com/ucl-bug/k-wave/blob/main/k-Wave/examples/example_pr_2D_TR_directional_sensors.m>`_) |
| 144 | + |
| 145 | +2. Locate ``kSpaceFirstOrder`` function call: |
| 146 | + |
| 147 | + .. code-block:: matlab |
| 148 | + |
| 149 | + input_args = {'PMLInside', false, 'PMLSize', PML_size, 'PlotPML', false, 'Smooth', false}; |
| 150 | + sensor_data = kspaceFirstOrder2D(kgrid, medium, source, sensor, input_args{:}); |
| 151 | + |
| 152 | +3. Add save options to ``input_args``: |
| 153 | + |
| 154 | + .. code-block:: matlab |
| 155 | + |
| 156 | + input_args = {'PMLInside', false, 'PMLSize', PML_size, 'PlotPML', false, 'Smooth', false, 'SaveToDisk', true, 'SaveToDiskExit', true}; |
| 157 | + |
| 158 | +4. Run modified example to generate ``.h5`` files in your ``tmp`` folder: |
| 159 | + |
| 160 | + - Single function call: creates ``example_input.h5`` |
| 161 | + - Multiple calls: creates ``example_input_1.h5``, ``example_input_2.h5``, etc. |
| 162 | + |
| 163 | +5. Convert ``.h5`` files to JSON hashes using ``H5Summary``: |
69 | 164 |
|
70 | | -Tests compare the outputs of the python and the matlab interfaces. |
71 | | -These tests are located in the ``tests`` directory. The comparison between ``matlab`` and ``python`` outputs are done in two ways: |
| 165 | + - Single file: see `lines 92-95 <https://github.com/waltsims/k-wave-python/blob/1f9df5d987d0b3edb1a8a43fad0885d3d6079029/tests/h5_summary.py#L92-L95>`_ |
| 166 | + - Multiple files: see `lines 97-106 <https://github.com/waltsims/k-wave-python/blob/1f9df5d987d0b3edb1a8a43fad0885d3d6079029/tests/h5_summary.py#L97-L106>`_ |
| 167 | + |
| 168 | +Publishing k-wave-python |
| 169 | +----------------- |
| 170 | + |
| 171 | +`Hatch <https://hatch.pypa.io/latest/>`_ is used to publish k-wave-python to `PyPI <https://pypi.org/>`_. |
72 | 172 |
|
73 | | -- **Unit testing**: k-Wave-python functions that have a direct counterpart in original k-Wave are tested by comparing the outputs of the two functions. |
74 | | - The output of the original k-Wave functions are stored in ``.mat`` files. |
75 | | - These files can be generated by running the corresponding MATLAB scripts located in the ``tests/matlab_test_data_collectors/matlab_collectors/`` directory by running ``tests/matlab_test_data_collectors/run_all_collectors.m``. |
76 | | - After running the scripts, the reference files can be found in ``tests/matlab_test_data_collectors/python_testes/collectedValues/``. |
77 | | - |
78 | 173 | .. note:: |
79 | | - If you do not have MATLAB installed to generate the reference files, you can download recently generated reference file outputs from the GitHub CI and place them in the ``python_testers/collectedValues/`` directory. |
80 | | - The latest reference files can be found in the artifacts of the latest CI run of ``pytest.yml`` (e.g. `here <https://github.com/waltsims/k-wave-python/actions/runs/7770639710/artifacts/1217868112>`_). |
81 | | - |
82 | | -- **Integration testing**: k-Wave-python tests output .h5 files that are passed to the k-Wave binaries and ensures that they match the output of the original k-Wave. |
83 | | - This testing compares the output for many of the example scripts from the original k-Wave package. |
84 | | - Hash values of the reference output ``.h5`` file from MATLAB examples are generated and stored in ``.json`` files in ``tests/reference_outputs/``. |
85 | | - These ``.json`` files are stored in the code repository and do not need to be regenerated. |
86 | | - Since these files are generated from the original k-Wave package, they only need to be updated when a new release of k-Wave is made. |
87 | | - |
88 | | -**Matlab reference file generation** can be described in the following steps. |
89 | | - |
90 | | -#. Open desired example in matlab, e.g. `example_pr_2D_TR_directional_sensors.m <https://github.com/ucl-bug/k-wave/blob/main/k-Wave/examples/example_pr_2D_TR_directional_sensors.m>`_ |
91 | | -#. Find the lines where the call to one of the `kSpaceFirstOrder-family` function is made. For example, |
92 | | - |
93 | | - .. code-block:: matlab |
94 | | - |
95 | | - input_args = {'PMLInside', false, 'PMLSize', PML_size, 'PlotPML', false, 'Smooth', false}; |
96 | | - sensor_data = kspaceFirstOrder2D(kgrid, medium, source, sensor, input_args{:}); |
97 | | - |
98 | | -#. Update the ``input_args`` field by adding two new options - ``{'SaveToDisk', true, 'SaveToDiskExit': true}``. These options will ensure that we a ``.h5`` file will be created and saved in your ``tmp`` folder, while avoiding to run the actual simulation. |
99 | | -#. Run the modified example. You will find created files in your ``tmp`` folder. Usually exact file name depends on how many calls are made to the `kSpaceFirstOrder-family` function in the example: |
100 | | - * If there is only a single call, created file name will be ``example_input.h5`` |
101 | | - * If there are two or more calls, created files will have names like ``example_input_1.h5``, ``example_input_2.h5``, ``example_input_3.h5`` and so on |
102 | | -#. Now it is time to turn the ``.h5`` files to the hashed ``.json`` files. This can be done with the ``H5Summary``. |
103 | | - * If you have a single ``.h5`` file, adapt the lines below and run the script: |
104 | | - https://github.com/waltsims/k-wave-python/blob/1f9df5d987d0b3edb1a8a43fad0885d3d6079029/tests/h5_summary.py#L92-L95 |
105 | | - * For multiple files, adapt the lines below: |
106 | | - https://github.com/waltsims/k-wave-python/blob/1f9df5d987d0b3edb1a8a43fad0885d3d6079029/tests/h5_summary.py#L97-L106 |
| 174 | + This is only performed by developers with write access to the k-wave-python package on PiPI. |
| 175 | + |
| 176 | +The package can be built using: |
| 177 | + |
| 178 | +.. code-block:: bash |
| 179 | + |
| 180 | + hatch build |
| 181 | + |
| 182 | +And pushed to the production index with: |
| 183 | + |
| 184 | +.. code-block:: bash |
| 185 | + |
| 186 | + hatch publish -u __token__ |
| 187 | + |
| 188 | + |
107 | 189 |
|
108 | 190 |
|
0 commit comments