Skip to content

Commit

Permalink
Add files to staged
Browse files Browse the repository at this point in the history
  • Loading branch information
shihab-dls committed Jan 22, 2025
1 parent ebb5e2c commit 8fa3ad9
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
61 changes: 61 additions & 0 deletions src/ophyd_async/epics/eiger/det_dist_to_beam_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from enum import Enum

from numpy import interp, loadtxt


class Axis(Enum):
X_AXIS = 1
Y_AXIS = 2


class DetectorDistanceToBeamXYConverter:
def __init__(self, lookup_file: str):
self.lookup_file: str = lookup_file
self.lookup_table_values: list = self.parse_table()

def get_beam_xy_from_det_dist(self, det_dist_mm: float, beam_axis: Axis) -> float:
beam_axis_values = self.lookup_table_values[beam_axis.value]
det_dist_array = self.lookup_table_values[0]
return float(interp(det_dist_mm, det_dist_array, beam_axis_values))

def get_beam_axis_pixels(
self,
det_distance: float,
image_size_pixels: int,
det_dim: float,
beam_axis: Axis,
) -> float:
beam_mm = self.get_beam_xy_from_det_dist(det_distance, beam_axis)
return beam_mm * image_size_pixels / det_dim

def get_beam_y_pixels(
self, det_distance: float, image_size_pixels: int, det_dim: float
) -> float:
return self.get_beam_axis_pixels(
det_distance, image_size_pixels, det_dim, Axis.Y_AXIS
)

def get_beam_x_pixels(
self, det_distance: float, image_size_pixels: int, det_dim: float
) -> float:
return self.get_beam_axis_pixels(
det_distance, image_size_pixels, det_dim, Axis.X_AXIS
)

def reload_lookup_table(self):
self.lookup_table_values = self.parse_table()

def parse_table(self) -> list:
rows = loadtxt(self.lookup_file, delimiter=" ", comments=["#", "Units"])
columns = list(zip(*rows, strict=False))

return columns

def __eq__(self, other):
if not isinstance(other, DetectorDistanceToBeamXYConverter):
return NotImplemented
if self.lookup_file != other.lookup_file:
return False
if self.lookup_table_values != other.lookup_table_values:
return False
return True
106 changes: 106 additions & 0 deletions tests/epics/eiger/test_beam_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from unittest.mock import Mock, patch

import pytest

from ophyd_async.epics.eiger.det_dist_to_beam_converter import (
Axis,
DetectorDistanceToBeamXYConverter,
)

LOOKUP_TABLE_TEST_VALUES = [(100.0, 200.0), (150.0, 151.0), (160.0, 165.0)]


@pytest.fixture
def fake_converter():
with patch.object(
DetectorDistanceToBeamXYConverter,
"parse_table",
return_value=LOOKUP_TABLE_TEST_VALUES,
):
yield DetectorDistanceToBeamXYConverter("test.txt")


def test_converter_eq():
test_file = "tests/epics/eiger/test_lookup_table.txt"
test_converter = DetectorDistanceToBeamXYConverter(test_file)
test_converter_dupe = DetectorDistanceToBeamXYConverter(test_file)
test_file_2 = "tests/epics/eiger/test_lookup_table_2.txt"
test_converter_2 = DetectorDistanceToBeamXYConverter(test_file_2)
assert test_converter != 1
assert test_converter == test_converter_dupe
assert test_converter != test_converter_2
previous_value = test_converter_dupe.lookup_table_values[0]
test_converter_dupe.lookup_table_values[0] = (7.5, 23.5)
assert test_converter != test_converter_dupe
test_converter_dupe.lookup_table_values[0] = previous_value


@pytest.mark.parametrize(
"detector_distance, axis, expected_value",
[
(100.0, Axis.Y_AXIS, 160.0),
(200.0, Axis.X_AXIS, 151.0),
(150.0, Axis.X_AXIS, 150.5),
(190.0, Axis.Y_AXIS, 164.5),
],
)
def test_interpolate_beam_xy_from_det_distance(
fake_converter: DetectorDistanceToBeamXYConverter,
detector_distance: float,
axis: Axis,
expected_value: float,
):
assert isinstance(
fake_converter.get_beam_xy_from_det_dist(detector_distance, axis), float
)

assert (
fake_converter.get_beam_xy_from_det_dist(detector_distance, axis)
== expected_value
)


def test_get_beam_in_pixels(fake_converter: DetectorDistanceToBeamXYConverter):
detector_distance = 100.0
image_size_pixels = 100
detector_dimensions = 200.0
interpolated_x_value = 150.0
interpolated_y_value = 160.0

def mock_callback(dist: float, axis: Axis):
match axis:
case Axis.X_AXIS:
return interpolated_x_value
case Axis.Y_AXIS:
return interpolated_y_value

fake_converter.get_beam_xy_from_det_dist = Mock()
fake_converter.get_beam_xy_from_det_dist.side_effect = mock_callback
expected_y_value = interpolated_y_value * image_size_pixels / detector_dimensions
expected_x_value = interpolated_x_value * image_size_pixels / detector_dimensions

calculated_y_value = fake_converter.get_beam_y_pixels(
detector_distance, image_size_pixels, detector_dimensions
)

assert calculated_y_value == expected_y_value
assert (
fake_converter.get_beam_x_pixels(
detector_distance, image_size_pixels, detector_dimensions
)
== expected_x_value
)


def test_parse_table():
test_file = "tests/epics/eiger/test_lookup_table.txt"
test_converter = DetectorDistanceToBeamXYConverter(test_file)

assert test_converter.lookup_file == test_file
assert test_converter.lookup_table_values == LOOKUP_TABLE_TEST_VALUES
assert test_converter.parse_table() == LOOKUP_TABLE_TEST_VALUES

test_converter.reload_lookup_table()

assert test_converter.lookup_file == test_file
assert test_converter.lookup_table_values == LOOKUP_TABLE_TEST_VALUES
5 changes: 5 additions & 0 deletions tests/epics/eiger/test_lookup_table_2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Beam converter lookup table for testing

Units det_dist beam_x beam_y
100.0 150.0 160.0
200.0 151.0 165.0

0 comments on commit 8fa3ad9

Please sign in to comment.