def get_meta_sample_data(self, name): """ get meta data to plot. the meta data can contain sample log data and fitted peak parameters :param name: :return: """ # get data key if self.parent._project_name is None: pop_message(self, 'No data loaded', 'error') return sample_log_names = self.parent._core.reduction_service.get_sample_logs_names( self.parent._project_name, True) if name == HidraConstants.SUB_RUNS: # sub run vector value_vector = np.array( self.parent._core.reduction_service.get_sub_runs( self.parent._project_name)) elif name in sample_log_names: # sample log but not sub-runs value_vector = self.parent._core.reduction_service.get_sample_log_value( self.parent._project_name, name) elif name == 'Center of mass': # center of mass is different???? # TODO - #84 - Make sure of it! value_vector = self.parent._core.get_peak_center_of_mass( self.parent._project_name) else: value_vector = None return value_vector
def browse_load_hidra(self): """Allow users to browse for a HiDRA project file Returns ------- """ # default is current working directory default_dir = self._controller.working_dir # get default output directory for the run try: run_number = self._current_runnumber() if run_number is not None: default_dir = get_default_output_dir(self._current_runnumber()) except RuntimeError as e: print('While looking for {}:'.format(run_number)) print(e) # Browse hidra_file = browse_file(self.parent, caption='Select a HIDRA project file', default_dir=default_dir, file_filter='HiDRA project (*.h5)', file_list=False, save_file=False) if not hidra_file: return # Load Nexus try: self._controller.load_project_file(hidra_file, load_counts=False, load_pattern=True) except RuntimeError as run_err: pop_message( self.parent, 'Loading {} failed.\nTry to load diffraction only!'.format( hidra_file), detailed_message='{}'.format(run_err), message_type='error') return # sub runs sub_runs = self._controller.get_sub_runs() # set sub runs to (1) Table and (2) Combo box self._set_sub_run_numbers(sub_runs) # Set to first sub run and plot self.ui.comboBox_sub_runs.setCurrentIndex(0) # Fill in self.ui.frame_subRunInfoTable meta_data_array = self._controller.get_sample_logs_values( [HidraConstants.SUB_RUNS, HidraConstants.TWO_THETA]) self.ui.rawDataTable.add_subruns_info(meta_data_array, clear_table=True)
def do_decrease_value(self): """ Decrease the value in the associated QLineEdit from QPushButton event taking account of the associated resolution value in QLineEdit :return: """ # get sender of the event sender = self.sender() if sender not in self._decrease_button_dict: raise RuntimeError( 'Sender of decrease value message (registered as {}) is not in _decrease_button_dict' ''.format(sender)) else: value_edit, resolution_edit = self._decrease_button_dict[sender] # get current value try: curr_value = gui_helper.parse_line_edit(value_edit, float, throw_if_blank=False) except RuntimeError as run_err: gui_helper.pop_message(self, '{}'.format(run_err)) curr_value = None # default if curr_value is None: curr_value = 0. value_edit.setText('{}'.format(curr_value)) # resolution try: resolution = gui_helper.parse_line_edit(resolution_edit, float, throw_if_blank=False, edit_name='Resolution') except RuntimeError as run_err: gui_helper.pop_message(self, '{}'.format(run_err)) resolution = None if resolution is None: resolution = 0.001 resolution_edit.setText('{}'.format(resolution)) # get next value next_value = curr_value - resolution value_edit.setText('{}'.format(next_value)) # reduction? if self.ui.checkBox_reducedRealtime.isChecked(): self.do_reduce_data() return
def load_run_number_plot(self): try: project_dir = get_input_project_file( int(self.parent.ui.lineEdit_expNumber.text()), preferredType=self.parent.ui.comboBox_reduction.currentText( ).lower()) except (FileNotFoundError, RuntimeError) as run_err: pop_message( self, f'Failed to find run {self.parent.ui.lineEdit_expNumber.text()}', str(run_err), 'error') return hidra_file_name = os.path.join( project_dir, f'HB2B_{self.parent.ui.lineEdit_expNumber.text()}.h5') self.parent.current_hidra_file_name = hidra_file_name self.load_and_plot(hidra_file_name)
def do_load_mask(self): """ Load mask file """ # get the current mask file curr_mask_file = gui_helper.parse_line_edit(self.ui.lineEdit_maskFile, str, False, 'Masking file') print('[DB...BAT] Parsed line edit value: {} of type {}'.format( curr_mask_file, type(curr_mask_file))) # whether it has been loaded if curr_mask_file in self._core.reduction_service.get_loaded_mask_files( ): gui_helper.pop_message( self, message='Mask {} has been loaded', message_type='info', detailed_message= 'If need to load a new mask, clear the file name in editor') return # get mask if curr_mask_file is None or not os.path.exists(curr_mask_file): # need to load if curr_mask_file == '' or curr_mask_file is None: default_dir = os.getcwd() else: default_dir = os.path.basename(curr_mask_file) curr_mask_file = QFileDialog.getOpenFileName( self, 'Maks file name', default_dir, 'All Files(*.*)') if isinstance(curr_mask_file, tuple): raise NotImplementedError('Case of tuple of getOpenFileName') if curr_mask_file == '': return else: # set file names self.ui.lineEdit_maskFile.setText('{}'.format(curr_mask_file)) # END-IF try: self.load_mask_file(curr_mask_file) except RuntimeError: pass return
def get_default_hdf(self): """ use IPTS and run number to determine the name of the project file By default, look into the /HFIR/HB2B/IPTS-####/shared/pyrs_reduction folder if the project file for the given run number exists. If it does not, look into the /HFIR/HB2B/IPTS-####/autoreduce folder """ try: ipts_number = parse_integer(self.parent.ui.lineEdit_iptsNumber) exp_number = parse_integer(self.parent.ui.lineEdit_expNumber) except RuntimeError as run_err: pop_message(self, 'Unable to parse IPTS or Exp due to {0}'.format(run_err)) return None # Locate default saved HidraProject data archive_data = hb2b_utilities.get_hb2b_raw_data(ipts_number, exp_number) return archive_data
def plot_detector_counts(self): """ Returns ------- """ # Get valid sub run sub_run = parse_combo_box(self.ui.comboBox_sub_runs, int) if sub_run is None: return # Get counts try: counts_matrix = self._controller.get_detector_counts( sub_run, output_matrix=True) except RuntimeError as run_err: pop_message( self.parent, 'Unable to plot sub run {} counts on detector view'.format( sub_run), str(run_err), message_type='error') return # Plot # set information det_2theta = self._controller.get_sample_log_value( HidraConstants.TWO_THETA, sub_run) info = 'sub-run: {}, 2theta = {}'.format(sub_run, det_2theta) # mask ID is not None # if mask_id is not None: # # Get mask in array and do a AND operation to detector counts (array) # mask_array = self._core.reduction_service.get_mask_array(self._curr_project_name, mask_id) # detector_counts_array *= mask_array # info += ', mask ID = {}'.format(mask_id) # Set information self.ui.lineEdit_detViewInfo.setText(info) # Plot: self.ui.graphicsView_detectorView.plot_detector_view( counts_matrix, (sub_run, None))
def load_data_file(self, file_name): """ Load data fle :param file_name: :return: """ # load try: # FIXME - NOTE - Target dimension shall be set up by user self._curr_data_id, two_theta = self._core.reduction_service.load_data( file_name, target_dimension=2048, load_to_workspace=False) except RuntimeError as run_err: gui_helper.pop_message( self, message_type='error', message='Unable to load data {}'.format(file_name), detailed_message='{}'.format(run_err)) return
def plot_diff_data(self, plot_model=True): """ plot diffraction data :return: """ # gather the information try: scan_log_index_list = parse_integers(str(self.parent.ui.lineEdit_listSubRuns.text())) except RuntimeError: pop_message(self, "Unable to parse the string", message_type='error') return if len(scan_log_index_list) == 0: pop_message(self, 'There is not scan-log index input', 'error') # possibly clean the previous # keep_prev = self.ui.checkBox_keepPrevPlot.isChecked() # if keep_prev is False: self.parent._ui_graphicsView_fitSetup.reset_viewer() if len(scan_log_index_list) == 1: self.plot_scan(value=np.int(scan_log_index_list[0])) return # get data and plot err_msg = '' plot_model = len(scan_log_index_list) == 1 and plot_model for scan_log_index in scan_log_index_list: try: self.plot_diff_and_fitted_data(scan_log_index, plot_model) except RuntimeError as run_err: err_msg += '{0}\n'.format(run_err) if len(err_msg) > 0: pop_message(self, err_msg, message_type='error')
def get_function_parameter_data(self, param_name): """ get the parameter function data :param param_name: :return: """ # get data key if self.parent._project_name is None: pop_message(self, 'No data loaded', 'error') return param_names, param_data = self.parent._core.get_peak_fitting_result(self.parent._project_name, 0, return_format=dict, effective_parameter=False) print('[DB...BAT] Param Names: {}'.format(param_names)) sub_run_vec = param_data[HidraConstants.SUB_RUNS] param_value_2darray = param_data[param_name] print('[DB...BAT] 2D array shape: {}'.format(param_value_2darray.shape)) return sub_run_vec, param_value_2darray[:, 0]
def plot_powder_pattern(self): """ Returns ------- """ # Get valid sub run sub_run = parse_combo_box(self.ui.comboBox_sub_runs, int) print('[TEST-OUTPUT] sub run = {}, type = {}'.format( sub_run, type(sub_run))) if sub_run is None: return # Get diffraction pattern try: pattern = self._controller.get_powder_pattern(sub_run) except RuntimeError as run_err: pop_message( self.parent, 'Unable to plot sub run {} histogram/powder pattern'.format( sub_run), str(run_err), message_type='error') return # Get detector 2theta of this sub run det_2theta = self._controller.get_sample_log_value( HidraConstants.TWO_THETA, sub_run) info = 'sub-run: {}, 2theta = {}'.format(sub_run, det_2theta) # Plot self.ui.graphicsView_1DPlot.plot_diffraction(pattern[0], pattern[1], '2theta', 'intensity', line_label=info, keep_prev=False)
def load_mask_file(self, mask_file_name): # load mask try: two_theta, note, mask_id = self._core.reduction_service.load_mask_file( mask_file_name) self.ui.plainTextEdit_maskList.appendPlainText( '{}: 2theta = {}, note = {}\n' ''.format(mask_file_name, two_theta, note)) except RuntimeError as run_err: gui_helper.pop_message( self, message='Unable to load {}'.format(mask_file_name), message_type='error', detailed_message='{}'.format(run_err)) return # update UI self._number_rois += 1 # self.ui.graphicsView_calibration.set_number_rois(self._number_rois) self._subplot_mask_dict[self._number_rois - 1] = mask_id self._mask_subplot_dict[mask_id] = self._number_rois - 1 return
def load_and_plot(self, hidra_file_name): try: o_load = Load(parent=self.parent) o_load.load(project_file=hidra_file_name) except RuntimeError as run_err: pop_message(self, 'Failed to load {}'.format(hidra_file_name), str(run_err), 'error') except KeyError as key_err: pop_message(self, 'Failed to load {}'.format(hidra_file_name), str(key_err), 'error') self.parent.current_root_statusbar_message = "Working with: {} " \ "\t\t\t\t Project Name: {}" \ "".format(hidra_file_name, self.parent._project_name) self.parent.ui.statusbar.showMessage( self.parent.current_root_statusbar_message) try: o_plot = Plot(parent=self.parent) o_plot.plot_diff_data(plot_model=False) o_plot.reset_fitting_plot() except RuntimeError as run_err: pop_message(self, 'Failed to plot {}'.format(hidra_file_name), str(run_err), 'error') try: o_fit = Fit(parent=self.parent) o_fit.initialize_fitting_table() # enabled all fitting widgets and main plot o_gui = GuiUtilities(parent=self.parent) o_gui.check_if_fitting_widgets_can_be_enabled() o_gui.enabled_sub_runs_interation_widgets(True) # o_gui.enabled_fitting_widgets(True) o_gui.enabled_data_fit_plot(True) o_gui.enabled_peak_ranges_widgets(True) o_gui.enabled_1dplot_widgets(True) except RuntimeError as run_err: pop_message( self, 'Failed to initialize widgets for {}'.format(hidra_file_name), str(run_err), 'error')
def load(self, project_file=None): if project_file is None: return try: self.__set_up_project_name(project_file=project_file) ws = self.parent._core.load_hidra_project( project_file, project_name=self.parent._project_name, load_detector_counts=False, load_diffraction=True) # Record data key and next self.parent._curr_file_name = project_file self.parent.hidra_workspace = ws self.parent.create_plot_color_range() except (RuntimeError, TypeError) as run_err: pop_message(self, 'Unable to load {}'.format(project_file), detailed_message=str(run_err), message_type='error') # # Edit information on the UI for user to visualize # self.parent.ui.label_loadedFileInfo.setText('Loaded {}; Project name: {}' # .format(project_file, self.parent._project_name)) # Get and set the range of sub runs o_utility = Utilities(parent=self.parent) sub_run_list = o_utility.get_subruns_limit() o_gui = GuiUtilities(parent=self.parent) o_gui.initialize_fitting_slider(max=len(sub_run_list)) o_gui.set_1D_2D_axis_comboboxes(with_clear=True, fill_raw=True) o_gui.enabled_1dplot_widgets(enabled=True) o_gui.initialize_combobox()
def browse_load_plot_hdf(self): if self.parent._core is None: raise RuntimeError('Not set up yet!') # o_utility = Utilities(parent=self.parent) # hydra_file_name = o_utility.get_default_hdf() hidra_file_name = None if hidra_file_name is None: # No default Hidra file: browse the file file_filter = 'HDF (*.hdf);H5 (*.h5)' hidra_file_name = browse_file(self.parent, 'HIDRA Project File', os.getcwd(), file_filter, file_list=False, save_file=False) if hidra_file_name is None: return # user clicked cancel self.parent.current_hidra_file_name = hidra_file_name try: o_load = Load(parent=self.parent) o_load.load(project_file=hidra_file_name) except RuntimeError as run_err: pop_message(self, 'Failed to load {}'.format(hidra_file_name), str(run_err), 'error') except KeyError as key_err: pop_message(self, 'Failed to load {}'.format(hidra_file_name), str(key_err), 'error') self.parent.current_root_statusbar_message = "Working with: {} " \ "\t\t\t\t Project Name: {}" \ "".format(hidra_file_name, self.parent._project_name) self.parent.ui.statusbar.showMessage( self.parent.current_root_statusbar_message) try: o_plot = Plot(parent=self.parent) o_plot.plot_diff_data(plot_model=False) o_plot.reset_fitting_plot() except RuntimeError as run_err: pop_message(self, 'Failed to plot {}'.format(hidra_file_name), str(run_err), 'error') try: o_fit = Fit(parent=self.parent) o_fit.initialize_fitting_table() # enabled all fitting widgets and main plot o_gui = GuiUtilities(parent=self.parent) o_gui.check_if_fitting_widgets_can_be_enabled() o_gui.enabled_sub_runs_interation_widgets(True) # o_gui.enabled_fitting_widgets(True) o_gui.enabled_data_fit_plot(True) o_gui.enabled_peak_ranges_widgets(True) o_gui.enabled_1dplot_widgets(True) except RuntimeError as run_err: pop_message( self, 'Failed to initialize widgets for {}'.format(hidra_file_name), str(run_err), 'error')
def manual_reduce_run(self): """ (simply) reduce a list of runs in same experiment in a batch Returns ------- """ # Files names: NeXus, (output) project, mask, calibration run_number = self._current_runnumber() if isinstance(run_number, int): # use specify run number (integer) nexus_file = get_nexus_file(run_number) else: nexus_file = str(self.ui.lineEdit_runNumber.text()).strip() # quit if the input is not NeXus if not (os.path.exists(nexus_file) and nexus_file.endswith('.nxs.h5')): return # END-IF # Output HidraProject file project_file = str(self.ui.lineEdit_outputDirectory.text().strip()) # mask file mask_file = str(self.ui.lineEdit_maskFile.text().strip()) if mask_file == '': mask_file = None # calibration file calibration_file = str(self.ui.lineEdit_calibrationFile.text().strip()) if calibration_file == '': calibration_file = None # vanadium file vanadium_file = str(self.ui.lineEdit_vanRunNumber.text().strip()) if vanadium_file == '': vanadium_file = None # Start task if True: # single thread: try: hidra_ws = self._controller.reduce_hidra_workflow( nexus_file, project_file, self.ui.progressBar, mask=mask_file, calibration=calibration_file, vanadium_file=vanadium_file) except RuntimeError as run_err: pop_message(self.parent, 'Failed to reduce {}', str(run_err), message_type='error') return # Update table # TODO - Need to fill the table! sub_runs = list(hidra_ws.get_sub_runs()) # for sub_run in sub_runs: # self.ui.rawDataTable.update_reduction_state(sub_run, True) # Set the sub runs combo box self._set_sub_run_numbers(sub_runs) else: task = BlockingAsyncTaskWithCallback( self._controller.reduce_hidra_workflow, args=(nexus_file, project_file, self.ui.progressBar), kwargs={ 'mask': mask_file, 'calibration': calibration_file }, blocking_cb=QApplication.processEvents) # TODO - catch RuntimeError! ... # FIXME - check output directory task.start() return
def fit_peaks(self, all_sub_runs=False): """ Fit peaks either all peaks or selected peaks The workflow includes 1. parse sub runs, peak and background type 2. fit peaks 3. show the fitting result in table 4. plot the peak in first sub runs that is fit :param all_sub_runs: Flag to fit peaks of all sub runs without checking :return: """ # Get the sub runs to fit or all the peaks # if not all_sub_runs: # # Parse sub runs specified in lineEdit_scanNumbers # o_utilities = Utilities(parent=self.parent) # sub_run_list = o_utilities.parse_sub_runs() # else: sub_run_list = None # Get peak function and background function peak_function = str(self.parent.ui.comboBox_peakType.currentText()) bkgd_function = str( self.parent.ui.comboBox_backgroundType.currentText()) # Get peak fitting range from the range of figure fit_range = self.parent._ui_graphicsView_fitSetup.get_x_limit() print('[INFO] Peak fit range: {0}'.format(fit_range)) # Fit Peaks: It is better to fit all the peaks at the same time after testing guessed_peak_center = 0.5 * (fit_range[0] + fit_range[1]) peak_info_dict = { 'Peak 1': { 'Center': guessed_peak_center, 'Range': fit_range } } self.parent._core.fit_peaks(project_name=self.parent._project_name, sub_run_list=sub_run_list, peak_type=peak_function, background_type=bkgd_function, peaks_fitting_setup=peak_info_dict) # Process fitted peaks # TEST - #84 - This shall be reviewed! try: # FIXME - effective_parameter=True will fail! # FIXME - other than return_format=dict will fail! # FIXME - need to give a real value to default_tag # FIXME - this only works if fitting 1 peak a time default_tag = peak_info_dict.keys()[0] function_params, fit_values = self.parent._core.get_peak_fitting_result( self.parent._project_name, default_tag, return_format=dict, effective_parameter=False, fitting_function=peak_function) except AttributeError as err: pop_message(self, 'Zoom in/out to only show peak to fit!', str(err), "error") return # TODO - #84+ - Need to implement the option as effective_parameter=True print('[DB...BAT...FITWINDOW....FIT] returned = {}, {}'.format( function_params, fit_values)) self.parent._sample_log_names_mutex = True for param_name in function_params: self.parent._function_param_name_set.add(param_name) # # log index and center of mass # size_x = len(self.parent._sample_log_names) + len(self.parent._function_param_name_set) + 2 # # # center of mass # size_y = len(self.parent._sample_log_names) + len(self.parent._function_param_name_set) + 1 # release the mutex: because re-plot is required anyway self.parent._sample_log_names_mutex = False # Show fitting result in Table # TODO - could add an option to show native or effective peak parameters try: self.show_fit_result_table(peak_function, function_params, fit_values, is_effective=False) except IndexError: return # plot the model and difference if sub_run_list is None: o_plot = Plot(parent=self.parent) o_plot.plot_diff_and_fitted_data(1, True) o_gui = GuiUtilities(parent=self.parent) o_gui.set_1D_2D_axis_comboboxes(fill_fit=True) o_gui.enabled_export_csv_widgets(True)
def do_reduce_data(self): """ reduce data :return: """ try: cal_shift_x = gui_helper.parse_line_edit(self.ui.lineEdit_centerX, float, False, 'Center X', default=0.) cal_shift_y = gui_helper.parse_line_edit(self.ui.lineEdit_centerY, float, False, 'Center Y', default=0.) cal_shift_z = gui_helper.parse_line_edit(self.ui.lineEdit_centerZ, float, False, 'Center Z', default=0.) cal_rot_x = gui_helper.parse_line_edit(self.ui.lineEdit_rotationX, float, False, 'Rotation X', default=0.) cal_rot_y = gui_helper.parse_line_edit(self.ui.lineEdit_rotationY, float, False, 'Rotation Y', default=0.) cal_rot_z = gui_helper.parse_line_edit(self.ui.lineEdit_rotationZ, float, False, 'Rotation Z', default=0.) cal_wave_length = gui_helper.parse_line_edit( self.ui.lineEdit_wavelength, float, False, 'Rotation Z', default=1.) except RuntimeError as run_err: gui_helper.pop_message(self, 'Unable to parse calibration value', str(run_err), 'error') return # get data file try: two_theta = gui_helper.parse_line_edit(self.ui.lineEdit_2theta, float, True, 'Two theta', default=None) except RuntimeError as run_err: gui_helper.pop_message(self, '2-theta error', str(run_err), 'error') return # load instrument # self._core.reduction_engine.set_instrument(instrument) # # self._core.reduction_engine.load_instrument(two_theta, cal_shift_x, cal_shift_y, cal_shift_z, # cal_rot_x, cal_rot_y, cal_rot_z, # cal_wave_length) # reduce masks geom_calibration = AnglerCameraDetectorShift() geom_calibration.center_shift_x = cal_shift_x geom_calibration.center_shift_y = cal_shift_y geom_calibration.center_shift_z = cal_shift_z geom_calibration.rotation_x = cal_rot_x geom_calibration.rotation_y = cal_rot_y geom_calibration.rotation_z = cal_rot_z self._core.reduction_service.set_geometry_calibration(geom_calibration) for mask_id in self._core.reduction_service.get_mask_ids(): # mask_vec = self._core.reduction_engine.get_mask_vector(mask_id) self._core.reduction_service.reduce_to_2theta_histogram( data_id=self._curr_data_id, output_name=None, use_mantid_engine=False, mask=mask_id, two_theta=two_theta) """ data_id, output_name, use_mantid_engine, mask, two_theta, min_2theta=None, max_2theta=None, resolution_2theta=None """ vec_x, vec_y = self._core.reduction_service.get_reduced_data() self.ui.graphicsView_calibration.plot_data( vec_x, vec_y, self._mask_subplot_dict[mask_id]) if cal_wave_length: # TODO - Need to implement how to calibrate wave length raise NotImplementedError('Implement ASAP') return