Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 69 additions & 19 deletions hexrdgui/calibration/panel_buffer_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@
import matplotlib.pyplot as plt
import numpy as np

from hexrd.utils.panel_buffer import (
panel_buffer_from_str,
valid_panel_buffer_names,
)

from hexrdgui.create_hedm_instrument import create_hedm_instrument
from hexrdgui.hexrd_config import HexrdConfig
from hexrdgui.ui_loader import UiLoader
from hexrdgui.utils import block_signals
from hexrdgui.utils.dialog import add_help_url

CONFIG_MODE_BORDER = 'border'
CONFIG_MODE_NUMPY = 'numpy'
CONFIG_MODE_NAME = 'name'


class PanelBufferDialog(QObject):
Expand Down Expand Up @@ -41,6 +48,7 @@ def __init__(self, detector, parent=None):
# Hide the tab bar. It gets selected by changes to the combo box.
self.ui.tab_widget.tabBar().hide()
self.setup_combo_box_data()
self.setup_valid_names()

self.update_gui()

Expand All @@ -58,11 +66,17 @@ def setup_connections(self):
def setup_combo_box_data(self):
item_data = [
CONFIG_MODE_BORDER,
CONFIG_MODE_NUMPY
CONFIG_MODE_NUMPY,
CONFIG_MODE_NAME,
]
for i, data in enumerate(item_data):
self.ui.config_mode.setItemData(i, data)

def setup_valid_names(self):
w = self.ui.selected_name
w.clear()
w.addItems(valid_panel_buffer_names())

def show(self):
self.ui.show()

Expand Down Expand Up @@ -114,13 +128,16 @@ def widgets(self):
return [
self.ui.file_name,
self.ui.border_x_spinbox,
self.ui.border_y_spinbox
self.ui.border_y_spinbox,
self.ui.selected_name,
]

@property
def current_editing_buffer_value(self):
if self.mode == CONFIG_MODE_BORDER:
return [self.x_border, self.y_border]
elif self.mode == CONFIG_MODE_NAME:
return self.ui.selected_name.currentText()
elif self.file_name == '':
# Just return the currently saved buffer
return copy.deepcopy(self.current_saved_buffer_value)
Expand Down Expand Up @@ -165,25 +182,49 @@ def update_config(self):

self.detector_config['buffer'] = value

if isinstance(value, str):
# Check if this has ROIs and a group
# If so, ask if the user wants to apply this setting
# to all detectors in this group.
group = HexrdConfig().detector_group(self.detector)
if HexrdConfig().instrument_has_roi and group:
det_keys = HexrdConfig().detectors_in_group(group)
if len(det_keys) > 1:
title = 'Apply to Other Detectors?'
msg = (
f'Set panel buffer "{value}" to all '
f'detectors in the group "{group}"?'
)
response = QMessageBox.question(self.ui, title, msg)
if response == QMessageBox.Yes:
for det_key in det_keys:
config = HexrdConfig().detector(det_key)
config['buffer'] = value

return True

def update_gui(self):
with block_signals(*self.widgets):
if 'buffer' in self.detector_config:
buffer = np.asarray(self.detector_config['buffer'])
buffer = self.detector_config['buffer']
if isinstance(buffer, str):
self.mode = CONFIG_MODE_NAME
self.ui.selected_name.setCurrentText(buffer)
else:
buffer = np.asarray(buffer)

if buffer.size in (1, 2):
self.mode = CONFIG_MODE_BORDER
if np.array_equal(buffer, None):
buffer = np.asarray([0])
if buffer.size in (1, 2):
self.mode = CONFIG_MODE_BORDER
if np.array_equal(buffer, None):
buffer = np.asarray([0])

if buffer.size == 1:
buffer = [buffer.item()] * 2
if buffer.size == 1:
buffer = [buffer.item()] * 2

self.ui.border_x_spinbox.setValue(buffer[0])
self.ui.border_y_spinbox.setValue(buffer[1])
else:
self.mode = CONFIG_MODE_NUMPY
self.ui.border_x_spinbox.setValue(buffer[0])
self.ui.border_y_spinbox.setValue(buffer[1])
else:
self.mode = CONFIG_MODE_NUMPY

self.update_mode_tab()

Expand All @@ -209,8 +250,11 @@ def update_mode_tab(self):
self.update_enable_states()

def update_enable_states(self):
buffer = np.asarray(self.current_editing_buffer_value)
has_numpy_array = buffer.size > 2
has_numpy_array = False
if not isinstance(self.current_editing_buffer_value, str):
buffer = np.asarray(self.current_editing_buffer_value)
has_numpy_array = buffer.size > 2

self.ui.show_panel_buffer.setEnabled(has_numpy_array)

