MNeuEventLib 0.2.1__tar.gz → 0.3.0__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 (60) hide show
  1. mneueventlib-0.3.0/.github/workflows/push.yml +111 -0
  2. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/Cargo.lock +26 -18
  3. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/Cargo.toml +3 -1
  4. mneueventlib-0.3.0/MNeuEventLib/test_helpers.py +40 -0
  5. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/PKG-INFO +1 -1
  6. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/README.md +8 -0
  7. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/how-to/filtering.ipynb +3 -3
  8. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/tutorials/getting_started.ipynb +3 -1
  9. mneueventlib-0.3.0/files/README.md +1 -0
  10. mneueventlib-0.3.0/files/muon_ref.nxs +0 -0
  11. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/pyproject.toml +1 -0
  12. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/batch_interface.rs +71 -8
  13. mneueventlib-0.3.0/src/consts.rs +15 -0
  14. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/mod.rs +1 -1
  15. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/nexus_data.rs +8 -6
  16. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/save/instrument.rs +16 -10
  17. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/save/mod.rs +1 -0
  18. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/save/periods.rs +1 -0
  19. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/save/sample_logs.rs +4 -0
  20. mneueventlib-0.3.0/src/data/save/sanitise/mod.rs +8 -0
  21. mneueventlib-0.3.0/src/data/save/sanitise/nexus_data.rs +707 -0
  22. mneueventlib-0.3.0/src/data/save/sanitise/utils.rs +426 -0
  23. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/save/utils.rs +13 -12
  24. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/save/wimda.rs +5 -2
  25. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/interface.rs +19 -4
  26. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/stats.rs +52 -103
  27. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/test_utils.rs +10 -0
  28. mneueventlib-0.3.0/tests/integration/test_mantid.py +352 -0
  29. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/tests/test_data/HIFI00195790.nxs +0 -0
  30. mneueventlib-0.3.0/tools/make_default.py +156 -0
  31. mneueventlib-0.2.1/.github/workflows/push.yml +0 -41
  32. mneueventlib-0.2.1/src/consts.rs +0 -3
  33. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/.github/workflows/label_merge_conflicts.yml +0 -0
  34. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/.github/workflows/release.yml +0 -0
  35. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/.gitignore +0 -0
  36. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/.readthedocs.yaml +0 -0
  37. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/LICENSE +0 -0
  38. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/MNeuEventLib/__init__.py +0 -0
  39. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/MNeuEventLib/plotting.py +0 -0
  40. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/bench.py +0 -0
  41. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/Makefile +0 -0
  42. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/make.bat +0 -0
  43. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/_static/HIFI00195790.nxs +0 -0
  44. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/_static/api/README.md +0 -0
  45. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/api.rst +0 -0
  46. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/conf.py +0 -0
  47. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/how-to/create_plots.ipynb +0 -0
  48. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/how-to/index.rst +0 -0
  49. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/index.rst +0 -0
  50. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/install.rst +0 -0
  51. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/tutorials/batch_processing.ipynb +0 -0
  52. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/docs/source/tutorials/index.rst +0 -0
  53. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/frame_data.rs +0 -0
  54. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/data/sample_logs.rs +0 -0
  55. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/filters/api.rs +0 -0
  56. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/filters/filtering.rs +0 -0
  57. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/filters/mod.rs +0 -0
  58. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/filters/weights.rs +0 -0
  59. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/lib.rs +0 -0
  60. {mneueventlib-0.2.1 → mneueventlib-0.3.0}/src/utils.rs +0 -0
