Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Big rewrite #117

Merged
merged 99 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
022f3e8
Prototype new loader code
SimonHeybrock Mar 8, 2023
c6f81dd
Begin refactoring tests
SimonHeybrock Mar 15, 2023
ebf3584
Refactor more tests and restore old behavior
SimonHeybrock Mar 15, 2023
ccbd6ed
Use old field dims guessing code
SimonHeybrock Mar 15, 2023
8dcc999
Pass more tests
SimonHeybrock Mar 16, 2023
d9e8739
Refactor to init fields on NXobject creation
SimonHeybrock Mar 16, 2023
3e1b487
Cleanup
SimonHeybrock Mar 16, 2023
0b22bf9
Restore coord to attr conversion
SimonHeybrock Mar 16, 2023
c77c68b
Legacy signal handling
SimonHeybrock Mar 16, 2023
cc02a4b
Update most NXdata tests
SimonHeybrock Mar 17, 2023
05debb9
Support NXlog
SimonHeybrock Mar 17, 2023
97ffb0c
Cache sizes for significant speedup
SimonHeybrock Mar 17, 2023
26cb1e2
Fixes and NXoff_geometry support
SimonHeybrock Mar 20, 2023
dbdc9f5
Implement special field handling
SimonHeybrock Mar 20, 2023
60d6499
Improve support for special fields
SimonHeybrock Mar 20, 2023
cef6a7d
Cleanup and pass pre-commit
SimonHeybrock Mar 20, 2023
f6c9b91
NXcylindrical_geometry
SimonHeybrock Mar 20, 2023
1c3e930
Fallback from pre_assemble errors
SimonHeybrock Mar 20, 2023
764daab
NXevent_data
SimonHeybrock Mar 20, 2023
b2327b9
Do not auto-group event data by detector
SimonHeybrock Mar 20, 2023
66d6067
Continue work on event data
SimonHeybrock Mar 20, 2023
d658250
Update monitor tests
SimonHeybrock Mar 21, 2023
2ab8015
Fix remaining NXdetector tests
SimonHeybrock Mar 21, 2023
aa7fb12
Pass some NXtransformations tests
SimonHeybrock Mar 21, 2023
e4f1900
Do not convert all translations to meter
SimonHeybrock Mar 21, 2023
97af919
Set depends_on as attr instead of executing transform chains
SimonHeybrock Mar 21, 2023
4053873
cleanup
SimonHeybrock Mar 21, 2023
47cca4c
Move new API to folder 'v2'
SimonHeybrock Mar 22, 2023
f3f5df4
nx_class property
SimonHeybrock Mar 22, 2023
ea70280
Add conftest.py for scipp's assert_identical
SimonHeybrock Mar 22, 2023
bf6466b
Simplify and improve shape/squeeze handling
SimonHeybrock Mar 22, 2023
681fcd0
Make all tests run again
SimonHeybrock Mar 22, 2023
b1da422
Pass more tests
SimonHeybrock Mar 22, 2023
3e4621a
Handle aux signals by returning dataset
SimonHeybrock Mar 22, 2023
6fa4c9b
Update squeeze behavior tests
SimonHeybrock Mar 22, 2023
ccc254d
Access via class
SimonHeybrock Mar 22, 2023
99167b4
Try to avoid reinit of nexus tree from transformation chains
SimonHeybrock Mar 22, 2023
405a4a0
Fix coord to attr code
SimonHeybrock Mar 23, 2023
de5b8a4
Fix or disable remaining tests
SimonHeybrock Mar 23, 2023
881b269
Update file load test and avoid slow scipp integer-array indexing
SimonHeybrock Mar 23, 2023
b62af2e
Add missing file file
SimonHeybrock Mar 23, 2023
1992be2
Add write support for appl-defs
SimonHeybrock Mar 23, 2023
9e8af94
Bring back NXcanSAS support
SimonHeybrock Mar 23, 2023
d1260b9
Change folder name
SimonHeybrock Mar 23, 2023
a99bb94
Proper submodule
SimonHeybrock Mar 23, 2023
2aec1f2
Handle and test NXsample
SimonHeybrock Mar 23, 2023
2b2bf52
Add YMIR file
SimonHeybrock Mar 23, 2023
0874dac
Split large file
SimonHeybrock Mar 23, 2023
126b6fd
Try to avoid NXobject dependency on Group
SimonHeybrock Mar 24, 2023
635758e
Fix NXgeometry
SimonHeybrock Mar 24, 2023
d7702ad
Docstrings
SimonHeybrock Mar 24, 2023
3a37a65
Remove prints
SimonHeybrock Mar 24, 2023
c82127f
Missing file
SimonHeybrock Mar 24, 2023
1cc8954
Prevent writing to cached attrs
SimonHeybrock Mar 24, 2023
ac519b7
Some docstrings
SimonHeybrock Mar 27, 2023
fd46585
Avoid messy mechanism for the sole purpose of supporting NXcanSAS
SimonHeybrock Mar 27, 2023
73fd602
Restore ability to load with no definitions
SimonHeybrock Mar 27, 2023
d004d46
Detect transformations via transform_type attribute
SimonHeybrock Mar 27, 2023
33d111c
Minor cleanup
SimonHeybrock Mar 27, 2023
50a00a0
Document some thoughts
SimonHeybrock Mar 27, 2023
8bd855f
Test loading files without definitions
SimonHeybrock Mar 28, 2023
138a4a3
Do not resolve depends_on chain, but replace by relpath
SimonHeybrock Mar 29, 2023
3a2a323
Remove parent mechanism
SimonHeybrock Mar 29, 2023
9ca7759
To not transform geometry classes
SimonHeybrock Mar 29, 2023
258a2f5
Cleanup
SimonHeybrock Mar 29, 2023
3034926
Docstrings
SimonHeybrock Mar 30, 2023
a6f2c7f
Comment NXdata logic
SimonHeybrock Mar 30, 2023
be72981
Cleanup event grouping code
SimonHeybrock Mar 30, 2023
17cf4cf
Rename asarray -> asvariable
SimonHeybrock Mar 31, 2023
2346df8
Use posixpath for depends_on handling
SimonHeybrock Mar 31, 2023
90c786a
Address comments on base.py
SimonHeybrock Mar 31, 2023
856d2ac
Fix __all__
SimonHeybrock Mar 31, 2023
e6a20a8
Avoid cached_property in cases where it makes logic intransparent
SimonHeybrock Mar 31, 2023
c4fb7c9
Cleaner and fixed mechanism for forcing NXlog time axes to datetime
SimonHeybrock Apr 3, 2023
49a18ef
Fix length-0 datetime fields
SimonHeybrock Apr 3, 2023
bd4c5ca
Fix length-0 time-independent transformation loading
SimonHeybrock Apr 3, 2023
2f9a239
Fix type hint
SimonHeybrock Apr 3, 2023
3784fdf
Small readability improvements
SimonHeybrock Apr 3, 2023
538926d
Move Field to file
SimonHeybrock Apr 3, 2023
0d62b3a
Remove unused protocol class
SimonHeybrock Apr 3, 2023
d9df2c2
Begin splitting NXdata.__init__
SimonHeybrock Apr 3, 2023
a8d2f4e
Finish split
SimonHeybrock Apr 3, 2023
2376aa8
Remove unused fixture param
SimonHeybrock Apr 3, 2023
1544f13
Add test for errors field with different unit
SimonHeybrock Apr 3, 2023
398dd97
Move tests
SimonHeybrock Apr 3, 2023
77e2d7c
Restore ability to load monitors with embedded event data
SimonHeybrock Apr 3, 2023
6964f0b
Revert "Restore ability to load monitors with embedded event data"
SimonHeybrock Apr 3, 2023
69ec01e
Remove unreachable code
SimonHeybrock Apr 3, 2023
266a56b
Restore handling of files with raw bytes instead of string attrs
SimonHeybrock Apr 3, 2023
c55bcd3
Bump scipp requirement to fix segfault with Python3.10 var.value
SimonHeybrock Apr 3, 2023
94357b5
Comment on dropping of cue_* fields
SimonHeybrock Apr 4, 2023
e338eae
Try another way of handling embedded event data
SimonHeybrock Apr 4, 2023
0cba7d6
Restore handling of embedded event fields in NXdetector
SimonHeybrock Apr 4, 2023
d3ddad2
Fix issue that lead to multi-init of NXobject sbuclasses
SimonHeybrock Apr 4, 2023
098b806
Try to load embedded events in NXdetector better
SimonHeybrock Apr 4, 2023
7d199bf
Update test
SimonHeybrock Apr 4, 2023
bd17388
Minor datetime code simplification
SimonHeybrock Apr 5, 2023
d6cf717
Remove superfluous dtype check for event_id
SimonHeybrock Apr 5, 2023
7c1d69f
Merge branch 'main' into nx2
SimonHeybrock Apr 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conda/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ requirements:
run:
- python>=3.8
- python-dateutil
- scipp>=23.01.1
- scipp>=23.03.1
- scipy
- h5py

