Ejemplo n.º 1
0
    def __on_run_button_click(self):
        """
        Creates a HapiWorker to run the Select query.
        """
        selected_params = self.get_select_parameters()
        table_name = self.get_select_table_name()
        new_table_name = self.get_output_table_name()
        expression = self.get_select_expression()
        parsed_expression = DSL.parse_expression(expression)

        if parsed_expression == None and expression.strip() != '':
            err_log('Invalid select expression.')
            return
        if table_name == new_table_name:
            err_log(
                'Cannot have select output table be the same as the input table'
            )
            return

        self.run_button.setDisabled(True)

        args = HapiWorker.echo(ParameterNames=selected_params,
                               TableName=table_name,
                               DestinationTableName=new_table_name,
                               Conditions=parsed_expression)

        worker = HapiWorker(WorkRequest.SELECT, args, self.__on_run_done)
        self.parent.workers.append(worker)
        worker.start()
Ejemplo n.º 2
0
    def add_worker(self, graph_ty, work_object):
        id = self.cur_work_id
        self.cur_work_id += 1
        worker = HapiWorker(GraphDisplayWidget.graph_ty_to_work_ty[graph_ty], work_object,
                            lambda x: (self.plot(x), self.workers.pop(id)))

        self.workers[id] = worker
        worker.start()
Ejemplo n.º 3
0
 def __on_fetch_clicked(self, _checked: bool):
     xscs = self.get_selected_xscs()
     if len(xscs) == 0:
         return
     args = HapiWorker.echo(xscs=xscs,
                            molecule_name=self.molecule.currentText())
     self.fetch_button.setDisabled(True)
     self.worker = HapiWorker(WorkRequest.DOWNLOAD_XSCS, args,
                              self.__on_fetch_xsc_done)
     self.worker.start()
Ejemplo n.º 4
0
    def __on_data_name_changed(self, new_table):
        """
        Disables all graph buttons. (Inner method callback : enables graph buttons if necessary
        params to graph are supplied.)
        """
        self.set_graph_buttons_enabled(False)
        self.same_window_checked = self.use_existing_window.isChecked()

        def callback(work_result):
            self.remove_worker_by_jid(work_result.job_id)
            result = work_result.result
            if result is None:
                return

            self.plot_name.setText(self.data_name.currentText())

            if 'parameters' not in result:
                self.set_graph_buttons_enabled(True)
                return

            if not result['xsc']:
                for param in GraphingWidget.parameters_required_to_graph:
                    if param not in result['parameters']:
                        err_log('Table does not contain required parameters.')
                        return

            self.numin.setValue(result['numin'])
            self.numax.setValue(result['numax'])
            self.set_graph_buttons_enabled(True)

            # Cross sections can only be graphed as cross sections
            if result['xsc'] is not None:
                self.set_xsc_mode(True)
                self.graph_type.clear()
                self.graph_type.addItems([GraphingWidget.XSC_STRING])
            else:
                # Normal tables can be graphed as anything other than a cross section
                self.set_xsc_mode(False)
                self.graph_type.clear()
                graph_types = list(GraphingWidget.str_to_graph_ty.keys())
                graph_types.remove(GraphingWidget.XSC_STRING)
                self.graph_type.addItems(
                    list(GraphingWidget.str_to_graph_ty.keys()))

            self.xsc = result['xsc']
            self.use_existing_window.setChecked(self.same_window_checked)

        self.broadener_input.set_table(new_table)

        worker = HapiWorker(WorkRequest.TABLE_META_DATA,
                            {'table_name': new_table}, callback)
        self.workers.append(worker)
        worker.start()
Ejemplo n.º 5
0
    def __on_select_table_name_selection_changed(self, new_selection):
        """
        When the table that is being worked with changes, update the parameter list.
        """
        self.run_button.setDisabled(True)
        if new_selection == '':
            return

        args = HapiWorker.echo(table_name=new_selection)

        worker = HapiWorker(WorkRequest.TABLE_META_DATA, args,
                            self.__on_select_table_name_complete)
        worker.start()
        self.parent.workers.append(worker)
