Skip to content

Commit

Permalink
Add ability to specify center of rotation
Browse files Browse the repository at this point in the history
For relative constraints, when tilts are applied to the detectors, the
center of rotation is an additional setting that can be varied.
Specifying a center of rotation that better matches what is expected in
the experiment will result in calibrations with greater accuracy and
speed.

For example, for FIDDLE, if there is any tilt whatsoever, then the
detectors must have rotated about the lab origin (0, 0, 0). Requiring
the detectors to be rotated about the origin ensures that the
calibration will match what is expected from the experiment.

For other detector setups, such as the Eiger, the mean center of the
instrument better matches what is expected if a tilt must be applied.

This PR also sets the default settings for FIDDLE calibration to use
instrument rigid body (system) constraints, as well as using the
Origin for the center of rotation.

Depends on: HEXRD/hexrd#735

Signed-off-by: Patrick Avery <[email protected]>
  • Loading branch information
psavery committed Dec 11, 2024
1 parent 83cd7ae commit 92dae39
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 31 deletions.
75 changes: 68 additions & 7 deletions hexrdgui/calibration/calibration_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
)
from hexrd.fitting.calibration.relative_constraints import (
RelativeConstraintsType,
RotationCenter,
)

from hexrdgui import resource_loader
Expand Down Expand Up @@ -42,6 +43,7 @@ class CalibrationDialog(QObject):
save_picks_clicked = Signal()
load_picks_clicked = Signal()
relative_constraints_changed = Signal(RelativeConstraintsType)
tilt_center_of_rotation_changed = Signal(RotationCenter)
engineering_constraints_changed = Signal(str)

pinhole_correction_settings_modified = Signal()
Expand Down Expand Up @@ -75,6 +77,7 @@ def __init__(self, instr, params_dict, format_extra_params_func=None,
self.on_pinhole_correction_settings_modified)

self.populate_relative_constraint_options()
self.populate_tilt_rotation_center_options()