def clear_panel_buffer(self):
Expand All @@ -224,10 +268,16 @@ def default_buffer(self):
return [0., 0.]

def show_panel_buffer(self):
buffer = np.asarray(self.current_editing_buffer_value)
if buffer.size <= 2:
# We only support showing numpy array buffers currently
return
buffer = self.current_editing_buffer_value
if isinstance(buffer, str):
instr = create_hedm_instrument()
panel = instr.detectors[self.detector]
buffer = panel_buffer_from_str(buffer, panel)
else:
buffer = np.asarray(buffer)
if buffer.size <= 2:
# We only support showing numpy array buffers currently
return

fig, ax = plt.subplots()
fig.canvas.manager.set_window_title(f'{self.detector}')
Expand Down
22 changes: 22 additions & 0 deletions hexrdgui/hexrd_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from hexrd.material import load_materials_hdf5, save_materials_hdf5, Material
from hexrd.rotations import angleAxisOfRotMat, RotMatEuler, rotMatOfExpMap
from hexrd.utils.decorators import memoize
from hexrd.utils.panel_buffer import panel_buffer_from_str
from hexrd.utils.yaml import NumpyToNativeDumper
from hexrd.valunits import valWUnit

Expand Down Expand Up @@ -1699,6 +1700,15 @@ def detector_group(self, detector_name):
det = self.detector(detector_name)
return det.get('group', {})

def detectors_in_group(self, group: str) -> list[str]:
names = []
for det_key in self.detectors:
this_group = self.detector_group(det_key)
if this_group == group:
names.append(det_key)

return names

def detector_pixel_size(self, detector_name):
detector = self.detector(detector_name)
return detector.get('pixels', {}).get('size', [0.1, 0.1])
Expand Down Expand Up @@ -3061,11 +3071,23 @@ def recent_images(self, images):
def clean_panel_buffers(self):
# Ensure that the panel buffer sizes match the pixel sizes.
# If not, clear the panel buffer and print a warning.
instr = None
for name, det_info in self.detectors.items():
buffer = det_info.get('buffer')
if buffer is None:
continue

if isinstance(buffer, str):
if instr is None:
# This instrument is not fully set up properly like
# the one from `create_hedm_instrument()` is, but it
# has the shape and roi set up properly, which are
# needed for the function.
iconfig = self.instrument_config_none_euler_convention
instr = HEDMInstrument(instrument_config=iconfig)

buffer = panel_buffer_from_str(buffer, instr.detectors[name])

buffer = np.asarray(buffer)
if buffer.ndim == 1:
continue
Expand Down
13 changes: 9 additions & 4 deletions hexrdgui/image_file_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,25 @@ def open_file(self, f, options=None):
elif ext in self.HDF5_FILE_EXTS:
regular_hdf5 = True
with h5py.File(f, 'r') as data:
eiger_stream_format = None
if data.attrs.get('version') == 'CHESS_EIGER_STREAM_V1':
ims_type = 'eiger-stream-v1'
eiger_stream_format = 'eiger-stream-v1'
elif data.attrs.get('version') == 'CHESS_EIGER_STREAM_V2':
eiger_stream_format = 'eiger-stream-v2'

if eiger_stream_format is not None:
registry = (
imageseries.load.registry.Registry.adapter_registry
)
if ims_type not in registry:
if eiger_stream_format not in registry:
msg = (
'"dectris-compression" must be installed to load '
'eiger stream files.\n\n'
'Try `pip install dectris-compression`'
)
raise Exception(msg)

ims = imageseries.open(f, 'eiger-stream-v1')
ims = imageseries.open(f, eiger_stream_format)
regular_hdf5 = False
else:
dset = data['/'.join(self.path)]
Expand Down Expand Up @@ -251,7 +256,7 @@ def hdf_path_exists(self, f):
def hdf5_path_exists(self, f):
# If it is a special HDF5 file, just return True
with h5py.File(f, 'r') as rf:
if rf.attrs.get('version') == 'CHESS_EIGER_STREAM_V1':
if rf.attrs.get('version', '').startswith('CHESS_EIGER_STREAM'):
return True

all_paths = []
Expand Down
104 changes: 102 additions & 2 deletions hexrdgui/image_mode_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from PySide6.QtCore import QEvent, QObject, QTimer, Signal
from PySide6.QtWidgets import QApplication

from hexrd.imageseries import ImageSeries

from hexrdgui.azimuthal_overlay_manager import AzimuthalOverlayManager
from hexrdgui.constants import PolarXAxisType, ViewType
from hexrdgui.create_hedm_instrument import create_hedm_instrument
Expand Down Expand Up @@ -55,6 +57,7 @@ def __init__(self, parent=None):
# FIXME: why is projecting from raw different?
self.ui.stereo_project_from_polar.setVisible(False)