Ejemplo n.º 6
0
    def graph_as(self, standard_params):
        path_length = self.get_path_length()
        instrumental_fn = self.get_instrumental_fn()
        AF_wing = self.get_instrumental_fn_wing()
        Resolution = self.get_instrumental_resolution()

        if standard_params['WavenumberStep'] is None:
            standard_params['WavenumberStep'] = Resolution / 2
        elif standard_params['WavenumberStep'] <= Resolution:
            standard_params[
                'WavenumberStep'] = Resolution * 1.0001  # err_log('Wavenumber Step must be less
            # than Instrumental Resolution')  # self.done_graphing()  # return

        work = HapiWorker.echo(title=GraphingWidget.ABSORPTION_SPECTRUM_STRING,
                               titlex="Wavenumber (cm$^{-1}$)",
                               titley="Absorption Spectrum",
                               path_length=path_length,
                               instrumental_fn=instrumental_fn,
                               Resolution=Resolution,
                               AF_wing=AF_wing,
                               **standard_params)
        if self.use_existing_window.isChecked():
            selected_window = self.get_selected_window()
            if selected_window in GraphDisplayWidget.graph_windows:
                GraphDisplayWidget.graph_windows[selected_window].add_worker(
                    GraphType.ABSORPTION_SPECTRUM, work)
                return

        GraphDisplayWidget(GraphType.ABSORPTION_SPECTRUM, work,
                           self.backend.currentText())
        self.update_existing_window_items()
Ejemplo n.º 7
0
 def graph_bands(self, _standard_params):
     work = HapiWorker.echo(TableName=self.get_data_name(), title="Bands")
     if self.use_existing_window.isChecked():
         selected_window = self.get_selected_window()
         if selected_window in GraphDisplayWidget.graph_windows:
             GraphDisplayWidget.graph_windows[selected_window].add_worker(
                 GraphType.BANDS, work)
             return
     BandDisplayWidget(work, self.backend.currentText())
     self.update_existing_window_items()
Ejemplo n.º 8
0
    def graph_xsc(self, standard_params):
        work = HapiWorker.echo(title=GraphingWidget.XSC_STRING,
                               titlex="Wavenumber (cm$^{-1}$)",
                               titley="Intensity",
                               **standard_params)
        if self.use_existing_window.isChecked():
            selected_window = self.get_selected_window()
            if selected_window in GraphDisplayWidget.graph_windows:
                GraphDisplayWidget.graph_windows[selected_window].add_worker(
                    GraphType.XSC, work)
                return

        _ = GraphDisplayWidget(GraphType.XSC, work, self.backend.currentText())
Ejemplo n.º 9
0
    def __init__(self, graph_ty: GraphType, work_object: Dict, backend: str):
        """
        Initializes the GUI and sends a work request for the graph to be plotted, and connect
        signals to the appropriate handler methods.

        :param ty the type of graph to be calculated. May be different for different types of graphs
        :param work_object has information about the graph that is to be made
        :param parent the parent QObject

        """
        QMainWindow.__init__(self)
        self.n_plots = 0
        self.plots = {}

        self.graph_ty = graph_ty
        self.graph_display_id = GraphDisplayWidget.graph_display_id()
        self.workers = {
            0: HapiWorker(GraphDisplayWidget.graph_ty_to_work_ty[graph_ty], work_object,
                          lambda x: (self.plot(x), self.workers.pop(0)))
            }

        GraphDisplayWidget.graph_windows[self.graph_display_id] = self

        self.workers[0].start()
        self.cur_work_id = 1

        from widgets.graphing.graphing_widget import GraphingWidget

        self.done_signal.connect(lambda: GraphingWidget.GRAPHING_WIDGET_INSTANCE.done_graphing())
        self.setWindowTitle(f"{work_object['title']} - {str(self.graph_display_id)}")

        self.setWindowIcon(program_icon())
        self.as_json: QAction = None


        uic.loadUi('layouts/graph_display_window.ui', self)

        self.as_json.triggered.connect(self.__on_save_as_json_triggered)
        self.as_csv.triggered.connect(self.__on_save_as_csv_triggered)

        if backend == "matplotlib":
            self.backend = MplWidget(self)
        else:
            self.backend = VispyWidget(self)

        self.setCentralWidget(self.backend)
        self.series = []

        self.setWindowTitle(f"Graphing window {self.graph_display_id}")
        self.show()
