Source code for ewoksfluo.io.nexus

import datetime
import logging
import os
from contextlib import ExitStack
from contextlib import contextmanager
from typing import Iterator
from typing import Mapping
from typing import Optional

import h5py
from ewoksdata.data.hdf5.dataset_writer import DatasetWriter
from silx.io import h5py_utils

from . import hdf5
from .types import ScanData

logger = logging.getLogger(__name__)


[docs] def save_as_bliss_scan( filename: str, entry_name: str, scan_data: Iterator[ScanData], positioners: Optional[Mapping[str, float]] = None, title: Optional[str] = None, **openoptions, ): openoptions.setdefault("mode", "a") os.makedirs(os.path.abspath(os.path.dirname(filename)), exist_ok=True) with h5py_utils.File(filename, **openoptions) as f: if entry_name in f: logger.warning("%s::/%s already exists", filename, entry_name) return with ExitStack() as stack: entry = stack.enter_context(_writer_context(f, entry_name)) instrument = entry.create_group("instrument") instrument.attrs["NX_class"] = "NXinstrument" measurement = entry.create_group("measurement") measurement.attrs["NX_class"] = "NXcollection" if title: entry["title"] = title if positioners: collection = instrument.create_group("positioners_start") collection.attrs["NX_class"] = "NXcollection" for k, v in positioners.items(): collection[k] = v positioners = dict(positioners) writers = dict() for data in scan_data: detector = instrument.require_group(data.group) if data.detector_type == "positioner": detector.attrs["NX_class"] = "NXpositioner" if positioners: positioners[data.group] = data.data else: detector.attrs["NX_class"] = "NXdetector" if "type" not in detector and data.detector_type: detector["type"] = data.detector_type key = data.group, data.name writer = writers.get(key) if writer is None: writer = stack.enter_context(DatasetWriter(detector, data.name)) writers[key] = writer if data.local_alias: detector[data.local_alias] = h5py.SoftLink(writer.dataset_name) if data.global_alias and data.global_alias not in measurement: measurement[data.global_alias] = h5py.SoftLink( writer.dataset_name ) writer.add_points(data.data) if positioners: collection = instrument.create_group("positioners") collection.attrs["NX_class"] = "NXcollection" for k, v in positioners.items(): collection[k] = v
@contextmanager def _writer_context(root: hdf5.FileType, entry_name: str) -> Iterator[h5py.Group]: root.attrs["NX_class"] = "NXroot" root.attrs["creator"] = "ewoksfluo" entry = root.create_group(entry_name) try: entry.attrs["NX_class"] = "NXentry" entry.attrs["start_time"] = _timestamp() writer = entry.create_group("writer") writer.attrs["NX_class"] = "NXnote" writer["status"] = "STARTING" yield entry except Exception: writer["status"][()] = "FAILED" raise else: writer["status"][()] = "SUCCEEDED" finally: entry["end_time"] = _timestamp() def _timestamp() -> str: return datetime.datetime.now().astimezone().isoformat()