From 89a34285ba905c5595ae0a6ed4c1b01e95e7d7e9 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Mon, 11 Sep 2023 15:09:34 +0200 Subject: [PATCH 01/14] Add dream.load_geant4_csv --- src/ess/dream/__init__.py | 4 ++ src/ess/dream/io/__init__.py | 6 +++ src/ess/dream/io/geant4.py | 71 ++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/ess/dream/io/__init__.py create mode 100644 src/ess/dream/io/geant4.py diff --git a/src/ess/dream/__init__.py b/src/ess/dream/__init__.py index df1769802..a16679849 100644 --- a/src/ess/dream/__init__.py +++ b/src/ess/dream/__init__.py @@ -1,2 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) + +from .io import load_geant4_csv + +__all__ = ['load_geant4_csv'] diff --git a/src/ess/dream/io/__init__.py b/src/ess/dream/io/__init__.py new file mode 100644 index 000000000..fbc9cfe76 --- /dev/null +++ b/src/ess/dream/io/__init__.py @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) + +from .geant4 import load_geant4_csv + +__all__ = ['load_geant4_csv'] diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py new file mode 100644 index 000000000..2222cc7b8 --- /dev/null +++ b/src/ess/dream/io/geant4.py @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) + +import os +from typing import Dict, Union + +import scipp as sc + +MANTLE_DETECTOR_ID = sc.index(7) +HIGH_RES_DETECTOR_ID = sc.index(8) +ENDCAPS_DETECTOR_IDS = tuple(map(sc.index, (3, 4, 5, 6))) + + +def load_geant4_csv(filename: Union[str, os.PathLike]) -> sc.DataGroup: + """Load a GEANT4 CSV file for DREAM. + + Parameters + ---------- + filename: + Path to the GEANT4 CSV file. + + Returns + ------- + : + A :class:`scipp.DataGroup` containing the loaded events. + """ + events = _load_raw_events(filename) + detectors = _split_detectors(events) + for det in detectors.values(): + _adjust_coords(det) + + dg = sc.DataGroup({'instrument': sc.DataGroup(detectors)}) + return _group(dg) + + +def _load_raw_events(filename: Union[str, os.PathLike]) -> sc.DataArray: + table = sc.io.load_csv(filename, sep='\t', header_parser='bracket', data_columns=[]) + table = table.rename_dims(row='event') + return sc.DataArray(sc.ones(sizes=table.sizes), coords=table.coords) + + +def _adjust_coords(da: sc.DataArray) -> None: + da.coords['wavelength'] = da.coords['lambda'] + da.coords['position'] = sc.spatial.as_vectors( + da.coords['x_pos'], da.coords['y_pos'], da.coords['z_pos'] + ) + + +def _group(dg: sc.DataGroup) -> sc.DataGroup: + return dg.group('counter', 'segment', 'module', 'strip', 'wire') + + +def _split_detectors( + data: sc.DataArray, detector_id_name: str = 'det ID' +) -> Dict[str, sc.DataArray]: + groups = data.group(detector_id_name) + mantle = groups[detector_id_name, MANTLE_DETECTOR_ID].value + high_res = groups[detector_id_name, HIGH_RES_DETECTOR_ID].value + + endcaps = sc.concat( + [groups[detector_id_name, i].value for i in ENDCAPS_DETECTOR_IDS], data.dim + ) + endcap_forward = endcaps[endcaps.coords['z_pos'] > sc.scalar(0, unit='mm')] + endcap_backward = endcaps[endcaps.coords['z_pos'] < sc.scalar(0, unit='mm')] + + return { + 'mantle': mantle.copy(), + 'high_resolution': high_res.copy(), + 'endcap_forward': endcap_forward.copy(), + 'endcap_backward': endcap_backward.copy(), + } From f16077ce96bb6fcdc362ad1f31fcb0fe50de2637 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Mon, 11 Sep 2023 15:26:59 +0200 Subject: [PATCH 02/14] Skip detector if not in file --- src/ess/dream/io/geant4.py | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index 2222cc7b8..df8f82919 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import os -from typing import Dict, Union +from typing import Dict, Optional, Union import scipp as sc @@ -54,18 +54,36 @@ def _split_detectors( data: sc.DataArray, detector_id_name: str = 'det ID' ) -> Dict[str, sc.DataArray]: groups = data.group(detector_id_name) - mantle = groups[detector_id_name, MANTLE_DETECTOR_ID].value - high_res = groups[detector_id_name, HIGH_RES_DETECTOR_ID].value - - endcaps = sc.concat( - [groups[detector_id_name, i].value for i in ENDCAPS_DETECTOR_IDS], data.dim - ) - endcap_forward = endcaps[endcaps.coords['z_pos'] > sc.scalar(0, unit='mm')] - endcap_backward = endcaps[endcaps.coords['z_pos'] < sc.scalar(0, unit='mm')] + mantle = _extract_detector(groups, detector_id_name, MANTLE_DETECTOR_ID) + high_res = _extract_detector(groups, detector_id_name, HIGH_RES_DETECTOR_ID) + + endcaps_list = [ + det + for i in ENDCAPS_DETECTOR_IDS + if (det := _extract_detector(groups, detector_id_name, i)) is not None + ] + if endcaps_list: + endcaps = sc.concat(endcaps_list, data.dim) + endcap_forward = endcaps[endcaps.coords['z_pos'] > sc.scalar(0, unit='mm')] + endcap_backward = endcaps[endcaps.coords['z_pos'] < sc.scalar(0, unit='mm')] + else: + endcap_forward = None + endcap_backward = None return { - 'mantle': mantle.copy(), - 'high_resolution': high_res.copy(), - 'endcap_forward': endcap_forward.copy(), - 'endcap_backward': endcap_backward.copy(), + key: val + for key, val in zip( + ('mantle', 'high_resolution', 'endcap_forward', 'endcap_backward'), + (mantle, high_res, endcap_forward, endcap_backward), + ) + if val is not None } + + +def _extract_detector( + detector_groups: sc.DataArray, detector_id_name: str, detector_id: sc.Variable +) -> Optional[sc.DataArray]: + try: + return detector_groups[detector_id_name, detector_id].value.copy() + except IndexError: + return None From f08447cb465130afdea54889bc6c0229ce315c0f Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 14 Sep 2023 09:30:22 +0200 Subject: [PATCH 03/14] Drop processed coords --- src/ess/dream/io/geant4.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index df8f82919..dd234d65c 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -40,9 +40,9 @@ def _load_raw_events(filename: Union[str, os.PathLike]) -> sc.DataArray: def _adjust_coords(da: sc.DataArray) -> None: - da.coords['wavelength'] = da.coords['lambda'] + da.coords['wavelength'] = da.coords.pop('lambda') da.coords['position'] = sc.spatial.as_vectors( - da.coords['x_pos'], da.coords['y_pos'], da.coords['z_pos'] + da.coords.pop('x_pos'), da.coords.pop('y_pos'), da.coords.pop('z_pos') ) From f081b348423ac92576d4ce16099a76e8a6cd3074 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 14 Sep 2023 09:37:35 +0200 Subject: [PATCH 04/14] Group using known indices --- src/ess/dream/io/geant4.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index dd234d65c..349f3f36b 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -53,7 +53,12 @@ def _group(dg: sc.DataGroup) -> sc.DataGroup: def _split_detectors( data: sc.DataArray, detector_id_name: str = 'det ID' ) -> Dict[str, sc.DataArray]: - groups = data.group(detector_id_name) + groups = data.group( + sc.concat( + [MANTLE_DETECTOR_ID, HIGH_RES_DETECTOR_ID, *ENDCAPS_DETECTOR_IDS], + dim=detector_id_name, + ) + ) mantle = _extract_detector(groups, detector_id_name, MANTLE_DETECTOR_ID) high_res = _extract_detector(groups, detector_id_name, HIGH_RES_DETECTOR_ID) From fe85d36f5f125ef9776bd21b6403afef1d4fcaa6 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 14 Sep 2023 09:40:45 +0200 Subject: [PATCH 05/14] Avoid extra copy --- src/ess/dream/io/geant4.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index 349f3f36b..c90d054e9 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -59,8 +59,8 @@ def _split_detectors( dim=detector_id_name, ) ) - mantle = _extract_detector(groups, detector_id_name, MANTLE_DETECTOR_ID) - high_res = _extract_detector(groups, detector_id_name, HIGH_RES_DETECTOR_ID) + mantle = _extract_detector(groups, detector_id_name, MANTLE_DETECTOR_ID).copy() + high_res = _extract_detector(groups, detector_id_name, HIGH_RES_DETECTOR_ID).copy() endcaps_list = [ det @@ -89,6 +89,6 @@ def _extract_detector( detector_groups: sc.DataArray, detector_id_name: str, detector_id: sc.Variable ) -> Optional[sc.DataArray]: try: - return detector_groups[detector_id_name, detector_id].value.copy() + return detector_groups[detector_id_name, detector_id].value except IndexError: return None From 5bc9550fefdd2bd780001f6385ade114e8188a51 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 14 Sep 2023 10:05:48 +0200 Subject: [PATCH 06/14] Build dict piecewise --- src/ess/dream/io/geant4.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index c90d054e9..e658323c8 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -59,8 +59,15 @@ def _split_detectors( dim=detector_id_name, ) ) - mantle = _extract_detector(groups, detector_id_name, MANTLE_DETECTOR_ID).copy() - high_res = _extract_detector(groups, detector_id_name, HIGH_RES_DETECTOR_ID).copy() + detectors = {} + if ( + mantle := _extract_detector(groups, detector_id_name, MANTLE_DETECTOR_ID) + ) is not None: + detectors['mantle'] = mantle.copy() + if ( + high_res := _extract_detector(groups, detector_id_name, HIGH_RES_DETECTOR_ID) + ) is not None: + detectors['high_resolution'] = high_res.copy() endcaps_list = [ det @@ -69,20 +76,14 @@ def _split_detectors( ] if endcaps_list: endcaps = sc.concat(endcaps_list, data.dim) - endcap_forward = endcaps[endcaps.coords['z_pos'] > sc.scalar(0, unit='mm')] - endcap_backward = endcaps[endcaps.coords['z_pos'] < sc.scalar(0, unit='mm')] - else: - endcap_forward = None - endcap_backward = None - - return { - key: val - for key, val in zip( - ('mantle', 'high_resolution', 'endcap_forward', 'endcap_backward'), - (mantle, high_res, endcap_forward, endcap_backward), - ) - if val is not None - } + detectors['endcap_forward'] = endcaps[ + endcaps.coords['z_pos'] > sc.scalar(0, unit='mm') + ] + detectors['endcap_backward'] = endcaps[ + endcaps.coords['z_pos'] < sc.scalar(0, unit='mm') + ] + + return detectors def _extract_detector( From 4840594f801602f92ec4a68a0752209f4b42360a Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 15 Sep 2023 14:15:18 +0200 Subject: [PATCH 07/14] Use binning to split endcaps --- src/ess/dream/io/geant4.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index e658323c8..5c6f719f2 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -4,6 +4,7 @@ import os from typing import Dict, Optional, Union +import numpy as np import scipp as sc MANTLE_DETECTOR_ID = sc.index(7) @@ -76,12 +77,15 @@ def _split_detectors( ] if endcaps_list: endcaps = sc.concat(endcaps_list, data.dim) - detectors['endcap_forward'] = endcaps[ - endcaps.coords['z_pos'] > sc.scalar(0, unit='mm') - ] - detectors['endcap_backward'] = endcaps[ - endcaps.coords['z_pos'] < sc.scalar(0, unit='mm') - ] + endcaps = endcaps.bin( + z_pos=sc.array( + dims=['z_pos'], + values=[-np.inf, 0.0, np.inf], + unit=endcaps.coords['z_pos'].unit, + ) + ) + detectors['endcap_backward'] = endcaps[0].bins.concat().value.copy() + detectors['endcap_forward'] = endcaps[1].bins.concat().value.copy() return detectors From e0a95cc0d4f5d8a0b55f9a5101f2ab0a1217ef05 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Wed, 27 Sep 2023 15:19:26 +0200 Subject: [PATCH 08/14] Group into sectors as well --- src/ess/dream/io/geant4.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index 5c6f719f2..3925c16b5 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -29,9 +29,9 @@ def load_geant4_csv(filename: Union[str, os.PathLike]) -> sc.DataGroup: detectors = _split_detectors(events) for det in detectors.values(): _adjust_coords(det) + detectors = _group(detectors) - dg = sc.DataGroup({'instrument': sc.DataGroup(detectors)}) - return _group(dg) + return sc.DataGroup({'instrument': sc.DataGroup(detectors)}) def _load_raw_events(filename: Union[str, os.PathLike]) -> sc.DataArray: @@ -47,8 +47,15 @@ def _adjust_coords(da: sc.DataArray) -> None: ) -def _group(dg: sc.DataGroup) -> sc.DataGroup: - return dg.group('counter', 'segment', 'module', 'strip', 'wire') +def _group(detectors: Dict[str, sc.DataArray]) -> Dict[str, sc.DataArray]: + # Only the HR detector has sectors. + elements = ('module', 'segment', 'counter', 'wire', 'strip') + return { + key: da.group('sector', *elements) + if key == 'high_resolution' + else da.group(*elements) + for key, da in detectors.items() + } def _split_detectors( From fb5972da1d452d202684cb6997865c6ce9650a64 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 28 Sep 2023 10:34:55 +0200 Subject: [PATCH 09/14] Drop sector coord when unused --- src/ess/dream/io/geant4.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index 3925c16b5..fd3454275 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -48,14 +48,17 @@ def _adjust_coords(da: sc.DataArray) -> None: def _group(detectors: Dict[str, sc.DataArray]) -> Dict[str, sc.DataArray]: - # Only the HR detector has sectors. elements = ('module', 'segment', 'counter', 'wire', 'strip') - return { - key: da.group('sector', *elements) - if key == 'high_resolution' - else da.group(*elements) - for key, da in detectors.items() - } + + def group(key: str, da: sc.DataArray) -> sc.DataArray: + if key == 'high_resolution': + # Only the HR detector has sectors. + return da.group('sector', *elements) + res = da.group(*elements) + res.bins.coords.pop('sector', None) + return res + + return {key: group(key, da) for key, da in detectors.items()} def _split_detectors( From a454f47ea367fb91bd3fb6e43d2eba4edf1816e2 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 28 Sep 2023 10:35:06 +0200 Subject: [PATCH 10/14] Add data module for dream --- src/ess/dream/__init__.py | 3 ++- src/ess/dream/data.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/ess/dream/data.py diff --git a/src/ess/dream/__init__.py b/src/ess/dream/__init__.py index a16679849..58b200d15 100644 --- a/src/ess/dream/__init__.py +++ b/src/ess/dream/__init__.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +from . import data from .io import load_geant4_csv -__all__ = ['load_geant4_csv'] +__all__ = ['data', 'load_geant4_csv'] diff --git a/src/ess/dream/data.py b/src/ess/dream/data.py new file mode 100644 index 000000000..cf9f0a1e3 --- /dev/null +++ b/src/ess/dream/data.py @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +_version = '1' + +__all__ = ['get_path'] + + +def _make_pooch(): + import pooch + + return pooch.create( + path=pooch.os_cache('ess/dream'), + env='ESS_DREAM_DATA_DIR', + base_url='https://public.esss.dk/groups/scipp/ess/dream/{version}/', + version=_version, + registry={ + 'data_dream_with_sectors.csv.zip': 'md5:52ae6eb3705e5e54306a001bc0ae85d8', + }, + ) + + +_pooch = _make_pooch() + + +def get_path(name: str) -> str: + """ + Return the path to a data file bundled with scippneutron. + + This function only works with example data and cannot handle + paths to custom files. + """ + return _pooch.fetch(name) From c537be338506d27ca3cc48056762297c02feff13 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 28 Sep 2023 10:35:22 +0200 Subject: [PATCH 11/14] Add tests for dream.load_geant4_csv --- tests/dream/__init__.py | 0 tests/dream/io/__init__.py | 0 tests/dream/io/geant4_test.py | 114 ++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+) create mode 100644 tests/dream/__init__.py create mode 100644 tests/dream/io/__init__.py create mode 100644 tests/dream/io/geant4_test.py diff --git a/tests/dream/__init__.py b/tests/dream/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/dream/io/__init__.py b/tests/dream/io/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/dream/io/geant4_test.py b/tests/dream/io/geant4_test.py new file mode 100644 index 000000000..0b109a0e4 --- /dev/null +++ b/tests/dream/io/geant4_test.py @@ -0,0 +1,114 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2023 Scipp contributors (https://github.com/scipp) + +import zipfile +from io import BytesIO +from typing import Optional, Set + +import numpy as np +import pytest +import scipp as sc + +from ess.dream import data, load_geant4_csv + + +@pytest.fixture(scope='module') +def file_path(): + return data.get_path('data_dream_with_sectors.csv.zip') + + +# Load file into memory only once +@pytest.fixture(scope='module') +def load_file(file_path): + with zipfile.ZipFile(file_path, 'r') as archive: + return archive.read(archive.namelist()[0]) + + +@pytest.fixture(scope='function') +def file(load_file): + return BytesIO(load_file) + + +def assert_index_coord( + coord: sc.Variable, *, values: Optional[Set[int]] = None +) -> None: + assert coord.ndim == 1 + assert coord.unit is None + assert coord.dtype == 'int64' + if values is not None: + assert set(np.unique(coord.values)) == values + + +def test_load_geant4_csv_loads_expected_structure(file): + loaded = load_geant4_csv(file) + assert isinstance(loaded, sc.DataGroup) + assert loaded.keys() == {'instrument'} + + instrument = loaded['instrument'] + assert isinstance(instrument, sc.DataGroup) + assert instrument.keys() == { + 'mantle', + 'high_resolution', + 'endcap_forward', + 'endcap_backward', + } + + +def test_load_geant4_csv_mantle_has_expected_coords(file): + # Only testing ranges that will not change in the future + mantle = load_geant4_csv(file)['instrument']['mantle'] + assert_index_coord(mantle.coords['module']) + assert_index_coord(mantle.coords['segment']) + assert_index_coord(mantle.coords['counter']) + assert_index_coord(mantle.coords['wire'], values=set(range(1, 33))) + assert_index_coord(mantle.coords['strip'], values=set(range(1, 257))) + assert 'sector' not in mantle.coords + + assert 'sector' not in mantle.bins.coords + assert 'tof' in mantle.bins.coords + assert 'wavelength' in mantle.bins.coords + assert 'position' in mantle.bins.coords + + +def test_load_geant4_csv_endcap_backward_has_expected_coords(file): + endcap = load_geant4_csv(file)['instrument']['endcap_backward'] + assert_index_coord(endcap.coords['module']) + assert_index_coord(endcap.coords['segment']) + assert_index_coord(endcap.coords['counter']) + assert_index_coord(endcap.coords['wire'], values=set(range(1, 17))) + assert_index_coord(endcap.coords['strip'], values=set(range(1, 17))) + assert 'sector' not in endcap.coords + + assert 'sector' not in endcap.bins.coords + assert 'tof' in endcap.bins.coords + assert 'wavelength' in endcap.bins.coords + assert 'position' in endcap.bins.coords + + +def test_load_geant4_csv_endcap_forward_has_expected_coords(file): + endcap = load_geant4_csv(file)['instrument']['endcap_forward'] + assert_index_coord(endcap.coords['module']) + assert_index_coord(endcap.coords['segment']) + assert_index_coord(endcap.coords['counter']) + assert_index_coord(endcap.coords['wire'], values=set(range(1, 17))) + assert_index_coord(endcap.coords['strip'], values=set(range(1, 17))) + assert 'sector' not in endcap.coords + + assert 'sector' not in endcap.bins.coords + assert 'tof' in endcap.bins.coords + assert 'wavelength' in endcap.bins.coords + assert 'position' in endcap.bins.coords + + +def test_load_geant4_csv_high_resolution_has_expected_coords(file): + hr = load_geant4_csv(file)['instrument']['high_resolution'] + assert_index_coord(hr.coords['module']) + assert_index_coord(hr.coords['segment']) + assert_index_coord(hr.coords['counter']) + assert_index_coord(hr.coords['wire'], values=set(range(1, 17))) + assert_index_coord(hr.coords['strip'], values=set(range(1, 33))) + assert_index_coord(hr.coords['sector'], values=set(range(1, 5))) + + assert 'tof' in hr.bins.coords + assert 'wavelength' in hr.bins.coords + assert 'position' in hr.bins.coords From 5d714cb9ec7317a30f6030bccb78cbb3e44162c3 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 28 Sep 2023 10:38:19 +0200 Subject: [PATCH 12/14] Add StringIO, BytesIO to type hint --- src/ess/dream/io/geant4.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index fd3454275..e5ce6629f 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -2,6 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import os +from io import BytesIO, StringIO from typing import Dict, Optional, Union import numpy as np @@ -12,7 +13,9 @@ ENDCAPS_DETECTOR_IDS = tuple(map(sc.index, (3, 4, 5, 6))) -def load_geant4_csv(filename: Union[str, os.PathLike]) -> sc.DataGroup: +def load_geant4_csv( + filename: Union[str, os.PathLike, StringIO, BytesIO] +) -> sc.DataGroup: """Load a GEANT4 CSV file for DREAM. Parameters @@ -34,7 +37,9 @@ def load_geant4_csv(filename: Union[str, os.PathLike]) -> sc.DataGroup: return sc.DataGroup({'instrument': sc.DataGroup(detectors)}) -def _load_raw_events(filename: Union[str, os.PathLike]) -> sc.DataArray: +def _load_raw_events( + filename: Union[str, os.PathLike, StringIO, BytesIO] +) -> sc.DataArray: table = sc.io.load_csv(filename, sep='\t', header_parser='bracket', data_columns=[]) table = table.rename_dims(row='event') return sc.DataArray(sc.ones(sizes=table.sizes), coords=table.coords) From 9b458bb6fd74df3274209038600cd4b9c29e5c4c Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Thu, 28 Sep 2023 10:48:17 +0200 Subject: [PATCH 13/14] Add pandas to ci env --- environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.yml b/environment.yml index f8fb774c0..5fc1cdf22 100644 --- a/environment.yml +++ b/environment.yml @@ -17,6 +17,7 @@ dependencies: - ipykernel==6.25.1 - ipywidgets==8.1.0 - nbsphinx=0.9.2 + - pandas=2.0.3 - pandoc=3.1.3 - pip=23.2.1 - plopp=23.09.0 From cb010a51fd94958dc02a8fd43fd25602005bc1cb Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Mon, 2 Oct 2023 12:54:17 +0200 Subject: [PATCH 14/14] Set variances and unit of events --- src/ess/dream/io/geant4.py | 5 ++++- tests/dream/io/geant4_test.py | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ess/dream/io/geant4.py b/src/ess/dream/io/geant4.py index e5ce6629f..8205f079c 100644 --- a/src/ess/dream/io/geant4.py +++ b/src/ess/dream/io/geant4.py @@ -42,7 +42,10 @@ def _load_raw_events( ) -> sc.DataArray: table = sc.io.load_csv(filename, sep='\t', header_parser='bracket', data_columns=[]) table = table.rename_dims(row='event') - return sc.DataArray(sc.ones(sizes=table.sizes), coords=table.coords) + return sc.DataArray( + sc.ones(sizes=table.sizes, with_variances=True, unit='counts'), + coords=table.coords, + ) def _adjust_coords(da: sc.DataArray) -> None: diff --git a/tests/dream/io/geant4_test.py b/tests/dream/io/geant4_test.py index 0b109a0e4..a9a944655 100644 --- a/tests/dream/io/geant4_test.py +++ b/tests/dream/io/geant4_test.py @@ -8,6 +8,7 @@ import numpy as np import pytest import scipp as sc +import scipp.testing from ess.dream import data, load_geant4_csv @@ -54,6 +55,17 @@ def test_load_geant4_csv_loads_expected_structure(file): } +@pytest.mark.parametrize( + 'key', ('mantle', 'high_resolution', 'endcap_forward', 'endcap_backward') +) +def test_load_gean4_csv_set_weights_to_one(file, key): + detector = load_geant4_csv(file)['instrument'][key] + events = detector.bins.constituents['data'].data + sc.testing.assert_identical( + events, sc.ones(sizes=events.sizes, with_variances=True, unit='counts') + ) + + def test_load_geant4_csv_mantle_has_expected_coords(file): # Only testing ranges that will not change in the future mantle = load_geant4_csv(file)['instrument']['mantle']