Skip to content

Commit

Permalink
Merge pull request #243 from scipp/transforms
Browse files Browse the repository at this point in the history
Improve and simplify loading of transformation chains
  • Loading branch information
SimonHeybrock authored Oct 7, 2024
2 parents cd17d10 + 54b2b68 commit b1bf148
Show file tree
Hide file tree
Showing 5 changed files with 284 additions and 473 deletions.
22 changes: 20 additions & 2 deletions src/scippnexus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,26 @@
create_class,
create_field,
)
from .field import Attrs, Field
from .field import Attrs, DependsOn, Field
from .file import File
from ._load import load
from .nexus_classes import *
from .nxtransformations import compute_positions, zip_pixel_offsets
from .nxtransformations import compute_positions, zip_pixel_offsets, TransformationChain

__all__ = [
'Attrs',
'DependsOn',
'Field',
'File',
'Group',
'NXobject',
'NexusStructureError',
'TransformationChain',
'base_definitions',
'compute_positions',
'create_class',
'create_field',
'load',
'typing',
'zip_pixel_offsets',
]
13 changes: 5 additions & 8 deletions src/scippnexus/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,16 +409,13 @@ def isclass(x):
# For a time-dependent transformation in NXtransformations, an NXlog may
# take the place of the `value` field. In this case, we need to read the
# properties of the NXlog group to make the actual transformation.
from .nxtransformations import maybe_resolve, maybe_transformation
from .nxtransformations import maybe_transformation, parse_depends_on_chain

if (
isinstance(dg, sc.DataGroup)
and (depends_on := dg.get('depends_on')) is not None
):
if (resolved := maybe_resolve(self['depends_on'], depends_on)) is not None:
dg['resolved_depends_on'] = resolved
if isinstance(dg, sc.DataGroup) and 'depends_on' in dg:
if (chain := parse_depends_on_chain(self, dg['depends_on'])) is not None:
dg['depends_on'] = chain

return maybe_transformation(self, value=dg, sel=sel)
return maybe_transformation(self, value=dg)

def _warn_fallback(self, e: Exception) -> None:
msg = (
Expand Down
32 changes: 19 additions & 13 deletions src/scippnexus/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,22 @@
from .base import Group


def depends_on_to_relative_path(depends_on: str, parent_path: str) -> str:
"""Replace depends_on paths with relative paths.
@dataclass
class DependsOn:
"""
Represents a depends_on reference in a NeXus file.
The parent (the full path within the NeXus file) is stored, as the value may be
relative or absolute, so having the path available after loading is essential.
"""

parent: str
value: str

After loading we will generally not have the same root so absolute paths
cannot be resolved after loading."""
if depends_on.startswith('/'):
return posixpath.relpath(depends_on, parent_path)
return depends_on
def absolute_path(self) -> str | None:
if self.value == '.':
return None
return posixpath.normpath(posixpath.join(self.parent, self.value))


def _is_time(obj):
Expand Down Expand Up @@ -161,7 +169,7 @@ def __getitem__(self, select: ScippIndex) -> Any | sc.Variable:
# If the variable is empty, return early
if np.prod(shape) == 0:
variable = self._maybe_datetime(variable)
return maybe_transformation(self, value=variable, sel=select)
return maybe_transformation(self, value=variable)

if self.dtype == sc.DType.string:
try:
Expand All @@ -170,10 +178,8 @@ def __getitem__(self, select: ScippIndex) -> Any | sc.Variable:
strings = self.dataset.asstr(encoding='latin-1')[index]
_warn_latin1_decode(self.dataset, strings, str(e))
variable.values = np.asarray(strings).flatten()
if self.dataset.name.endswith('depends_on') and variable.ndim == 0:
variable.value = depends_on_to_relative_path(
variable.value, self.dataset.parent.name
)
if self.dataset.name.endswith('/depends_on') and variable.ndim == 0:
return DependsOn(parent=self.dataset.parent.name, value=variable.value)
elif variable.values.flags["C_CONTIGUOUS"]:
# On versions of h5py prior to 3.2, a TypeError occurs in some cases
# where h5py cannot broadcast data with e.g. shape (20, 1) to a buffer
Expand All @@ -199,7 +205,7 @@ def __getitem__(self, select: ScippIndex) -> Any | sc.Variable:
else:
return variable.value
variable = self._maybe_datetime(variable)
return maybe_transformation(self, value=variable, sel=select)
return maybe_transformation(self, value=variable)

def _maybe_datetime(self, variable: sc.Variable) -> sc.Variable:
if _is_time(variable):
Expand Down
Loading

0 comments on commit b1bf148

Please sign in to comment.