Ejemplo n.º 10
0
    def __init__(self, work_object: Dict, backend: str):
        QMainWindow.__init__(self, None)

        self.graph_ty = GraphType.BANDS

        self.legend = BandLegend(self)

        self.graph_display_id = GraphDisplayWidget.graph_display_id()
        self.workers = {
            0:
            HapiWorker(GraphDisplayWidget.graph_ty_to_work_ty[self.graph_ty],
                       work_object, lambda x:
                       (self.plot_bands(x), self.workers.pop(0)))
        }

        GraphDisplayWidget.graph_windows[self.graph_display_id] = self

        self.workers[0].start()
        self.cur_work_id = 1

        from widgets.graphing.graphing_widget import GraphingWidget

        self.done_signal.connect(
            lambda: GraphingWidget.GRAPHING_WIDGET_INSTANCE.done_graphing())
        self.setWindowTitle(
            f"{work_object['title']} - {str(self.graph_display_id)}")

        self.setWindowIcon(program_icon())

        uic.loadUi('layouts/graph_display_window.ui', self)

        if backend == "matplotlib":
            self.backend = MplWidget(self)
        else:
            self.backend = VispyWidget(self)

        self.central_widget: QSplitter = QSplitter()
        self.central_widget.addWidget(self.backend)
        self.central_widget.addWidget(self.legend)
        self.setCentralWidget(self.central_widget)
        self.series = []

        self.setWindowTitle(f"Graphing window {self.graph_display_id}")
        self.show()
Ejemplo n.º 11
0
 def graph_abs_coef(self, standard_parameters):
     work = HapiWorker.echo(
         title=GraphingWidget.ABSORPTION_COEFFICIENT_STRING,
         titlex="Wavenumber (cm$^{-1}$)",
         titley='Absorption Coefficient ',
         **standard_parameters)
     if work['SourceTables'][0].endswith('.xsc'):
         work['titley'] = 'molecules / cm$^2$'
         work['title'] = 'Absorption Cross-Section'
     if self.use_existing_window.isChecked():
         selected_window = self.get_selected_window()
         if selected_window in GraphDisplayWidget.graph_windows:
             GraphDisplayWidget.graph_windows[selected_window].add_worker(
                 GraphType.ABSORPTION_COEFFICIENT, work)
             return
     # No need to store a reference to it, since the GraphDisplayWidget will add itself to a list
     _ = GraphDisplayWidget(GraphType.ABSORPTION_COEFFICIENT, work,
                            self.backend.currentText())
     self.update_existing_window_items()
Ejemplo n.º 12
0
    def get_standard_parameters(self):
        data_name = self.get_data_name()
        backend = self.backend.currentText()

        if data_name.endswith(".xsc"):
            Components = []
            SourceTables = [data_name]
            Environment = {'p': self.xsc.pressure, 'T': self.xsc.temp}
            WavenumberRange = (self.xsc.numin, self.xsc.numax)
            WavenumberStep = self.xsc.step
            Diluent = {'air': 0.0, 'self': 1.0}
            # TODO: Verify that these are the proper values.
            WavenumberWing = 0.0
            WavenumberWingHW = 0.0
        else:
            hmd = HapiMetaData(data_name)
            Components = hmd.iso_tuples
            SourceTables = [data_name]
            Environment = {'p': self.get_pressure(), 'T': self.get_temp()}
            Diluent = self.get_diluent()
            WavenumberRange = self.get_wn_range()
            WavenumberStep = self.get_wn_step()
            WavenumberWing = self.get_wn_wing()
            WavenumberWingHW = self.get_wn_wing_hw()

        name = self.plot_name.text()
        graph_fn = self.get_line_profile()
        return HapiWorker.echo(graph_fn=graph_fn,
                               Components=Components,
                               SourceTables=SourceTables,
                               Environment=Environment,
                               Diluent=Diluent,
                               HITRAN_units=False,
                               WavenumberRange=WavenumberRange,
                               WavenumberStep=WavenumberStep,
                               WavenumberWing=WavenumberWing,
                               WavenumberWingHW=WavenumberWingHW,
                               backend=backend,
                               name=name)
