Thanks to visit codestin.com
Credit goes to github.com

Skip to content
6 changes: 5 additions & 1 deletion cdiutils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from . import load, plot, process
from .geometry import Geometry
from .converter import SpaceConverter

__all__ = [
"load",
"plot",
"process"
"process",
"Geometry",
"SpaceConverter"
]
3 changes: 2 additions & 1 deletion cdiutils/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def _check_shape(self, shape: tuple) -> None:
def init_interpolator(
self,
detector_data: np.ndarray,
direct_space_data_shape: tuple = None,
direct_space_data_shape: tuple | np.ndarray | list = None,
direct_space_voxel_size: tuple | np.ndarray | list | float = None,
space: str = "direct",
shift_voxel: tuple = None
Expand Down Expand Up @@ -414,6 +414,7 @@ def init_interpolator(
"if space is 'direct' direct_space_data_shape must be "
"provided."
)
direct_space_data_shape = tuple(direct_space_data_shape)
if shape != direct_space_data_shape:
raise ValueError(
"The cropped_raw_data should have the same shape as the "
Expand Down
31 changes: 24 additions & 7 deletions cdiutils/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,33 +39,50 @@ def from_setup(cls, beamline_setup: str) -> None:
"""Create a Geometry instance using a beamline name."""

# Note that we use CXI convention here
if beamline_setup in ("ID01", "ID01SPEC", "ID01BLISS"):
if beamline_setup.lower() in ("id01", "id01spec", "id01bliss"):
return cls(
sample_circles=["x-", "y-"], # eta, phi
detector_circles=["y-", "x-"], # delta, nu
detector_circles=["y-", "x-"], # nu, delta
detector_vertical_orientation="y-",
detector_horizontal_orientation="x+",
beam_direction=[1, 0, 0]
)
if "P10" in beamline_setup:
if "p10" in beamline_setup.lower():
return cls(
sample_circles=["x-", "y-"], # om (or samth), phi
detector_circles=["y+", "x-"], # del (or e2_t02), gam
detector_circles=["y+", "x-"], # gam, del (or e2_t02)
detector_vertical_orientation="y-",
detector_horizontal_orientation="x+",
beam_direction=[1, 0, 0]
)
if beamline_setup == "SIXS2022":
if beamline_setup.lower() == "sixs2022":
return cls(
sample_circles=["x-", "y+"], # mu, omega
detector_circles=["y+", "x-"], # gamma, delta
detector_circles=["y+", "x-"], # gamma, delta NOT SURE OF THE COMMENT
detector_vertical_orientation="y-",
detector_horizontal_orientation="x+",
beam_direction=[1, 0, 0]
)
if beamline_setup.lower() == "nanomax":
return cls(
sample_circles=["x-", "y-"], # gontheta, gonphi
detector_circles=["y-", "x-"], # gamma, delta
detector_vertical_orientation="y+",
detector_horizontal_orientation="x-",
beam_direction=[1, 0, 0]
)
if beamline_setup.lower() == "cristal":
return cls(
sample_circles=["x-", "y+"], # omega, phi
detector_circles=["y+", "x-"], # gamma, delta OK FOR omega/delta but not for the two others
detector_vertical_orientation="y-",
detector_horizontal_orientation="x+",
beam_direction=[1, 0, 0]
)
raise NotImplementedError(
f"The beamline_setup {beamline_setup} is not valid. Available:\n"
"'ID01', 'ID01SPEC', 'ID01BLISS', 'P10' , 'SIXS2022'"
"'ID01', 'ID01SPEC', 'ID01BLISS', 'P10', 'P10EH2', 'SIXS2022' "
"and NanoMAX."
)

def cxi_to_xu(self) -> None:
Expand Down
16 changes: 5 additions & 11 deletions cdiutils/load/bliss.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import hdf5plugin
import silx.io.h5py_utils

from cdiutils.utils import CroppingHandler
from cdiutils.load import Loader


Expand All @@ -23,10 +22,10 @@ class BlissLoader(Loader):
"""

angle_names = {
"sample_outofplane_angle": "eta",
"sample_inplane_angle": "phi",
"detector_outofplane_angle": "delta",
"detector_inplane_angle": "nu"
"sample_outofplane_angle": "eta",
"sample_inplane_angle": "phi",
"detector_outofplane_angle": "delta",
"detector_inplane_angle": "nu"
}

def __init__(
Expand Down Expand Up @@ -79,12 +78,7 @@ def load_detector_data(
+ f".1/measurement/{self.detector_name}"
)

if roi is None:
roi = tuple(slice(None) for i in range(3))
elif len(roi) == 2:
roi = tuple([slice(None), roi[0], roi[1]])
elif all(isinstance(e, int) for e in roi):
roi = CroppingHandler.roi_list_to_slices(roi)
roi = self._check_roi(roi)

try:
if binning_along_axis0:
Expand Down
35 changes: 35 additions & 0 deletions cdiutils/load/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import numpy as np

from cdiutils.utils import CroppingHandler


class Loader:
"""A generic class for loaders."""
Expand Down Expand Up @@ -86,6 +88,39 @@ def _check_load(data_or_path: np.ndarray | str) -> np.ndarray:
"parameter provide a path, np.ndarray or leave it to None"
)

@staticmethod
def _check_roi(roi: tuple = None) -> tuple[slice]:
"""
Utility function to check if a region of interest (roi) was
parsed correctly.

Args:
roi (tuple, optional): the roi, a tuple of slices.
len = 2 or len = 3 if tuple of slices. len = 4 or
len = 6 if tuple of int. Defaults to None.

Raises:
ValueError: if roi does not correspond to tuple of slices
with len 2 or 3 or tuple of int wit len 4 or 6.

Returns:
tuple[slice]: the prepared roi.
"""
usage_text = (
"Wrong value for roi (roi={}), roi should be:\n"
"\t - either a tuple of slices with len = 2 or len = 3"
"\t - either a tuple of int with len = 4 or len = 6"
)
if roi is None:
return tuple(slice(None) for _ in range(3))
if len(roi) == 2 or len(roi) == 3:
if all(isinstance(e, slice) for e in roi):
return (slice(None), roi[0], roi[1])
if len(roi) == 4 or len(roi) == 6:
if all(isinstance(e, int) for e in roi):
return CroppingHandler.roi_list_to_slices(roi)
raise ValueError(usage_text.format(roi))

@staticmethod
def get_mask(
channel: int = None,
Expand Down
106 changes: 106 additions & 0 deletions cdiutils/load/nanomax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""
Loader for the Nanomax beamlien at MAXIV.
See:
https://www.maxiv.lu.se/beamlines-accelerators/beamlines/nanomax/
"""

import numpy as np

from cdiutils.load import Loader
from cdiutils.load.bliss import safe


class NanoMaxLoader(Loader):
"""
A class to handle loading/reading .h5 files that were created at the
NanoMax beamline.

Args:
experiment_file_path (str): path to the master file
used for the experiment.
detector_name (str): name of the detector.
sample_name (str, optional): name of the sample. Defaults
to None.
flat_field (np.ndarray | str, optional): flat field to
account for the non homogeneous counting of the
detector. Defaults to None.
alien_mask (np.ndarray | str, optional): array to mask the
aliens. Defaults to None.
"""

angle_names = {
"sample_outofplane_angle": "gontheta",
"sample_inplane_angle": "gonphi",
"detector_outofplane_angle": "delta",
"detector_inplane_angle": "nu"
}

def __init__(
self,
experiment_file_path: str,
detector_name: str = "eiger500k",
sample_name: str = None,
flat_field: np.ndarray | str = None,
alien_mask: np.ndarray | str = None,
**kwargs
) -> None:
"""
Initialise NanoMaxLoader with experiment data file path and
detector information.

Args:
experiment_file_path (str): path to the master file
used for the experiment.
detector_name (str): name of the detector.
sample_name (str, optional): name of the sample. Defaults
to None.
flat_field (np.ndarray | str, optional): flat field to
account for the non homogeneous counting of the
detector. Defaults to None.
alien_mask (np.ndarray | str, optional): array to mask the
aliens. Defaults to None.
"""
super(NanoMaxLoader, self).__init__(flat_field, alien_mask)
self.experiment_file_path = experiment_file_path
self.detector_name = detector_name
self.sample_name = sample_name

@safe
def load_detector_data(
self,
scan: int,
sample_name: str = None,
roi: tuple[slice] = None,
binning_along_axis0: int = None,
binnig_method: str = "sum"
) -> np.ndarray:
"""
Main method to load the detector data (collected intensity).

Args:
scan (int): the scan number you want to load the data from.
sample_name (str, optional): the sample name for this scan.
Only used if self.sample_name is None. Defaults to None.
roi (tuple[slice], optional): the region of interest of the
detector to load. Defaults to None.
binning_along_axis0 (int, optional): whether to bin the data
along the rocking curve axis. Defaults to None.
binnig_method (str, optional): the method employed for the
binning. It can be sum or "mean". Defaults to "sum".

Returns:
np.ndarray: the detector data.
"""
# # The self.h5file is initialised by the @safe decorator.
# h5file = self.h5file
# if sample_name is None:
# sample_name = self.sample_name

# # Where to find the data.
# key_path = (
# "_".join((sample_name, str(scan)))
# + f"/entry/measurement/{self.detector_name}"
# )

# roi = self._check_roi(roi)
pass
5 changes: 1 addition & 4 deletions cdiutils/load/p10.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,7 @@ def load_detector_data(
path = self._get_file_path(scan, sample_name)
key_path = "entry/data/data_000001"

if roi is None:
roi = tuple(slice(None) for i in range(3))
elif len(roi) == 2:
roi = tuple([slice(None), roi[0], roi[1]])
roi = self._check_roi(roi)

with silx.io.h5py_utils.File(path) as h5file:
if binning_along_axis0:
Expand Down
5 changes: 1 addition & 4 deletions cdiutils/load/sixs.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,7 @@ def load_detector_data(
path = self._get_file_path(scan, sample_name)
key_path = "com/scan_data/test_image"

if roi is None:
roi = tuple(slice(None) for i in range(3))
elif len(roi) == 2:
roi = tuple([slice(None), roi[0], roi[1]])
roi = self._check_roi(roi)

with silx.io.h5py_utils.File(path) as h5file:
if binning_along_axis0:
Expand Down
5 changes: 1 addition & 4 deletions cdiutils/load/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,7 @@ def load_detector_data(
roi: tuple[slice] = None,
binning_along_axis0=None
):
if roi is None:
roi = tuple(slice(None) for i in range(3))
elif len(roi) == 2:
roi = tuple([slice(None), roi[0], roi[1]])
roi = self._check_roi(roi)

# TODO: implement flat_field consideration and binning_along_axis0
frame_ids = specfile[f"{scan}.1/measurement/{self.detector_name}"][...]
Expand Down
2 changes: 1 addition & 1 deletion cdiutils/plot/formatting.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get_extents(
to the y-axis extent in the matshow/imshow plot.
"""
absolute_extents = [
voxel_size[i] * shape[i] // (2 if zero_centered else 1)
voxel_size[i] * shape[i] / (2 if zero_centered else 1)
for i in range(3)
]
return (
Expand Down
2 changes: 1 addition & 1 deletion cdiutils/process/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"support_update_period": 20,
"support_smooth_width_begin": 2,
"support_smooth_width_end": 1,
"support_post_expand": None,
"support_post_expand": None, # (-1, 1)
"psf": "pseudo-voigt,0.5,0.1,10",
"nb_raar": 500,
"nb_hio": 300,
Expand Down
2 changes: 1 addition & 1 deletion cdiutils/process/phaser.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@
# support-related params
"support_threshold": (0.15, 0.40),
"smooth_width": (2, 0.5, 600),
"post_expand": None, # (-1, 1)
"support_update_period": 50,
"post_expand": (1, -2, 1),
"method": "rms",
"force_shrink": False,
"update_border_n": 0,
Expand Down