Expand Down
4 changes: 2 additions & 2 deletions requirements/base.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SHA1:20e195123d87c5cf695f1f70a994a4a4b8d9178b
# SHA1:c3c05567d668423130fa3b892cc2cae373423b1c
#
# This file is autogenerated by pip-compile-multi
# To update, run:
Expand All @@ -20,7 +20,7 @@ python-dateutil==2.8.2
# via -r base.in
pyyaml==6.0
# via confuse
scipp==23.3.0
scipp==23.3.1
# via -r base.in
scipy==1.10.0
# via -r base.in
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ package_dir =
packages = find:
install_requires =
python-dateutil
scipp>=23.01.1
scipp>=23.03.1
scipy # we use scipp.interpolate which depends on this
h5py
python_requires = >=3.8
Expand Down
25 changes: 25 additions & 0 deletions src/scippnexus/v2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
# @author Simon Heybrock

# flake8: noqa
import importlib.metadata

try:
__version__ = importlib.metadata.version(__package__ or __name__)
except importlib.metadata.PackageNotFoundError:
__version__ = "0.0.0"

from .. import typing
from .base import (
Group,
NexusStructureError,
NXobject,
base_definitions,
create_class,
create_field,
)
from .field import Field
from .file import File
from .nexus_classes import *
from .nxdata import group_events_by_detector_number
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
# @author Simon Heybrock