Ejemplo n.º 13
0
    def graph_ts(self, standard_params):
        path_length = self.get_path_length()
        instrumental_fn = self.get_instrumental_fn()
        AF_wing = self.get_instrumental_fn_wing()
        Resolution = self.get_instrumental_resolution()

        if standard_params['WavenumberStep'] == None:
            standard_params['WavenumberStep'] = Resolution / 2
        elif standard_params['WavenumberStep'] <= Resolution:
            err_log(
                'Wavenumber Step must be less than Instrumental Resolution')
            self.data_name_error.setText(
                '<span style="color:#aa0000;">' +
                'Wavenumber Step must be less than the '
                'Instrumental Resolution' + '</span>')
            self.done_graphing()
            return

        work = HapiWorker.echo(
            title=GraphingWidget.TRANSMITTANCE_SPECTRUM_STRING,
            titlex="Wavenumber (cm$^{-1}$)",
            titley="Transmittance",
            path_length=path_length,
            instrumental_fn=instrumental_fn,
            Resolution=Resolution,
            AF_wing=AF_wing,
            **standard_params)
        if self.use_existing_window.isChecked():
            selected_window = self.get_selected_window()
            if selected_window in GraphDisplayWidget.graph_windows:
                GraphDisplayWidget.graph_windows[selected_window].add_worker(
                    GraphType.TRANSMITTANCE_SPECTRUM, work)
                return

        GraphDisplayWidget(GraphType.TRANSMITTANCE_SPECTRUM, work,
                           self.backend.currentText())
        self.update_existing_window_items()
Ejemplo n.º 14
0
class CrossSectionFetchWidget(QWidget):

    CROSS_SECTION_FETCH_WIDGET_INSTANCE = None

    @staticmethod
    def gen_toggle_function(other_widgets: List[QWidget]):
        return lambda checked: list(
            map(lambda widget: widget.setDisabled(not checked), other_widgets))

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        if CrossSectionFetchWidget.CROSS_SECTION_FETCH_WIDGET_INSTANCE is not None:
            raise Exception(
                "No more than one instance of CrossSectionFetchWidget"
                " should be created")
        CrossSectionFetchWidget.CROSS_SECTION_FETCH_WIDGET_INSTANCE = self

        self.all_molecules = MoleculeMeta.all_names()

        self.parent = parent

        self.wn_check: QCheckBox = None
        self.numin: QDoubleSpinBox = None
        self.numax: QDoubleSpinBox = None

        self.pressure_check: QCheckBox = None
        self.pressure_min: QDoubleSpinBox = None
        self.pressure_max: QDoubleSpinBox = None

        self.temp_check: QCheckBox = None
        self.temp_min: QDoubleSpinBox = None
        self.temp_max: QDoubleSpinBox = None

        self.molecule: QComboBox = None
        self.cross_section_list: QListWidget = None

        self.fetch_button: QPushButton = None
        self.apply_filters: QPushButton = None

        self.cross_section_meta: CrossSectionMeta = None

        self.fetching = False

        uic.loadUi('layouts/cross_section_widget.ui', self)

        self.pressure_check.toggled.connect(
            self.gen_toggle_function([self.pressure_max, self.pressure_min]))
        self.temp_check.toggled.connect(
            self.gen_toggle_function([self.temp_max, self.temp_min]))
        self.wn_check.toggled.connect(
            self.gen_toggle_function([self.numax, self.numin]))

        self.pressure_check.setChecked(True)
        self.temp_check.setChecked(True)
        self.wn_check.setChecked(True)

        self.temp_check.toggle()
        self.wn_check.toggle()
        self.pressure_check.toggle()

        self.fetch_button.clicked.connect(self.__on_fetch_clicked)
        self.apply_filters.clicked.connect(self.__on_apply_filters_clicked)
        self.molecule.addItems(
            CrossSectionMeta.all_names_sorted_by_hitran_id())
        self.molecule.setEditable(True)
        self.completer: QCompleter = QCompleter(CrossSectionMeta.all_aliases(),
                                                self)
        self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.molecule.setCompleter(self.completer)

        self.molecule.currentTextChanged.connect(
            self.__on_molecule_selection_changed)
        self.__on_molecule_selection_changed(self.molecule.currentText())

    def get_selected_xscs(self) -> List[str]:
        xscs = []
        for i in range(self.cross_section_list.count()):
            item = self.cross_section_list.item(i)

            if item.checkState() == QtCore.Qt.Checked:
                xscs.append(str(item.text()))
        return xscs

    def __on_apply_filters_clicked(self, _checked: bool):
        if self.pressure_check.isChecked():
            pressure = [self.pressure_min.value(), self.pressure_max.value()]
            pressure.sort()
        else:
            pressure = None

        if self.wn_check.isChecked():
            wn = [self.numin.value(), self.numax.value()]
            wn.sort()
        else:
            wn = None

        if self.temp_check.isChecked():
            temp = [self.temp_min.value(), self.temp_max.value()]
            temp.sort()
        else:
            temp = None

        xsc_filter = CrossSectionFilter(self.get_selected_molecule_id(), wn,
                                        pressure, temp)
        self.set_cross_section_list_items(xsc_filter.get_cross_sections())

    def __on_molecule_selection_changed(self, _current_text: str):
        mid = self.get_selected_molecule_id()
        if mid is None:
            return

        self.cross_section_meta = CrossSectionMeta(mid)
        items = self.cross_section_meta.get_all_filenames()
        self.set_cross_section_list_items(items)

        if self.fetching:
            return

        if len(items) == 0:
            self.fetch_button.setDisabled(True)
        else:
            self.fetch_button.setEnabled(True)

    def __on_fetch_clicked(self, _checked: bool):
        xscs = self.get_selected_xscs()
        if len(xscs) == 0:
            return
        args = HapiWorker.echo(xscs=xscs,
                               molecule_name=self.molecule.currentText())
        self.fetch_button.setDisabled(True)
        self.worker = HapiWorker(WorkRequest.DOWNLOAD_XSCS, args,
                                 self.__on_fetch_xsc_done)
        self.worker.start()

    def __on_fetch_xsc_done(self, res):
        _result = res.result
        if _result is None:
            err_log("Failed to fetch cross sections...")
        self.parent.populate_table_lists()
        self.fetching = False
        self.fetch_button.setEnabled(True)

    def get_selected_molecule_id(self) -> Optional[int]:
        selected_molecule_name = self.molecule.currentText()
        mid = MoleculeMeta(selected_molecule_name)
        if mid.populated:
            return mid.id
        else:
            return None

    def set_cross_section_list_items(self, xscs: List[str]):
        list(
            map(lambda _: self.cross_section_list.takeItem(0),
                range(self.cross_section_list.count())))
        for xsc in xscs:
            item = QtWidgets.QListWidgetItem(xsc)
            item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable
                          | QtCore.Qt.ItemIsEnabled)

            item.setCheckState(QtCore.Qt.Unchecked)

            self.cross_section_list.addItem(item)