self.setup_eiger_stream_v2_options()
self.setup_connections()
self.update_gui_from_config()

Expand All @@ -67,6 +70,10 @@ def setup_connections(self):
HexrdConfig().set_stitch_raw_roi_images)
self.ui.raw_show_zoom_dialog.clicked.connect(
self.raw_show_zoom_dialog)
self.ui.eiger_stream_v2_setting.currentIndexChanged.connect(
self.on_eiger_stream_v2_settings_modified)
self.ui.eiger_stream_v2_multiplier.valueChanged.connect(
self.on_eiger_stream_v2_settings_modified)
self.ui.cartesian_pixel_size.valueChanged.connect(
HexrdConfig()._set_cartesian_pixel_size)
self.ui.cartesian_virtual_plane_distance.valueChanged.connect(
Expand Down Expand Up @@ -153,7 +160,80 @@ def setup_connections(self):
HexrdConfig().set_stereo_project_from_polar)

ImageLoadManager().new_images_loaded.connect(
self.update_visibility_states)
self.on_new_images_loaded)

def setup_eiger_stream_v2_options(self):
combo = self.ui.eiger_stream_v2_setting
combo.clear()

options = {
'Threshold 1': 'threshold_1',
'Threshold 2': 'threshold_2',
'Difference': 'man_diff',
}
for k, v in options.items():
combo.addItem(k, v)

def on_new_images_loaded(self):
self.update_visibility_states()
self.update_eiger_stream_v2_settings()

def update_eiger_stream_v2_settings(self):
ims_dict = HexrdConfig().imageseries_dict

# We assume that all imageseries have the same options set
visible = False
if ims_dict:
ims = next(iter(ims_dict.values()))
visible = _is_eiger_stream_v2(ims)

self.ui.eiger_stream_v2_group.setVisible(visible)

if not visible:
# Nothing else to do
return

settings = ims.option_values()
w = self.ui.eiger_stream_v2_setting
idx = w.findData(settings['threshold_setting'])
if idx != -1:
with block_signals(w):
w.setCurrentIndex(idx)

mult_enabled = w.currentData() == 'man_diff'
mult_widgets = [
self.ui.eiger_stream_v2_multiplier_label,
self.ui.eiger_stream_v2_multiplier,
]
for w in mult_widgets:
w.setEnabled(mult_enabled)

w = self.ui.eiger_stream_v2_multiplier
with block_signals(w):
w.setValue(settings['multiplier'])

def on_eiger_stream_v2_settings_modified(self):
ims_dict = HexrdConfig().imageseries_dict

if (
not ims_dict or
not _is_eiger_stream_v2(next(iter(ims_dict.values())))
):
# This shouldn't have been triggered. Let's ignore it.
self.update_eiger_stream_v2_settings()
return

settings = {
'threshold_setting': self.ui.eiger_stream_v2_setting.currentData(),
'multiplier': self.ui.eiger_stream_v2_multiplier.value(),
}

for ims in ims_dict.values():
for k, v in settings.items():
ims.set_option(k, v)

# Trigger all the same logic as if we loaded new images
ImageLoadManager().new_images_loaded.emit()

def eventFilter(self, target, event):
if target is self.ui and event.type() == QEvent.Resize:
Expand Down Expand Up @@ -269,6 +349,7 @@ def update_gui_from_config(self):
self.update_enable_states()

self.update_visibility_states()
self.update_eiger_stream_v2_settings()

def update_enable_states(self):
apply_snip1d = self.ui.polar_apply_snip1d.isChecked()
Expand Down Expand Up @@ -370,7 +451,6 @@ def auto_generate_polar_params(self):
# Get the GUI to update with the new values
self.update_gui_from_config()


@property
def polar_apply_tth_distortion(self):
return self.ui.polar_apply_tth_distortion.isChecked()
Expand Down Expand Up @@ -589,3 +669,23 @@ def compute_polar_params(panel, max_tth_ps, max_eta_ps, min_tth, max_tth):
ptth, peta = panel.pixel_angles()
min_tth.append(np.degrees(np.min(ptth)))
max_tth.append(np.degrees(np.max(ptth)))


def _get_ims_format(ims: ImageSeries) -> str | None:
# If "None" is returned, the format could not be determined

# We have to recursively "dig" into the imageseries and adapters
# in order to find the original adapter.
adapter = ims
while hasattr(adapter, '_adapter') or hasattr(adapter, '_imser'):
if hasattr(adapter, '_adapter'):
adapter = adapter._adapter
else:
# ProcessedImageSeries have an '_imser' on them
adapter = adapter._imser

return getattr(adapter, 'format', None)


def _is_eiger_stream_v2(ims: ImageSeries) -> bool:
return _get_ims_format(ims) == 'eiger-stream-v2'
Loading
Loading