# flake8: noqa

from .nxcansas import SASdata, SASentry, definitions

__all__ = ['definitions', 'SASentry', 'SASdata']
128 changes: 128 additions & 0 deletions src/scippnexus/v2/application_definitions/nxcansas/nxcansas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
# @author Simon Heybrock
from typing import Any, Callable, Dict, Literal, Optional, Union

import scipp as sc

from ....typing import H5Group
from ...base import Group, NXobject, base_definitions, create_field
from ...field import Field
from ...nxdata import NXdata


class SASentry:
nx_class = 'NXentry'

def __init__(self, *, title: str, run: Union[str, int]):
self.title = title
self.run = run

def __write_to_nexus_group__(self, group: H5Group):
group.attrs['canSAS_class'] = 'SASentry'
group.attrs['version'] = '1.0'
group.attrs['definition'] = 'NXcanSAS'
create_field(group, 'title', self.title)
create_field(group, 'run', self.run)


class SASdata:
nx_class = 'NXdata'

def __init__(self,
data: sc.DataArray,
Q_variances: Optional[Literal['uncertainties', 'resolutions']] = None):
self.data = data
valid = ('uncertainties', 'resolutions')
if Q_variances not in (None, ) + valid:
raise ValueError(f"Q_variances must be in {valid}")
self._variances = Q_variances

