Exemple #1
0
 def populate_molecule_list(self):
     """
     Extract the name of each molocule that hapi has data on and add it to the molecule list.
     """
     # Make sure that molecule meta has had it's static members initialized initialized.
     self.molecules_current_molecule.addItems(MoleculeMeta.all_names_sorted_by_hitran_id())
     self.completer: QCompleter = QCompleter(MoleculeMeta.all_aliases(), self)
     self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
     self.molecules_current_molecule.setEditable(True)
     self.molecules_current_molecule.setCompleter(self.completer)
Exemple #2
0
    def __on_molecules_current_text_changed(self, *_args):
        molecule = MoleculeMeta(self.molecules_current_molecule.currentText())
        if not molecule.is_populated():
            return

        if self.molecule_info is not None:
            for i in reversed(range(self.molecule_container.count())):
                self.molecule_container.itemAt(i).widget().setParent(None)
        self.molecule_info = MoleculeInfoWidget(self.molecules_current_molecule.currentText(), self)
        self.molecule_container.addWidget(self.molecule_info)
Exemple #3
0
    def create_alias_list(meta_objs: List[Dict]):
        mids = set(map(lambda m: m['molecule_id'], meta_objs))
        aliases = set()
        ambiguous_aliases = set()

        for mid in mids:
            mm = MoleculeMeta(mid)
            if not mm.populated:
                continue  # I don't think this will ever happen?

            def try_add_alias(alias_str):
                if alias_str in aliases:
                    ambiguous_aliases.add(alias_str)
                else:
                    aliases.add(alias_str)

            for alias in mm.aliases:
                try_add_alias(alias.alias)

            try_add_alias(mm.inchi)
            try_add_alias(mm.inchikey)

        for alias in ambiguous_aliases:
            aliases.remove(alias)

        CrossSectionMeta.__XSC_ALIASES = aliases
 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
Exemple #5
0
    def all_names_sorted_by_hitran_id() -> List[str]:
        molecules = list(
            filter(
                lambda m: m.populated,
                map(lambda m: MoleculeMeta(m), CrossSectionMeta.__XSC_NAMES)))

        return list(
            map(lambda m: m.name, sorted(molecules, key=lambda m: m.id)))
def generate_availability_():
    Config.data_folder = "__temp_data"
    hapi.db_begin(Config.data_folder)

    records = dict()
    for molecule_id in range(0, 100):
        molecule = MoleculeMeta(molecule_id)
        if not molecule.is_populated():
            continue
        records[molecule.id] = check_availability(molecule)

    with open(f"res/parameters/availability.json", "w+") as f:
        f.write(json.dumps(records, indent=2, sort_keys=True))

    print(records)

    sys.exit(0)
    def __init__(self, molecule):
        if ParameterAvailability.__PARAMETER_GROUP_REQUIREMENTS is None:
            ParameterAvailability.create_parameter_group_requirements()

        if ParameterAvailability.__AVAILABILITY is None:
            ParameterAvailability.load_availability()

        self.molecule = MoleculeMeta(molecule)
        if self.molecule.populated:
            if self.molecule.id in ParameterAvailability.__AVAILABILITY:
                self.available_parameters = \
                    set(ParameterAvailability.__AVAILABILITY[self.molecule.id])
            else:
                self.available_parameters = set()
        else:
            self.available_parameters = set()
Exemple #8
0
    def test(self) -> bool:
        app = QtWidgets.QApplication([])
        window = QtWidgets.QMainWindow()

        def close_window():
            sleep(0.25)
            window.deleteLater()

        # Necessary initialization
        _ = MoleculeMeta(0)

        t = threading.Thread(target=close_window)
        t.start()
        widget = MoleculeInfoWidget('CO2', None)
        window.setCentralWidget(widget)
        window.show()
        return app.exec_() == 0
Exemple #9
0
 def create_name_list(meta_objs: List[Dict]):
     CrossSectionMeta.__XSC_NAMES = set()
     for meta in meta_objs:
         CrossSectionMeta.__XSC_NAMES.add(
             MoleculeMeta(meta['molecule_id']).name)