Ejemplo n.º 15
0
def run():
    """
    The main method starts the GUI after asking for an api key if necessary.
    """

    if not check_internet_connection_and_obtain_api_key():
        return 0

    # Create the data folder if it doesn't exist.
    if not os.path.exists(Config.data_folder):
        os.makedirs(Config.data_folder)

    if Config.online:
        if len(sys.argv) > 1:
            if sys.argv[1] in {'--test', '-t'}:
                import test

                test.run_tests()
                return 0
            elif sys.argv[1] in ('--download-molecule-images', '-dmi'):
                import res_gen.image_downloader as id
                id.download_images()
                return 0
            elif sys.argv[1] in ("-gba", "--generate-broadener-availability"):
                import res_gen.generate_broadener_availability as gba
                gba.generate_availability()
                return 0
    if Config.high_dpi:
        # Enable High DPI display with PyQt5
        QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)

    # Fix for mac-based systems...
    os.environ['no_proxy'] = '*'

    ##
    # The following blocks of code verify the hapi API key is in place, and it
    # is valid. If it is not valid or in place the user will we prompted for
    # one. This code also checks for a working internet connection, as hapi
    # needs one to download data. In the future, if there is no internet
    # connection the GUI should simply disable the features that require it,
    # and there could be a periodic check for internet connection that will
    # re-enable them.

    from metadata.molecule_meta import MoleculeMeta

    WorkRequest.start_work_process()

    # Hapi is now started automatically in the work process
    # start = HapiWorker(WorkRequest.START_HAPI, {})
    # start.start() # When a start_hapi request is sent, it starts automatically.

    _ = MoleculeMeta(0)
    from metadata.xsc_meta import CrossSectionMeta

    # If the cache is expired, download a list of the cross section meta file.
    # This also populates the CrossSectionMeta.molecule_metas field.
    _ = CrossSectionMeta(0)

    app = QtWidgets.QApplication(sys.argv)
    app.setStyle(QStyleFactory.create("Fusion"))
    window = MainWindow()
    window.gui.adjustSize()

    TextReceiver.init(window)

    _qt_result = app.exec_()

    TextReceiver.redirect_close()
    close = HapiWorker(WorkRequest.END_WORK_PROCESS, {}, callback=None)
    close.safe_exit()
    WorkRequest.WORKER.process.join()
    HapiThread.kill_all()
    return 0