@@ -0,0 +1,111 @@
1
+ name:
2
+
3
+ on:
4
+ push:
5
+
6
+ env:
7
+ CARGO_TERM_COLOR: always
8
+
9
+ jobs:
10
+ format:
11
+ name: Check formatting
12
+ runs-on: ubuntu-slim
13
+ steps:
14
+ - uses: actions/checkout@v7
15
+ - uses: dtolnay/rust-toolchain@stable
16
+ with:
17
+ components: rustfmt
18
+ - run: cargo fmt --check
19
+
20
+ lint:
21
+ name: Lint
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ - uses: dtolnay/rust-toolchain@stable
26
+ with:
27
+ components: clippy
28
+ - run: cargo clippy --all-targets --all-features -- -D warnings
29
+
30
+ linux:
31
+ name: Run unit tests
32
+ needs: [lint, format]
33
+ strategy:
34
+ matrix:
35
+ os: [windows-latest, ubuntu-latest, macOS-latest]
36
+ runs-on: ${{ matrix.os }}
37
+ steps:
38
+ - uses: actions/checkout@v7
39
+ - uses: dtolnay/rust-toolchain@stable
40
+ - run: cargo test --verbose
41
+
42
+ run_integration_tests:
43
+ name: Integration tests
44
+ needs: [lint, format]
45
+ strategy:
46
+ fail-fast: false
47
+ matrix:
48
+ os: [windows-latest, ubuntu-latest, macos-latest]
49
+ build: [stable, nightly]
50
+ include:
51
+ - build: stable
52
+ mantid_channel: 'mantid'
53
+ - build: nightly
54
+ mantid_channel: 'mantid/label/nightly'
55
+ runs-on: ${{ matrix.os }}
56
+ steps:
57
+ - uses: actions/checkout@v7
58
+ with:
59
+ fetch-depth: "0"
60
+
61
+ - name: Setup Conda
62
+ uses: conda-incubator/setup-miniconda@v4
63
+ with:
64
+ miniconda-version: "latest"
65
+ mamba-version: "*"
66
+ channels: ${{ matrix.mantid_channel }},conda-forge
67
+ channel-priority: flexible
68
+ conda-remove-defaults: true
69
+ activate-environment: mantid-env
70
+ auto-activate-base: false
71
+
72
+ - name: Install Mantid and test deps
73
+ shell: bash -el {0}
74
+ env:
75
+ MSYS_NO_PATHCONV: 1
76
+ run: mamba install -y -n mantid-env mantid pytest pip
77
+
78
+ - name: Show resolved python version
79
+ shell: bash -el {0}
80
+ run: |
81
+ conda activate mantid-env
82
+ python --version
83
+
84
+ - name: Install maturin into mantid-env
85
+ shell: bash -el {0}
86
+ run: |
87
+ conda activate mantid-env
88
+ python -m pip install maturin
89
+
90
+ - name: Verify test deps installed
91
+ shell: bash -el {0}
92
+ run: |
93
+ mamba list -n mantid-env pytest
94
+ conda activate mantid-env
95
+ python -c "import pytest; print(pytest.__version__)"
96
+
97
+ - name: Install Rust toolchain
98
+ uses: dtolnay/rust-toolchain@stable
99
+
100
+ - name: Build and install Rust extension into conda env
101
+ shell: bash -el {0}
102
+ run: |
103
+ conda activate mantid-env
104
+ python -m maturin develop --release
105
+
106
+ - name: Run integration tests
107
+ shell: bash -el {0}
108
+ run: |
109
+ conda activate mantid-env
110
+ python -m pytest tests/integration/
111
+
@@ -4,15 +4,17 @@ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "MNeuEventLib"
7
- version = "0.2.1"
7
+ version = "0.3.0"
8
8
  dependencies = [
9
9
  "anyhow",
10
10
  "chrono",
11
11
  "hdf5-metno",
12
+ "hdf5-metno-sys",
12
13
  "ndarray",
13
14
  "numpy",
14
15
  "pyo3",
15
16
  "rayon",
17
+ "seq-macro",
16
18
  "serde",
17
19
  "serde_json",
18
20
  "tabled",
@@ -75,9 +77,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
75
77
 
76
78
  [[package]]
77
79
  name = "cc"
78
- version = "1.4.6"
80
+ version = "1.4.7"
79
81
  source = "registry+https://github.com/rust-lang/crates.io-index"
80
- checksum = "a3eb0f42d6c360dc3f8a821f6bf2fdea7f72bfd36b3076eb0e6d1e9e0752fff4"
82
+ checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313"
81
83
  dependencies = [
82
84
  "find-msvc-tools",
83
85
  "shlex",
@@ -85,9 +87,9 @@ dependencies = [
85
87
 
86
88
  [[package]]
87
89
  name = "cfg-if"
88
- version = "1.0.4"
90
+ version = "1.0.5"
89
91
  source = "registry+https://github.com/rust-lang/crates.io-index"
90
- checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
92
+ checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
91
93
 
92
94
  [[package]]
93
95
  name = "chrono"
@@ -172,9 +174,9 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
172
174
 
173
175
  [[package]]
174
176
  name = "find-msvc-tools"
175
- version = "0.1.12"
177
+ version = "0.1.13"
176
178
  source = "registry+https://github.com/rust-lang/crates.io-index"
177
- checksum = "3e0f1c7c3a72c66fd80abe965175f7523475c0489a87d3ff9d6e8c87d87a9d2d"
179
+ checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b"
178
180
 
179
181
  [[package]]
180
182
  name = "fnv"
@@ -248,7 +250,7 @@ dependencies = [
248
250
  "proc-macro-crate",
249
251
  "proc-macro2",
250
252
  "quote",
251
- "syn 3.0.5",
253
+ "syn 3.0.6",
252
254
  ]
253
255
 
254
256
  [[package]]
@@ -262,9 +264,9 @@ dependencies = [
262
264
 
263
265
  [[package]]
264
266
  name = "hdf5-metno-sys"
265
- version = "0.12.3"
267
+ version = "0.12.4"
266
268
  source = "registry+https://github.com/rust-lang/crates.io-index"
267
- checksum = "8139abe2218e47a40bdc7822a4365b620e23dce17e6b4735bbe6629410cdfedb"
269
+ checksum = "567a57ee34c38263f551f2cf02b95675def6b91d0e321c5e70f8c6d5ef9cee87"
268
270
  dependencies = [
269
271
  "hdf5-metno-src",
270
272
  "libc",
@@ -716,9 +718,9 @@ checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
716
718
 
717
719
  [[package]]
718
720
  name = "rustix"
719
- version = "1.1.4"
721
+ version = "1.1.5"
720
722
  source = "registry+https://github.com/rust-lang/crates.io-index"
721
- checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
723
+ checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d"
722
724
  dependencies = [
723
725
  "bitflags",
724
726
  "errno",
@@ -739,6 +741,12 @@ version = "1.2.0"
739
741
  source = "registry+https://github.com/rust-lang/crates.io-index"
740
742
  checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
741
743
 
744
+ [[package]]
745
+ name = "seq-macro"
746
+ version = "0.3.6"
747
+ source = "registry+https://github.com/rust-lang/crates.io-index"
748
+ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc"
749
+
742
750
  [[package]]
743
751
  name = "serde"
744
752
  version = "1.0.229"
@@ -766,7 +774,7 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
766
774
  dependencies = [
767
775
  "proc-macro2",
768
776
  "quote",
769
- "syn 3.0.5",
777
+ "syn 3.0.6",
770
778
  ]
771
779
 
772
780
  [[package]]
@@ -813,9 +821,9 @@ dependencies = [
813
821
 
814
822
  [[package]]
815
823
  name = "syn"
816
- version = "3.0.5"
824
+ version = "3.0.6"
817
825
  source = "registry+https://github.com/rust-lang/crates.io-index"
818
- checksum = "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9"
826
+ checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee"
819
827
  dependencies = [
820
828
  "proc-macro2",
821
829
  "quote",
@@ -906,9 +914,9 @@ dependencies = [
906
914
 
907
915
  [[package]]
908
916
  name = "unicode-ident"
909
- version = "1.0.24"
917
+ version = "1.0.26"
910
918
  source = "registry+https://github.com/rust-lang/crates.io-index"
911
- checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
919
+ checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954"
912
920
 
913
921
  [[package]]
914
922
  name = "unicode-width"
@@ -948,7 +956,7 @@ dependencies = [
948
956
  "bumpalo",
949
957
  "proc-macro2",
950
958
  "quote",
951
- "syn 3.0.5",
959
+ "syn 3.0.6",
952
960
  "wasm-bindgen-shared",
953
961
  ]
954
962
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "MNeuEventLib"
3
- version = "0.2.1"
3
+ version = "0.3.0"
4
4
  edition = "2021"
5
5
  license = "BSD-3-Clause"
6
6
  readme = "README.md"
@@ -12,6 +12,7 @@ crate-type = ["cdylib"]
12
12
 
13
13
  [dependencies]
14
14
  hdf5 = { package = "hdf5-metno", version = "0.14.1", features = ["static"] }
15
+ hdf5-metno-sys = "0.12.3"
15
16
  ndarray = "0.17.2"
16
17
  rayon = "1.12.0"
17
18
  anyhow = "1.0.102"
@@ -21,6 +22,7 @@ serde = { version = "1.0.228", features = ["derive"] }
21
22
  serde_json = "1.0.150"
22
23
  chrono = { version = "0.4.45", features = ["std"] }
23
24
  tabled = "0.21.0"
25
+ seq-macro = "0.3"
24
26
 
25
27
  [dev-dependencies]
26
28
  tempfile = "3.27.0"
@@ -0,0 +1,40 @@
1
+ import h5py
2
+ import numpy as np
3
+ import shutil
4
+
5
+
6
+ def replace(f, key, values, dtype):
7
+ """
8
+ A simple helper method to replace
9
+ a dataset (without attributes)
10
+ """
11
+ del f[key]
12
+ f.create_dataset(key, data=values, dtype=dtype)
13
+
14
+ def make_single_period_data(multi_period,
15
+ single_period):
16
+ """
17
+ This is a simple method to convert
18
+ multi-period data into single
19
+ period.
20
+ :param multi_period: the file path
21
+ to the multi-period data.
22
+ :param single_period: the file path
23
+ to write the single period data to
24
+ """
25
+ shutil.copy(multi_period,
26
+ single_period)
27
+ f = h5py.File(single_period, 'a')
28
+ data = f['raw_data_1']
29
+ tmp = data['detector_1_events']
30
+ N = tmp['period_number'].len()
31
+ zeros = np.zeros(N)
32
+ replace(tmp, 'period_number', zeros, 'int64')
33
+
34
+ tmp = data['periods']
35
+ replace(tmp, 'labels', 'period_1', 'S8')
36
+
37
+ replace(tmp, 'number', 1, 'int32')
38
+ replace(tmp, 'type', [1], 'int32')
39
+ f.close()
40
+ return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: MNeuEventLib
3
- Version: 0.2.1
3
+ Version: 0.3.0
4
4
  Classifier: Programming Language :: Rust
5
5
  Classifier: Programming Language :: Python :: Implementation :: CPython
6
6
  Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -1,4 +1,12 @@
1
1
  # MNeuEventLib
2
+ MNeuEventLib is an event data filtering library for ISIS Neutron and Muon Source.
3
+
4
+ ## Install from PyPI
5
+ MNeuEventLib can be installed as a pre-compiled binary [from PyPI](https://pypi.org/project/MNeuEventLib/) using
6
+ ```
7
+ pip install MNeuEventLib
8
+ ```
9
+
2
10
 
3
11
  ## Build from source
4
12
  MNeuEventLib is built with [`maturin`](https://www.maturin.rs/). Compilation also requires the [`rustup` toolchain](https://rustup.rs/).
@@ -88,7 +88,7 @@
88
88
  "id": "0ca97a00-642c-47c1-b0fd-e2929d3a56a6",
89
89
  "metadata": {},
90
90
  "source": [
91
- "Now, if we calculate our data, we will see in the histogram section of our data that some events have been removed. The full dataset contains 64235 events."
91
+ "Now, if we calculate our data, we will see in the histogram section of our data that some events have been removed. The full dataset contains 64147 events."
92
92
  ]
93
93
  },
94
94
  {
@@ -106,7 +106,7 @@
106
106
  "id": "f76da006-458a-424c-a202-c063407ff1e0",
107
107
  "metadata": {},
108
108
  "source": [
109
- "Now if we change the time filter type to `include` and calculate again, we will exclude all data _except_ that between 0.5 and 1.5 seconds. We'd expect our output histogram to have `64235 - 49115 =` 15120 events, which it does:"
109
+ "Now if we change the time filter type to `include` and calculate again, we will exclude all data _except_ that between 0.5 and 1.5 seconds. We'd expect our output histogram to have `64147 - 49048 =` 15099 events, which it does:"
110
110
  ]
111
111
  },
112
112
  {
@@ -181,7 +181,7 @@
181
181
  "id": "2a2ab3f5-0e76-4cba-a9d5-8949334914d3",
182
182
  "metadata": {},
183
183
  "source": [
184
- "We can see from the output here that this filtered data has 50874 events, as opposed to the full data which had 64235.\n",
184
+ "We can see from the output here that this filtered data has 50804 events, as opposed to the full data which had 64147.\n",
185
185
  "\n",
186
186
  "Note that there are also log filter functions for when you want an unbounded range on one side: \n",
187
187
  "- `add_log_filter_above(name, log, lower)` for above;\n",
@@ -73,6 +73,8 @@
73
73
  "id": "74f13f07-7b5f-42fa-9082-c6976fceb2d1",
74
74
  "metadata": {},
75
75
  "source": [
76
+ " The save method will automatically add any missing meta-data to the file with some default values (typically zero). This will produce a file that is compatable with Mantid. To only use the meta-data in the original event file (i.e. not add any missing data) by setting `autofill=False` as an argument to the save method. This may not load correctly into Mantid. \n",
77
+ "\n",
76
78
  "## Sample log filtering\n",
77
79
  "Converting our event data to a histogram directly is good, but where the event data format really shines is its ability to let us filter out parts of the data that we do not see as relevant. MNeuEventLib allows multiple kinds of filter:\n",
78
80
  "- Filters over **time ranges** ('time filters')\n",
@@ -160,7 +162,7 @@
160
162
  "id": "5793c76f-0513-4d74-b06b-4c87bb3b73d3",
161
163
  "metadata": {},
162
164
  "source": [
163
- "We can see from the output here that this filtered data has 50874 events, as opposed to the full data which had 64235."
165
+ "We can see from the output here that this filtered data has 50804 events, as opposed to the full data which had 64147."
164
166
  ]
165
167
  },
166
168
  {
@@ -0,0 +1 @@
1
+ The `muon_ref.nxs` file provides a template for a complete muon V2 nexus file. This is used when saving to create a file that can be used by Mantid, by adding missing meta-data with default values.
Binary file
@@ -25,4 +25,5 @@ docs = ["ipykernel", "nbsphinx"]
25
25
  [tool.maturin]
26
26
  features = ["pyo3/extension-module"]
27
27
  module-name = "MNeuEventLib.core"
28
+ include = ["files/muon_ref.nxs"]
28
29
  universal2 = true # makes arm64 + x86_64 wheels for mac
@@ -1,11 +1,12 @@
1
+ use crate::data::save::sanitise::nexus_data::{get_period_info, save_default};
2
+ use crate::data::{NexusData, SaveFile, WiMDAFile};
3
+ use crate::filters::Filters;
4
+ use crate::stats::Histogram;
1
5
  use anyhow::{Error, Result};
2
6
  use numpy::{PyArray3, ToPyArray};
3
7
  use pyo3::prelude::{pyclass, pymethods, Borrowed, Bound, FromPyObject, PyAny};
4
8
  use pyo3::types::{PyInt, PyString};
5
-
6
- use crate::data::{NexusData, SaveFile, WiMDAFile};
7
- use crate::filters::Filters;
8
- use crate::stats::Histogram;
9
+ use std::path::PathBuf;
9
10
 
10
11
  pub type PyHist<'py> = Bound<'py, PyArray3<i32>>;
11
12
 
@@ -88,7 +89,7 @@ impl BatchData {
88
89
  Ok(BatchData {
89
90
  dataset,
90
91
  results: (0..n_filter_sets)
91
- .map(|_| Histogram::new(0., 32.768, 2048))
92
+ .map(|_| Histogram::new(0, 32768, 2048))
92
93
  .collect(),
93
94
  filters: (0..n_filter_sets).map(|_| Filters::new()).collect(),
94
95
  data_changed: vec![true; n_filter_sets],
@@ -148,7 +149,8 @@ impl BatchData {
148
149
  }
149
150
  for i in self.resolve_indices(&index)? {
150
151
  self.data_changed[i] = true;
151
- self.results[i] = Histogram::new(min_time, max_time, n_bins);
152
+ self.results[i] =
153
+ Histogram::new((min_time * 1e3) as u32, (max_time * 1e3) as u32, n_bins);
152
154
  }
153
155
  Ok(())
154
156
  }
@@ -351,7 +353,30 @@ impl BatchData {
351
353
  /// an index number will be appended to each filename.
352
354
  /// filename: str
353
355
  /// The filename for the saved file.
354
- pub fn save(&self, index: FilterIndex, filename: String) -> Result<()> {
356
+ /// default: bool
357
+ /// Whether to use default values for the missing meta-data (this is
358
+ /// needed because the event data files has mistakes/problems).
359
+ /// This allows the file to be read by Mantid even if the event file
360
+ /// is incomplete.
361
+ /// autofill: bool
362
+ /// Whether to use automatically fill the file with
363
+ /// default values for the missing meta-data (this is
364
+ /// needed because the event data files have mistakes/problems).
365
+ /// This allows the file to be read by Mantid even if the event file
366
+ /// is incomplete.
367
+ /// ref_file: str
368
+ /// The reference file for the saved file. (must be a Nexus file)
369
+ /// Contains "correct" data that should be copied to the output file.
370
+ /// This is only need it the reference file needed is not the standard
371
+ /// muon nexus v2 file. The ref_file is generated from tools/make_default.py.
372
+ #[pyo3(signature = (index, filename, autofill=true, ref_file = (PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("files/muon_ref.nxs")).display().to_string()))]
373
+ pub fn save(
374
+ &self,
375
+ index: FilterIndex,
376
+ filename: String,
377
+ autofill: bool,
378
+ ref_file: String,
379
+ ) -> Result<()> {
355
380
  let filename_stem = if filename.to_lowercase().ends_with(".nxs") {
356
381
  filename.clone()[..(filename.len() - 4)].to_string()
357
382
  } else {
@@ -367,6 +392,9 @@ impl BatchData {
367
392
  }
368
393
  let wimda_file = WiMDAFile::new(&self.dataset, &self.filters[i], &self.results[i])?;
369
394
  wimda_file.save_file(format!("{filename_stem}.nxs"), &self.dataset.file)?;
395
+ if autofill {
396
+ self.save_nexus(format!("{filename_stem}.nxs"), ref_file.clone())?;
397
+ }
370
398
  }
371
399
  FilterIndex::All => {
372
400
  if self.results.iter().any(|r| r.hist.shape() == [0, 0, 0]) {
@@ -378,6 +406,9 @@ impl BatchData {
378
406
  let wimda_file =
379
407
  WiMDAFile::new(&self.dataset, &self.filters[i], &self.results[i])?;
380
408
  wimda_file.save_file(format!("{filename_stem}_{i}.nxs"), &self.dataset.file)?;
409
+ if autofill {
410
+ self.save_nexus(format!("{filename_stem}_{i}.nxs"), ref_file.clone())?;
411
+ }
381
412
  }
382
413
  }
383
414
  }
@@ -463,6 +494,38 @@ impl BatchData {
463
494
  fn n_batches(&self) -> usize {
464
495
  self.filters.len()
465
496
  }
497
+
498
+ /// Save to a Nexus version 2 file that is compatable with
499
+ /// Mantid using provided reference file for data.
500
+ /// This is needed because the event data files has mistakes/problems.
501
+ ///
502
+ /// Parameters
503
+ /// ----------
504
+ /// filename: str
505
+ /// The filename for the saved file.
506
+ /// ref_file: str
507
+ /// The reference file for the saved file. (must be a Nexus file)
508
+ /// Contains "correct" data that should be copied to the output file.
509
+ /// This is only need it the reference file needed is not the standard
510
+ /// muon nexus v2 file. The ref_file is generated from tools/make_default.py.
511
+ pub fn save_nexus(&self, filename: String, ref_file: String) -> Result<()> {
512
+ // 1. Read p_info from input file
513
+ let (periods, dwell) = get_period_info(&self.dataset.filename)?;
514
+
515
+ // 2. Setup shapes map
516
+ let mut shapes = std::collections::HashMap::new();
517
+ let n = self.dataset.n_spec;
518
+ shapes.insert("N".to_string(), n);
519
+ shapes.insert("P".to_string(), periods);
520
+ shapes.insert("NP".to_string(), n * periods);
521
+ shapes.insert("PD".to_string(), periods + dwell);
522
+ shapes.insert("NPD".to_string(), n * (periods + dwell));
523
+
524
+ // 3. Run save_default to merge/copy from ref_file
525
+ save_default(&filename, &ref_file, &shapes)?;
526
+
527
+ Ok(())
528
+ }
466
529
  }
467
530
 
468
531
  #[cfg(test)]
@@ -479,7 +542,7 @@ mod tests {
479
542
  BatchData {
480
543
  dataset,
481
544
  results: (0..n_filter_sets)
482
- .map(|_| Histogram::new(0., 32.768, 2048))
545
+ .map(|_| Histogram::new(0, 32768, 2048))
483
546
  .collect(),
484
547
  filters: (0..n_filter_sets).map(|_| Filters::new()).collect(),
485
548
  data_changed: vec![true; n_filter_sets],
@@ -0,0 +1,15 @@
1
+ //! Constants.
2
+
3
+ pub const S_TO_NS: f64 = 1e9;
4
+
5
+ pub const NS_TO_US: f32 = 1e-3;
6
+
7
+ pub trait ToMicroseconds {
8
+ fn to_micros(&self) -> f32;
9
+ }
10
+
11
+ impl ToMicroseconds for u32 {
12
+ fn to_micros(&self) -> f32 {
13
+ *self as f32 * NS_TO_US
14
+ }
15
+ }
@@ -6,7 +6,7 @@ mod sample_logs;
6
6
  pub use sample_logs::SampleLog;
7
7
  mod frame_data;
8
8
  pub use frame_data::FrameData;
9
- mod save;
9
+ pub mod save;
10
10
  pub use save::{SaveFile, WiMDAFile};
11
11
 
12
12
  // we use ValueLog in tests to directly create sample logs from arrays
@@ -269,14 +269,16 @@ mod tests {
269
269
  use super::*;
270
270
  use crate::test_utils::MockData;
271
271
 
272
- fn test_data() -> NexusData {
272
+ fn test_data() -> (NexusData, std::sync::MutexGuard<'static, ()>) {
273
+ let guard = crate::test_utils::lock_hdf5_test();
273
274
  let path = Path::new("./tests/test_data/HIFI00195790.nxs");
274
- load_data(path, 64, 1048576).unwrap()
275
+ (load_data(path, 64, 1048576).unwrap(), guard)
275
276
  }
276
277
 
277
278
  /// Test the program creates data when you load an existing file.
278
279
  #[test]
279
280
  fn test_file_load() {
281
+ let _guard = crate::test_utils::lock_hdf5_test();
280
282
  let path = Path::new("./tests/test_data/HIFI00195790.nxs");
281
283
  let data = load_data(path, 64, 1048576);
282
284
 
@@ -294,7 +296,7 @@ mod tests {
294
296
  /// Test the sample log names are correctly loaded in.
295
297
  #[test]
296
298
  fn test_sample_log_names() {
297
- let data = test_data();
299
+ let (data, _guard) = test_data();
298
300
 
299
301
  assert_eq!(data.sample_log_names, vec!("Temp".to_string()))
300
302
  }
@@ -302,7 +304,7 @@ mod tests {
302
304
  /// Test that an existing sample log can be read successfully.
303
305
  #[test]
304
306
  fn test_load_sample_log() {
305
- let data = test_data();
307
+ let (data, _guard) = test_data();
306
308
 
307
309
  let log = data.get_sample_log(&"Temp".to_string());
308
310
  assert!(log.is_ok());
@@ -314,7 +316,7 @@ mod tests {
314
316
  /// Test that a non-real sample log throws an error.
315
317
  #[test]
316
318
  fn test_load_sample_log_not_found() {
317
- let data = test_data();
319
+ let (data, _guard) = test_data();
318
320
 
319
321
  let log = data.get_sample_log(&"Lunch".to_string());
320
322
  assert!(log.is_err())
@@ -357,7 +359,7 @@ mod tests {
357
359
  /// Test that `__repr__` includes the filename.
358
360
  #[test]
359
361
  fn test_repr_includes_filename() {
360
- let data = test_data();
362
+ let (data, _guard) = test_data();
361
363
  let repr = data.__repr__();
362
364
  assert_eq!(
363
365
  repr,