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)
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)
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
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()
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
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)
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())
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