self.instr = instr
self._params_dict = params_dict
Expand All @@ -84,12 +87,6 @@ def __init__(self, instr, params_dict, format_extra_params_func=None,

self._ignore_next_tree_view_update = False

instr_type = guess_instrument_type(instr.detectors)
# Use delta boundaries by default for anything other than TARDIS
# and PXRDIP. We might want to change this to a whitelist later.
use_delta_boundaries = instr_type not in ('TARDIS', 'PXRDIP')
self.delta_boundaries = use_delta_boundaries

self.initialize_advanced_options()

self.load_tree_view_mapping()
Expand All @@ -101,6 +98,7 @@ def __init__(self, instr, params_dict, format_extra_params_func=None,
self.update_visibility_states()

self.load_settings()
self.update_relative_constraint_visibilities()
self.setup_connections()

def setup_connections(self):
Expand All @@ -111,6 +109,8 @@ def setup_connections(self):
self.show_picks_from_all_xray_sources_toggled)
self.ui.relative_constraints.currentIndexChanged.connect(
self.on_relative_constraints_changed)
self.ui.tilt_center_of_rotation.currentIndexChanged.connect(
self.on_tilt_center_of_rotation_changed)
self.ui.engineering_constraints.currentIndexChanged.connect(
self.on_engineering_constraints_changed)
self.ui.delta_boundaries.toggled.connect(
Expand Down Expand Up @@ -150,7 +150,28 @@ def populate_relative_constraint_options(self):
w = self.ui.relative_constraints
w.clear()
for option in options:
w.addItem(option.value, option)
w.addItem(RELATIVE_CONSTRAINT_LABELS[option], option)

def populate_tilt_rotation_center_options(self):
# We are skipping group constraints until it is actually implemented
w = self.ui.tilt_center_of_rotation
w.clear()
for label in ROTATION_CENTER_LABELS.values():
w.addItem(label)

def set_instrument_defaults(self):
# This function should only be called after the Callbacks have been
# connected, because the changes here may also affect the Calibrator
# classes.
instr_type = guess_instrument_type(self.instr.detectors)
# Use delta boundaries by default for anything other than TARDIS
# and PXRDIP. We might want to change this to a whitelist later.
use_delta_boundaries = instr_type not in ('TARDIS', 'PXRDIP')
self.delta_boundaries = use_delta_boundaries

if instr_type == 'FIDDLE':
self.relative_constraints = RelativeConstraintsType.system
self.tilt_center_of_rotation = RotationCenter.lab_origin

def update_edit_picks_enable_state(self):
is_polar = HexrdConfig().image_mode == ViewType.polar
Expand Down Expand Up @@ -220,6 +241,16 @@ def update_visibility_states(self):
self.ui.active_beam_label.setVisible(has_multi_xrs)
self.ui.show_picks_from_all_xray_sources.setVisible(has_multi_xrs)

def update_relative_constraint_visibilities(self):
visible = self.relative_constraints != RelativeConstraintsType.none

tilt_center_widgets = [
self.ui.tilt_center_of_rotation,
self.ui.tilt_center_of_rotation_label,
]
for w in tilt_center_widgets:
w.setVisible(visible)

def on_draw_picks_toggled(self, b):
self.draw_picks_toggled.emit(b)

Expand Down Expand Up @@ -347,6 +378,19 @@ def relative_constraints(self, v: RelativeConstraintsType):

w.setCurrentText(v.value)

self.update_relative_constraint_visibilities()

@property
def tilt_center_of_rotation(self) -> RotationCenter:
w = self.ui.tilt_center_of_rotation
return ROTATION_CENTER_LABELS_R[w.currentText()]

@tilt_center_of_rotation.setter
def tilt_center_of_rotation(self, v: RotationCenter):
w = self.ui.tilt_center_of_rotation
text = ROTATION_CENTER_LABELS[v]
w.setCurrentText(text)

@property
def engineering_constraints(self):
return self.ui.engineering_constraints.currentText()
Expand Down Expand Up @@ -405,6 +449,10 @@ def on_relative_constraints_changed(self):

self.relative_constraints_changed.emit(self.relative_constraints)
self.reinitialize_tree_view()
self.update_relative_constraint_visibilities()

def on_tilt_center_of_rotation_changed(self):
self.tilt_center_of_rotation_changed.emit(self.tilt_center_of_rotation)

def on_engineering_constraints_changed(self):
self.engineering_constraints_changed.emit(self.engineering_constraints)
Expand Down Expand Up @@ -458,6 +506,9 @@ def mirror_constraints_from_first_detector(self):

def update_from_calibrator(self, calibrator):
self.relative_constraints = calibrator.relative_constraints_type
self.tilt_center_of_rotation = (
calibrator.relative_constraints.rotation_center
)
self.engineering_constraints = calibrator.engineering_constraints
self.tth_distortion = calibrator.tth_distortion
self.params_dict = calibrator.params
Expand Down Expand Up @@ -721,6 +772,16 @@ def tree_view_model_class(self):
('zxz', False): ('Z', "X'", "Z''"),
}

RELATIVE_CONSTRAINT_LABELS = {
RelativeConstraintsType.none: 'None',
RelativeConstraintsType.system: 'Instrument Rigid Body',
}
ROTATION_CENTER_LABELS = {
RotationCenter.instrument_mean_center: 'Mean Instrument Center',
RotationCenter.lab_origin: 'Origin',
}
ROTATION_CENTER_LABELS_R = {v: k for k, v in ROTATION_CENTER_LABELS.items()}


def guess_engineering_constraints(instr) -> str | None:
# First guess the instrument type.
Expand Down
17 changes: 17 additions & 0 deletions hexrdgui/calibration/calibration_dialog_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ def __init__(self, dialog, calibrator, instr, async_runner):
self.draw_picks()
self.setup_connections()

# Trigger the instrument defaults to be set on the dialog
self.dialog.set_instrument_defaults()

def setup_connections(self):
dialog = self.dialog

Expand All @@ -56,6 +59,8 @@ def setup_connections(self):
dialog.load_picks_clicked.connect(self.on_load_picks_clicked)
dialog.relative_constraints_changed.connect(
self.on_relative_constraints_changed)
dialog.tilt_center_of_rotation_changed.connect(
self.on_tilt_center_of_rotation_changed)
dialog.engineering_constraints_changed.connect(
self.on_engineering_constraints_changed)
dialog.run.connect(self.on_run_clicked)
Expand Down Expand Up @@ -163,8 +168,20 @@ def update_undo_enable_state(self):

def on_relative_constraints_changed(self, new_constraint):
self.calibrator.relative_constraints_type = new_constraint
# Reset the tilt center of rotation in the dialog
self.dialog.tilt_center_of_rotation = (
self.calibrator.relative_constraints.rotation_center
)
self.on_constraints_changed()

def on_tilt_center_of_rotation_changed(self, new_center):
relative_constraints = self.calibrator.relative_constraints
if relative_constraints.rotation_center != new_center:
# Some of the relative constraint types have a fixed getter
# for this, and no setter. We should avoid causing an exception
# if we are just setting it unnecessarily.
relative_constraints.rotation_center = new_center

def on_engineering_constraints_changed(self, new_constraint):
self.calibrator.engineering_constraints = new_constraint
self.on_constraints_changed()
Expand Down
7 changes: 7 additions & 0 deletions hexrdgui/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ class LLNLTransform:
'IMAGE-PLATE-R',
'IMAGE-PLATE-U',
],
'FIDDLE': [
'ic2',
'ic3',
'ic5',
'ic7',
'ic8',
],
}

