|
| 1 | +# Pace-Neutrons: getting started |
| 2 | +version: 0.3.0 |
| 3 | +## Introduction |
| 4 | + |
| 5 | +Pace-Neutrons (formerly known as pace-python) is a Python package which brings Horace >3.6.3 and SpinW to Python, removing the need for Matlab whilst keeping the commands you have become familiar with. |
| 6 | + |
| 7 | +## Requirements |
| 8 | + |
| 9 | +- Windows |
| 10 | +- Python 3.8, 3.9 or 3.10 (You can check this by running `python --version` in your terminal) |
| 11 | +- Matlab R2021b runtime |
| 12 | + |
| 13 | +## Installation |
| 14 | + |
| 15 | +The easiest way to install `pace-neutrons` and its installer is by downloading the `pace_neutrons_installer` from the [release](https://github.com/pace-neutrons/pace-python/releases) on github. |
| 16 | +When this is run, it will install the pace-neutrons pypi package as well as the Matlab runtime required to use the package. |
| 17 | + |
| 18 | +Alternatively, Pace-Neutrons can be installed from [PyPi](https://pypi.org/project/pace-neutrons/#description) by running: |
| 19 | + |
| 20 | +`pip install pace-neutrons` |
| 21 | + |
| 22 | +This will require you to download and install the corresponding Matlab runtime (by default R2021b) which can be found along with installation instructions |
| 23 | +[here](https://uk.mathworks.com/products/compiler/matlab-runtime.html). The correct runtime can also be obtained by running the `pace_neutrons --install-mcr` |
| 24 | +command in your terminal. |
| 25 | + |
| 26 | +## Usage |
| 27 | + |
| 28 | +### Differences to regular Horace |
| 29 | + |
| 30 | +All of the familiar [Horace commands](https://pace-neutrons.github.io/Horace/v3.6.3/) can be used with pace-neutrons simply by prefixing them |
| 31 | +with `m.`, transforming MATLAB arrays and cell-arrays to numpy `array`s/`list`s and `struct`s to `dict`s and dropping the semi-colon at the end of the line. For example, |
| 32 | + |
| 33 | +```matlab |
| 34 | +plot(cut_sqw('file.sqw', proj, [-2 0.05 2], [-2 0.05 2], [-0.1 0.1], [9 11], '-nopix')); |
| 35 | +``` |
| 36 | + |
| 37 | +would become |
| 38 | + |
| 39 | +```python |
| 40 | +m.plot(m.cut_sqw('file.sqw', proj, [-2, 0.05, 2], [-2, 0.05, 2], [-0.1, 0.1], [9, 11], '-nopix')) |
| 41 | +``` |
| 42 | + |
| 43 | +(Note that Python requires a comma between vector elements, unlike Matlab). |
| 44 | + |
| 45 | +Beyond this, the key difference is that the syntax used beyond Horace, e.g. for loops |
| 46 | +and conditional statements, or to define structures will be Python. |
| 47 | +So, in the above example, whilst the projection `struct` would be defined as |
| 48 | + |
| 49 | +```matlab |
| 50 | +proj = struct('u', [1 1 0], 'v', [-1 1 0], 'type', 'rrr'); |
| 51 | +``` |
| 52 | + |
| 53 | +or |
| 54 | + |
| 55 | +```matlab |
| 56 | +proj = struct(); |
| 57 | +proj.u = [1 1 0]; proj.v = [-1 1 0]; proj.type = 'rrr'; |
| 58 | +``` |
| 59 | + |
| 60 | +in Matlab, in Python it must be defined as a `dict` as follows |
| 61 | + |
| 62 | +```python |
| 63 | +proj = {'u':[1, 1, 0], 'v':[-1, 1, 0], 'type':'rrr'} |
| 64 | +``` |
| 65 | + |
| 66 | +or |
| 67 | + |
| 68 | +```python |
| 69 | +proj = {} |
| 70 | +proj['u'] = [1, 1, 0]; proj['v'] = [-1, 1, 0]; proj['type'] = 'rrr'; |
| 71 | +``` |
| 72 | + |
| 73 | +Likewise, loops would use Python syntax so something in Matlab like: |
| 74 | + |
| 75 | +```matlab |
| 76 | +proj = struct('u', [1 1 0], 'v', [-1 1 0], 'type', 'rrr'); |
| 77 | +for en = [10:2:20] |
| 78 | + plot(cut_sqw('file.sqw', proj, [-2 0.05 2], [-2 0.05 2], [-0.1 0.1], en+[-1 1], '-nopix')); |
| 79 | + lz 0 0.01; |
| 80 | + keep_figure; |
| 81 | +end |
| 82 | +``` |
| 83 | + |
| 84 | +would become in Python: |
| 85 | + |
| 86 | +```python |
| 87 | +proj = {'u':[1, 1, 0], 'v':[-1, 1, 0], 'type':'rrr'} |
| 88 | +for en in range(10, 21, 2): |
| 89 | + m.plot(m.cut_sqw('file.sqw', proj, [-2, 0.05, 2], [-2, 0.05, 2], [-0.1, 0.1], [en-1, en+1], '-nopix')) |
| 90 | + m.lz(0, 0.01) |
| 91 | + m.keep_figure() |
| 92 | +``` |
| 93 | + |
| 94 | +Note that the Matlab "command syntax" (e.g. `lz 0 0.01`) will not work in Python so you must use the "Function syntax" instead. |
| 95 | +Also, whilst Matlab allows functions to be called without the brackets if no arguments are needed, |
| 96 | +Python does not, hence the need for brackets in `m.keep_figure()`. |
| 97 | +Finally, the `plus` (`+`) operator functions differently for Matlab `vector`s and Python `list`s, |
| 98 | +so the syntax `en+[-1 1]` in Matlab will not work in Python. |
| 99 | +In Matlab is works as an addition, whilst in Python it is a concatenation operator. |
| 100 | +The Matlab `vector` is more like a *numpy* `array`, than a Python `list` but the similarity of square bracket operators for |
| 101 | +the construction of Matlab `vector`s and Python `list`s caused us to choose to allow `list`s of numbers to be substituted |
| 102 | +for Matlab `vector`s. |
| 103 | +If you want to use the `plus` operator like in Matlab, you can convert the list into a numpy array, e.g. |
| 104 | + |
| 105 | +```python |
| 106 | +import numpy as np |
| 107 | +for en in range(10, 21, 2): |
| 108 | + m.plot(m.cut_sqw('file.sqw', proj, [-2, 0.05, 2], [-2, 0.05, 2], [-0.1, 0.1], en+np.array([-1, 1]), '-nopix')) |
| 109 | +``` |
| 110 | + |
| 111 | +A Matlab `cell array` is more similar to a Python `list` but in Python the curly brackets are used to construct a `dict`. |
| 112 | +So, instead we have chosen to use a Python `tuple` as equivalent to a Matlab `cell array` |
| 113 | +(a Python `list` which contains non-numeric elements will also be interpreted as a Matlab `cell array`). |
| 114 | + |
| 115 | +Thus the following code in Matlab: |
| 116 | + |
| 117 | +```matlab |
| 118 | +proj = struct('u', [1 1 0], 'v', [-1 1 0], 'type', 'rrr'); |
| 119 | +ws = cut_sqw('file.sqw', proj, [-2, 0.05, 2], [-0.1, 0.1], [-0.1, 0.1], [4, 6]); |
| 120 | +tri = sw_model('triAF', 1); |
| 121 | +fwhm = 0.75; |
| 122 | +scalefactor = 1; |
| 123 | +kk = multifit_sqw(ws); |
| 124 | +kk = kk.set_fun(@tri.horace_sqw); |
| 125 | +kk = kk.set_pin({[J fwhm scalefactor], 'mat', {'J_1'}, 'hermit', false, 'formfact', true, 'resfun', 'gauss'}); |
| 126 | +tic |
| 127 | +ws_sim = kk.simulate() |
| 128 | +toc |
| 129 | +``` |
| 130 | + |
| 131 | +would be in Python: |
| 132 | + |
| 133 | +```python |
| 134 | +proj = {'u':[1, 1, 0], 'v':[-1, 1, 0], 'type':'rrr'} |
| 135 | +ws = m.cut_sqw('file.sqw', proj, [-2, 0.05, 2], [-0.1, 0.1], [-0.1, 0.1], [4, 6]) |
| 136 | +tri = m.sw_model('triAF', 1) |
| 137 | +fwhm = 0.75 |
| 138 | +scalefactor = 1 |
| 139 | +kk = m.multifit_sqw(ws) |
| 140 | +kk = kk.set_fun(tri.horace_sqw) |
| 141 | +kk = kk.set_pin(([J, fwhm, scalefactor], 'mat', ['J_1'], 'hermit', false, 'formfact', true, 'resfun', 'gauss')) |
| 142 | +m.tic() |
| 143 | +ws_sim = kk.simulate() |
| 144 | +m.toc() |
| 145 | +``` |
| 146 | + |
| 147 | +### Setup |
| 148 | + |
| 149 | +In order to get started with pace-neutrons, first begin a python session either in your terminal |
| 150 | +by running either the `python` or `python3` command or by creating a `.py` file. Once this is done, |
| 151 | +the following commands must be run in order for Horace commands to be useable: |
| 152 | + |
| 153 | +```python |
| 154 | +from pace_neutrons import Matlab |
| 155 | +m = Matlab() |
| 156 | +``` |
| 157 | + |
| 158 | +**Note:** if you assign `Matlab()` to a different variable name this would be the new prefix to |
| 159 | +the Horace matlab commands. |
| 160 | + |
| 161 | +### Example commands |
| 162 | + |
| 163 | +#### Example |
| 164 | + |
| 165 | +Using Horace: |
| 166 | +```matlab |
| 167 | +proj = projaxes([-0.5, 1, 0], [0, 0, 1], 'type', 'rrr'); |
| 168 | +w1 = cut_sqw('ei30_10K.sqw', proj, [0.1, 0.02, 0.5], [1.5, 2.5], [0.4, 0.5], [3, 0.5, 20]); |
| 169 | +hf = plot(w1); |
| 170 | +``` |
| 171 | + |
| 172 | +Using pace-neutrons: |
| 173 | +```python |
| 174 | +from pace_neutrons import Matlab |
| 175 | +m = Matlab() |
| 176 | +proj = m.projaxes([-0.5, 1, 0], [0, 0, 1], 'type', 'rrr') |
| 177 | +w1 = m.cut_sqw('ei30_10K.sqw', proj, [0.1, 0.02, 0.5], [1.5, 2.5], [0.4, 0.5], [3, 0.5, 20]) |
| 178 | +hf = m.plot(w1) |
| 179 | +``` |
| 180 | + |
| 181 | +**Note:** The above example will not work for you due the absence of the `'ei30_10K.sqw'` file. |
| 182 | + |
| 183 | +Additional examples can be found in the demo scripts detailed in the next section. |
| 184 | +The examples found in the demo are complete with the required data files ready for use. |
| 185 | + |
| 186 | +#### Demo |
| 187 | + |
| 188 | +A demo for pace-neutrons is found [here](https://github.com/pace-neutrons/pace-python-demo). This can be |
| 189 | +downloaded by first navigating to the provided github repository and clicking on the green code button and |
| 190 | +selecting the `Download ZIP` option. This demo is complete with a demo `.py` script as well as a `.ipynb` |
| 191 | +file for use in a Jupyter notebook. |
| 192 | + |
| 193 | + |
| 194 | +#### Horace GUI |
| 195 | + |
| 196 | +The Horace GUI can be opened, following the setup procedure outlined above, by |
| 197 | +running `m.horace()` |
| 198 | + |
| 199 | +## Jupyter notebook specifics |
| 200 | + |
| 201 | +By default, when creating the Matlab plots in a Jupyter notebook, a screenshot of the plot is taken |
| 202 | +and displayed in the document. To bypass this behaviour and obtain the usual pop out plots expected |
| 203 | +from plots created using Horace, `%matlab_plot_mode windowed` can be run in a code cell. More information |
| 204 | +on this, as well as additional commands can be found [here](IPythonMagics_commands.md). |
| 205 | + |
| 206 | +## Advanced usage (for developers): Creating a custom build |
| 207 | + |
| 208 | +An installable wheel file can be built by running `python setup.py bdist_wheel <options>` in the top level |
| 209 | +directory of pace-python. The command line <options> allow a build to be customised. The available options are |
| 210 | +detailed below and can be used by prefixing them with `-D`. |
| 211 | + |
| 212 | +**Note:** Through the dependence on the `libpymcr` python package, custom builds are not required to conform to |
| 213 | +standard Matlab-python version compatability and instead can use any combination of Python3 and Matlab. |
| 214 | + |
| 215 | +#### Command line options |
| 216 | + |
| 217 | +- **WITH_HORACE** - Set Horace use ON/OFF |
| 218 | +- **WITH_SPINW** - Set SpinW use ON/OFF |
| 219 | +- **HORACE_PATH** - Provide a path to your version of Horace |
| 220 | +- **SPINW_PATH** - Provide a path to your version of SpinW |
| 221 | +- **HORACE_VERSION** - Set the Horace release version to download e.g. 3.6.3 |
| 222 | +- **SPINW_VERSION** - Set the SpinW version (git tag/branch/hash) |
| 223 | +- **SPINW_REPO** - Set the repo to get SpinW from e.g. "mducle/spinw" |
| 224 | +- **Matlab_ROOT_DIR** - Provide a path to desired Matlab version |
| 225 | + |
| 226 | +#### Example |
| 227 | + |
| 228 | +```sh |
| 229 | +python setup.py bdist_wheel -DWITH_SPINW=OFF -DHORACE_PATH="/path/to/your/systems/Horace" |
| 230 | +``` |
| 231 | + |
| 232 | +This example builds pace-neutrons without SpinW and uses a local copy of Horace located at |
| 233 | +the provided path. |
| 234 | + |
| 235 | +## Running on Linux |
| 236 | + |
| 237 | +Currently, whilst using linux, `pace_neutrons` struggles to locate Matlab. It may be possible |
| 238 | +to resolve this by setting the following two environment variables: |
| 239 | + |
| 240 | +``` |
| 241 | +LD_LIBRARY_PATH = "<matlab_runtime_root>/runtime/glnxa64:<matlab_runtime_root>/bin/glnxa64" |
| 242 | +LD_PRELOAD = "<matlab_runtime_root>/sys/os/glnxa64/libiomp5.so" |
| 243 | +``` |
| 244 | + |
| 245 | +Alternatively, try running the `pace_neutrons` with the `--matlab-dir` option as shown below: |
| 246 | + |
| 247 | +`pace_neutrons --matlab-dir /path/to/matlab/runtime` |
0 commit comments