Exemple #10
0
    def __init__(self, molecule_name, parent):
        QWidget.__init__(self, parent)

        self.molecule = MoleculeMeta(molecule_name)

        if not self.molecule.is_populated():
            raise Exception("Don't make a molecule info widget with an invalid molecule")

        self.fetch_widget: FetchWidget = FetchWidget.FETCH_WIDGET_INSTANCE
        self.xsc_widget: CrossSectionFetchWidget = \
            CrossSectionFetchWidget.CROSS_SECTION_FETCH_WIDGET_INSTANCE
        self.main_gui = parent

        self.parent = parent
        self.setWindowIcon(program_icon())

        def create_field(text):
            field_name = text.lower()
            label = QLabel(f'<b>{text}:</b>')
            value = QLabel()
            value.setTextInteractionFlags(Qt.TextSelectableByMouse)
            label.setTextFormat(Qt.RichText)
            value.setWordWrap(True)
            value.setTextFormat(Qt.RichText)

            self.__dict__[field_name + "_label"] = label
            self.__dict__[field_name] = value

        self.setObjectName('MoleculeInfoWidget')

        self.name = \
            QLabel(f"<span style='font-size: 16pt'><i><b>{self.molecule.name}</b></i></span>")

        self.button_style = "padding: .1em .2em .1em .2em;"
        self.get_xsc_button = QPushButton("Get cross-sections")
        self.get_xsc_button.pressed.connect(self.__open_cross_sections)
        self.get_xsc_button.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum))
        self.get_xsc_button.setStyleSheet(self.button_style)

        self.get_lbl_button = QPushButton("Get line-by-line data")
        self.get_lbl_button.pressed.connect(self.__open_line_by_line)
        self.get_lbl_button.setSizePolicy(QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum))
        self.get_lbl_button.setStyleSheet(self.button_style)

        self.img = QWidget()
        self.img.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))

        if Config.high_dpi:
            self.img.setFixedWidth(300)
            self.img.setFixedHeight(300)
        else:
            self.img.setFixedWidth(400)
            self.img.setFixedHeight(400)

        # Have to call list because map is lazy
        list(map(create_field, MoleculeInfoWidget.FIELDS))

        self.aliases.setWordWrap(True)

        self.form_layout = QFormLayout()

        list(map(lambda x: self.form_layout.addRow(self.__dict__[x.lower() + '_label'],
                                                   self.__dict__[x.lower()]),
                 MoleculeInfoWidget.FIELDS))

        self.button_container = QHBoxLayout()

        if self.molecule.has_lbl_data:
            self.button_container.addWidget(self.get_lbl_button)
        if len(CrossSectionMeta(self.molecule.id).metas) > 0:
            self.button_container.addWidget(self.get_xsc_button)

        self.button_spacer = QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Preferred)
        self.button_container.addSpacerItem(self.button_spacer)

        self.img_layout = QVBoxLayout()
        self.img_layout.addWidget(self.img)
        self.img_layout.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding))

        self.info_layout = QVBoxLayout()
        self.info_layout.addWidget(self.name)
        self.info_layout.addLayout(self.button_container)
        self.info_layout.addLayout(self.form_layout)
        self.info_layout.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Fixed, QSizePolicy.Expanding))

        self.central_layout = QHBoxLayout()
        self.central_layout.addLayout(self.img_layout)
        self.central_layout.addSpacerItem(QSpacerItem(50, 1, QSizePolicy.Fixed, QSizePolicy.Fixed))
        self.central_layout.addLayout(self.info_layout)
        self.central_layout.addSpacerItem(
                QSpacerItem(1, 1, QSizePolicy.Expanding, QSizePolicy.Expanding))

        self.setLayout(self.central_layout)

        if not Config.online:
            self.get_xsc_button.setDisabled(True)
            self.get_lbl_button.setDisabled(True)

        formula = self.molecule.formula
        if self.molecule.is_populated():
            self.img.setAttribute(Qt.WA_StyledBackground)
            self.img.setStyleSheet(
                f'border-image: url("res/img/molecules/{formula}.gif") 0 0 0 0 stretch stretch;')
            self.img.show()

            try:
                self.formula.setText(self.molecule.html)
                self.hitranonline_id.setText(str(self.molecule.id))
                self.inchi.setText(self.molecule.inchi)
                self.inchikey.setText(self.molecule.inchikey)

                alias_text = ''
                for alias in self.molecule.aliases:
                    alias_text = f'{alias_text}<i>{alias.alias}</i><hr>'
                self.aliases.setText(alias_text)

            except Exception as e:
                err_log(f'Encountered error \'{str(e)}\' - likely a malformed molecule json file')

            self.adjustSize()
    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())
Exemple #12
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