essreduce 25.2.2__tar.gz → 25.2.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 (139) hide show
  1. {essreduce-25.2.2/src/essreduce.egg-info → essreduce-25.2.4}/PKG-INFO +2 -2
  2. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/tof/dream.ipynb +3 -0
  3. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/tof/frame-unwrapping.ipynb +6 -3
  4. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/tof/wfm.ipynb +1 -0
  5. {essreduce-25.2.2 → essreduce-25.2.4}/pyproject.toml +1 -1
  6. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/base.in +1 -1
  7. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/base.txt +26 -5
  8. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/basetest.txt +2 -10
  9. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/ci.txt +0 -6
  10. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/dev.txt +1 -7
  11. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/docs.txt +1 -16
  12. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/nightly.txt +2 -9
  13. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/wheels.txt +0 -2
  14. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/live/raw.py +1 -1
  15. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/nexus/_nexus_loader.py +17 -1
  16. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/nexus/types.py +8 -0
  17. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/nexus/workflow.py +21 -0
  18. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/streaming.py +37 -5
  19. essreduce-25.2.4/src/ess/reduce/time_of_flight/fakes.py +119 -0
  20. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/time_of_flight/toa_to_tof.py +97 -39
  21. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/time_of_flight/types.py +2 -2
  22. {essreduce-25.2.2 → essreduce-25.2.4/src/essreduce.egg-info}/PKG-INFO +2 -2
  23. {essreduce-25.2.2 → essreduce-25.2.4}/src/essreduce.egg-info/requires.txt +1 -1
  24. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/workflow_test.py +30 -0
  25. {essreduce-25.2.2 → essreduce-25.2.4}/tests/streaming_test.py +106 -0
  26. essreduce-25.2.4/tests/time_of_flight/unwrap_test.py +385 -0
  27. {essreduce-25.2.2 → essreduce-25.2.4}/tests/time_of_flight/wfm_test.py +103 -2
  28. essreduce-25.2.2/src/ess/reduce/time_of_flight/fakes.py +0 -222
  29. essreduce-25.2.2/tests/time_of_flight/unwrap_test.py +0 -395
  30. {essreduce-25.2.2 → essreduce-25.2.4}/.copier-answers.ess.yml +0 -0
  31. {essreduce-25.2.2 → essreduce-25.2.4}/.copier-answers.yml +0 -0
  32. {essreduce-25.2.2 → essreduce-25.2.4}/.github/ISSUE_TEMPLATE/blank.md +0 -0
  33. {essreduce-25.2.2 → essreduce-25.2.4}/.github/ISSUE_TEMPLATE/high-level-requirement.yml +0 -0
  34. {essreduce-25.2.2 → essreduce-25.2.4}/.github/dependabot.yml +0 -0
  35. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/ci.yml +0 -0
  36. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/docs.yml +0 -0
  37. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/nightly_at_main.yml +0 -0
  38. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/nightly_at_release.yml +0 -0
  39. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/python-version-ci +0 -0
  40. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/release.yml +0 -0
  41. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/test.yml +0 -0
  42. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/unpinned.yml +0 -0
  43. {essreduce-25.2.2 → essreduce-25.2.4}/.github/workflows/weekly_windows_macos.yml +0 -0
  44. {essreduce-25.2.2 → essreduce-25.2.4}/.gitignore +0 -0
  45. {essreduce-25.2.2 → essreduce-25.2.4}/.pre-commit-config.yaml +0 -0
  46. {essreduce-25.2.2 → essreduce-25.2.4}/.python-version +0 -0
  47. {essreduce-25.2.2 → essreduce-25.2.4}/CODE_OF_CONDUCT.md +0 -0
  48. {essreduce-25.2.2 → essreduce-25.2.4}/CONTRIBUTING.md +0 -0
  49. {essreduce-25.2.2 → essreduce-25.2.4}/LICENSE +0 -0
  50. {essreduce-25.2.2 → essreduce-25.2.4}/MANIFEST.in +0 -0
  51. {essreduce-25.2.2 → essreduce-25.2.4}/README.md +0 -0
  52. {essreduce-25.2.2 → essreduce-25.2.4}/conda/meta.yaml +0 -0
  53. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_static/anaconda-icon.js +0 -0
  54. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_static/favicon.svg +0 -0
  55. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_static/logo-dark.svg +0 -0
  56. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_static/logo.svg +0 -0
  57. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_templates/class-template.rst +0 -0
  58. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_templates/doc_version.html +0 -0
  59. {essreduce-25.2.2 → essreduce-25.2.4}/docs/_templates/module-template.rst +0 -0
  60. {essreduce-25.2.2 → essreduce-25.2.4}/docs/about/index.md +0 -0
  61. {essreduce-25.2.2 → essreduce-25.2.4}/docs/api-reference/index.md +0 -0
  62. {essreduce-25.2.2 → essreduce-25.2.4}/docs/conf.py +0 -0
  63. {essreduce-25.2.2 → essreduce-25.2.4}/docs/developer/coding-conventions.md +0 -0
  64. {essreduce-25.2.2 → essreduce-25.2.4}/docs/developer/dependency-management.md +0 -0
  65. {essreduce-25.2.2 → essreduce-25.2.4}/docs/developer/getting-started.md +0 -0
  66. {essreduce-25.2.2 → essreduce-25.2.4}/docs/developer/gui.ipynb +0 -0
  67. {essreduce-25.2.2 → essreduce-25.2.4}/docs/developer/index.md +0 -0
  68. {essreduce-25.2.2 → essreduce-25.2.4}/docs/index.md +0 -0
  69. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/index.md +0 -0
  70. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/reduction-workflow-guidelines.md +0 -0
  71. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/tof/index.md +0 -0
  72. {essreduce-25.2.2 → essreduce-25.2.4}/docs/user-guide/widget.md +0 -0
  73. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/basetest.in +0 -0
  74. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/ci.in +0 -0
  75. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/dev.in +0 -0
  76. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/docs.in +0 -0
  77. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/make_base.py +0 -0
  78. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/mypy.in +0 -0
  79. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/mypy.txt +0 -0
  80. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/nightly.in +0 -0
  81. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/static.in +0 -0
  82. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/static.txt +0 -0
  83. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/test.in +0 -0
  84. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/test.txt +0 -0
  85. {essreduce-25.2.2 → essreduce-25.2.4}/requirements/wheels.in +0 -0
  86. {essreduce-25.2.2 → essreduce-25.2.4}/resources/logo.svg +0 -0
  87. {essreduce-25.2.2 → essreduce-25.2.4}/setup.cfg +0 -0
  88. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/__init__.py +0 -0
  89. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/data.py +0 -0
  90. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/live/__init__.py +0 -0
  91. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/live/roi.py +0 -0
  92. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/live/workflow.py +0 -0
  93. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/logging.py +0 -0
  94. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/nexus/__init__.py +0 -0
  95. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/nexus/json_generator.py +0 -0
  96. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/nexus/json_nexus.py +0 -0
  97. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/parameter.py +0 -0
  98. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/py.typed +0 -0
  99. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/scripts/grow_nexus.py +0 -0
  100. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/time_of_flight/__init__.py +0 -0
  101. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/time_of_flight/simulation.py +0 -0
  102. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/time_of_flight/to_events.py +0 -0
  103. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/ui.py +0 -0
  104. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/uncertainty.py +0 -0
  105. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/__init__.py +0 -0
  106. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_base.py +0 -0
  107. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_binedges_widget.py +0 -0
  108. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_bounds_widget.py +0 -0
  109. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_config.py +0 -0
  110. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_filename_widget.py +0 -0
  111. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_linspace_widget.py +0 -0
  112. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_optional_widget.py +0 -0
  113. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_spinner.py +0 -0
  114. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_string_widget.py +0 -0
  115. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_switchable_widget.py +0 -0
  116. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/widgets/_vector_widget.py +0 -0
  117. {essreduce-25.2.2 → essreduce-25.2.4}/src/ess/reduce/workflow.py +0 -0
  118. {essreduce-25.2.2 → essreduce-25.2.4}/src/essreduce.egg-info/SOURCES.txt +0 -0
  119. {essreduce-25.2.2 → essreduce-25.2.4}/src/essreduce.egg-info/dependency_links.txt +0 -0
  120. {essreduce-25.2.2 → essreduce-25.2.4}/src/essreduce.egg-info/entry_points.txt +0 -0
  121. {essreduce-25.2.2 → essreduce-25.2.4}/src/essreduce.egg-info/top_level.txt +0 -0
  122. {essreduce-25.2.2 → essreduce-25.2.4}/tests/live/raw_test.py +0 -0
  123. {essreduce-25.2.2 → essreduce-25.2.4}/tests/live/roi_test.py +0 -0
  124. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_generator_test.py +0 -0
  125. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/array_dataset.json +0 -0
  126. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/dataset.json +0 -0
  127. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/detector.json +0 -0
  128. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/entry.json +0 -0
  129. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/event_data.json +0 -0
  130. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/instrument.json +0 -0
  131. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_examples/log.json +0 -0
  132. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/json_nexus_test.py +0 -0
  133. {essreduce-25.2.2 → essreduce-25.2.4}/tests/nexus/nexus_loader_test.py +0 -0
  134. {essreduce-25.2.2 → essreduce-25.2.4}/tests/package_test.py +0 -0
  135. {essreduce-25.2.2 → essreduce-25.2.4}/tests/scripts/test_grow_nexus.py +0 -0
  136. {essreduce-25.2.2 → essreduce-25.2.4}/tests/time_of_flight/to_events_test.py +0 -0
  137. {essreduce-25.2.2 → essreduce-25.2.4}/tests/uncertainty_test.py +0 -0
  138. {essreduce-25.2.2 → essreduce-25.2.4}/tests/widget_test.py +0 -0
  139. {essreduce-25.2.2 → essreduce-25.2.4}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: essreduce
