From f01357e68a97790e3a734ec1125ec06d8a2f738c Mon Sep 17 00:00:00 2001 From: Noemi Frisina <54588199+noemifrisina@users.noreply.github.com> Date: Wed, 6 Dec 2023 10:50:37 +0000 Subject: [PATCH] Add tests (#153) --- CHANGELOG.md | 3 ++- src/nexgen/beamlines/ED_singla_nxs.py | 15 +++++++++----- src/nexgen/tools/ED_tools.py | 20 +++++++++--------- tests/tools/test_tools_for_ED.py | 29 ++++++++++++++++++++++----- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4962a248..8c263a72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,12 +2,13 @@ -## 0.#.# +## 0.7.3 ### Added - Added possibility to write `end_time_estimated` field in NXmxWriter and refactored `write_NXdatetime`. - A small utility to write a nexus file for electron diffraction and a new command line tool for SINGLA without phil. - Choice to avoid using the meta file for I19-2 data, as long as all relevant information is passed. +- Utilities to extract collection start time and exposure time from singla master file for ED. ### Changed - (Temporary) Write a soft link for /entry/instrument/detector/detector_z in NXdetector, for compatibility with autoPROC. diff --git a/src/nexgen/beamlines/ED_singla_nxs.py b/src/nexgen/beamlines/ED_singla_nxs.py index c77ce8aa..788c5a10 100644 --- a/src/nexgen/beamlines/ED_singla_nxs.py +++ b/src/nexgen/beamlines/ED_singla_nxs.py @@ -13,9 +13,12 @@ from ..nxs_utils.ScanUtils import calculate_scan_points from ..nxs_write.NXmxWriter import EDNXmxFileWriter from ..nxs_write.write_utils import find_number_of_images -from ..tools.ED_tools import extract_from_SINGLA_master, find_beam_centre -from ..tools.ED_tools import extract_start_time_from_master -from ..tools.ED_tools import extract_exposure_time_from_master +from ..tools.ED_tools import ( + extract_detector_info_from_master, + extract_exposure_time_from_master, + extract_start_time_from_master, + find_beam_centre, +) from ..utils import coerce_to_path, find_in_dict, get_iso_timestamp, get_nexus_filename from .ED_params import ED_coord_system, EDSingla, EDSource @@ -129,7 +132,7 @@ def singla_nexus_writer( logger.info( "Looking through Dectris master file to extract at least mask and flatfield." ) - det_info = extract_from_SINGLA_master(master_file) + det_info = extract_detector_info_from_master(master_file) det_params.constants.update(det_info) # If beam_centre not passed, define it if not find_in_dict("beam_center", params) or params["beam_center"] is None: @@ -152,7 +155,9 @@ def singla_nexus_writer( exp_time = extract_exposure_time_from_master(master_file) if not exp_time: - raise ValueError("Exposure time not provided. No 'count_time' in the master file.") + raise ValueError( + "Exposure time not provided. No 'count_time' in the master file." + ) # Define detector detector = Detector( diff --git a/src/nexgen/tools/ED_tools.py b/src/nexgen/tools/ED_tools.py index 4bd538d4..44a6afaa 100644 --- a/src/nexgen/tools/ED_tools.py +++ b/src/nexgen/tools/ED_tools.py @@ -3,6 +3,8 @@ """ from __future__ import annotations +import logging +from datetime import datetime from functools import cached_property from pathlib import Path from typing import Any, Dict, List, Tuple @@ -10,9 +12,7 @@ import h5py import hdf5plugin # noqa: F401 import numpy as np -from datetime import datetime from numpy.typing import ArrayLike -import logging logger = logging.getLogger("nexgen.EDtools.Singla") logger.setLevel(logging.DEBUG) @@ -128,7 +128,7 @@ def get_exposure_time(self) -> float: _loc = [obj for obj in self.walk if "count_time" in obj] if len(_loc) == 0: return None - return float(self.__getitem__(_loc[0])[()]) + return self.__getitem__(_loc[0])[()] def get_photon_energy(self) -> float: _loc = [obj for obj in self.walk if "photon_energy" in obj] @@ -154,21 +154,19 @@ def get_data_collection_date(self) -> str: return None else: collection_date = str(self.__getitem__(_loc[0])[()])[2:21] - collection_date = datetime.strptime(collection_date, - '%Y-%m-%dT%H:%M:%S') + collection_date = datetime.strptime(collection_date, "%Y-%m-%dT%H:%M:%S") return collection_date def extract_exposure_time_from_master(master: Path | str) -> float: """ - Extracts `count_time` from the master file + Extracts the exposure time from the count_time field in the master file. Args: master (Path | str): Path to Singla master file. Returns: - exposure time (float): In the master file this - is recorded as `count_time`. + exposure_time (float): Exposure time, in seconds. """ if SinglaMaster.isDectrisSingla(master) is False: @@ -186,13 +184,13 @@ def extract_exposure_time_from_master(master: Path | str) -> float: def extract_start_time_from_master(master: Path | str) -> datetime: """ - Extracts `data_collection_date` from the master file + Extracts start_time from the data_collection_date field of the master file. Args: master (Path | str): Path to Singla master file. Returns: - data collection date: Datetime object. + start_time (datetime): Collection start time, as datetime object. """ if SinglaMaster.isDectrisSingla(master) is False: @@ -208,7 +206,7 @@ def extract_start_time_from_master(master: Path | str) -> datetime: return start_time -def extract_from_SINGLA_master(master: Path | str) -> Dict[str, Any]: +def extract_detector_info_from_master(master: Path | str) -> Dict[str, Any]: """ Extracts mask, flatfield and any other information relative to the detector \ from a Singla master file. diff --git a/tests/tools/test_tools_for_ED.py b/tests/tools/test_tools_for_ED.py index 6698c0c1..77e6167c 100644 --- a/tests/tools/test_tools_for_ED.py +++ b/tests/tools/test_tools_for_ED.py @@ -1,4 +1,5 @@ import tempfile +from datetime import datetime import h5py import numpy as np @@ -8,7 +9,9 @@ from nexgen.tools.ED_tools import ( SinglaMaster, centroid_max, - extract_from_SINGLA_master, + extract_detector_info_from_master, + extract_exposure_time_from_master, + extract_start_time_from_master, find_beam_centre, ) @@ -39,6 +42,10 @@ def dummy_singla_master_file(): test_hdf_file = tempfile.NamedTemporaryFile(suffix=".h5", delete=True) with h5py.File(test_hdf_file, "w") as test_master_file: + test_master_file["/entry/instrument/detector/count_time"] = 0.1 + test_master_file[ + "/entry/instrument/detector/detectorSpecific/data_collection_date" + ] = "2023-12-06T10:30:42.039+02:00" test_master_file["/entry/instrument/detector/description/"] = b"Dectris Singla" test_master_file["/entry/instrument/detector/pixel_mask_applied"] = False test_master_file[ @@ -56,7 +63,7 @@ def test_isSingla_master_file(dummy_singla_master_file): def test_get_mask_and_flatfield_from_singla_master_file(dummy_singla_master_file): - D = extract_from_SINGLA_master(dummy_singla_master_file.name) + D = extract_detector_info_from_master(dummy_singla_master_file.name) assert "pixel_mask" in D.keys() and "flatfield" in D.keys() assert D["pixel_mask"] is None assert D["pixel_mask_applied"] == 0 @@ -65,12 +72,24 @@ def test_get_mask_and_flatfield_from_singla_master_file(dummy_singla_master_file def test_get_software_version_from_singla_master_file(dummy_singla_master_file): - D = extract_from_SINGLA_master(dummy_singla_master_file.name) + D = extract_detector_info_from_master(dummy_singla_master_file.name) assert "software_version" in D.keys() - assert type(D["software_version"]) is bytes + assert isinstance(D["software_version"], bytes) assert D["software_version"].decode() == "0.0.0" +def test_get_exposure_time_from_singla_master_file(dummy_singla_master_file): + exp_time = extract_exposure_time_from_master(dummy_singla_master_file.name) + assert isinstance(exp_time, float) + assert exp_time == 0.1 + + +def test_get_collection_start_time_from_singla_master_file(dummy_singla_master_file): + start_time = extract_start_time_from_master(dummy_singla_master_file.name) + assert isinstance(start_time, datetime) + assert start_time == datetime.fromisoformat("2023-12-06T10:30:42") + + def test_get_nimages_and_triggers(dummy_singla_master_file): with h5py.File(dummy_singla_master_file.name, "r") as fh: master = SinglaMaster(fh) @@ -110,6 +129,6 @@ def test_find_beam_center(dummy_singla_master_file): beam_center = find_beam_centre( dummy_singla_master_file.name, test_img_hdf_file.name ) - assert type(beam_center) is tuple + assert isinstance(beam_center, tuple) assert beam_center[0] is not None assert beam_center[1] is not None