def __write_to_nexus_group__(self, group: H5Group):
da = self.data
group.attrs['canSAS_class'] = 'SASdata'
group.attrs['signal'] = 'I'
group.attrs['axes'] = da.dims # for NeXus compliance, same as I_axes
group.attrs['I_axes'] = da.dims
group.attrs['Q_indices'] = tuple(da.dims.index(d) for d in da.coords['Q'].dims)
# TODO writing Field should deal with variances
signal = create_field(group, 'I', sc.values(da.data))
# We use the _errors suffix for NeXus compliance, unlike the examples given in
# NXcanSAS.
if da.variances is not None:
signal.attrs['uncertainties'] = 'I_errors'
create_field(group, 'I_errors', sc.stddevs(da.data))
if da.coords.is_edges('Q'):
raise ValueError(
"Q is given as bin-edges, but NXcanSAS requires Q points (such as "
"bin centers).")
coord = create_field(group, 'Q', da.coords['Q'])
if da.coords['Q'].variances is not None:
if self._variances is None:
raise ValueError(
"Q has variances, must specify whether these represent "
"'uncertainties' or 'resolutions' using the 'Q_variances' option'")

coord.attrs[self._variances] = 'Q_errors'
create_field(group, 'Q_errors', sc.stddevs(da.coords['Q']))


class _SASdata(NXdata):

def __init__(self, attrs: Dict[str, Any], children: Dict[str, Union[Field, Group]]):
fallback_dims = attrs.get('I_axes')
if fallback_dims is not None:
fallback_dims = (fallback_dims, )
super().__init__(attrs=attrs,
children=children,
fallback_dims=fallback_dims,
fallback_signal_name='I')

# TODO Mechanism for custom error names
@staticmethod
def signal_errors(group: NXobject) -> Optional[str]:
signal_name = group.attrs.get('signal', 'I')
signal = group._group[signal_name]
return signal.attrs.get('uncertainties')

def coord_errors(group: NXobject, name: str) -> Optional[str]:
if name != 'Q':
return None
# TODO This naively stores this as Scipp errors, which are just Gaussian.
# This is probably not correct in all cases.
uncertainties = group[name].attrs.get('uncertainties')
resolutions = group[name].attrs.get('resolutions')
if uncertainties is None:
return resolutions
elif resolutions is None:
return uncertainties
raise RuntimeError("Cannot handle both uncertainties and resolutions for Q")


class _SAStransmission_spectrum(NXdata):

def __init__(self, attrs: Dict[str, Any], children: Dict[str, Union[Field, Group]]):
# TODO A valid file should have T_axes, do we need to fallback?
super().__init__(attrs=attrs,
children=children,
fallback_dims=(attrs.get('T_axes', 'lambda'), ),
fallback_signal_name='T')


class NXcanSAS:

def get(self, key: type, default: Callable) -> Callable:

def _definition_factory(attrs: Dict[str, Any],
children: Dict[str, Union[Field, Group]]) -> NXobject:
if (cls := attrs.get('canSAS_class')) is not None:
if cls == 'SASdata':
return _SASdata(attrs, children)
if cls == 'SAStransmission_spectrum':
return _SAStransmission_spectrum(attrs, children)
return base_definitions.get(key, default)(attrs, children)

return _definition_factory


definitions = NXcanSAS()
28 changes: 28 additions & 0 deletions src/scippnexus/v2/attrs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
# @author Simon Heybrock
from collections.abc import Mapping
from typing import Any, Iterator

from .._hdf5_nexus import _cset_to_encoding, _ensure_str


class Attrs(Mapping):

def __init__(self, attrs: Mapping):
self._base_attrs = attrs
self._attrs = dict(attrs) if attrs else dict()

def __getitem__(self, name: str) -> Any:
attr = self._attrs[name]
# Is this check for string attributes sufficient? Is there a better way?
if isinstance(attr, (str, bytes)):
cset = self._base_attrs.get_id(name.encode("utf-8")).get_type().get_cset()
return _ensure_str(attr, _cset_to_encoding(cset))
return attr

def __iter__(self) -> Iterator[str]:
return iter(self._attrs)

def __len__(self) -> int:
return len(self._attrs)
Loading