# encoding: utf-8
#
# Project: MXCuBE
# https://github.com/mxcube
#
# This file is part of MXCuBE software.
#
# MXCuBE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# MXCuBE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with MXCuBE. If not, see <http://www.gnu.org/licenses/>.
"""
AbstractBeam class - methods to define the size and shape of the beam.
emits:
- beamSizeChanged (self._beam_width, self._beam_height)
- beamInfoChanged (self._beam_info_dict.copy())
"""
__copyright__ = """ Copyright © by MXCuBE Collaboration """
__license__ = "LGPLv3+"
import abc
import sys
from warnings import warn
from enum import Enum, unique
from mxcubecore.BaseHardwareObjects import HardwareObject
[docs]@unique
class BeamShape(Enum):
"""Beam shape definitions"""
UNKNOWN = "unknown"
RECTANGULAR = "rectangular"
ELLIPTICAL = "ellipse"
[docs]class AbstractBeam(HardwareObject):
"""AbstractBeam class"""
__metaclass__ = abc.ABCMeta
def __init__(self, name):
super().__init__(name)
self._aperture = None
self._slits = None
self._definer = None
self._definer_type = None
self._beam_size_dict = {
"aperture": [sys.float_info.max, sys.float_info.max],
"slits": [sys.float_info.max, sys.float_info.max],
"definer": [sys.float_info.max, sys.float_info.max],
}
self._beam_width = None
self._beam_height = None
self._beam_shape = BeamShape.UNKNOWN
self._beam_label = None
self._beam_divergence = (None, None)
self._beam_position_on_screen = [None, None]
self._beam_info_dict = {
"size_x": self._beam_width,
"size_y": self._beam_height,
"shape": self._beam_shape,
"label": self._beam_label,
}
[docs] def init(self):
"""
Initialise default values and objects
"""
super().init()
_divergence_vertical = self.get_property("beam_divergence_vertical")
_divergence_horizontal = self.get_property("beam_divergence_horizontal")
self._beam_divergence = (_divergence_horizontal, _divergence_vertical)
self._beam_position_on_screen = [0, 0]
self._definer_type = self.get_property("definer_type")
@property
def aperture(self):
"""
Returns aperture hwobj
"""
return self._aperture
@property
def slits(self):
"""
Returns slits hwobj
"""
return self._slits
@property
def definer(self):
"""
Beam definer device, equipment like focusing optics, CRLs, and etc.
"""
return self._definer
[docs] def get_beam_divergence(self):
"""Get the beam divergence.
Returns:
(tuple): Beam divergence (horizontal, vertical) [μm]
"""
return self._beam_divergence
[docs] def get_available_size(self):
"""Get the available beam definers configuration.
Returns:
(dict): Dictionary {"type": (list), "values": (list)}, where
"type": the definer type ("aperture", "slits","definer")
"values": List of available beam size difinitions,
according to the "type".
Raises:
NotImplementedError
"""
raise NotImplementedError
[docs] def get_defined_beam_size(self):
"""Get the predefined beam labels and size.
Returns:
(dict): Dictionary wiith list of avaiable beam size labels
and the corresponding size (width,height) tuples.
{"label": [str, str, ...], "size": [(w,h), (w,h), ...]}
Raises:
NotImplementedError
"""
raise NotImplementedError
[docs] def get_beam_shape(self):
"""
Returns:
beam_shape: Enum BeamShape
"""
self.evaluate_beam_info()
return self._beam_shape
[docs] def get_beam_size(self):
"""
Returns:
(tuple): two floats
"""
self.evaluate_beam_info()
return self._beam_width, self._beam_height
[docs] def set_value(self, size=None):
"""Set the beam size.
Args:
size (list): Width, heigth [um] or
(str): Aperture or definer name.
Raises:
NotImplementedError
"""
raise NotImplementedError
[docs] def set_beam_size_shape(self, beam_width, beam_height, beam_shape):
"""
Sets beam size and shape
Args:
beam_width (float): requested beam width in microns
beam_height (float): requested beam height in microns
beam_shape (BeamShape enum): requested beam shape
"""
warn(
"set_beam_size_shape is deprecated. Use set_value() instead",
DeprecationWarning,
)
if beam_shape == BeamShape.RECTANGULAR:
self._slits.set_horizontal_gap(beam_width)
self._slits.set_vertical_gap(beam_height)
elif beam_shape == BeamShape.ELLIPTICAL:
self._aperture.set_diameter_size(beam_width)
[docs] def get_beam_position_on_screen(self):
"""Get the beam position
Returns:
(tuple): Position (x, y) [pixel]
"""
# (TODO) move this method to AbstractSampleView
return self._beam_position_on_screen
[docs] def set_beam_position_on_screen(self, beam_x_y):
"""Set the beam position
Returns:
beam_x_y (tuple): Position (x, y) [pixel]
"""
raise NotImplementedError
[docs] def get_beam_info_dict(self):
"""
Returns:
(dict): copy of beam_info_dict
"""
return self._beam_info_dict.copy()
[docs] def evaluate_beam_info(self):
"""
Method called if aperture, slits or focusing has been changed.
Evaluates which of the beam size defining devices determins the size.
Returns:
(dict): Beam info dictionary (dict), type of the definer (str).
{size_x: float, size_y: float,
shape: BeamShape enum, label: str},
"""
_shape = BeamShape.UNKNOWN
_size = min(self._beam_size_dict.values())
key = [k for k, v in self._beam_size_dict.items() if v == _size]
if len(key) == 1:
_label = key[0]
else:
if self._definer_type in key:
_label = self._definer_type
else:
_label = "UNKNOWN"
if _label == "slits":
_shape = BeamShape.RECTANGULAR
else:
_shape = BeamShape.ELLIPTICAL
self._beam_width = _size[0]
self._beam_height = _size[1]
self._beam_shape = _shape
self._beam_info_dict["size_x"] = _size[0]
self._beam_info_dict["size_y"] = _size[1]
self._beam_info_dict["shape"] = _shape
self._beam_info_dict["label"] = _label
return self._beam_info_dict
[docs] def re_emit_values(self):
"""
Reemits beamSizeChanged and beamInfoChanged signals
"""
HardwareObject.re_emit_values(self)
if self._beam_width != 9999 and self._beam_height != 9999:
self.emit("beamSizeChanged", (self._beam_width, self._beam_height))
self.emit("beamInfoChanged", (self._beam_info_dict))
self.emit("beamPosChanged", (self._beam_position_on_screen,))