def do_save_quit(self): """ Save and quit with applying to parent :return: """ # Get parameter values from GUI start_time = gutil.parse_float(self.ui.lineEdit_minTime) stop_time = gutil.parse_float(self.ui.lineEdit_maxTime) min_log_value = gutil.parse_float(self.ui.lineEdit_minLogValue) max_log_value = gutil.parse_float(self.ui.lineEdit_maxLogValue) delta_value = gutil.parse_float(self.ui.lineEdit_logValueInterval) # FIXME - Treat 'comboBox_direction' if start_time < 0.: start_time = 0. self._myParent.get_controller().gen_data_slicer_sample_log( run_number=self._myRunNumber, sample_log_name=self._logName, start_time=start_time, end_time=stop_time, min_log_value=min_log_value, max_log_value=max_log_value, log_value_step=delta_value) # Update the state variables self._slicerIsSaved = True self._currSessionDiscardable = True # Quit self.close() return
def do_smooth_vanadium(self): """ smooth vanadium data :return: """ # bank_group_index = self._get_banks_group() # get smoothing parameter try: smoother_type = str( self.ui.comboBox_smoothFilterTiype.currentText()) smoother_n = GuiUtility.parse_integer( self.ui.lineEdit_smoothParameterN, allow_blank=False) smoother_order = GuiUtility.parse_integer( self.ui.lineEdit_smoothParameterOrder, allow_blank=False) except RuntimeError: GuiUtility.pop_dialog_error( self, 'Smoothing parameter N or order is specified incorrectly.') return # emit signal print('[DB...BAT] Smooth type = {}, n = {}, order = {}'.format( smoother_type, smoother_n, smoother_order)) self.mySmoothVanadiumSignal.emit(1, smoother_type, smoother_n, smoother_order) return
def do_save_result(self): """ apply the result to controller :return: """ # get IPTS number and run number try: run_number = GuiUtility.parse_integer(self.ui.lineEdit_runNumber, allow_blank=False) except RuntimeError as run_err: GuiUtility.pop_dialog_error( self, 'IPTS and run number must be specified in order to save for GSAS. {}.' .format(run_err)) return # get default directory default_dir = '/SNS/VULCAN/shared/CalibrationFiles/Instrument/Standards/Vanadium' if not os.access(default_dir, os.W_OK): default_dir = os.getcwd() file_filter = 'GSAS (*.gda);;All (*.*)' van_file_name = str( QFileDialog.getSaveFileName(self, 'Smoothed Vanadium File', default_dir, file_filter)) if len(van_file_name) == 0: return self.myApplyResultSignal.emit(van_file_name, run_number) return
def do_strip_vanadium_peaks(self): """ strip vanadium peaks :return: """ # collect the parameters from the UI try: peak_fwhm = GuiUtility.parse_integer(self.ui.lineEdit_vanPeakFWHM, allow_blank=False) fit_tolerance = GuiUtility.parse_float( self.ui.lineEdit_stripPeakTolerance, allow_blank=False) except RuntimeError: GuiUtility.pop_dialog_error( self, 'Both FWHM and Tolerance must be specified.') return # append the banks # bank_group = str(self.ui.comboBox_banks.currentText()) # if bank_group.count('East') > 0: # bank_group_index = 90 # elif bank_group.count('High') > 0: # bank_group_index = 150 # else: # raise NotImplementedError('Bank group {} is not supported.'.format(bank_group)) # bank_group_index = self._get_banks_group() background_type = str( self.ui.comboBox_vanPeakBackgroundType.currentText()) is_high_background = self.ui.checkBox_isHighBackground.isChecked() self.myStripPeakSignal.emit(1, peak_fwhm, fit_tolerance, background_type, is_high_background) return
def show_hide_v_peaks(self, show_v_peaks): """ Handling event that show or hide vanadium peaks on the figure (the dashed indicators) :return: """ datatypeutility.check_bool_variable( 'Flag to indicate show or hide vanadium peaks', show_v_peaks) if show_v_peaks and self._is_v_peaks_shown is False: # show peaks if self._curr_unit != UNIT['d']: GuiUtility.pop_dialog_error( self._parent, 'Vanadium peaks can only been shown when unit is dSpacing') self.ui.checkBox_vpeakShowPeakPos.setChecked(False) return else: # show!: self._vpeak_indicators = self.ui.graphicsView_main.add_vanadium_peaks( VANADIUM_PEAKS_D) self._is_v_peaks_shown = True elif not show_v_peaks and self._is_v_peaks_shown: # hide/delete vanadium peaks self.ui.graphicsView_main.remove_vanadium_peaks( self._vpeak_indicators) self._vpeak_indicators = None self._is_v_peaks_shown = False return
def evt_smooth_vanadium(self): """ handle the event that the smoothing parameters are changed in the line edits if the smoothing operation is in the interactive mode, then it is same as pressing the 'smooth vanadium' button :return: """ # change parameters self._slidersMutex = True param_n = GuiUtility.parse_integer(self.ui.lineEdit_smoothParameterN, allow_blank=False) if param_n is None or param_n == 0: param_n = 1 self.ui.horizontalSlider_smoothN.setValue(param_n) param_order = GuiUtility.parse_integer( self.ui.lineEdit_smoothParameterOrder, allow_blank=False) if param_order is None or param_order == 0: param_order = 1 self.ui.horizontalSlider_smoothOrder.setValue(param_order) self._slidersMutex = False # smooth vanadium if self.ui.checkBox_interactiveSmoothing.isChecked(): self.do_smooth_vanadium() return
def strip_vanadium_peaks(self, bank_id, peak_fwhm=4, tolerance=0.1, background_type='Quadratic', is_high_background=True): """ Strip vanadium peaks of a certain bank :return: """ if bank_id is None: bank_id = self.get_bank_id() try: processor = self._myController.project.vanadium_processing_manager processor.strip_v_peaks(bank_id, peak_fwhm, tolerance, background_type, is_high_background) self._peak_fwhm_dict[bank_id] = peak_fwhm except RuntimeError as run_err: GuiUtility.pop_dialog_error( self._parent, 'Unable to strip vanadium peaks on bank {} due to {}' ''.format(bank_id, run_err)) return # plot self.plot_strip_peak_vanadium(bank_id) return
def read_pixel_binning_parameters(self): """ binning pixel :return: """ # return the case for not being checked if not self.user_interface.checkBox_overPixel.isChecked(): return False, None # process the binning parameters if self.user_interface.radioButton_binVerticalPixels.isChecked(): bin_pixel_size = GuiUtility.parse_integer(self.user_interface.lineEdit_pixelSizeVertical) bin_pixel_direction = 'vertical' elif self.user_interface.radioButton_binHorizontalPixels.isChecked(): bin_pixel_size = GuiUtility.parse_integer(self.user_interface.lineEdit_pixelSizeHorizontal) bin_pixel_direction = 'horizontal' else: raise RuntimeError( 'Binning pixels: neither of 2 radio buttons (vertical/horizontal) is selected.') # form output par_dict = {'direction': bin_pixel_direction, 'pixel_size': bin_pixel_size} return True, par_dict
def do_set_target(self): """ set the target workspace/index to the slicers in case some of them will be merged :return: """ # check whether any rows are selected row_list = self.ui.tableWidget_segments.get_selected_rows(True) if len(row_list) == 0: GuiUtility.pop_dialog_information( self, 'No row is selected to set target.') return # get the name of the target # pop a dialog for the name of the slicer target, status = QInputDialog.getText( self, 'Input Target', 'Enter chopping target for selected rows:') # return if rejected with if status is False: return else: target = str(target) self.ui.tableWidget_segments.rename_chop_target(row_list, target) return
def do_save_data(self): """ Save plotted data as data file or image according to the file type :return: """ default_dir = self._parent.controller.get_working_dir() file_filter = 'PNG (*.png);;JPG (*.jpg);;Post Script (*.ps);;Ascii (*.dat);;HDF5 (*.hdf5)' out_file_name = GuiUtility.get_save_file_by_dialog( self, 'Specify file name to save data', default_dir, file_filter) # identify the file type file_postfix = out_file_name.split('.')[-1].lower() if file_postfix in ['png', 'jpg', 'jpeg', 'ps', 'pdf']: # export image to file self.ui.graphicsView_mainPlot.save_image(out_file_name) elif file_postfix in ['hdf5', 'h5', 'dat', 'data']: # save column data self.ui.graphicsView_mainPlot.export_data(out_file_name) else: GuiUtility.pop_dialog_error( self, 'Output file {} with type {} is not supported.' ''.format(out_file_name, file_postfix)) return
def get_phase_value(self, phase_value_list): """ Purpose: set the phase values to the input list. It is used for save_to_buffer the values of phase temporarily. if value is not set up, then it will ignored; Requirements: if the value is set, then it must be valid :param phase_value_list: :return: """ # Check requirements: assert isinstance(phase_value_list, list), 'Phase value list %s must be a list but not of type %s.' \ '' % (str(phase_value_list), type(phase_value_list)) assert len(phase_value_list ) == 5, 'Phase value list %s must be 5 elements.' % str( phase_value_list) # Set name phase_value_list[0] = str(self._lineEdit_name.text()).strip() # Set phase phase_value_list[1] = str(self._comboBox_type.currentText()).split()[0] # Set a, b and c a = GuiUtility.parse_float(self._lineEdit_a) phase_value_list[2] = a b = GuiUtility.parse_float(self._lineEdit_b) phase_value_list[3] = b c = GuiUtility.parse_float(self._lineEdit_c) phase_value_list[4] = c return
def set_retrieved_information(self, run_tup_list): """ Assumption: sort by time and date should have the exactly same result :param run_tup_list: sorted run tuple list :return: """ assert (isinstance(run_tup_list, list)) and len(run_tup_list) > 0 if len(run_tup_list) == 1: GuiUtility.pop_dialog_information(self, 'Only 1 run is given!') # set up run information first_run = run_tup_list[0][0] last_run = run_tup_list[-1][0] self.ui.lineEdit_begin.setText(str(first_run)) self.ui.lineEdit_end.setText(str(last_run)) # Sort by date first_run_time = run_tup_list[0][1] last_run_time = run_tup_list[-1][1] date_begin = GuiUtility.convert_to_qdate(first_run_time) self.ui.dateEdit_begin.setDate(date_begin) date_end = GuiUtility.convert_to_qdate(last_run_time) self.ui.dateEdit_end.setDate(date_end) self.ui.label_loadingStatus.setText('IPTS directory %s: Run %d - %d.' '' % (self._iptsDir, first_run, last_run)) return
def do_set_x_range(self): """ Set image X range from line edits :return: """ x_min = GuiUtility.parse_float(self.ui.lineEdit_xMin, True, 0.25) x_max = GuiUtility.parse_float(self.ui.lineEdit_xMax, True, 3.50) self.ui.graphicsView_mainPlot.setXYLimit(xmin=x_min, xmax=x_max) return
def do_save_vanadium_smooth_parameters(self): """ save the vanadium smoothing parameters :return: """ self._defaultDict['Order'] = GuiUtility.parse_integer( self.ui.lineEdit_smoothParameterOrder) self._defaultDict['n'] = GuiUtility.parse_integer( self.ui.lineEdit_smoothParameterN) self._defaultDict['Smoother'] = str( self.ui.comboBox_smoothFilterTiype.currentText()) return
def save_processing_result(self): """ Get saved file directory :return: """ try: message = self._myController.project.vanadium_processing_manager.save_vanadium_to_file( ) GuiUtility.pop_dialog_information(self._parent, message) except RuntimeError as run_err: GuiUtility.pop_dialog_error(self._parent, '{}'.format(run_err)) return
def smooth_vanadium_peaks(self, bank_id, smoother_type=None, param_n=None, param_order=None): """ Smooth vanadium peaks :param bank_id: :param smoother_type: :param param_n: :param param_order: :return: """ # get bank ID if bank_id is None: bank_id = self.get_bank_id() if bank_id is None: GuiUtility.pop_dialog_error(self._parent, 'Bank ID is not given!') # set default number van_processor = self._myController.project.vanadium_processing_manager if smoother_type is None: smoother_type = 'Butterworth' param_n = van_processor.get_default_smooth_n( smoother_type, bank_id) param_order = van_processor.get_default_smooth_order( smoother_type, bank_id) # smooth! try: van_processor.smooth_v_spectrum(bank_id=bank_id, smoother_filter_type=smoother_type, param_n=param_n, param_order=param_order) self._smooth_n_dict[bank_id] = param_n self._smooth_order_dict[bank_id] = param_order except RuntimeError as run_err: GuiUtility.pop_dialog_error( self._parent, 'Unable to smooth vanadium for bank {} due to {}' ''.format(bank_id, run_err)) return self.plot_smoothed_peak_vanadium( bank_id, with_raw=self.ui.checkBox_vpeakShowRaw.isChecked(), label='{}: {}/{}'.format(smoother_type, param_n, param_order)) return
def do_add_runs(self): """ Add runs to parent (but not quit) :return: """ # Access parent's workflow controller workflow_controller = self._myParent.get_controller() assert workflow_controller is not None # Check whether it is fine to leave with 'OK' if self._iptsDir is None: # error message and return: data directory must be given! GuiUtility.pop_dialog_error(self, 'IPTS or data directory has not been set up.' 'Unable to add runs.') return # try to get the IPTS from IPTS directory if self._iptsNumber is None: # get the ipts number for IPTS directory status, ret_obj = workflow_controller.get_ipts_number_from_dir(self._iptsDir) if status is False: # use IPTS = 0 for no-IPTS message = 'Unable to get IPTS number due to %s. Using user directory.' % ret_obj GuiUtility.pop_dialog_error(self, message) self._iptsNumber = 0 else: # good IPTS self._iptsNumber = ret_obj # END-IF-ELSE # # set IPTS number of controller # workflow_controller.set_ipts(self._iptsNumber) # get the list of runs by run number of date if self.ui.radioButton_filterByDate.isChecked(): # add runs by date run_tup_list = self.add_runs_by_date() elif self.ui.radioButton_filterByRun.isChecked(): # add runs by run numbers run_tup_list = self.get_runs_by_number() else: # exception raise RuntimeError('Neither radio button to filter by date or run number is selected.') # return with error if run_tup_list is False: GuiUtility.pop_dialog_error(self, 'Unable to get runs with information.') return # add runs to workflow status, error_message = workflow_controller.add_runs_to_project(run_tup_list) if status is False: return False, error_message status, err_msg = self._myParent.add_runs_trees( self._iptsNumber, self._iptsDir, run_tup_list) if not status: GuiUtility.pop_dialog_error(self, error_message) return
def scan_record_file(self, record_data_only, is_archive=True): """ Scan record log file :param record_data_only: flag to read AutoRecordData :param is_archive: locate file in archive :return: boolean """ if is_archive: # in archive status, ret_str = self._search_logs(record_data_only) else: # get log file: the higher priority is the log file name that is browsed log_file_path = str(self.ui.lineEdit_logFilePath.text()) if len(log_file_path.strip()) == 0: status = False ret_str = 'User must specify path to "Auto Record" file.' elif os.path.exists(log_file_path): status = True ret_str = log_file_path else: status = False ret_str = 'User specified "Auto Record" file {0} does not exist.'.format( log_file_path) # END-IF-ELSE if status: # scan record file log_file_path = ret_str scan_status, ret_obj = self._myParent.get_controller().scan_vulcan_record(log_file_path) if scan_status: # set record key as current archive key and get the range of the run record_key = ret_obj self._archiveKey = record_key start_run, end_run = self._myParent.get_controller().get_ipts_run_range(record_key) run_info_list = [start_run, end_run] self.set_retrieved_information(run_info_list) else: # error in retrieving error_message = ret_obj GuiUtility.pop_dialog_error(self, 'Unable to get IPTS information from log file %s due to %s.' '' % (log_file_path, error_message)) self.ui.label_loadingStatus.setText('Failed to access %s.' % log_file_path) return False else: error_message = ret_str GuiUtility.pop_dialog_error(self, error_message) return True
def do_set_y_range(self): """ Set image X range from line edits :return: """ y_min = GuiUtility.parse_float(self.ui.lineEdit_yMin, True, 0.) y_max = GuiUtility.parse_float(self.ui.lineEdit_yMax, True, None) if y_min >= y_max: GuiUtility.pop_dialog_error( self, 'Lower Y limit {} cannot be equal to or larger than upper Y limit {}' ''.format(y_min, y_max)) return self.ui.graphicsView_mainPlot.setXYLimit(ymin=y_min, ymax=y_max) return
def do_save_peak_strip_parameters(self): """ save current vanadium-peak-striping parameters as defaults :return: """ self._defaultDict['FWHM'] = GuiUtility.parse_integer( self.ui.lineEdit_vanPeakFWHM) self._defaultDict['Tolerance'] = GuiUtility.parse_integer( self.ui.lineEdit_vanPeakFWHM) self._defaultDict['BackgroundType'] = str( self.ui.comboBox_vanPeakBackgroundType.currentText()) self._defaultDict[ 'IsHighBackground'] = self.ui.checkBox_isHighBackground.isChecked( ) return
def do_accept_return(self): """ Return from the MTS peek-scan window :return: """ # check if self._logFileName is None or self._summaryDict is None: GuiUtility.pop_dialog_error( self, 'MTS log file is not given AND/OR log file format is not scanned!') return # send signal self.mtsLogReturnSignal.emit(1) # close window self.close() return
def do_set_x_range(self): """ Set image X range from line edits :return: """ min_x = GuiUtility.parse_float(self.ui.lineEdit_xMin, True, 0.) max_x = GuiUtility.parse_float(self.ui.lineEdit_xMax, True, 3.5) if min_x >= max_x: GuiUtility.pop_dialog_error( self, 'Lower X limit {} cannot be equal to or larger than upper X limit {}' ''.format(min_x, max_x)) return self._x_min = min_x self._x_max = max_x self.ui.graphicsView_mainPlot.setXYLimit(xmin=self._x_min, xmax=self._x_max) return
def do_add_peak_param(self): """ :return: """ # blabla peak_type = str(self.ui.comboBox_peakY.currentText()).lower() if peak_type.count('intensity'): peak_type = 'intensity' elif peak_type.count('center'): peak_type = 'center' else: raise RuntimeError('Who knows') # side side_str = self.ui.comboBox_plotPeak.currentText() if side_str == 'Left': is_main = True else: is_main = False # check whether there is any item related to peak integration min_d_str = str(self.ui.lineEdit_minDPeakIntegrate.text()) max_d_str = str(self.ui.lineEdit_dMaxPeakIntegrate.text()) try: min_d = float(min_d_str) max_d = float(max_d_str) except ValueError as value_err: err_msg = 'Min-D "{0}" or/and Max-D "{1}" cannot be parsed as a float due to {2}' \ ''.format(min_d_str, max_d_str, value_err) GuiUtility.pop_dialog_error(self, err_msg) return norm_by_van = self.ui.checkBox_normByVan.isChecked() peak_info_str = '* Peak: {0}'.format(peak_type) self.ui.tableWidget_plotYAxis.add_peak_parameter( peak_info_str, is_main, min_d, max_d, norm_by_van) return
def do_peek_log_file(self): """ Set and scan MTS file :return: """ # get default value if self.ui.radioButton_browseArchive.isChecked(): # default from archive if self._iptsNumber is None: ipts_number_str = str(self.ui.lineEdit_ipts.text()).strip() if len(ipts_number_str) > 0: ipts_number = int(ipts_number_str) else: GuiUtility.pop_dialog_error( self, 'IPTS number is not given! Unable to locate archive.') return else: ipts_number = self._iptsNumber if isinstance(ipts_number, int): working_dir = '/SNS/VULCAN/IPTS-%d/shared/' % ipts_number else: working_dir = '/SNS/VULCAN/' elif self.ui.radioButton_browseLocal.isChecked(): if self._dataDir is None: working_dir = os.getcwd() else: working_dir = self._dataDir else: raise RuntimeError('Programming error for neither radio buttons is selected.') # get file name log_file_name = str(QFileDialog.getOpenFileName(self, 'Get Log File', working_dir)) if log_file_name is None or len(log_file_name) == 0: return else: self._logFileName = log_file_name self.ui.lineEdit_mtsFileName.setText(self._logFileName) # scan file self.peek_log_file(self._logFileName) return
def do_set_width(self): """ Set peak width :return: """ peak_width = GuiUtility.parse_float(self.ui.lineEdit_peakWidth) if peak_width is None: GuiUtility.pop_dialog_error(self, 'Peak width is not set up!') return if peak_width <= 0.: GuiUtility.pop_dialog_error( self, 'Peak width %f cannot be 0 or negative!' % peak_width) return self._peakWidth = peak_width # Close self.close() return
def do_chop(self): """ record the state to chop/reduce to be True and close the window Note: this is the OK button and thus dialog will be closed and be returned with 1 :return: """ # check output directory if self.ui.radioButton_saveToArbitrary.isChecked(): # output directory target_dir = str(self.ui.lineEdit_outputDir.text()) if len(target_dir) == 0: GuiUtility.pop_dialog_error( self, 'Output directory is not specified.') return # END-IF self.close() return
def read_binning_parameters(self): """ parse and check binning parameters. :return: """ # parse binning parameter if self.user_interface.radioButton_binStandard.isChecked(): # will use default binning parameter bin_par = None elif self.user_interface.radioButton_binCustomized.isChecked(): # customized bin parameters bin_width = GuiUtility.parse_float(self.user_interface.lineEdit_binWidth) min_tof = GuiUtility.parse_float(self.user_interface.lineEdit_binMinTOF) max_tof = GuiUtility.parse_float(self.user_interface.lineEdit_binMaxTOF) bin_par = (min_tof, bin_width, max_tof) else: # violate requirements raise RuntimeError('It is impossible to have either standard binning or customized binning.' 'Will be implemented in #32.') return bin_par
def do_apply_change(self): """ Apply new set up for the slicer range :return: """ # Time min_time = gutil.parse_float(self.ui.lineEdit_minTime) self._move_time_boundary(self._horizontalIndicatorList[0], min_time) max_time = gutil.parse_float(self.ui.lineEdit_maxTime) self._move_time_boundary(self._horizontalIndicatorList[1], max_time) # Value min_log_value = gutil.parse_float(self.ui.lineEdit_minLogValue) max_log_value = gutil.parse_float(self.ui.lineEdit_maxLogValue) v_id_0 = self.ui.graphicsView_main.add_horizontal_indicator( min_log_value, 'blue') v_id_1 = self.ui.graphicsView_main.add_horizontal_indicator( max_log_value, 'blue') self._verticalIndicatorList[0] = v_id_0 self._verticalIndicatorList[1] = v_id_1 return
def init_session(self, data_key): """ Init a vanadium processing session including (1) laod meta data :param data_key: :return: """ print('[DB...BAT] Init vanadium session with data key (workspace) {}'. format(data_key)) # generate a temporary gsas file name gsas_dir = '/SNS/VULCAN/shared/Calibrationfiles/Instrument/Standard/Vanadium' if not os.path.exists(gsas_dir) or not os.access(gsas_dir, os.W_OK): GuiUtility.pop_dialog_information( self._parent, 'User cannot write GSAS file to {}'.format(gsas_dir)) gsas_dir = os.path.expanduser('~') temp_out_gda_name = os.path.join(gsas_dir, '{}-s.gda'.format(self._run_number)) # load sample log workspace # TODO - TODAY 9 - Load meta data can take up to 3 seconds. Make it on a separate thread log_ws_name = self._myController.load_meta_data( self._ipts_number, self._run_number, None) # call processor = self._myController.project.vanadium_processing_manager try: processor.init_session(workspace_name=data_key, ipts_number=self._ipts_number, van_run_number=self._run_number, out_gsas_name=temp_out_gda_name, sample_log_ws_name=log_ws_name) except RuntimeError as run_err: GuiUtility.pop_dialog_error( self._parent, 'Unable to initialize a vanadium processing sesson due to {}' ''.format(run_err)) return
def do_apply(self): """Apply setup :return: """ # get x-axis name and y-axis name x_axis_name = str(self.ui.comboBox_X.currentText()) # get the Y axis and check y_axis_name_list, is_main_list, peak_range_list, norm_by_van_list = \ self.ui.tableWidget_plotYAxis.get_selected_items() if len(y_axis_name_list) == 0: GuiUtility.pop_dialog_error(self, 'Y-axis list is empty!') return elif len(y_axis_name_list) > 2: GuiUtility.pop_dialog_error( self, 'More than 2 items are selected to plot. It is NOT OK.') return elif len(y_axis_name_list) == 2 and is_main_list[0] == is_main_list[1]: GuiUtility.pop_dialog_error( self, 'Two items cannot be on the same side of axis.') return # now it is the time to send message self.PlotSignal.emit(x_axis_name, y_axis_name_list, is_main_list, peak_range_list, norm_by_van_list) return