def __init__(self, cfg, app_win, main_win, app_root_dir): self.cfg = cfg self.cdm = CfgDataModel(self.cfg) self.app_win = app_win self.main_win = main_win self.cur_row = -1 self.main_win.sensARunBtn.setEnabled(False) self.main_win.sensBRunBtn.setEnabled(False) self.last_click = datetime.min self.app_root_dir = app_root_dir self.test_set = dict() self.verbose_log = False self.log_dlgHlpr = None self.test_set_action_group = QtWidgets.QActionGroup(app_win) self.test_set_action_group.addAction(self.main_win.actionUOSS_2016) self.test_set_action_group.addAction(self.main_win.actionAAK_2015) self.test_set_action_group.addAction(self.main_win.actionXPFO_2016) self.test_set_action_group.addAction(self.main_win.actionALE) self.test_set_action_group.addAction(self.main_win.actionERM) self.test_set_action_group.addAction(self.main_win.actionRPN) self.test_set_action_group.addAction(self.main_win.actionTAU) self.test_set_action_group.addAction(self.main_win.actionBORG) self.test_set_action_group.addAction(self.main_win.actionPFO_CTBTO) self.test_set_action_group.addAction(self.main_win.actionSHEMLYA)
class MainWindowHelper(object): def __init__(self, cfg, app_win, main_win, app_root_dir): self.cfg = cfg self.cdm = CfgDataModel(self.cfg) self.app_win = app_win self.main_win = main_win self.cur_row = -1 self.main_win.sensARunBtn.setEnabled(False) self.main_win.sensBRunBtn.setEnabled(False) self.last_click = datetime.min self.app_root_dir = app_root_dir self.test_set = dict() self.verbose_log = False self.log_dlgHlpr = None self.test_set_action_group = QtWidgets.QActionGroup(app_win) self.test_set_action_group.addAction(self.main_win.actionUOSS_2016) self.test_set_action_group.addAction(self.main_win.actionAAK_2015) self.test_set_action_group.addAction(self.main_win.actionXPFO_2016) self.test_set_action_group.addAction(self.main_win.actionALE) self.test_set_action_group.addAction(self.main_win.actionERM) self.test_set_action_group.addAction(self.main_win.actionRPN) self.test_set_action_group.addAction(self.main_win.actionTAU) self.test_set_action_group.addAction(self.main_win.actionBORG) self.test_set_action_group.addAction(self.main_win.actionPFO_CTBTO) self.test_set_action_group.addAction(self.main_win.actionSHEMLYA) def setup_main_window(self): self.setup_actions() self.setup_tableview() def setup_actions(self): logging.debug('Setting up QActions') self.main_win.actionAbout_PyCal.triggered.connect(self.show_about) self.main_win.acViewLogMessages.triggered.connect(self.view_log_messages) self.main_win.actionUser_Guide.triggered.connect(self.open_user_guide) self.main_win.quitBtn.clicked.connect(self.main_win.actionQuit.trigger) self.main_win.sensARunBtn.clicked.connect(self.run_cal_A) self.main_win.sensBRunBtn.clicked.connect(self.run_cal_B) self.main_win.addBtn.clicked.connect(self.main_win.actionNew.trigger) self.main_win.editBtn.clicked.connect(self.main_win.actionEdit.trigger) self.main_win.actionNew.triggered.connect(self.AddCfg) self.main_win.actionEdit.triggered.connect(self.EditCfg) self.main_win.actionDelete.triggered.connect(self.delete_cfg) self.main_win.actionQuit.triggered.connect(self.close) self.main_win.actionVerbose_Log.triggered.connect(self.toggle_verbose) # self.main_win.testAnalysisBtn.clicked.connect(self.run_test_analysis) self.test_set_action_group.triggered.connect(self.set_test_set) def show_about(self): dlg = QtWidgets.QDialog(self.app_win) dlg.setModal(False) dlgUI = Ui_AboutDlg() dlgUI.setupUi(dlg) # dlg.setWindowTitle('PyCal - Log Viewer') # dlgHlpr = LogviewDlgHelper(pcgl.get_log_filename(), dlg, dlgUI) # self.log_dlgHlpr = dlgHlpr dlg.show() def toggle_verbose(self): self.verbose_log = not self.verbose_log if self.verbose_log: lvl = logging.disable(logging.NOTSET) else: lvl = logging.disable(logging.DEBUG) def set_test_set(self, action): if action == self.main_win.actionUOSS_2016: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'UOSS', 'loc' : 'TT', 'ip' : 'uoss10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-uoss10-sts2-rbhf-2016-0204-0612.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-uoss10-sts2-rbhf-2016-0204-0612.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-uoss10-sts2-rblf-2016-0204-0651.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-uoss10-sts2-rblf-2016-0204-0651.log' } elif action == self.main_win.actionAAK_2015: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'AAK', 'loc' : 'TT', 'ip' : 'aak10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-aak10-sts2.5-rbhf-2015-0605-0610.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-aak10-sts2.5-rbhf-2015-0605-0610.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-aak10-sts2.5-rblf-2015-0605-0648.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-aak10-sts2.5-rblf-2015-0605-0648.log' } elif action == self.main_win.actionXPFO_2016: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'XPFO', 'loc' : '50', 'ip' : '172.23.34.108', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-172.23.34.108-STS2_5-rbhf-2016-0602-2154.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-172.23.34.108-STS2_5-rbhf-2016-0602-2154.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-172.23.34.108-STS2_5-rblf-2016-0602-1718.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-172.23.34.108-STS2_5-rblf-2016-0602-1718.log' } elif action == self.main_win.actionPFO_CTBTO: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'PFO', 'loc' : 'TT', 'ip' : '198.202.124.228', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-198.202.124.228-sts2.5-rbhf-2016-0511-1213.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-198.202.124.228-sts2.5-rbhf-2016-0511-1213.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-198.202.124.228-sts2.5-rblf-2016-0511-1249.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-198.202.124.228-sts2.5-rblf-2016-0511-1249.log' } elif action == self.main_win.actionALE: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'ALE', 'loc' : 'TT', 'ip' : 'ale10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-ale10-sts2-rbhf-2015-0903-1826.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-ale10-sts2-rbhf-2015-0903-1826.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-ale10-sts2-rblf-2015-0903-1859.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-ale10-sts2-rblf-2015-0903-1859.log' } elif action == self.main_win.actionBORG: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'BORG', 'loc' : 'TT', 'ip' : 'borg10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-borg10-sts2-rbhf-2015-1020-2358.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-borg10-sts2-rbhf-2015-1020-2358.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-borg10-sts2-rblf-2015-1021-0037.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-borg10-sts2-rblf-2015-1021-0037.log' } elif action == self.main_win.actionERM: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'ERM', 'loc' : 'TT', 'ip' : 'erm10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-erm10-sts2-rbhf-2015-0819-0609.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-erm10-sts2-rbhf-2015-0819-0609.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-erm10-sts2-rblf-2015-0819-0647.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-erm10-sts2-rblf-2015-0819-0647.log' } elif action == self.main_win.actionRPN: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'RPN', 'loc' : 'TT', 'ip' : 'rpn10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-rpn10-sts2.5-rbhf-2015-0701-0612.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-rpn10-sts2.5-rbhf-2015-0701-0612.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-rpn10-sts2.5-rblf-2015-0701-0650.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-rpn10-sts2.5-rblf-2015-0701-0650.log' } elif action == self.main_win.actionTAU: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'TAU', 'loc' : 'TT', 'ip' : 'tau10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-tau10-sts2-rbhf-2016-0127-0622.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-tau10-sts2-rbhf-2016-0127-0622.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-tau10-sts2-rblf-2016-0127-0700.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-tau10-sts2-rblf-2016-0127-0700.log' } elif action == self.main_win.actionSHEMLYA: self.test_set = { 'seis_model' : SEISTYPE_STS25, 'sta' : 'SHEM', 'loc' : '', 'ip' : 'shem10', 'hf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-SHEMLYA-STS25_2016-05-25-HF.ms', 'hf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-SHEMLYA-STS25_2016-05-25-HF.log', 'lf_msfn' : '/Users/dauerbach/dev/ical/src/CAL-SHEMLYA-STS25_2016-05-25-LF.ms', 'lf_logfn' : '/Users/dauerbach/dev/ical/src/CAL-SHEMLYA-STS25_2016-05-25-LF.log' } # CAL-SHEMLYA-STS25_2016-05-25- def setup_tableview(self): #MainWindow, mw_ui): logging.debug('Setting up QTableview') self.main_win.cfgListTV.setModel(self.cdm) hdrvw = self.main_win.cfgListTV.horizontalHeader() hdrvw.setStretchLastSection(True) self.main_win.cfgListTV.resizeColumnsToContents() self.main_win.cfgListTV.setSortingEnabled(False) self.main_win.cfgListTV.clicked.connect(self.record_click) self.main_win.cfgListTV.selectionModel().selectionChanged.connect(self.MWSelectionChanged) self.update_details(-1) def close(self): self.app_win.close() def view_log_messages(self): if self.log_dlgHlpr: dlg = self.log_dlgHlpr.qtDlg dlgUI = self.log_dlgHlpr.dlgUI else: dlg = QtWidgets.QDialog(self.app_win) dlg.setModal(False) dlgUI = Ui_LogviewDlg() dlgUI.setupUi(dlg) dlg.setWindowTitle('PyCal - Log Viewer') dlgHlpr = LogviewDlgHelper(pcgl.get_log_filename(), dlg, dlgUI) self.log_dlgHlpr = dlgHlpr dlg.show() def open_user_guide(self): if os.path.exists(pcgl.get_user_guide_fullpath()): call(['open', pcgl.get_user_guide_fullpath()]) def MWSelectionChanged(self, seldelta, deseldelta): sel_ndxs = self.main_win.cfgListTV.selectedIndexes() if len(sel_ndxs) >= 1: self.cur_row = sel_ndxs[0].row() else: self.cur_row = -1 self.update_details(self.cur_row) def record_click(self): gap = datetime.now() - self.last_click self.last_click = datetime.now() if (gap.seconds + gap.microseconds/10.0**6) < 0.25: self.EditCfg() def setup_edit_dialog(self, edit_mode, cur_data={}): dlg = QtWidgets.QDialog(self.app_win) dlgUI = Ui_EditDlg() dlgUI.setupUi(dlg) dlgUIHlpr = EditDlgHelper() dlgUIHlpr.sensorlist = self.cfg.sensor_list() dlgUIHlpr.setupUi(cur_data, edit_mode, dlg, dlgUI) if edit_mode == EditDlgHelper.EDIT_MODE: dlg.setWindowTitle('PyCal - Edit Configuration') elif edit_mode == EditDlgHelper.ADD_MODE: dlg.setWindowTitle('PyCal - Add New Configuration') return (dlg, dlgUI, dlgUIHlpr) def EditCfg(self): if self.cur_row >= 0: # get tagno and then wcfg... mdlNdx = QtCore.QAbstractItemModel.createIndex(self.cdm, self.cur_row, CfgDataModel.TAGNO_COL) tagno = self.cdm.data(mdlNdx, QtCore.Qt.DisplayRole) logging.info('Editing configuration for Q330 with Tag # {}'.format(tagno)) wcfg = self.cfg.find(tagno) if wcfg: dlg, dlgUI, dlgUIHlpr = self.setup_edit_dialog(EditDlgHelper.EDIT_MODE, wcfg.data) # need to keep dlgUIHlpr in scope for GUI callbacks if dlg.exec() == QtWidgets.QDialog.Accepted: try: self.cdm.UpdateCfg(wcfg.tagno(), dlgUI.new_cfg) logging.debug('PyCal Q330 configuration updated.') # if tagno changed get new tagno and ndx of row to select the currect row when done ndx = self.cfg.index_from_tagno(dlgUI.new_cfg[WrapperCfg.WRAPPER_KEY_TAGNO]) if ndx is not None: self.cur_row = ndx except Exception as e: logging.error('Error saving PyCal Q330 config record. ' + str(e)) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', str(e), QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) self.main_win.cfgListTV.resizeColumnsToContents() else: logging.info('Editing cancelled by user.') dlg, dlgUI, dlgUIHlpr = None, None, None self.main_win.cfgListTV.selectRow(self.cur_row) def delete_cfg(self): if self.cur_row >= 0: # get tagno and delete mdlNdx = QtCore.QAbstractItemModel.createIndex(self.cdm, self.cur_row, CfgDataModel.TAGNO_COL) tagno = self.cdm.data(mdlNdx, QtCore.Qt.DisplayRole) if tagno: msg_box = QtWidgets.QMessageBox() msg_box.setIcon(QtWidgets.QMessageBox.Warning) msg_box.setText('DELETE config for Q330 with Tag # {}?'.format(tagno)) msg_box.setInformativeText('This is permanent!') msg_box.setDefaultButton(QtWidgets.QMessageBox.Cancel) del_btn = msg_box.addButton("DELETE", QtWidgets.QMessageBox.DestructiveRole); cancel_btn = msg_box.addButton(QtWidgets.QMessageBox.Cancel); msg_box.exec() if msg_box.clickedButton() == del_btn: logging.info('Deleting configuration for Q330 with Tag # {}'.format(tagno)) self.cfg.remove(tagno) self.cdm.endResetModel() self.cur_row = -1 self.update_details(self.cur_row) self.main_win.cfgListTV.resizeColumnsToContents() def AddCfg(self): logging.info('Adding new q330 configuration') dlg, dlgUI, dlgUIHlpr = self.setup_edit_dialog(EditDlgHelper.ADD_MODE, WrapperCfg.new_dict()) # need to keep dlgUIHlpr in scope for GUI callbacks if dlg.exec() == QtWidgets.QDialog.Accepted: try: self.cdm.AddCfg(dlgUI.new_cfg) new_tag_no = dlgUI.new_cfg[WrapperCfg.WRAPPER_KEY_TAGNO] ndx = self.cfg.index_from_tagno(new_tag_no) if ndx is not None: self.cur_row = ndx self.main_win.cfgListTV.selectRow(self.cur_row) logging.debug('New PyCal Q330 configuration saved.') except Exception as e: logging.error('Error saving new PyCal Q330 config record. ' + str(e)) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', str(e), QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) else: logging.info('Add new configuration cancelled by user.') # self.cur_Row = -1 # self.update_details(self.cur_row) self.main_win.cfgListTV.resizeColumnsToContents() def run_analysis(self, method, *args): dlg = ProgressDlg() dlgUI = Ui_AnalysisProgressFrm() dlgUI.setupUi(dlg) dlg.setWindowTitle('PyCal - Data Analysis') dlgHlpr = AnalysisProgressDlgHelper(dlg, dlgUI) res, msg_fn, amppltfn, phapltfn = dlgHlpr.run_analysis(method, *args) if res == -1: logging.warning('Analysis canceled by user.') elif res == 0: logging.info('Analysis completed.') return res, msg_fn, amppltfn, phapltfn def cool_off_q330(self, window_title= '', info_text='', cooling_period_seconds=330): dlg = ProgressDlg() dlgUI = Ui_CoolOffFrm() dlgUI.setupUi(dlg) dlgUI.infoLbl.setText(info_text) dlg.setWindowTitle(window_title) dlgHlpr = CoolOffDlgHelper(dlg, dlgUI) dlgHlpr.cooling_period_seconds = cooling_period_seconds success = dlgHlpr.exec() == QtWidgets.QDialog.Accepted if (success): logging.info('cool off completed.') else: logging.warning('cool off canceled by user during q330 cool off with msg: ' + info_text) return success def run_test_analysis(self): QtWidgets.QMessageBox().information(self.app_win, 'PyCal Analysis', 'Calibration data acquired successfully.\n\n' 'The data will now be analyzed.\n' 'This could take several minutes.', QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) channel_codes = ComponentsTpl(north='BHN', east='BHE', vertical='BHZ') sensor = 'A' seis_model = SEISTYPE_STS25 # sta = 'AS108' # loc = '10' # ip = '198.202.124.228' # hf_msfn = 'CAL-198.202.124.228-sts2.5-rbhf-2016-0511-1213.ms' # hf_logfn = 'CAL-198.202.124.228-sts2.5-rbhf-2016-0511-1213.log' # lf_msfn = 'CAL-198.202.124.228-sts2.5-rblf-2016-0511-1249.ms' # lf_logfn = 'CAL-198.202.124.228-sts2.5-rblf-2016-0511-1249.log' # # # XPFO "Fast" test # seis_model = 'sts2.5-F' # sta='XPFO' # ip = '172.23.34.108' # hf_msfn = 'CAL-172.23.34.108-sts2.5-F-rbhf-2016-0511-0838.ms' # hf_logfn = 'CAL-172.23.34.108-sts2.5-F-rbhf-2016-0511-0838.log' # lf_msfn = 'CAL-172.23.34.108-sts2.5-F-rblf-2016-0511-0836.ms' # lf_logfn = 'CAL-172.23.34.108-sts2.5-F-rblf-2016-0511-0836.log' # seis_model = self.test_set['seis_model'] sta = self.test_set['sta'] ip = self.test_set['ip'] loc = self.test_set['loc'] hf_msfn = self.test_set['hf_msfn'] hf_logfn = self.test_set['hf_logfn'] lf_msfn = self.test_set['lf_msfn'] lf_logfn = self.test_set['lf_logfn'] output_dir = os.path.join(pcgl.get_results_root(), '-'.join([sta, ip.replace('.','_'), sensor, seis_model])) if seis_model in SEISMOMETER_RESPONSES: if getattr(sys, 'frozen', False): bundle_dir = sys._MEIPASS full_paz_fn = os.path.abspath(os.path.join(bundle_dir, 'IDA', 'data', SEISMOMETER_RESPONSES[seis_model]['full_resp_file'])) else: full_paz_fn = os.path.abspath(os.path.join('.', 'data', SEISMOMETER_RESPONSES[seis_model]['full_resp_file'])) else: msg1 = 'PyCal does not have response information for SENSOR MODEL: ' + seis_model msg2 = 'Analysis can not be performed.' logging.error(msg1) logging.error(msg2) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', msg1 + '\n' + msg2, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) return logging.info('Analysis starting...') logging.debug('Using FULL response at: ' + full_paz_fn) retcode, \ ims_calres_txt_fn, \ cal_amp_plot_fn, \ cal_pha_plot_fn = self.run_analysis(process_qcal_data, sta, channel_codes, loc, output_dir, (lf_msfn, lf_logfn), (hf_msfn, hf_logfn), seis_model, full_paz_fn) if retcode == 0: call(['open', output_dir]) call(['open', '-a', 'TextEdit', ims_calres_txt_fn]) call(['open', cal_amp_plot_fn]) call(['open', cal_pha_plot_fn]) msg_list = ['Results can be found in directory:\n\n{}\n\n'.format(output_dir), '{}\n{}\n\n'.format('IMS 2.0 MESSAGE TEMPLATE:', os.path.basename(ims_calres_txt_fn)), '{}\n{}\n\n'.format('AMP PLOTS:', os.path.basename(cal_amp_plot_fn)), '{}\n{}'.format('PHASE PLOTS:', os.path.basename(cal_pha_plot_fn))] logging.info('The following files have been saved in directory: ' + output_dir) logging.info(' IMS 2.0 MESSAGE TEMPLATE: ' + os.path.basename(ims_calres_txt_fn)) logging.info(' Amplitude Response Plots: ' + os.path.basename(cal_amp_plot_fn)) logging.info(' Phase Response Plots: ' + os.path.basename(cal_pha_plot_fn)) res = QtWidgets.QMessageBox().information(self.app_win, 'PyCal', 'Calibration completed successfully!\n\n' + ''.join(msg_list), QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) def run_sensor_cal_type(self, sensor, caltype, cal_info): completed = False logging.info('Running {} calibration for sensor {} on q330 (hostname: {})'.format(caltype.upper(), sensor, cal_info['ip'])) # create qcal thread qcal_thread = QCalThread(os.path.join(self.app_root_dir, pcgl.get_bin_root()), cal_info['cmd_line'][caltype], cal_info['output_dir']) ping_thread = PingThread(cal_info['ip']) dlg = QtWidgets.QDialog(self.app_win) dlg = ProgressDlg(self.app_win) progdlg = Ui_ProgressDlg() progdlg.setupUi(dlg) dlg.setWindowTitle('PyCal - Data Acquisition') if caltype == CALTYPE_RBLF: cal_descr = 'Calibration Signal: LOW Frequency Random Binary\n\n' + cal_info['cal_descr'] elif caltype == CALTYPE_RBHF: cal_descr = 'Calibration Signal: HIGH Frequency Random Binary\n\n' + cal_info['cal_descr'] else: msg = 'Invalid CALIBRATION TYPE:' + caltype logging.error(msg) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', msg, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) return False, None progdlgHlpr = ProgressDlgHelper(dlg, cal_descr, cal_info['cal_time'][caltype], progdlg, qcal_thread, ping_thread) progdlgHlpr.start() if (dlg.exec() == QtWidgets.QDialog.Accepted) and (progdlgHlpr.retcode == 0): completed = True msg = 'Calibration completed successfully. Miniseed file saved: {}'.format(progdlgHlpr.calmsfn) logging.info(msg) # res = QtWidgets.QMessageBox().information(self.app_win, 'PyCal', # 'Calibration Completed!\n\n' + progdlgHlpr.msg, # QtWidgets.QMessageBox().Close, # QtWidgets.QMessageBox().Close) else: completed = False msg1 = 'Calibration failed with exit code: {}'.format(progdlgHlpr.retcode) msg2 = 'Calibration failed with message: {}'.format(progdlgHlpr.msg) logging.error(msg1) logging.error(msg2) res = QtWidgets.QMessageBox().critical(self.app_win, 'PyCal', msg2, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) return completed, progdlgHlpr.calmsfn def run_sensor_cal(self, sensor): if (self.cur_row < 0): msg = 'No Q330 has been seleceted' logging.info(msg) res = QtWidgets.QMessageBox().warning(self.app_win, 'PyCal', msg, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) else: wcfg = self.cfg[self.cur_row] if sensor not in ['A', 'B']: msg = 'Invalid sensor can not be calibrated:' + sensor logging.error(msg) raise Exception(msg) if sensor == 'A': seis_model = wcfg.data[WrapperCfg.WRAPPER_KEY_SENS_COMPNAME_A] sensor_descr = wcfg.data[WrapperCfg.WRAPPER_KEY_SENS_DESCR_A] chancodes = wcfg.data[WrapperCfg.WRAPPER_KEY_CHANNELS_A] loc = wcfg.data[WrapperCfg.WRAPPER_KEY_LOCATION_A] elif sensor == 'B': seis_model = wcfg.data[WrapperCfg.WRAPPER_KEY_SENS_COMPNAME_B] sensor_descr = wcfg.data[WrapperCfg.WRAPPER_KEY_SENS_DESCR_B] chancodes = wcfg.data[WrapperCfg.WRAPPER_KEY_CHANNELS_B] loc = wcfg.data[WrapperCfg.WRAPPER_KEY_LOCATION_B] # replace 'no LOC' underscores with spaces. loc = loc.replace('_', ' ') # lets just make sure sensor in CTBTO supported list # should never get here is cfg files deployed correctly if seis_model not in CTBTO_SEIS_MODELS: msg = 'PyCal UNSUPPORTED SENSOR MODEL: ' + seis_model logging.error(msg) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', msg, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) return lf_calib = self.cfg.find_calib(seis_model + '|' + CALTYPE_RBLF) hf_calib = self.cfg.find_calib(seis_model + '|' + CALTYPE_RBHF) if (not lf_calib) or (not hf_calib): msg = 'Calib Record missing for sensor [{}].'.format(seis_model) logging.error(msg) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', msg, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) return sta = wcfg.data[WrapperCfg.WRAPPER_KEY_STA] ip = wcfg.data[WrapperCfg.WRAPPER_KEY_IP] output_dir = os.path.join(pcgl.get_results_root(), '-'.join([sta, ip.replace('.', '_'), sensor, seis_model])) makedirs(output_dir, mode=0o744, exist_ok=True) cal_descr = '{:>11} : {:<6} at {}'.format('Q330 Tag#', wcfg.data[WrapperCfg.WRAPPER_KEY_TAGNO], ip) cal_descr += '\n{:>11} : {} (Sensor {})'.format('Sensor', sensor_descr, sensor) cal_descr += '\n{:>11} : {}'.format('Station', wcfg.data[WrapperCfg.WRAPPER_KEY_STA]) cal_descr += '\n{:>11} : {}'.format('Loc', loc) cal_descr += '\n{:>11} : {}'.format('Chan Codes', chancodes) tot_cal_time = lf_calib.cal_time_min() + hf_calib.cal_time_min() cal_info = { 'sta' : sta, 'loc' : loc, 'chancodes' : chancodes, 'ip' : ip, 'seis_model' : seis_model, 'cal_descr': cal_descr, 'cal_tot_time_mins': tot_cal_time, 'cal_time' : { CALTYPE_RBLF : lf_calib.cal_time_min(), CALTYPE_RBHF : hf_calib.cal_time_min(), }, 'cmd_line' : { CALTYPE_RBHF : wcfg.gen_qcal_cmdline(sensor, CALTYPE_RBHF) + ' root=' + self.cfg.root_dir, CALTYPE_RBLF : wcfg.gen_qcal_cmdline(sensor, CALTYPE_RBLF) + ' root=' + self.cfg.root_dir }, 'output_dir': output_dir } logging.debug('cal_info:' + str(cal_info)) success, lf_msfn = self.run_sensor_cal_type(sensor, CALTYPE_RBLF, cal_info) if success: lf_logfn = os.path.splitext(lf_msfn)[0] + '.log' logging.info('QCal RBLF Miniseed file saved: ' + os.path.join(output_dir, lf_msfn)) logging.info('QCal RBLF Log file saved: ' + os.path.join(output_dir, lf_logfn)) # need 5.5 minute "cooling off period" before starting HF run if not self.cool_off_q330(window_title='PyCal - Preparing for HF Stage', info_text='Preparing for HF calibration stage...', cooling_period_seconds=330): return success, hf_msfn = self.run_sensor_cal_type(sensor, CALTYPE_RBHF, cal_info) if success: chancodeslst = chancodes.split(',') channel_codes = ComponentsTpl(vertical=chancodeslst[0], north=chancodeslst[1], east=chancodeslst[2]) hf_logfn = os.path.splitext(hf_msfn)[0] + '.log' logging.info('QCal RBHF Miniseed file saved: ' + os.path.join(output_dir, hf_msfn)) logging.info('QCal RBHF Log file saved: ' + os.path.join(output_dir, hf_logfn)) # msg_box = QtWidgets.QMessageBox(self.app_win) # msg_box.setIcon(QtWidgets.QMessageBox.Information) # msg_box.setText('PyCal Analysis Phase Starting') # msg_box.setInformativeText( # 'Calibration data acquired successfully.\n\n' + # 'The data will now be analyzed.\n' + # 'This will take several minutes.') # btn = msg_box.addButton('Continue...', QtWidgets.QMessageBox.RejectRole) # msg_box.setDefaultButton(btn) # msg_box.exec() # if seis_model in SEISMOMETER_RESPONSES: if getattr(sys, 'frozen', False): bundle_dir = sys._MEIPASS full_paz_fn = os.path.abspath(os.path.join(bundle_dir, 'IDA', 'data', SEISMOMETER_RESPONSES[seis_model]['full_resp_file'])) else: full_paz_fn = os.path.abspath(os.path.join('.', 'data', SEISMOMETER_RESPONSES[seis_model]['full_resp_file'])) else: msg1 = 'PyCal does not have response information for SENSOR MODEL: ' + seis_model msg2 = 'Analysis can not be performed.' logging.error(msg1) logging.error(msg2) QtWidgets.QMessageBox().critical(self.app_win, 'PyCal ERROR', msg1 + '\n' + msg2, QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) return logging.info('Analysis starting...') logging.debug('Using FULL response at: ' + full_paz_fn) retcode, \ ims_calres_txt_fn, \ cal_amp_plot_fn, \ cal_pha_plot_fn = self.run_analysis(process_qcal_data, sta, channel_codes, loc, output_dir, (lf_msfn, lf_logfn), (hf_msfn, hf_logfn), seis_model, full_paz_fn) if retcode == 0: logging.info('Analysis phase completed with return code: {}'.format(retcode)) logging.info('The following files have been saved in directory: ' + output_dir) logging.info(' {} {}'.format('CALIBRATE_RESULT Msg: ', os.path.basename(ims_calres_txt_fn))) logging.info(' {} {}'.format('Amplitude Response Plots: ', os.path.basename(cal_amp_plot_fn))) logging.info(' {} {}'.format('Phase Response Plots: ', os.path.basename(cal_pha_plot_fn))) msg_list = ['Result files saved in directory:\n\n{}\n\n'.format(output_dir), '{}\n{}\n\n'.format('IMS 2.0 MESSAGE TEMPLATE:', os.path.basename(ims_calres_txt_fn)), '{}\n{}\n\n'.format('AMP PLOTS:', os.path.basename(cal_amp_plot_fn)), '{}\n{}'.format('PHASE PLOTS:', os.path.basename(cal_pha_plot_fn))] res = QtWidgets.QMessageBox().information(self.app_win, 'PyCal', 'Calibration completed successfully!\n\n' + ''.join(msg_list), QtWidgets.QMessageBox().Close, QtWidgets.QMessageBox().Close) call(['open', output_dir]) call(['open', '-a', 'TextEdit', ims_calres_txt_fn]) call(['open', cal_amp_plot_fn]) call(['open', cal_pha_plot_fn]) else: logging.warning('Analysis phase completed with return code: {}'.format(retcode)) else: self.update_details(self.cur_row) # triggers comms check... else: self.update_details(self.cur_row) # triggers comms check... logging.error("Unable to complete calibration") def run_cal_A(self): if self.cur_row != -1: qtDlg = ProgressDlg() dlgUI = Ui_EstConnFrm() dlgUI.setupUi(qtDlg) qtDlg.setWindowTitle('PyCal - Connecting to Q330') wcfg = self.cfg[self.cur_row] estcomms = EstCommsDlgHelper(qtDlg, dlgUI, 'A', wcfg) if estcomms.exec() == QtWidgets.QDialog.Accepted: self.run_sensor_cal('A') def run_cal_B(self): if self.cur_row != -1: qtDlg = ProgressDlg() dlgUI = Ui_EstConnFrm() dlgUI.setupUi(qtDlg) qtDlg.setWindowTitle('PyCal - Connecting to Q330') wcfg = self.cfg[self.cur_row] estcomms = EstCommsDlgHelper(qtDlg, dlgUI, 'B', wcfg) if estcomms.exec() == QtWidgets.QDialog.Accepted: self.run_sensor_cal('B') def update_details(self, row): print('update_details row:', row) self.main_win.editBtn.setEnabled(row != -1) self.main_win.actionEdit.setEnabled(row != -1) self.main_win.actionDelete.setEnabled(row != -1) if row == -1: self.set_details(row) self.main_win.sensARunBtn.setEnabled(False) self.main_win.sensBRunBtn.setEnabled(False) else: cfg = self.cfg[row] self.set_details(row) self.main_win.sensARunBtn.setEnabled((cfg.data[WrapperCfg.WRAPPER_KEY_SENS_COMPNAME_A] != WrapperCfg.WRAPPER_KEY_NONE)) self.main_win.sensBRunBtn.setEnabled((cfg.data[WrapperCfg.WRAPPER_KEY_SENS_COMPNAME_B] != WrapperCfg.WRAPPER_KEY_NONE)) def set_details(self, cfg_ndx): if cfg_ndx == -1: self.main_win.netLE.setText('') self.main_win.staLE.setText('') self.main_win.ipLE.setText('') self.main_win.tagnoLE.setText('') self.main_win.snLE.setText('') self.main_win.dpLE.setText('') self.main_win.dpauthLE.setText('') self.main_win.sensADescrLE.setPlainText('') self.main_win.sensAMonPortLE.setText('') self.main_win.sensAPriChansLE.setText('') self.main_win.sensBDescrLE.setPlainText('') self.main_win.sensBMonPortLE.setText('') self.main_win.sensBPriChansLE.setText('') else: cfg = self.cfg[cfg_ndx] self.main_win.netLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_NET]) self.main_win.staLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_STA]) self.main_win.ipLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_IP]) self.main_win.tagnoLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_TAGNO]) self.main_win.snLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_SN]) self.main_win.dpLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_DATAPORT]) self.main_win.dpauthLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_DP1_AUTH]) self.main_win.sensADescrLE.setPlainText(cfg.data[WrapperCfg.WRAPPER_KEY_SENS_DESCR_A]) if cfg.data[WrapperCfg.WRAPPER_KEY_SENS_ROOTNAME_A].lower() == WrapperCfg.WRAPPER_KEY_NONE: self.main_win.sensAMonPortLE.setText('') self.main_win.sensAPriChansLE.setText('') else: self.main_win.sensAMonPortLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_MONPORT_A]) self.main_win.sensAPriChansLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_CHANNELS_A]) self.main_win.sensBDescrLE.setPlainText(cfg.data[WrapperCfg.WRAPPER_KEY_SENS_DESCR_B]) if cfg.data[WrapperCfg.WRAPPER_KEY_SENS_ROOTNAME_B].lower() == WrapperCfg.WRAPPER_KEY_NONE: self.main_win.sensBMonPortLE.setText('') self.main_win.sensBPriChansLE.setText('') else: self.main_win.sensBMonPortLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_MONPORT_B]) self.main_win.sensBPriChansLE.setText(cfg.data[WrapperCfg.WRAPPER_KEY_CHANNELS_B])