KEY_ROTATE_ANGLE_FINE = 0.00175
Expand Down
2 changes: 1 addition & 1 deletion hexrdgui/hexrd_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3054,7 +3054,7 @@ def physics_package(self):
return self._physics_package

def update_physics_package(self, instr_type=None, **kwargs):
if instr_type is None:
if instr_type not in ('TARDIS', 'PXRDIP'):
self._physics_package = None
elif self.physics_package is None:
all_kwargs = PHYSICS_PACKAGE_DEFAULTS.HED
Expand Down
64 changes: 41 additions & 23 deletions hexrdgui/resources/ui/calibration_dialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,51 @@
<string>Constraints</string>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="0">
<widget class="QLabel" name="engineering_constraints_label">
<item row="0" column="0">
<widget class="QLabel" name="relative_constraints_label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add engineering constraints for certain instrument types. This may add extra parameters to the table.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;For example, for TARDIS, the distance between IMAGE-PLATE-2 and IMAGE-PLATE-4 must be within a certain range. If TARDIS is selected, a new parameter is added with default values for this distance.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If the instrument type can be guessed, it will be selected automatically when the dialog first appears. For example, TARDIS is automatically selected if any of the detector names are IMAGE-PLATE-2, IMAGE-PLATE-3, or IMAGE-PLATE-4.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Options to set relative constraints between the detectors.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;None&amp;quot; means no relative constraints.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;System&amp;quot; means all detectors are relatively constrained to one another. In this case, the mean center of the detectors and a mean tilt may be refined.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add engineering constraints for:</string>
<string>Relative constraints:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QCheckBox" name="delta_boundaries">
<property name="text">
<string>Use delta for boundaries</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="4" column="0" colspan="2">
<widget class="QPushButton" name="mirror_constraints_from_first_detector">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If clicked, the &amp;quot;Vary&amp;quot; and &amp;quot;Delta&amp;quot; (if &amp;quot;Use delta for boundaries&amp;quot; is checked) settings of the first detector's tilt/translation parameters will be copied to all other detectors' tilt/translation parameters.&lt;/p&gt;&lt;p&gt;This is helpful if you have many detectors and want to modify all of their &amp;quot;Vary&amp;quot; and &amp;quot;Delta&amp;quot; settings in a similar way.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Mirror Constraints from First Detector</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="relative_constraints">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Options to set relative constraints between the detectors.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;None&amp;quot; means no relative constraints.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;Instrument Rigid Body&amp;quot; means all detectors in the entire instrument are relatively constrained to one another. In this case, the mean center of the detectors and a mean tilt may be refined.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="engineering_constraints_label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add engineering constraints for certain instrument types. This may add extra parameters to the table.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;For example, for TARDIS, the distance between IMAGE-PLATE-2 and IMAGE-PLATE-4 must be within a certain range. If TARDIS is selected, a new parameter is added with default values for this distance.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If the instrument type can be guessed, it will be selected automatically when the dialog first appears. For example, TARDIS is automatically selected if any of the detector names are IMAGE-PLATE-2, IMAGE-PLATE-3, or IMAGE-PLATE-4.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add engineering constraints for:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="engineering_constraints">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Add engineering constraints for certain instrument types. This may add extra parameters to the table.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;For example, for TARDIS, the distance between IMAGE-PLATE-2 and IMAGE-PLATE-4 must be within a certain range. If TARDIS is selected, a new parameter is added with default values for this distance.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If the instrument type can be guessed, it will be selected automatically when the dialog first appears. For example, TARDIS is automatically selected if any of the detector names are IMAGE-PLATE-2, IMAGE-PLATE-3, or IMAGE-PLATE-4.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
Expand All @@ -54,30 +81,20 @@
</item>
</widget>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="mirror_constraints_from_first_detector">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If clicked, the &amp;quot;Vary&amp;quot; and &amp;quot;Delta&amp;quot; (if &amp;quot;Use delta for boundaries&amp;quot; is checked) settings of the first detector's tilt/translation parameters will be copied to all other detectors' tilt/translation parameters.&lt;/p&gt;&lt;p&gt;This is helpful if you have many detectors and want to modify all of their &amp;quot;Vary&amp;quot; and &amp;quot;Delta&amp;quot; settings in a similar way.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Mirror Constraints from First Detector</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="relative_constraints_label">
<item row="1" column="0">
<widget class="QLabel" name="tilt_center_of_rotation_label">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Options to set relative constraints between the detectors.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;None&amp;quot; means no relative constraints.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;System&amp;quot; means all detectors are relatively constrained to one another. In this case, the mean center of the detectors and a mean tilt may be refined.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The center of rotation to be used for tilt parameters when relative constraints are enabled.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;Mean Instrument Center&amp;quot; will cause the panels to be rotated about the mean center of the detectors when the tilt is modified.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;Origin&amp;quot; will cause the panels to be rotated about lab origin (i. e., [0, 0, 0]) when the tilt is modified.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Relative constraints:</string>
<string>Tilt center of rotation:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="relative_constraints">
<item row="1" column="1">
<widget class="QComboBox" name="tilt_center_of_rotation">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Options to set relative constraints between the detectors.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;None&amp;quot; means no relative constraints.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;System&amp;quot; means all detectors are relatively constrained to one another. In this case, the mean center of the detectors and a mean tilt may be refined.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The center of rotation to be used for tilt parameters when relative constraints are enabled.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;Mean Instrument Center&amp;quot; will cause the panels to be rotated about the mean center of the detectors when the tilt is modified.&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;&amp;quot;Origin&amp;quot; will cause the panels to be rotated about lab origin (i. e., [0, 0, 0]) when the tilt is modified.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -484,6 +501,7 @@ See scipy.optimize.least_squares for more details.</string>
<tabstop>active_beam</tabstop>
<tabstop>show_picks_from_all_xray_sources</tabstop>
<tabstop>relative_constraints</tabstop>
<tabstop>tilt_center_of_rotation</tabstop>
<tabstop>engineering_constraints</tabstop>
<tabstop>delta_boundaries</tabstop>
<tabstop>mirror_constraints_from_first_detector</tabstop>
Expand Down

0 comments on commit 92dae39

Please sign in to comment.