3
- Version: 25.2.2
3
+ Version: 25.2.4
4
4
  Summary: Common data reduction tools for the ESS facility
5
5
  Author: Scipp contributors
6
6
  License: BSD 3-Clause License
@@ -53,7 +53,7 @@ Description-Content-Type: text/markdown
53
53
  License-File: LICENSE
54
54
  Requires-Dist: sciline>=24.06.2
55
55
  Requires-Dist: scipp>=25.01.0
56
- Requires-Dist: scippneutron>=24.11.0
56
+ Requires-Dist: scippneutron>=25.02.0
57
57
  Requires-Dist: scippnexus>=24.11.0
58
58
  Provides-Extra: test
59
59
  Requires-Dist: ipywidgets; extra == "test"
@@ -290,6 +290,7 @@
290
290
  " time_of_flight.providers(), params=time_of_flight.default_parameters()\n",
291
291
  ")\n",
292
292
  "workflow[time_of_flight.RawData] = raw_data\n",
293
+ "workflow[time_of_flight.Ltotal] = Ltotal\n",
293
294
  "workflow[time_of_flight.LtotalRange] = (\n",
294
295
  " sc.scalar(75.5, unit=\"m\"),\n",
295
296
  " sc.scalar(78.0, unit=\"m\"),\n",
