Skip to content

Commit

Permalink
Merge branch 'main' into CI-playground
Browse files Browse the repository at this point in the history
  • Loading branch information
noemifrisina committed Dec 6, 2023
2 parents b0d714d + f01357e commit 11a35e2
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 19 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
27 changes: 20 additions & 7 deletions src/nexgen/beamlines/ED_singla_nxs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@
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 ..utils import (coerce_to_path, find_in_dict, get_iso_timestamp,
get_nexus_filename)
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

logger = logging.getLogger("nexgen.EDNeXusWriter")
Expand Down Expand Up @@ -101,13 +105,13 @@ def singla_nexus_writer(
if find_in_dict("start_time", params):
start_time = get_iso_timestamp(params["start_time"])
else:
start_time = None
start_time = extract_start_time_from_master(master_file)

# Update source if new info passed
source = EDSource
if find_in_dict("new_source_info", params):
logger.warning("Updating source information.")
for k, v in params["new_source_info"].keys():
for k, v in params["new_source_info"].items():
source.__setattr__(k, v)
logger.info(f"Source {k} now set to {v}.")
logger.info(source.__repr__())
Expand All @@ -128,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:
Expand All @@ -146,6 +150,15 @@ def singla_nexus_writer(
det_axes = EDSingla.det_axes
det_axes[0].start_pos = det_distance

if not exp_time:
logger.warning("Exposure time not set, trying to read it from the master file.")
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."
)

# Define detector
detector = Detector(
det_params,
Expand Down Expand Up @@ -181,7 +194,7 @@ def singla_nexus_writer(
logger.info(goniometer.__repr__())

vds_writer = (
"dataset" if not find_in_dict("vds_writer", params) else params["vds_wrter"]
"dataset" if not find_in_dict("vds_writer", params) else params["vds_writer"]
)

# Start writing
Expand Down
2 changes: 1 addition & 1 deletion src/nexgen/command_line/ED_nexus.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def write_from_SINGLA_with_phil(args):
# Find scan axis in parsed values
scan_idx = [
n
for n in len(params.goniometer.axes)
for n in range(len(params.goniometer.axes))
if params.goniometer.types[n] == "rotation"
][0]
scan_info = [
Expand Down
68 changes: 63 additions & 5 deletions src/nexgen/tools/ED_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -12,6 +14,9 @@
import numpy as np
from numpy.typing import ArrayLike

logger = logging.getLogger("nexgen.EDtools.Singla")
logger.setLevel(logging.DEBUG)


class SinglaMaster:
"""
Expand Down Expand Up @@ -143,8 +148,65 @@ def get_software_version(self) -> bytes:
return None
return self.__getitem__(_loc[0])[()]

def get_data_collection_date(self) -> str:
_loc = [obj for obj in self.walk if "data_collection_date" in obj]
if len(_loc) == 0:
return None
else:
collection_date = str(self.__getitem__(_loc[0])[()])[2:21]
collection_date = datetime.strptime(collection_date, "%Y-%m-%dT%H:%M:%S")
return collection_date


def extract_from_SINGLA_master(master: Path | str) -> Dict[str, Any]:
def extract_exposure_time_from_master(master: Path | str) -> float:
"""
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): Exposure time, in seconds.
"""

if SinglaMaster.isDectrisSingla(master) is False:
logger.warning(f"The file {master} is the wrong format.")
return

exposure_time = None

with h5py.File(master, "r") as fh:
singla = SinglaMaster(fh)
exposure_time = singla.get_exposure_time()

return exposure_time


def extract_start_time_from_master(master: Path | str) -> datetime:
"""
Extracts start_time from the data_collection_date field of the master file.
Args:
master (Path | str): Path to Singla master file.
Returns:
start_time (datetime): Collection start time, as datetime object.
"""

if SinglaMaster.isDectrisSingla(master) is False:
logger.warning(f"The file {master} is the wrong format.")
return

start_time = None

with h5py.File(master, "r") as fh:
singla = SinglaMaster(fh)
start_time = singla.get_data_collection_date()

return start_time


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.
Expand All @@ -155,10 +217,6 @@ def extract_from_SINGLA_master(master: Path | str) -> Dict[str, Any]:
Returns:
Dict[str, Any]: Dictionary of information relative to the detector.
"""
import logging

logger = logging.getLogger("nexgen.EDtools.Singla")
logger.setLevel(logging.DEBUG)

if SinglaMaster.isDectrisSingla(master) is False:
logger.warning(f"The file {master} is the wrong format.")
Expand Down
29 changes: 24 additions & 5 deletions tests/tools/test_tools_for_ED.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import tempfile
from datetime import datetime

import h5py
import numpy as np
Expand All @@ -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,
)

Expand Down Expand Up @@ -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[
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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

0 comments on commit 11a35e2

Please sign in to comment.