From 5d1ef9c6921ccd1c520a335f0a7fc0f15accff52 Mon Sep 17 00:00:00 2001 From: Saransh Singh Date: Mon, 16 Dec 2024 15:00:12 -0800 Subject: [PATCH 1/3] Fix x-ray propagation sign to always be positive Signed-off-by: Patrick Avery --- hexrdgui/calibration/cartesian_plot.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hexrdgui/calibration/cartesian_plot.py b/hexrdgui/calibration/cartesian_plot.py index 1b329e5d8..9a25d769f 100644 --- a/hexrdgui/calibration/cartesian_plot.py +++ b/hexrdgui/calibration/cartesian_plot.py @@ -22,6 +22,8 @@ def cartesian_viewer(): return InstrumentViewer() +def get_xray_propagation_sign(instr): + return np.sign(instr.beam_vector[2]) class InstrumentViewer: @@ -40,7 +42,8 @@ def __init__(self): self.detector_corners = {} dist = HexrdConfig().cartesian_virtual_plane_distance - dplane_tvec = np.array([0., 0., -dist]) + sgn = get_xray_propagation_sign(self.instr) + dplane_tvec = np.array([0., 0., sgn*dist]) rotate_x = HexrdConfig().cartesian_plane_normal_rotate_x rotate_y = HexrdConfig().cartesian_plane_normal_rotate_y From 38f7d64fcc728800b80ef3440a733d9f8de05ab2 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 18 Dec 2024 15:19:10 -0600 Subject: [PATCH 2/3] Require cartesian distance to be positive It is expected to always be positive now, so enforce this in the GUI, and handle old settings where it may have been negative. Signed-off-by: Patrick Avery --- hexrdgui/hexrd_config.py | 21 +++++++++++++++++---- hexrdgui/image_mode_widget.py | 3 +++ hexrdgui/resources/ui/image_mode_widget.ui | 5 ++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/hexrdgui/hexrd_config.py b/hexrdgui/hexrd_config.py index 8f8afe5b4..2ba5c2b5f 100644 --- a/hexrdgui/hexrd_config.py +++ b/hexrdgui/hexrd_config.py @@ -535,6 +535,12 @@ def load_from_state(self, state): pinhole_settings.pop('pinhole_radius') * 2 ) + if self.cartesian_virtual_plane_distance < 0: + # We used to allow this to be negative, but now must be positive. + # Taking the absolute value should correct this adequately. + self.cartesian_virtual_plane_distance = abs( + self.cartesian_virtual_plane_distance) + # All QSettings come back as strings. So check that we are dealing with # a boolean and convert if necessary if not isinstance(self.live_update, bool): @@ -2511,7 +2517,8 @@ def _cartesian_pixel_size(self): def _set_cartesian_pixel_size(self, v): if v != self.cartesian_pixel_size: self.config['image']['cartesian']['pixel_size'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_pixel_size = property(_cartesian_pixel_size, _set_cartesian_pixel_size) @@ -2520,9 +2527,13 @@ def _cartesian_virtual_plane_distance(self): return self.config['image']['cartesian']['virtual_plane_distance'] def set_cartesian_virtual_plane_distance(self, v): + if v < 0: + raise RuntimeError(f'Invalid plane distance: {v}') + if v != self.cartesian_virtual_plane_distance: self.config['image']['cartesian']['virtual_plane_distance'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_virtual_plane_distance = property( _cartesian_virtual_plane_distance, @@ -2534,7 +2545,8 @@ def _cartesian_plane_normal_rotate_x(self): def set_cartesian_plane_normal_rotate_x(self, v): if v != self.cartesian_plane_normal_rotate_x: self.config['image']['cartesian']['plane_normal_rotate_x'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_plane_normal_rotate_x = property( _cartesian_plane_normal_rotate_x, @@ -2546,7 +2558,8 @@ def _cartesian_plane_normal_rotate_y(self): def set_cartesian_plane_normal_rotate_y(self, v): if v != self.cartesian_plane_normal_rotate_y: self.config['image']['cartesian']['plane_normal_rotate_y'] = v - self.rerender_needed.emit() + if self.image_mode == constants.ViewType.cartesian: + self.rerender_needed.emit() cartesian_plane_normal_rotate_y = property( _cartesian_plane_normal_rotate_y, diff --git a/hexrdgui/image_mode_widget.py b/hexrdgui/image_mode_widget.py index 6fa540285..cf1f833c3 100644 --- a/hexrdgui/image_mode_widget.py +++ b/hexrdgui/image_mode_widget.py @@ -40,6 +40,9 @@ def __init__(self, parent=None): # Always start with raw tab self.ui.tab_widget.setCurrentIndex(0) + # Don't allow negative distances + self.ui.cartesian_virtual_plane_distance.setMinimum(1e-8) + # Hide stereo_project_from_polar for now, as projecting from polar # appears to give a better image (lines up better with overlays) # than projecting from raw. diff --git a/hexrdgui/resources/ui/image_mode_widget.ui b/hexrdgui/resources/ui/image_mode_widget.ui index fa96859e7..051cb5f0f 100644 --- a/hexrdgui/resources/ui/image_mode_widget.ui +++ b/hexrdgui/resources/ui/image_mode_widget.ui @@ -38,7 +38,7 @@ QTabWidget::Rounded - 2 + 1 @@ -167,6 +167,9 @@ 8 + + 0.000000000000000 + 1000000.000000000000000 From d38e5a7ed49d71d62ae66a1f71cea0882a74ce39 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 18 Dec 2024 15:33:21 -0600 Subject: [PATCH 3/3] Set invalid pixels in cartesian view to nan This sets pixels to nan that are either: 1. Part of a detector's panel buffer 2. Not located on any detector This is important for making FIDDLE images appear nice. Signed-off-by: Patrick Avery --- hexrdgui/calibration/cartesian_plot.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/hexrdgui/calibration/cartesian_plot.py b/hexrdgui/calibration/cartesian_plot.py index 9a25d769f..45548722d 100644 --- a/hexrdgui/calibration/cartesian_plot.py +++ b/hexrdgui/calibration/cartesian_plot.py @@ -31,6 +31,10 @@ def __init__(self): self.type = ViewType.cartesian self.instr = create_hedm_instrument() self.images_dict = HexrdConfig().images_dict + + # Set invalid pixels to be nan + HexrdConfig().apply_panel_buffer_to_images(self.images_dict) + self.img = None # Perform some checks before proceeding @@ -283,8 +287,15 @@ def create_warped_image(self, detector_id): res = tf.warp(img, tform3, output_shape=(self.dpanel.rows, self.dpanel.cols), - preserve_range=True) - self.warp_dict[detector_id] = res + preserve_range=True, cval=np.nan) + nan_mask = np.isnan(res) + + self.warp_dict[detector_id] = np.ma.masked_array( + res, + mask=nan_mask, + fill_value=0, + ) + return res @property @@ -293,8 +304,15 @@ def display_img(self): def generate_image(self): img = np.zeros((self.dpanel.rows, self.dpanel.cols)) + always_nan = np.ones(img.shape, dtype=bool) for key in self.images_dict.keys(): - img += self.warp_dict[key] + # Use zeros when summing, but identify pixels that + # are nans in all images and set those to nan. + warp_img = self.warp_dict[key] + img += warp_img.filled(0) + always_nan = np.logical_and(always_nan, warp_img.mask) + + img[always_nan] = np.nan # In case there were any nans... nan_mask = np.isnan(img)