@@ -565,6 +566,7 @@
565
566
  "source": [
566
567
  "# Update workflow\n",
567
568
  "workflow[time_of_flight.RawData] = raw_data\n",
569
+ "workflow[time_of_flight.Ltotal] = Ltotal\n",
568
570
  "\n",
569
571
  "# Compute tofs and wavelengths\n",
570
572
  "tofs = workflow.compute(time_of_flight.TofData)\n",
@@ -663,6 +665,7 @@
663
665
  " choppers=disk_choppers, neutrons=2_000_000\n",
664
666
  ")\n",
665
667
  "workflow[time_of_flight.RawData] = ess_beamline.get_monitor(\"detector\")[0]\n",
668
+ "workflow[time_of_flight.Ltotal] = Ltotal\n",
666
669
  "\n",
667
670
  "sim = workflow.compute(time_of_flight.SimulationResults)\n",
668
671
  "\n",
@@ -164,6 +164,7 @@
164
164
  ")\n",
165
165
  "\n",
166
166
  "workflow[time_of_flight.RawData] = nxevent_data\n",
167
+ "workflow[time_of_flight.Ltotal] = nxevent_data.coords[\"Ltotal\"]\n",
167
168
  "workflow[time_of_flight.LtotalRange] = detectors[0].distance, detectors[-1].distance\n",
168
169
  "workflow[time_of_flight.SimulationResults] = time_of_flight.simulate_beamline(\n",
169
170
  " choppers={\n",
@@ -345,7 +346,7 @@
345
346
  "\n",
346
347
  "model = tof.Model(source=source, choppers=choppers, detectors=detectors)\n",
347
348
  "results = model.run()\n",
348
- "results.plot(cmap=\"viridis_r\", blocked_rays=5000)"
349
+ "results.plot(blocked_rays=5000)"
349
350
  ]
350
351
  },
