From aebb3d9e16ed8e6f48c2661f1594874008112ff6 Mon Sep 17 00:00:00 2001 From: David McDonagh <60879630+toastisme@users.noreply.github.com> Date: Mon, 12 Aug 2024 08:41:29 +0100 Subject: [PATCH 1/3] Additional methods for FormatISISSXD to extract data more efficiently. (#743) --- newsfragments/743.misc | 1 + src/dxtbx/format/FormatISISSXD.py | 95 +++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 10 deletions(-) create mode 100644 newsfragments/743.misc diff --git a/newsfragments/743.misc b/newsfragments/743.misc new file mode 100644 index 000000000..5574bbb6f --- /dev/null +++ b/newsfragments/743.misc @@ -0,0 +1 @@ +Additional methods for FormatISISSXD to extract data more efficiently. diff --git a/src/dxtbx/format/FormatISISSXD.py b/src/dxtbx/format/FormatISISSXD.py index 00299d515..549fe3064 100644 --- a/src/dxtbx/format/FormatISISSXD.py +++ b/src/dxtbx/format/FormatISISSXD.py @@ -3,6 +3,7 @@ from typing import List, Tuple import h5py +import numpy as np import cctbx.array_family.flex as flex @@ -44,6 +45,9 @@ def get_name(image_file: str) -> str: return get_name(image_file) == "SXD" + def get_instrument_name(self) -> str: + return "SXD" + def get_experiment_title(self) -> str: return self._nxs_file["raw_data_1"]["title"][0].decode() @@ -55,23 +59,26 @@ def get_experiment_description(self) -> str: run_number = self.get_experiment_run_number() return f"{title} ({run_number})" - def get_goniometer(self, idx: int = None) -> Goniometer: - rotation_axis = (0.0, 1.0, 0.0) - fixed_rotation = (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) - goniometer = GoniometerFactory.make_goniometer(rotation_axis, fixed_rotation) + def get_goniometer_phi_angle(self) -> float: try: experiment_title = self.get_experiment_title() if "w=" in experiment_title: - angle = float(experiment_title().split("w=")[1].split()[0]) + return float(experiment_title.split("w=")[1].split()[0]) elif "wccr" in experiment_title: - angle = float(experiment_title.split("wccr=")[1].split()[0]) + return float(experiment_title.split("wccr=")[1].split()[0]) elif "wtl" in experiment_title: - angle = float(experiment_title.split("wtl=")[1].split()[0]) + return float(experiment_title.split("wtl=")[1].split()[0]) else: - return goniometer - goniometer.rotate_around_origin(rotation_axis, angle) + return 0 except (ValueError, IndexError): - pass + return 0 + + def get_goniometer(self, idx: int = None) -> Goniometer: + rotation_axis = (0.0, 1.0, 0.0) + fixed_rotation = (1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0) + goniometer = GoniometerFactory.make_goniometer(rotation_axis, fixed_rotation) + angle = self.get_goniometer_phi_angle() + goniometer.rotate_around_origin(rotation_axis, angle) return goniometer def get_detector(self, index: int = None) -> Detector: @@ -313,3 +320,71 @@ def get_raw_data(self, index: int, use_loaded_data=True) -> Tuple[flex.int]: raw_data.append(panel_data) return tuple(raw_data) + + def get_flattened_data( + self, image_range: None | Tuple = None, scale_data: bool = True + ) -> Tuple[flex.int]: + """ + Image data summed along the time-of-flight direction + """ + + panel_size = self._get_image_size() + total_pixels = panel_size[0] * panel_size[1] + # Panel positions are offset by 4 in raw_data array + # See p24 of https://www.isis.stfc.ac.uk/Pages/sxd-user-guide6683.pdf + idx_offset = 4 + max_val = None + num_tof_bins = len(self._get_time_of_flight()) + raw_data = [] + for panel_idx in range(self._get_num_panels()): + start_idx = (panel_idx * total_pixels) + (panel_idx * idx_offset) + end_idx = start_idx + total_pixels + panel_data = self._nxs_file["raw_data_1/detector_1/counts"][ + 0, start_idx:end_idx, : + ] + panel_data = np.reshape( + panel_data, (panel_size[0], panel_size[1], num_tof_bins) + ) + if image_range is not None: + assert ( + len(image_range) == 2 + ), "expected image_range to be only two values" + assert ( + image_range[0] >= 0 and image_range[0] < image_range[1] + ), "image_range[0] out of range" + assert image_range[1] <= num_tof_bins, "image_range[1] out of range" + panel_data = np.flipud( + np.sum(panel_data[:, :, image_range[0] : image_range[1]], axis=2) + ) + else: + panel_data = np.flipud(np.sum(panel_data, axis=2)) + if panel_idx == 0 and self._panel_0_flipped(): + panel_data = np.flipud(panel_data) + panel_max_val = np.max(panel_data) + if max_val is None or max_val < panel_max_val: + max_val = panel_max_val + raw_data.append(panel_data) + + if scale_data: + return tuple([(i / max_val).tolist() for i in raw_data]) + + return tuple([i.tolist() for i in raw_data]) + + def get_flattened_pixel_data( + self, panel_idx: int, x: int, y: int + ) -> Tuple[Tuple, Tuple]: + time_channels = self._get_time_of_flight() + panel_size = self._get_image_size() + height = panel_size[1] + total_pixels = panel_size[0] * panel_size[1] + # Panel positions are offset by 4 in raw_data array + # See p24 of https://www.isis.stfc.ac.uk/Pages/sxd-user-guide6683.pdf + idx_offset = 4 + idx = (panel_idx * total_pixels) + (panel_idx * idx_offset) + y * height + x + return ( + time_channels, + tuple(self._nxs_file["raw_data_1/detector_1/counts"][0, idx, :].tolist()), + ) + + def get_proton_charge(self): + return float(self._nxs_file["raw_data_1/proton_charge"][0]) From f3635adf57634bffefff7ecb628a889dec1468b6 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Fri, 16 Aug 2024 13:16:01 +0100 Subject: [PATCH 2/3] Pin numpy to <2 for CI (#750) We will need to address this at some point soon, but for now just fix the CI. --- .azure-pipelines/ci-conda-env.txt | 6 +++--- newsfragments/750.misc | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 newsfragments/750.misc diff --git a/.azure-pipelines/ci-conda-env.txt b/.azure-pipelines/ci-conda-env.txt index d9c93bc90..23081b8ff 100644 --- a/.azure-pipelines/ci-conda-env.txt +++ b/.azure-pipelines/ci-conda-env.txt @@ -1,10 +1,10 @@ conda-forge::boost conda-forge::boost-cpp conda-forge::bzip2 -conda-forge::c-compiler<1.5 +conda-forge::c-compiler conda-forge::cctbx-base conda-forge::conda -conda-forge::cxx-compiler<1.5 +conda-forge::cxx-compiler conda-forge::python-dateutil conda-forge::dials-data conda-forge::docutils @@ -16,7 +16,7 @@ conda-forge::hdf5 conda-forge::matplotlib-base conda-forge::mrcfile conda-forge::natsort -conda-forge::numpy +conda-forge::numpy<2 conda-forge::nxmx conda-forge::orderedset conda-forge::pillow>=5.4.1 diff --git a/newsfragments/750.misc b/newsfragments/750.misc new file mode 100644 index 000000000..af2ac0bf2 --- /dev/null +++ b/newsfragments/750.misc @@ -0,0 +1 @@ +Fix CI by pinning numpy 2.0. From 9a8cff3d26488948b6bc0f468e3f0bf1e611bfd5 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Fri, 16 Aug 2024 13:38:40 +0100 Subject: [PATCH 3/3] Maintenance: Set a CMake policy version (#749) 3.30 added a new policy around pending removal of the FindBoost module. This is quite noisy without this setting. --- CMakeLists.txt | 2 +- newsfragments/749.misc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 newsfragments/749.misc diff --git a/CMakeLists.txt b/CMakeLists.txt index 96c6b76d5..c356a050e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20 FATAL_ERROR) +cmake_minimum_required(VERSION 3.20...3.30 FATAL_ERROR) project(dxtbx LANGUAGES C CXX) diff --git a/newsfragments/749.misc b/newsfragments/749.misc new file mode 100644 index 000000000..a18f8bf2a --- /dev/null +++ b/newsfragments/749.misc @@ -0,0 +1 @@ +Set a CMake policy version, to avoid warnings on newer version.