1010 normalize_euler_convention ,
1111 param_names_euler_convention ,
1212)
13+ from hexrd .fitting .calibration .relative_constraints import (
14+ RelativeConstraintsType ,
15+ )
1316
1417from hexrdgui import resource_loader
1518from hexrdgui .calibration .tree_item_models import (
@@ -38,6 +41,7 @@ class CalibrationDialog(QObject):
3841 edit_picks_clicked = Signal ()
3942 save_picks_clicked = Signal ()
4043 load_picks_clicked = Signal ()
44+ relative_constraints_changed = Signal (RelativeConstraintsType )
4145 engineering_constraints_changed = Signal (str )
4246
4347 pinhole_correction_settings_modified = Signal ()
@@ -47,8 +51,10 @@ class CalibrationDialog(QObject):
4751 finished = Signal ()
4852
4953 def __init__ (self , instr , params_dict , format_extra_params_func = None ,
50- parent = None , engineering_constraints = None ,
51- window_title = 'Calibration Dialog' , help_url = 'calibration/' ):
54+ parent = None , relative_constraints = None ,
55+ engineering_constraints = None ,
56+ window_title = 'Calibration Dialog' ,
57+ help_url = 'calibration/' ):
5258 super ().__init__ (parent )
5359
5460 loader = UiLoader ()
@@ -68,11 +74,16 @@ def __init__(self, instr, params_dict, format_extra_params_func=None,
6874 HexrdConfig ().physics_package_modified .connect (
6975 self .on_pinhole_correction_settings_modified )
7076
77+ self .populate_relative_constraint_options ()
78+
7179 self .instr = instr
7280 self ._params_dict = params_dict
7381 self .format_extra_params_func = format_extra_params_func
82+ self .relative_constraints = relative_constraints
7483 self .engineering_constraints = engineering_constraints
7584
85+ self ._ignore_next_tree_view_update = False
86+
7687 instr_type = guess_instrument_type (instr .detectors )
7788 # Use delta boundaries by default for anything other than TARDIS
7889 # and PXRDIP. We might want to change this to a whitelist later.
@@ -98,6 +109,8 @@ def setup_connections(self):
98109 self .on_active_beam_changed )
99110 self .ui .show_picks_from_all_xray_sources .toggled .connect (
100111 self .show_picks_from_all_xray_sources_toggled )
112+ self .ui .relative_constraints .currentIndexChanged .connect (
113+ self .on_relative_constraints_changed )
101114 self .ui .engineering_constraints .currentIndexChanged .connect (
102115 self .on_engineering_constraints_changed )
103116 self .ui .delta_boundaries .toggled .connect (
@@ -128,6 +141,17 @@ def hide(self):
128141 def load_settings (self ):
129142 pass
130143
144+ def populate_relative_constraint_options (self ):
145+ # We are skipping group constraints until it is actually implemented
146+ options = [
147+ RelativeConstraintsType .none ,
148+ RelativeConstraintsType .system ,
149+ ]
150+ w = self .ui .relative_constraints
151+ w .clear ()
152+ for option in options :
153+ w .addItem (option .value , option )
154+
131155 def update_edit_picks_enable_state (self ):
132156 is_polar = HexrdConfig ().image_mode == ViewType .polar
133157
@@ -308,6 +332,21 @@ def undo_enabled(self):
308332 def undo_enabled (self , b ):
309333 self .ui .undo_run_button .setEnabled (b )
310334
335+ @property
336+ def relative_constraints (self ) -> RelativeConstraintsType :
337+ ret = self .ui .relative_constraints .currentData ()
338+ return ret if ret is not None else RelativeConstraintsType .none
339+
340+ @relative_constraints .setter
341+ def relative_constraints (self , v : RelativeConstraintsType ):
342+ v = v if v is not None else RelativeConstraintsType .none
343+ w = self .ui .relative_constraints
344+ options = [w .itemText (i ) for i in range (w .count ())]
345+ if v .value not in options :
346+ raise Exception (f'Invalid relative constraints: { v .value } ' )
347+
348+ w .setCurrentText (v .value )
349+
311350 @property
312351 def engineering_constraints (self ):
313352 return self .ui .engineering_constraints .currentText ()
@@ -353,6 +392,20 @@ def tth_distortion(self, v):
353392 first = next (iter (v .values ()))
354393 self .pinhole_correction_editor .update_from_object (first )
355394
395+ def on_relative_constraints_changed (self ):
396+ # If the relative constraints is not None, then the engineering
397+ # constraints must be set to None
398+ enable = self .relative_constraints == RelativeConstraintsType .none
399+ if not enable :
400+ self ._ignore_next_tree_view_update = True
401+ self .engineering_constraints = None
402+
403+ self .ui .engineering_constraints .setEnabled (enable )
404+ self .ui .mirror_constraints_from_first_detector .setEnabled (enable )
405+
406+ self .relative_constraints_changed .emit (self .relative_constraints )
407+ self .reinitialize_tree_view ()
408+
356409 def on_engineering_constraints_changed (self ):
357410 self .engineering_constraints_changed .emit (self .engineering_constraints )
358411
@@ -404,6 +457,7 @@ def mirror_constraints_from_first_detector(self):
404457 self .tree_view .reset_gui ()
405458
406459 def update_from_calibrator (self , calibrator ):
460+ self .relative_constraints = calibrator .relative_constraints_type
407461 self .engineering_constraints = calibrator .engineering_constraints
408462 self .tth_distortion = calibrator .tth_distortion
409463 self .params_dict = calibrator .params
@@ -504,6 +558,9 @@ def recursively_set_items(this_config, this_template):
504558 # Now generate the detectors
505559 detector_template = template_dict ['detectors' ].pop ('{det}' )
506560
561+ euler_convention = HexrdConfig ().euler_angle_convention
562+ euler_normalized = normalize_euler_convention (euler_convention )
563+
507564 def recursively_format_det (det , this_config , this_template ):
508565 for k , v in this_template .items ():
509566 if isinstance (v , dict ):
@@ -524,10 +581,11 @@ def recursively_format_det(det, this_config, this_template):
524581 current = template .format (det = det , i = i )
525582 elif k == 'tilt' :
526583 # Special case. Take into account euler angles.
527- convention = HexrdConfig ().euler_angle_convention
528- normalized = normalize_euler_convention (convention )
529- param_names = param_names_euler_convention (det , convention )
530- labels = TILT_LABELS_EULER [normalized ]
584+ param_names = param_names_euler_convention (
585+ det ,
586+ euler_convention ,
587+ )
588+ labels = TILT_LABELS_EULER [euler_normalized ]
531589 this_dict = this_config .setdefault (k , {})
532590 for label , param_name in zip (labels , param_names ):
533591 param = params_dict [param_name ]
@@ -540,14 +598,39 @@ def recursively_format_det(det, this_config, this_template):
540598 if v in params_dict :
541599 this_config [k ] = create_param_item (params_dict [v ])
542600
543- det_dict = tree_dict .setdefault ('detectors' , {})
544- for det_key in self .instr .detectors :
545- this_config = det_dict .setdefault (det_key , {})
546- this_template = copy .deepcopy (detector_template )
547-
548- # For the parameters, we need to convert dashes to underscores
549- det = det_key .replace ('-' , '_' )
550- recursively_format_det (det , this_config , this_template )
601+ if self .relative_constraints == RelativeConstraintsType .none :
602+ det_dict = tree_dict .setdefault ('detectors' , {})
603+ for det_key in self .instr .detectors :
604+ this_config = det_dict .setdefault (det_key , {})
605+ this_template = copy .deepcopy (detector_template )
606+
607+ # For the parameters, we need to convert dashes to underscores
608+ det = det_key .replace ('-' , '_' )
609+ recursively_format_det (det , this_config , this_template )
610+ elif self .relative_constraints == RelativeConstraintsType .group :
611+ raise NotImplementedError (self .relative_constraints )
612+ elif self .relative_constraints == RelativeConstraintsType .system :
613+ det_dict = tree_dict .setdefault ('detector system' , {})
614+
615+ tvec_names = [
616+ 'system_tvec_x' ,
617+ 'system_tvec_y' ,
618+ 'system_tvec_z' ,
619+ ]
620+ tilt_names = param_names_euler_convention (
621+ 'system' , euler_convention )
622+
623+ this_config = det_dict .setdefault ('translation' , {})
624+ tvec_keys = ['X' , 'Y' , 'Z' ]
625+ for key , name in zip (tvec_keys , tvec_names ):
626+ this_config [key ] = create_param_item (params_dict [name ])
627+
628+ this_config = det_dict .setdefault ('tilt' , {})
629+ tilt_keys = TILT_LABELS_EULER [euler_normalized ]
630+ for key , name in zip (tilt_keys , tilt_names ):
631+ this_config [key ] = create_param_item (params_dict [name ])
632+ else :
633+ raise NotImplementedError (self .relative_constraints )
551634
552635 if self .format_extra_params_func is not None :
553636 self .format_extra_params_func (params_dict , tree_dict ,
@@ -597,6 +680,12 @@ def reinitialize_tree_view(self):
597680 self .tree_view .verticalScrollBar ().setValue (scroll_value )
598681
599682 def update_tree_view (self ):
683+ if self ._ignore_next_tree_view_update :
684+ # Sometimes this is necessary when updating multiple
685+ # parameters at once.
686+ self ._ignore_next_tree_view_update = False
687+ return
688+
600689 tree_dict = self .tree_view_dict_of_params
601690 self .tree_view .model ().config = tree_dict
602691 self .tree_view .reset_gui ()
0 commit comments