351
352
  {
@@ -372,8 +373,11 @@
372
373
  " time_of_flight.providers(), params=time_of_flight.default_parameters()\n",
373
374
  ")\n",
374
375
  "\n",
376
+ "nxevent_data = results.to_nxevent_data()\n",
377
+ "\n",
375
378
  "workflow[time_of_flight.PulseStride] = 2\n",
376
- "workflow[time_of_flight.RawData] = results.to_nxevent_data()\n",
379
+ "workflow[time_of_flight.RawData] = nxevent_data\n",
380
+ "workflow[time_of_flight.Ltotal] = nxevent_data.coords[\"Ltotal\"]\n",
377
381
  "workflow[time_of_flight.LtotalRange] = detectors[0].distance, detectors[-1].distance\n",
378
382
  "workflow[time_of_flight.SimulationResults] = time_of_flight.simulate_beamline(\n",
379
383
  " choppers={\n",
@@ -391,7 +395,6 @@
391
395
  " )\n",
392
396
  " for ch in choppers\n",
393
397
  " },\n",
394
- " neutrons=500_000,\n",
395
398
  ")\n",
396
399
  "\n",
397
400
  "workflow[time_of_flight.DistanceResolution] = sc.scalar(0.5, unit=\"m\")\n",
@@ -310,6 +310,7 @@
310
310
  " time_of_flight.providers(), params=time_of_flight.default_parameters()\n",
311
311
  ")\n",
312
312
  "workflow[time_of_flight.RawData] = raw_data\n",
313
+ "workflow[time_of_flight.Ltotal] = Ltotal\n",
313
314
  "workflow[time_of_flight.LtotalRange] = Ltotal, Ltotal\n",
314
315
  "workflow[time_of_flight.LookupTableRelativeErrorThreshold] = 0.1\n",
315
316
  "\n",
@@ -33,7 +33,7 @@ requires-python = ">=3.10"
33
33
  dependencies = [
34
34
  "sciline>=24.06.2",
35
35
  "scipp>=25.01.0",
36
- "scippneutron>=24.11.0",
36
+ "scippneutron>=25.02.0",
37
37
  "scippnexus>=24.11.0",
38
38
  ]
39
39
 
@@ -4,5 +4,5 @@
4
4
  # The following was generated by 'tox -e deps', DO NOT EDIT MANUALLY!
5
5
  sciline>=24.06.2
6
6
  scipp>=25.01.0
7
- scippneutron>=24.11.0
7
+ scippneutron>=25.02.0
8
8
  scippnexus>=24.11.0
@@ -1,24 +1,34 @@
1
- # SHA1:d18487328be0c30ec0a6929501d1c4a58c71bd48
1
+ # SHA1:0aac37186f254abb39dbd8f3c3c6ad52bafc0553
2
2
  #
3
3
  # This file is autogenerated by pip-compile-multi
4
4
  # To update, run:
5
5
  #
6
6
  # pip-compile-multi
7
7
  #
8
+ annotated-types==0.7.0
9
+ # via pydantic
8
10
  contourpy==1.3.1
9
11
  # via matplotlib
10
12
  cyclebane==24.10.0
11
13
  # via sciline
12
14
  cycler==0.12.1
13
15
  # via matplotlib
16
+ dnspython==2.7.0
17
+ # via email-validator
18
+ email-validator==2.2.0
19
+ # via scippneutron
14
20
  fonttools==4.56.0
15
21
  # via matplotlib
16
22
  h5py==3.12.1
17
23
  # via
18
24
  # scippneutron
19
25
  # scippnexus
26
+ idna==3.10
27
+ # via email-validator
20
28
  kiwisolver==1.4.8
21
29
  # via matplotlib
30
+ lazy-loader==0.4
31
+ # via scippneutron
22
32
  matplotlib==3.10.0
23
33
  # via
24
34
  # mpltoolbox
@@ -27,7 +37,7 @@ mpltoolbox==24.5.1
27
37
  # via scippneutron
28
38
  networkx==3.4.2
29
39
  # via cyclebane
30
- numpy==2.2.2
40
+ numpy==2.2.3
31
41
  # via
32
42
  # contourpy
33
43
  # h5py
@@ -37,16 +47,23 @@ numpy==2.2.2
37
47
  # scippneutron
38
48
  # scipy
39
49
  packaging==24.2
40
- # via matplotlib
50
+ # via
51
+ # lazy-loader
52
+ # matplotlib
41
53
  pillow==11.1.0
42
54
  # via matplotlib
43
55
  plopp==24.10.0
44
56
  # via scippneutron
57
+ pydantic==2.10.6
58
+ # via scippneutron
59
+ pydantic-core==2.27.2
60
+ # via pydantic
45
61
  pyparsing==3.2.1
46
62
  # via matplotlib
47
63
  python-dateutil==2.9.0.post0
48
64
  # via
49
65
  # matplotlib
66
+ # scippneutron
50
67
  # scippnexus
51
68
  sciline==24.10.0
52
69
  # via -r base.in
@@ -55,15 +72,19 @@ scipp==25.2.0
55
72
  # -r base.in
56
73
  # scippneutron
57
74
  # scippnexus
58
- scippneutron==25.1.0
75
+ scippneutron==25.2.0
59
76
  # via -r base.in
60
77
  scippnexus==24.11.1
61
78
  # via
62
79
  # -r base.in
63
80
  # scippneutron
64
- scipy==1.15.1
81
+ scipy==1.15.2
65
82
  # via
66
83
  # scippneutron
67
84
  # scippnexus
68
85
  six==1.17.0
69
86
  # via python-dateutil
87
+ typing-extensions==4.12.2
88
+ # via
89
+ # pydantic
90
+ # pydantic-core
@@ -19,10 +19,6 @@ cycler==0.12.1
19
19
  # via matplotlib
20
20
  decorator==5.1.1
21
21
  # via ipython
22
- exceptiongroup==1.2.2
23
- # via
24
- # ipython
25
- # pytest
26
22
  executing==2.2.0
27
23
  # via stack-data
28
24
  fonttools==4.56.0
@@ -47,7 +43,7 @@ matplotlib==3.10.0
47
43
  # via plopp
48
44
  matplotlib-inline==0.1.7
49
45
  # via ipython
50
- numpy==2.2.2
46
+ numpy==2.2.3
51
47
  # via
52
48
  # contourpy
53
49
  # matplotlib
@@ -90,7 +86,7 @@ requests==2.32.3
90
86
  # via pooch
91
87
  scipp==25.2.0
92
88
  # via tof
93
- scipy==1.15.1
89
+ scipy==1.15.2
94
90
  # via
95
91
  # -r basetest.in
96
92
  # tof
@@ -100,16 +96,12 @@ stack-data==0.6.3
100
96
  # via ipython
101
97
  tof==25.2.0
102
98
  # via -r basetest.in
103
- tomli==2.2.1
104
- # via pytest
105
99
  traitlets==5.14.3
106
100
  # via
107
101
  # comm
108
102
  # ipython
109
103
  # ipywidgets
110
104
  # matplotlib-inline
111
- typing-extensions==4.12.2
112
- # via ipython
113
105
  urllib3==2.3.0
114
106
  # via requests
115
107
  wcwidth==0.2.13
@@ -44,14 +44,8 @@ requests==2.32.3
44
44
  # via -r ci.in
45
45
  smmap==5.0.2
46
46
  # via gitdb
47
- tomli==2.2.1
48
- # via
49
- # pyproject-api
50
- # tox
51
47
  tox==4.24.1
52
48
  # via -r ci.in
53
- typing-extensions==4.12.2
54
- # via tox
55
49
  urllib3==2.3.0
56
50
  # via requests
57
51
  virtualenv==20.29.2
@@ -12,8 +12,6 @@
12
12
  -r static.txt
13
13
  -r test.txt
14
14
  -r wheels.txt
15
- annotated-types==0.7.0
16
- # via pydantic
17
15
  anyio==4.8.0
18
16
  # via
19
17
  # httpx
@@ -32,7 +30,7 @@ click==8.1.8
32
30
  # via
33
31
  # pip-compile-multi
34
32
  # pip-tools
35
- copier==9.4.1
33
+ copier==9.5.0
36
34
  # via -r dev.in
37
35
  dunamai==1.23.0
38
36
  # via copier
@@ -91,10 +89,6 @@ prometheus-client==0.21.1
91
89
  # via jupyter-server
92
90
  pycparser==2.22
93
91
  # via cffi
94
- pydantic==2.10.6
95
- # via copier
96
- pydantic-core==2.27.2
97
- # via pydantic
98
92
  python-json-logger==3.2.1
99
93
  # via jupyter-events
100
94
  questionary==2.1.0
@@ -10,8 +10,6 @@ accessible-pygments==0.0.5
10
10
  # via pydata-sphinx-theme
11
11
  alabaster==1.0.0
12
12
  # via sphinx
13
- appnope==0.1.4
14
- # via ipykernel
15
13
  asttokens==3.0.0
16
14
  # via stack-data
17
15
  attrs==25.1.0
@@ -48,16 +46,12 @@ docutils==0.21.2
48
46
  # nbsphinx
49
47
  # pydata-sphinx-theme
50
48
  # sphinx
51
- exceptiongroup==1.2.2
52
- # via ipython
53
49
  executing==2.2.0
54
50
  # via stack-data
55
51
  fastjsonschema==2.21.1
56
52
  # via nbformat
57
53
  graphviz==0.20.3
58
54
  # via -r docs.in
59
- idna==3.10
60
- # via requests
61
55
  imagesize==1.4.1
62
56
  # via sphinx
63
57
  importlib-resources==6.5.2
@@ -141,7 +135,7 @@ platformdirs==4.3.6
141
135
  # via jupyter-core
142
136
  prompt-toolkit==3.0.50
143
137
  # via ipython
144
- psutil==6.1.1
138
+ psutil==7.0.0
145
139
  # via ipykernel
146
140
  ptyprocess==0.7.0
147
141
  # via pexpect
@@ -209,8 +203,6 @@ tinycss2==1.4.0
209
203
  # via bleach
210
204
  tof==25.2.0
211
205
  # via -r docs.in
212
- tomli==2.2.1
213
- # via sphinx
214
206
  tornado==6.4.2
215
207
  # via
216
208
  # ipykernel
@@ -228,13 +220,6 @@ traitlets==5.14.3
228
220
  # nbconvert
229
221
  # nbformat
230
222
  # nbsphinx
231
- typing-extensions==4.12.2
232
- # via
233
- # beautifulsoup4
234
- # ipython
235
- # mistune
236
- # pydata-sphinx-theme
237
- # referencing
238
223
  urllib3==2.3.0
239
224
  # via requests
240
225
  wcwidth==0.2.13
@@ -32,10 +32,6 @@ dnspython==2.7.0
32
32
  # via email-validator
33
33
  email-validator==2.2.0
34
34
  # via scippneutron
35
- exceptiongroup==1.2.2
36
- # via
37
- # ipython
38
- # pytest
39
35
  executing==2.2.0
40
36
  # via stack-data
41
37
  fonttools==4.56.0
@@ -74,7 +70,7 @@ mpltoolbox==24.5.1
74
70
  # via scippneutron
75
71
  networkx==3.4.2
76
72
  # via cyclebane
77
- numpy==2.2.2
73
+ numpy==2.2.3
78
74
  # via
79
75
  # contourpy
80
76
  # h5py
@@ -142,7 +138,7 @@ scippnexus @ git+https://github.com/scipp/scippnexus@main
142
138
  # via
143
139
  # -r nightly.in
144
140
  # scippneutron
145
- scipy==1.15.1
141
+ scipy==1.15.2
146
142
  # via
147
143
  # -r nightly.in
148
144
  # scippneutron
@@ -154,8 +150,6 @@ stack-data==0.6.3
154
150
  # via ipython
155
151
  tof @ git+https://github.com/scipp/tof@main
156
152
  # via -r nightly.in
157
- tomli==2.2.1
158
- # via pytest
159
153
  traitlets==5.14.3
160
154
  # via
161
155
  # comm
@@ -164,7 +158,6 @@ traitlets==5.14.3
164
158
  # matplotlib-inline
165
159
  typing-extensions==4.12.2
166
160
  # via
167
- # ipython
168
161
  # pydantic
169
162
  # pydantic-core
170
163
  urllib3==2.3.0
@@ -11,5 +11,3 @@ packaging==24.2
11
11
  # via build
12
12
  pyproject-hooks==1.2.0
13
13
  # via build
14
- tomli==2.2.1
15
- # via build
@@ -639,7 +639,7 @@ def position_with_noisy_replicas(
639
639
  # "Paint" the short array of noise on top of the (replicated) position data.
640
640
  noise = sc.concat(
641
641
  [position_noise] * ceil(size / position_noise.size), dim=noise_dim
642
- )[:size].fold(dim=noise_dim, sizes={'replica': replicas, position.dim: -1})
642
+ )[:size].fold(dim=noise_dim, sizes={'replica': replicas, **position.sizes})
643
643
  return sc.concat([position, noise + position], dim='replica')
644
644
 
645
645
 
@@ -8,14 +8,16 @@ from collections.abc import Generator, Mapping
8
8
  from contextlib import AbstractContextManager, contextmanager, nullcontext
9
9
  from dataclasses import dataclass
10
10
  from math import prod
11
- from typing import cast
11
+ from typing import TypeVar, cast
12
12
 
13
13
  import scipp as sc
14
14
  import scippnexus as snx
15
15
 
16
16
  from ..logging import get_logger
17
17
  from .types import (
18
+ Beamline,
18
19
  FilePath,
20
+ Measurement,
19
21
  NeXusAllLocationSpec,
20
22
  NeXusEntryName,
21
23
  NeXusFile,
@@ -27,6 +29,8 @@ from .types import (
27
29
  class NoNewDefinitionsType: ...
28
30
 
29
31
 
32
+ _Model = TypeVar('_Model', Beamline, Measurement)
33
+
30
34
  NoNewDefinitions = NoNewDefinitionsType()
31
35
 
32
36
 
@@ -74,6 +78,18 @@ def load_all_components(
74
78
  return components
75
79
 
76
80
 
81
+ def load_metadata(
82
+ file_path: FilePath | NeXusFile | NeXusGroup,
83
+ model: type[_Model],
84
+ *,
85
+ entry_name: NeXusEntryName | None = None,
86
+ definitions: Mapping | NoNewDefinitionsType = NoNewDefinitions,
87
+ ) -> _Model:
88
+ with _open_nexus_file(file_path, definitions=definitions) as f:
89
+ entry = _unique_child_group(f, snx.NXentry, entry_name)
90
+ return model.from_nexus_entry(entry)
91
+
92
+
77
93
  def compute_component_position(dg: sc.DataGroup) -> sc.DataGroup:
78
94
  # In some downstream packages we use some of the Nexus components which attempt
79
95
  # to compute positions without having actual Nexus data defining depends_on chains.
@@ -7,6 +7,7 @@ from typing import Any, BinaryIO, Generic, NewType, TypeVar
7
7
  import sciline
8
8
  import scipp as sc
9
9
  import scippnexus as snx
10
+ from scippneutron import metadata as scn_meta
10
11
 
11
12
  FilePath = NewType('FilePath', Path)
12
13
  """Full path to a NeXus file on disk."""
@@ -177,6 +178,13 @@ Component = TypeVar(
177
178
  UniqueComponent = TypeVar('UniqueComponent', snx.NXsample, snx.NXsource)
178
179
  """Components that can be identified by their type as there will only be one."""
179
180
 
181
+ Beamline = scn_meta.Beamline
182
+ """Beamline metadata."""
183
+ Measurement = scn_meta.Measurement
184
+ """measurement metadata."""
185
+ Source = scn_meta.Source
186
+ """Neutron source metadata."""
187
+
180
188
 
181
189
  class NeXusName(sciline.Scope[Component, str], str):
182
190
  """Name of a component in a NeXus file."""
@@ -19,6 +19,7 @@ from . import _nexus_loader as nexus
19
19
  from .types import (
20
20
  AllNeXusComponents,
21
21
  Analyzers,
22
+ Beamline,
22
23
  CalibratedBeamline,
23
24
  CalibratedDetector,
24
25
  CalibratedMonitor,
@@ -29,6 +30,7 @@ from .types import (
29
30
  DetectorPositionOffset,
30
31
  Filename,
31
32
  GravityVector,
33
+ Measurement,
32
34
  MonitorData,
33
35
  MonitorPositionOffset,
34
36
  MonitorType,
@@ -45,6 +47,7 @@ from .types import (
45
47
  Position,
46
48
  PreopenNeXusFile,
47
49
  RunType,
50
+ SampleRun,
48
51
  TimeInterval,
49
52
  UniqueComponent,
50
53
  )
@@ -586,6 +589,18 @@ def _add_variances(da: sc.DataArray) -> sc.DataArray:
586
589
  return out
587
590
 
588
591
 
592
+ def load_beamline_metadata_from_nexus(file_spec: NeXusFileSpec[SampleRun]) -> Beamline:
593
+ """Load beamline metadata from a sample NeXus file."""
594
+ return nexus.load_metadata(file_spec.value, Beamline)
595
+
596
+
597
+ def load_measurement_metadata_from_nexus(
598
+ file_spec: NeXusFileSpec[SampleRun],
599
+ ) -> Measurement:
600
+ """Load measurement metadata from a sample NeXus file."""
601
+ return nexus.load_metadata(file_spec.value, Measurement)
602
+
603
+
589
604
  definitions = snx.base_definitions()
590
605
  definitions["NXdetector"] = _StrippedDetector
591
606
  definitions["NXmonitor"] = _StrippedMonitor
@@ -631,6 +646,11 @@ _chopper_providers = (parse_disk_choppers,)
631
646
 
632
647
  _analyzer_providers = (parse_analyzers,)
633
648
 
649
+ _metadata_providers = (
650
+ load_beamline_metadata_from_nexus,
651
+ load_measurement_metadata_from_nexus,
652
+ )
653
+
634
654
 
635
655
  def LoadMonitorWorkflow() -> sciline.Pipeline:
636
656
  """Generic workflow for loading monitor data from a NeXus file."""
@@ -689,6 +709,7 @@ def GenericNeXusWorkflow(
689
709
  *_detector_providers,
690
710
  *_chopper_providers,
691
711
  *_analyzer_providers,
712
+ *_metadata_providers,
692
713
  )
693
714
  )
694
715
  wf[DetectorBankSizes] = DetectorBankSizes({})
@@ -147,7 +147,7 @@ class StreamProcessor:
147
147
  *,
148
148
  dynamic_keys: tuple[sciline.typing.Key, ...],
149
149
  target_keys: tuple[sciline.typing.Key, ...],
150
- accumulators: dict[sciline.typing.Key, Accumulator, Callable[..., Accumulator]]
150
+ accumulators: dict[sciline.typing.Key, Accumulator | Callable[..., Accumulator]]
151
151
  | tuple[sciline.typing.Key, ...],
152
152
  allow_bypass: bool = False,
153
153
  ) -> None:
@@ -180,6 +180,8 @@ class StreamProcessor:
180
180
  for key in dynamic_keys:
181
181
  workflow[key] = None # hack to prune branches
182
182
 
183
+ self._dynamic_keys = set(dynamic_keys)
184
+
183
185
  # Find and pre-compute static nodes as far down the graph as possible
184
186
  # See also https://github.com/scipp/sciline/issues/148.
185
187
  nodes = _find_descendants(workflow, dynamic_keys)
@@ -194,12 +196,19 @@ class StreamProcessor:
194
196
  if isinstance(accumulators, dict)
195
197
  else {key: EternalAccumulator() for key in accumulators}
196
198
  )
199
+
200
+ # Map each accumulator to its dependent dynamic keys
201
+ graph = workflow.underlying_graph
202
+ self._accumulator_dependencies = {
203
+ acc_key: nx.ancestors(graph, acc_key) & self._dynamic_keys
204
+ for acc_key in self._accumulators
205
+ if acc_key in graph
206
+ }
207
+
197
208
  # Depending on the target_keys, some accumulators can be unused and should not
198
209
  # be computed when adding a chunk.
199
210
  self._accumulators = {
200
- key: value
201
- for key, value in self._accumulators.items()
202
- if key in self._process_chunk_workflow.underlying_graph
211
+ key: value for key, value in self._accumulators.items() if key in graph
203
212
  }
204
213
  # Create accumulators unless instances were passed. This allows for initializing
205
214
  # accumulators with arguments that depend on the workflow such as bin edges,
@@ -242,7 +251,30 @@ class StreamProcessor:
242
251
  ----------
243
252
  chunks:
244
253
  Chunks to be processed.
254
+
255
+ Raises
256
+ ------
257
+ ValueError
258
+ If non-dynamic keys are provided in chunks.
259
+ If accumulator computation requires dynamic keys not provided in chunks.
245
260
  """
261
+ non_dynamic = set(chunks) - self._dynamic_keys
262
+ if non_dynamic:
263
+ raise ValueError(
264
+ f"Can only update dynamic keys. Got non-dynamic keys: {non_dynamic}"
265
+ )
266
+
267
+ accumulators_to_update = []
268
+ for acc_key, deps in self._accumulator_dependencies.items():
269
+ if deps.isdisjoint(chunks.keys()):
270
+ continue
271
+ if not deps.issubset(chunks.keys()):
272
+ raise ValueError(
273
+ f"Accumulator '{acc_key}' requires dynamic keys "
274
+ f"{deps - chunks.keys()} not provided in the current chunk."
275
+ )
276
+ accumulators_to_update.append(acc_key)
277
+
246
278
  for key, value in chunks.items():
247
279
  self._process_chunk_workflow[key] = value
248
280
  # There can be dynamic keys that do not "terminate" in any accumulator. In
@@ -250,7 +282,7 @@ class StreamProcessor:
250
282
  # the target keys.
251
283
  if self._allow_bypass:
252
284
  self._finalize_workflow[key] = value
253
- to_accumulate = self._process_chunk_workflow.compute(self._accumulators)
285
+ to_accumulate = self._process_chunk_workflow.compute(accumulators_to_update)
254
286
  for key, processed in to_accumulate.items():
255
287
  self._accumulators[key].push(processed)
256
288