From b9748f10b6f27c34748f98c8b4d51725120cd239 Mon Sep 17 00:00:00 2001 From: Kyle Sunden Date: Fri, 10 Jan 2020 15:44:54 -0600 Subject: [PATCH] Blacken --- PyCMDS.py | 136 ++-- autonomic/coset.py | 143 ++-- devices/InGaAs_array/InGaAs.py | 153 ++-- devices/InGaAs_array/InGaAs_test.py | 39 +- devices/InGaAs_array/__init__.py | 2 +- devices/PCI-6251/PCI-6251.py | 722 ++++++++++------- devices/PCI-6251/shots_processing/default.py | 5 +- devices/__init__.py | 2 +- devices/devices.py | 527 +++++++------ hardware/delays/Aerotech/Aerotech.py | 41 +- hardware/delays/LTS300/LTS300.py | 17 +- hardware/delays/LTS300/__init__.py | 3 +- hardware/delays/MFA/MFA.py | 176 ++--- hardware/delays/PMC/PMC.py | 22 +- hardware/delays/delays.py | 116 +-- hardware/delays/test.py | 3 +- hardware/filters/filters.py | 113 +-- hardware/filters/homebuilt/homebuilt.py | 47 +- hardware/hardware.py | 125 +-- hardware/opas/OPA-800/OPA-800.py | 51 +- .../PoyntingCorrectionDevice.py | 44 +- .../ZaberCorrectionDevice.py | 13 +- hardware/opas/TOPAS/TOPAS-800.py | 15 +- hardware/opas/TOPAS/TOPAS-C.py | 16 +- hardware/opas/TOPAS/TOPAS.py | 66 +- hardware/opas/opas.py | 193 ++--- hardware/spectrometers/MicroHR/MicroHR.py | 29 +- hardware/spectrometers/spectrometers.py | 15 +- library/ThorlabsAPT/APT.py | 118 +-- library/zaber/binary.py | 111 +-- library/zaber/exceptions.py | 10 +- project/classes.py | 283 +++---- project/com_handler.py | 79 +- project/file_dialog_handler.py | 69 +- project/ini_handler.py | 51 +- project/kit.py | 75 +- project/logging_handler.py | 102 ++- project/project_globals.py | 152 +++- project/slack/__init__.py | 1 + project/slack/bots.py | 100 +-- project/slack/rtmbot.py | 97 ++- project/slack/slack.py | 194 +++-- project/slack/test_slack.py | 14 +- project/style.py | 118 +-- project/widgets.py | 487 +++++++----- somatic/acquisition.py | 186 +++-- somatic/modules/abstract_tuning.py | 71 +- somatic/modules/home.py | 65 +- somatic/modules/motortune.py | 350 +++++---- somatic/modules/scan.py | 235 +++--- somatic/modules/tune_holistic.py | 20 +- somatic/modules/tune_intensity.py | 23 +- somatic/modules/tune_setpoint.py | 15 +- somatic/modules/tune_test.py | 25 +- somatic/modules/zero_tune.py | 179 +++-- somatic/order/ndindex.py | 29 +- somatic/order/snake.py | 280 ++++--- somatic/queue.py | 728 ++++++++++-------- 58 files changed, 4065 insertions(+), 3036 deletions(-) diff --git a/PyCMDS.py b/PyCMDS.py index d3693f9a..b0f6af15 100755 --- a/PyCMDS.py +++ b/PyCMDS.py @@ -2,23 +2,25 @@ ### ensure folders exist ###################################################### import matplotlib -matplotlib.use('ps') # important - images will be generated in worker threads + +matplotlib.use("ps") # important - images will be generated in worker threads import sys from PySide2 import QtWidgets, QtCore + app = QtWidgets.QApplication(sys.argv) import os folders = [] -folders.append(['data']) -folders.append(['logs']) -folders.append(['autonomic', 'files']) -folders.append(['hardware', 'opas', 'OPA-800', 'OPA2 curves']) -folders.append(['hardware', 'opas', 'OPA-800', 'OPA3 curves']) -folders.append(['hardware', 'opas', 'TOPAS', 'OPA1 (10743) curves']) -folders.append(['hardware', 'opas', 'TOPAS', 'OPA2 (10742) curves']) -folders.append(['hardware', 'opas', 'TOPAS', 'configuration']) +folders.append(["data"]) +folders.append(["logs"]) +folders.append(["autonomic", "files"]) +folders.append(["hardware", "opas", "OPA-800", "OPA2 curves"]) +folders.append(["hardware", "opas", "OPA-800", "OPA3 curves"]) +folders.append(["hardware", "opas", "TOPAS", "OPA1 (10743) curves"]) +folders.append(["hardware", "opas", "TOPAS", "OPA2 (10742) curves"]) +folders.append(["hardware", "opas", "TOPAS", "configuration"]) for folder in folders: folder_path = os.path.join(os.getcwd(), *folder) @@ -30,7 +32,7 @@ #### import ################################################################### -#BEWARE OF CHANGING ORDER OF IMPORTS!!!!!!!!! +# BEWARE OF CHANGING ORDER OF IMPORTS!!!!!!!!! import copy @@ -39,10 +41,12 @@ import subprocess import project.project_globals as g + g.app.write(app) g.logger.load() import project.ini_handler as ini -g.logger.log('info', 'Startup', 'PyCMDS is attempting startup') + +g.logger.log("info", "Startup", "PyCMDS is attempting startup") import project.style as style import project.widgets as pw @@ -66,15 +70,15 @@ # MAJOR.MINOR.PATCH (semantic versioning) # major version changes may break backwards compatibility -__version__ = '0.10.0' +__version__ = "0.10.0" # add git branch, if appropriate -p = os.path.join(directory, '.git', 'HEAD') +p = os.path.join(directory, ".git", "HEAD") if os.path.isfile(p): with open(p) as _f: - __branch__ = _f.readline().rstrip().split(r'/')[-1] - if __branch__ != 'master': - __version__ += '-' + __branch__ + __branch__ = _f.readline().rstrip().split(r"/")[-1] + if __branch__ != "master": + __version__ += "-" + __branch__ else: __branch__ = None @@ -87,12 +91,12 @@ class MainWindow(QtWidgets.QMainWindow): shutdown = QtCore.Signal() queue_control = QtCore.Signal() - + def __init__(self): QtWidgets.QMainWindow.__init__(self, parent=None) g.main_window.write(self) g.shutdown.write(self.shutdown) - self.setWindowTitle('PyCMDS %s'%__version__) + self.setWindowTitle("PyCMDS %s" % __version__) # begin poll timer self._begin_poll_loop() # disable 'x' @@ -101,8 +105,8 @@ def __init__(self): # set size, position self.window_verti_size = 600 self.window_horiz_size = 1000 - self.setGeometry(0,0, self.window_horiz_size, self.window_verti_size) - #self._center() + self.setGeometry(0, 0, self.window_horiz_size, self.window_verti_size) + # self._center() self.resize(self.window_horiz_size, self.window_verti_size) self._create_main_frame() # initialize program @@ -112,21 +116,21 @@ def __init__(self): self._load_google_drive() self._load_witch() # populate self - self.data_folder = os.path.join(directory, 'data') + self.data_folder = os.path.join(directory, "data") # somatic system from somatic import queue + self.queue_gui = queue.GUI(self.queue_widget, self.queue_message) self.queue_gui.load_modules() # log completion if g.debug.read(): - print('PyCMDS_ui.MainWindow.__init__ complete') - g.logger.log('info', 'Startup', 'PyCMDS MainWindow __init__ finished') + print("PyCMDS_ui.MainWindow.__init__ complete") + g.logger.log("info", "Startup", "PyCMDS MainWindow __init__ finished") all_initialized() - - + def _create_main_frame(self): self.main_frame = QtWidgets.QWidget(parent=self) - hbox = QtWidgets.QHBoxLayout() + hbox = QtWidgets.QHBoxLayout() # hardware ------------------------------------------------------------ hardware_box = QtWidgets.QVBoxLayout() # exit button @@ -154,10 +158,12 @@ def _create_main_frame(self): box.addWidget(progress_bar) # time elapsed/remaining, queue message progress_bar.setLayout(QtWidgets.QHBoxLayout()) - time_elapsed = QtWidgets.QLabel('00:00:00') - self.queue_message = QtWidgets.QLabel('NO QUEUE') - time_remaining = QtWidgets.QLabel('00:00:00') - StyleSheet = 'QLabel{color: custom_color; font: bold 14px}'.replace('custom_color', g.colors_dict.read()['text_light']) + time_elapsed = QtWidgets.QLabel("00:00:00") + self.queue_message = QtWidgets.QLabel("NO QUEUE") + time_remaining = QtWidgets.QLabel("00:00:00") + StyleSheet = "QLabel{color: custom_color; font: bold 14px}".replace( + "custom_color", g.colors_dict.read()["text_light"] + ) time_elapsed.setStyleSheet(StyleSheet) self.queue_message.setStyleSheet(StyleSheet) time_remaining.setStyleSheet(StyleSheet) @@ -189,25 +195,25 @@ def _create_main_frame(self): somatic_widget.setLayout(layout) somatic_tabs = pw.TabWidget() self.queue_widget = QtWidgets.QWidget(parent=self.main_frame) - somatic_tabs.addTab(self.queue_widget, 'Queue') + somatic_tabs.addTab(self.queue_widget, "Queue") self.scan_widget = QtWidgets.QWidget(parent=self.main_frame) - somatic_tabs.addTab(self.scan_widget, 'Scan') - somatic_tabs.setContentsMargins(0., 0., 0., 0.) + somatic_tabs.addTab(self.scan_widget, "Scan") + somatic_tabs.setContentsMargins(0.0, 0.0, 0.0, 0.0) layout.addWidget(somatic_tabs) # plot box plot_widget = QtWidgets.QWidget(parent=self.main_frame) g.daq_plot_widget.write(plot_widget) # tab widget self.tabs = pw.TabWidget() - self.tabs.addTab(program_widget, 'Program') - self.tabs.addTab(hardware_advanced_widget, 'Hardware') - self.tabs.addTab(device_widget, 'Devices') - self.tabs.addTab(coset_widget, 'Autonomic') - self.tabs.addTab(somatic_widget, 'Somatic') - self.tabs.addTab(plot_widget, 'Plot') + self.tabs.addTab(program_widget, "Program") + self.tabs.addTab(hardware_advanced_widget, "Hardware") + self.tabs.addTab(device_widget, "Devices") + self.tabs.addTab(coset_widget, "Autonomic") + self.tabs.addTab(somatic_widget, "Somatic") + self.tabs.addTab(plot_widget, "Plot") self.tabs.setCurrentIndex(4) # start on sonomic tab - self.tabs.setContentsMargins(0., 0., 0., 0.) - box.addWidget(self.tabs) + self.tabs.setContentsMargins(0.0, 0.0, 0.0, 0.0) + box.addWidget(self.tabs) # vertical stretch box.addStretch(1) hbox.addLayout(box) @@ -227,15 +233,16 @@ def _begin_poll_loop(self): g.poll_timer.connect_to_timeout(self.poll) # now we can begin the CPU watcher (which is triggered by poll) import project.logging_handler as logging_handler + logging_handler.begin_cpu_watcher() - + def poll(self): pass def _initialize_hardware(self): g.offline.get_saved() if g.debug.read(): - print('initialize hardware') + print("initialize hardware") # import import hardware import hardware.opas.opas @@ -243,26 +250,26 @@ def _initialize_hardware(self): import hardware.delays.delays import hardware.filters.filters import devices.devices - + def _initialize_widgets(self): if g.debug.read(): - print('initialize widgets') + print("initialize widgets") # import widgets import autonomic.coset - + def _load_google_drive(self): - google_drive_ini = ini.Ini(os.path.join(g.main_dir.read(), 'project', 'google_drive.ini')) - g.google_drive_enabled.write(google_drive_ini.read('main', 'enable')) + google_drive_ini = ini.Ini(os.path.join(g.main_dir.read(), "project", "google_drive.ini")) + g.google_drive_enabled.write(google_drive_ini.read("main", "enable")) if g.google_drive_enabled.read(): - g.google_drive_control.write(yaqc.Client(google_drive_ini.read('main', 'port'))) - - + g.google_drive_control.write(yaqc.Client(google_drive_ini.read("main", "port"))) + def _load_witch(self): # check if witch is enabled - bots_ini = ini.Ini(os.path.join(g.main_dir.read(), 'project', 'slack', 'bots.ini')) - g.slack_enabled.write(bots_ini.read('bots', 'enable')) + bots_ini = ini.Ini(os.path.join(g.main_dir.read(), "project", "slack", "bots.ini")) + g.slack_enabled.write(bots_ini.read("bots", "enable")) if g.slack_enabled.read(): import project.slack as slack + # create witch self.witch = slack.control # begin poll timer @@ -271,27 +278,28 @@ def _load_witch(self): self.shutdown.connect(timer.stop) g.slack_poll_timer.write(timer) g.slack_poll_timer.connect_to_timeout(self.witch.poll) - + def _shutdown(self): - ''' + """ attempt a clean shutdown - ''' + """ if g.debug.read(): - print('shutdown') - g.logger.log('info', 'Shutdown', 'PyCMDS is attempting shutdown') + print("shutdown") + g.logger.log("info", "Shutdown", "PyCMDS is attempting shutdown") self.shutdown.emit() g.shutdown.fire() - + def _center(self): # a function which ensures that the window appears in the center of the screen at startup - screen = QtWidgets.QDesktopWidget().screenGeometry() - size = self.geometry() - self.move((screen.width()-size.width())/2, (screen.height()-size.height())/2) - + screen = QtWidgets.QDesktopWidget().screenGeometry() + size = self.geometry() + self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) + def get_status(self, full=False): # called by slack return self.queue_gui.get_status(full) + def main(): global MainWindow MainWindow = MainWindow() @@ -300,4 +308,6 @@ def main(): MainWindow.showMaximized() app.exec_() return MainWindow + + main_form = main() diff --git a/autonomic/coset.py b/autonomic/coset.py index c1ab733d..1db27ad3 100644 --- a/autonomic/coset.py +++ b/autonomic/coset.py @@ -21,10 +21,11 @@ import hardware.spectrometers.spectrometers as spectrometers import hardware.delays.delays as delays import hardware.filters.filters as filters + all_hardwares = opas.hardwares + spectrometers.hardwares + delays.hardwares + filters.hardwares main_dir = g.main_dir.read() -ini = project.ini_handler.Ini(os.path.join(main_dir, 'autonomic', 'coset.ini')) +ini = project.ini_handler.Ini(os.path.join(main_dir, "autonomic", "coset.ini")) ini.return_raw = True # ensure that all elements are in the ini file @@ -33,26 +34,26 @@ for section in all_hardware_names: if not ini.config.has_section(section): ini.config.add_section(section) - ini.write(section, 'offset', 0.) + ini.write(section, "offset", 0.0) # 'use' bool - if not ini.config.has_option(section, 'use'): - ini.write(section, 'use', False) + if not ini.config.has_option(section, "use"): + ini.write(section, "use", False) # hardware names for option in all_hardware_names: if not section == option: if not ini.config.has_option(section, option): ini.write(section, option, None) - ini.write(section, option + ' offset', 0.) + ini.write(section, option + " offset", 0.0) ### objects ################################################################### -class CoSetHW: +class CoSetHW: def __init__(self, hardware): self.hardware = hardware # directly write stored offset to hardware - stored_offset = float(ini.read(self.hardware.name, 'offset')) + stored_offset = float(ini.read(self.hardware.name, "offset")) self.hardware.offset.write(stored_offset) self.corrs = [] self.control_hardware = [] @@ -65,14 +66,14 @@ def __init__(self, hardware): # load files ini.config.read(ini.filepath) for option in ini.config.options(self.hardware.name): - if 'offset' in option: + if "offset" in option: continue value = ini.read(self.hardware.name, option) - if value not in ['None', 'False', 'True']: + if value not in ["None", "False", "True"]: value = value[1:] value = value[:-1] self.load_file(value) - stored_use_state = ast.literal_eval(ini.read(self.hardware.name, 'use')) + stored_use_state = ast.literal_eval(ini.read(self.hardware.name, "use")) self.use_bool.write(stored_use_state) # initialize self.update_display() @@ -80,7 +81,10 @@ def __init__(self, hardware): @property def control_position(self): - return [np.clip(hw.get_destination(corr.setpoints.units), *corr.get_limits()) for hw, corr in zip(self.control_hardware, self.corrs)] + return [ + np.clip(hw.get_destination(corr.setpoints.units), *corr.get_limits()) + for hw, corr in zip(self.control_hardware, self.corrs) + ] def add_table_row(self, corr): # insert into table @@ -97,10 +101,10 @@ def add_table_row(self, corr): label.setToolTip(str(corr.path)) self.table.setCellWidget(new_row_index, 1, label) # button - button = pw.SetButton('REMOVE', color='stop') + button = pw.SetButton("REMOVE", color="stop") g.queue_control.disable_when_true(button) - button.setProperty('TableRowIndex', new_row_index) - button.clicked.connect(lambda: self.on_remove_file(button.property('TableRowIndex'))) + button.setProperty("TableRowIndex", new_row_index) + button.clicked.connect(lambda: self.on_remove_file(button.property("TableRowIndex"))) self.table.setCellWidget(new_row_index, 2, button) def create_frame(self, layout): @@ -115,7 +119,7 @@ def create_frame(self, layout): self.plot_scatter = self.plot_widget.add_scatter() display_layout.addWidget(self.plot_widget) # vertical line - line = pw.line('V') + line = pw.line("V") layout.addWidget(line) # settings area settings_container_widget = QtWidgets.QWidget() @@ -129,19 +133,19 @@ def create_frame(self, layout): layout.addWidget(settings_scroll_area) # input table input_table = pw.InputTable() - input_table.add('Display', None) + input_table.add("Display", None) self.display_combobox = pc.Combo() self.display_combobox.updated.connect(self.update_display) - input_table.add('Hardware', self.display_combobox) - input_table.add('Settings', None) + input_table.add("Hardware", self.display_combobox) + input_table.add("Settings", None) self.use_bool = pc.Bool() self.use_bool.updated.connect(self.on_toggle_use) g.queue_control.disable_when_true(self.use_bool) - input_table.add('Use', self.use_bool) - input_table.add('Current Offset', self.hardware.offset) + input_table.add("Use", self.use_bool) + input_table.add("Current Offset", self.hardware.offset) settings_layout.addWidget(input_table) # add button - self.add_button = pw.SetButton('ADD FILE', color='go') + self.add_button = pw.SetButton("ADD FILE", color="go") self.add_button.clicked.connect(self.on_add_file) g.queue_control.disable_when_true(self.add_button) settings_layout.addWidget(self.add_button) @@ -151,55 +155,65 @@ def create_frame(self, layout): self.table.insertColumn(0) self.table.insertColumn(1) self.table.insertColumn(2) - self.table.setHorizontalHeaderLabels(['Hardware', 'File Name', '']) + self.table.setHorizontalHeaderLabels(["Hardware", "File Name", ""]) self.table.setColumnWidth(0, 100) self.table.setColumnWidth(1, 100) self.table.horizontalHeader().setStretchLastSection(True) settings_layout.addWidget(self.table) def launch(self): - ''' + """ Apply offsets. - ''' + """ if self.use_bool.read(): - corr_results = [wt.units.converter( - list(corr(self.control_position[i]).values())[0], list(corr.dependents.values())[0].units, self.hardware.native_units) for i, corr in enumerate(self.corrs)] + corr_results = [ + wt.units.converter( + list(corr(self.control_position[i]).values())[0], + list(corr.dependents.values())[0].units, + self.hardware.native_units, + ) + for i, corr in enumerate(self.corrs) + ] new_offset = np.sum(corr_results) if g.hardware_initialized.read(): self.hardware.set_offset(new_offset, self.hardware.native_units) - ini.write(self.hardware.name, 'offset', new_offset) + ini.write(self.hardware.name, "offset", new_offset) def load_file(self, path): - ''' + """ Load a file. - ''' + """ corr = attune.Curve.read(path) setattr(corr, "path", path) self.corrs.append(corr) - self.control_hardware.append(next(hw for hw in all_hardwares if hw.name == corr.setpoints.name)) + self.control_hardware.append( + next(hw for hw in all_hardwares if hw.name == corr.setpoints.name) + ) self.add_table_row(corr) self.update_combobox() self.update_use_bool() return corr def on_add_file(self): - ''' + """ Add a file through file dialog. - ''' + """ # get filepath - caption = 'Import a coset file' - directory = os.path.join(g.main_dir.read(), 'coset', 'files') - options = 'COSET (*.curve);;All Files (*.*)' + caption = "Import a coset file" + directory = os.path.join(g.main_dir.read(), "coset", "files") + options = "COSET (*.curve);;All Files (*.*)" path = project.file_dialog_handler.open_dialog(caption, directory, options) if not os.path.isfile(path): # presumably user canceled return corr = attune.Curve.read(path) # this object is throwaway setattr(corr, "path", path) if not list(corr.dependents.keys())[0] == self.hardware.name: - warnings.warn('incorrect hardware') + warnings.warn("incorrect hardware") return for i, loaded_corr in enumerate(self.corrs): - if loaded_corr.setpoints.name == corr.setpoints.name: # will not allow two of same control + if ( + loaded_corr.setpoints.name == corr.setpoints.name + ): # will not allow two of same control self.unload_file(i) # unload old one break # should only be one # load in @@ -208,30 +222,30 @@ def on_add_file(self): self.display_combobox.write(corr.setpoints.name) def on_remove_file(self, row): - ''' + """ Fires when one of the REMOVE buttons gets pushed. - ''' + """ # get row as int (given as QVariant) try: row = row.toInt()[0] except AttributeError: - pass # already an int? + pass # already an int? self.unload_file(row) def on_toggle_use(self): - ini.write(self.hardware.name, 'use', self.use_bool.read()) + ini.write(self.hardware.name, "use", self.use_bool.read()) if self.use_bool.read(): self.launch() else: if g.hardware_initialized.read(): - self.hardware.set_offset(0., self.hardware.native_units) - ini.write(self.hardware.name, 'offset', 0.) + self.hardware.set_offset(0.0, self.hardware.native_units) + ini.write(self.hardware.name, "offset", 0.0) def unload_file(self, index): removed_corr = self.corrs.pop(index) self.control_hardware.pop(index) ini.write(self.hardware.name, removed_corr.setpoints.name, None) - ini.write(self.hardware.name, list(removed_corr.dependents.keys())[0] + ' offset', 0.) + ini.write(self.hardware.name, list(removed_corr.dependents.keys())[0] + " offset", 0.0) # clear table for i in range(self.table.rowCount()): self.table.removeRow(0) @@ -261,34 +275,43 @@ def update_display(self): corr = self.corrs[self.display_combobox.read_index()] xi = corr.setpoints[:] yi = list(corr.dependents.values())[0][:] - x_label = corr.setpoints.name + ' (' + corr.setpoints.units + ')' - y_label = list(corr.dependents.keys())[0] + ' (' + list(corr.dependents.values())[0].units + ')' + x_label = corr.setpoints.name + " (" + corr.setpoints.units + ")" + y_label = ( + list(corr.dependents.keys())[0] + + " (" + + list(corr.dependents.values())[0].units + + ")" + ) self.plot_widget.set_labels(x_label, y_label) self.plot_scatter.clear() self.plot_scatter.setData(xi, yi) else: # this doesn't work as expected, but that isn't crucial right now # - Blaise 2015.10.24 - self.plot_widget.set_labels('', '') + self.plot_widget.set_labels("", "") self.plot_scatter.clear() self.plot_widget.update() self.plot_scatter.update() def zero(self): - ''' + """ Offsets to zero for all corrs based on current positions. - ''' + """ use = self.use_bool.read() paths = [] for i, corr in enumerate(self.corrs): corr.offset_to(list(corr.dependents.keys())[0], 0, self.control_position[i]) corr.name = f"{next(iter(corr.dependents))}_{corr.setpoints.name} offset" - paths.append(corr.save(save_directory=pathlib.Path(g.main_dir.read()) / "autonomic" / "files")) + paths.append( + corr.save(save_directory=pathlib.Path(g.main_dir.read()) / "autonomic" / "files") + ) for i in range(len(self.corrs)): self.unload_file(0) for path in paths: corr = self.load_file(path) - ini.write(self.hardware.name, corr.setpoints.name, str(corr.path), with_apostrophe=True) + ini.write( + self.hardware.name, corr.setpoints.name, str(corr.path), with_apostrophe=True + ) self.launch() use = self.use_bool.write(use) @@ -301,8 +324,7 @@ def zero(self): ### control ################################################################### -class Control(): - +class Control: def __init__(self): pass @@ -311,9 +333,9 @@ def launch(self): coset_hardware.launch() def zero(self, hardware_name): - ''' + """ Offsets to zero forr all corrs based on current positions. - ''' + """ for coset_harware in coset_hardwares: if coset_harware.hardware.name == hardware_name: coset_harware.zero() @@ -328,7 +350,6 @@ def zero(self, hardware_name): class GUI(QtCore.QObject): - def __init__(self): QtCore.QObject.__init__(self) self.create_frame() @@ -343,16 +364,16 @@ def create_frame(self): self.tabs = QtWidgets.QTabWidget() # OPAs if len(opas.hardwares) > 0: - self.create_hardware_frame('OPAs', opas.hardwares) + self.create_hardware_frame("OPAs", opas.hardwares) # spectrometers if len(spectrometers.hardwares) > 0: - self.create_hardware_frame('Spectrometers', spectrometers.hardwares) + self.create_hardware_frame("Spectrometers", spectrometers.hardwares) # delays if len(delays.hardwares) > 0: - self.create_hardware_frame('Delays', delays.hardwares) + self.create_hardware_frame("Delays", delays.hardwares) # filters if len(filters.hardwares) > 0: - self.create_hardware_frame('Filters', filters.hardwares) + self.create_hardware_frame("Filters", filters.hardwares) parent_layout.addWidget(self.tabs) def create_hardware_frame(self, name, hardwares): @@ -376,5 +397,5 @@ def create_hardware_frame(self, name, hardwares): ### testing ################################################################### -if __name__ == '__main__': +if __name__ == "__main__": pass diff --git a/devices/InGaAs_array/InGaAs.py b/devices/InGaAs_array/InGaAs.py index 9d2a9ad6..a846f1ea 100644 --- a/devices/InGaAs_array/InGaAs.py +++ b/devices/InGaAs_array/InGaAs.py @@ -28,23 +28,20 @@ app = g.app.read() main_dir = g.main_dir.read() -ini = Ini(os.path.join(main_dir, 'devices', - 'InGaAs_array', - 'InGaAs.ini')) +ini = Ini(os.path.join(main_dir, "devices", "InGaAs_array", "InGaAs.ini")) -pixel_width = 50. # um +pixel_width = 50.0 # um # --- device -------------------------------------------------------------------------------------- class Device(BaseDevice): - def __init__(self, *args, **kwargs): - kwargs['shape'] = (256, ) - kwargs['has_map'] = True - kwargs['shots_compatible'] = False - self.map_axes = {'wa': ['a', 'nm']} + kwargs["shape"] = (256,) + kwargs["has_map"] = True + kwargs["shots_compatible"] = False + self.map_axes = {"wa": ["a", "nm"]} self.map = pc.Data() self.map.write(np.arange(256)) BaseDevice.__init__(self, *args, **kwargs) @@ -52,28 +49,29 @@ def __init__(self, *args, **kwargs): self.spectrometer_hardware = spectrometers.hardwares[0] self.spectrometer_hardware.position.updated.connect(self.calculate_map) - def calculate_map(self, mono_setpoint=None, write=True): """mono setpoint in nm""" # get setpoint if mono_setpoint is None: - mono_setpoint = self.spectrometer_hardware.get_position('nm') + mono_setpoint = self.spectrometer_hardware.get_position("nm") # calculate - arr = kit.grating_linear_dispersion(spec_inclusion_angle=24., - spec_focal_length=140., - spec_focal_length_tilt=0., - spec_grooves_per_mm=150., - spec_central_wavelength=mono_setpoint, - spec_order=1, - number_of_pixels=256, - pixel_width=50., - calibration_pixel=100) + arr = kit.grating_linear_dispersion( + spec_inclusion_angle=24.0, + spec_focal_length=140.0, + spec_focal_length_tilt=0.0, + spec_grooves_per_mm=150.0, + spec_central_wavelength=mono_setpoint, + spec_order=1, + number_of_pixels=256, + pixel_width=50.0, + calibration_pixel=100, + ) if write: self.map.write(arr) return arr def get_axis_properties(self, destinations_list): - ''' + """ Get the axis properties to record for the given scan, given hardware positions. @@ -85,27 +83,27 @@ def get_axis_properties(self, destinations_list): Returns ------- tuple : (identity, units, points, centers, interpolate) - ''' - scanned_hardware_names = [d.hardware.name for d in destinations_list] - if 'wm' in scanned_hardware_names: + """ + scanned_hardware_names = [d.hardware.name for d in destinations_list] + if "wm" in scanned_hardware_names: # calculate points, centers - destinations = [d for d in destinations_list if d.hardware.name == 'wm'][0] - centers_nm = wt.units.converter(destinations.arr, destinations.units, 'nm') - centers_wn = wt.units.converter(destinations.arr, destinations.units, 'wn') + destinations = [d for d in destinations_list if d.hardware.name == "wm"][0] + centers_nm = wt.units.converter(destinations.arr, destinations.units, "nm") + centers_wn = wt.units.converter(destinations.arr, destinations.units, "wn") map_nm = self.calculate_map(mono_setpoint=centers_nm.min(), write=False) - map_wn = wt.units.converter(map_nm, 'nm', 'wn') + map_wn = wt.units.converter(map_nm, "nm", "wn") map_wn -= centers_wn.max() - map_nm = wt.units.converter(map_wn, 'wn', 'nm') + map_nm = wt.units.converter(map_wn, "wn", "nm") # assemble outputs - identity = 'Dwa' - units = 'wn' + identity = "Dwa" + units = "wn" points = map_wn centers = centers_wn interpolate = True print(points) else: - identity = 'wa' - units = 'nm' + identity = "wa" + units = "nm" points = self.map.read() centers = None interpolate = False @@ -119,11 +117,10 @@ def load_settings(self, aqn): class Driver(BaseDriver): - def _read(self): # handle communication with special end of line 'ready' - eol = r'ready\n'.encode() - line = ''.encode() + eol = r"ready\n".encode() + line = "".encode() while True: c = self.serial_port.read(1) if c: @@ -136,24 +133,24 @@ def _read(self): return line def initialize(self): - print('INGAAS INITIALIZE') + print("INGAAS INITIALIZE") if g.debug.read(): - print('InGaAs initializing') - g.logger.log('info', 'InGaAs initializing') + print("InGaAs initializing") + g.logger.log("info", "InGaAs initializing") # initialize serial port self.serial_port = serial.Serial() self.serial_port.baudrate = 57600 - self.serial_port.port = 'COM' + str(ini.read('main', 'serial port')) + self.serial_port.port = "COM" + str(ini.read("main", "serial port")) self.serial_port.timeout = 0.1 # might need to make this larger... self.serial_port.open() # initialize arrays for later use - self.spectra_averaged = 5 #int(ini.read('main', 'spectra averaged')) + self.spectra_averaged = 5 # int(ini.read('main', 'spectra averaged')) self.out = np.zeros(256) self.buffer = np.zeros([256, self.spectra_averaged]) # finish self.timer = wt.kit.Timer(verbose=False) - #self.measure() - + # self.measure() + def measure(self): # prepare self.running = True @@ -163,24 +160,23 @@ def measure(self): done = False while not done: # get data as string from arduino - self.serial_port.write('S'.encode()) + self.serial_port.write("S".encode()) raw_string = self._read() if len(raw_string) == 519: done = True else: - print('InGaAs array bad read!') + print("InGaAs array bad read!") # transform to floats - raw_pixels = np.frombuffer(raw_string, dtype='>i2', count=256) + raw_pixels = np.frombuffer(raw_string, dtype=">i2", count=256) # hardcoded processing - pixels = 0.00195*(raw_pixels[::-1] - (2060. + -0.0142*np.arange(256))) + pixels = 0.00195 * (raw_pixels[::-1] - (2060.0 + -0.0142 * np.arange(256))) self.buffer[:, i] = pixels self.out = np.mean(self.buffer, axis=1) - self.data.write_properties((256,), ['array_signal'], [self.out]) + self.data.write_properties((256,), ["array_signal"], [self.out]) self.measure_time.write(self.timer.interval) # finish self.update_ui.emit() - self.running = False - + self.running = False def shutdown(self): """cleanly shut down""" @@ -193,20 +189,19 @@ def shutdown(self): class GUI(BaseGUI): - def create_frame(self, parent_widget): - #get parent widget----------------------------------------------------- + # get parent widget----------------------------------------------------- parent_widget.setLayout(QtWidgets.QHBoxLayout()) parent_widget.layout().setContentsMargins(0, 10, 0, 0) layout = parent_widget.layout() - #display area---------------------------------------------------------- - #container widget + # display area---------------------------------------------------------- + # container widget display_container_widget = pw.ExpandingWidget() display_container_widget.setLayout(QtWidgets.QVBoxLayout()) display_layout = display_container_widget.layout() display_layout.setMargin(0) layout.addWidget(display_container_widget) - #big number + # big number big_number_container_widget = QtWidgets.QWidget() big_number_container_widget.setLayout(QtWidgets.QHBoxLayout()) big_number_container_layout = big_number_container_widget.layout() @@ -214,16 +209,16 @@ def create_frame(self, parent_widget): big_number_container_layout.addStretch(1) self.big_display = pw.SpinboxAsDisplay(font_size=100) big_number_container_layout.addWidget(self.big_display) - display_layout.addWidget(big_number_container_widget) - #plot + display_layout.addWidget(big_number_container_widget) + # plot self.plot_widget = pw.Plot1D() self.plot_widget.set_ylim(0, 4) self.plot_curve = self.plot_widget.add_line() self.plot_v_line = self.plot_widget.add_infinite_line(hide=False) - self.plot_widget.set_labels(ylabel='arbitrary units', xlabel='nm') + self.plot_widget.set_labels(ylabel="arbitrary units", xlabel="nm") display_layout.addWidget(self.plot_widget) - #vertical line--------------------------------------------------------- - line = pw.line('V') + # vertical line--------------------------------------------------------- + line = pw.line("V") layout.addWidget(line) # settings area ------------------------------------------------------- # container widget / scroll area @@ -238,22 +233,21 @@ def create_frame(self, parent_widget): layout.addWidget(settings_scroll_area) # input table input_table = pw.InputTable() - input_table.add('Display', None) + input_table.add("Display", None) pixel_limits = pc.NumberLimits(0, 255) - self.display_pixel_index = pc.Number(ini=ini, section='main', - option='display pixel index', - limits=pixel_limits, - decimals=0) - input_table.add('Pixel Index', self.display_pixel_index) - #input_table.add('Settings', None) - #input_table.add('Integration Time (ms)', self.hardware.integration_time) - #input_table.add('Spectra Averaged', self.hardware.spectra_averaged) + self.display_pixel_index = pc.Number( + ini=ini, section="main", option="display pixel index", limits=pixel_limits, decimals=0 + ) + input_table.add("Pixel Index", self.display_pixel_index) + # input_table.add('Settings', None) + # input_table.add('Integration Time (ms)', self.hardware.integration_time) + # input_table.add('Spectra Averaged', self.hardware.spectra_averaged) settings_layout.addWidget(input_table) - #streach + # streach settings_layout.addStretch(1) # signals and slots self.hardware.update_ui.connect(self.update) - + def update(self): if not self.hardware.data.read() == None: # plot @@ -266,29 +260,28 @@ def update(self): self.plot_v_line.setValue(xi[display_pixel_index]) # data readout self.big_display.setValue(yi[display_pixel_index]) - + def stop(self): pass class Widget(BaseWidget): - def __init__(self): QtWidgets.QWidget.__init__(self) layout = QtWidgets.QVBoxLayout() self.setLayout(layout) layout.setMargin(0) input_table = pw.InputTable() - input_table.add('InGaAs', None) + input_table.add("InGaAs", None) self.use = pc.Bool(initial_value=False) - input_table.add('Use', self.use) + input_table.add("Use", self.use) layout.addWidget(input_table) - + def load(self, aqn_path): ini = wt.kit.INI(aqn_path) - self.use.write(ini.read('InGaAs', 'use')) - + self.use.write(ini.read("InGaAs", "use")) + def save(self, aqn_path): ini = wt.kit.INI(aqn_path) - ini.add_section('InGaAs') - ini.write('InGaAs', 'use', self.use.read()) + ini.add_section("InGaAs") + ini.write("InGaAs", "use", self.use.read()) diff --git a/devices/InGaAs_array/InGaAs_test.py b/devices/InGaAs_array/InGaAs_test.py index e3bbbbf1..996cfb3b 100644 --- a/devices/InGaAs_array/InGaAs_test.py +++ b/devices/InGaAs_array/InGaAs_test.py @@ -1,24 +1,24 @@ -#import------------------------------------------------------------------------ +# import------------------------------------------------------------------------ import numpy as np import serial -#initialize-------------------------------------------------------------------- +# initialize-------------------------------------------------------------------- ser = serial.Serial() ser.baudrate = 9600 -ser.port = 'COM5' +ser.port = "COM5" ser.timeout = 0.1 -#read-------------------------------------------------------------------------- +# read-------------------------------------------------------------------------- ser.open() -ser.write('S'.encode()) +ser.write("S".encode()) -eol = r'ready\n'.encode() +eol = r"ready\n".encode() leneol = len(eol) -line = ''.encode() +line = "".encode() while True: c = ser.read(1) if c: @@ -30,30 +30,31 @@ ser.close() -#process----------------------------------------------------------------------- +# process----------------------------------------------------------------------- out = np.zeros(256) -#remove 'ready' from end +# remove 'ready' from end string = line[:512] -out = np.frombuffer(string, dtype='>i2') -#out = [string[511-(2*i):510-(2*i):-1] for i in range(256)] -#out = out[::-1] -#out = [codecs.encode(o, 'hex') for o in out] -#out = [int(o, 16) for o in out] -#out = np.array(out, dtype=np.float64) +out = np.frombuffer(string, dtype=">i2") +# out = [string[511-(2*i):510-(2*i):-1] for i in range(256)] +# out = out[::-1] +# out = [codecs.encode(o, 'hex') for o in out] +# out = [int(o, 16) for o in out] +# out = np.array(out, dtype=np.float64) out = out - (2060 + -0.0142 * np.arange(256)) out *= 0.0195 import matplotlib.pyplot as plt + plt.plot(out) -#import pyqtgraph as pg -#plt = pg.plot(out, title="Simplest possible plotting example") +# import pyqtgraph as pg +# plt = pg.plot(out, title="Simplest possible plotting example") -''' +""" vals = np.fromstring(raw_vals, dtype = float, sep = ',') return vals -''' +""" diff --git a/devices/InGaAs_array/__init__.py b/devices/InGaAs_array/__init__.py index cdc9a3a2..5a6d523e 100644 --- a/devices/InGaAs_array/__init__.py +++ b/devices/InGaAs_array/__init__.py @@ -1 +1 @@ -import InGaAs \ No newline at end of file +import InGaAs diff --git a/devices/PCI-6251/PCI-6251.py b/devices/PCI-6251/PCI-6251.py index 246c0dbe..e951363a 100644 --- a/devices/PCI-6251/PCI-6251.py +++ b/devices/PCI-6251/PCI-6251.py @@ -32,11 +32,9 @@ app = g.app.read() main_dir = g.main_dir.read() -ini = Ini(os.path.join(main_dir, 'devices', - 'PCI-6251', - 'PCI-6251.ini')) +ini = Ini(os.path.join(main_dir, "devices", "PCI-6251", "PCI-6251.ini")) -DAQ_device_name = ini.read('DAQ', 'device name') +DAQ_device_name = ini.read("DAQ", "device name") # TODO: actually read these values from the driver ---Blaise 2017-01-06 ranges = [0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0] # V @@ -49,9 +47,9 @@ resolution[5.0] = 160.0 resolution[10.0] = 320.0 - + # --- data mutex objects -------------------------------------------------------------------------- - + data = pc.Data() shots = pc.Data() @@ -61,129 +59,187 @@ # --- special objects ----------------------------------------------------------------------------- -rest_channel = pc.Number(decimals=0, ini=ini, section='DAQ', - option='rest channel', - limits=pc.NumberLimits(0, 7, None), - import_from_ini=True, save_to_ini_at_shutdown=True) +rest_channel = pc.Number( + decimals=0, + ini=ini, + section="DAQ", + option="rest channel", + limits=pc.NumberLimits(0, 7, None), + import_from_ini=True, + save_to_ini_at_shutdown=True, +) -class Channel(): - +class Channel: def __init__(self, index): self.index = index - ini_section = ' '.join(['Channel', str(self.index)]) + ini_section = " ".join(["Channel", str(self.index)]) self.section = ini_section - self.active = pc.Bool(ini=ini, section=ini_section, option='active') - self.name = pc.String(inital_value='Name', ini=ini, section=ini_section, option='name') - self.physical_correspondance = pc.Number(decimals=0, limits=pc.NumberLimits(0, 7, None), ini=ini, section=ini_section, option='physical correspondance') - allowed_ranges = ['%0.1f (%0.1f)'%(r, resolution[r]) for r in ranges] - self.range = pc.Combo(allowed_values=allowed_ranges, ini=ini, section=ini_section, option='range') + self.active = pc.Bool(ini=ini, section=ini_section, option="active") + self.name = pc.String(inital_value="Name", ini=ini, section=ini_section, option="name") + self.physical_correspondance = pc.Number( + decimals=0, + limits=pc.NumberLimits(0, 7, None), + ini=ini, + section=ini_section, + option="physical correspondance", + ) + allowed_ranges = ["%0.1f (%0.1f)" % (r, resolution[r]) for r in ranges] + self.range = pc.Combo( + allowed_values=allowed_ranges, ini=ini, section=ini_section, option="range" + ) # TODO: resolution display - self.invert = pc.Bool(ini=ini, section=ini_section, option='invert') - sample_limits=pc.NumberLimits(0, 899, None) - self.signal_start_index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='signal start') - self.signal_stop_index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='signal stop') - self.signal_pre_index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='signal presample') - processing_methods = ['Average', 'Sum', 'Min', 'Max'] - self.signal_method = pc.Combo(allowed_values=processing_methods, ini=ini, section=ini_section, option='signal method') - self.use_baseline = pc.Bool(ini=ini, section=ini_section, option='use baseline') - self.baseline_start_index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='baseline start') - self.baseline_stop_index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='baseline stop') - self.baseline_pre_index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='baseline presample') - self.baseline_method = pc.Combo(allowed_values=processing_methods, ini=ini, section=ini_section, option='baseline method') + self.invert = pc.Bool(ini=ini, section=ini_section, option="invert") + sample_limits = pc.NumberLimits(0, 899, None) + self.signal_start_index = pc.Number( + decimals=0, limits=sample_limits, ini=ini, section=ini_section, option="signal start" + ) + self.signal_stop_index = pc.Number( + decimals=0, limits=sample_limits, ini=ini, section=ini_section, option="signal stop" + ) + self.signal_pre_index = pc.Number( + decimals=0, + limits=sample_limits, + ini=ini, + section=ini_section, + option="signal presample", + ) + processing_methods = ["Average", "Sum", "Min", "Max"] + self.signal_method = pc.Combo( + allowed_values=processing_methods, ini=ini, section=ini_section, option="signal method" + ) + self.use_baseline = pc.Bool(ini=ini, section=ini_section, option="use baseline") + self.baseline_start_index = pc.Number( + decimals=0, limits=sample_limits, ini=ini, section=ini_section, option="baseline start" + ) + self.baseline_stop_index = pc.Number( + decimals=0, limits=sample_limits, ini=ini, section=ini_section, option="baseline stop" + ) + self.baseline_pre_index = pc.Number( + decimals=0, + limits=sample_limits, + ini=ini, + section=ini_section, + option="baseline presample", + ) + self.baseline_method = pc.Combo( + allowed_values=processing_methods, + ini=ini, + section=ini_section, + option="baseline method", + ) # a list of all properties - self.properties = [self.active, self.name, - self.physical_correspondance, self.range, - self.invert, self.signal_start_index, - self.signal_stop_index, self.signal_method, - self.signal_pre_index, self.use_baseline, - self.baseline_method, self.baseline_pre_index, - self.baseline_start_index, self.baseline_stop_index] + self.properties = [ + self.active, + self.name, + self.physical_correspondance, + self.range, + self.invert, + self.signal_start_index, + self.signal_stop_index, + self.signal_method, + self.signal_pre_index, + self.use_baseline, + self.baseline_method, + self.baseline_pre_index, + self.baseline_start_index, + self.baseline_stop_index, + ] # call get saved on self self.get_saved() # signals self.use_baseline.updated.connect(lambda: self.on_use_baseline()) self.on_use_baseline() - + def get_range(self): - ''' + """ Returns ------- tuple (minimum_voltage, maximum_voltage) - ''' + """ r = ranges[self.range.read_index()] return -r, r - + def get_saved(self): for obj in self.properties: obj.get_saved() def get_widget(self): self.input_table = pw.InputTable() - self.input_table.add('Name', self.name) - self.input_table.add('Physical Channel', self.physical_correspondance) - self.input_table.add('Range +/-V, (uV/level)', self.range) + self.input_table.add("Name", self.name) + self.input_table.add("Physical Channel", self.physical_correspondance) + self.input_table.add("Range +/-V, (uV/level)", self.range) # TODO: resolution display - self.input_table.add('Invert', self.invert) - self.input_table.add('Signal Start', self.signal_start_index) - self.input_table.add('Signal Stop', self.signal_stop_index) - self.input_table.add('Signal Presample', self.signal_pre_index) - self.input_table.add('Signal Method', self.signal_method) - self.input_table.add('Use Baseline', self.use_baseline) - self.input_table.add('Baseline Start', self.baseline_start_index) - self.input_table.add('Baseline Stop', self.baseline_stop_index) - self.input_table.add('Baseline Presample', self.baseline_pre_index) - self.input_table.add('Baseline Method', self.baseline_method) + self.input_table.add("Invert", self.invert) + self.input_table.add("Signal Start", self.signal_start_index) + self.input_table.add("Signal Stop", self.signal_stop_index) + self.input_table.add("Signal Presample", self.signal_pre_index) + self.input_table.add("Signal Method", self.signal_method) + self.input_table.add("Use Baseline", self.use_baseline) + self.input_table.add("Baseline Start", self.baseline_start_index) + self.input_table.add("Baseline Stop", self.baseline_stop_index) + self.input_table.add("Baseline Presample", self.baseline_pre_index) + self.input_table.add("Baseline Method", self.baseline_method) return self.input_table - + def on_use_baseline(self): - self.baseline_method.set_disabled(not self.use_baseline.read()) - self.baseline_start_index.set_disabled(not self.use_baseline.read()) - self.baseline_stop_index.set_disabled(not self.use_baseline.read()) + self.baseline_method.set_disabled(not self.use_baseline.read()) + self.baseline_start_index.set_disabled(not self.use_baseline.read()) + self.baseline_stop_index.set_disabled(not self.use_baseline.read()) self.baseline_pre_index.set_disabled(not self.use_baseline.read()) - + def save(self): for obj in self.properties: obj.save() - + channels = pc.Mutex([Channel(i) for i in range(8)]) destination_channels = pc.Mutex([Channel(i) for i in range(8)]) -class Chopper(): - +class Chopper: def __init__(self, index): self.index = index - ini_section = ' '.join(['Chopper', str(self.index)]) + ini_section = " ".join(["Chopper", str(self.index)]) self.section = ini_section - self.active = pc.Bool(ini=ini, section=ini_section, option='active') - self.name = pc.String(inital_value='Name', ini=ini, section=ini_section, option='name') - self.physical_correspondance = pc.Number(decimals=0, limits=pc.NumberLimits(0, 7, None), ini=ini, section=ini_section, option='physical correspondance') - self.invert = pc.Bool(ini=ini, section=ini_section, option='invert') + self.active = pc.Bool(ini=ini, section=ini_section, option="active") + self.name = pc.String(inital_value="Name", ini=ini, section=ini_section, option="name") + self.physical_correspondance = pc.Number( + decimals=0, + limits=pc.NumberLimits(0, 7, None), + ini=ini, + section=ini_section, + option="physical correspondance", + ) + self.invert = pc.Bool(ini=ini, section=ini_section, option="invert") sample_limits = pc.NumberLimits(0, 899, None) - self.index = pc.Number(decimals=0, limits=sample_limits, ini=ini, section=ini_section, option='index') + self.index = pc.Number( + decimals=0, limits=sample_limits, ini=ini, section=ini_section, option="index" + ) # a list of all properties - self.properties = [self.active, self.name, - self.physical_correspondance, self.invert, - self.index] + self.properties = [ + self.active, + self.name, + self.physical_correspondance, + self.invert, + self.index, + ] # call get saved on self self.get_saved() - def get_saved(self): for obj in self.properties: obj.get_saved() def get_widget(self): self.input_table = pw.InputTable() - self.input_table.add('Name', self.name) - self.input_table.add('Physical Channel', self.physical_correspondance) - self.input_table.add('Invert', self.invert) - self.input_table.add('Index', self.index) + self.input_table.add("Name", self.name) + self.input_table.add("Physical Channel", self.physical_correspondance) + self.input_table.add("Invert", self.invert) + self.input_table.add("Index", self.index) return self.input_table - + def save(self): for obj in self.properties: obj.save() @@ -195,22 +251,40 @@ def save(self): # shots shot_channel_combo = pc.Combo() -shots_processing_module_path = pc.Filepath(ini=ini, section='DAQ', - option='shots processing module path', - import_from_ini=True, - save_to_ini_at_shutdown=True, - options=['*.py']) +shots_processing_module_path = pc.Filepath( + ini=ini, + section="DAQ", + option="shots processing module path", + import_from_ini=True, + save_to_ini_at_shutdown=True, + options=["*.py"], +) seconds_for_shots_processing = pc.Number(initial_value=np.nan, display=True, decimals=3) -save_shots_bool = pc.Bool(ini=ini, section='DAQ', option='save shots', display=True, - import_from_ini=True, save_to_ini_at_shutdown=True) +save_shots_bool = pc.Bool( + ini=ini, + section="DAQ", + option="save shots", + display=True, + import_from_ini=True, + save_to_ini_at_shutdown=True, +) axes = pc.Mutex() origin = pc.Mutex() # daq -nshots = pc.Number(initial_value = np.nan, ini=ini, section='DAQ', option='Shots', disable_under_module_control=True, decimals=0) -nsamples = pc.Number(initial_value = np.nan, ini=ini, section='DAQ', option='samples', decimals=0, display=True) +nshots = pc.Number( + initial_value=np.nan, + ini=ini, + section="DAQ", + option="Shots", + disable_under_module_control=True, + decimals=0, +) +nsamples = pc.Number( + initial_value=np.nan, ini=ini, section="DAQ", option="samples", decimals=0, display=True +) scan_index = pc.Number(initial_value=0, display=True, decimals=0) # sample correspondances holds an array of integers @@ -230,7 +304,6 @@ def save(self): class Device(BaseDevice): - def __init__(self, *args, **kwargs): self.initialized = False shots_processing_module_path.updated.connect(self.update_task) @@ -241,22 +314,22 @@ def __init__(self, *args, **kwargs): self.nshots.updated.connect(self.update_task) def load_settings(self, aqn): - self.nshots.write(aqn.read(self.name, 'shots')) - + self.nshots.write(aqn.read(self.name, "shots")) + def update_sample_correspondances(self, proposed_channels, proposed_choppers): - ''' + """ Parameters ---------- channels : list of Channel objects The proposed channel settings. choppers : list of Chopper objects The proposed chopper settings. - ''' + """ # sections is a list of lists: [correspondance, start index, stop index] sections = [] for i in range(len(proposed_channels)): channel = proposed_channels[i] - if channel.active.read(): + if channel.active.read(): correspondance = i + 1 # channels go from 1 --> infinity start = channel.signal_start_index.read() stop = channel.signal_stop_index.read() @@ -265,14 +338,14 @@ def update_sample_correspondances(self, proposed_channels, proposed_choppers): start = channel.baseline_start_index.read() stop = channel.baseline_stop_index.read() sections.append([correspondance, start, stop]) - # desired is a list of lists containing all of the channels + # desired is a list of lists containing all of the channels # that desire to be read at a given sample desired = [[] for _ in range(nsamples.read())] for section in sections: correspondance = section[0] start = int(section[1]) stop = int(section[2]) - for i in range(start, stop+1): + for i in range(start, stop + 1): desired[i].append(correspondance) desired[i] = [val for val in set(desired[i])] # remove non-unique desired[i].sort() @@ -281,11 +354,11 @@ def update_sample_correspondances(self, proposed_channels, proposed_choppers): for i in range(len(samples)): lis = desired[i] if not len(lis) == 0: - samples[i] = lis[i%len(lis)] + samples[i] = lis[i % len(lis)] # choppers for i, chopper in enumerate(proposed_choppers): if chopper.active.read(): - samples[int(chopper.index.read())] = -(i+1) + samples[int(chopper.index.read())] = -(i + 1) # check if proposed is valid # TODO: !!!!!!!!!!!!!!! # apply to channels @@ -296,24 +369,28 @@ def update_sample_correspondances(self, proposed_channels, proposed_choppers): for chopper in choppers.read(): chopper.save() # update channel names - channel_names = [channel.name.read() for channel in channels.read() if channel.active.read()] - chopper_names = [chopper.name.read() for chopper in choppers.read() if chopper.active.read()] + channel_names = [ + channel.name.read() for channel in channels.read() if channel.active.read() + ] + chopper_names = [ + chopper.name.read() for chopper in choppers.read() if chopper.active.read() + ] allowed_values = channel_names + chopper_names shot_channel_combo.set_allowed_values(allowed_values) # finish sample_correspondances.write(samples) self.update_task() - + def update_task(self): if self.initialized: if freerun.read(): return_to_freerun = True freerun.write(False) self.wait_until_still() - else: + else: return_to_freerun = False - self.q.push('create_task') - if return_to_freerun: + self.q.push("create_task") + if return_to_freerun: freerun.write(True) self.settings_updated.emit() @@ -331,15 +408,15 @@ def initialize(self): self.create_task() self.measure() self.settings_updated.emit() - + def create_task(self): - ''' + """ Define a new DAQ task. This needs to be run once every time the parameters of the aquisition (channel correspondance, shots, etc.) change. No inputs - ''' + """ # ensure previous task closed ----------------------------------------- if self.task_created: DAQmxStopTask(self.task_handle) @@ -353,16 +430,16 @@ def create_task(self): try: self.task_handle = TaskHandle() self.read = int32() # ??? --BJT 2017-06-03 - DAQmxCreateTask('', byref(self.task_handle)) + DAQmxCreateTask("", byref(self.task_handle)) except DAQError as err: - print("DAQmx Error: %s"%err) - g.logger.log('error', 'Error in task creation', err) + print("DAQmx Error: %s" % err) + g.logger.log("error", "Error in task creation", err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) return # initialize channels ------------------------------------------------- - # The daq is addressed in a somewhat non-standard way. A total of ~1000 - # virtual channels are initialized (depends on DAQ speed and laser rep + # The daq is addressed in a somewhat non-standard way. A total of ~1000 + # virtual channels are initialized (depends on DAQ speed and laser rep # rate). These virtual channels are evenly distributed over the physical # channels addressed by the software. When the task is run, it round # robins over all the virtual channels, essentially oversampling the @@ -383,47 +460,54 @@ def create_task(self): for correspondance in sample_correspondances.read(): if correspondance == 0: physical_channel = rest_channel.read() - min_voltage = -10. - max_voltage = 10. + min_voltage = -10.0 + max_voltage = 10.0 elif correspondance > 0: - channel = channels.read()[correspondance-1] + channel = channels.read()[correspondance - 1] physical_channel = channel.physical_correspondance.read() min_voltage, max_voltage = channel.get_range() elif correspondance < 0: - physical_channel = choppers.read()[-correspondance-1].physical_correspondance.read() - min_voltage = -10. - max_voltage = 10. - channel_name = 'sample_' + str(name_index).zfill(3) - DAQmxCreateAIVoltageChan(self.task_handle, # task handle - DAQ_device_name + '/ai%i'%physical_channel, # physical chanel - channel_name, # name to assign to channel - DAQmx_Val_Diff, # the input terminal configuration - min_voltage, max_voltage, # minVal, maxVal - DAQmx_Val_Volts, # units - None) # custom scale + physical_channel = choppers.read()[ + -correspondance - 1 + ].physical_correspondance.read() + min_voltage = -10.0 + max_voltage = 10.0 + channel_name = "sample_" + str(name_index).zfill(3) + DAQmxCreateAIVoltageChan( + self.task_handle, # task handle + DAQ_device_name + "/ai%i" % physical_channel, # physical chanel + channel_name, # name to assign to channel + DAQmx_Val_Diff, # the input terminal configuration + min_voltage, + max_voltage, # minVal, maxVal + DAQmx_Val_Volts, # units + None, + ) # custom scale name_index += 1 except DAQError as err: - print("DAQmx Error: %s"%err) - g.logger.log('error', 'Error in virtual channel creation', err) + print("DAQmx Error: %s" % err) + g.logger.log("error", "Error in virtual channel creation", err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) return # define timing ------------------------------------------------------- try: - DAQmxCfgSampClkTiming(self.task_handle, # task handle - '/' + DAQ_device_name + '/PFI0', # sorce terminal - 1000.0, # sampling rate (samples per second per channel) (float 64) (in externally clocked mode, only used to initialize buffer) - DAQmx_Val_Rising, # acquire samples on the rising edges of the sample clock - DAQmx_Val_FiniteSamps, # acquire a finite number of samples - int(self.shots)) # samples per channel to acquire (unsigned integer 64) + DAQmxCfgSampClkTiming( + self.task_handle, # task handle + "/" + DAQ_device_name + "/PFI0", # sorce terminal + 1000.0, # sampling rate (samples per second per channel) (float 64) (in externally clocked mode, only used to initialize buffer) + DAQmx_Val_Rising, # acquire samples on the rising edges of the sample clock + DAQmx_Val_FiniteSamps, # acquire a finite number of samples + int(self.shots), + ) # samples per channel to acquire (unsigned integer 64) except DAQError as err: - print("DAQmx Error: %s"%err) - g.logger.log('error', 'Error in timing definition', err) + print("DAQmx Error: %s" % err) + g.logger.log("error", "Error in timing definition", err) DAQmxStopTask(self.task_handle) DAQmxClearTask(self.task_handle) return # create arrays for task to fill -------------------------------------- - self.samples = np.zeros(int(self.shots*nsamples.read()), dtype=np.float64) + self.samples = np.zeros(int(self.shots * nsamples.read()), dtype=np.float64) self.samples_len = len(self.samples) # do not want to call for every acquisition # finish -------------------------------------------------------------- self.task_created = True @@ -438,7 +522,7 @@ def measure(self): ### measure ########################################################### # unpack inputs ------------------------------------------------------- self.running = True - #self.update_ui.emit() + # self.update_ui.emit() if not self.task_created: return start_time = time.time() @@ -449,18 +533,20 @@ def measure(self): self.thread self.read = int32() DAQmxStartTask(self.task_handle) - DAQmxReadAnalogF64(self.task_handle, # task handle - int(self.shots), # number of samples per channel - 10.0, # timeout (seconds) for each read operation - DAQmx_Val_GroupByScanNumber, # fill mode (specifies whether or not the samples are interleaved) - self.samples, # read array - self.samples_len, # size of the array, in samples, into which samples are read - byref(self.read), # reference of thread - None) # reserved by NI, pass NULL (?) - DAQmxStopTask(self.task_handle) + DAQmxReadAnalogF64( + self.task_handle, # task handle + int(self.shots), # number of samples per channel + 10.0, # timeout (seconds) for each read operation + DAQmx_Val_GroupByScanNumber, # fill mode (specifies whether or not the samples are interleaved) + self.samples, # read array + self.samples_len, # size of the array, in samples, into which samples are read + byref(self.read), # reference of thread + None, + ) # reserved by NI, pass NULL (?) + DAQmxStopTask(self.task_handle) except DAQError as err: - print("DAQmx Error: %s"%err) - g.logger.log('error', 'Error in timing definition', err) + print("DAQmx Error: %s" % err) + g.logger.log("error", "Error in timing definition", err) DAQmxStopTask(self.task_handle) time.sleep(wait) else: @@ -473,40 +559,59 @@ def measure(self): # calculate shot values for each channel, chopper --------------------- active_channels = [channel for channel in channels.read() if channel.active.read()] active_choppers = [chopper for chopper in choppers.read() if chopper.active.read()] - shots_array = np.full((len(active_channels)+len(active_choppers), int(self.shots)), np.nan) - folded_samples = self.samples.copy().reshape((nsamples.read(), -1), order='F') + shots_array = np.full( + (len(active_channels) + len(active_choppers), int(self.shots)), np.nan + ) + folded_samples = self.samples.copy().reshape((nsamples.read(), -1), order="F") index = 0 # channels for channel_index, channel in enumerate(active_channels): # get signal points - signal_index_possibilities = range(int(channel.signal_start_index.read()), int(channel.signal_stop_index.read()) + 1) - signal_indicies = [i for i in signal_index_possibilities if sample_correspondances.read()[i] == channel_index + 1] - signal_indicies = signal_indicies[int(channel.signal_pre_index.read()):] # remove pre points + signal_index_possibilities = range( + int(channel.signal_start_index.read()), int(channel.signal_stop_index.read()) + 1 + ) + signal_indicies = [ + i + for i in signal_index_possibilities + if sample_correspondances.read()[i] == channel_index + 1 + ] + signal_indicies = signal_indicies[ + int(channel.signal_pre_index.read()) : + ] # remove pre points signal_samples = folded_samples[signal_indicies] # process signal - if channel.signal_method.read() == 'Average': + if channel.signal_method.read() == "Average": signal = np.mean(signal_samples, axis=0) - elif channel.signal_method.read() == 'Sum': + elif channel.signal_method.read() == "Sum": signal = np.sum(signal_samples, axis=0) - elif channel.signal_method.read() == 'Min': + elif channel.signal_method.read() == "Min": signal = np.min(signal_samples, axis=0) - elif channel.signal_method.read() == 'Max': + elif channel.signal_method.read() == "Max": signal = np.max(signal_samples, axis=0) # baseline if channel.use_baseline.read(): # get baseline points - baseline_index_possibilities = range(int(channel.baseline_start_index.read()), int(channel.baseline_stop_index.read()) + 1) - baseline_indicies = [i for i in baseline_index_possibilities if sample_correspondances.read()[i] == channel_index + 1] - baseline_indicies = baseline_indicies[int(channel.baseline_pre_index.read()):] # remove pre points + baseline_index_possibilities = range( + int(channel.baseline_start_index.read()), + int(channel.baseline_stop_index.read()) + 1, + ) + baseline_indicies = [ + i + for i in baseline_index_possibilities + if sample_correspondances.read()[i] == channel_index + 1 + ] + baseline_indicies = baseline_indicies[ + int(channel.baseline_pre_index.read()) : + ] # remove pre points baseline_samples = folded_samples[baseline_indicies] # process baseline - if channel.baseline_method.read() == 'Average': + if channel.baseline_method.read() == "Average": baseline = np.mean(baseline_samples, axis=0) - elif channel.baseline_method.read() == 'Sum': + elif channel.baseline_method.read() == "Sum": baseline = np.sum(baseline_samples, axis=0) - elif channel.baseline_method.read() == 'Min': + elif channel.baseline_method.read() == "Min": baseline = np.min(baseline_samples, axis=0) - elif channel.baseline_method.read() == 'Max': + elif channel.baseline_method.read() == "Max": baseline = np.max(baseline_samples, axis=0) else: baseline = 0 @@ -519,10 +624,10 @@ def measure(self): index += 1 # choppers for chopper in active_choppers: - cutoff = 1. # volts + cutoff = 1.0 # volts out = folded_samples[int(chopper.index.read())] - out[out<=cutoff] = -1. - out[out>cutoff] = 1. + out[out <= cutoff] = -1.0 + out[out > cutoff] = 1.0 if chopper.invert.read(): out *= -1 shots_array[index] = out @@ -531,16 +636,16 @@ def measure(self): channel_names = [channel.name.read() for channel in active_channels] chopper_names = [chopper.name.read() for chopper in active_choppers] shots.write(shots_array) # TODO: can I remove this? - shots.write_properties((1,), channel_names+chopper_names, shots_array) + shots.write_properties((1,), channel_names + chopper_names, shots_array) # do math ------------------------------------------------------------- # pass through shots processing module with self.processing_timer: path = shots_processing_module_path.read() - name = os.path.basename(path).split('.')[0] + name = os.path.basename(path).split(".")[0] directory = os.path.dirname(path) f, p, d = imp.find_module(name, [directory]) processing_module = imp.load_module(name, f, p, d) - kinds = ['channel' for _ in channel_names] + ['chopper' for _ in chopper_names] + kinds = ["channel" for _ in channel_names] + ["chopper" for _ in chopper_names] names = channel_names + chopper_names out = processing_module.process(shots_array, names, kinds) if len(out) == 3: @@ -548,7 +653,7 @@ def measure(self): else: out, out_names = out out_signed = False - + seconds_for_shots_processing.write(self.processing_timer.interval) # export last data self.data.write_properties((1,), out_names, out, out_signed) @@ -562,14 +667,14 @@ def measure(self): self.measure_time.write(seconds_for_acquisition.read()) def shutdown(self, inputs): - if self.task_created: - DAQmxStopTask(self.task_handle) - DAQmxClearTask(self.task_handle) - + if self.task_created: + DAQmxStopTask(self.task_handle) + DAQmxClearTask(self.task_handle) + # --- gui ----------------------------------------------------------------------------------------- - + class GUI(BaseGUI): samples_tab_initialized = False @@ -585,14 +690,14 @@ def create_frame(self, parent_widget): samples_box = QtWidgets.QHBoxLayout() samples_box.setContentsMargins(0, 10, 0, 0) samples_widget.setLayout(samples_box) - self.tabs.addTab(samples_widget, 'Samples') + self.tabs.addTab(samples_widget, "Samples") self.create_samples_tab(samples_box) # shots tab shots_widget = QtWidgets.QWidget() shots_box = QtWidgets.QHBoxLayout() shots_box.setContentsMargins(0, 10, 0, 0) shots_widget.setLayout(shots_box) - self.tabs.addTab(shots_widget, 'Shots') + self.tabs.addTab(shots_widget, "Shots") self.create_shots_tab(shots_box) # finish layout.addWidget(self.tabs) @@ -600,7 +705,7 @@ def create_frame(self, parent_widget): self.samples_chopper_combo.updated.connect(self.update_samples_tab) self.hardware.update_ui.connect(self.update) self.update_samples_tab() - + def create_samples_tab(self, layout): # display ------------------------------------------------------------- # container widget @@ -613,36 +718,44 @@ def create_samples_tab(self, layout): self.samples_plot_widget = pw.Plot1D(yAutoRange=False) self.samples_plot_scatter = self.samples_plot_widget.add_scatter(color=0.25) self.samples_plot_active_scatter = self.samples_plot_widget.add_scatter() - self.samples_plot_widget.set_labels(xlabel='sample', ylabel='volts') - self.samples_plot_max_voltage_line = self.samples_plot_widget.add_infinite_line(color='y', angle=0) - self.samples_plot_min_voltage_line = self.samples_plot_widget.add_infinite_line(color='y', angle=0) - self.samples_plot_signal_stop_line = self.samples_plot_widget.add_infinite_line(color='r') - self.samples_plot_signal_start_line = self.samples_plot_widget.add_infinite_line(color='g') - self.samples_plot_baseline_stop_line = self.samples_plot_widget.add_infinite_line(color='r', style='dashed') - self.samples_plot_baseline_start_line = self.samples_plot_widget.add_infinite_line(color='g', style='dashed') - self.samples_plot_chopper_line = self.samples_plot_widget.add_infinite_line(color='b') + self.samples_plot_widget.set_labels(xlabel="sample", ylabel="volts") + self.samples_plot_max_voltage_line = self.samples_plot_widget.add_infinite_line( + color="y", angle=0 + ) + self.samples_plot_min_voltage_line = self.samples_plot_widget.add_infinite_line( + color="y", angle=0 + ) + self.samples_plot_signal_stop_line = self.samples_plot_widget.add_infinite_line(color="r") + self.samples_plot_signal_start_line = self.samples_plot_widget.add_infinite_line(color="g") + self.samples_plot_baseline_stop_line = self.samples_plot_widget.add_infinite_line( + color="r", style="dashed" + ) + self.samples_plot_baseline_start_line = self.samples_plot_widget.add_infinite_line( + color="g", style="dashed" + ) + self.samples_plot_chopper_line = self.samples_plot_widget.add_infinite_line(color="b") display_layout.addWidget(self.samples_plot_widget) legend = self.samples_plot_widget.plot_object.addLegend() - legend.addItem(self.samples_plot_active_scatter, 'channel samples') - legend.addItem(self.samples_plot_scatter, 'other samples') - style = pg.PlotDataItem(pen='y') - legend.addItem(style, 'voltage limits') - style = pg.PlotDataItem(pen='g') - legend.addItem(style, 'signal start') - style = pg.PlotDataItem(pen='r') - legend.addItem(style, 'signal stop') - pen = pg.mkPen('g', style=QtCore.Qt.DashLine) + legend.addItem(self.samples_plot_active_scatter, "channel samples") + legend.addItem(self.samples_plot_scatter, "other samples") + style = pg.PlotDataItem(pen="y") + legend.addItem(style, "voltage limits") + style = pg.PlotDataItem(pen="g") + legend.addItem(style, "signal start") + style = pg.PlotDataItem(pen="r") + legend.addItem(style, "signal stop") + pen = pg.mkPen("g", style=QtCore.Qt.DashLine) style = pg.PlotDataItem(pen=pen) - legend.addItem(style, 'baseline start') - pen = pg.mkPen('r', style=QtCore.Qt.DashLine) + legend.addItem(style, "baseline start") + pen = pg.mkPen("r", style=QtCore.Qt.DashLine) style = pg.PlotDataItem(pen=pen) - legend.addItem(style, 'baseline stop') - style = pg.PlotDataItem(pen='b') - legend.addItem(style, 'chopper index') + legend.addItem(style, "baseline stop") + style = pg.PlotDataItem(pen="b") + legend.addItem(style, "chopper index") # vertical line ------------------------------------------------------- - line = pw.line('V') - layout.addWidget(line) - # settings area ------------------------------------------------------- + line = pw.line("V") + layout.addWidget(line) + # settings area ------------------------------------------------------- # container widget / scroll area settings_container_widget = QtWidgets.QWidget() settings_scroll_area = pw.scroll_area(130) @@ -654,16 +767,18 @@ def create_samples_tab(self, layout): settings_layout.setMargin(5) layout.addWidget(settings_scroll_area) input_table = pw.InputTable() - input_table.add('Display', None) - self.sample_shots_displayed = pc.Number(initial_value=1, limits=pc.NumberLimits(1, 10), decimals=0, display=True) + input_table.add("Display", None) + self.sample_shots_displayed = pc.Number( + initial_value=1, limits=pc.NumberLimits(1, 10), decimals=0, display=True + ) self.sample_shots_displayed.updated.connect(self.on_sample_shots_displayed_updated) - input_table.add('Shots Displayed', self.sample_shots_displayed) - input_table.add('Settings', None) - input_table.add('Samples per Shot', nsamples) - input_table.add('Rest Channel', rest_channel) + input_table.add("Shots Displayed", self.sample_shots_displayed) + input_table.add("Settings", None) + input_table.add("Samples per Shot", nsamples) + input_table.add("Rest Channel", rest_channel) settings_layout.addWidget(input_table) # channels - line = pw.line('H') + line = pw.line("H") settings_layout.addWidget(line) # channel_combobox allowed_values = [channel.section for channel in channels.read() if channel.active.read()] @@ -671,16 +786,16 @@ def create_samples_tab(self, layout): self.samples_channel_combo.updated.connect(self.on_sample_shots_displayed_updated) self.on_sample_shots_displayed_updated() input_table = pw.InputTable() - input_table.add('Channel', self.samples_channel_combo) + input_table.add("Channel", self.samples_channel_combo) settings_layout.addWidget(input_table) # add button - self.add_channel_button = pw.SetButton('ADD CHANNEL') + self.add_channel_button = pw.SetButton("ADD CHANNEL") settings_layout.addWidget(self.add_channel_button) - self.add_channel_button.clicked.connect(self.on_add_channel) + self.add_channel_button.clicked.connect(self.on_add_channel) # remove button - self.remove_channel_button = pw.SetButton('REMOVE TRAILING CHANNEL', 'stop') + self.remove_channel_button = pw.SetButton("REMOVE TRAILING CHANNEL", "stop") settings_layout.addWidget(self.remove_channel_button) - self.remove_channel_button.clicked.connect(self.on_remove_channel) + self.remove_channel_button.clicked.connect(self.on_remove_channel) # channel widgets self.channel_widgets = [] for channel in destination_channels.read(): @@ -689,30 +804,32 @@ def create_samples_tab(self, layout): widget.hide() self.channel_widgets.append(widget) # apply button - self.apply_channel_button = pw.SetButton('APPLY CHANGES') + self.apply_channel_button = pw.SetButton("APPLY CHANGES") self.apply_channel_button.clicked.connect(self.on_apply_channel) settings_layout.addWidget(self.apply_channel_button) # revert button - self.revert_channel_button = pw.SetButton('REVERT CHANGES', 'stop') + self.revert_channel_button = pw.SetButton("REVERT CHANGES", "stop") self.revert_channel_button.clicked.connect(self.on_revert_channel) settings_layout.addWidget(self.revert_channel_button) # dividing line - line = pw.line('H') + line = pw.line("H") settings_layout.addWidget(line) # chopper_combobox - allowed_values = [chopper.section for chopper in destination_choppers.read() if chopper.active.read()] + allowed_values = [ + chopper.section for chopper in destination_choppers.read() if chopper.active.read() + ] self.samples_chopper_combo = pc.Combo(allowed_values=allowed_values) input_table = pw.InputTable() - input_table.add('Chopper', self.samples_chopper_combo) + input_table.add("Chopper", self.samples_chopper_combo) settings_layout.addWidget(input_table) # add button - self.add_chopper_button = pw.SetButton('ADD CHOPPER') + self.add_chopper_button = pw.SetButton("ADD CHOPPER") settings_layout.addWidget(self.add_chopper_button) - self.add_chopper_button.clicked.connect(self.on_add_chopper) + self.add_chopper_button.clicked.connect(self.on_add_chopper) # remove button - self.remove_chopper_button = pw.SetButton('REMOVE TRAILING CHOPPER', 'stop') + self.remove_chopper_button = pw.SetButton("REMOVE TRAILING CHOPPER", "stop") settings_layout.addWidget(self.remove_chopper_button) - self.remove_chopper_button.clicked.connect(self.on_remove_chopper) + self.remove_chopper_button.clicked.connect(self.on_remove_chopper) # chopper widgets self.chopper_widgets = [] for chopper in destination_choppers.read(): @@ -721,11 +838,11 @@ def create_samples_tab(self, layout): widget.hide() self.chopper_widgets.append(widget) # apply button - self.apply_chopper_button = pw.SetButton('APPLY CHANGES') + self.apply_chopper_button = pw.SetButton("APPLY CHANGES") self.apply_chopper_button.clicked.connect(self.on_apply_chopper) settings_layout.addWidget(self.apply_chopper_button) # revert button - self.revert_chopper_button = pw.SetButton('REVERT CHANGES', 'stop') + self.revert_chopper_button = pw.SetButton("REVERT CHANGES", "stop") self.revert_chopper_button.clicked.connect(self.on_revert_chopper) settings_layout.addWidget(self.revert_chopper_button) # finish -------------------------------------------------------------- @@ -738,15 +855,15 @@ def create_shots_tab(self, layout): display_container_widget.setLayout(QtWidgets.QVBoxLayout()) display_layout = display_container_widget.layout() display_layout.setMargin(0) - layout.addWidget(display_container_widget) + layout.addWidget(display_container_widget) # plot self.shots_plot_widget = pw.Plot1D() self.shots_plot_scatter = self.shots_plot_widget.add_scatter() - self.shots_plot_widget.set_labels(xlabel='shot', ylabel='volts') - display_layout.addWidget(self.shots_plot_widget) + self.shots_plot_widget.set_labels(xlabel="shot", ylabel="volts") + display_layout.addWidget(self.shots_plot_widget) # vertical line ------------------------------------------------------- - line = pw.line('V') - layout.addWidget(line) + line = pw.line("V") + layout.addWidget(line) # settings ------------------------------------------------------------ # container widget / scroll area settings_container_widget = QtWidgets.QWidget() @@ -760,31 +877,35 @@ def create_shots_tab(self, layout): layout.addWidget(settings_scroll_area) # input table input_table = pw.InputTable() - input_table.add('Display', None) - input_table.add('Channel', shot_channel_combo) + input_table.add("Display", None) + input_table.add("Channel", shot_channel_combo) shot_channel_combo.updated.connect(self.on_shot_channel_updated) - input_table.add('Settings', None) - input_table.add('Shots', nshots) - input_table.add('Save Shots', save_shots_bool) - input_table.add('Shot Processing', shots_processing_module_path) - input_table.add('Processing Time', seconds_for_shots_processing) + input_table.add("Settings", None) + input_table.add("Shots", nshots) + input_table.add("Save Shots", save_shots_bool) + input_table.add("Shot Processing", shots_processing_module_path) + input_table.add("Processing Time", seconds_for_shots_processing) settings_layout.addWidget(input_table) # finish -------------------------------------------------------------- settings_layout.addStretch(1) shot_channel_combo.updated.emit() def on_add_channel(self): - allowed_values = [channel.section for channel in destination_channels.read() if channel.active.read()] - new_channel_section = 'Channel %i'%len(allowed_values) + allowed_values = [ + channel.section for channel in destination_channels.read() if channel.active.read() + ] + new_channel_section = "Channel %i" % len(allowed_values) allowed_values.append(new_channel_section) self.samples_channel_combo.set_allowed_values(allowed_values) self.samples_channel_combo.write(new_channel_section) # do not activate channel until changes are applied self.update_samples_tab() - + def on_add_chopper(self): - allowed_values = [chopper.section for chopper in destination_choppers.read() if chopper.active.read()] - new_chopper_section = 'Chopper %i'%len(allowed_values) + allowed_values = [ + chopper.section for chopper in destination_choppers.read() if chopper.active.read() + ] + new_chopper_section = "Chopper %i" % len(allowed_values) allowed_values.append(new_chopper_section) self.samples_chopper_combo.set_allowed_values(allowed_values) self.samples_chopper_combo.write(new_chopper_section) @@ -799,7 +920,7 @@ def on_apply_channel(self): new_channels[new_channel_index] = new_channel self.hardware.update_sample_correspondances(new_channels, choppers.read()) self.update_samples_tab() - + def on_apply_chopper(self): new_chopper_index = int(self.samples_chopper_combo.read()[-1]) new_chopper = destination_choppers.read()[new_chopper_index] @@ -808,7 +929,7 @@ def on_apply_chopper(self): new_choppers[new_chopper_index] = new_chopper self.hardware.update_sample_correspondances(channels.read(), new_choppers) self.update_samples_tab() - + def on_remove_channel(self): # loop through channels backwards for channel in channels.read()[::-1]: @@ -818,7 +939,9 @@ def on_remove_channel(self): channel.save() break self.hardware.update_sample_correspondances(channels.read(), choppers.read()) - allowed_values = [channel.section for channel in destination_channels.read() if channel.active.read()] + allowed_values = [ + channel.section for channel in destination_channels.read() if channel.active.read() + ] self.samples_channel_combo.set_allowed_values(allowed_values) self.samples_channel_combo.write(allowed_values[-1]) self.update_samples_tab() @@ -832,7 +955,9 @@ def on_remove_chopper(self): chopper.save() break self.hardware.update_sample_correspondances(channels.read(), choppers.read()) - allowed_values = [chopper.section for chopper in destination_choppers.read() if chopper.active.read()] + allowed_values = [ + chopper.section for chopper in destination_choppers.read() if chopper.active.read() + ] self.samples_chopper_combo.set_allowed_values(allowed_values) self.samples_chopper_combo.write(allowed_values[-1]) self.update_samples_tab() @@ -844,31 +969,49 @@ def on_revert_channel(self): def on_revert_chopper(self): chopper_index = int(self.samples_chopper_combo.read()[-1]) destination_choppers.read()[chopper_index].get_saved() - + def on_sample_shots_displayed_updated(self): # all samples - self.sample_xi = list(range(nsamples.read()))*int(self.sample_shots_displayed.read()) + self.sample_xi = list(range(nsamples.read())) * int(self.sample_shots_displayed.read()) # signal samples current_channel_object = channels.read()[self.samples_channel_combo.read_index()] signal_start_index = int(current_channel_object.signal_start_index.read()) signal_stop_index = int(current_channel_object.signal_stop_index.read()) - self.signal_indicies = np.array([i for i in np.arange(signal_start_index, signal_stop_index) if sample_correspondances.read()[i] == self.samples_channel_combo.read_index() + 1], dtype=np.int) - self.signal_xi = list(self.signal_indicies)*int(self.sample_shots_displayed.read()) + self.signal_indicies = np.array( + [ + i + for i in np.arange(signal_start_index, signal_stop_index) + if sample_correspondances.read()[i] == self.samples_channel_combo.read_index() + 1 + ], + dtype=np.int, + ) + self.signal_xi = list(self.signal_indicies) * int(self.sample_shots_displayed.read()) for i in range(1, int(self.sample_shots_displayed.read())): - self.signal_indicies = np.hstack((self.signal_indicies, self.signal_indicies+i*nsamples.read())) + self.signal_indicies = np.hstack( + (self.signal_indicies, self.signal_indicies + i * nsamples.read()) + ) # baseline samples baseline_start_index = int(current_channel_object.baseline_start_index.read()) baseline_stop_index = int(current_channel_object.baseline_stop_index.read()) - self.baseline_indicies = np.array([i for i in np.arange(baseline_start_index, baseline_stop_index) if sample_correspondances.read()[i] == self.samples_channel_combo.read_index() + 1], dtype=np.int) - self.baseline_xi = list(self.baseline_indicies)*int(self.sample_shots_displayed.read()) + self.baseline_indicies = np.array( + [ + i + for i in np.arange(baseline_start_index, baseline_stop_index) + if sample_correspondances.read()[i] == self.samples_channel_combo.read_index() + 1 + ], + dtype=np.int, + ) + self.baseline_xi = list(self.baseline_indicies) * int(self.sample_shots_displayed.read()) for i in range(1, int(self.sample_shots_displayed.read())): - self.baseline_indicies = np.hstack((self.baseline_indicies, self.baseline_indicies+i*nsamples.read())) + self.baseline_indicies = np.hstack( + (self.baseline_indicies, self.baseline_indicies + i * nsamples.read()) + ) def on_shot_channel_updated(self): # update y range to be range of channel channel_index = shot_channel_combo.read_index() active_channels = [channel for channel in channels.read() if channel.active.read()] - if channel_index > len(active_channels)-1: + if channel_index > len(active_channels) - 1: # must be a chopper ymin = -1 ymax = 1 @@ -876,22 +1019,22 @@ def on_shot_channel_updated(self): # is a channel channel = active_channels[channel_index] ymin, ymax = channel.get_range() - self.shots_plot_widget.set_ylim(ymin*1.05, ymax*1.05) - + self.shots_plot_widget.set_ylim(ymin * 1.05, ymax * 1.05) + def set_slice_xlim(self, xmin, xmax): self.values_plot_widget.set_xlim(xmin, xmax) - + def update(self): - ''' + """ Runs each time an update_ui signal fires (basically every run_task) - ''' - # TODO: I need this check for a race condition during startup that I + """ + # TODO: I need this check for a race condition during startup that I # do not understand. Eventually it should be removed. # - Blaise 2016.01.30 - if samples.read() is None: + if samples.read() is None: return # all samples - yi = samples.read()[:nsamples.read()*self.sample_shots_displayed.read()] + yi = samples.read()[: nsamples.read() * self.sample_shots_displayed.read()] self.samples_plot_scatter.clear() self.samples_plot_scatter.setData(self.sample_xi, yi) # active samples @@ -915,7 +1058,7 @@ def update(self): self.update_samples_tab() def update_samples_tab(self): - # TODO: I need this check for a race condition during startup that I + # TODO: I need this check for a race condition during startup that I # do not understand. Eventually it should be removed. # - Blaise 2016-01-30 if samples.read() is None: @@ -952,20 +1095,28 @@ def update_samples_tab(self): if current_channel_object.active.read(): channel_min, channel_max = current_channel_object.get_range() self.samples_plot_max_voltage_line.show() - self.samples_plot_max_voltage_line.setValue(channel_max*1.05) + self.samples_plot_max_voltage_line.setValue(channel_max * 1.05) self.samples_plot_min_voltage_line.show() - self.samples_plot_min_voltage_line.setValue(channel_min*1.05) - self.samples_plot_signal_start_line.show() - self.samples_plot_signal_start_line.setValue(current_channel_object.signal_start_index.read()) + self.samples_plot_min_voltage_line.setValue(channel_min * 1.05) + self.samples_plot_signal_start_line.show() + self.samples_plot_signal_start_line.setValue( + current_channel_object.signal_start_index.read() + ) self.samples_plot_signal_stop_line.show() - self.samples_plot_signal_stop_line.setValue(current_channel_object.signal_stop_index.read()) + self.samples_plot_signal_stop_line.setValue( + current_channel_object.signal_stop_index.read() + ) if current_channel_object.use_baseline.read(): self.samples_plot_baseline_start_line.show() - self.samples_plot_baseline_start_line.setValue(current_channel_object.baseline_start_index.read()) + self.samples_plot_baseline_start_line.setValue( + current_channel_object.baseline_start_index.read() + ) self.samples_plot_baseline_stop_line.show() - self.samples_plot_baseline_stop_line.setValue(current_channel_object.baseline_stop_index.read()) + self.samples_plot_baseline_stop_line.setValue( + current_channel_object.baseline_stop_index.read() + ) current_chopper_object = choppers.read()[chopper_index] - if current_chopper_object.active.read(): + if current_chopper_object.active.read(): self.samples_plot_chopper_line.show() self.samples_plot_chopper_line.setValue(current_chopper_object.index.read()) # finish @@ -980,32 +1131,31 @@ def stop(self): class Widget(BaseWidget): - def __init__(self): BaseWidget.__init__(self) layout = QtWidgets.QVBoxLayout() self.setLayout(layout) layout.setMargin(0) input_table = pw.InputTable() - input_table.add('PCI-6251', None) + input_table.add("PCI-6251", None) self.use = pc.Bool(initial_value=True) - input_table.add('Use', self.use) + input_table.add("Use", self.use) self.shots = pc.Number(initial_value=100, decimals=0) - input_table.add('Shots', self.shots) - #self.save_shots = pc.Bool(initial_value=False) - #self.save_shots.set_disabled(True) - #input_table.add('Save Shots', self.save_shots) + input_table.add("Shots", self.shots) + # self.save_shots = pc.Bool(initial_value=False) + # self.save_shots.set_disabled(True) + # input_table.add('Save Shots', self.save_shots) layout.addWidget(input_table) - + def load(self, aqn_path): ini = wt.kit.INI(aqn_path) - self.use.write(ini.read('PCI-6251', 'use')) - self.shots.write(ini.read('PCI-6251', 'shots')) + self.use.write(ini.read("PCI-6251", "use")) + self.shots.write(ini.read("PCI-6251", "shots")) # self.save_shots.write(ini.read('PCI-6251', 'save shots')) def save(self, aqn_path): ini = wt.kit.INI(aqn_path) - ini.add_section('PCI-6251') - ini.write('PCI-6251', 'use', self.use.read()) - ini.write('PCI-6251', 'shots', self.shots.read()) + ini.add_section("PCI-6251") + ini.write("PCI-6251", "use", self.use.read()) + ini.write("PCI-6251", "shots", self.shots.read()) # ini.write('PCI-6251', 'save shots', self.save_shots.read()) diff --git a/devices/PCI-6251/shots_processing/default.py b/devices/PCI-6251/shots_processing/default.py index 5f1e28cb..361fd220 100644 --- a/devices/PCI-6251/shots_processing/default.py +++ b/devices/PCI-6251/shots_processing/default.py @@ -1,7 +1,8 @@ import numpy as np + def process(shots, names, kinds): - ''' + """ Mean of everything Parameters @@ -17,6 +18,6 @@ def process(shots, names, kinds): ------- list [ndarray (channels), list of channel names] - ''' + """ out = [np.mean(arr) for arr in shots] return [out, names] diff --git a/devices/__init__.py b/devices/__init__.py index d8ccb6ff..2c343950 100644 --- a/devices/__init__.py +++ b/devices/__init__.py @@ -1 +1 @@ -#import InGaAs_array \ No newline at end of file +# import InGaAs_array diff --git a/devices/devices.py b/devices/devices.py index cd9779a4..9a45d727 100644 --- a/devices/devices.py +++ b/devices/devices.py @@ -26,13 +26,23 @@ main_dir = g.main_dir.read() -ini = wt.kit.INI(os.path.join(main_dir, 'devices', 'devices.ini')) +ini = wt.kit.INI(os.path.join(main_dir, "devices", "devices.ini")) # dictionary of how to access all PyCMDS-compatible DAQ devices # [module path, class name, initialization arguments, friendly name] device_dict = collections.OrderedDict() -device_dict['NI 6251'] = [os.path.join(main_dir, 'devices', 'NI_6251', 'NI_6251.py'), 'Device', [None], 'ni6251'] -device_dict['InGaAs array'] = [os.path.join(main_dir, 'devices', 'InGaAs_array', 'InGaAs.py'), 'Device', [None], 'InGaAs'] +device_dict["NI 6251"] = [ + os.path.join(main_dir, "devices", "NI_6251", "NI_6251.py"), + "Device", + [None], + "ni6251", +] +device_dict["InGaAs array"] = [ + os.path.join(main_dir, "devices", "InGaAs_array", "InGaAs.py"), + "Device", + [None], + "InGaAs", +] axes = pc.Mutex() @@ -48,21 +58,22 @@ save_shots = pc.Bool(display=True) ms_wait_limits = pc.NumberLimits(0, 10000) -ms_wait = pc.Number(ini=ini, section='settings', option='ms wait', decimals=0, - limits=ms_wait_limits, display=True) - +ms_wait = pc.Number( + ini=ini, section="settings", option="ms wait", decimals=0, limits=ms_wait_limits, display=True +) + # --- classes ------------------------------------------------------------------------------------- - + class CurrentSlice(QtCore.QObject): indexed = QtCore.Signal() appended = QtCore.Signal() - + def __init__(self): QtCore.QObject.__init__(self) - + def begin(self, shape): - ''' + """ Tell current slice that a new scan is beginning. Mostly works to reset y limits. @@ -70,18 +81,18 @@ def begin(self, shape): ---------- shape : list of ints Number of channels for all devices. - ''' + """ self.xi = [] self.data = [] self.ymins = [] self.ymaxs = [] self.use_actual = False for n_channels in shape: - self.ymins.append([-1e-6]*n_channels) - self.ymaxs.append([1e-6]*n_channels) - + self.ymins.append([-1e-6] * n_channels) + self.ymaxs.append([1e-6] * n_channels) + def index(self, d): - ''' + """ Clear the old data from memory, and define new parameters for the next slice. @@ -90,17 +101,17 @@ def index(self, d): d : dictionary The new slice dictionary, passed all the way from the acquisition orderer module. - ''' - self.name = str(d['name']) # somehow a qstring is getting here? - Blaise 2016.07.27 - self.units = d['units'] - self.points = d['points'] - self.use_actual = d['use actual'] + """ + self.name = str(d["name"]) # somehow a qstring is getting here? - Blaise 2016.07.27 + self.units = d["units"] + self.points = d["points"] + self.use_actual = d["use actual"] self.xi = [] self.data = [] self.indexed.emit() - + def append(self, position, data): - ''' + """ Add new values into the slice. Parameters @@ -109,7 +120,7 @@ def append(self, position, data): The axis position (in the slices' own axis / units) data : list of lists of arrays List of 1) devices, 2) channels, containing arrays - ''' + """ if self.use_actual: self.xi.append(position) else: @@ -125,22 +136,22 @@ def append(self, position, data): self.ymaxs[device_index][channel_index] = maximum self.appended.emit() + current_slice = CurrentSlice() class Headers: - def __init__(self): - ''' + """ Contains all the seperate dictionaries that go into assembling file headers. - ''' + """ self.clear() - + def clear(self): - ''' + """ All dictionaries are now empty OrderedDicts. - ''' + """ self.pycmds_info = collections.OrderedDict() self.scan_info = collections.OrderedDict() self.data_info = collections.OrderedDict() @@ -150,35 +161,43 @@ def clear(self): self.daq_info = collections.OrderedDict() self.data_cols = collections.OrderedDict() self.shots_cols = collections.OrderedDict() - - def read(self, kind='data'): - ''' + + def read(self, kind="data"): + """ Assemble contained dictionaries into a single dictionary. Parameters ---------- kind : {'data', 'shots'} (optional) Which kind of dictionary to return. Default is data. - ''' + """ # get correct cols dictionary - if kind == 'data': + if kind == "data": cols = self.data_cols channel_info = self.channel_info - elif kind == 'shots': + elif kind == "shots": cols = self.shots_cols channel_info = {} else: - raise Exception('kind {} not recognized in daq.Headers.get'.format(kind)) + raise Exception("kind {} not recognized in daq.Headers.get".format(kind)) # assemble - dicts = [self.pycmds_info, self.data_info, self.scan_info, - self.axis_info, self.constant_info, channel_info, - self.daq_info, cols] + dicts = [ + self.pycmds_info, + self.data_info, + self.scan_info, + self.axis_info, + self.constant_info, + channel_info, + self.daq_info, + cols, + ] out = collections.OrderedDict() for d in dicts: for key, value in d.items(): out[key] = value return out + headers = Headers() @@ -199,121 +218,128 @@ def read(self, kind='data'): class FileAddress(QtCore.QObject): update_ui = QtCore.Signal() queue_emptied = QtCore.Signal() - + @QtCore.Slot(str, list) def dequeue(self, method, inputs): - ''' + """ accepts queued signals from 'queue' (address using q method) method must be string, inputs must be list - ''' - if g.debug.read(): - print('data dequeue:', method) + """ + if g.debug.read(): + print("data dequeue:", method) getattr(self, str(method))(inputs) # method passed as qstring enqueued_data.pop() - if not enqueued_data.read(): + if not enqueued_data.read(): self.queue_emptied.emit() self.check_busy([]) - + def check_busy(self, inputs): - ''' + """ must always write busy whether answer is True or False should include a sleep if answer is True to prevent very fast loops: time.sleep(0.1) - ''' + """ if enqueued_data.read(): time.sleep(0.01) data_busy.write(True) else: time.sleep(0.01) data_busy.write(False) - + def create_data(self, inputs): - # unpack inputs + # unpack inputs aqn, scan_folder = inputs file_index = 0 # pixels -------------------------------------------------------------- # file name file_index_str = str(file_index).zfill(3) - self.filename = ' '.join([file_index_str]).rstrip() + self.filename = " ".join([file_index_str]).rstrip() # create folder - data_path.write(os.path.join(scan_folder, self.filename + '.data')) + data_path.write(os.path.join(scan_folder, self.filename + ".data")) # generate file - dictionary = headers.read(kind='data') + dictionary = headers.read(kind="data") tidy_headers.write(data_path.read(), dictionary) # shots --------------------------------------------------------------- # TODO: this is hack - if aqn.has_section('NI 6251'): - if False and aqn.read('NI 6251', 'save shots'): - p = os.path.join(os.path.dirname(data_path.read()), 'NI 6251 shots.hdf5') + if aqn.has_section("NI 6251"): + if False and aqn.read("NI 6251", "save shots"): + p = os.path.join(os.path.dirname(data_path.read()), "NI 6251 shots.hdf5") f = h5py.File(p) - dictionary = headers.read(kind='shots') + dictionary = headers.read(kind="shots") for key, value in dictionary.items(): # remove None if type(value) is list: for i, val in enumerate(value): if val is None: - value[i] = 'None' + value[i] = "None" if isinstance(val, basestring): value[i] = str(val) # cannot handle unicode in lists... # write to hdf5 f.attrs[key] = value - col_count = len(dictionary['name']) - f.create_dataset('array', (col_count, 0), maxshape=(col_count, None), compression='gzip') - f['array'].set_fill_value = np.nan + col_count = len(dictionary["name"]) + f.create_dataset( + "array", (col_count, 0), maxshape=(col_count, None), compression="gzip" + ) + f["array"].set_fill_value = np.nan f.close() def write_data(self, inputs): data_arr, shots_arr = inputs # pixels -------------------------------------------------------------- - data_file = open(data_path.read(), 'ab') + data_file = open(data_path.read(), "ab") if len(data_arr.shape) == 2: # case of multidimensional devices for row in data_arr.T: - np.savetxt(data_file, row, fmt=str('%8.6f'), delimiter='\t', newline='\t') - data_file.write(b'\n') + np.savetxt(data_file, row, fmt=str("%8.6f"), delimiter="\t", newline="\t") + data_file.write(b"\n") else: - np.savetxt(data_file, data_arr, fmt=str('%8.6f'), delimiter='\t', newline='\t') - data_file.write(b'\n') + np.savetxt(data_file, data_arr, fmt=str("%8.6f"), delimiter="\t", newline="\t") + data_file.write(b"\n") data_file.close() # shots --------------------------------------------------------------- - p = os.path.join(os.path.dirname(data_path.read()), 'NI 6251 shots.hdf5') # TODO: this is hack + p = os.path.join( + os.path.dirname(data_path.read()), "NI 6251 shots.hdf5" + ) # TODO: this is hack if os.path.isfile(p): f = h5py.File(p) - current_row_count = f['array'].shape[1] + current_row_count = f["array"].shape[1] new_row_count = shots_arr.shape[1] - f['array'].resize(current_row_count+new_row_count, axis=1) - f['array'][:, current_row_count:current_row_count+new_row_count] = shots_arr + f["array"].resize(current_row_count + new_row_count, axis=1) + f["array"][:, current_row_count : current_row_count + new_row_count] = shots_arr f.close() def initialize(self, inputs): pass - + def shutdown(self, inputs): # TODO: ? pass -#begin address object in seperate thread + +# begin address object in seperate thread data_thread = QtCore.QThread() data_obj = FileAddress() data_obj.moveToThread(data_thread) data_thread.start() -#create queue to communiate with address thread +# create queue to communiate with address thread class DataQueue(QtCore.QObject): signal = QtCore.Signal(str, list) def __init__(self): super(DataQueue, self).__init__() + data_queue = DataQueue() data_queue.signal.connect(data_obj.dequeue, type=QtCore.Qt.QueuedConnection) -def q(method, inputs = []): - #add to friendly queue list + +def q(method, inputs=[]): + # add to friendly queue list enqueued_data.push([method, time.time()]) - #busy + # busy data_busy.write(True) - #send Qt SIGNAL to address thread + # send Qt SIGNAL to address thread data_queue.signal.emit(method, inputs) - #data_queue.invokeMethod(data_obj, 'dequeue', QtCore.Qt.QueuedConnection, QtCore.Q_ARG(str, method), QtCore.Q_ARG(list, inputs)) + # data_queue.invokeMethod(data_obj, 'dequeue', QtCore.Qt.QueuedConnection, QtCore.Q_ARG(str, method), QtCore.Q_ARG(list, inputs)) # --- device -------------------------------------------------------------------------------------- @@ -321,27 +347,27 @@ def q(method, inputs = []): class Device(pc.Hardware): settings_updated = QtCore.Signal() - + def __init__(self, *args, **kwargs): self.freerun = pc.Bool(initial_value=False) - self.Widget = kwargs.pop('Widget') + self.Widget = kwargs.pop("Widget") self.data = pc.Data() self.active = False # shape - if 'shape' in kwargs.keys(): - self.shape = kwargs.pop('shape') + if "shape" in kwargs.keys(): + self.shape = kwargs.pop("shape") else: self.shape = (1,) # map - if 'has_map' in kwargs.keys(): - self.has_map = kwargs.pop('has_map') + if "has_map" in kwargs.keys(): + self.has_map = kwargs.pop("has_map") else: self.has_map = False # shots_compatable - if 'shots_compatible' in kwargs.keys(): - self.shots_compatible = kwargs.pop('shots_compatible') + if "shots_compatible" in kwargs.keys(): + self.shots_compatible = kwargs.pop("shots_compatible") else: - self.shots_compatible = False + self.shots_compatible = False self.nshots = pc.Number(initial_value=100) self.measure_time = pc.Number(initial_value=np.nan, display=True, decimals=3) pc.Hardware.__init__(self, *args, **kwargs) @@ -356,10 +382,10 @@ def close(self): # TODO: log if False: if g.debug.read(): - print('daq shutting down') - g.logger.log('info', 'DAQ shutdown') + print("daq shutting down") + g.logger.log("info", "DAQ shutdown") # shutdown driver - q.push('shutdown') + q.push("shutdown") self.wait_until_done() self.thread.quit() else: @@ -367,31 +393,31 @@ def close(self): def get_headers(self): out = collections.OrderedDict() - out['shots'] = self.nshots.read() + out["shots"] = self.nshots.read() return out - + def give_widget(self, widget): self.widget = widget self.gui.create_frame(widget) - + def initialize(self): self.wait_until_still() self.freerun.updated.connect(self.on_freerun_updated) self.update_ui.emit() self.driver.update_ui.connect(self.on_driver_update_ui) self.settings_updated.emit() - + def load_settings(self, aqn): pass def measure(self): - self.q.push('measure') - + self.q.push("measure") + def on_driver_update_ui(self): self.update_ui.emit() - + def on_freerun_updated(self): - self.q.push('loop') + self.q.push("loop") def set_freerun(self, state): self.freerun.write(state) @@ -409,11 +435,11 @@ def wait_until_still(self): class Driver(pc.Driver): settings_updated = QtCore.Signal() running = False - + def __init__(self, device): pc.Driver.__init__(self) # attributes - self.name = 'Virtual' + self.name = "Virtual" self.enqueued = device.enqueued self.busy = device.busy self.freerun = device.freerun @@ -430,13 +456,13 @@ def loop(self): self.measure() self.busy.write(False) else: - print(' '.join([self.name, 'exiting loop!'])) + print(" ".join([self.name, "exiting loop!"])) def measure(self): timer = wt.kit.Timer(verbose=False) with timer: time.sleep(0.1) - out_names = ['channel_%i' % i for i in range(5)] + out_names = ["channel_%i" % i for i in range(5)] signed = [not i % 2 for i in range(5)] out = np.random.standard_normal(len(out_names)) self.data.write_properties(self.shape, out_names, out, signed) @@ -451,29 +477,27 @@ def shutdown(self): class Widget(QtWidgets.QWidget): - def __init__(self): QtWidgets.QWidget.__init__(self) layout = QtWidgets.QVBoxLayout() self.setLayout(layout) layout.setMargin(0) input_table = pw.InputTable() - input_table.add('Virtual', None) + input_table.add("Virtual", None) self.use = pc.Bool(initial_value=True) - input_table.add('Use', self.use) + input_table.add("Use", self.use) layout.addWidget(input_table) - + def load(self, aqn_path): pass - + def save(self, aqn_path): ini = wt.kit.INI(aqn_path) - ini.add_section('virtual') - ini.write('virtual', 'use', self.use.read()) + ini.add_section("virtual") + ini.write("virtual", "use", self.use.read()) - -class DeviceGUI(QtCore.QObject): +class DeviceGUI(QtCore.QObject): def __init__(self, hardware): QtCore.QObject.__init__(self) self.hardware = hardware @@ -496,8 +520,9 @@ class Control(QtCore.QObject): """ Only one instance in the entire program. """ - settings_updated = QtCore.Signal() - + + settings_updated = QtCore.Signal() + def __init__(self): QtCore.QObject.__init__(self) self.devices = [] @@ -505,31 +530,46 @@ def __init__(self): self.channel_names = [] # import devices for section in ini.sections: - if section == 'settings': + if section == "settings": continue - if ini.read(section, 'enable'): + if ini.read(section, "enable"): # collect arguments kwargs = collections.OrderedDict() for option in ini.get_options(section): - if option in ['enable', 'model', 'serial', 'path', '__name__']: + if option in ["enable", "model", "serial", "path", "__name__"]: continue else: - kwargs[option] = ini.read(section, option) - model = ini.read(section, 'model') + kwargs[option] = ini.read(section, option) + model = ini.read(section, "model") # import - if model == 'Virtual': - device = Device(Driver, kwargs, DeviceGUI, Widget=DeviceWidget, name=section, model='Virtual') + if model == "Virtual": + device = Device( + Driver, + kwargs, + DeviceGUI, + Widget=DeviceWidget, + name=section, + model="Virtual", + ) else: - path = os.path.abspath(ini.read(section, 'path')) - fname = os.path.basename(path).split('.')[0] + path = os.path.abspath(ini.read(section, "path")) + fname = os.path.basename(path).split(".")[0] mod = imp.load_source(fname, path) - device_cls = getattr(mod, 'Device') - cls = getattr(mod, 'Driver') - gui = getattr(mod, 'GUI') - widget_cls = getattr(mod, 'Widget') - serial = ini.read(section, 'serial') - device = device_cls(cls, kwargs, gui, Widget=widget_cls, name=section, model=model, serial=serial) - self.devices.append(device) + device_cls = getattr(mod, "Device") + cls = getattr(mod, "Driver") + gui = getattr(mod, "GUI") + widget_cls = getattr(mod, "Widget") + serial = ini.read(section, "serial") + device = device_cls( + cls, + kwargs, + gui, + Widget=widget_cls, + name=section, + model=model, + serial=serial, + ) + self.devices.append(device) # gui self.gui = GUI(self) for device, widget in zip(self.devices, self.gui.device_widgets): @@ -539,7 +579,7 @@ def __init__(self): device.initialize() self.set_freerun(True) self.wait_until_done() # TODO:... - #time.sleep(3) # TOD: remove + # time.sleep(3) # TOD: remove # connect for device in self.devices: device.settings_updated.connect(self.on_device_settings_updated) @@ -550,14 +590,14 @@ def __init__(self): self.channel_names.append(channel_name) # finish self.settings_updated.emit() - + def acquire(self, save=False, index=None): # loop time now = time.time() loop_time.write(now - self.t_last) self.t_last = now # ms wait - time.sleep(ms_wait.read()/1000.) + time.sleep(ms_wait.read() / 1000.0) # acquire for device in self.devices: if device.active: @@ -567,10 +607,17 @@ def acquire(self, save=False, index=None): if save: # 1D things ------------------------------------------------------- data_rows = np.prod([d.data.size for d in self.devices if d.active]) - data_shape = (len(headers.data_cols['name']), data_rows) + data_shape = (len(headers.data_cols["name"]), data_rows) data_arr = np.full(data_shape, np.nan) - shots_rows = int(np.prod([d.nshots.read() if d.active and d.shots_compatible else 1 for d in self.devices])) - shots_shape = (len(headers.shots_cols['name']), shots_rows) + shots_rows = int( + np.prod( + [ + d.nshots.read() if d.active and d.shots_compatible else 1 + for d in self.devices + ] + ) + ) + shots_shape = (len(headers.shots_cols["name"]), shots_rows) shots_arr = np.full(shots_shape, np.nan) data_i = 0 shots_i = 0 @@ -635,11 +682,11 @@ def acquire(self, save=False, index=None): shots_arr[shots_i] = arr shots_i += 1 # send to file_address -------------------------------------------- - q('write_data', [data_arr, shots_arr]) + q("write_data", [data_arr, shots_arr]) # fill slice ------------------------------------------------------ - slice_axis_index = headers.data_cols['name'].index(current_slice.name) + slice_axis_index = headers.data_cols["name"].index(current_slice.name) slice_position = np.mean(data_arr[slice_axis_index]) - native_units = headers.data_cols['units'][slice_axis_index] + native_units = headers.data_cols["units"][slice_axis_index] slice_position = wt.units.converter(slice_position, native_units, current_slice.units) data_arrs = [] for device in self.devices: @@ -651,16 +698,16 @@ def initialize_scan(self, aqn, scan_folder, destinations_list): # stop freerunning self.set_freerun(False) # fill out pycmds_information in headers - headers.pycmds_info['PyCMDS version'] = g.version.read() - headers.pycmds_info['system name'] = g.system_name.read() - headers.pycmds_info['file created'] = timestamp.RFC3339 + headers.pycmds_info["PyCMDS version"] = g.version.read() + headers.pycmds_info["system name"] = g.system_name.read() + headers.pycmds_info["file created"] = timestamp.RFC3339 # apply device settings from aqn - ms_wait.write(aqn.read('device settings', 'ms wait')) + ms_wait.write(aqn.read("device settings", "ms wait")) for device in self.devices: if not aqn.has_section(device.name): device.active = False continue - if not aqn.read(device.name, 'use'): + if not aqn.read(device.name, "use"): device.active = False continue # apply settings from aqn to device @@ -670,17 +717,19 @@ def initialize_scan(self, aqn, scan_folder, destinations_list): if device.has_map: for key in device.map_axes.keys(): # add axis - headers.axis_info['axis names'].append(key) - identity, units, points, centers, interpolate = device.get_axis_properties(destinations_list) - headers.axis_info['axis identities'].append(identity) - headers.axis_info['axis units'].append(units) - headers.axis_info['axis interpolate'].append(interpolate) - headers.axis_info[' '.join([key, 'points'])] = points + headers.axis_info["axis names"].append(key) + identity, units, points, centers, interpolate = device.get_axis_properties( + destinations_list + ) + headers.axis_info["axis identities"].append(identity) + headers.axis_info["axis units"].append(units) + headers.axis_info["axis interpolate"].append(interpolate) + headers.axis_info[" ".join([key, "points"])] = points if centers is not None: - headers.axis_info[' '.join([key, 'centers'])] = centers + headers.axis_info[" ".join([key, "centers"])] = centers # expand exisiting axes (not current axis) for subkey in headers.axis_info.keys(): - if 'centers' in subkey and key not in subkey: + if "centers" in subkey and key not in subkey: centers = headers.axis_info[subkey] centers = np.expand_dims(centers, axis=-1) centers = np.repeat(centers, points.size, axis=-1) @@ -692,19 +741,19 @@ def initialize_scan(self, aqn, scan_folder, destinations_list): signed = [] for device in self.devices: signed += device.data.signed - headers.channel_info['channel signed'] = signed + headers.channel_info["channel signed"] = signed # add daq information to headers for device in self.devices: if device.active: for key, value in device.get_headers().items(): - headers.daq_info[' '.join([device.name, key])] = value - q('create_data', [aqn, scan_folder]) + headers.daq_info[" ".join([device.name, key])] = value + q("create_data", [aqn, scan_folder]) # refresh current slice properties current_slice.begin([len(device.data.cols) for device in self.devices]) # wait until daq is done before letting module continue self.wait_until_done() self.wait_until_file_done() - + def on_device_settings_updated(self): self.channel_names = [] for device in self.devices: @@ -723,47 +772,47 @@ def queue_control_update(self): def set_freerun(self, state): for device in self.devices: device.set_freerun(state) - + def shutdown(self): self.set_freerun(False) self.wait_until_done() for device in self.devices: device.close() - + def update_cols(self, aqn): - for cols_type in ['data', 'shots']: + for cols_type in ["data", "shots"]: kind = [] tolerance = [] units = [] label = [] name = [] # indicies - for n in headers.axis_info['axis names']: + for n in headers.axis_info["axis names"]: kind.append(None) tolerance.append(None) units.append(None) - label.append('') - name.append('_'.join([n, 'index'])) - if cols_type == 'shots': + label.append("") + name.append("_".join([n, "index"])) + if cols_type == "shots": # shot indicies for device in self.devices: if device.shots_compatible: kind.append(None) tolerance.append(None) units.append(None) - label.append('') - name.append('_'.join([device.name, 'shot', 'index'])) + label.append("") + name.append("_".join([device.name, "shot", "index"])) # time kind.append(None) tolerance.append(0.01) - units.append('s') - label.append('lab') - name.append('time') + units.append("s") + label.append("lab") + name.append("time") # scan hardware positions for scan_hardware_module in scan_hardware_modules: for scan_hardware in scan_hardware_module.hardwares: for key in scan_hardware.recorded: - kind.append('hardware') + kind.append("hardware") tolerance.append(scan_hardware.recorded[key][2]) units.append(scan_hardware.recorded[key][1]) label.append(scan_hardware.recorded[key][3]) @@ -772,11 +821,11 @@ def update_cols(self, aqn): for device in self.devices: if not aqn.has_section(device.name): continue - if not aqn.read(device.name, 'use'): + if not aqn.read(device.name, "use"): continue if device.has_map: for i in range(len(device.map_axes)): - kind.append('hardware') + kind.append("hardware") tolerance.append(None) vals = list(device.map_axes.values()) units.append(vals[i][1]) @@ -787,43 +836,43 @@ def update_cols(self, aqn): for device in self.devices: if not aqn.has_section(device.name): continue - if not aqn.read(device.name, 'use'): + if not aqn.read(device.name, "use"): continue - if device.shots_compatible and cols_type == 'shots': + if device.shots_compatible and cols_type == "shots": mutex = device.shots else: mutex = device.data for col in mutex.cols: - kind.append('channel') + kind.append("channel") tolerance.append(None) - units.append('') # TODO: better units support? - label.append('') # TODO: ? + units.append("") # TODO: better units support? + label.append("") # TODO: ? name.append(col) self.channel_names.append(col) # clean up for i, s in enumerate(label): - label[i] = s.replace('prime', r'\'') + label[i] = s.replace("prime", r"\'") # finish - if cols_type == 'data': + if cols_type == "data": cols = headers.data_cols - elif cols_type == 'shots': + elif cols_type == "shots": cols = headers.shots_cols - cols['kind'] = kind - cols['tolerance'] = tolerance - cols['label'] = label - cols['units'] = units - cols['name'] = name - self.on_device_settings_updated() - + cols["kind"] = kind + cols["tolerance"] = tolerance + cols["label"] = label + cols["units"] = units + cols["name"] = name + self.on_device_settings_updated() + def wait_until_file_done(self): while data_busy.read(): data_busy.wait_for_update() - + def wait_until_done(self): - ''' + """ Wait until the acquisition devices are no longer busy. Does not wait for the file writing queue to empty. - ''' + """ for device in self.devices: if device.active: device.wait_until_still() @@ -833,23 +882,21 @@ def wait_until_done(self): class DeviceWidget(QtWidgets.QWidget): - def __init__(self): QtWidgets.QWidget.__init__(self) - + def load(self, aqn_path): # TODO: pass - + def save(self, aqn_path): # TODO: ini = wt.kit.INI(aqn_path) - ini.add_section('Virtual') - ini.write('Virtual', 'use', True) + ini.add_section("Virtual") + ini.write("Virtual", "use", True) class Widget(QtWidgets.QWidget): - def __init__(self): QtWidgets.QWidget.__init__(self) layout = QtWidgets.QVBoxLayout() @@ -857,10 +904,11 @@ def __init__(self): layout.setMargin(0) # daq settings input_table = pw.InputTable() - input_table.add('Device Settings', None) - self.ms_wait = pc.Number(initial_value=0, limits=ms_wait_limits, - decimals=0, disable_under_queue_control=True) - input_table.add('ms Wait', self.ms_wait) + input_table.add("Device Settings", None) + self.ms_wait = pc.Number( + initial_value=0, limits=ms_wait_limits, decimals=0, disable_under_queue_control=True + ) + input_table.add("ms Wait", self.ms_wait) layout.addWidget(input_table) # device settings self.device_widgets = [] @@ -871,51 +919,50 @@ def __init__(self): def load(self, aqn_path): ini = wt.kit.INI(aqn_path) - self.ms_wait.write(ini.read('device settings', 'ms wait')) + self.ms_wait.write(ini.read("device settings", "ms wait")) for device_widget in self.device_widgets: device_widget.load(aqn_path) - def save(self, aqn_path): ini = wt.kit.INI(aqn_path) - ini.add_section('device settings') - ini.write('device settings', 'ms wait', self.ms_wait.read()) + ini.add_section("device settings") + ini.write("device settings", "ms wait", self.ms_wait.read()) for device_widget in self.device_widgets: device_widget.save(aqn_path) - - + + class DisplaySettings(QtCore.QObject): updated = QtCore.Signal() - + def __init__(self, device): - ''' + """ Display settings for a particular device. - ''' + """ QtCore.QObject.__init__(self) self.device = device - #self.device.wait_until_done() + # self.device.wait_until_done() self.widget = pw.InputTable() self.channel_combo = pc.Combo() self.channel_combo.updated.connect(lambda: self.updated.emit()) - self.widget.add('Channel', self.channel_combo) + self.widget.add("Channel", self.channel_combo) self.shape_controls = [] if self.device.shape != (1,): map_axis_names = list(self.device.map_axes.keys()) for i in range(len(self.device.shape)): - limits = pc.NumberLimits(0, self.device.shape[i]-1) + limits = pc.NumberLimits(0, self.device.shape[i] - 1) control = pc.Number(initial_value=0, decimals=0, limits=limits) - self.widget.add(' '.join([map_axis_names[i], 'index']), control) + self.widget.add(" ".join([map_axis_names[i], "index"]), control) self.shape_controls.append(control) control.updated.connect(lambda: self.updated.emit()) - + def get_channel_index(self): return self.channel_combo.read_index() - + def get_map_index(self): if len(self.shape_controls) == 0: return None return tuple(c.read() for c in self.shape_controls) - + def hide(self): self.widget.hide() @@ -929,7 +976,6 @@ def update_channels(self): class GUI(QtCore.QObject): - def __init__(self, control): QtCore.QObject.__init__(self) self.control = control @@ -957,7 +1003,7 @@ def create_frame(self): device.give_widget(widget) # finish layout.addWidget(self.tabs) - + def create_main_tab(self): if self.main_tab_created: return @@ -994,7 +1040,7 @@ def create_main_tab(self): self.plot_line = self.plot_widget.add_line() display_layout.addWidget(self.plot_widget) # vertical line ------------------------------------------------------- - line = pw.line('V') + line = pw.line("V") layout.addWidget(line) # settings ------------------------------------------------------------ # container widget / scroll area @@ -1009,11 +1055,11 @@ def create_main_tab(self): layout.addWidget(settings_scroll_area) # display settings input_table = pw.InputTable() - input_table.add('Display', None) + input_table.add("Display", None) allowed_values = [device.name for device in self.control.devices] self.device_combo = pc.Combo(allowed_values=allowed_values) self.device_combo.updated.connect(self.on_update_device) - input_table.add('Device', self.device_combo) + input_table.add("Device", self.device_combo) settings_layout.addWidget(input_table) self.display_settings_widgets = collections.OrderedDict() for device in self.control.devices: @@ -1024,20 +1070,20 @@ def create_main_tab(self): display_settings.updated.connect(self.on_update_device) # global daq settings input_table = pw.InputTable() - input_table.add('Settings', None) - input_table.add('ms Wait', ms_wait) + input_table.add("Settings", None) + input_table.add("ms Wait", ms_wait) for device in self.control.devices: input_table.add(device.name, None) - input_table.add('Status', device.busy) - input_table.add('Freerun', device.freerun) - input_table.add('Time', device.measure_time) - input_table.add('File', None) - data_busy.update_signal = data_obj.update_ui - input_table.add('Status', data_busy) - input_table.add('Scan', None) - input_table.add('Loop Time', loop_time) - self.idx_string = pc.String(initial_value='None', display=True) - input_table.add('Scan Index', self.idx_string) + input_table.add("Status", device.busy) + input_table.add("Freerun", device.freerun) + input_table.add("Time", device.measure_time) + input_table.add("File", None) + data_busy.update_signal = data_obj.update_ui + input_table.add("Status", data_busy) + input_table.add("Scan", None) + input_table.add("Loop Time", loop_time) + self.idx_string = pc.String(initial_value="None", display=True) + input_table.add("Scan Index", self.idx_string) settings_layout.addWidget(input_table) # stretch settings_layout.addStretch(1) @@ -1064,9 +1110,9 @@ def on_slice_append(self): # finish self.plot_scatter.setData(xi, yi) self.plot_line.setData(xi, yi) - + def on_slice_index(self): - xlabel = '{0} ({1})'.format(current_slice.name, current_slice.units) + xlabel = "{0} ({1})".format(current_slice.name, current_slice.units) self.plot_widget.set_labels(xlabel=xlabel) xmin = min(current_slice.points) xmax = max(current_slice.points) @@ -1075,23 +1121,23 @@ def on_slice_index(self): def on_update_channels(self): for display_settings in self.display_settings_widgets.values(): display_settings.update_channels() - + def on_update_device(self): current_device_index = self.device_combo.read_index() for display_settings in self.display_settings_widgets.values(): display_settings.hide() list(self.display_settings_widgets.values())[current_device_index].show() self.update() - + def update(self): - ''' + """ Runs each time an update_ui signal fires (basically every run_task) - ''' + """ # scan index self.idx_string.write(str(idx.read())) # big number current_device_index = self.device_combo.read_index() - device = self.control.devices[current_device_index] + device = self.control.devices[current_device_index] widget = list(self.display_settings_widgets.values())[current_device_index] channel_index = widget.get_channel_index() map_index = widget.get_map_index() @@ -1100,8 +1146,8 @@ def update(self): else: big_number = device.data.read()[channel_index][map_index] if len(self.control.channel_names) > channel_index: - self.big_channel.setText(self.control.channel_names[channel_index]) - self.big_display.setValue(big_number) + self.big_channel.setText(self.control.channel_names[channel_index]) + self.big_display.setValue(big_number) def stop(self): pass @@ -1116,4 +1162,5 @@ def stop(self): import hardware.spectrometers.spectrometers as spectrometers import hardware.delays.delays as delays import hardware.filters.filters as filters + scan_hardware_modules = [opas, spectrometers, delays, filters] diff --git a/hardware/delays/Aerotech/Aerotech.py b/hardware/delays/Aerotech/Aerotech.py index 97034f36..fd37b6fc 100644 --- a/hardware/delays/Aerotech/Aerotech.py +++ b/hardware/delays/Aerotech/Aerotech.py @@ -19,27 +19,26 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): BaseDriver.__init__(self, *args, **kwargs) - self.com_channel = kwargs.pop('port') - kwargs['native_units'] = 'ps' - self.index = kwargs.pop('index') + self.com_channel = kwargs.pop("port") + kwargs["native_units"] = "ps" + self.index = kwargs.pop("index") self.native_per_mm = 6.671281903963041 def close(self): - self.port.write('S') + self.port.write("S") self.port.close() def get_motor_position(self): # I am trying to prevent some timing condition that I don't understand fully # ---Blaise 2017-08-13 try: - p = float(self.port.write('G', then_read=True)) + p = float(self.port.write("G", then_read=True)) self.motor_position.write(p) - return(p) + return p except BaseException as error: - print('AEROTECH GET MOTOR POSITION EXCEPT', error) + print("AEROTECH GET MOTOR POSITION EXCEPT", error) time.sleep(1) self.port.instrument.reset_input_buffer() self.port.instrument.reset_output_buffer() @@ -53,17 +52,17 @@ def get_position(self): self.position.write(delay, self.native_units) # return return delay - + def home(self): - self.port.write('H') + self.port.write("H") while self.is_busy(): self.get_position() time.sleep(1) self.set_position(self.hardware.destination.read()) def initialize(self): - self.port = com_handler.get_com(self.com_channel) - self.motor_limits.write(0, 250, 'mm') + self.port = com_handler.get_com(self.com_channel) + self.motor_limits.write(0, 250, "mm") self.update_recorded() self.set_zero(self.zero_position.read()) self.get_position() @@ -73,32 +72,34 @@ def initialize(self): def is_busy(self): if self.port.is_open(): self.port.flush() - status = self.port.write('Q', then_read=True) - if status == 'B': + status = self.port.write("Q", then_read=True) + if status == "B": return True - elif status == 'R': + elif status == "R": return False else: return False def set_position(self, destination): - destination_mm = self.zero_position.read() + destination/(self.native_per_mm * self.factor.read()) + destination_mm = self.zero_position.read() + destination / ( + self.native_per_mm * self.factor.read() + ) self.set_motor_position(destination_mm) def set_motor_position(self, motor_position): - command = 'M %f'%motor_position + command = "M %f" % motor_position self.port.write(command) while self.is_busy(): self.get_position() time.sleep(0.1) self.get_position() BaseDriver.set_motor_position(self, motor_position) - + def set_zero(self, zero): self.zero_position.write(zero) min_value = -self.zero_position.read() * self.native_per_mm * self.factor.read() - max_value = (250. - self.zero_position.read()) * self.native_per_mm * self.factor.read() - self.limits.write(min_value, max_value, 'ps') + max_value = (250.0 - self.zero_position.read()) * self.native_per_mm * self.factor.read() + self.limits.write(min_value, max_value, "ps") ### gui ####################################################################### diff --git a/hardware/delays/LTS300/LTS300.py b/hardware/delays/LTS300/LTS300.py index 46f4c202..7329951b 100644 --- a/hardware/delays/LTS300/LTS300.py +++ b/hardware/delays/LTS300/LTS300.py @@ -20,11 +20,10 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): BaseDriver.__init__(self, *args, **kwargs) - kwargs['native_units'] = 'ps' - self.index = kwargs.pop('index') + kwargs["native_units"] = "ps" + self.index = kwargs.pop("index") self.native_per_mm = 6.671281903963041 def close(self): @@ -49,7 +48,9 @@ def home(self): def initialize(self): self.motor = APTMotor(serial_number=int(self.serial), hardware_type=42) - self.motor_limits.write(self.motor.minimum_position, self.motor.maximum_position, self.motor_units) + self.motor_limits.write( + self.motor.minimum_position, self.motor.maximum_position, self.motor_units + ) self.update_recorded() self.set_zero(self.zero_position.read()) self.get_position() @@ -57,10 +58,12 @@ def initialize(self): self.initialized_signal.emit() def is_busy(self): - return not 'stopped' in self.motor.status + return not "stopped" in self.motor.status def set_position(self, destination): - destination_mm = self.zero_position.read() + destination/(self.native_per_mm * self.factor.read()) + destination_mm = self.zero_position.read() + destination / ( + self.native_per_mm * self.factor.read() + ) self.set_motor_position(destination_mm) def set_motor_position(self, motor_position): @@ -79,7 +82,7 @@ def set_motor_position(self, motor_position): def set_zero(self, zero): self.zero_position.write(zero) min_value = -self.zero_position.read() * self.native_per_mm * self.factor.read() - max_value = (300. - self.zero_position.read()) * self.native_per_mm * self.factor.read() + max_value = (300.0 - self.zero_position.read()) * self.native_per_mm * self.factor.read() self.limits.write(min_value, max_value, self.native_units) diff --git a/hardware/delays/LTS300/__init__.py b/hardware/delays/LTS300/__init__.py index 8e47394c..37a1f943 100644 --- a/hardware/delays/LTS300/__init__.py +++ b/hardware/delays/LTS300/__init__.py @@ -1,2 +1,3 @@ import LTS300 -control = LTS300.control \ No newline at end of file + +control = LTS300.control diff --git a/hardware/delays/MFA/MFA.py b/hardware/delays/MFA/MFA.py index f8fce9f4..78d7ba45 100644 --- a/hardware/delays/MFA/MFA.py +++ b/hardware/delays/MFA/MFA.py @@ -17,58 +17,60 @@ main_dir = g.main_dir.read() -ini = Ini(os.path.join(main_dir, 'hardware', 'delays', - 'MFA', - 'MFA.ini')) +ini = Ini(os.path.join(main_dir, "hardware", "delays", "MFA", "MFA.ini")) ### define #################################################################### -error_dict = {'0': None, - '@': None, - 'A': 'Unknown message code or floating point controller address [A]', - 'B': 'Controller address not correct [B]', - 'C': 'Parameter missing or out of range [C]', - 'D': 'Command not allowed [D]', - 'E': 'Home sequence already started [E]', - 'F': 'ESP stage name unknown [F]', - 'G': 'Displacement out of limits [G]', - 'H': 'Command not allowed in NOT REFERENCED state [H]', - 'I': 'Command not allowed in CONFIGURATION state [I]', - 'J': 'Command not allowed in DISABLE state [J]', - 'K': 'Command not allowed in READY state [K]', - 'L': 'Command not allowed in HOMING state [L]', - 'M': 'Command not allowed in MOVING state [M]', - 'N': 'Current position out of software limit [N]', - 'S': 'Communication time-out [S]', - 'U': 'Error during EEPROM access [U]', - 'V': 'Error during command execution [V]', - 'W': 'Command not allowed for PP version [W]', - 'X': 'Command not allowed for CC version [X]'} - -controller_states = {'0A': 'NOT REFERENCED from reset', - '0B': 'NOT REFERENCED from HOMING', - '0C': 'NOT REFERENCED from CONFIGURATION', - '0D': 'NON REFERENCED from DISABLE', - 'OE': 'NOT REFERENCED from READY', - 'OF': 'NOT REFERENCED from MOVING', - '10': 'NOT REFERENCED ESP stage error', - '11': 'NOT REFERENCED from JOGGING', - '14': 'CONFIGURATION', - '1E': 'HOMING command from RS-232-C', - '1F': 'HOMING command by SMC-RC', - '28': 'MOVING', - '32': 'READY from HOMING', - '33': 'READY from MOVING', - '34': 'READY from DISABLE', - '35': 'READY from JOGGING', - '3C': 'DISABLE from READY', - '3D': 'DISABLE from MOVING', - '3E': 'DISABLE from JOGGING', - '46': 'JOGGING from READY', - '47': 'JOGGING from DISABLE'} - +error_dict = { + "0": None, + "@": None, + "A": "Unknown message code or floating point controller address [A]", + "B": "Controller address not correct [B]", + "C": "Parameter missing or out of range [C]", + "D": "Command not allowed [D]", + "E": "Home sequence already started [E]", + "F": "ESP stage name unknown [F]", + "G": "Displacement out of limits [G]", + "H": "Command not allowed in NOT REFERENCED state [H]", + "I": "Command not allowed in CONFIGURATION state [I]", + "J": "Command not allowed in DISABLE state [J]", + "K": "Command not allowed in READY state [K]", + "L": "Command not allowed in HOMING state [L]", + "M": "Command not allowed in MOVING state [M]", + "N": "Current position out of software limit [N]", + "S": "Communication time-out [S]", + "U": "Error during EEPROM access [U]", + "V": "Error during command execution [V]", + "W": "Command not allowed for PP version [W]", + "X": "Command not allowed for CC version [X]", +} + +controller_states = { + "0A": "NOT REFERENCED from reset", + "0B": "NOT REFERENCED from HOMING", + "0C": "NOT REFERENCED from CONFIGURATION", + "0D": "NON REFERENCED from DISABLE", + "OE": "NOT REFERENCED from READY", + "OF": "NOT REFERENCED from MOVING", + "10": "NOT REFERENCED ESP stage error", + "11": "NOT REFERENCED from JOGGING", + "14": "CONFIGURATION", + "1E": "HOMING command from RS-232-C", + "1F": "HOMING command by SMC-RC", + "28": "MOVING", + "32": "READY from HOMING", + "33": "READY from MOVING", + "34": "READY from DISABLE", + "35": "READY from JOGGING", + "3C": "DISABLE from READY", + "3D": "DISABLE from MOVING", + "3E": "DISABLE from JOGGING", + "46": "JOGGING from READY", + "47": "JOGGING from DISABLE", +} + status_dict = {value: key for key, value in controller_states.items()} @@ -76,31 +78,30 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): super(self.__class__, self).__init__(*args, **kwargs) - self.index = kwargs.pop('index') - self.com_channel = kwargs.pop('port') + self.index = kwargs.pop("index") + self.com_channel = kwargs.pop("port") self.native_per_mm = 6671.281903963041 - self.axis = kwargs.pop('axis') + self.axis = kwargs.pop("axis") self.status = pc.String(display=True) - self.motor_limits = pc.NumberLimits(0, 25, 'mm') + self.motor_limits = pc.NumberLimits(0, 25, "mm") self.motor_position.decimals = 5 self.zero_position.decimals = 5 - + def _tell_status(self): # read - status = self.port.write(str(self.axis)+'TS', then_read=True) + status = self.port.write(str(self.axis) + "TS", then_read=True) # process out = {} try: - status = str(status).split('TS')[1] - out['error'] = status[:4] - out['state'] = status[4:6] - self.status.write(controller_states[out['state']].split('from')[0]) + status = str(status).split("TS")[1] + out["error"] = status[:4] + out["state"] = status[4:6] + self.status.write(controller_states[out["state"]].split("from")[0]) except: - out['error'] = None - out['state'] = None + out["error"] = None + out["state"] = None return out def close(self): @@ -113,33 +114,35 @@ def get_position(self): # The root cause is as yet unknown, but the strategy to mitigate is to simply # retry the request until the expected response is recieved. # Thus far, it has worked. - while(True): + while True: try: - position = self.port.write(str(self.axis)+'TP', then_read=True) + position = self.port.write(str(self.axis) + "TP", then_read=True) # proccess (mm) - position = float(str(position).split('TP')[1]) + position = float(str(position).split("TP")[1]) except IndexError: - warnings.warn("Unexpected reply from MFA: expected '#TP##', got '{}'".format(position)) + warnings.warn( + "Unexpected reply from MFA: expected '#TP##', got '{}'".format(position) + ) else: break - self.motor_position.write(position, 'mm') + self.motor_position.write(position, "mm") # calculate delay (fs) delay = (position - self.zero_position.read()) * self.native_per_mm * self.factor.read() - self.position.write(delay, 'fs') + self.position.write(delay, "fs") # return return delay - + def home(self, inputs=[]): - self.port.write(str(self.axis)+'RS') # reset + self.port.write(str(self.axis) + "RS") # reset time.sleep(5) - self.port.write(str(self.axis)+'OR') # execute home search - while not self._tell_status()['state'] == status_dict['READY from HOMING']: + self.port.write(str(self.axis) + "OR") # execute home search + while not self._tell_status()["state"] == status_dict["READY from HOMING"]: time.sleep(0.1) time.sleep(5) self.set_position(self.hardware.destination.read()) def initialize(self): - self.port = com_handler.get_com(self.com_channel) + self.port = com_handler.get_com(self.com_channel) self.set_zero(self.zero_position.read()) self.label.updated.connect(self.update_recorded) self.update_recorded() @@ -147,7 +150,7 @@ def initialize(self): self._tell_status() self.initialized.write(True) self.initialized_signal.emit() - + def on_factor_updated(self): if self.factor.read() == 0: self.factor.write(1) @@ -155,41 +158,40 @@ def on_factor_updated(self): self.factor.save() # update limits min_value = -self.zero_position.read() * self.native_per_mm * self.factor.read() - max_value = (25. - self.zero_position.read()) * self.native_per_mm * self.factor.read() - self.limits.write(min_value, max_value, 'fs') - + max_value = (25.0 - self.zero_position.read()) * self.native_per_mm * self.factor.read() + self.limits.write(min_value, max_value, "fs") + def set_position(self, destination): # get destination_mm - destination_mm = self.zero_position.read() + destination/(self.native_per_mm * self.factor.read()) + destination_mm = self.zero_position.read() + destination / ( + self.native_per_mm * self.factor.read() + ) self.set_motor_position(destination_mm) - + def set_motor_position(self, motor_position): """ motor_position in mm """ # move hardware - # TODO: consider backlash correction? - self.port.write(str(self.axis)+'PA'+str(motor_position)) - while not self._tell_status()['state'] == status_dict['READY from MOVING']: + # TODO: consider backlash correction? + self.port.write(str(self.axis) + "PA" + str(motor_position)) + while not self._tell_status()["state"] == status_dict["READY from MOVING"]: time.sleep(0.01) self.get_position() # get final position self.get_position() - + def set_zero(self, zero): self.zero_position.write(zero) min_value = -self.zero_position.read() * self.native_per_mm * self.factor.read() - max_value = (25. - self.zero_position.read()) * self.native_per_mm * self.factor.read() - self.limits.write(min_value, max_value, 'fs') - - + max_value = (25.0 - self.zero_position.read()) * self.native_per_mm * self.factor.read() + self.limits.write(min_value, max_value, "fs") ### gui ####################################################################### class GUI(BaseGUI): - def initialize(self): - self.attributes_table.add('Status', self.hardware.driver.status) + self.attributes_table.add("Status", self.hardware.driver.status) BaseGUI.initialize(self) diff --git a/hardware/delays/PMC/PMC.py b/hardware/delays/PMC/PMC.py index 41deba82..a2e607d6 100644 --- a/hardware/delays/PMC/PMC.py +++ b/hardware/delays/PMC/PMC.py @@ -5,7 +5,8 @@ import project.project_globals as g from hardware.delays.delays import Driver as BaseDriver from hardware.delays.delays import GUI as BaseGUI -#import library.precision_micro_motors.precision_motors as motors + +# import library.precision_micro_motors.precision_motors as motors import yaqc @@ -19,10 +20,9 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): BaseDriver.__init__(self, *args, **kwargs) - self.index = kwargs['index'] + self.index = kwargs["index"] self.yaqd_port = kwargs["yaqd_port"] self.native_per_mm = 6.671281903963041 @@ -31,14 +31,14 @@ def close(self): def get_position(self): position = self.motor.get_position() - self.motor_position.write(position, 'mm') + self.motor_position.write(position, "mm") delay = (position - self.zero_position.read()) * self.native_per_mm * self.factor.read() - self.position.write(delay, 'ps') + self.position.write(delay, "ps") return delay def initialize(self): self.motor = yaqc.Client(self.yaqd_port) - self.current_position_mm = pc.Number(units='mm', display=True, decimals=5) + self.current_position_mm = pc.Number(units="mm", display=True, decimals=5) # finish self.get_position() self.initialized.write(True) @@ -48,9 +48,11 @@ def is_busy(self): return self.motor.busy() def set_position(self, destination): - destination_mm = self.zero_position.read() + destination/(self.native_per_mm * self.factor.read()) + destination_mm = self.zero_position.read() + destination / ( + self.native_per_mm * self.factor.read() + ) self.set_motor_position(destination_mm) - + def set_motor_position(self, destination): self.motor.set_position(destination) time.sleep(0.01) @@ -61,8 +63,8 @@ def set_motor_position(self, destination): def set_zero(self, zero): self.zero_position.write(zero) min_value = -self.zero_position.read() * self.native_per_mm * self.factor.read() - max_value = (50. - self.zero_position.read()) * self.native_per_mm * self.factor.read() - self.limits.write(min_value, max_value, 'ps') + max_value = (50.0 - self.zero_position.read()) * self.native_per_mm * self.factor.read() + self.limits.write(min_value, max_value, "ps") self.get_position() diff --git a/hardware/delays/delays.py b/hardware/delays/delays.py index 75c7d875..20b8b74b 100644 --- a/hardware/delays/delays.py +++ b/hardware/delays/delays.py @@ -18,97 +18,120 @@ app = g.app.read() directory = os.path.dirname(os.path.abspath(__file__)) -ini = wt.kit.INI(os.path.join(directory, 'delays.ini')) +ini = wt.kit.INI(os.path.join(directory, "delays.ini")) # --- driver -------------------------------------------------------------------------------------- class Driver(hw.Driver): - def __init__(self, *args, **kwargs): self.hardware_ini = ini - self.motor_units = kwargs.pop('motor_units') + self.motor_units = kwargs.pop("motor_units") hw.Driver.__init__(self, *args, **kwargs) self.factor = self.hardware.factor - self.factor.write(kwargs['factor']) + self.factor.write(kwargs["factor"]) self.motor_limits = self.hardware.motor_limits self.motor_position = self.hardware.motor_position self.zero_position = self.hardware.zero_position - self.zero_position.write(kwargs['zero_position']) - self.recorded['_'.join([self.name, 'zero'])] = [self.zero_position, 'mm', 0.001, self.name[-1], True] + self.zero_position.write(kwargs["zero_position"]) + self.recorded["_".join([self.name, "zero"])] = [ + self.zero_position, + "mm", + 0.001, + self.name[-1], + True, + ] self.native_per_mm = 1 - + def save_status(self): - self.hardware_ini.write(self.name, 'zero_position', self.zero_position.read(self.motor_units)) - self.hardware_ini.write(self.name, 'factor', int(self.factor.read())) - hw.Driver.save_status(self) - + self.hardware_ini.write( + self.name, "zero_position", self.zero_position.read(self.motor_units) + ) + self.hardware_ini.write(self.name, "factor", int(self.factor.read())) + hw.Driver.save_status(self) + def set_motor_position(self, motor_position): self.motor_position.write(motor_position) def set_offset(self, offset): # update zero offset_from_here = offset - self.offset.read(self.native_units) - offset_mm = offset_from_here/(self.native_per_mm*self.factor.read()) - new_zero = self.zero_position.read('mm') + offset_mm + offset_mm = offset_from_here / (self.native_per_mm * self.factor.read()) + new_zero = self.zero_position.read("mm") + offset_mm self.set_zero(new_zero) self.offset.write(offset, self.native_units) # return to old position destination = self.hardware.destination.read(self.native_units) self.set_position(destination) - + def update_recorded(self): self.recorded.clear() - self.recorded['d' + str(self.index)] = [self.position, self.native_units, 1., self.label.read(), False] - self.recorded['d' + str(self.index) + '_position'] = [self.motor_position, 'mm', 1., self.label.read(), False] - self.recorded['d' + str(self.index) + '_zero'] = [self.zero_position, 'mm', 1., self.label.read(), False] + self.recorded["d" + str(self.index)] = [ + self.position, + self.native_units, + 1.0, + self.label.read(), + False, + ] + self.recorded["d" + str(self.index) + "_position"] = [ + self.motor_position, + "mm", + 1.0, + self.label.read(), + False, + ] + self.recorded["d" + str(self.index) + "_zero"] = [ + self.zero_position, + "mm", + 1.0, + self.label.read(), + False, + ] def set_zero(self, new_zero): pass - # --- gui ----------------------------------------------------------------------------------------- class GUI(hw.GUI): - def initialize(self): self.layout.addWidget(self.scroll_area) # attributes - self.attributes_table.add('Label', self.hardware.label) - self.attributes_table.add('Factor', self.hardware.factor) + self.attributes_table.add("Label", self.hardware.label) + self.attributes_table.add("Factor", self.hardware.factor) self.scroll_layout.addWidget(self.attributes_table) # mm input table input_table = pw.InputTable() - input_table.add('Motor Position', None) - input_table.add('Current', self.hardware.motor_position) + input_table.add("Motor Position", None) + input_table.add("Current", self.hardware.motor_position) self.motor_destination = self.hardware.motor_position.associate(display=False) - input_table.add('Destination', self.motor_destination) + input_table.add("Destination", self.motor_destination) self.scroll_layout.addWidget(input_table) # set mm button - self.set_motor_button = pw.SetButton('SET POSITION') + self.set_motor_button = pw.SetButton("SET POSITION") self.scroll_layout.addWidget(self.set_motor_button) self.set_motor_button.clicked.connect(self.on_set_motor) g.queue_control.disable_when_true(self.set_motor_button) # zero input table input_table = pw.InputTable() - input_table.add('Zero Position', None) - input_table.add('Current', self.hardware.zero_position) + input_table.add("Zero Position", None) + input_table.add("Current", self.hardware.zero_position) self.zero_destination = self.hardware.zero_position.associate(display=False) - input_table.add('Destination', self.zero_destination) + input_table.add("Destination", self.zero_destination) self.scroll_layout.addWidget(input_table) # set zero button - self.set_zero_button = pw.SetButton('SET ZERO') + self.set_zero_button = pw.SetButton("SET ZERO") self.scroll_layout.addWidget(self.set_zero_button) self.set_zero_button.clicked.connect(self.on_set_zero) g.queue_control.disable_when_true(self.set_zero_button) # horizontal line - self.scroll_layout.addWidget(pw.line('H')) + self.scroll_layout.addWidget(pw.line("H")) # home button input_table = pw.InputTable() - self.home_button = pw.SetButton('HOME', 'advanced') + self.home_button = pw.SetButton("HOME", "advanced") self.scroll_layout.addWidget(self.home_button) self.home_button.clicked.connect(self.on_home) g.queue_control.disable_when_true(self.home_button) @@ -116,16 +139,16 @@ def initialize(self): self.scroll_layout.addStretch(1) self.layout.addStretch(1) self.hardware.update_ui.connect(self.update) - + def on_home(self): - self.driver.hardware.q.push('home') - + self.driver.hardware.q.push("home") + def on_set_motor(self): - new_mm = self.motor_destination.read('mm') - self.hardware.set_motor_position(new_mm, units='mm') + new_mm = self.motor_destination.read("mm") + self.hardware.set_motor_position(new_mm, units="mm") def on_set_zero(self): - new_zero = self.zero_destination.read('mm') + new_zero = self.zero_destination.read("mm") self.driver.set_zero(new_zero) self.driver.offset.write(0) name = self.hardware.name @@ -141,23 +164,24 @@ def update(self): class Hardware(hw.Hardware): - def __init__(self, *arks, **kwargs): - self.kind = 'delay' + self.kind = "delay" self.factor = pc.Number(1, decimals=0) - self.motor_limits = pc.NumberLimits(min_value=0, max_value=50, units='mm') - self.motor_position = pc.Number(units='mm', display=True, limits=self.motor_limits) + self.motor_limits = pc.NumberLimits(min_value=0, max_value=50, units="mm") + self.motor_position = pc.Number(units="mm", display=True, limits=self.motor_limits) self.zero_position = pc.Number(display=True) hw.Hardware.__init__(self, *arks, **kwargs) self.label = pc.String(self.name, display=True) - - def set_motor_position(self, motor_position, units='mm'): + + def set_motor_position(self, motor_position, units="mm"): # TODO: should probably support 'motor native units' - self.q.push('set_motor_position', motor_position) + self.q.push("set_motor_position", motor_position) # --- import -------------------------------------------------------------------------------------- -ini_path = os.path.join(directory, 'delays.ini') -hardwares, gui, advanced_gui = hw.import_hardwares(ini_path, name='Delays', Driver=Driver, GUI=GUI, Hardware=Hardware) +ini_path = os.path.join(directory, "delays.ini") +hardwares, gui, advanced_gui = hw.import_hardwares( + ini_path, name="Delays", Driver=Driver, GUI=GUI, Hardware=Hardware +) diff --git a/hardware/delays/test.py b/hardware/delays/test.py index 097aeb91..40f07d22 100644 --- a/hardware/delays/test.py +++ b/hardware/delays/test.py @@ -1,3 +1,4 @@ from LTS300 import control + control.move_absolute(10) -control.move_absolute(30) \ No newline at end of file +control.move_absolute(30) diff --git a/hardware/filters/filters.py b/hardware/filters/filters.py index 162e5633..0a4ebb4a 100644 --- a/hardware/filters/filters.py +++ b/hardware/filters/filters.py @@ -18,34 +18,37 @@ app = g.app.read() directory = os.path.dirname(os.path.abspath(__file__)) -ini = wt.kit.INI(os.path.join(directory, 'filters.ini')) +ini = wt.kit.INI(os.path.join(directory, "filters.ini")) # --- driver -------------------------------------------------------------------------------------- class Driver(hw.Driver): - def __init__(self, *args, **kwargs): self.hardware_ini = ini - self.motor_units = kwargs.pop('motor_units') + self.motor_units = kwargs.pop("motor_units") hw.Driver.__init__(self, *args, **kwargs) self.factor = self.hardware.factor - self.factor.write(kwargs['factor']) + self.factor.write(kwargs["factor"]) self.motor_limits = self.hardware.motor_limits self.motor_position = self.hardware.motor_position - self.motor_position.write(kwargs['motor_position']) + self.motor_position.write(kwargs["motor_position"]) self.zero_position = self.hardware.zero_position - self.zero_position.write(kwargs['zero_position']) + self.zero_position.write(kwargs["zero_position"]) self.update_recorded() self.native_per_deg = 1 - + def save_status(self): - self.hardware_ini.write(self.name, 'zero_position', self.zero_position.read(self.motor_units)) - self.hardware_ini.write(self.name, 'factor', int(self.factor.read())) - self.hardware_ini.write(self.name, 'motor_position', self.motor_position.read(self.motor_units)) - hw.Driver.save_status(self) - + self.hardware_ini.write( + self.name, "zero_position", self.zero_position.read(self.motor_units) + ) + self.hardware_ini.write(self.name, "factor", int(self.factor.read())) + self.hardware_ini.write( + self.name, "motor_position", self.motor_position.read(self.motor_units) + ) + hw.Driver.save_status(self) + def set_motor_position(self, motor_position): self.motor_position.write(motor_position) self.save_status() @@ -53,65 +56,82 @@ def set_motor_position(self, motor_position): def set_offset(self, offset): # update zero offset_from_here = offset - self.offset.read(self.native_units) - offset_deg = offset_from_here/(self.native_per_deg * self.factor.read()) - new_zero = self.zero_position.read('deg') + offset_deg + offset_deg = offset_from_here / (self.native_per_deg * self.factor.read()) + new_zero = self.zero_position.read("deg") + offset_deg self.set_zero(new_zero) self.offset.write(offset, self.native_units) # return to old position destination = self.hardware.destination.read(self.native_units) self.set_position(destination) - + def set_zero(self, zero): self.zero_position.write(zero) self.save_status() def update_recorded(self): self.recorded.clear() - self.recorded[self.name] = [self.position, self.native_units, 1., self.label.read(), False] - self.recorded[self.name + '_position'] = [self.motor_position, 'deg', 1., self.label.read(), False] - self.recorded[self.name + '_zero'] = [self.zero_position, 'deg', 1., self.label.read(), False] + self.recorded[self.name] = [ + self.position, + self.native_units, + 1.0, + self.label.read(), + False, + ] + self.recorded[self.name + "_position"] = [ + self.motor_position, + "deg", + 1.0, + self.label.read(), + False, + ] + self.recorded[self.name + "_zero"] = [ + self.zero_position, + "deg", + 1.0, + self.label.read(), + False, + ] # --- gui ----------------------------------------------------------------------------------------- class GUI(hw.GUI): - def initialize(self): self.layout.addWidget(self.scroll_area) # attributes - self.attributes_table.add('Label', self.hardware.label) - self.attributes_table.add('Factor', self.hardware.factor) + self.attributes_table.add("Label", self.hardware.label) + self.attributes_table.add("Factor", self.hardware.factor) self.scroll_layout.addWidget(self.attributes_table) # mm input table input_table = pw.InputTable() - input_table.add('Motor Position', None) - input_table.add('Current', self.hardware.motor_position) + input_table.add("Motor Position", None) + input_table.add("Current", self.hardware.motor_position) self.motor_destination = self.hardware.motor_position.associate(display=False) - input_table.add('Destination', self.motor_destination) + input_table.add("Destination", self.motor_destination) self.scroll_layout.addWidget(input_table) # set mm button - self.set_motor_button = pw.SetButton('SET POSITION') + self.set_motor_button = pw.SetButton("SET POSITION") self.scroll_layout.addWidget(self.set_motor_button) self.set_motor_button.clicked.connect(self.on_set_motor) g.queue_control.disable_when_true(self.set_motor_button) # zero input table input_table = pw.InputTable() - input_table.add('Zero Position', None) - input_table.add('Current', self.hardware.zero_position) + input_table.add("Zero Position", None) + input_table.add("Current", self.hardware.zero_position) self.zero_destination = self.hardware.zero_position.associate(display=False) - input_table.add('Destination', self.zero_destination) + input_table.add("Destination", self.zero_destination) self.scroll_layout.addWidget(input_table) # set zero button - self.set_zero_button = pw.SetButton('SET ZERO') + self.set_zero_button = pw.SetButton("SET ZERO") self.scroll_layout.addWidget(self.set_zero_button) self.set_zero_button.clicked.connect(self.on_set_zero) g.queue_control.disable_when_true(self.set_zero_button) # horizontal line - self.scroll_layout.addWidget(pw.line('H')) + self.scroll_layout.addWidget(pw.line("H")) # home button input_table = pw.InputTable() - self.home_button = pw.SetButton('HOME', 'advanced') + self.home_button = pw.SetButton("HOME", "advanced") self.scroll_layout.addWidget(self.home_button) self.home_button.clicked.connect(self.on_home) g.queue_control.disable_when_true(self.home_button) @@ -119,16 +139,16 @@ def initialize(self): self.scroll_layout.addStretch(1) self.layout.addStretch(1) self.hardware.update_ui.connect(self.update) - + def on_home(self): - self.driver.hardware.q.push('home') - + self.driver.hardware.q.push("home") + def on_set_motor(self): - new_mm = self.motor_destination.read('deg') - self.hardware.set_motor_position(new_mm, units='deg') + new_mm = self.motor_destination.read("deg") + self.hardware.set_motor_position(new_mm, units="deg") def on_set_zero(self): - new_zero = self.zero_destination.read('deg') + new_zero = self.zero_destination.read("deg") self.driver.set_zero(new_zero) self.driver.offset.write(0) name = self.hardware.name @@ -143,23 +163,24 @@ def update(self): class Hardware(hw.Hardware): - def __init__(self, *arks, **kwargs): - self.kind = 'filter' + self.kind = "filter" self.factor = pc.Number(1, decimals=0) - self.motor_limits = pc.NumberLimits(min_value=-360., max_value=360., units='deg') - self.motor_position = pc.Number(units='deg', display=True, limits=self.motor_limits) + self.motor_limits = pc.NumberLimits(min_value=-360.0, max_value=360.0, units="deg") + self.motor_position = pc.Number(units="deg", display=True, limits=self.motor_limits) self.zero_position = pc.Number(display=True) hw.Hardware.__init__(self, *arks, **kwargs) self.label = pc.String(self.name, display=True) - - def set_motor_position(self, motor_position, units='deg'): + + def set_motor_position(self, motor_position, units="deg"): # TODO: should probably support 'motor native units' - self.q.push('set_motor_position', motor_position) + self.q.push("set_motor_position", motor_position) # --- import -------------------------------------------------------------------------------------- -ini_path = os.path.join(directory, 'filters.ini') -hardwares, gui, advanced_gui = hw.import_hardwares(ini_path, name='Filters', Driver=Driver, GUI=GUI, Hardware=Hardware) +ini_path = os.path.join(directory, "filters.ini") +hardwares, gui, advanced_gui = hw.import_hardwares( + ini_path, name="Filters", Driver=Driver, GUI=GUI, Hardware=Hardware +) diff --git a/hardware/filters/homebuilt/homebuilt.py b/hardware/filters/homebuilt/homebuilt.py index 439d9a89..e79ea589 100644 --- a/hardware/filters/homebuilt/homebuilt.py +++ b/hardware/filters/homebuilt/homebuilt.py @@ -11,6 +11,7 @@ from hardware.filters.filters import Driver as BaseDriver from hardware.filters.filters import GUI as BaseGUI import project.com_handler as com_handler + main_dir = g.main_dir.read() @@ -18,36 +19,41 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): BaseDriver.__init__(self, *args, **kwargs) - self.index = kwargs['index'] - + self.index = kwargs["index"] + def close(self): self.port.close() - + def home(self, inputs=[]): position = self.get_position() - self.port.write(' '.join(['H', str(self.index)])) + self.port.write(" ".join(["H", str(self.index)])) self.wait_until_ready() self.motor_position.write(0) self.get_position() self.set_position(position) def get_position(self): - position = (self.motor_position.read() - self.zero_position.read()) * self.native_per_deg * self.factor.read() - self.position.write(position, 'deg') + position = ( + (self.motor_position.read() - self.zero_position.read()) + * self.native_per_deg + * self.factor.read() + ) + self.position.write(position, "deg") return position def initialize(self): # open com port - port_index = self.hardware_ini.read(self.name, 'serial_port') + port_index = self.hardware_ini.read(self.name, "serial_port") self.port = com_handler.get_com(port_index, timeout=100000) # timeout in 100 seconds # stepping - self.microsteps = self.hardware_ini.read(self.name, 'degree_of_microstepping') - steps_per_rotation = self.hardware_ini.read(self.name, 'full_steps_per_rotation') * self.microsteps - self.degrees_per_step = 360. / steps_per_rotation - self.port.write('U %i' % self.microsteps) + self.microsteps = self.hardware_ini.read(self.name, "degree_of_microstepping") + steps_per_rotation = ( + self.hardware_ini.read(self.name, "full_steps_per_rotation") * self.microsteps + ) + self.degrees_per_step = 360.0 / steps_per_rotation + self.port.write("U %i" % self.microsteps) # finish self.initialized.write(True) self.initialized_signal.emit() @@ -60,9 +66,9 @@ def is_busy(self): def set_degrees(self, degrees): change = degrees - self.motor_position.read() - steps = np.floor(change/self.degrees_per_step) + steps = np.floor(change / self.degrees_per_step) signed_steps = steps - command = ' '.join(['M', str(self.index), str(signed_steps)]) + command = " ".join(["M", str(self.index), str(signed_steps)]) self.port.write(command) self.wait_until_ready() # update own position @@ -70,18 +76,21 @@ def set_degrees(self, degrees): motor_position += steps * self.degrees_per_step self.motor_position.write(motor_position) self.get_position() - + def set_position(self, destination): - self.set_degrees(self.zero_position.read('deg') + destination / (self.native_per_deg * self.factor.read())) + self.set_degrees( + self.zero_position.read("deg") + + destination / (self.native_per_deg * self.factor.read()) + ) self.save_status() - + def wait_until_ready(self): while True: - command = ' '.join(['Q', str(self.index)]) + command = " ".join(["Q", str(self.index)]) if not self.port.is_open(): return status = self.port.write(command, then_read=True).rstrip() - if status == 'R': + if status == "R": break time.sleep(0.1) self.port.flush() diff --git a/hardware/hardware.py b/hardware/hardware.py index 2a0039b9..326aefae 100644 --- a/hardware/hardware.py +++ b/hardware/hardware.py @@ -36,21 +36,30 @@ def __init__(self, hardware, **kwargs): self.name = self.hardware.name self.model = self.hardware.model self.serial = self.hardware.serial - self.label = pc.String(kwargs['label']) - self.native_units = kwargs['native_units'] + self.label = pc.String(kwargs["label"]) + self.native_units = kwargs["native_units"] # mutex attributes self.limits = pc.NumberLimits(units=self.native_units) - self.position = pc.Number(initial_value=kwargs['position'], - units=self.native_units, name='Position', - display=True, set_method='set_position', - limits=self.limits) - self.offset = pc.Number(units=self.native_units, name='Offset', - display=True) - self.position.set_units(kwargs['display_units']) + self.position = pc.Number( + initial_value=kwargs["position"], + units=self.native_units, + name="Position", + display=True, + set_method="set_position", + limits=self.limits, + ) + self.offset = pc.Number(units=self.native_units, name="Offset", display=True) + self.position.set_units(kwargs["display_units"]) # attributes for 'exposure' self.exposed = [self.position] self.recorded = collections.OrderedDict() - self.recorded[self.name] = [self.position, self.native_units, 1., self.label.read(), False] + self.recorded[self.name] = [ + self.position, + self.native_units, + 1.0, + self.label.read(), + False, + ] def close(self): pass @@ -65,10 +74,16 @@ def initialize(self): self.label.updated.connect(self.on_label_updated) self.initialized.write(True) self.initialized_signal.emit() - + @QtCore.Slot() def on_label_updated(self): - self.recorded[self.name] = [self.position, self.native_units, 1., self.label.read(), False] + self.recorded[self.name] = [ + self.position, + self.native_units, + 1.0, + self.label.read(), + False, + ] def poll(self): """ @@ -78,9 +93,9 @@ def poll(self): self.is_busy() def save_status(self): - self.hardware_ini.write(self.name, 'position', self.position.read(self.native_units)) - self.hardware_ini.write(self.name, 'display_units', self.position.units) - self.hardware_ini.write(self.name, 'label', self.label.read()) + self.hardware_ini.write(self.name, "position", self.position.read(self.native_units)) + self.hardware_ini.write(self.name, "display_units", self.position.units) + self.hardware_ini.write(self.name, "label", self.label.read()) def set_offset(self, offset): self.offset.write(offset, self.native_units) @@ -96,7 +111,6 @@ def set_position(self, destination): class GUI(QtCore.QObject): - def __init__(self, hardware): """ Runs after driver.__init__, but before driver.initialize. @@ -104,10 +118,10 @@ def __init__(self, hardware): QtCore.QObject.__init__(self) self.hardware = hardware self.driver = hardware.driver - + def close(self): pass - + def create_frame(self, layout): """ Runs before initialize. @@ -126,26 +140,26 @@ def create_frame(self, layout): self.scroll_layout.setMargin(5) # attributes table self.attributes_table = pw.InputTable() - self.attributes_table.add('Attributes', None) + self.attributes_table.add("Attributes", None) name = pc.String(self.hardware.name, display=True) - self.attributes_table.add('Name', name) + self.attributes_table.add("Name", name) model = pc.String(self.hardware.model, display=True) - self.attributes_table.add('Model', model) + self.attributes_table.add("Model", model) serial = pc.String(self.hardware.serial, display=True) - self.attributes_table.add('Serial', serial) + self.attributes_table.add("Serial", serial) self.position = self.hardware.position.associate() self.hardware.position.updated.connect(self.on_position_updated) - self.attributes_table.add('Label', self.hardware.driver.label) - self.attributes_table.add('Position', self.position) - self.offset = self.hardware.offset.associate() + self.attributes_table.add("Label", self.hardware.driver.label) + self.attributes_table.add("Position", self.position) + self.offset = self.hardware.offset.associate() self.hardware.offset.updated.connect(self.on_offset_updated) - self.attributes_table.add('Offset', self.offset) + self.attributes_table.add("Offset", self.offset) # initialization if self.hardware.initialized.read(): self.initialize() else: self.hardware.initialized_signal.connect(self.initialize) - + def initialize(self): """ Runs only once the hardware is done initializing. @@ -170,6 +184,8 @@ def on_position_updated(self): hardwares = [] + + def all_initialized(): # fires any time a hardware is initialized for hardware in hardwares: @@ -180,7 +196,6 @@ def all_initialized(): class Hardware(pc.Hardware): - def __init__(self, *args, **kwargs): pc.Hardware.__init__(self, *args, **kwargs) self.driver.initialized_signal.connect(self.on_address_initialized) @@ -197,66 +212,60 @@ def __init__(self, *args, **kwargs): hardwares.append(self) def close(self): - self.q.push('save_status') + self.q.push("save_status") pc.Hardware.close(self) - def get_destination(self, output_units='same'): + def get_destination(self, output_units="same"): return self.destination.read(output_units=output_units) - def get_position(self, output_units='same'): + def get_position(self, output_units="same"): return self.position.read(output_units=output_units) def is_valid(self, destination, input_units=None): if input_units is None: pass else: - destination = wt.units.converter(destination, - input_units, - self.native_units) + destination = wt.units.converter(destination, input_units, self.native_units) min_value, max_value = self.limits.read(self.native_units) if min_value <= destination <= max_value: return True else: return False - + def on_address_initialized(self): self.destination.write(self.get_position(), self.native_units) - #all_initialized() + # all_initialized() self.initialized_signal.emit() def poll(self, force=False): if force: - self.q.push('poll') + self.q.push("poll") self.get_position() elif not g.queue_control.read(): - self.q.push('poll') + self.q.push("poll") self.get_position() - + def set_offset(self, offset, input_units=None): if input_units is None: pass else: - offset = wt.units.converter(offset, - input_units, - self.native_units) + offset = wt.units.converter(offset, input_units, self.native_units) # do nothing if new offset is same as current offset if offset == self.offset.read(self.native_units): return - self.q.push('set_offset', offset) + self.q.push("set_offset", offset) def set_position(self, destination, input_units=None, force_send=False): if input_units is None: pass else: - destination = wt.units.converter(destination, - input_units, - self.native_units) + destination = wt.units.converter(destination, input_units, self.native_units) # do nothing if new destination is same as current destination if destination == self.destination.read(self.native_units): if not force_send: return self.destination.write(destination, self.native_units) - self.q.push('set_position', destination) + self.q.push("set_position", destination) @property def units(self): @@ -270,24 +279,24 @@ def import_hardwares(ini_path, name, Driver, GUI, Hardware): ini = wt.kit.INI(ini_path) hardwares = [] for section in ini.sections: - if ini.read(section, 'enable'): + if ini.read(section, "enable"): # initialization arguments kwargs = collections.OrderedDict() for option in ini.get_options(section): - if option in ['__name__', 'enable', 'model', 'serial', 'path']: + if option in ["__name__", "enable", "model", "serial", "path"]: continue else: - kwargs[option] = ini.read(section, option) - model = ini.read(section, 'model') - if model == 'Virtual': - hardware = Hardware(Driver, kwargs, GUI, name=section, model='Virtual') + kwargs[option] = ini.read(section, option) + model = ini.read(section, "model") + if model == "Virtual": + hardware = Hardware(Driver, kwargs, GUI, name=section, model="Virtual") else: - path = os.path.abspath(ini.read(section, 'path')) - fname = os.path.basename(path).split('.')[0] + path = os.path.abspath(ini.read(section, "path")) + fname = os.path.basename(path).split(".")[0] mod = imp.load_source(fname, path) - cls = getattr(mod, 'Driver') - gui = getattr(mod, 'GUI') - serial = ini.read(section, 'serial') + cls = getattr(mod, "Driver") + gui = getattr(mod, "GUI") + serial = ini.read(section, "serial") hardware = Hardware(cls, kwargs, gui, name=section, model=model, serial=serial) hardwares.append(hardware) gui = pw.HardwareFrontPanel(hardwares, name=name) diff --git a/hardware/opas/OPA-800/OPA-800.py b/hardware/opas/OPA-800/OPA-800.py index c7c8a867..5906f81f 100644 --- a/hardware/opas/OPA-800/OPA-800.py +++ b/hardware/opas/OPA-800/OPA-800.py @@ -23,30 +23,35 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): - self.motor_names = kwargs.pop("motor_names", ['Grating', 'BBO', 'Mixer']) + self.motor_names = kwargs.pop("motor_names", ["Grating", "BBO", "Mixer"]) self.motor_ports = kwargs.pop("motor_ports") self.motors = {} self.curve_paths = collections.OrderedDict() # TODO: Determine if pico_opa needs to have interaction string combo - allowed_values = ['SHS'] + allowed_values = ["SHS"] self.interaction_string_combo = pc.Combo(allowed_values=allowed_values) BaseDriver.__init__(self, *args, **kwargs) # load curve - self.curve_path = pc.Filepath(ini=self.hardware_ini, section=self.name, option='curve_path', - import_from_ini=True, save_to_ini_at_shutdown=True, options=['Curve File (*.curve)']) + self.curve_path = pc.Filepath( + ini=self.hardware_ini, + section=self.name, + option="curve_path", + import_from_ini=True, + save_to_ini_at_shutdown=True, + options=["Curve File (*.curve)"], + ) self.curve_path.updated.connect(self.curve_path.save) self.curve_path.updated.connect(lambda: self.load_curve()) - self.curve_paths['Curve'] = self.curve_path + self.curve_paths["Curve"] = self.curve_path self.load_curve() def _load_curve(self, interaction): - ''' + """ when loading externally, write to curve_path object directly - ''' - self.curve = attune.Curve.read(self.curve_paths['Curve'].read()) + """ + self.curve = attune.Curve.read(self.curve_paths["Curve"].read()) self.curve.kind = "opa800" return self.curve @@ -65,23 +70,33 @@ def get_motor_positions(self): def initialize(self): self.serial_number = -1 - self.recorded['w%d' % self.index] = [self.position, self.native_units, 1., str(self.index)] + self.recorded["w%d" % self.index] = [ + self.position, + self.native_units, + 1.0, + str(self.index), + ] # motor positions motor_limits = pc.NumberLimits(min_value=0, max_value=50) for motor_index, motor_name in enumerate(self.motor_names): - if motor_name in ['Phi', 'Theta']: + if motor_name in ["Phi", "Theta"]: continue - number = pc.Number(name=motor_name, initial_value=25., - decimals=6, limits=motor_limits, display=True) + number = pc.Number( + name=motor_name, initial_value=25.0, decimals=6, limits=motor_limits, display=True + ) self.motor_positions[motor_name] = number - self.motors.update({ motor_name: yaqc.Client(self.motor_ports[motor_index])}) - self.recorded['w%d_%s' % (self.index, motor_name)] = [ - number, None, 0.001, motor_name.lower()] + self.motors.update({motor_name: yaqc.Client(self.motor_ports[motor_index])}) + self.recorded["w%d_%s" % (self.index, motor_name)] = [ + number, + None, + 0.001, + motor_name.lower(), + ] # self.get_motor_positions() # tuning self.best_points = {} - self.best_points['SHS'] = np.linspace(13500, 18200, 21) - self.best_points['DFG'] = np.linspace(1250, 2500, 11) + self.best_points["SHS"] = np.linspace(13500, 18200, 21) + self.best_points["DFG"] = np.linspace(1250, 2500, 11) # finish BaseDriver.initialize(self) diff --git a/hardware/opas/PoyntingCorrection/PoyntingCorrectionDevice.py b/hardware/opas/PoyntingCorrection/PoyntingCorrectionDevice.py index 63bb8183..7e23b161 100644 --- a/hardware/opas/PoyntingCorrection/PoyntingCorrectionDevice.py +++ b/hardware/opas/PoyntingCorrection/PoyntingCorrectionDevice.py @@ -18,17 +18,16 @@ class PoyntingCorrectionDevice(object): - - def __init__(self, native_units='wn'): + def __init__(self, native_units="wn"): self.native_units = native_units - self.limits = pc.NumberLimits(units = self.native_units) - self.offset = pc.Number(initial_value = 0, units = self.native_units, display = True) + self.limits = pc.NumberLimits(units=self.native_units) + self.offset = pc.Number(initial_value=0, units=self.native_units, display=True) # TODO: not use hardcoded Phi and Theta as motor names, read from curve self.recorded = collections.OrderedDict() - self.motor_names = ['Phi', 'Theta'] - self.motor_positions = collections.OrderedDict() - self.motor_positions['Phi'] = pc.Number() - self.motor_positions['Theta'] = pc.Number() + self.motor_names = ["Phi", "Theta"] + self.motor_positions = collections.OrderedDict() + self.motor_positions["Phi"] = pc.Number() + self.motor_positions["Theta"] = pc.Number() self.motors = [] self.initialized = pc.Bool() @@ -38,7 +37,7 @@ def _get_motor_position(self, index): def _home(self, index): raise NotImplementedError - def _initialize(self,inputs): + def _initialize(self, inputs): raise NotImplementedError def _set_motor(self, index, position): @@ -58,7 +57,7 @@ def get_motor_position(self, motor): motor_index = motor motor = self.motor_name.index(motor) else: - print('motor_index not recognized in PoyntingCorrectionDevice get_motor_position') + print("motor_index not recognized in PoyntingCorrectionDevice get_motor_position") return # read position position = self._get_motor_position(motor_index) @@ -69,12 +68,12 @@ def get_motor_positions(self): return [self.get_motor_position(s) for s in self.motor_names] def home(self, motor=None): - if motor==None: + if motor == None: for m in range(len(self.motor_names)): self._home(m) elif isinstance(motor, str): self._home(self.motor_names.index(motor)) - elif isinstance(motor,int): + elif isinstance(motor, int): self._home(motor) else: self._home(self.motors.index(motor)) @@ -84,9 +83,16 @@ def initialize(self, OPA): self.motor_positions = collections.OrderedDict() motor_limits = self.motor_limits() for motor_index, motor_name in enumerate(self.motor_names): - number = pc.Number(name=motor_name, initial_value=0, decimals=0, limits=motor_limits, display=True) + number = pc.Number( + name=motor_name, initial_value=0, decimals=0, limits=motor_limits, display=True + ) self.motor_positions[motor_name] = number - self.recorded['%s_%s'%(self.OPA.name,motor_name)] = [number, None, 1, motor_name.lower()] + self.recorded["%s_%s" % (self.OPA.name, motor_name)] = [ + number, + None, + 1, + motor_name.lower(), + ] self._initialize() self.initialized.write(True) @@ -99,15 +105,15 @@ def motor_limits(self): def move_rel(self, motor, position): if str(motor) in self.motor_names: self._move_rel(self.motor_names.index(motor), int(position)) - elif isinstance(motor,int): + elif isinstance(motor, int): self._move_rel(motor, int(position)) else: - self._move_rel(self.motors.index(motor),int(position)) + self._move_rel(self.motors.index(motor), int(position)) def set_motor(self, motor, position): if str(motor) in self.motor_names: self._set_motor(self.motor_names.index(motor), int(position)) - elif isinstance(motor,int): + elif isinstance(motor, int): self._set_motor(motor, int(position)) else: self._set_motor(self.motors.index(motor), int(position)) @@ -120,12 +126,12 @@ def wait_until_still(self): self.get_motor_positions() def zero(self, motor=None): - if motor==None: + if motor == None: for m in range(len(self.motor_names)): self._zero(m) elif isinstance(motor, str): self._zero(self.motor_names.index(motor)) - elif isinstance(motor,int): + elif isinstance(motor, int): self._zero(motor) else: self._zero(self.motors.index(motor)) diff --git a/hardware/opas/PoyntingCorrection/ZaberCorrectionDevice.py b/hardware/opas/PoyntingCorrection/ZaberCorrectionDevice.py index fa95a7c9..95b24100 100644 --- a/hardware/opas/PoyntingCorrection/ZaberCorrectionDevice.py +++ b/hardware/opas/PoyntingCorrection/ZaberCorrectionDevice.py @@ -15,8 +15,7 @@ class ZaberCorrectionDevice(PoyntingCorrectionDevice): - - def __init__ (self, port, indexes, native_units = 'wn'): + def __init__(self, port, indexes, native_units="wn"): self.portStg = str(port) self.indexes = list(indexes[0]) PoyntingCorrectionDevice.__init__(self, native_units) @@ -28,23 +27,23 @@ def _home(self, index): position = self.motors[index].get_position() self.motors[index].home() self.motors[index].move_abs(position) - + def _initialize(self): self.port = zb.BinarySerial(self.portStg) for i in self.indexes: - self.motors.append(zb.BinaryDevice(self.port, i)) + self.motors.append(zb.BinaryDevice(self.port, i)) def _set_motor(self, index, position): return self.motors[index].move_abs(position) - + def _zero(self, index): self.motors[index].home() time.sleep(2) self.motors[index].move_abs(0) - + def motor_limits(self): return pc.NumberLimits(min_value=-62000, max_value=62000) - + def is_busy(self): return False busy = False diff --git a/hardware/opas/TOPAS/TOPAS-800.py b/hardware/opas/TOPAS/TOPAS-800.py index 40342caf..bb147ad4 100644 --- a/hardware/opas/TOPAS/TOPAS-800.py +++ b/hardware/opas/TOPAS/TOPAS-800.py @@ -8,16 +8,21 @@ ### autotune ################################################################## - ### driver #################################################################### class Driver(BaseDriver): - def __init__(self, *args, **kwargs): - self.motor_names = ['Crystal', 'Amplifier', 'Grating', 'NDFG_Crystal', 'NDFG_Mirror', 'NDFG_Delay'] - #self.motor_names = ['0', '1', '2', '3', '4', '5'] - self.curve_indices = {'Base': 1, 'Mixer 3': 4} + self.motor_names = [ + "Crystal", + "Amplifier", + "Grating", + "NDFG_Crystal", + "NDFG_Mirror", + "NDFG_Delay", + ] + # self.motor_names = ['0', '1', '2', '3', '4', '5'] + self.curve_indices = {"Base": 1, "Mixer 3": 4} self.kind = "TOPAS-800" BaseDriver.__init__(self, *args, **kwargs) diff --git a/hardware/opas/TOPAS/TOPAS-C.py b/hardware/opas/TOPAS/TOPAS-C.py index 86f14c78..50f4a9a4 100644 --- a/hardware/opas/TOPAS/TOPAS-C.py +++ b/hardware/opas/TOPAS/TOPAS-C.py @@ -9,12 +9,18 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): - self.motor_names = ['Crystal_1', 'Delay_1', 'Crystal_2', 'Delay_2', - 'Mixer_1', 'Mixer_2','Mixer_3'] - self.curve_indices = {'Base': 1, 'Mixer_1': 2, 'Mixer_2': 3, 'Mixer_3': 4} - self.kind = 'TOPAS-C' + self.motor_names = [ + "Crystal_1", + "Delay_1", + "Crystal_2", + "Delay_2", + "Mixer_1", + "Mixer_2", + "Mixer_3", + ] + self.curve_indices = {"Base": 1, "Mixer_1": 2, "Mixer_2": 3, "Mixer_3": 4} + self.kind = "TOPAS-C" BaseDriver.__init__(self, *args, **kwargs) diff --git a/hardware/opas/TOPAS/TOPAS.py b/hardware/opas/TOPAS/TOPAS.py index e09a1891..9a151f0a 100644 --- a/hardware/opas/TOPAS/TOPAS.py +++ b/hardware/opas/TOPAS/TOPAS.py @@ -14,7 +14,7 @@ from project.ini_handler import Ini from hardware.opas.opas import Driver as BaseDriver from hardware.opas.opas import GUI as BaseGUI - + # --- define -------------------------------------------------------------------------------------- @@ -25,43 +25,51 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): - self.motors={} + self.motors = {} self.curve_paths = collections.OrderedDict() - self.ini = project.ini_handler.Ini(os.path.join(main_dir, 'hardware', 'opas', 'TOPAS', 'TOPAS.ini')) - self.has_shutter = kwargs['has_shutter'] - self.yaq_port = kwargs['yaq_port'] + self.ini = project.ini_handler.Ini( + os.path.join(main_dir, "hardware", "opas", "TOPAS", "TOPAS.ini") + ) + self.has_shutter = kwargs["has_shutter"] + self.yaq_port = kwargs["yaq_port"] if self.has_shutter: - self.shutter_position = pc.Bool(name='Shutter', display=True, set_method='set_shutter') - BaseDriver.__init__(self, *args, **kwargs) - self.serial_number = self.ini.read('OPA' + str(self.index), 'serial number') + self.shutter_position = pc.Bool(name="Shutter", display=True, set_method="set_shutter") + BaseDriver.__init__(self, *args, **kwargs) + self.serial_number = self.ini.read("OPA" + str(self.index), "serial number") # load api self.api = yaqc.Client(self.yaq_port) if self.has_shutter: self.api.set_shutter(False) - + # motor positions for motor_name in self.motor_names: min_position, max_position = self.api.get_motor_range(motor_name) limits = pc.NumberLimits(min_position, max_position) number = pc.Number(initial_value=0, limits=limits, display=True, decimals=6) self.motor_positions[motor_name] = number - self.recorded['w%d_'%self.index + motor_name] = [number, None, 1., motor_name] + self.recorded["w%d_" % self.index + motor_name] = [number, None, 1.0, motor_name] # finish if self.has_shutter: self.exposed += [self.shutter_position] # tuning curves - self.serial_number = self.ini.read(f"OPA{self.index}", 'serial number') - self.TOPAS_ini_filepath = os.path.join(g.main_dir.read(), 'hardware', 'opas', 'TOPAS', 'configuration', str(self.serial_number) + '.ini') + self.serial_number = self.ini.read(f"OPA{self.index}", "serial number") + self.TOPAS_ini_filepath = os.path.join( + g.main_dir.read(), + "hardware", + "opas", + "TOPAS", + "configuration", + str(self.serial_number) + ".ini", + ) self.TOPAS_ini = Ini(self.TOPAS_ini_filepath) self.TOPAS_ini.return_raw = True for curve_type in self.curve_indices.keys(): - section = 'Optical Device' - option = 'Curve ' + str(self.curve_indices[curve_type]) + section = "Optical Device" + option = "Curve " + str(self.curve_indices[curve_type]) initial_value = self.TOPAS_ini.read(section, option) - options = ['CRV (*.crv)'] + options = ["CRV (*.crv)"] curve_filepath = pc.Filepath(initial_value=initial_value, options=options) curve_filepath.updated.connect(self.load_curve) self.curve_paths[curve_type] = curve_filepath @@ -72,11 +80,11 @@ def __init__(self, *args, **kwargs): all_crvs = attune.TopasCurve.read_all(paths) allowed_values = list(all_crvs.keys()) self.interaction_string_combo = pc.Combo(allowed_values=allowed_values) - current_value = self.ini.read('OPA%i'%self.index, 'current interaction string') + current_value = self.ini.read("OPA%i" % self.index, "current interaction string") self.interaction_string_combo.write(current_value) self.interaction_string_combo.updated.connect(self.load_curve) g.queue_control.disable_when_true(self.interaction_string_combo) - self.load_curve(update = False) + self.load_curve(update=False) self.homeable = {m: True for m in self.motor_names} def _get_motor_index(self, name): @@ -95,8 +103,8 @@ def _home_motors(self, motor_names): def _load_curve(self, interaction): interaction = self.interaction_string_combo.read() curve_paths_copy = self.curve_paths.copy() - if 'Poynting' in curve_paths_copy.keys(): - del curve_paths_copy['Poynting'] + if "Poynting" in curve_paths_copy.keys(): + del curve_paths_copy["Poynting"] crv_paths = [m.read() for m in curve_paths_copy.values()] all_curves = attune.TopasCurve.read_all(crv_paths) for curve in all_curves.values(): @@ -109,7 +117,7 @@ def _load_curve(self, interaction): self.interaction_string_combo.set_allowed_values(list(all_curves.keys())) self.curve = all_curves[interaction] return self.curve - + def _set_motors(self, motor_destinations): for motor_name, destination in motor_destinations.items(): destination = float(destination) @@ -118,14 +126,14 @@ def _set_motors(self, motor_destinations): def _update_api(self, interaction): # write to TOPAS ini for curve_type, curve_path_mutex in self.curve_paths.items(): - if curve_type == 'Poynting': + if curve_type == "Poynting": continue - curve_path = curve_path_mutex.read() - section = 'Optical Device' - option = 'Curve ' + str(self.curve_indices[curve_type]) + curve_path = curve_path_mutex.read() + section = "Optical Device" + option = "Curve " + str(self.curve_indices[curve_type]) self.TOPAS_ini.write(section, option, curve_path) # save current interaction string - self.ini.write('OPA%i'%self.index, 'current interaction string', interaction) + self.ini.write("OPA%i" % self.index, "current interaction string", interaction) def _wait_until_still(self): while self.is_busy(): @@ -142,16 +150,16 @@ def get_motor_positions(self): motor_mutex.write(position) if self.poynting_correction: self.poynting_correction.get_motor_positions() - + def is_busy(self): return any(self.api.is_motor_busy(m) for m in self.motor_names) - + def set_shutter(self, inputs): shutter_state = inputs[0] error = self.api.set_shutter(shutter_state) self.shutter_position.write(shutter_state) return error - + # --- gui ----------------------------------------------------------------------------------------- diff --git a/hardware/opas/opas.py b/hardware/opas/opas.py index c06ae151..5a1dfbb5 100644 --- a/hardware/opas/opas.py +++ b/hardware/opas/opas.py @@ -35,50 +35,51 @@ class Driver(hw.Driver): - def __init__(self, *args, **kwargs): self.hardware_ini = ini - self.index = kwargs['index'] + self.index = kwargs["index"] self.motor_positions = collections.OrderedDict() self.homeable = {} # TODO: - self.poynting_type = kwargs.pop('poynting_type') - self.poynting_correction = None - self.poynting_curve_path = kwargs.pop('poynting_curve_path') + self.poynting_type = kwargs.pop("poynting_type") + self.poynting_correction = None + self.poynting_curve_path = kwargs.pop("poynting_curve_path") hw.Driver.__init__(self, *args, **kwargs) - if not hasattr(self, 'motor_names'): # for virtual... - self.motor_names = ['Delay', 'Crystal', 'Mixer'] - if not hasattr(self, 'curve_paths'): # for virtual... + if not hasattr(self, "motor_names"): # for virtual... + self.motor_names = ["Delay", "Crystal", "Mixer"] + if not hasattr(self, "curve_paths"): # for virtual... self.curve_paths = collections.OrderedDict() - if not hasattr(self, 'interaction_string_combo'): # for virtual... - self.interaction_string_combo = pc.Combo(allowed_values=['sig']) + if not hasattr(self, "interaction_string_combo"): # for virtual... + self.interaction_string_combo = pc.Combo(allowed_values=["sig"]) if self.poynting_type is not None: - self.motor_names += ['Phi', 'Theta'] #TODO: Generalize + self.motor_names += ["Phi", "Theta"] # TODO: Generalize self.curve = None # poynting correction - if self.poynting_type == 'zaber': - self.poynting_correction = ZaberCorrectionDevice(kwargs.pop('poynting_port'), kwargs.pop('poynting_indexes')) + if self.poynting_type == "zaber": + self.poynting_correction = ZaberCorrectionDevice( + kwargs.pop("poynting_port"), kwargs.pop("poynting_indexes") + ) else: self.poynting_correction = None self.poynting_type = None if self.poynting_correction: - self.curve_paths['Poynting'] = pc.Filepath(initial_value=self.poynting_curve_path) - if self.model == 'Virtual': + self.curve_paths["Poynting"] = pc.Filepath(initial_value=self.poynting_curve_path) + if self.model == "Virtual": self.load_curve() def _home_motors(self, motor_names): raise NotImplementedError def _load_curve(self, interaction): - if self.model == 'Virtual': + if self.model == "Virtual": colors = np.linspace(400, 10000, 17) motors = [] - motors.append(attune.Dependent(((colors-500)/1e4)**2, 'Delay')) - motors.append(attune.Dependent(-(colors-90)**0.25, 'Crystal')) - motors.append(attune.Dependent((colors-30)**0.25, 'Mixer')) - name = 'curve' - interaction = 'sig' - kind = 'Virtual' + motors.append(attune.Dependent(((colors - 500) / 1e4) ** 2, "Delay")) + motors.append(attune.Dependent(-((colors - 90) ** 0.25), "Crystal")) + motors.append(attune.Dependent((colors - 30) ** 0.25, "Mixer")) + name = "curve" + interaction = "sig" + kind = "Virtual" colors = attune.Setpoints(colors, "Colors", units="nm") self.curve = attune.Curve(colors, motors, name, interaction, kind) self.curve.convert(self.native_units) @@ -86,8 +87,8 @@ def _load_curve(self, interaction): raise NotImplementedError def _set_motors(self, motor_destinations): - if self.model == 'Virtual': - #Virtual hardware, just set the position directly + if self.model == "Virtual": + # Virtual hardware, just set the position directly for k, v in motor_destinations.items(): self.motor_positions[k].write(v) else: @@ -98,7 +99,9 @@ def _update_api(self, interaction): def _wait_until_still(self, inputs=[]): while self.is_busy(): - time.sleep(0.1) # I've experienced hard crashes when wait set to 0.01 - Blaise 2015.12.30 + time.sleep( + 0.1 + ) # I've experienced hard crashes when wait set to 0.01 - Blaise 2015.12.30 self.get_motor_positions() self.get_motor_positions() @@ -106,12 +109,12 @@ def get_position(self): position = self.hardware.destination.read() self.position.write(position, self.native_units) return position - + def get_motor_positions(self): pass def home_all(self, inputs=[]): - names = [i for i in self.motor_names if self.homeable.get(i) ] + names = [i for i in self.motor_names if self.homeable.get(i)] if self.poynting_correction: self.poynting_correction.home() for n in self.poynting_correction.motor_names: @@ -130,18 +133,18 @@ def home_motor(self, inputs): def initialize(self): # virtual stuff - if self.model == 'Virtual': - self.motor_positions['Delay'] = pc.Number(0., display=True) - self.motor_positions['Crystal'] = pc.Number(0., display=True) - self.motor_positions['Mixer'] = pc.Number(0., display=True) + if self.model == "Virtual": + self.motor_positions["Delay"] = pc.Number(0.0, display=True) + self.motor_positions["Crystal"] = pc.Number(0.0, display=True) + self.motor_positions["Mixer"] = pc.Number(0.0, display=True) if self.poynting_correction: - # initialize - self.poynting_correction.initialize(self) + # initialize + self.poynting_correction.initialize(self) for name in self.poynting_correction.motor_names: self.homeable[name] = True number = self.poynting_correction.motor_positions[name] self.motor_positions[name] = number - self.recorded[self.name + '_' + name] = [number, None, 1., name] + self.recorded[self.name + "_" + name] = [number, None, 1.0, name] # get position self.load_curve() self.get_motor_positions() @@ -158,19 +161,18 @@ def load_curve(self, name=None, path=None, update=True): # remake own curve object curve = self._load_curve(interaction) if self.poynting_correction: - p = self.curve_paths['Poynting'].read() + p = self.curve_paths["Poynting"].read() self.curve = attune.Curve.read(p, subcurve=curve) self.curve.kind = "poynting" - self.hardware_ini.write(self.name, 'poynting_curve_path', p) + self.hardware_ini.write(self.name, "poynting_curve_path", p) self.curve.convert(self.native_units) # update limits self.limits.write(*self.curve.get_limits(), self.native_units) if update: self._update_api(interaction) - def set_motor(self, motor_name, destination, wait=True): - + if self.poynting_correction: if motor_name in self.poynting_correction.motor_names: self.poynting_correction.set_motor(motor_name, destination) @@ -180,7 +182,7 @@ def set_motor(self, motor_name, destination, wait=True): self.wait_until_still() def set_motors(self, motor_names, motor_positions, wait=True): - destinations = {n: p for n,p in zip(motor_names, motor_positions)} + destinations = {n: p for n, p in zip(motor_names, motor_positions)} if self.poynting_correction: for name, pos in zip(motor_names, motor_positions): if name in self.poynting_correction.motor_names: @@ -205,13 +207,13 @@ def set_position(self, destination): # finish self.wait_until_still() self.get_position() - + def set_position_except(self, destination, exceptions): - ''' + """ set position, except for motors that follow does not wait until still... - ''' + """ self.hardware.destination.write(destination, self.native_units) self.position.write(destination, self.native_units) motor_destinations = self.curve(destination, self.native_units) @@ -234,9 +236,8 @@ def wait_until_still(self): class GUI(hw.GUI): - def initialize(self): - #self.hardware.driver.initialize() + # self.hardware.driver.initialize() # container widget display_container_widget = QtWidgets.QWidget() display_container_widget.setLayout(QtWidgets.QVBoxLayout()) @@ -251,7 +252,7 @@ def initialize(self): self.plot_v_line = self.plot_widget.add_infinite_line(angle=90, hide=False) display_layout.addWidget(self.plot_widget) # vertical line - line = pw.line('V') + line = pw.line("V") self.layout.addWidget(line) # container widget / scroll area settings_container_widget = QtWidgets.QWidget() @@ -268,37 +269,43 @@ def initialize(self): settings_layout.addWidget(input_table) # plot control input_table = pw.InputTable() - input_table.add('Display', None) + input_table.add("Display", None) self.plot_motor = pc.Combo(allowed_values=self.driver.curve.dependent_names) self.plot_motor.updated.connect(self.update_plot) - input_table.add('Motor', self.plot_motor) + input_table.add("Motor", self.plot_motor) allowed_values = list(wt.units.energy.keys()) - self.plot_units = pc.Combo(initial_value=self.driver.native_units, allowed_values=allowed_values) + self.plot_units = pc.Combo( + initial_value=self.driver.native_units, allowed_values=allowed_values + ) self.plot_units.updated.connect(self.update_plot) - input_table.add('Units', self.plot_units) + input_table.add("Units", self.plot_units) settings_layout.addWidget(input_table) # curves input_table = pw.InputTable() - input_table.add('Curves', None) + input_table.add("Curves", None) for name, obj in self.driver.curve_paths.items(): input_table.add(name, obj) obj.updated.connect(self.on_curve_paths_updated) - input_table.add('Interaction String', self.driver.interaction_string_combo) + input_table.add("Interaction String", self.driver.interaction_string_combo) # limits limits = pc.NumberLimits() # units None - self.low_energy_limit_display = pc.Number(units=self.driver.native_units, display=True, limits=limits) - input_table.add('Low Energy Limit', self.low_energy_limit_display) - self.high_energy_limit_display = pc.Number(units=self.driver.native_units, display=True, limits=limits) - input_table.add('High Energy LImit', self.high_energy_limit_display) + self.low_energy_limit_display = pc.Number( + units=self.driver.native_units, display=True, limits=limits + ) + input_table.add("Low Energy Limit", self.low_energy_limit_display) + self.high_energy_limit_display = pc.Number( + units=self.driver.native_units, display=True, limits=limits + ) + input_table.add("High Energy LImit", self.high_energy_limit_display) settings_layout.addWidget(input_table) self.driver.limits.updated.connect(self.on_limits_updated) # motors input_table = pw.InputTable() - input_table.add('Motors', None) + input_table.add("Motors", None) settings_layout.addWidget(input_table) for motor_name, motor_mutex in self.driver.motor_positions.items(): settings_layout.addWidget(MotorControlGUI(motor_name, motor_mutex, self.driver)) - self.home_all_button = pw.SetButton('HOME ALL', 'advanced') + self.home_all_button = pw.SetButton("HOME ALL", "advanced") settings_layout.addWidget(self.home_all_button) homeable = any(self.driver.homeable) self.home_all_button.clicked.connect(self.on_home_all) @@ -307,7 +314,7 @@ def initialize(self): if self.driver.poynting_correction: self.poynting_manual_control = pc.Bool() input_table = pw.InputTable() - input_table.add('Poynting Control', self.poynting_manual_control) + input_table.add("Poynting Control", self.poynting_manual_control) self.poynting_manual_control.updated.connect(self.on_poynting_manual_control_updated) settings_layout.addWidget(input_table) # stretch @@ -331,7 +338,7 @@ def update(self): for motor_mutex in self.driver.motor_positions.values(): motor_mutex.set_disabled(False) # update destination motor positions - # TODO: + # TODO: # update plot lines motor_name = self.plot_motor.read() try: @@ -349,7 +356,9 @@ def update_plot(self): colors = self.driver.curve.setpoints[:] xi = wt.units.converter(colors, self.driver.curve.setpoints.units, units) # yi - self.plot_motor.set_allowed_values(self.driver.curve.dependent_names) # can be done on initialization? + self.plot_motor.set_allowed_values( + self.driver.curve.dependent_names + ) # can be done on initialization? motor_name = self.plot_motor.read() yi = self.driver.curve(xi, units)[motor_name] self.plot_widget.set_labels(xlabel=units, ylabel=motor_name) @@ -367,22 +376,21 @@ def on_curve_paths_updated(self): self.update_plot() def on_home_all(self): - self.hardware.q.push('home_all') - + self.hardware.q.push("home_all") + def on_limits_updated(self): - low_energy_limit, high_energy_limit = self.driver.limits.read('wn') - self.low_energy_limit_display.write(low_energy_limit, 'wn') - self.high_energy_limit_display.write(high_energy_limit, 'wn') - + low_energy_limit, high_energy_limit = self.driver.limits.read("wn") + self.low_energy_limit_display.write(low_energy_limit, "wn") + self.high_energy_limit_display.write(high_energy_limit, "wn") + def on_poynting_manual_control_updated(self): if self.poynting_manual_control.read(): - self.driver.poynting_correction.port.setMode('manual') + self.driver.poynting_correction.port.setMode("manual") else: - self.driver.poynting_correction.port.setMode('computer') + self.driver.poynting_correction.port.setMode("computer") class MotorControlGUI(QtWidgets.QWidget): - def __init__(self, motor_name, motor_mutex, driver): QtWidgets.QWidget.__init__(self) self.motor_name = motor_name @@ -394,17 +402,17 @@ def __init__(self, motor_name, motor_mutex, driver): input_table = pw.InputTable() input_table.add(motor_name, motor_mutex) self.destination = motor_mutex.associate(display=False) - input_table.add('Dest. ' + motor_name, self.destination) + input_table.add("Dest. " + motor_name, self.destination) self.layout.addWidget(input_table) # buttons - home_button, set_button = self.add_buttons(self.layout, 'HOME', 'advanced', 'SET', 'set') + home_button, set_button = self.add_buttons(self.layout, "HOME", "advanced", "SET", "set") home_button.clicked.connect(self.on_home) set_button.clicked.connect(self.on_set) g.queue_control.disable_when_true(home_button) g.queue_control.disable_when_true(set_button) # finish self.setLayout(self.layout) - + def add_buttons(self, layout, button1_text, button1_color, button2_text, button2_color): colors = g.colors_dict.read() # layout @@ -415,7 +423,9 @@ def add_buttons(self, layout, button1_text, button1_color, button2_text, button2 button1 = QtWidgets.QPushButton() button1.setText(button1_text) button1.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors[button1_color]) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors[button1_color] + ) button1.setStyleSheet(StyleSheet) button_container.layout().addWidget(button1) g.queue_control.disable_when_true(button1) @@ -423,17 +433,19 @@ def add_buttons(self, layout, button1_text, button1_color, button2_text, button2 button2 = QtWidgets.QPushButton() button2.setText(button2_text) button2.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors[button2_color]) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors[button2_color] + ) button2.setStyleSheet(StyleSheet) button_container.layout().addWidget(button2) g.queue_control.disable_when_true(button2) # finish layout.addWidget(button_container) return [button1, button2] - + def on_home(self): - self.driver.hardware.q.push('home_motor', [self.motor_name]) - + self.driver.hardware.q.push("home_motor", [self.motor_name]) + def on_set(self): destination = self.destination.read() self.hardware.set_motor(self.motor_name, destination) @@ -443,26 +455,27 @@ def on_set(self): class Hardware(hw.Hardware): - def __init__(self, *arks, **kwargs): - self.kind = 'OPA' + self.kind = "OPA" hw.Hardware.__init__(self, *arks, **kwargs) @property def curve(self): # TODO: a more thread-safe operation (copy?) return self.driver.curve - + @property def curve_paths(self): """ OrderedDict {name: path} """ # TODO: a more thread-safe operation - return collections.OrderedDict({key: value.read() for key, value in self.driver.curve_paths.items()}) + return collections.OrderedDict( + {key: value.read() for key, value in self.driver.curve_paths.items()} + ) - def get_tune_points(self, units='native'): - if units == 'native': + def get_tune_points(self, units="native"): + if units == "native": units = self.native_units return wt.units.converter(self.curve.setpoints[:], self.curve.setpoints.units, units) @@ -470,22 +483,24 @@ def home_motor(self, motor): """ motor list [name] """ - self.q.push('home_motor', motor) + self.q.push("home_motor", motor) def load_curve(self, name, path): - self.q.push('load_curve', name, path) + self.q.push("load_curve", name, path) @property def motor_names(self): # TODO: a more thread-safe operation return self.driver.motor_names - + def set_motor(self, motor, destination): - self.q.push('set_motor', motor, destination) + self.q.push("set_motor", motor, destination) ### initialize ################################################################ -ini_path = os.path.join(directory, 'opas.ini') -hardwares, gui, advanced_gui = hw.import_hardwares(ini_path, name='OPAs', Driver=Driver, GUI=GUI, Hardware=Hardware) +ini_path = os.path.join(directory, "opas.ini") +hardwares, gui, advanced_gui = hw.import_hardwares( + ini_path, name="OPAs", Driver=Driver, GUI=GUI, Hardware=Hardware +) diff --git a/hardware/spectrometers/MicroHR/MicroHR.py b/hardware/spectrometers/MicroHR/MicroHR.py index 228badca..31cba8db 100644 --- a/hardware/spectrometers/MicroHR/MicroHR.py +++ b/hardware/spectrometers/MicroHR/MicroHR.py @@ -20,15 +20,17 @@ class Driver(BaseDriver): - def __init__(self, *args, **kwargs): self._yaqd_port = kwargs.pop("yaqd_port") BaseDriver.__init__(self, *args, **kwargs) - self.grating_index = pc.Combo(name='Grating', allowed_values=[1, 2], - section=self.name, - option='grating_index', - display=True, - set_method='set_turret') + self.grating_index = pc.Combo( + name="Grating", + allowed_values=[1, 2], + section=self.name, + option="grating_index", + display=True, + set_method="set_turret", + ) self.exposed.append(self.grating_index) def get_position(self): @@ -44,7 +46,7 @@ def initialize(self, *args, **kwargs): self.serial_number = id_dict["serial"] self.position.write(self.ctrl.get_position()) # recorded - self.recorded['wm'] = [self.position, 'nm', 1., 'm', False] + self.recorded["wm"] = [self.position, "nm", 1.0, "m", False] while self.is_busy(): time.sleep(0.1) # finish @@ -53,7 +55,7 @@ def initialize(self, *args, **kwargs): def is_busy(self): return self.ctrl.busy() - + def set_position(self, destination): self.ctrl.set_position(destination) while self.is_busy(): @@ -70,14 +72,15 @@ def set_turret(self, destination_index): while self.is_busy(): time.sleep(0.01) - - #TODO: move limit handling to daemon + # TODO: move limit handling to daemon # update own limits - max_limit = self.hardware_ini.read(self.name, 'grating_%i_maximum_wavelength'%self.grating_index.read()) + max_limit = self.hardware_ini.read( + self.name, "grating_%i_maximum_wavelength" % self.grating_index.read() + ) if self.grating_index.read() == 1: - self.limits.write(0, max_limit, 'nm') + self.limits.write(0, max_limit, "nm") elif self.grating_index.read() == 2: - self.limits.write(0, max_limit, 'nm') + self.limits.write(0, max_limit, "nm") # set position for new grating self.set_position(self.position.read(self.native_units)) diff --git a/hardware/spectrometers/spectrometers.py b/hardware/spectrometers/spectrometers.py index cffe99be..703bb545 100644 --- a/hardware/spectrometers/spectrometers.py +++ b/hardware/spectrometers/spectrometers.py @@ -5,6 +5,7 @@ import project import project.project_globals as g + main_dir = g.main_dir.read() app = g.app.read() import hardware.hardware as hw @@ -14,18 +15,17 @@ directory = os.path.dirname(os.path.abspath(__file__)) -ini = project.ini_handler.Ini(os.path.join(directory, 'spectrometers.ini')) +ini = project.ini_handler.Ini(os.path.join(directory, "spectrometers.ini")) ### driver #################################################################### class Driver(hw.Driver): - def __init__(self, *args, **kwargs): self.hardware_ini = ini hw.Driver.__init__(self, *args, **kwargs) - self.limits.write(0., 10000.) + self.limits.write(0.0, 10000.0) ### gui ####################################################################### @@ -39,14 +39,15 @@ class GUI(hw.GUI): class Hardware(hw.Hardware): - def __init__(self, *args, **kwargs): - self.kind = 'spectrometer' + self.kind = "spectrometer" hw.Hardware.__init__(self, *args, **kwargs) ### import #################################################################### -ini_path = os.path.join(directory, 'spectrometers.ini') -hardwares, gui, advanced_gui = hw.import_hardwares(ini_path, name='Spectrometers', Driver=Driver, GUI=GUI, Hardware=Hardware) +ini_path = os.path.join(directory, "spectrometers.ini") +hardwares, gui, advanced_gui = hw.import_hardwares( + ini_path, name="Spectrometers", Driver=Driver, GUI=GUI, Hardware=Hardware +) diff --git a/library/ThorlabsAPT/APT.py b/library/ThorlabsAPT/APT.py index 98200ea8..2a1dcb97 100644 --- a/library/ThorlabsAPT/APT.py +++ b/library/ThorlabsAPT/APT.py @@ -18,12 +18,12 @@ ### first-time ################################################################ -d = os.path.join(directory, 'APTDLLPAck', 'DLL') -if platform.architecture()[0] == '32bit': - d = os.path.join(d, 'x86') +d = os.path.join(directory, "APTDLLPAck", "DLL") +if platform.architecture()[0] == "32bit": + d = os.path.join(d, "x86") else: - d = os.path.join(d, 'x64') -ns = ['APT.dll', 'APT.lib'] + d = os.path.join(d, "x64") +ns = ["APT.dll", "APT.lib"] for n in ns: destination = os.path.join(directory, n) if not os.path.isfile(destination): @@ -35,52 +35,51 @@ hardware_types = collections.OrderedDict() -hardware_types[11] = '1 Ch benchtop stepper driver' -hardware_types[12] = '1 Ch benchtop stepper driver' -hardware_types[13] = '2 Ch benchtop stepper driver' -hardware_types[14] = '1 Ch benchtop DC servo driver' -hardware_types[21] = '1 Ch stepper driver card (used within BSC102,103 units)' -hardware_types[22] = '1 Ch DC servo driver card (used within BDC102,103 units)' -hardware_types[24] = '1 Ch DC servo driver cube' -hardware_types[25] = '1 Ch stepper driver cube' -hardware_types[26] = '2 Ch modular stepper driver module' -hardware_types[29] = '1 Ch Stepper driver T-Cube' -hardware_types[31] = '1 Ch DC servo driver T-Cube' -hardware_types[42] = 'LTS300/LTS150 Long Travel Integrated Driver/Stages' -hardware_types[43] = 'L490MZ Integrated Driver/Labjack' -hardware_types[44] = '1/2/3 Ch benchtop brushless DC servo driver' +hardware_types[11] = "1 Ch benchtop stepper driver" +hardware_types[12] = "1 Ch benchtop stepper driver" +hardware_types[13] = "2 Ch benchtop stepper driver" +hardware_types[14] = "1 Ch benchtop DC servo driver" +hardware_types[21] = "1 Ch stepper driver card (used within BSC102,103 units)" +hardware_types[22] = "1 Ch DC servo driver card (used within BDC102,103 units)" +hardware_types[24] = "1 Ch DC servo driver cube" +hardware_types[25] = "1 Ch stepper driver cube" +hardware_types[26] = "2 Ch modular stepper driver module" +hardware_types[29] = "1 Ch Stepper driver T-Cube" +hardware_types[31] = "1 Ch DC servo driver T-Cube" +hardware_types[42] = "LTS300/LTS150 Long Travel Integrated Driver/Stages" +hardware_types[43] = "L490MZ Integrated Driver/Labjack" +hardware_types[44] = "1/2/3 Ch benchtop brushless DC servo driver" ### status codes ############################################################## status_codes = collections.OrderedDict() -status_codes[0] = 'stopped and disconnected' -status_codes[-2147478512] = 'moving' -status_codes[-2147479552] = 'stopped not homed' -status_codes[-2147478528] = 'stopped and homed' -status_codes[-2147478496] = '???' +status_codes[0] = "stopped and disconnected" +status_codes[-2147478512] = "moving" +status_codes[-2147479552] = "stopped not homed" +status_codes[-2147478528] = "stopped and homed" +status_codes[-2147478496] = "???" ### units codes ############################################################### units_codes = collections.OrderedDict() -units_codes[1] = 'mm' -units_codes[2] = 'deg' +units_codes[1] = "mm" +units_codes[2] = "deg" ### motor ##################################################################### -class APTMotor(): - +class APTMotor: def __init__(self, serial_number=None, hardware_type=None): self.serial_number = serial_number self.hardware_type = hardware_type # create dll - p = os.path.join(directory, 'APT.dll') - self.dll = ctypes.windll.LoadLibrary(str(p)) + p = os.path.join(directory, "APT.dll") + self.dll = ctypes.windll.LoadLibrary(str(p)) # initialize hardware self.dll.EnableEventDlg(True) self.dll.APTInit() @@ -91,7 +90,9 @@ def _get_hardware_information(self): model = ctypes.c_buffer(255) softwareVersion = ctypes.c_buffer(255) hardwareNotes = ctypes.c_buffer(255) - error = self.dll.GetHWInfo(serial_number, model, 255, softwareVersion, 255, hardwareNotes, 255) + error = self.dll.GetHWInfo( + serial_number, model, 255, softwareVersion, 255, hardwareNotes, 255 + ) return model.value, softwareVersion.value, hardwareNotes.value def _get_stage_axis_information(self): @@ -100,7 +101,13 @@ def _get_stage_axis_information(self): maximumPosition = ctypes.c_float() units = ctypes.c_long() pitch = ctypes.c_float() - error = self.dll.MOT_GetStageAxisInfo(serial_number, ctypes.pointer(minimumPosition), ctypes.pointer(maximumPosition), ctypes.pointer(units), ctypes.pointer(pitch)) + error = self.dll.MOT_GetStageAxisInfo( + serial_number, + ctypes.pointer(minimumPosition), + ctypes.pointer(maximumPosition), + ctypes.pointer(units), + ctypes.pointer(pitch), + ) return minimumPosition.value, maximumPosition.value, units.value, pitch.value def _get_velocity_parameters(self): @@ -108,14 +115,21 @@ def _get_velocity_parameters(self): minimumVelocity = ctypes.c_float() acceleration = ctypes.c_float() maximumVelocity = ctypes.c_float() - error = self.dll.MOT_GetVelParams(serial_number, ctypes.pointer(minimumVelocity), ctypes.pointer(acceleration), ctypes.pointer(maximumVelocity)) + error = self.dll.MOT_GetVelParams( + serial_number, + ctypes.pointer(minimumVelocity), + ctypes.pointer(acceleration), + ctypes.pointer(maximumVelocity), + ) return minimumVelocity.value, acceleration.value, maximumVelocity.value def _get_velocity_parameter_limits(self): serial_number = ctypes.c_long(self.serial_number) maximumAcceleration = ctypes.c_float() maximumVelocity = ctypes.c_float() - error = self.dll.MOT_GetVelParamLimits(serial_number, ctypes.pointer(maximumAcceleration), ctypes.pointer(maximumVelocity)) + error = self.dll.MOT_GetVelParamLimits( + serial_number, ctypes.pointer(maximumAcceleration), ctypes.pointer(maximumVelocity) + ) return maximumAcceleration.value, maximumVelocity.value def _set_velocity_parameters(self, minimum_velocity, acceleration, maximum_velocity): @@ -123,7 +137,9 @@ def _set_velocity_parameters(self, minimum_velocity, acceleration, maximum_veloc minimumVelocity = ctypes.c_float(minimum_velocity) acceleration = ctypes.c_float(acceleration) maximumVelocity = ctypes.c_float(maximum_velocity) - error = self.dll.MOT_SetVelParams(serial_number, minimumVelocity, acceleration, maximumVelocity) + error = self.dll.MOT_SetVelParams( + serial_number, minimumVelocity, acceleration, maximumVelocity + ) return error @property @@ -155,7 +171,7 @@ def go_home(self): serial_number = ctypes.c_long(self.serial_number) error = self.dll.MOT_MoveHome(serial_number, True) return error - + @property def maximum_acceleration(self): return self._get_velocity_parameter_limits()[0] @@ -197,7 +213,7 @@ def position(self): def set_acceleration(self, acceleration): if acceleration > self.maximum_acceleration: - raise ValueError('acceleration too large') + raise ValueError("acceleration too large") self._set_velocity_parameters(self.minimum_velocity, acceleration, self.maximum_velocity) def set_backlash_distance(self, distance): @@ -207,7 +223,7 @@ def set_backlash_distance(self, distance): return BLashDist.value def set_maximum_velocity(self, maximum_velocity): - self._set_velocity_parameters(self.minimum_velocity, self.acceleration, maximum_velocity) + self._set_velocity_parameters(self.minimum_velocity, self.acceleration, maximum_velocity) def set_minimum_velocity(self, minimum_velocity): self._set_velocity_parameters(minimum_velocity, self.acceleration, self.maximum_velocity) @@ -237,17 +253,17 @@ def units(self): ### testing ################################################################### -if __name__ == '__main__': +if __name__ == "__main__": motor = APTMotor(serial_number=45837036, hardware_type=42) - print('acceleration', motor.acceleration) - print('maximum_acceleration', motor.maximum_acceleration) - print('maximum_position', motor.maximum_position) - print('maximum_velocity', motor.maximum_velocity) - print('minimum_position', motor.minimum_position) - print('minimum_velocity', motor.minimum_velocity) - print('model', motor.model) - print('notes', motor.notes) - print('pitch', motor.pitch) - print('position', motor.position) - print('software_version', motor.software_version) - print('units', motor.units) + print("acceleration", motor.acceleration) + print("maximum_acceleration", motor.maximum_acceleration) + print("maximum_position", motor.maximum_position) + print("maximum_velocity", motor.maximum_velocity) + print("minimum_position", motor.minimum_position) + print("minimum_velocity", motor.minimum_velocity) + print("model", motor.model) + print("notes", motor.notes) + print("pitch", motor.pitch) + print("position", motor.position) + print("software_version", motor.software_version) + print("units", motor.units) diff --git a/library/zaber/binary.py b/library/zaber/binary.py index f648c364..d8cc0ed4 100644 --- a/library/zaber/binary.py +++ b/library/zaber/binary.py @@ -2,7 +2,7 @@ protocol. """ -#Changed from 'import serial' for PyCMDS +# Changed from 'import serial' for PyCMDS import project.com_handler as serial import struct import logging @@ -16,6 +16,7 @@ logger = logging.getLogger(__name__) logger.addHandler(logging.NullHandler()) + class BinaryCommand(object): """Models a single command in Zaber's Binary protocol. @@ -36,8 +37,8 @@ class BinaryCommand(object): .. _message ID: http://www.zaber.com/wiki/Manuals/Binary_Protocol_Ma nual#Set_Message_Id_Mode_-_Cmd_102 """ - def __init__(self, device_number, command_number, data = 0, - message_id = None): + + def __init__(self, device_number, command_number, data=0, message_id=None): """ Args: device_number: An integer specifying the number of the @@ -55,8 +56,7 @@ def __init__(self, device_number, command_number, data = 0, ValueError: An invalid value was passed. """ if device_number < 0 or command_number < 0: - raise ValueError("Device and command number must be between 0 " - "and 255.") + raise ValueError("Device and command number must be between 0 " "and 255.") self.device_number = device_number self.command_number = command_number self.data = data @@ -71,15 +71,14 @@ def encode(self): A byte string of length 6, formatted according to Zaber's `Binary Protocol Manual`_. """ - packed = struct.pack("<2Bl", - self.device_number, self.command_number, self.data) + packed = struct.pack("<2Bl", self.device_number, self.command_number, self.data) if self.message_id is not None: packed = packed[:5] + struct.pack("B", self.message_id) return packed def __str__(self): - return "[{:d}, {:d}, {:d}]".format(self.device_number, - self.command_number, self.data) + return "[{:d}, {:d}, {:d}]".format(self.device_number, self.command_number, self.data) + class BinaryDevice(object): """A class to represent a Zaber device in the Binary protocol. @@ -89,6 +88,7 @@ class BinaryDevice(object): this device is connected. number: The integer number of this device. 1-255. """ + def __init__(self, port, number): """ Args: @@ -147,16 +147,18 @@ def send(self, *args): command.device_number = self.number - #self.port._ser.external_lock_control = True + # self.port._ser.external_lock_control = True self.port._ser.lock() self.port.write(command) reply = self.port.read(command.message_id is not None) self.port._ser.unlock() - #self.port._ser.external_lock_control = False + # self.port._ser.external_lock_control = False if reply.device_number != self.number: - raise UnexpectedReplyError("Received an unexpected reply from " - "device number {0:d}".format(reply.device_number), - reply) + raise UnexpectedReplyError( + "Received an unexpected reply from " + "device number {0:d}".format(reply.device_number), + reply, + ) return reply def home(self): @@ -226,7 +228,7 @@ def get_status(self): ol_Manual#Return_Status_-_Cmd_54 """ return self.send(54).data - + ### Methods not included in Zaber provided Code def get_position(self): """Sends the "Return Current Position" command (60), and returns the @@ -241,8 +243,6 @@ def get_position(self): return self.send(60).data - - class BinaryReply(object): """Models a single reply in Zaber's Binary protocol. @@ -254,7 +254,8 @@ class BinaryReply(object): data: The data value associated with the reply. message_id: The message ID number, if present, otherwise None. """ - def __init__(self, reply, message_id = False): + + def __init__(self, reply, message_id=False): """ Args: reply: A byte string of length 6 containing a binary reply @@ -275,32 +276,33 @@ def __init__(self, reply, message_id = False): binary (ascii) string. """ if isinstance(reply, bytes): - self.device_number, self.command_number, self.data = \ - struct.unpack("<2Bl", reply) - if (message_id): + self.device_number, self.command_number, self.data = struct.unpack("<2Bl", reply) + if message_id: # Use bitmasks to extract the message ID. self.message_id = (self.data & 0xFF000000) >> 24 - self.data = self.data & 0x00FFFFFF - + self.data = self.data & 0x00FFFFFF + # Sign extend 24 to 32 bits in the message ID case. # If the data is more than 24 bits it will still be wrong, # but now negative smaller values will be right. if 0 != (self.data & 0x00800000): self.data = (int)((self.data | 0xFF000000) - (1 << 32)) - else: + else: self.message_id = None elif isinstance(reply, list): # Assume a 4th element is a message ID. - if len(reply) > 3: message_id = True + if len(reply) > 3: + message_id = True self.device_number = reply[0] self.command_number = reply[1] self.data = reply[2] self.message_id = reply[3] if message_id else None else: - raise TypeError("BinaryReply must be passed a byte string " - "('bytes' type) or a list.") + raise TypeError( + "BinaryReply must be passed a byte string " "('bytes' type) or a list." + ) def encode(self): """Returns the reply as a binary string, in the form in which it @@ -310,12 +312,11 @@ def encode(self): A byte string of length 6 formatted according to the Binary Protocol Manual. """ - return struct.pack("<2Bl", self.device_number, - self.command_number, self.data) + return struct.pack("<2Bl", self.device_number, self.command_number, self.data) def __str__(self): - return "[{:d}, {:d}, {:d}]".format(self.device_number, - self.command_number, self.data) + return "[{:d}, {:d}, {:d}]".format(self.device_number, self.command_number, self.data) + class BinarySerial(object): """A class for interacting with Zaber devices using the Binary protocol. @@ -324,7 +325,7 @@ class BinarySerial(object): from a device connected over the serial port. """ - def __init__(self, port, baud = 9600, timeout = 5, inter_char_timeout = 0.1): + def __init__(self, port, baud=9600, timeout=5, inter_char_timeout=0.1): """Creates a new instance of the BinarySerial class. Args: @@ -359,7 +360,9 @@ def __init__(self, port, baud = 9600, timeout = 5, inter_char_timeout = 0.1): self._ser.open() except AttributeError: # serial_for_url not supported; use fallback - self._ser = serial.Serial(port, baud, timeout = timeout*1000, interCharTimeout = inter_char_timeout) + self._ser = serial.Serial( + port, baud, timeout=timeout * 1000, interCharTimeout=inter_char_timeout + ) self._ser.external_lock_control = True def write(self, *args): @@ -403,8 +406,10 @@ def write(self, *args): elif 1 < len(args) < 5: message = BinaryCommand(*args) else: - raise TypeError("write() takes at least 1 and no more than 4 " - "arguments ({0:d} given)".format(len(args))) + raise TypeError( + "write() takes at least 1 and no more than 4 " + "arguments ({0:d} given)".format(len(args)) + ) if isinstance(message, str): logger.debug("> %s", message) @@ -413,21 +418,22 @@ def write(self, *args): # pyserial doesn't handle hex strings. if sys.version_info > (3, 0): - data = bytes(message, "UTF-8") + data = bytes(message, "UTF-8") else: - data = bytes(message) + data = bytes(message) elif isinstance(message, BinaryCommand): data = message.encode() logger.debug("> %s", message) else: - raise TypeError("write must be passed several integers, or a " - "string, list, or BinaryCommand.") + raise TypeError( + "write must be passed several integers, or a " "string, list, or BinaryCommand." + ) self._ser.write(data) - def read(self, message_id = False): + def read(self, message_id=False): """Reads six bytes from the port and returns a BinaryReply. Args: @@ -499,20 +505,23 @@ def baudrate(self): @baudrate.setter def baudrate(self, b): if b not in (115200, 57600, 38400, 19200, 9600): - raise ValueError("Invalid baud rate: {:d}. Valid baud rates are " - "115200, 57600, 38400, 19200, and 9600.".format(b)) + raise ValueError( + "Invalid baud rate: {:d}. Valid baud rates are " + "115200, 57600, 38400, 19200, and 9600.".format(b) + ) self._ser.baudrate = b - ### Additional Methods not in Zaber library def setMode(self, mode, device=0): - if isinstance(mode,str): - if mode=='computer': - mode=0x482e - elif mode=='manual': - mode=0x0827 + if isinstance(mode, str): + if mode == "computer": + mode = 0x482E + elif mode == "manual": + mode = 0x0827 else: - raise ValueError("Unkown mode string: {:s}. Valid strings are " - "'computer', 'manual'. Or input an integer".format(mode)) - self.write(device,40,mode) + raise ValueError( + "Unkown mode string: {:s}. Valid strings are " + "'computer', 'manual'. Or input an integer".format(mode) + ) + self.write(device, 40, mode) diff --git a/library/zaber/exceptions.py b/library/zaber/exceptions.py index f85e22b6..fb37acc2 100644 --- a/library/zaber/exceptions.py +++ b/library/zaber/exceptions.py @@ -2,14 +2,17 @@ this library. """ + class TimeoutError(Exception): """Raised when a read operation exceeded its specified time limit.""" + pass + class UnexpectedReplyError(Exception): """Raised when a reply was read from an unexpected device.""" - - def __init__(self, message, reply = None): + + def __init__(self, message, reply=None): """ Args: message: The error message to display. @@ -21,6 +24,5 @@ def __init__(self, message, reply = None): was thrown. You can access it through the *reply* attribute. """ super(UnexpectedReplyError, self).__init__(message) - - self.reply = reply + self.reply = reply diff --git a/project/classes.py b/project/classes.py index 075ff0c5..8f2ca0ba 100644 --- a/project/classes.py +++ b/project/classes.py @@ -17,57 +17,56 @@ class Mutex(QtCore.QMutex): - def __init__(self, initial_value=None): QtCore.QMutex.__init__(self) self.WaitCondition = QtCore.QWaitCondition() self.value = initial_value - + def read(self): return self.value - + def write(self, value): self.lock() self.value = value self.WaitCondition.wakeAll() self.unlock() - + def wait_for_update(self, timeout=5000): if self.value: self.lock() self.WaitCondition.wait(self, msecs=timeout) self.unlock() -class Busy(QtCore.QMutex): +class Busy(QtCore.QMutex): def __init__(self): - ''' + """ QMutex object to communicate between threads that need to wait \n while busy.read(): busy.wait_for_update() - ''' + """ QtCore.QMutex.__init__(self) self.WaitCondition = QtCore.QWaitCondition() self.value = False - self.type = 'busy' + self.type = "busy" self.update_signal = None def read(self): return self.value def write(self, value): - ''' + """ bool value - ''' + """ self.lock() self.value = value self.WaitCondition.wakeAll() self.unlock() def wait_for_update(self, timeout=5000): - ''' + """ wait in calling thread for any thread to call 'write' method \n int timeout in milliseconds - ''' + """ if self.value: self.lock() self.WaitCondition.wait(self, msecs=timeout) @@ -75,11 +74,10 @@ def wait_for_update(self, timeout=5000): class Data(QtCore.QMutex): - def __init__(self): QtCore.QMutex.__init__(self) self.WaitCondition = QtCore.QWaitCondition() - self.shape = (1, ) + self.shape = (1,) self.size = 1 self.channels = [] self.cols = [] @@ -88,25 +86,25 @@ def __init__(self): def read(self): return self.channels - + def read_properties(self): - ''' + """ Returns ------- tuple shape, cols, map - ''' + """ self.lock() outs = self.shape, self.cols, self.map self.unlock() return outs - + def write(self, channels): self.lock() self.channels = channels self.WaitCondition.wakeAll() self.unlock() - + def write_properties(self, shape, cols, channels, signed=False, map=None): self.lock() self.shape = shape @@ -131,11 +129,10 @@ def wait_for_update(self, timeout=5000): class Value(QtCore.QMutex): - def __init__(self, initial_value=None): - ''' + """ Basic QMutex object to hold a single object in a thread-safe way. - ''' + """ QtCore.QMutex.__init__(self) self.value = initial_value @@ -152,15 +149,25 @@ class PyCMDS_Object(QtCore.QObject): updated = QtCore.Signal() disabled = False - def __init__(self, initial_value=None, - ini=None, section='', option='', - import_from_ini=True, save_to_ini_at_shutdown=True, - display=False, name='', label = '', set_method=None, - disable_under_queue_control=False, - *args, **kwargs): + def __init__( + self, + initial_value=None, + ini=None, + section="", + option="", + import_from_ini=True, + save_to_ini_at_shutdown=True, + display=False, + name="", + label="", + set_method=None, + disable_under_queue_control=False, + *args, + **kwargs + ): QtCore.QObject.__init__(self) self.has_widget = False - self.tool_tip = '' + self.tool_tip = "" self.value = Value(initial_value) self.display = display self.set_method = set_method @@ -182,25 +189,24 @@ def __init__(self, initial_value=None, g.shutdown.add_method(self.save) # name self.name = name - if not label == '': + if not label == "": pass else: self.label = self.name # disable under module control if disable_under_queue_control: g.main_window.read().queue_control.connect(self.on_queue_control) - - def associate(self, display=None, pre_name=''): + + def associate(self, display=None, pre_name=""): # display if display is None: display = self.display # name name = pre_name + self.name # new object - new_obj = self.__class__(initial_value=self.read(), display=display, - name=name) + new_obj = self.__class__(initial_value=self.read(), display=display, name=name) return new_obj - + def on_queue_control(self): if g.queue_control.read(): if self.has_widget: @@ -231,10 +237,10 @@ def set_disabled(self, disabled): self.disabled = bool(disabled) if self.has_widget: self.widget.setDisabled(self.disabled) - + def setDisabled(self, disabled): self.set_disabled(disabled) - + def set_tool_tip(self, tool_tip): self.tool_tip = str(tool_tip) if self.has_widget: @@ -242,17 +248,16 @@ def set_tool_tip(self, tool_tip): class Bool(PyCMDS_Object): - ''' + """ holds 'value' (bool) - the state of the checkbox use read method to access - ''' + """ def __init__(self, initial_value=False, *args, **kwargs): - PyCMDS_Object.__init__(self, initial_value=initial_value, - *args, **kwargs) - self.type = 'checkbox' - + PyCMDS_Object.__init__(self, initial_value=initial_value, *args, **kwargs) + self.type = "checkbox" + def give_control(self, control_widget): self.widget = control_widget # set @@ -267,10 +272,9 @@ def give_control(self, control_widget): class Combo(PyCMDS_Object): - - def __init__(self, allowed_values=['None'], initial_value=None, *args, **kwargs): + def __init__(self, allowed_values=["None"], initial_value=None, *args, **kwargs): PyCMDS_Object.__init__(self, *args, **kwargs) - self.type = 'combo' + self.type = "combo" self.allowed_values = list(allowed_values) self.data_type = type(self.allowed_values[0]) if initial_value is None: @@ -278,17 +282,21 @@ def __init__(self, allowed_values=['None'], initial_value=None, *args, **kwargs) else: self.write(initial_value) - def associate(self, display=None, pre_name=''): + def associate(self, display=None, pre_name=""): # display if display is None: display = self.display # name name = pre_name + self.name # new object - new_obj = Combo(initial_value=self.read(), display=display, - allowed_values=self.allowed_values, name=name) + new_obj = Combo( + initial_value=self.read(), + display=display, + allowed_values=self.allowed_values, + name=name, + ) return new_obj - + def read_index(self): return self.allowed_values.index(self.read()) @@ -297,9 +305,9 @@ def save(self, value=None): self.value.write(value) if self.has_ini: self.ini.write(self.section, self.option, self.value.read(), with_apostrophe=True) - + def set_allowed_values(self, allowed_values): - ''' + """ Set the allowed values of the Combo object. Parameters @@ -311,7 +319,7 @@ def set_allowed_values(self, allowed_values): ---------- The value of the object is written to the first allowed value if the current value is not in the allowed values. - ''' + """ if allowed_values == self.allowed_values: return self.allowed_values = list(allowed_values) @@ -327,7 +335,7 @@ def set_allowed_values(self, allowed_values): self.write(list(self.allowed_values)[0]) else: self.write(self.read()) - + def set_widget(self): allowed_values_strings = [str(value) for value in self.allowed_values] index = allowed_values_strings.index(str(self.read())) @@ -337,7 +345,7 @@ def write(self, value): # value will be maintained as original data type value = self.data_type(value) PyCMDS_Object.write(self, value) - + def write_from_widget(self): # needs to be defined method so we can connect and disconnect self.write(self.widget.currentText()) @@ -348,7 +356,7 @@ def give_control(self, control_widget): allowed_values_strings = [str(value) for value in self.allowed_values] self.widget.addItems(allowed_values_strings) if self.read() is not None: - self.widget.setCurrentIndex(allowed_values_strings.index(str(self.read()))) + self.widget.setCurrentIndex(allowed_values_strings.index(str(self.read()))) # connect signals and slots self.updated.connect(self.set_widget) self.widget.currentIndexChanged.connect(self.write_from_widget) @@ -358,21 +366,19 @@ def give_control(self, control_widget): class Filepath(PyCMDS_Object): - - def __init__(self, caption='Open', directory=None, options=[], kind='file', - *args, **kwargs): - ''' + def __init__(self, caption="Open", directory=None, options=[], kind="file", *args, **kwargs): + """ holds the filepath as a string \n Kind one in {'file', 'directory'} - ''' + """ PyCMDS_Object.__init__(self, *args, **kwargs) - self.type = 'filepath' + self.type = "filepath" self.caption = caption self.directory = directory self.options = options self.kind = kind - + def give_control(self, control_widget): self.widget = control_widget if self.read() is not None: @@ -382,13 +388,14 @@ def give_control(self, control_widget): self.widget.setToolTip(str(self.read())) self.updated.connect(lambda: self.widget.setToolTip(self.read())) self.has_widget = True - + def give_button(self, button_widget): self.button = button_widget self.button.clicked.connect(self.on_load) - + def on_load(self): from project import file_dialog_handler + # directory if self.directory is not None: directory_string = self.directory @@ -398,14 +405,14 @@ def on_load(self): else: directory_string = g.main_dir.read() # filter - - if self.kind == 'file': - filter_string = ';;'.join(self.options + ['All Files (*.*)']) + + if self.kind == "file": + filter_string = ";;".join(self.options + ["All Files (*.*)"]) out = file_dialog_handler.open_dialog(self.caption, directory_string, filter_string) if os.path.isfile(out): self.write(out) - elif self.kind == 'directory': - out = file_dialog_handler.dir_dialog(self.caption, directory_string, '') + elif self.kind == "directory": + out = file_dialog_handler.dir_dialog(self.caption, directory_string, "") if os.path.isdir(out): self.write(out) @@ -423,42 +430,39 @@ def save(self, value=None): if value is not None: self.value.write(value) if self.has_ini: - out = str(self.value.read().replace('\\', '/')) + out = str(self.value.read().replace("\\", "/")) self.ini.write(self.section, self.option, out) class NumberLimits(PyCMDS_Object): - def __init__(self, min_value=-1e6, max_value=1e6, units=None): - ''' + """ not appropriate for use as a gui element - only for backend use units must never change for this kind of object - ''' + """ PyCMDS_Object.__init__(self) PyCMDS_Object.write(self, [min_value, max_value]) self.units = units - def read(self, output_units='same'): + def read(self, output_units="same"): min_value, max_value = PyCMDS_Object.read(self) - if output_units == 'same': + if output_units == "same": pass else: min_value = wt_units.converter(min_value, self.units, output_units) max_value = wt_units.converter(max_value, self.units, output_units) # ensure order - min_value, max_value = [min([min_value, max_value]), - max([min_value, max_value])] + min_value, max_value = [min([min_value, max_value]), max([min_value, max_value])] return [min_value, max_value] - def write(self, min_value, max_value, input_units='same'): - if input_units == 'same': + def write(self, min_value, max_value, input_units="same"): + if input_units == "same": pass else: min_value = wt_units.converter(min_value, input_units, self.units) max_value = wt_units.converter(max_value, input_units, self.units) # ensure order - min_value, max_value = [min([min_value, max_value]), - max([min_value, max_value])] + min_value, max_value = [min([min_value, max_value]), max([min_value, max_value])] PyCMDS_Object.write(self, [min_value, max_value]) self.updated.emit() @@ -466,11 +470,18 @@ def write(self, min_value, max_value, input_units='same'): class Number(PyCMDS_Object): units_updated = QtCore.Signal() - def __init__(self, initial_value=np.nan, single_step=1., decimals=3, - limits=None, units=None, *args, **kwargs): - PyCMDS_Object.__init__(self, initial_value=initial_value, - *args, **kwargs) - self.type = 'number' + def __init__( + self, + initial_value=np.nan, + single_step=1.0, + decimals=3, + limits=None, + units=None, + *args, + **kwargs + ): + PyCMDS_Object.__init__(self, initial_value=initial_value, *args, **kwargs) + self.type = "number" self.disabled_units = False self.single_step = single_step self.decimals = decimals @@ -499,26 +510,29 @@ def _set_limits(self): min_value = wt_units.converter(min_value, limits_units, self.units) max_value = wt_units.converter(max_value, limits_units, self.units) # ensure order - min_value, max_value = [min([min_value, max_value]), - max([min_value, max_value])] + min_value, max_value = [min([min_value, max_value]), max([min_value, max_value])] if self.has_widget: self.widget.setMinimum(min_value) self.widget.setMaximum(max_value) if not self.display: - self.set_tool_tip('min: ' + str(min_value) + '\n' + - 'max: ' + str(max_value)) + self.set_tool_tip("min: " + str(min_value) + "\n" + "max: " + str(max_value)) - def associate(self, display=None, pre_name=''): + def associate(self, display=None, pre_name=""): # display if display is None: display = self.display # name name = pre_name + self.name # new object - new_obj = Number(initial_value=self.read(), display=display, - units=self.units, limits=self.limits, - single_step=self.single_step, - decimals=self.decimals, name=name) + new_obj = Number( + initial_value=self.read(), + display=display, + units=self.units, + limits=self.limits, + single_step=self.single_step, + decimals=self.decimals, + name=name, + ) return new_obj def convert(self, destination_units): @@ -534,9 +548,9 @@ def convert(self, destination_units): self.units_updated.emit() self.updated.emit() - def read(self, output_units='same'): + def read(self, output_units="same"): value = PyCMDS_Object.read(self) - if output_units == 'same': + if output_units == "same": pass else: value = wt_units.converter(value, self.units, output_units) @@ -545,13 +559,13 @@ def read(self, output_units='same'): def set_control_steps(self, single_step=None, decimals=None): limits = [self.single_step, self.decimals] inputs = [single_step, decimals] - widget_methods = ['setSingleStep', 'setDecimals'] + widget_methods = ["setSingleStep", "setDecimals"] for i in range(len(limits)): - if not inputs[i] is None: - limits[i] = inputs[i] - if self.has_widget: - getattr(self.widget, widget_methods[i])(limits[i]) - + if not inputs[i] is None: + limits[i] = inputs[i] + if self.has_widget: + getattr(self.widget, widget_methods[i])(limits[i]) + def set_disabled_units(self, disabled): self.disabled_units = bool(disabled) if self.has_widget: @@ -568,10 +582,10 @@ def set_units(self, units): def set_widget(self): # special value text is displayed when widget is at minimum if np.isnan(self.value.read()): - self.widget.setSpecialValueText('nan') + self.widget.setSpecialValueText("nan") self.widget.setValue(self.widget.minimum()) else: - self.widget.setSpecialValueText('') + self.widget.setSpecialValueText("") self.widget.setValue(self.value.read()) def give_control(self, control_widget): @@ -600,12 +614,14 @@ def give_units_combo(self, units_combo_widget): # set current item self.units_widget.setCurrentIndex(unit_types.index(self.units)) # associate update with conversion - self.units_widget.currentIndexChanged.connect(lambda: self.convert(self.units_widget.currentText())) + self.units_widget.currentIndexChanged.connect( + lambda: self.convert(self.units_widget.currentText()) + ) # finish self.units_widget.setDisabled(self.disabled_units) - def write(self, value, input_units='same'): - if input_units == 'same': + def write(self, value, input_units="same"): + if input_units == "same": pass else: value = wt_units.converter(value, input_units, self.units) @@ -613,10 +629,9 @@ def write(self, value, input_units='same'): class String(PyCMDS_Object): - - def __init__(self, initial_value='', max_length=None, *args, **kwargs): + def __init__(self, initial_value="", max_length=None, *args, **kwargs): PyCMDS_Object.__init__(self, initial_value=initial_value, *args, **kwargs) - self.type = 'string' + self.type = "string" self.max_length = max_length def give_control(self, control_widget): @@ -630,13 +645,13 @@ def give_control(self, control_widget): self.widget.editingFinished.connect(lambda: self.write(str(self.widget.text()))) self.widget.setToolTip(self.tool_tip) self.has_widget = True - + def read(self): return str(PyCMDS_Object.read(self)) - + def write(self, value): if self.max_length is not None: - value = value[:self.max_length] + value = value[: self.max_length] self.value.write(value) self.updated.emit() @@ -648,7 +663,7 @@ class Driver(QtCore.QObject): update_ui = QtCore.Signal() queue_emptied = QtCore.Signal() initialized = Bool() - + def check_busy(self): """ Handles writing of busy to False. @@ -657,21 +672,21 @@ def check_busy(self): """ if self.is_busy(): if g.debug.read(): - print(self.name, ' busy') + print(self.name, " busy") time.sleep(0.01) # don't loop like crazy self.busy.write(True) elif self.enqueued.read(): if g.debug.read(): - print(self.name, ' not empty') + print(self.name, " not empty") print(self.enqueued.value) time.sleep(0.1) # don't loop like crazy self.busy.write(True) else: if g.debug.read(): - print(self.name, ' not busy') + print(self.name, " not busy") self.busy.write(False) self.update_ui.emit() - + @QtCore.Slot(str, list) def dequeue(self, method, inputs): """ @@ -685,21 +700,20 @@ def dequeue(self, method, inputs): method = str(method) # method passed as qstring args, kwargs = inputs if g.debug.read(): - print(self.name, ' dequeue:', method, inputs, self.busy.read()) + print(self.name, " dequeue:", method, inputs, self.busy.read()) self.enqueued.pop() - getattr(self, method)(*args, **kwargs) - if not self.enqueued.read(): + getattr(self, method)(*args, **kwargs) + if not self.enqueued.read(): if g.debug.read(): - print(self.name, ' queue empty') + print(self.name, " queue empty") self.queue_emptied.emit() self.check_busy() - + def is_busy(self): return False class Enqueued(QtCore.QMutex): - def __init__(self): """ Holds list of enqueued options. @@ -725,8 +739,7 @@ class Hardware(QtCore.QObject): update_ui = QtCore.Signal() initialized_signal = QtCore.Signal() - def __init__(self, driver_class, driver_arguments, gui_class, - name, model, serial=None): + def __init__(self, driver_class, driver_arguments, gui_class, name, model, serial=None): """ Hardware representation object living in the main thread. @@ -761,7 +774,7 @@ def __init__(self, driver_class, driver_arguments, gui_class, self.driver.update_ui.connect(self.update) self.busy.update_signal = self.driver.update_ui # initialize drivers - self.q.push('initialize') + self.q.push("initialize") # integrate close into PyCMDS shutdown self.shutdown_timeout = 30 # seconds g.shutdown.add_method(self.close) @@ -769,17 +782,15 @@ def __init__(self, driver_class, driver_arguments, gui_class, def close(self): # begin driver shutdown - self.q.push('close') + self.q.push("close") # wait for driver shutdown to complete start_time = time.time() - self.q.push('check_busy') + self.q.push("check_busy") while self.busy.read(): - if time.time()-start_time < self.shutdown_timeout: + if time.time() - start_time < self.shutdown_timeout: self.busy.wait_for_update() else: - g.logger.log('warning', - 'Wait until done timed out', - self.name) + g.logger.log("warning", "Wait until done timed out", self.name) break # quit thread self.thread.exit() @@ -803,7 +814,7 @@ def __init__(self, enqueued, busy, driver): self.busy = busy self.driver = driver super(Q, self).__init__() - #self.queue = QtCore.QMetaObject() + # self.queue = QtCore.QMetaObject() self.signal.connect(self.driver.dequeue, type=QtCore.Qt.QueuedConnection) def push(self, method, *args, **kwargs): diff --git a/project/com_handler.py b/project/com_handler.py index aec47876..37432347 100644 --- a/project/com_handler.py +++ b/project/com_handler.py @@ -28,39 +28,40 @@ class COM(QtCore.QMutex): - - def __init__(self, port, baud_rate, timeout, write_termination='\r\n', data='ASCII', size=-1, **kwargs): + def __init__( + self, port, baud_rate, timeout, write_termination="\r\n", data="ASCII", size=-1, **kwargs + ): QtCore.QMutex.__init__(self) self.port_index = port - self.instrument = serial.Serial(port,baud_rate,timeout=timeout, **kwargs) + self.instrument = serial.Serial(port, baud_rate, timeout=timeout, **kwargs) self.external_lock_control = False self.data = data self.write_termination = write_termination self.size = size g.shutdown.add_method(self.close) - def _read(self,size=None): - if self.data == 'pass': + def _read(self, size=None): + if self.data == "pass": if size == None: - size=1 + size = 1 return self.instrument.read(size) - elif self.data == 'ASCII': - buf = b'' + elif self.data == "ASCII": + buf = b"" char = self.instrument.read() - while char != b'': + while char != b"": buf = buf + char if buf.endswith(self.write_termination.encode()): buf = buf.rstrip(self.write_termination.encode()) - break; + break char = self.instrument.read() - return buf.decode('utf-8') + return buf.decode("utf-8") else: if self.size > 0: return [ord(i) for i in self.instrument.read(self.size)] else: - buf = b'' + buf = b"" char = self.instrument.read() - while char != b'': + while char != b"": buf = buf + char char = self.instrument.read() return [ord(i) for i in buf] @@ -70,54 +71,60 @@ def close(self): def open(self): self.instrument.open() - - def flush(self, then_delay=0.): - if not self.external_lock_control: self.lock() + + def flush(self, then_delay=0.0): + if not self.external_lock_control: + self.lock() self.instrument.flush() - if not self.external_lock_control: self.unlock() - + if not self.external_lock_control: + self.unlock() + def is_open(self): return self.instrument.isOpen() - + def read(self, size=None): - if not self.external_lock_control: self.lock() + if not self.external_lock_control: + self.lock() value = self._read(size) - if not self.external_lock_control: self.unlock() + if not self.external_lock_control: + self.unlock() return value - + def write(self, data, then_read=False): if not self.external_lock_control: self.lock() version = int(sys.version[0]) - if self.data == 'pass': + if self.data == "pass": value = self.instrument.write(data) - elif self.data == 'ASCII': + elif self.data == "ASCII": if version == 2: data = str(data) # just making sure value = self.instrument.write(data) if not data.endswith(self.write_termination.encode()): - value+=self.instrument.write(self.write_termination) + value += self.instrument.write(self.write_termination) else: - data = bytes(data, 'utf-8') + data = bytes(data, "utf-8") value = self.instrument.write(data) if not data.endswith(self.write_termination.encode()): - value+=self.instrument.write(self.write_termination.encode()) + value += self.instrument.write(self.write_termination.encode()) else: - value = self.instrument.write(''.join([chr(i) for i in data]))# Python3: bytes(data)) + value = self.instrument.write("".join([chr(i) for i in data])) # Python3: bytes(data)) if then_read: value = self._read() - if not self.external_lock_control: self.unlock() + if not self.external_lock_control: + self.unlock() return value ### helper methods ############################################################ - -def Serial(port,baud_rate=9600, timeout=1, **kwargs): + +def Serial(port, baud_rate=9600, timeout=1, **kwargs): """ Convience method for pass_through serial communication. """ - return get_com(port,baud_rate,timeout*1000,data='pass',**kwargs) + return get_com(port, baud_rate, timeout * 1000, data="pass", **kwargs) + def get_com(port, baud_rate=57600, timeout=1000, **kwargs): """ @@ -132,16 +139,16 @@ def get_com(port, baud_rate=57600, timeout=1000, **kwargs): creating_com.wait_for_update() creating_com.write(True) # return open com if already open - if isinstance(port,int): - port = "COM%d"%port + if isinstance(port, int): + port = "COM%d" % port out = None for key in open_coms.keys(): if key == port: out = open_coms[key] # otherwise open new com if not out: - out = COM(port, baud_rate, timeout/1000., **kwargs) - open_coms[port] = out + out = COM(port, baud_rate, timeout / 1000.0, **kwargs) + open_coms[port] = out # finish creating_com.write(False) return out diff --git a/project/file_dialog_handler.py b/project/file_dialog_handler.py index 34198380..48c3fdb5 100644 --- a/project/file_dialog_handler.py +++ b/project/file_dialog_handler.py @@ -1,6 +1,6 @@ -''' +""" QFileDialog objects can only be run in the main thread. -''' +""" ### imports ################################################################### @@ -27,13 +27,13 @@ class FileDialog(QtCore.QObject): update_ui = QtCore.Signal() queue_emptied = QtCore.Signal() - + def __init__(self, enqueued_object, busy_object): QtCore.QObject.__init__(self) - self.name = 'file_dialog' + self.name = "file_dialog" self.enqueued = enqueued_object self.busy = busy_object - + @QtCore.Slot(str, list) def dequeue(self, method, inputs): """ @@ -47,17 +47,17 @@ def dequeue(self, method, inputs): method = str(method) # method passed as qstring args, kwargs = inputs if g.debug.read(): - print(self.name, ' dequeue:', method, inputs, self.busy.read()) + print(self.name, " dequeue:", method, inputs, self.busy.read()) self.enqueued.pop() - getattr(self, method)(*args, **kwargs) - if not self.enqueued.read(): + getattr(self, method)(*args, **kwargs) + if not self.enqueued.read(): self.queue_emptied.emit() self.check_busy() - + def check_busy(self): - ''' + """ decides if the hardware is done and handles writing of 'busy' to False - ''' + """ # must always write busy whether answer is True or False if self.enqueued.read(): time.sleep(0.1) # don't loop like crazy @@ -65,29 +65,41 @@ def check_busy(self): else: self.busy.write(False) self.update_ui.emit() - + def clean(self, out): - ''' + """ takes the output and returns a string that has the properties I want - ''' + """ out = str(out) - out = out.replace('/', os.sep) + out = out.replace("/", os.sep) return out - + def getExistingDirectory(self, inputs=[]): caption, directory, options = inputs options = QtWidgets.QFileDialog.ShowDirsOnly - out = self.clean(QtWidgets.QFileDialog.getExistingDirectory(g.main_window.read(), caption, directory, options)) - directory_filepath.write(out) - + out = self.clean( + QtWidgets.QFileDialog.getExistingDirectory( + g.main_window.read(), caption, directory, options + ) + ) + directory_filepath.write(out) + def getOpenFileName(self, inputs=[]): caption, directory, options = inputs - out = self.clean(QtWidgets.QFileDialog.getOpenFileName(g.main_window.read(), caption, directory, options)[0]) + out = self.clean( + QtWidgets.QFileDialog.getOpenFileName( + g.main_window.read(), caption, directory, options + )[0] + ) open_filepath.write(out) - + def getSaveFileName(self, inputs=[]): caption, directory, savefilter, selectedfilter, options = inputs - out = self.clean(QtWidgets.QFileDialog.getSaveFileName(g.main_window.read(), caption, directory, savefilter, selectedfilter, options)[0]) + out = self.clean( + QtWidgets.QFileDialog.getSaveFileName( + g.main_window.read(), caption, directory, savefilter, selectedfilter, options + )[0] + ) save_filepath.write(out) @@ -102,12 +114,13 @@ def getSaveFileName(self, inputs=[]): # the q method only works between different threads # call directly if the calling object is in the main thread + def dir_dialog(caption, directory, options=None): inputs = [caption, directory, options] - if QtCore.QThread.currentThread() == g.main_thread.read(): + if QtCore.QThread.currentThread() == g.main_thread.read(): file_dialog.getExistingDirectory(inputs) else: - q.push('getExistingDirectory', inputs) + q.push("getExistingDirectory", inputs) while busy.read(): time.sleep(0.1) return directory_filepath.read() @@ -115,10 +128,10 @@ def dir_dialog(caption, directory, options=None): def open_dialog(caption, directory, options): inputs = [caption, directory, options] - if QtCore.QThread.currentThread() == g.main_thread.read(): + if QtCore.QThread.currentThread() == g.main_thread.read(): file_dialog.getOpenFileName(inputs) else: - q.push('getOpenFileName', inputs) + q.push("getOpenFileName", inputs) while busy.read(): time.sleep(0.1) return open_filepath.read() @@ -126,10 +139,10 @@ def open_dialog(caption, directory, options): def save_dialog(caption, directory, savefilter, selectedfilter, options): inputs = [caption, directory, savefilter, selectedfilter, options] - if QtCore.QThread.currentThread() == g.main_thread.read(): + if QtCore.QThread.currentThread() == g.main_thread.read(): file_dialog.getSaveFileName(inputs) else: - q.push('getSaveFileName', inputs) + q.push("getSaveFileName", inputs) while busy.read(): time.sleep(0.1) return save_filepath.read() diff --git a/project/ini_handler.py b/project/ini_handler.py index a43923c1..0bf41172 100644 --- a/project/ini_handler.py +++ b/project/ini_handler.py @@ -18,67 +18,60 @@ class Ini(QtCore.QMutex): - def __init__(self, filepath): QtCore.QMutex.__init__(self) self.filepath = filepath self.config = configparser.SafeConfigParser() self.return_raw = False - + def _do(self, operation, section, option, value, with_apostrophe): - ''' + """ put all interaction with ini file itself behind a 'busy' to make it a psuedo-Mutex. prevents bizzare race conditions that I don't understand DO NOT CALL THIS METHOD DIRECTLY! - ''' + """ self.lock() - if operation == 'read': + if operation == "read": self.config.read(self.filepath) raw = self.config.get(section, option, raw=False) self.unlock() - raw.replace('\\', '\\\\') + raw.replace("\\", "\\\\") if self.return_raw: return raw else: return ast.literal_eval(raw) - elif operation == 'write': + elif operation == "write": # ensure value is a string - value = str(value) - if with_apostrophe: - value = '\'' + value + '\'' + value = str(value) + if with_apostrophe: + value = "'" + value + "'" self.config.read(self.filepath) # update - self.config.set(section, option, value) + self.config.set(section, option, value) # save - with open(self.filepath, 'w') as configfile: + with open(self.filepath, "w") as configfile: self.config.write(configfile) self.unlock() def read(self, section, option): - return self._do('read', - section=section, - option=option, - value=None, - with_apostrophe=False) + return self._do("read", section=section, option=option, value=None, with_apostrophe=False) def write(self, section, option, value, with_apostrophe=False): if type(value) in [str] and not self.return_raw: - with_apostrophe = True - self._do('write', - section=section, - option=option, - value=value, - with_apostrophe=with_apostrophe) + with_apostrophe = True + self._do( + "write", section=section, option=option, value=value, with_apostrophe=with_apostrophe + ) ### shared inis initialized here ############################################## -main = Ini(os.path.join(main_dir, 'main.ini')) -config = Ini(os.path.join(main_dir, 'config.ini')) -daq = Ini(os.path.join(main_dir, 'devices', 'devices.ini')) -opas = Ini(os.path.join(main_dir, 'hardware', 'opas', 'opas.ini')) -filters = Ini(os.path.join(main_dir, 'hardware', 'filters', 'filters.ini')) -spectrometers = Ini(os.path.join(main_dir, 'hardware', 'spectrometers', 'spectrometers.ini')) +main = Ini(os.path.join(main_dir, "main.ini")) +config = Ini(os.path.join(main_dir, "config.ini")) +daq = Ini(os.path.join(main_dir, "devices", "devices.ini")) +opas = Ini(os.path.join(main_dir, "hardware", "opas", "opas.ini")) +filters = Ini(os.path.join(main_dir, "hardware", "filters", "filters.ini")) +spectrometers = Ini(os.path.join(main_dir, "hardware", "spectrometers", "spectrometers.ini")) diff --git a/project/kit.py b/project/kit.py index 950b8923..d87fc9d6 100644 --- a/project/kit.py +++ b/project/kit.py @@ -1,6 +1,6 @@ -''' +""" a collection of small, general purpose objects and methods -''' +""" ### import #################################################################### @@ -12,12 +12,18 @@ ### math ###################################################################### -def grating_linear_dispersion(spec_inclusion_angle, spec_focal_length, - spec_focal_length_tilt, spec_grooves_per_mm, - spec_central_wavelength, spec_order, - number_of_pixels, - pixel_width, calibration_pixel): - ''' +def grating_linear_dispersion( + spec_inclusion_angle, + spec_focal_length, + spec_focal_length_tilt, + spec_grooves_per_mm, + spec_central_wavelength, + spec_order, + number_of_pixels, + pixel_width, + calibration_pixel, +): + """ Parameters ---------- spec_inclusion_angle : float @@ -43,32 +49,47 @@ def grating_linear_dispersion(spec_inclusion_angle, spec_focal_length, ------- np.ndarray Color found on each pixel (nm) - ''' + """ # translate inputs into appropriate internal units spec_inclusion_angle_rad = np.radians(spec_inclusion_angle) spec_focal_length_tilt_rad = np.radians(spec_focal_length_tilt) - pixel_width_mm = pixel_width/1e3 + pixel_width_mm = pixel_width / 1e3 # create array i_pixel = np.arange(number_of_pixels) # calculate terms - x = np.arcsin((1e-6*spec_order*spec_grooves_per_mm*spec_central_wavelength)/(2*np.cos(spec_inclusion_angle_rad/2.))) - A = np.sin(x-spec_inclusion_angle_rad/2) - B = np.sin((spec_inclusion_angle_rad)+x-(spec_inclusion_angle_rad/2)- - np.arctan((pixel_width_mm*(i_pixel-calibration_pixel)+spec_focal_length*spec_focal_length_tilt_rad)/(spec_focal_length*np.cos(spec_focal_length_tilt_rad)))) - out = ((A+B)*1e6)/(spec_order*spec_grooves_per_mm) + x = np.arcsin( + (1e-6 * spec_order * spec_grooves_per_mm * spec_central_wavelength) + / (2 * np.cos(spec_inclusion_angle_rad / 2.0)) + ) + A = np.sin(x - spec_inclusion_angle_rad / 2) + B = np.sin( + (spec_inclusion_angle_rad) + + x + - (spec_inclusion_angle_rad / 2) + - np.arctan( + ( + pixel_width_mm * (i_pixel - calibration_pixel) + + spec_focal_length * spec_focal_length_tilt_rad + ) + / (spec_focal_length * np.cos(spec_focal_length_tilt_rad)) + ) + ) + out = ((A + B) * 1e6) / (spec_order * spec_grooves_per_mm) return out - + + ### testing ################################################################### -if __name__ == '__main__': - arr = grating_linear_dispersion(spec_inclusion_angle=24., - spec_focal_length=140., - spec_focal_length_tilt=0., - spec_grooves_per_mm=300., - spec_central_wavelength=1300., - spec_order=1, - number_of_pixels=256, - pixel_width=50., - calibration_pixel=100) +if __name__ == "__main__": + arr = grating_linear_dispersion( + spec_inclusion_angle=24.0, + spec_focal_length=140.0, + spec_focal_length_tilt=0.0, + spec_grooves_per_mm=300.0, + spec_central_wavelength=1300.0, + spec_order=1, + number_of_pixels=256, + pixel_width=50.0, + calibration_pixel=100, + ) print(arr[100]) - diff --git a/project/logging_handler.py b/project/logging_handler.py index 37591e37..f113894f 100644 --- a/project/logging_handler.py +++ b/project/logging_handler.py @@ -1,4 +1,4 @@ -#import######################################################################### +# import######################################################################### import os import time @@ -8,128 +8,156 @@ from PySide2 import QtCore -#import packages.psutil as psutil #why doesn't this work!?!?! +# import packages.psutil as psutil #why doesn't this work!?!?! import psutil from project import project_globals as g + app = g.app.read() - -#cpu watcher#################################################################### + +# cpu watcher#################################################################### + class busy(QtCore.QMutex): def __init__(self): QtCore.QMutex.__init__(self) self.WaitCondition = QtCore.QWaitCondition() self.value = False + def read(self): return self.value + def write(self, value): self.lock() self.value = value self.WaitCondition.wakeAll() self.unlock() + def wait_for_update(self): if self.value: self.lock() self.WaitCondition.wait(self) self.unlock() + + busy = busy() + class cpu(QtCore.QMutex): def __init__(self): QtCore.QMutex.__init__(self) self.WaitCondition = QtCore.QWaitCondition() - self.value = '??' + self.value = "??" + def read(self): return self.value + def write(self, value): self.lock() self.value = value self.WaitCondition.wakeAll() self.unlock() + def wait_for_update(self): if self.value: self.lock() self.WaitCondition.wait(self) self.unlock() + + cpu = cpu() -class cpu_watcher(QtCore.QObject): +class cpu_watcher(QtCore.QObject): @QtCore.Slot() def get_cpu(self): pass busy.write(True) - cpu_now = psutil.cpu_percent(interval = 1) + cpu_now = psutil.cpu_percent(interval=1) cpu.write(cpu_now) - time.sleep(1) #not meant to loop quickly + time.sleep(1) # not meant to loop quickly busy.write(False) + cpu_thread = QtCore.QThread() - + + def begin_cpu_watcher(): - - #begin cpu_watcher object in seperate thread + + # begin cpu_watcher object in seperate thread g.shutdown.add_method(cpu_thread.quit) - cpu_obj = cpu_watcher() + cpu_obj = cpu_watcher() cpu_obj.moveToThread(cpu_thread) caller = QtCore.QMetaObject() + def call_cpu_watcher(): - if not busy.read(): caller.invokeMethod(cpu_obj, 'get_cpu') + if not busy.read(): + caller.invokeMethod(cpu_obj, "get_cpu") g.poll_timer.connect_to_timeout(call_cpu_watcher) cpu_thread.start() - + g.shutdown.read().connect(cpu_thread.quit) - -#logger######################################################################### -#filepath -filepath = os.path.join(g.main_dir.read(), 'logs', str(time.strftime('%Y.%m.%d %H.%M.%S'))+'.log') -log_file = open(filepath, 'w') + +# logger######################################################################### + +# filepath +filepath = os.path.join( + g.main_dir.read(), "logs", str(time.strftime("%Y.%m.%d %H.%M.%S")) + ".log" +) +log_file = open(filepath, "w") log_file.close() -#setup -logger = logging.getLogger('PyCMDS') -formatter = logging.Formatter(fmt='%(asctime)s.%(msecs).03d | CPU %(cpu)-2s RAM %(ram)-2s | %(levelname)-8s | Thread %(thread)-5s | %(origin)-20s | %(name)-20s | %(message)s',datefmt='%Y.%m.%d %H:%M:%S') +# setup +logger = logging.getLogger("PyCMDS") +formatter = logging.Formatter( + fmt="%(asctime)s.%(msecs).03d | CPU %(cpu)-2s RAM %(ram)-2s | %(levelname)-8s | Thread %(thread)-5s | %(origin)-20s | %(name)-20s | %(message)s", + datefmt="%Y.%m.%d %H:%M:%S", +) + +# set level +if g.debug.read(): + logger.setLevel(logging.DEBUG) # default is info -#set level -if g.debug.read(): logger.setLevel(logging.DEBUG) #default is info class ContextFilter(logging.Filter): - def __init__(self, origin, name): self.origin = origin self.name = name - + def filter(self, record): record.thread = threading.current_thread().ident record.origin = self.origin record.name = self.name cpu_now = cpu.read() - if cpu_now == '??': record.cpu = cpu_now - else: record.cpu = str(int(cpu.read())).zfill(2) + if cpu_now == "??": + record.cpu = cpu_now + else: + record.cpu = str(int(cpu.read())).zfill(2) record.ram = str(int(psutil.swap_memory().percent)).zfill(2) return True -def log(level, name, message = '', origin = 'name'): - ''' + +def log(level, name, message="", origin="name"): + """ logging method for PyCMDS accepts strings levels: debug, info, warning, error, critical - ''' - #open + """ + # open handler = logging.FileHandler(filepath) handler.setFormatter(formatter) logger.addHandler(handler) - #additional context - if origin == 'name': origin = str(inspect.stack()[2][1]).split('\\')[-1].replace('.py', '') + # additional context + if origin == "name": + origin = str(inspect.stack()[2][1]).split("\\")[-1].replace(".py", "") logger.addFilter(ContextFilter(origin, name)) - - #log + + # log getattr(logger, level)(message) - #close + # close logger.removeHandler(handler) handler.close() diff --git a/project/project_globals.py b/project/project_globals.py index b5d4dcbc..f494e6e7 100644 --- a/project/project_globals.py +++ b/project/project_globals.py @@ -5,81 +5,111 @@ ### global classes ############################################################ + class SimpleGlobal: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value -class GlobalWithIni(): + +class GlobalWithIni: def __init__(self, ini, section, option): self.ini = ini self.section = section self.option = option self.get_saved() + def read(self): return self.value + def write(self, value): self.value = value + def get_saved(self): self.value = self.ini.read(self.section, self.option) return self.value - def save(self, value = None): - if not value == None: self.value = value + + def save(self, value=None): + if not value == None: + self.value = value self.ini.write(self.section, self.option, self.value) + ### order sensitive globals ################################################## + class main_dir: def __init__(self): import os + self.value = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, self.value) + def read(self): return self.value + def write(self, value): self.value = str(value) + + main_dir = main_dir() -import project.ini_handler as ini #must come after main_dir has been defined +import project.ini_handler as ini # must come after main_dir has been defined + +debug = GlobalWithIni(ini.config, "main", "debug") -debug = GlobalWithIni(ini.config, 'main', 'debug') class PollTimer: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value + def connect_to_timeout(self, slot): QtWidgets.QAction.connect(self.value, QtCore.SIGNAL("timeout()"), slot) + + poll_timer = PollTimer() slack_poll_timer = PollTimer() -class logger: #must come before other globals + +class logger: # must come before other globals def __init__(self): pass + def load(self): import project.logging_handler as logging_handler + self.value = logging_handler.log - if debug.read(): self.log('info', 'Debug', 'PyCMDS is in debug mode') - if offline.read(): self.log('info', 'Offline', 'PyCMDS is offline') - def log(self, level, name, message = '', origin = 'name'): - ''' + if debug.read(): + self.log("info", "Debug", "PyCMDS is in debug mode") + if offline.read(): + self.log("info", "Offline", "PyCMDS is offline") + + def log(self, level, name, message="", origin="name"): + """ wrapper of logging method for PyCMDS accepts strings levels: debug, info, warning, error, critical - ''' + """ self.value(level, name, message, origin) + + logger = logger() ### other globals ############################################################# -#alphabetical +# alphabetical app = SimpleGlobal() @@ -89,31 +119,46 @@ def log(self, level, name, message = '', origin = 'name'): coset_widget = SimpleGlobal() + class daq_widget: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value + + daq_widget = daq_widget() + class daq_array_widget: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value + + daq_array_widget = daq_array_widget() + class daq_plot_widget: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value + + daq_plot_widget = daq_plot_widget() hardware_advanced_box = SimpleGlobal() @@ -125,80 +170,111 @@ def write(self, value): google_drive_enabled = SimpleGlobal() + class hardware_waits: def __init__(self): - ''' + """ holds value, a list of hardware wait_until_still methods - ''' + """ self.value = [] + def add(self, method): self.value.append(method) + def give_coset_control(self, control): self.coset_control = control + def wait(self, coset=True): if coset: self.coset_control.launch() for method in self.value: method() + + hardware_waits = hardware_waits() + class hardware_widget: def __init__(self): self.value = None self.number_of_widgets = 0 + def read(self): return self.value + def write(self, value): self.value = value self.value.setLayout(QtWidgets.QVBoxLayout()) self.value.layout().setMargin(5) self.value.layout().addStretch(1) + def add_to(self, widget): self.value.layout().takeAt(self.number_of_widgets) self.value.layout().addWidget(widget) self.number_of_widgets += 1 self.value.layout().addStretch(1) + + hardware_widget = hardware_widget() + class main_thread: def __init__(self): self.value = QtCore.QThread.currentThread() + def read(self): return self.value + def write(self, value): self.value = str(value) + + main_thread = main_thread() + class main_window: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value + + main_window = main_window() + class module_advanced_widget: def __init__(self): self.value = None self.child = None + def read(self): return self.value + def write(self, value): self.value = value + def add_child(self, widget): self.value.setLayout(QtWidgets.QVBoxLayout()) self.child = widget self.value.layout().setMargin(0) self.value.layout().addWidget(self.child) + + module_advanced_widget = module_advanced_widget() + class QueueControl(QtCore.QObject): def __init__(self): self.value = None self.widgets_to_disable = [] + def read(self): return self.value + def write(self, value): for widget in self.widgets_to_disable: try: @@ -208,83 +284,111 @@ def write(self, value): self.widgets_to_disable.remove(widget) self.value = value main_window.read().queue_control.emit() + def disable_when_true(self, widget): self.widgets_to_disable.append(widget) + + queue_control = QueueControl() -offline = GlobalWithIni(ini.config, 'main', 'offline') +offline = GlobalWithIni(ini.config, "main", "offline") + class progress_bar: def __init__(self): self.value = None + def write(self, value): self.value = value + def give_time_display_elements(self, time_elapsed, time_remaining): self.time_elapsed = time_elapsed self.time_remaining = time_remaining + def begin_new_scan_timer(self): self.start_time = time.time() + def set_fraction(self, fraction): - self.value.setValue(fraction*100) - #time elapsed + self.value.setValue(fraction * 100) + # time elapsed time_elapsed = time.time() - self.start_time m, s = divmod(time_elapsed, 60) h, m = divmod(m, 60) - self.time_elapsed.setText('%02d:%02d:%02d' % (h, m, s)) - #time remaining + self.time_elapsed.setText("%02d:%02d:%02d" % (h, m, s)) + # time remaining if fraction == 0: - self.time_remaining.setText('??:??:??') + self.time_remaining.setText("??:??:??") else: time_remaining = (time_elapsed / fraction) - time_elapsed m, s = divmod(time_remaining, 60) h, m = divmod(m, 60) - self.time_remaining.setText('%02d:%02d:%02d' % (h, m, s)) + self.time_remaining.setText("%02d:%02d:%02d" % (h, m, s)) + + progress_bar = progress_bar() + class scan_thread: def __init__(self): self.value = None + def read(self): return self.value + def write(self, value): self.value = value + + scan_thread = scan_thread() + class shutdown: - ''' + """ holds the reference of MainWindow.shutdown Qt signal during startup, add your shutdown method to this object using the 'add_method' method it will be called upon shutdown. your method must not have any arguments - ''' + """ + def __init__(self): self.value = False self.methods = [] + def read(self): return self.value + def write(self, value): self.value = value + def add_method(self, method): self.methods.append(method) + def fire(self): for method in self.methods: method() main_window.read().close() + + shutdown = shutdown() slack_control = SimpleGlobal() slack_enabled = SimpleGlobal() -system_name = GlobalWithIni(ini.config, 'main', 'system name') +system_name = GlobalWithIni(ini.config, "main", "system name") + class UseArray: def __init__(self): self.value = False + def read(self): return self.value + def write(self, value): self.value = value + + use_array = UseArray() version = SimpleGlobal() diff --git a/project/slack/__init__.py b/project/slack/__init__.py index 67ce6ae9..9acbef9d 100644 --- a/project/slack/__init__.py +++ b/project/slack/__init__.py @@ -1,2 +1,3 @@ from . import slack + control = slack.control diff --git a/project/slack/bots.py b/project/slack/bots.py index 09523fb5..1e68699d 100644 --- a/project/slack/bots.py +++ b/project/slack/bots.py @@ -1,50 +1,53 @@ -#Slack implementation for pyCMDS +# Slack implementation for pyCMDS import os import sys import time import project.project_globals as g + main_dir = g.main_dir.read() # make ini from project.ini_handler import Ini -ini_path = os.path.join(main_dir, 'project', 'slack', 'bots.ini') + +ini_path = os.path.join(main_dir, "project", "slack", "bots.ini") ini = Ini(ini_path) from slacker.__init__ import Slacker from .rtmbot import RtmBot -team_creation = ini.read('bots','team_creation') -debug = ini.read("bots","DEBUG") -default_channel = ini.read("bots","CHANNEL") -witch_token = ini.read('bots',"Token") +team_creation = ini.read("bots", "team_creation") +debug = ini.read("bots", "DEBUG") +default_channel = ini.read("bots", "CHANNEL") +witch_token = ini.read("bots", "Token") + class PyCMDS_bot(object): - def __init__(self,token): + def __init__(self, token): self.slacker = Slacker(token) self.rtmbot = RtmBot(token) self.rtmbot.connect() - #These values should be read from an ini file. + # These values should be read from an ini file. self.channel = default_channel self.last_ping = 0 try: self.check = self._check_channel() except: print("Something is seriously wrong with the called slackerbot. DO NOT USE THIS BOT!!") - #try: + # try: if not self.check: print("The default channel does not exist. Better fix that.") self.channel = None else: pass - #self.users.set_active() + # self.users.set_active() hello = [] while hello == []: hello = self.rtmbot.rtm_read() - time.sleep(.01) + time.sleep(0.01) - def _check_channel(self,channel=None): + def _check_channel(self, channel=None): if not channel: channel = self.channel try: @@ -53,20 +56,20 @@ def _check_channel(self,channel=None): except: return False - def _filter_messages(self,messages): + def _filter_messages(self, messages): mess = [] for i in messages: - if 'type' in i: - if i['type']=='message': - pm = i["channel"].startswith('D') - if i.get("text", "").startswith('<@U0EALA010>'): - i["text"] = i["text"].split('>',1)[1] + if "type" in i: + if i["type"] == "message": + pm = i["channel"].startswith("D") + if i.get("text", "").startswith("<@U0EALA010>"): + i["text"] = i["text"].split(">", 1)[1] mess.append(i) elif pm: mess.append(i) return mess - def get_messages(self, newer_than = 60): + def get_messages(self, newer_than=60): """ Gets messages, returns [[message,timestamp,channel,user],..]. All elements are str. The messages are only returned if they start with a mention of witch followed by a space. @@ -79,8 +82,7 @@ def get_messages(self, newer_than = 60): messages = self._filter_messages(messages) return messages - - def send_message(self,text,channel=None,attachments=[]): + def send_message(self, text, channel=None, attachments=[]): """ text: string to post. attachemnts: list of attachment dictionaries, see slack api for more info. @@ -93,23 +95,30 @@ def send_message(self,text,channel=None,attachments=[]): channel_object = self.rtmbot.slack_client.server.channels.find(channel) try: if attachments == []: - message = text.encode('ascii', 'ignore') + message = text.encode("ascii", "ignore") channel_object.send_message("{}".format(text)) else: - self.slacker.chat.post_message(channel, text, attachments=attachments, as_user=True) + self.slacker.chat.post_message( + channel, text, attachments=attachments, as_user=True + ) return True except: - print("Message not posted: chat.post_message gave an error. Sorry buddy. :", sys.exc_info()[0]) + print( + "Message not posted: chat.post_message gave an error. Sorry buddy. :", + sys.exc_info()[0], + ) return False - def upload_file(self,file_path,Title=None,first_comment=None,channel=None): + def upload_file(self, file_path, Title=None, first_comment=None, channel=None): """ Uploads a file. Pretty self explanitory. """ if channel == None: channel = self.channel if self._check_channel(channel): - upload_ok = self.slacker.files.upload(file_path,title=Title,initial_comment=first_comment,channels=[channel]).body['ok'] + upload_ok = self.slacker.files.upload( + file_path, title=Title, initial_comment=first_comment, channels=[channel] + ).body["ok"] return upload_ok else: print("File not uploaded: Channel.info gave an error. Sorry bucko.") @@ -120,32 +129,36 @@ def delete_files(self): Deletes files older than 90 days, then deletes old files unitl there is 1 GB space remaining. Returns the total space used if it all comes out ok and False otherwise. """ - old = time.time()+90*24*60*60 + old = time.time() + 90 * 24 * 60 * 60 file_ask = self.slacker.files.list(ts_to=old).body - if file_ask['ok']: + if file_ask["ok"]: old = file_ask["files"] # it will try 3 times to remove each file, then give up if it hasn't finished. for i in range(3): for f in old: - if not f['is_starred']: - if self.slacker.files.delete(f["id"]).body['ok']: + if not f["is_starred"]: + if self.slacker.files.delete(f["id"]).body["ok"]: old.remove(f) fl_info = self.slacker.files.list(count=1000).body - all_files = fl_info['files'] - for idx in range(fl_info['paging']['pages']-1): - all_files.extend(self.slacker.files.list(ts_to=all_files[-1]['created'],count=1000)['files'][1:]) - space_used = sum([f['size'] for f in all_files]) + all_files = fl_info["files"] + for idx in range(fl_info["paging"]["pages"] - 1): + all_files.extend( + self.slacker.files.list(ts_to=all_files[-1]["created"], count=1000)["files"][ + 1: + ] + ) + space_used = sum([f["size"] for f in all_files]) if space_used > 4 * 10 ^ 9: - to_del=[] + to_del = [] idx = -1 while space_used > 4 * 10 ^ 9: - if not all_files[idx]['is_starred']: - to_del.append(all_files[idx]['id']) - space_used = space_used - all_files[idx]['size'] - idx = idx-1 + if not all_files[idx]["is_starred"]: + to_del.append(all_files[idx]["id"]) + space_used = space_used - all_files[idx]["size"] + idx = idx - 1 for i in range(3): for f in to_del: - if self.slacker.files.delete(f).body['ok']: + if self.slacker.files.delete(f).body["ok"]: to_del.remove(f) if to_del: return False @@ -155,14 +168,15 @@ def delete_files(self): return False def sign_off(self): - 'Use to signal that PyCMDS is shutting down.' + "Use to signal that PyCMDS is shutting down." self.send_message("Picosecond system signing off.") + witch = PyCMDS_bot(witch_token) -''' +""" g = [] for i in range(100): g.extend(witch.get_messages()) witch.rtmbot.autoping() time.sleep(.5) -''' +""" diff --git a/project/slack/rtmbot.py b/project/slack/rtmbot.py index 986f6155..c13aa843 100644 --- a/project/slack/rtmbot.py +++ b/project/slack/rtmbot.py @@ -1,6 +1,7 @@ #!/usr/bin/env python import sys + sys.dont_write_bytecode = True import glob @@ -13,49 +14,58 @@ from slackclient import SlackClient from project.ini_handler import Ini import project.project_globals as g + main_dir = g.main_dir.read() # make ini -ini_path = os.path.join(main_dir, 'project', 'slack', 'bots.ini') +ini_path = os.path.join(main_dir, "project", "slack", "bots.ini") ini = Ini(ini_path) # read from ini -debug = ini.read("bots","DEBUG") == "True" -default_channel = ini.read("bots","CHANNEL") -witch_token = ini.read('bots',"Token") -team_creation = ini.read('bots', 'team_creation') +debug = ini.read("bots", "DEBUG") == "True" +default_channel = ini.read("bots", "CHANNEL") +witch_token = ini.read("bots", "Token") +team_creation = ini.read("bots", "team_creation") + def dbg(debug_string): if debug: logging.info(debug_string) + class RtmBot(object): def __init__(self, token): self.last_ping = 0 self.token = token self.bot_plugins = [] self.slack_client = None + def connect(self): """Convenience method that creates Server instance""" self.slack_client = SlackClient(self.token) self.slack_client.rtm_connect() + def start(self): self.connect() self.load_plugins() + def run_plugins(self): for reply in self.rtm_read(): self.input(reply) self.crons() self.output() self.autoping() + def rtm_read(self): return self.slack_client.rtm_read() + def autoping(self): - #hardcode the interval to 3 seconds + # hardcode the interval to 3 seconds now = int(time.time()) if now > self.last_ping + 3: self.slack_client.server.ping() self.last_ping = now + def input(self, data): if "type" in data: function_name = "process_" + data["type"] @@ -63,6 +73,7 @@ def input(self, data): for plugin in self.bot_plugins: plugin.register_jobs() plugin.do(function_name, data) + def output(self): for plugin in self.bot_plugins: limiter = False @@ -70,23 +81,28 @@ def output(self): channel = self.slack_client.server.channels.find(output[0]) if channel != None and output[1] != None: if limiter == True: - time.sleep(.1) + time.sleep(0.1) limiter = False - message = output[1].encode('ascii','ignore') + message = output[1].encode("ascii", "ignore") channel.send_message("{}".format(message)) limiter = True + def crons(self): for plugin in self.bot_plugins: plugin.do_jobs() + def load_plugins(self): - for plugin in glob.glob(directory+'/plugins/*'): + for plugin in glob.glob(directory + "/plugins/*"): sys.path.insert(0, plugin) - sys.path.insert(0, directory+'/plugins/') - for plugin in glob.glob(directory+'/plugins/*.py') + glob.glob(directory+'/plugins/*/*.py'): + sys.path.insert(0, directory + "/plugins/") + for plugin in glob.glob(directory + "/plugins/*.py") + glob.glob( + directory + "/plugins/*/*.py" + ): logging.info(plugin) - name = plugin.split('/')[-1][:-3] + name = plugin.split("/")[-1][:-3] self.bot_plugins.append(Plugin(name)) + class Plugin(object): def __init__(self, name, plugin_config={}): self.name = name @@ -97,38 +113,42 @@ def __init__(self, name, plugin_config={}): if name in config: logging.info("config found for: " + name) self.module.config = config[name] - if 'setup' in dir(self.module): + if "setup" in dir(self.module): self.module.setup() + def register_jobs(self): - if 'crontable' in dir(self.module): + if "crontable" in dir(self.module): for interval, function in self.module.crontable: - self.jobs.append(Job(interval, eval("self.module."+function))) + self.jobs.append(Job(interval, eval("self.module." + function))) logging.info(self.module.crontable) self.module.crontable = [] else: self.module.crontable = [] + def do(self, function_name, data): if function_name in dir(self.module): - #this makes the plugin fail with stack trace in debug mode + # this makes the plugin fail with stack trace in debug mode if not debug: try: - eval("self.module."+function_name)(data) + eval("self.module." + function_name)(data) except: dbg("problem in module {} {}".format(function_name, data)) else: - eval("self.module."+function_name)(data) + eval("self.module." + function_name)(data) if "catch_all" in dir(self.module): try: self.module.catch_all(data) except: dbg("problem in catch all") + def do_jobs(self): for job in self.jobs: job.check() + def do_output(self): output = [] while True: - if 'outputs' in dir(self.module): + if "outputs" in dir(self.module): if len(self.module.outputs) > 0: logging.info("output from {}".format(self.module)) output.append(self.module.outputs.pop(0)) @@ -138,15 +158,19 @@ def do_output(self): self.module.outputs = [] return output + class Job(object): def __init__(self, interval, function): self.function = function self.interval = interval self.lastrun = 0 + def __str__(self): return "{} {} {}".format(self.function, self.interval, self.lastrun) + def __repr__(self): return self.__str__() + def check(self): if self.lastrun + self.interval < time.time(): if not debug: @@ -159,52 +183,47 @@ def check(self): self.lastrun = time.time() pass + class UnknownChannel(Exception): pass def main_loop(): if "LOGFILE" in config: - logging.basicConfig(filename=config["LOGFILE"], level=logging.INFO, format='%(asctime)s %(message)s') + logging.basicConfig( + filename=config["LOGFILE"], level=logging.INFO, format="%(asctime)s %(message)s" + ) logging.info(directory) try: bot.start() except KeyboardInterrupt: sys.exit(0) except: - logging.exception('OOPS') + logging.exception("OOPS") def parse_args(): parser = ArgumentParser() - parser.add_argument( - '-c', - '--config', - help='Full path to config file.', - metavar='path' - ) + parser.add_argument("-c", "--config", help="Full path to config file.", metavar="path") return parser.parse_args() -if False:# __name__ == "__main__": +if False: # __name__ == "__main__": args = parse_args() directory = os.path.dirname(sys.argv[0]) - if not directory.startswith('/'): - directory = os.path.abspath("{}/{}".format(os.getcwd(), - directory - )) - - #config = yaml.load(file(args.config or 'rtmbot.conf', 'r')) - #debug = config["DEBUG"] - #bot = RtmBot(config["SLACK_TOKEN"]) + if not directory.startswith("/"): + directory = os.path.abspath("{}/{}".format(os.getcwd(), directory)) + + # config = yaml.load(file(args.config or 'rtmbot.conf', 'r')) + # debug = config["DEBUG"] + # bot = RtmBot(config["SLACK_TOKEN"]) site_plugins = [] files_currently_downloading = [] job_hash = {} - '''if config.has_key("DAEMON"): + """if config.has_key("DAEMON"): if config["DAEMON"]: import daemon with daemon.DaemonContext(): - main_loop()''' + main_loop()""" main_loop() - diff --git a/project/slack/slack.py b/project/slack/slack.py index 3c1f3167..970dfb20 100644 --- a/project/slack/slack.py +++ b/project/slack/slack.py @@ -1,4 +1,4 @@ -#Slacker implementation for pyCMDS +# Slacker implementation for pyCMDS import os @@ -12,19 +12,19 @@ import project.project_globals as g from project.ini_handler import Ini from . import bots + main_dir = g.main_dir.read() -ini = Ini(os.path.join(main_dir, 'project', 'slack', 'bots.ini')) +ini = Ini(os.path.join(main_dir, "project", "slack", "bots.ini")) ### container objects ######################################################### class Messages(QtCore.QMutex): - def __init__(self): - ''' + """ holds list of enqueued options - ''' + """ QtCore.QMutex.__init__(self) self.value = [] @@ -44,10 +44,11 @@ def pop(self): self.lock() self.value = self.value[1:] self.unlock() - + + messages_mutex = Messages() - + ### address & control objects ################################################# @@ -60,7 +61,7 @@ def __init__(self, busy, enqueued): self.busy = busy self.enqueued = enqueued self.ctrl = bots.witch - self.name = 'slack' + self.name = "slack" def check_busy(self): """ @@ -91,11 +92,11 @@ def dequeue(self, method, inputs): method = str(method) # method passed as qstring args, kwargs = inputs self.enqueued.pop() - getattr(self, method)(*args, **kwargs) - if not self.enqueued.read(): + getattr(self, method)(*args, **kwargs) + if not self.enqueued.read(): self.queue_emptied.emit() self.check_busy() - + def get_messages(self, inputs): newer_than = inputs[0] messages = self.ctrl.get_messages(newer_than=newer_than) @@ -108,21 +109,20 @@ def is_busy(self): def send_message(self, inputs): text, channel, attachments = inputs self.ctrl.send_message(text, channel, attachments) - + def upload_file(self, inputs): file_path, Title, first_comment, channel = inputs self.ctrl.upload_file(file_path, Title, first_comment, channel) - + def delete_files(self, inputs): self.ctrl.delete_files - + def sign_off(self, inputs): message = inputs[0] self.ctrl.send_message(message) class Control: - def __init__(self): self.most_recent_delete = time.time() # create control containers @@ -138,25 +138,25 @@ def __init__(self): # connect g.shutdown.add_method(self.close) # signal startup - self.send_message(':wave: signing on', ini.read('bots', 'channel')) + self.send_message(":wave: signing on", ini.read("bots", "channel")) g.slack_control.write(self) - + def append(self, text, channel): - self.send_message(':confounded: sorry, that feature hasn\'t been implemented') - + self.send_message(":confounded: sorry, that feature hasn't been implemented") + def close(self): - self.q.push('sign_off', [':spock-hand: signing off']) + self.q.push("sign_off", [":spock-hand: signing off"]) time.sleep(1) # quit thread self.thread.exit() self.thread.quit() - + def get(self, text, channel): # interpret text as integer try: i = int(text) except: - self.send_message(':interrobang: I couldn\'t find a number in your request') + self.send_message(":interrobang: I couldn't find a number in your request") return def interrupt(self, text, channel): @@ -164,11 +164,11 @@ def interrupt(self, text, channel): if subcommand == "": subcommand = "PAUSE" messages = { - "PAUSE": ":double_vertical_bar: Queue Paused, use `interrupt resume` to continue", - "RESUME": ":arrow_forward: Queue resumed", - "STOP": ":octagonal_sign: Queue stopped, use `run` to continue with next item", - "SKIP": ":black_right_pointing_double_triangle_with_vertical_bar: Item skipped, continuing queue", - } + "PAUSE": ":double_vertical_bar: Queue Paused, use `interrupt resume` to continue", + "RESUME": ":arrow_forward: Queue resumed", + "STOP": ":octagonal_sign: Queue stopped, use `run` to continue with next item", + "SKIP": ":black_right_pointing_double_triangle_with_vertical_bar: Item skipped, continuing queue", + } message = messages.get(subcommand, ":confounded: I do not understand the command") if subcommand == "PAUSE": g.main_window.read().queue_gui.queue.status.pause.write(True) @@ -196,11 +196,10 @@ def screenshot(self, channel): self.upload_file(tf[1], ":camera:", channel=channel) time.sleep(1) os.unlink(tf[1]) - def log(self, text, channel): log_filepath = logging_handler.filepath - if 'get' in text: + if "get" in text: self.upload_file(log_filepath, channel=channel) return # extract numbers from text @@ -219,9 +218,13 @@ def log(self, text, channel): lines = lines[:number] # send message list_string = self._make_list(lines) - attachment = self._make_attachment(list_string) - self.send_message('here are the {0} most recent log items (out of {1})'.format(number, num_lines), channel, [attachment]) - + attachment = self._make_attachment(list_string) + self.send_message( + "here are the {0} most recent log items (out of {1})".format(number, num_lines), + channel, + [attachment], + ) + def ls(self, text, channel): # extract numbers from text numbers = [int(s) for s in text.split() if s.isdigit()] @@ -232,7 +235,7 @@ def ls(self, text, channel): # get files folder_names = self._get_data_folders() if len(folder_names) == 0: - self.send_message('PyCMDS currently has no data') + self.send_message("PyCMDS currently has no data") return num_folders = len(folder_names) if len(folder_names) < number: @@ -241,106 +244,127 @@ def ls(self, text, channel): # send message list_string = self._make_list(folder_names) attachment = self._make_attachment(list_string) - self.send_message('here are the {0} most recent aquisitions (out of {1})'.format(number, num_folders), channel, [attachment]) + self.send_message( + "here are the {0} most recent aquisitions (out of {1})".format(number, num_folders), + channel, + [attachment], + ) - def make_attachment(self, text, title=None, pretext=None, fields=None, color='#808080'): + def make_attachment(self, text, title=None, pretext=None, fields=None, color="#808080"): attachment = {} if pretext is not None: - attachment['pretext'] = pretext + attachment["pretext"] = pretext if fields is not None: - attachment['fields'] = fields + attachment["fields"] = fields if title is not None: - attachment['title'] = title - attachment['color'] = color - attachment['text'] = text - attachment['mrkdwn_in'] = ['fields'] + attachment["title"] = title + attachment["color"] = color + attachment["text"] = text + attachment["mrkdwn_in"] = ["fields"] return attachment - + def make_field(self, title, value, short=False): field = {} - field['title'] = title - field['value'] = value - field['short'] = short + field["title"] = title + field["value"] = value + field["short"] = short return field def move(self, text, channel): - self.send_message(':confounded: sorry, that feature hasn\'t been implemented') + self.send_message(":confounded: sorry, that feature hasn't been implemented") def poll(self): if not self.busy.read(): - self.q.push('get_messages', [60]) + self.q.push("get_messages", [60]) self.read_messages() - + def read_messages(self): messages = messages_mutex.read() for message in messages: # only process messages - if not 'type' in message.keys(): + if not "type" in message.keys(): + continue + if not message["type"] == "message": continue - if not message['type'] == 'message': - continue # unpack some things - text = message['text'] - channel = message['channel'] + text = message["text"] + channel = message["channel"] # only process messages that are posted in the appropriate channel - if not channel == ini.read('bots', 'channel'): + if not channel == ini.read("bots", "channel"): continue - text = text.split(' ', 1)[1] - print('message read from slack:', text) + text = text.split(" ", 1)[1] + print("message read from slack:", text) # process - if 'echo ' in text.lower(): - out = text.split('echo ', 1)[1] - message = ':mega: ' + out + if "echo " in text.lower(): + out = text.split("echo ", 1)[1] + message = ":mega: " + out self.send_message(message, channel) - elif 'get' == text[:3].lower(): + elif "get" == text[:3].lower(): self.get(text, channel) - elif 'status' in text.lower(): + elif "status" in text.lower(): self.status(text, channel) - elif 'remove' in text.lower(): + elif "remove" in text.lower(): self.remove(text, channel) - elif 'move' in text.lower(): + elif "move" in text.lower(): self.move(text, channel) - elif 'append' in text.lower(): + elif "append" in text.lower(): self.append(text, channel) - elif 'interrupt' in text.lower(): + elif "interrupt" in text.lower(): try: - text = text.split(' ', 1)[1] + text = text.split(" ", 1)[1] except IndexError: text = "" self.interrupt(text, channel) - elif 'run' in text.lower(): + elif "run" in text.lower(): self.run_queue() - elif 'screenshot' in text.lower(): + elif "screenshot" in text.lower(): self.screenshot(channel) - elif 'help' in text.lower(): + elif "help" in text.lower(): self.send_help(channel) else: - self.send_message(':thinking_face: command \'{}\' not recognized - type \'help\' for a list of available commands'.format(text), channel) + self.send_message( + ":thinking_face: command '{}' not recognized - type 'help' for a list of available commands".format( + text + ), + channel, + ) def remove(self, text, channel): - self.send_message(':confounded: sorry, that feature hasn\'t been implemented') + self.send_message(":confounded: sorry, that feature hasn't been implemented") def send_help(self, channel): command_fields = [] - command_fields.append(self.make_field('status [--full]', 'Get the current status of PyCMDS.')) - #command_fields.append(self.make_field('remove i', 'Remove the ith item from the queue.')) - #command_fields.append(self.make_field('move i to j', 'Move item i to position j. All other items retain their order.')) - #command_fields.append(self.make_field('append [name] [info]', 'Append a file to the queue. Must be made as a comment of an attached file.')) - command_fields.append(self.make_field('run', 'Run the queue.')) - command_fields.append(self.make_field('interrupt [pause|resume|skip|stop]', 'Interrupt the queue or resume from pause. Default is pause.')) - command_fields.append(self.make_field('screenshot', 'Take a screenshot of the current window and post to slack.')) - command_fields.append(self.make_field('help', 'Show this help message.')) - attachment = self.make_attachment('', fields=command_fields) - self.send_message(':robot_face: here are my commands', channel, [attachment]) + command_fields.append( + self.make_field("status [--full]", "Get the current status of PyCMDS.") + ) + # command_fields.append(self.make_field('remove i', 'Remove the ith item from the queue.')) + # command_fields.append(self.make_field('move i to j', 'Move item i to position j. All other items retain their order.')) + # command_fields.append(self.make_field('append [name] [info]', 'Append a file to the queue. Must be made as a comment of an attached file.')) + command_fields.append(self.make_field("run", "Run the queue.")) + command_fields.append( + self.make_field( + "interrupt [pause|resume|skip|stop]", + "Interrupt the queue or resume from pause. Default is pause.", + ) + ) + command_fields.append( + self.make_field( + "screenshot", "Take a screenshot of the current window and post to slack." + ) + ) + command_fields.append(self.make_field("help", "Show this help message.")) + attachment = self.make_attachment("", fields=command_fields) + self.send_message(":robot_face: here are my commands", channel, [attachment]) def send_message(self, text, channel=None, attachments=[]): - self.q.push('send_message', [text, channel, attachments]) - + self.q.push("send_message", [text, channel, attachments]) + def status(self, text, channel): text, attachments = g.main_window.read().get_status("full" in text.lower()) self.send_message(text, channel, attachments) - + def upload_file(self, file_path, title=None, first_comment=None, channel=None): - self.q.push('upload_file', [file_path, title, first_comment, channel]) + self.q.push("upload_file", [file_path, title, first_comment, channel]) + control = Control() diff --git a/project/slack/test_slack.py b/project/slack/test_slack.py index 37b403c9..3ca53ad3 100644 --- a/project/slack/test_slack.py +++ b/project/slack/test_slack.py @@ -7,13 +7,13 @@ ctrl = bots.witch -imageid = '0B8z-JGr_8g4RSlNPMC04bVBSZUk' -url = 'https://drive.google.com/open?id=0B8z-JGr_8g4RdTN4SHdxVGZTSkE' -image_url = 'https://docs.google.com/uc?id=' + imageid +imageid = "0B8z-JGr_8g4RSlNPMC04bVBSZUk" +url = "https://drive.google.com/open?id=0B8z-JGr_8g4RdTN4SHdxVGZTSkE" +image_url = "https://docs.google.com/uc?id=" + imageid field0 = {} -field0['title'] = 'MOTORTUNE [w1, w1_Mixer_2, wm] 2016.02.02 16_03_57' -field0['title_link'] = url -field0['image_url'] = image_url +field0["title"] = "MOTORTUNE [w1, w1_Mixer_2, wm] 2016.02.02 16_03_57" +field0["title_link"] = url +field0["image_url"] = image_url -ctrl.send_message('scan complete - 00:09:51 elapsed', channel, attachments=[field0]) +ctrl.send_message("scan complete - 00:09:51 elapsed", channel, attachments=[field0]) diff --git a/project/style.py b/project/style.py index 4b797a73..1e68224c 100644 --- a/project/style.py +++ b/project/style.py @@ -1,69 +1,87 @@ from PySide2 import QtWidgets from project import project_globals as g -#see http://www.google.com/design/spec/style/color.html#color-color-palette - -colors = {'background': '#212121', - 'go': '#009688', - 'stop': '#F44336', - 'set': '#009688', - 'advanced': '#FFC107', - 'text_light': '#EEEEEE', - 'text_disabled': '#757575', - 'widget_background':'#EEEEEE', - 'heading_1': '#00BCD4', - 'heading_0': '#FFC107'} #least important heading - +# see http://www.google.com/design/spec/style/color.html#color-color-palette + +colors = { + "background": "#212121", + "go": "#009688", + "stop": "#F44336", + "set": "#009688", + "advanced": "#FFC107", + "text_light": "#EEEEEE", + "text_disabled": "#757575", + "widget_background": "#EEEEEE", + "heading_1": "#00BCD4", + "heading_0": "#FFC107", +} # least important heading + g.colors_dict.write(colors) + def set_style(): - #Style Sheet---------------------------------------------------------------- - - StyleSheet = '' - - #main window - StyleSheet += 'QMainWindow{background:custom_color}'.replace('custom_color', colors['background']) - - #push button - #StyleSheet += 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['go']) - - #progress bar - StyleSheet += 'QProgressBar:horizontal{border: 0px solid gray; border-radius: 0px; background: custom_color; padding: 0px; height: 30px;}'.replace('custom_color', colors['background']) - StyleSheet += 'QProgressBar:chunk{background:custom_color}'.replace('custom_color', colors['go']) - - #tab widget - StyleSheet += 'QTabWidget::pane{border-top: 2px solid #C2C7CB;}' - StyleSheet += 'QTabWidget::tab-bar{left: 5px;}' - StyleSheet += 'QTabBar::tab{width: 100px; background: clr1; border: 0px; border-bottom-color: black; border-top-left-radius: 4px; border-top-right-radius: 4px; min-width: 8ex; padding: 2px; font: bold 14px; color: clr2}'.replace('clr1', colors['background']).replace('clr2', colors['heading_0']) - StyleSheet += 'QTabBar::tab:selected{border-color: black; border-bottom-color: black; color: clr1}'.replace('clr1', colors['heading_1']) - - #scroll bar - StyleSheet += 'QScrollArea::QWidget::QWidget{backround: transparent;}' - - #group box - StyleSheet += 'QGroupBox{border: 2px solid gray; font: bold 14px; margin-top: 0ex; border-radius: 0 px;}' - StyleSheet += 'QGroupBox::title{subcontrol-origin: margin; padding: 0 0px}' - + # Style Sheet---------------------------------------------------------------- + + StyleSheet = "" + + # main window + StyleSheet += "QMainWindow{background:custom_color}".replace( + "custom_color", colors["background"] + ) + + # push button + # StyleSheet += 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['go']) + + # progress bar + StyleSheet += "QProgressBar:horizontal{border: 0px solid gray; border-radius: 0px; background: custom_color; padding: 0px; height: 30px;}".replace( + "custom_color", colors["background"] + ) + StyleSheet += "QProgressBar:chunk{background:custom_color}".replace( + "custom_color", colors["go"] + ) + + # tab widget + StyleSheet += "QTabWidget::pane{border-top: 2px solid #C2C7CB;}" + StyleSheet += "QTabWidget::tab-bar{left: 5px;}" + StyleSheet += "QTabBar::tab{width: 100px; background: clr1; border: 0px; border-bottom-color: black; border-top-left-radius: 4px; border-top-right-radius: 4px; min-width: 8ex; padding: 2px; font: bold 14px; color: clr2}".replace( + "clr1", colors["background"] + ).replace( + "clr2", colors["heading_0"] + ) + StyleSheet += "QTabBar::tab:selected{border-color: black; border-bottom-color: black; color: clr1}".replace( + "clr1", colors["heading_1"] + ) + + # scroll bar + StyleSheet += "QScrollArea::QWidget::QWidget{backround: transparent;}" + + # group box + StyleSheet += ( + "QGroupBox{border: 2px solid gray; font: bold 14px; margin-top: 0ex; border-radius: 0 px;}" + ) + StyleSheet += "QGroupBox::title{subcontrol-origin: margin; padding: 0 0px}" + app = g.app.read() app.setStyleSheet(StyleSheet) - - #Palette-------------------------------------------------------------------- - - ''' + + # Palette-------------------------------------------------------------------- + + """ MainWindow = g.main_window.read() palette = QtWidgets.QPalette(MainWindow.palette()) palette.setColor(MainWindow.backgroundRole(), QtWidgets.QColor(colors['background'])) #MainWindow.setPalette(palette) - ''' + """ + + # style---------------------------------------------------------------------- + + # app.setStyle('windowsxp') + - #style---------------------------------------------------------------------- - - #app.setStyle('windowsxp') - def set_background_role(obj): palette = QtWidgets.QPalette(obj.palette()) - palette.setColor(obj.backgroundRole(), QtWidgets.QColor(colors['background'])) + palette.setColor(obj.backgroundRole(), QtWidgets.QColor(colors["background"])) obj.setPalette(palette) diff --git a/project/widgets.py b/project/widgets.py index f126d820..6f2f2b41 100644 --- a/project/widgets.py +++ b/project/widgets.py @@ -18,7 +18,6 @@ class ExpandingWidget(QtWidgets.QWidget): - def __init__(self): QtWidgets.QWidget.__init__(self) self.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum) @@ -26,7 +25,7 @@ def __init__(self): self.setMinimumHeight(0) self.setMinimumWidth(0) self.layout().setStretchFactor(self, 1) - + def sizeHint(self): return QtCore.QSize(16777215, 16777215) @@ -34,19 +33,24 @@ def add_to_layout(self, layout): layout.addWidget(self) layout.setStretchFactor(self, 16777215) - + class Line(QtWidgets.QFrame): - ''' + """ direction: 'V' or 'H' - ''' + """ + def __init__(self, direction): QtWidgets.QFrame.__init__(self) - if direction == 'V': + if direction == "V": self.setFrameShape(QtWidgets.QFrame.VLine) else: self.setFrameShape(QtWidgets.QFrame.HLine) - StyleSheet = 'QFrame{border: 2px solid custom_color; border-radius: 0px; padding: 0px;}'.replace('custom_color', colors['widget_background']) + StyleSheet = "QFrame{border: 2px solid custom_color; border-radius: 0px; padding: 0px;}".replace( + "custom_color", colors["widget_background"] + ) self.setStyleSheet(StyleSheet) + + line = Line # legacy @@ -58,8 +62,12 @@ def __init__(self, show_bar=True): if show_bar: self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - StyleSheet = 'QScrollArea, QWidget{background: custom_color;}'.replace('custom_color', colors['background']) - StyleSheet += 'QScrollBar{background: custom_color;}'.replace('custom_color', colors['widget_background']) + StyleSheet = "QScrollArea, QWidget{background: custom_color;}".replace( + "custom_color", colors["background"] + ) + StyleSheet += "QScrollBar{background: custom_color;}".replace( + "custom_color", colors["widget_background"] + ) self.setStyleSheet(StyleSheet) @@ -68,8 +76,8 @@ def __init__(self): QtWidgets.QCheckBox.__init__(self) self.setDisabled(True) path = str(__here__).replace("\\", "/") - StyleSheet = f'QCheckBox::indicator:checked {{image: url({path}/widget files/checkbox_checked.png);}}' - StyleSheet += f'QCheckBox::indicator:unchecked {{image: url({path}/widget files/checkbox_unchecked.png);}}' + StyleSheet = f"QCheckBox::indicator:checked {{image: url({path}/widget files/checkbox_checked.png);}}" + StyleSheet += f"QCheckBox::indicator:unchecked {{image: url({path}/widget files/checkbox_unchecked.png);}}" print(StyleSheet) self.setStyleSheet(StyleSheet) @@ -78,8 +86,7 @@ def __init__(self): class SpinboxAsDisplay(QtWidgets.QDoubleSpinBox): - - def __init__(self, font_size=14, decimals=6, justify='right'): + def __init__(self, font_size=14, decimals=6, justify="right"): QtWidgets.QDoubleSpinBox.__init__(self) self.setValue(0.0) self.setDisabled(True) @@ -87,41 +94,50 @@ def __init__(self, font_size=14, decimals=6, justify='right'): self.setDecimals(decimals) self.setMinimum(-100000) self.setMaximum(100000) - if justify == 'right': + if justify == "right": self.setAlignment(QtCore.Qt.AlignRight) - else: + else: self.setAlignment(QtCore.Qt.AlignLeft) self.setMinimumWidth(0) self.setMaximumWidth(600) self.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) - StyleSheet = 'QDoubleSpinBox{color: custom_color_1; font: bold font_sizepx; border: 0px solid #000000;}'.replace('custom_color_1', g.colors_dict.read()['text_light']).replace('font_size', str(int(font_size))) - StyleSheet += 'QScrollArea, QWidget{background: custom_color; border-color: black;}'.replace('custom_color', g.colors_dict.read()['background']) + StyleSheet = "QDoubleSpinBox{color: custom_color_1; font: bold font_sizepx; border: 0px solid #000000;}".replace( + "custom_color_1", g.colors_dict.read()["text_light"] + ).replace( + "font_size", str(int(font_size)) + ) + StyleSheet += "QScrollArea, QWidget{background: custom_color; border-color: black;}".replace( + "custom_color", g.colors_dict.read()["background"] + ) self.setStyleSheet(StyleSheet) class Shutdown_button(QtWidgets.QPushButton): shutdown_go = QtCore.Signal() + def __init__(self): QtWidgets.QPushButton.__init__(self) self.clicked.connect(self.initiate_shutdown) - self.setText('SHUT DOWN') - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['stop']) + self.setText("SHUT DOWN") + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["stop"] + ) self.setStyleSheet(StyleSheet) + def initiate_shutdown(self): - self.setText('SHUTTING DOWN') + self.setText("SHUTTING DOWN") g.app.read().processEvents() self.shutdown_go.emit() - + class InputTable(QtWidgets.QWidget): - def __getitem__(self, key): return self._dict[key] def __init__(self, width=130): - ''' + """ width of 160 good for modules - ''' + """ QtWidgets.QWidget.__init__(self) self.width_input = width self.setLayout(QtWidgets.QGridLayout()) @@ -136,7 +152,7 @@ def add(self, name, global_object, key=None): if key is None: key = name if global_object is None: - global_type = 'heading' + global_type = "heading" else: global_type = global_object.type self._dict[key] = global_object @@ -145,10 +161,14 @@ def add(self, name, global_object, key=None): def busy(self, name, global_object): # heading heading = QtWidgets.QLabel(name) - if name in ['DAQ status', 'Status']: # hardcoded exceptions - StyleSheet = 'QLabel{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) + if name in ["DAQ status", "Status"]: # hardcoded exceptions + StyleSheet = "QLabel{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) else: - StyleSheet = 'QLabel{color: custom_color; font: bold 14px;}'.replace('custom_color', colors['heading_0']) + StyleSheet = "QLabel{color: custom_color; font: bold 14px;}".replace( + "custom_color", colors["heading_0"] + ) heading.setStyleSheet(StyleSheet) self.layout().addWidget(heading, self.row_number, 0) # control @@ -162,7 +182,9 @@ def busy(self, name, global_object): def heading(self, name, global_object): # heading heading = QtWidgets.QLabel(name) - StyleSheet = 'QLabel{color: custom_color; font: bold 14px;}'.replace('custom_color', colors['heading_0']) + StyleSheet = "QLabel{color: custom_color; font: bold 14px;}".replace( + "custom_color", colors["heading_0"] + ) heading.setStyleSheet(StyleSheet) heading.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) self.layout().addWidget(heading, self.row_number, 0) @@ -172,136 +194,208 @@ def heading(self, name, global_object): def number(self, name, global_object): # heading heading = QtWidgets.QLabel(name) - StyleSheet = 'QLabel{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) + StyleSheet = "QLabel{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) heading.setStyleSheet(StyleSheet) heading.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) self.layout().addWidget(heading, self.row_number, 0) - #layout + # layout container_widget = QtWidgets.QWidget() container_widget.setLayout(QtWidgets.QHBoxLayout()) layout = container_widget.layout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - #control + # control control = QtWidgets.QDoubleSpinBox() if global_object.display: control.setDisabled(True) - StyleSheet = 'QDoubleSpinBox{color: custom_color_1; font: bold font_sizepx; border: 0px solid #000000;}'.replace('custom_color_1', g.colors_dict.read()['text_light']).replace('font_size', str(int(14))) - StyleSheet += 'QScrollArea, QWidget{background: custom_color; border-color: black;}'.replace('custom_color', g.colors_dict.read()['background']) + StyleSheet = "QDoubleSpinBox{color: custom_color_1; font: bold font_sizepx; border: 0px solid #000000;}".replace( + "custom_color_1", g.colors_dict.read()["text_light"] + ).replace( + "font_size", str(int(14)) + ) + StyleSheet += "QScrollArea, QWidget{background: custom_color; border-color: black;}".replace( + "custom_color", g.colors_dict.read()["background"] + ) else: - StyleSheet = 'QDoubleSpinBox{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) - StyleSheet += 'QScrollArea, QWidget{color: custom_color_1; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QWidget:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) - control.setStyleSheet(StyleSheet) + StyleSheet = "QDoubleSpinBox{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) + StyleSheet += "QScrollArea, QWidget{color: custom_color_1; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QWidget:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_disabled"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + control.setStyleSheet(StyleSheet) control.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) global_object.give_control(control) layout.addWidget(control) - #units combobox + # units combobox if not global_object.units_kind == None: control.setMinimumWidth(self.width_input - 55) control.setMaximumWidth(self.width_input - 55) units = QtWidgets.QComboBox() units.setMinimumWidth(50) units.setMaximumWidth(50) - StyleSheet = 'QComboBox{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QComboBox:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QAbstractItemView{color: custom_color_1; font: 50px solid white;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) + StyleSheet = "QComboBox{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QComboBox:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_disabled"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QAbstractItemView{color: custom_color_1; font: 50px solid white;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) units.setStyleSheet(StyleSheet) layout.addWidget(units) global_object.give_units_combo(units) - #finish + # finish self.layout().addWidget(container_widget, self.row_number, 1) self.controls.append(container_widget) self.row_number += 1 def string(self, name, global_object): - #heading + # heading heading = QtWidgets.QLabel(name) heading.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - StyleSheet = 'QLabel{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) + StyleSheet = "QLabel{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) heading.setStyleSheet(StyleSheet) self.layout().addWidget(heading, self.row_number, 0) - #control + # control control = QtWidgets.QLineEdit() control.setMinimumWidth(self.width_input) control.setMaximumWidth(self.width_input) if global_object.display: control.setDisabled(True) - StyleSheet = 'QWidget{color: custom_color_1; font: bold 14px; border: 0px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) + StyleSheet = "QWidget{color: custom_color_1; font: bold 14px; border: 0px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) else: - StyleSheet = 'QWidget{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QWidget:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) + StyleSheet = "QWidget{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QWidget:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_disabled"] + ).replace( + "custom_color_2", colors["widget_background"] + ) control.setStyleSheet(StyleSheet) global_object.give_control(control) - #finish + # finish self.layout().addWidget(control, self.row_number, 1) self.controls.append(control) self.row_number += 1 def combo(self, name, global_object): - #heading + # heading heading = QtWidgets.QLabel(name) heading.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - StyleSheet = 'QLabel{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) + StyleSheet = "QLabel{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) heading.setStyleSheet(StyleSheet) self.layout().addWidget(heading, self.row_number, 0) - #control + # control control = QtWidgets.QComboBox() control.setMinimumWidth(self.width_input) control.setMaximumWidth(self.width_input) if global_object.display: control.setDisabled(True) - StyleSheet = 'QComboBox{color: custom_color_1; font: bold 14px; border: 0px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) - #StyleSheet += 'QComboBox:disabled{color: custom_color_1; font: 14px; border: 0px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QAbstractItemView{color: custom_color_1; font: 50px solid white; border: 0px white}'.replace('custom_color_1', colors['widget_background']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QComboBox::drop-down{border: 0;}' - else: - StyleSheet = 'QComboBox{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QComboBox:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QAbstractItemView{color: custom_color_1; font: 50px solid white;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) + StyleSheet = "QComboBox{color: custom_color_1; font: bold 14px; border: 0px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + # StyleSheet += 'QComboBox:disabled{color: custom_color_1; font: 14px; border: 0px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) + StyleSheet += "QAbstractItemView{color: custom_color_1; font: 50px solid white; border: 0px white}".replace( + "custom_color_1", colors["widget_background"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QComboBox::drop-down{border: 0;}" + else: + StyleSheet = "QComboBox{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QComboBox:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_disabled"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QAbstractItemView{color: custom_color_1; font: 50px solid white;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) control.setStyleSheet(StyleSheet) - global_object.give_control(control) - #finish + global_object.give_control(control) + # finish self.layout().addWidget(control, self.row_number, 1) self.controls.append(control) self.row_number += 1 def checkbox(self, name, global_object): - #heading + # heading heading = QtWidgets.QLabel(name) heading.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - StyleSheet = 'QLabel{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) + StyleSheet = "QLabel{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) heading.setStyleSheet(StyleSheet) self.layout().addWidget(heading, self.row_number, 0) - #control + # control if global_object.display: control = Led() else: control = QtWidgets.QCheckBox() global_object.give_control(control) - #finish + # finish self.layout().addWidget(control, self.row_number, 1) self.controls.append(control) self.row_number += 1 def filepath(self, name, global_object): - #heading + # heading heading = QtWidgets.QLabel(name) heading.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) - StyleSheet = 'QLabel{color: custom_color; font: 14px;}'.replace('custom_color', colors['text_light']) + StyleSheet = "QLabel{color: custom_color; font: 14px;}".replace( + "custom_color", colors["text_light"] + ) heading.setStyleSheet(StyleSheet) self.layout().addWidget(heading, self.row_number, 0) - #layout + # layout container_widget = QtWidgets.QWidget() container_widget.setLayout(QtWidgets.QHBoxLayout()) layout = container_widget.layout() layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(5) - #push button - load_button = QtWidgets.QPushButton('Load') - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['go']) + # push button + load_button = QtWidgets.QPushButton("Load") + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["go"] + ) load_button.setStyleSheet(StyleSheet) load_button.setMinimumHeight(20) load_button.setMaximumHeight(20) @@ -309,89 +403,123 @@ def filepath(self, name, global_object): load_button.setMaximumWidth(40) layout.addWidget(load_button) global_object.give_button(load_button) - #display + # display display = QtWidgets.QLineEdit() - #display.setDisabled(True) + # display.setDisabled(True) display.setReadOnly(True) display.setMinimumWidth(self.width_input - 45) display.setMaximumWidth(self.width_input - 45) - StyleSheet = 'QWidget{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_light']).replace('custom_color_2', colors['widget_background']) - StyleSheet += 'QWidget:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}'.replace('custom_color_1', colors['text_disabled']).replace('custom_color_2', colors['widget_background']) + StyleSheet = "QWidget{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_light"] + ).replace( + "custom_color_2", colors["widget_background"] + ) + StyleSheet += "QWidget:disabled{color: custom_color_1; font: 14px; border: 1px solid custom_color_2; border-radius: 1px;}".replace( + "custom_color_1", colors["text_disabled"] + ).replace( + "custom_color_2", colors["widget_background"] + ) display.setStyleSheet(StyleSheet) layout.addWidget(display) global_object.give_control(display) - #finish + # finish self.layout().addWidget(container_widget, self.row_number, 1) self.controls.append(container_widget) self.row_number += 1 - + + class Label(QtWidgets.QLabel): - def __init__(self, text, color='text_light', bold=False, font_size=14): + def __init__(self, text, color="text_light", bold=False, font_size=14): QtWidgets.QLabel.__init__(self, text) if bold: - bold_status = 'bold' + bold_status = "bold" else: - bold_status = '' - StyleSheet = f'QLabel{{color: {colors[color]}; font: {font_size}px;}}'.replace('bold_status', bold_status) + bold_status = "" + StyleSheet = f"QLabel{{color: {colors[color]}; font: {font_size}px;}}".replace( + "bold_status", bold_status + ) self.setStyleSheet(StyleSheet) + class SetButton(QtWidgets.QPushButton): - def __init__(self, text, color='go'): + def __init__(self, text, color="go"): QtWidgets.QPushButton.__init__(self) self.setText(text) self.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors[color]) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors[color] + ) self.setStyleSheet(StyleSheet) + class TableWidget(QtWidgets.QTableWidget): def __init__(self): QtWidgets.QTableWidget.__init__(self) - StyleSheet = 'QTableWidget::item{padding: 0px}' - StyleSheet += 'QHeaderView::section{background: background_color; color:white; font: bold 14px}'.replace('background_color', colors['background']) - StyleSheet += 'QTableWidget{background-color: custom_color;}'.replace('custom_color', colors['background']) + StyleSheet = "QTableWidget::item{padding: 0px}" + StyleSheet += "QHeaderView::section{background: background_color; color:white; font: bold 14px}".replace( + "background_color", colors["background"] + ) + StyleSheet += "QTableWidget{background-color: custom_color;}".replace( + "custom_color", colors["background"] + ) self.setStyleSheet(StyleSheet) - + + class TabWidget(QtWidgets.QTabWidget): def __init__(self): QtWidgets.QTabWidget.__init__(self) - StyleSheet = 'QTabBar::tab{width: 130px;}' + StyleSheet = "QTabBar::tab{width: 130px;}" self.setStyleSheet(StyleSheet) + ### hardware ################################################################## class BusyDisplay(QtWidgets.QPushButton): - ''' + """ access value object to get state True: scan running pause methods are built in to this object - ''' + """ + def __init__(self, busy_object, update_signal): QtWidgets.QPushButton.__init__(self) self.busy_object = busy_object - update_signal.connect(self.update) - self.setText('READY') + update_signal.connect(self.update) + self.setText("READY") self.setMinimumHeight(15) self.setMaximumHeight(15) - StyleSheet = 'QPushButton{background:background_color; border-width:0px; border-radius: 0px; font: bold 14px; color: text_color}'.replace('background_color', colors['background']).replace('text_color', colors['background']) + StyleSheet = "QPushButton{background:background_color; border-width:0px; border-radius: 0px; font: bold 14px; color: text_color}".replace( + "background_color", colors["background"] + ).replace( + "text_color", colors["background"] + ) self.setStyleSheet(StyleSheet) self.update() + def update(self): if self.busy_object.read(): - self.setText('BUSY') - StyleSheet = 'QPushButton{background:background_color; border-width:0px; border-radius: 0px; font: bold 14px; color: text_color; text-align: left}'.replace('background_color', colors['background']).replace('text_color', colors['stop']) + self.setText("BUSY") + StyleSheet = "QPushButton{background:background_color; border-width:0px; border-radius: 0px; font: bold 14px; color: text_color; text-align: left}".replace( + "background_color", colors["background"] + ).replace( + "text_color", colors["stop"] + ) + self.setStyleSheet(StyleSheet) + else: + self.setText("READY") + StyleSheet = "QPushButton{background:background_color; border-width:0px; border-radius: 0px; font: bold 14px; color: text_color}".replace( + "background_color", colors["background"] + ).replace( + "text_color", colors["background"] + ) self.setStyleSheet(StyleSheet) - else: - self.setText('READY') - StyleSheet = 'QPushButton{background:background_color; border-width:0px; border-radius: 0px; font: bold 14px; color: text_color}'.replace('background_color', colors['background']).replace('text_color', colors['background']) - self.setStyleSheet(StyleSheet) class Hardware_control_table(QtWidgets.QWidget): - - def __init__(self, hardware_names, combobox=False, combobox_label=''): + def __init__(self, hardware_names, combobox=False, combobox_label=""): QtWidgets.QWidget.__init__(self) self.setLayout(QtWidgets.QGridLayout()) self.layout().setMargin(0) @@ -400,26 +528,28 @@ def __init__(self, hardware_names, combobox=False, combobox_label=''): self.new_position_controls = [] self.set_buttons = [] for i in range(len(hardware_names)): - #names + # names collumn = 0 label = QtWidgets.QLabel(hardware_names[i]) - StyleSheet = 'QLabel{color: custom_color; font: bold 14px;}'.replace('custom_color', colors['heading_0']) + StyleSheet = "QLabel{color: custom_color; font: bold 14px;}".replace( + "custom_color", colors["heading_0"] + ) label.setStyleSheet(StyleSheet) self.layout().addWidget(label, i, collumn) - #comboboxes + # comboboxes if combobox: collumn += 1 combobox_obj = QtWidgets.QComboBox() self.layout().addWidget(combobox_obj, i, collumn) self.comboboxes.append(combobox_obj) - #current + # current collumn += 1 current_position = QtWidgets.QDoubleSpinBox() current_position.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) current_position.setDisabled(True) self.layout().addWidget(current_position, i, collumn) self.current_position_displays.append(current_position) - #new + # new collumn += 1 new_position = QtWidgets.QDoubleSpinBox() new_position.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) @@ -437,7 +567,6 @@ def set_allowed_values(self, index, min_val, max_val, decimals=2, single_step=1. class HardwareLayoutWidget(QtWidgets.QGroupBox): - def __init__(self, name): QtWidgets.QGroupBox.__init__(self) # layout @@ -449,11 +578,13 @@ def __init__(self, name): heading_container.layout().setMargin(0) # add heading heading = QtWidgets.QLabel(name) - StyleSheet = 'QLabel{color: custom_color; font: bold 14px;}'.replace('custom_color', colors['heading_1']) + StyleSheet = "QLabel{color: custom_color; font: bold 14px;}".replace( + "custom_color", colors["heading_1"] + ) heading.setStyleSheet(StyleSheet) heading_container.layout().addWidget(heading) self.layout().addWidget(heading_container) - + def add_buttons(self, set_method, advanced_method, hardwares=[]): # layout button_container = QtWidgets.QWidget() @@ -461,17 +592,21 @@ def add_buttons(self, set_method, advanced_method, hardwares=[]): button_container.layout().setMargin(0) # advanced advanced_button = QtWidgets.QPushButton() - advanced_button.setText('ADVANCED') + advanced_button.setText("ADVANCED") advanced_button.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['advanced']) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["advanced"] + ) advanced_button.setStyleSheet(StyleSheet) button_container.layout().addWidget(advanced_button) advanced_button.clicked.connect(advanced_method) # set set_button = QtWidgets.QPushButton() - set_button.setText('SET') + set_button.setText("SET") set_button.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['set']) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["set"] + ) set_button.setStyleSheet(StyleSheet) # add self.layout().addWidget(button_container) @@ -483,7 +618,7 @@ def add_buttons(self, set_method, advanced_method, hardwares=[]): set_button.setDisabled(hardware.busy.read()) # first time hardware.update_ui.connect(lambda: set_button_decide(set_button, hardwares)) return [advanced_button, set_button] - + def set_button_decide(set_button, hardwares): if g.queue_control.read(): @@ -498,7 +633,7 @@ def set_button_decide(set_button, hardwares): class HardwareFrontPanel(QtCore.QObject): advanced = QtCore.Signal() - def __init__(self, hardwares, name='Hardware'): + def __init__(self, hardwares, name="Hardware"): QtCore.QObject.__init__(self) self.name = name # link hardware object signals @@ -515,15 +650,15 @@ def create_frame(self): input_table = InputTable(130) self.front_panel_elements = [] for hardware in self.hardwares: - name = ' '.join([hardware.name, '('+hardware.model+')']) + name = " ".join([hardware.name, "(" + hardware.model + ")"]) input_table.add(name, hardware.busy) current_objects = hardware.exposed destination_objects = [] for obj in hardware.exposed: input_table.add(obj.label, obj) - dest_obj = obj.associate(display=False, pre_name='Dest. ') + dest_obj = obj.associate(display=False, pre_name="Dest. ") destination_objects.append(dest_obj) - if hasattr(obj, 'units_updated'): + if hasattr(obj, "units_updated"): obj.units_updated.connect(self.on_position_units_updated) dest_obj.units_updated.connect(self.on_destination_units_updated) for obj in destination_objects: @@ -531,17 +666,21 @@ def create_frame(self): self.front_panel_elements.append([current_objects, destination_objects]) hardware.initialized.updated.connect(self.initialize) layout.addWidget(input_table) - self.advanced_button, self.set_button = layout_widget.add_buttons(self.on_set, self.show_advanced, self.hardwares) + self.advanced_button, self.set_button = layout_widget.add_buttons( + self.on_set, self.show_advanced, self.hardwares + ) g.hardware_widget.add_to(layout_widget) - + def initialize(self): # will fire each time ANY hardware contained within finishes initialize # not ideal behavior, but good enough for hardware, front_panel_elements in zip(self.hardwares, self.front_panel_elements): if hardware.initialized: - for current_object, destination_object in zip(front_panel_elements[0], front_panel_elements[1]): + for current_object, destination_object in zip( + front_panel_elements[0], front_panel_elements[1] + ): position = current_object.read() - destination_object.write(position) + destination_object.write(position) def update(self): pass @@ -551,19 +690,23 @@ def show_advanced(self): def on_destination_units_updated(self): for pl, dl in self.front_panel_elements: - if hasattr(pl[0], 'units'): + if hasattr(pl[0], "units"): pl[0].set_units(dl[0].units) - + def on_position_units_updated(self): for pl, dl in self.front_panel_elements: - if hasattr(pl[0], 'units'): + if hasattr(pl[0], "units"): dl[0].set_units(pl[0].units) def on_set(self): for hardware, front_panel_elements in zip(self.hardwares, self.front_panel_elements): - for current_object, destination_object in zip(front_panel_elements[0], front_panel_elements[1]): - if current_object.set_method == 'set_position': - hardware.set_position(destination_object.read(), destination_object.units, force_send=True) + for current_object, destination_object in zip( + front_panel_elements[0], front_panel_elements[1] + ): + if current_object.set_method == "set_position": + hardware.set_position( + destination_object.read(), destination_object.units, force_send=True + ) else: hardware.q.push(current_object.set_method, [destination_object.read()]) g.coset_control.read().launch() @@ -574,8 +717,8 @@ def stop(self): hardware_advanced_panels = [] -class HardwareAdvancedPanel(QtCore.QObject): +class HardwareAdvancedPanel(QtCore.QObject): def __init__(self, hardwares, advanced_button): QtCore.QObject.__init__(self) self.tabs = QtWidgets.QTabWidget() @@ -605,11 +748,11 @@ def on_advanced(self): for panel in hardware_advanced_panels: panel.hide() self.tabs.show() - #self.advanced_button.setDisabled(True) + # self.advanced_button.setDisabled(True) ### queue ##################################################################### - + class QueueControl(QtWidgets.QPushButton): launch_scan = QtCore.Signal() @@ -619,17 +762,18 @@ def __init__(self): QtWidgets.QPushButton.__init__(self) self.clicked.connect(self.update) self.setMinimumHeight(25) - self.set_style('RUN QUEUE', 'go') + self.set_style("RUN QUEUE", "go") self.value = False def set_style(self, text, color): self.setText(text) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors[color]) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors[color] + ) self.setStyleSheet(StyleSheet) class ChoiceWindow(QtWidgets.QMessageBox): - def __init__(self, title, button_labels): QtWidgets.QMessageBox.__init__(self) self.setWindowTitle(title) @@ -645,9 +789,9 @@ def set_text(self, text): self.setText(text) def show(self): - ''' + """ Returns the index of the chosen button - ''' + """ self.isActiveWindow() self.setFocusPolicy(QtCore.Qt.StrongFocus) return self.exec_() @@ -657,40 +801,39 @@ def show(self): class Plot1D(pg.GraphicsView): - def __init__(self, title=None, xAutoRange=True, yAutoRange=True): pg.GraphicsView.__init__(self) - #create layout - self.graphics_layout = pg.GraphicsLayout(border = 'w') + # create layout + self.graphics_layout = pg.GraphicsLayout(border="w") self.setCentralItem(self.graphics_layout) self.graphics_layout.layout.setSpacing(0) - self.graphics_layout.setContentsMargins(0., 0., 1., 1.) - #create plot object + self.graphics_layout.setContentsMargins(0.0, 0.0, 1.0, 1.0) + # create plot object self.plot_object = self.graphics_layout.addPlot(0, 0) - self.labelStyle = {'color': '#FFF', 'font-size': '14px'} - self.x_axis = self.plot_object.getAxis('bottom') + self.labelStyle = {"color": "#FFF", "font-size": "14px"} + self.x_axis = self.plot_object.getAxis("bottom") self.x_axis.setLabel(**self.labelStyle) - self.y_axis = self.plot_object.getAxis('left') + self.y_axis = self.plot_object.getAxis("left") self.y_axis.setLabel(**self.labelStyle) - self.plot_object.showGrid(x = True, y = True, alpha = 0.5) + self.plot_object.showGrid(x=True, y=True, alpha=0.5) self.plot_object.setMouseEnabled(False, True) self.plot_object.enableAutoRange(x=xAutoRange, y=yAutoRange) - #title - if title: + # title + if title: self.plot_object.setTitle(title) - - def add_scatter(self, color='c', size=3, symbol='o'): + + def add_scatter(self, color="c", size=3, symbol="o"): curve = pg.ScatterPlotItem(symbol=symbol, pen=(color), brush=(color), size=size) self.plot_object.addItem(curve) - return curve - - def add_line(self, color='c', size=3, symbol='o'): + return curve + + def add_line(self, color="c", size=3, symbol="o"): curve = pg.PlotCurveItem(symbol=symbol, pen=(color), brush=(color), size=size) self.plot_object.addItem(curve) - return curve - - def add_infinite_line(self, color='y', style='solid', angle=90., movable=False, hide=True): - ''' + return curve + + def add_infinite_line(self, color="y", style="solid", angle=90.0, movable=False, hide=True): + """ Add an InfiniteLine object. Parameters @@ -710,15 +853,15 @@ def add_infinite_line(self, color='y', style='solid', angle=90., movable=False, ------- InfiniteLine object Useful methods: setValue, show, hide - ''' - if style == 'solid': + """ + if style == "solid": linestyle = QtCore.Qt.SolidLine - elif style == 'dashed': + elif style == "dashed": linestyle = QtCore.Qt.DashLine - elif style == 'dotted': + elif style == "dotted": linestyle = QtCore.Qt.DotLine else: - print('style not recognized in add_infinite_line') + print("style not recognized in add_infinite_line") linestyle = QtCore.Qt.SolidLine pen = pg.mkPen(color, style=linestyle) line = pg.InfiniteLine(pen=pen) @@ -727,21 +870,21 @@ def add_infinite_line(self, color='y', style='solid', angle=90., movable=False, if hide: line.hide() self.plot_object.addItem(line) - return line - + return line + def set_labels(self, xlabel=None, ylabel=None): if xlabel: - self.plot_object.setLabel('bottom', text=xlabel) - self.plot_object.showLabel('bottom') + self.plot_object.setLabel("bottom", text=xlabel) + self.plot_object.showLabel("bottom") if ylabel: - self.plot_object.setLabel('left', text=ylabel) - self.plot_object.showLabel('left') - + self.plot_object.setLabel("left", text=ylabel) + self.plot_object.showLabel("left") + def set_xlim(self, xmin, xmax): self.plot_object.setXRange(xmin, xmax) - + def set_ylim(self, ymin, ymax): self.plot_object.setYRange(ymin, ymax) - + def clear(self): self.plot_object.clear() diff --git a/somatic/acquisition.py b/somatic/acquisition.py index fce17423..4280d972 100644 --- a/somatic/acquisition.py +++ b/somatic/acquisition.py @@ -1,6 +1,6 @@ -''' +""" Acquisition infrastructure shared by all modules. -''' +""" ### import #################################################################### @@ -26,12 +26,14 @@ import WrightTools as wt import project.project_globals as g + app = g.app.read() import hardware.spectrometers.spectrometers as spectrometers import hardware.delays.delays as delays import hardware.opas.opas as opas import hardware.filters.filters as filters + all_hardwares = opas.hardwares + spectrometers.hardwares + delays.hardwares + filters.hardwares import devices.devices as devices @@ -49,7 +51,6 @@ class Axis: - def __init__(self, points, units, name, identity, hardware_dict={}, **kwargs): self.points = points self.units = units @@ -60,21 +61,20 @@ def __init__(self, points, units, name, identity, hardware_dict={}, **kwargs): # fill hardware dictionary with defaults names = re.split("[=F]+", self.identity) # KFS 2018-12-07: Is this still used at all? replacing wt2 kit.parse_identity - if 'F' in self.identity: # last name should be a 'following' in this case + if "F" in self.identity: # last name should be a 'following' in this case names.pop(-1) for name in names: - if name[0] == 'D': - clean_name = name.replace('D', '', 1) + if name[0] == "D": + clean_name = name.replace("D", "", 1) else: clean_name = name if clean_name not in self.hardware_dict.keys(): hardware_object = [h for h in all_hardwares if h.name == clean_name][0] - self.hardware_dict[name] = [hardware_object, 'set_position', None] + self.hardware_dict[name] = [hardware_object, "set_position", None] + - class Constant: - - def __init__(self, units, name, identity, static=True, expression=''): + def __init__(self, units, name, identity, static=True, expression=""): self.units = units self.name = name self.identity = identity @@ -84,7 +84,6 @@ def __init__(self, units, name, identity, static=True, expression=''): class Destinations: - def __init__(self, arr, units, hardware, method, passed_args): self.arr = arr self.units = units @@ -94,19 +93,19 @@ def __init__(self, arr, units, hardware, method, passed_args): class Order: - def __init__(self, name, path): self.name = name self.module = imp.load_source(name, path) self.process = self.module.process + orderers = [] config = configparser.SafeConfigParser() -p = os.path.join(somatic_folder, 'order', 'order.ini') +p = os.path.join(somatic_folder, "order", "order.ini") config.read(p) -for name in config.options('load'): - if config.get('load', name) == 'True': - path = os.path.join(somatic_folder, 'order', name + '.py') +for name in config.options("load"): + if config.get("load", name) == "True": + path = os.path.join(somatic_folder, "order", name + ".py") orderers.append(Order(name, path)) @@ -117,7 +116,7 @@ class Worker(QtCore.QObject): update_ui = QtCore.Signal() scan_complete = QtCore.Signal() done = QtCore.Signal() - + def __init__(self, aqn_path, queue_worker, finished): # do not overload this method QtCore.QObject.__init__(self) @@ -134,11 +133,11 @@ def __init__(self, aqn_path, queue_worker, finished): self.stopped = self.queue_worker.queue_status.stopped # move aqn file into queue folder ini = wt.kit.INI(aqn_path) - module_name = ini.read('info', 'module') - item_name = ini.read('info', 'name') + module_name = ini.read("info", "module") + item_name = ini.read("info", "name") aqn_path = pathlib.Path(aqn_path) aqn_index_str = str(self.queue_worker.index.read()).zfill(3) - aqn_name = ' '.join([aqn_index_str, module_name, item_name]).rstrip() + aqn_name = " ".join([aqn_index_str, module_name, item_name]).rstrip() folder_path = pathlib.Path(self.queue_worker.folder.read()).joinpath(aqn_name) if aqn_path != folder_path.with_suffix(".aqn"): shutil.copyfile(aqn_path, folder_path.with_suffix(".aqn")) @@ -153,13 +152,13 @@ def __init__(self, aqn_path, queue_worker, finished): self.scan_index = None self.scan_folders = [] self.scan_urls = [] - + def process(self, scan_folder): # get path - data_path = devices.data_path.read() + data_path = devices.data_path.read() # make data object data = wt.data.from_PyCMDS(data_path, verbose=False) - data.save(data_path.replace('.data', '.p'), verbose=False) + data.save(data_path.replace(".data", ".p"), verbose=False) # make figures for each channel data_path = pathlib.Path(data_path) data_folder = data_path.parent @@ -169,21 +168,42 @@ def process(self, scan_folder): for channel_index, channel_name in enumerate(data.channel_names): output_folder = data_folder if data.ndim <= 2 else data_folder / channel_name output_folder.mkdir(exist_ok=True) - image_fname = channel_name + ' ' + file_name + image_fname = channel_name + " " + file_name if len(data.shape) == 1: - outs = wt.artists.quick1D(data, channel=channel_index, autosave=True, save_directory=output_folder, - fname=image_fname, verbose=False) + outs = wt.artists.quick1D( + data, + channel=channel_index, + autosave=True, + save_directory=output_folder, + fname=image_fname, + verbose=False, + ) else: - outs = wt.artists.quick2D(data, -1, -2, channel=channel_index, autosave=True, save_directory=output_folder, - fname=image_fname, verbose=False) + outs = wt.artists.quick2D( + data, + -1, + -2, + channel=channel_index, + autosave=True, + save_directory=output_folder, + fname=image_fname, + verbose=False, + ) # hack in a way to get the first image written if channel_index == 0: output_image_path = outs[0] # upload self.upload(self.scan_folders[self.scan_index], reference_image=output_image_path) - def scan(self, axes, constants=[], pre_wait_methods=[], - processing_method='process', module_reserved='', multiple_scans=False): + def scan( + self, + axes, + constants=[], + pre_wait_methods=[], + processing_method="process", + module_reserved="", + multiple_scans=False, + ): # do not overload this method # scan index ---------------------------------------------------------- if self.scan_index is None: @@ -195,10 +215,10 @@ def scan(self, axes, constants=[], pre_wait_methods=[], if len(axes) == 1: arrs = [axes[0].points] else: - arrs = np.meshgrid(*[a.points for a in axes], indexing='ij') + arrs = np.meshgrid(*[a.points for a in axes], indexing="ij") # treat 'scan about center' axes for axis_index, axis in enumerate(axes): - if axis.identity[0] == 'D': + if axis.identity[0] == "D": centers = axis.centers # transpose so own index is first (all others slide down) transpose_order = list(range(len(axes))) @@ -238,47 +258,49 @@ def scan(self, axes, constants=[], pre_wait_methods=[], for idx in np.ndindex(arrs[0].shape): for destination in destinations_list: if wt.units.kind(destination.units) == units_kind: - val = wt.units.converter(destination.arr[idx], destination.units, units) + val = wt.units.converter( + destination.arr[idx], destination.units, units + ) vals[destination.hardware.name] = val arr[idx] = numexpr.evaluate(expression, vals) - # finish + # finish hardware = constant.hardware - destinations = Destinations(arr, units, hardware, 'set_position', None) + destinations = Destinations(arr, units, hardware, "set_position", None) destinations_list.insert(0, destinations) - # check if scan is valid for hardware --------------------------------- + # check if scan is valid for hardware --------------------------------- # TODO: !!! # run through aquisition order handler -------------------------------- order = orderers[0] # TODO: real orderer support idxs, slices = order.process(destinations_list) - # initialize scan ----------------------------------------------------- + # initialize scan ----------------------------------------------------- g.queue_control.write(True) self.going.write(True) - self.fraction_complete.write(0.) - g.logger.log('info', 'Scan begun', '') + self.fraction_complete.write(0.0) + g.logger.log("info", "Scan begun", "") # put info into headers ----------------------------------------------- # clear values from previous scan devices.headers.clear() # data info - devices.headers.data_info['data name'] = self.aqn.read('info', 'name') - devices.headers.data_info['data info'] = self.aqn.read('info', 'info') - devices.headers.data_info['data origin'] = self.aqn.read('info', 'module') + devices.headers.data_info["data name"] = self.aqn.read("info", "name") + devices.headers.data_info["data info"] = self.aqn.read("info", "info") + devices.headers.data_info["data origin"] = self.aqn.read("info", "module") # axes (will be added onto in devices, potentially) - devices.headers.axis_info['axis names'] = [a.name for a in axes] - devices.headers.axis_info['axis identities'] = [a.identity for a in axes] - devices.headers.axis_info['axis units'] = [a.units for a in axes] - devices.headers.axis_info['axis interpolate'] = [False for a in axes] + devices.headers.axis_info["axis names"] = [a.name for a in axes] + devices.headers.axis_info["axis identities"] = [a.identity for a in axes] + devices.headers.axis_info["axis units"] = [a.units for a in axes] + devices.headers.axis_info["axis interpolate"] = [False for a in axes] for axis in axes: - devices.headers.axis_info[axis.name + ' points'] = axis.points - if axis.identity[0] == 'D': - devices.headers.axis_info[axis.name + ' centers'] = axis.centers + devices.headers.axis_info[axis.name + " points"] = axis.points + if axis.identity[0] == "D": + devices.headers.axis_info[axis.name + " centers"] = axis.centers # constants - devices.headers.constant_info['constant names'] = [c.name for c in constants] - devices.headers.constant_info['constant identities'] = [c.identity for c in constants] + devices.headers.constant_info["constant names"] = [c.name for c in constants] + devices.headers.constant_info["constant identities"] = [c.identity for c in constants] # create scan folder scan_index_str = str(self.scan_index).zfill(3) - axis_names = str([str(a.name) for a in axes]).replace('\'', '') + axis_names = str([str(a.name) for a in axes]).replace("'", "") if multiple_scans: - scan_folder_name = ' '.join([scan_index_str, axis_names, module_reserved]).rstrip() + scan_folder_name = " ".join([scan_index_str, axis_names, module_reserved]).rstrip() scan_folder = os.path.join(self.folder, scan_folder_name) os.mkdir(scan_folder) self.scan_folders.append(scan_folder) @@ -293,13 +315,13 @@ def scan(self, axes, constants=[], pre_wait_methods=[], self.scan_urls.append(None) # add urls to headers if g.google_drive_enabled.read(): - devices.headers.scan_info['queue url'] = self.queue_worker.queue_url - devices.headers.scan_info['acquisition url'] = self.aqn.read('info', 'url') - devices.headers.scan_info['scan url'] = scan_url + devices.headers.scan_info["queue url"] = self.queue_worker.queue_url + devices.headers.scan_info["acquisition url"] = self.aqn.read("info", "url") + devices.headers.scan_info["scan url"] = scan_url # initialize devices devices.control.initialize_scan(self.aqn, scan_folder, destinations_list) # acquire ------------------------------------------------------------- - self.fraction_complete.write(0.) + self.fraction_complete.write(0.0) slice_index = 0 npts = float(len(idxs)) for i, idx in enumerate(idxs): @@ -308,14 +330,14 @@ def scan(self, axes, constants=[], pre_wait_methods=[], # launch hardware for d in destinations_list: destination = d.arr[idx] - if d.method == 'set_position': + if d.method == "set_position": d.hardware.set_position(destination, d.units) else: inputs = copy.copy(d.passed_args) for input_index, input_val in enumerate(inputs): - if input_val == 'destination': + if input_val == "destination": inputs[input_index] = destination - elif input_val == 'units': + elif input_val == "units": inputs[input_index] = d.units d.hardware.q.push(d.method, *inputs) # execute pre_wait_methods @@ -323,7 +345,7 @@ def scan(self, axes, constants=[], pre_wait_methods=[], method() # slice if slice_index < len(slices): # takes care of last slice - if slices[slice_index]['index'] == i: + if slices[slice_index]["index"] == i: devices.current_slice.index(slices[slice_index]) slice_index += 1 # wait for hardware @@ -333,10 +355,10 @@ def scan(self, axes, constants=[], pre_wait_methods=[], # wait for devices devices.control.wait_until_done() # update - self.fraction_complete.write(i/npts) + self.fraction_complete.write(i / npts) self.update_ui.emit() # check continue - while self.pause.read(): + while self.pause.read(): self.paused.write(True) self.pause.wait_for_update() self.paused.write(False) @@ -345,10 +367,10 @@ def scan(self, axes, constants=[], pre_wait_methods=[], break # finish scan --------------------------------------------------------- devices.control.wait_until_file_done() - self.fraction_complete.write(1.) + self.fraction_complete.write(1.0) self.going.write(False) g.queue_control.write(False) - g.logger.log('info', 'Scan done', '') + g.logger.log("info", "Scan done", "") self.update_ui.emit() self.scan_complete.emit() # process scan -------------------------------------------------------- @@ -360,32 +382,40 @@ def scan(self, axes, constants=[], pre_wait_methods=[], traceback.print_exc() self.upload(scan_folder) return scan_folder - - def upload(self, scan_folder, message='scan complete', reference_image=None): + + def upload(self, scan_folder, message="scan complete", reference_image=None): # create folder on google drive, upload reference image if g.google_drive_enabled.read(): folder_url = g.google_drive_control.read().id_to_open_url(scan_folder) - g.google_drive_control.read().upload_folder(path=scan_folder, parent_id=str(pathlib.Path(scan_folder).parent), id_=scan_folder) + g.google_drive_control.read().upload_folder( + path=scan_folder, parent_id=str(pathlib.Path(scan_folder).parent), id_=scan_folder + ) image_url = None if reference_image is not None: reference_id = f"{scan_folder} reference" g.google_drive_control.read().reserve_id(reference_id) image_url = g.google_drive_control.read().id_to_download_url(reference_id) - g.google_drive_control.read().create_file(path=reference_image, parent_id=scan_folder, id_=reference_id) + g.google_drive_control.read().create_file( + path=reference_image, parent_id=scan_folder, id_=reference_id + ) else: folder_url = image_url = None # send message on slack if g.slack_enabled.read(): if g.google_drive_enabled.read() and reference_image is not None: start = time.time() - while time.time() - start < 10 and not g.google_drive_control.read().is_uploaded(reference_id): + while time.time() - start < 10 and not g.google_drive_control.read().is_uploaded( + reference_id + ): time.sleep(0.01) slack = g.slack_control.read() field = {} - field['title'] = pathlib.Path(scan_folder).name - field['title_link'] = folder_url - field['image_url'] = image_url - message = ':tada: scan complete - {} elapsed'.format(g.progress_bar.time_elapsed.text()) + field["title"] = pathlib.Path(scan_folder).name + field["title_link"] = folder_url + field["image_url"] = image_url + message = ":tada: scan complete - {} elapsed".format( + g.progress_bar.time_elapsed.text() + ) slack.send_message(message, attachments=[field]) @@ -393,7 +423,6 @@ def upload(self, scan_folder, message='scan complete', reference_image=None): class GUI(QtCore.QObject): - def __init__(self, module_name): QtCore.QObject.__init__(self) self.module_name = module_name @@ -410,7 +439,6 @@ def __init__(self, module_name): self.frame.setLayout(self.layout) # signals and slots devices.control.settings_updated.connect(self.on_device_settings_updated) - def create_frame(self): layout = QtWidgets.QVBoxLayout() @@ -430,9 +458,9 @@ def hide(self): def on_device_settings_updated(self): # overload this if your gui has device-dependent settings pass - + def show(self): - self.frame.show() - + self.frame.show() + def update(self): pass diff --git a/somatic/modules/abstract_tuning.py b/somatic/modules/abstract_tuning.py index 6a90aa8d..8a1c3b41 100644 --- a/somatic/modules/abstract_tuning.py +++ b/somatic/modules/abstract_tuning.py @@ -13,12 +13,13 @@ import hardware.spectrometers.spectrometers as spectrometers import devices.devices as devices + class Worker(acquisition.Worker): def process(self, scan_folder): config = self.config_dictionary - data_path = wt.kit.glob_handler('.data', folder=str(scan_folder))[0] + data_path = wt.kit.glob_handler(".data", folder=str(scan_folder))[0] data = wt.data.from_PyCMDS(data_path) - kwargs = {k.lower(): v for k,v in config["Processing"].items()} + kwargs = {k.lower(): v for k, v in config["Processing"].items()} apply_ = kwargs.pop("apply") old_path = self.curve.save(scan_folder, plot=False) old_path.rename(old_path.with_suffix(f".old{old_path.suffix}")) @@ -26,7 +27,9 @@ def process(self, scan_folder): if apply_ and not self.stopped.read(): path = curve.save(pathlib.Path(self.opa_hardware.curve_paths[self.curve_id]).parent) self.opa_hardware.driver.curve_paths[self.curve_id].write(str(path)) - self.upload(scan_folder, reference_image=str(pathlib.Path(scan_folder) / self.reference_image)) + self.upload( + scan_folder, reference_image=str(pathlib.Path(scan_folder) / self.reference_image) + ) def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config): ... @@ -87,7 +90,7 @@ def run(self): if "num" not in conf: continue full_shape.append(int(conf["num"])) - if spec_action == "Scanned": + if spec_action == "Scanned": for section, conf in config.items(): if not section.startswith("Spectral"): continue @@ -103,28 +106,37 @@ def run(self): name = conf["motor"] width = conf["width"] npts = int(conf["num"]) - points = np.linspace(-width/2.,width/2., npts) - sh = [1] * (len(full_shape)-1) + points = np.linspace(-width / 2.0, width / 2.0, npts) + sh = [1] * (len(full_shape) - 1) sh[0] = len(self.curve[name]) centers = self.curve[name][:].reshape(sh) print(f"{sh}") - centers = np.broadcast_to(centers, full_shape[:index] + full_shape[index+1:]) - hardware_dict = {opa_name: [self.opa_hardware, 'set_motor', [name, 'destination']]} - axes.append(acquisition.Axis(points, None, f"{opa_name}_{name}", f"D{opa_name}", hardware_dict, centers=centers)) + centers = np.broadcast_to(centers, full_shape[:index] + full_shape[index + 1 :]) + hardware_dict = {opa_name: [self.opa_hardware, "set_motor", [name, "destination"]]} + axes.append( + acquisition.Axis( + points, + None, + f"{opa_name}_{name}", + f"D{opa_name}", + hardware_dict, + centers=centers, + ) + ) index += 1 - if spec_action == "Scanned": + if spec_action == "Scanned": for section, conf in config.items(): if not section.startswith("Spectral"): continue name = conf["axis"] width = conf["width"] npts = int(conf["num"]) - points = np.linspace(-width/2.,width/2., npts) - sh = [1] * (len(full_shape)-1) + points = np.linspace(-width / 2.0, width / 2.0, npts) + sh = [1] * (len(full_shape) - 1) sh[0] = len(self.curve.setpoints) centers = self.curve.setpoints[:].reshape(sh) - centers = np.broadcast_to(centers, full_shape[:index] + full_shape[index+1:]) + centers = np.broadcast_to(centers, full_shape[:index] + full_shape[index + 1 :]) axes.append(acquisition.Axis(points, "wn", f"{name}", f"D{name}", centers=centers)) index += 1 @@ -134,15 +146,15 @@ def run(self): self.finished.write(True) - class GUI(acquisition.GUI): - def __init__(self, module_name): - self.items.update({ - "OPA": OpaSectionWidget("OPA", self), - "Spectrometer": SpectrometerSectionWidget("Spectrometer", self), - "Processing": ProcessingSectionWidget("Processing", self), - }) + self.items.update( + { + "OPA": OpaSectionWidget("OPA", self), + "Spectrometer": SpectrometerSectionWidget("Spectrometer", self), + "Processing": ProcessingSectionWidget("Processing", self), + } + ) super().__init__(module_name) for item in self.items.values(): for i in item.items.values(): @@ -163,10 +175,9 @@ def load(self, aqn_path): for item in self.items.values(): item.load(aqn_path) - def save(self, aqn_path): aqn = wt.kit.INI(aqn_path) - aqn.write('info', 'description', f"{self['OPA']['OPA'].read()} {self.module_name}") + aqn.write("info", "description", f"{self['OPA']['OPA'].read()} {self.module_name}") for item in self.items.values(): item.save(aqn_path) @@ -181,6 +192,7 @@ def on_update(self): def __getitem__(self, name): return self.items[name] + class AqnSectionWidget: def __init__(self, section_name, parent): self.section_name = section_name @@ -215,23 +227,27 @@ def on_update(self): def __getitem__(self, name): return self.items[name] - + class OpaSectionWidget(AqnSectionWidget): def __init__(self, section_name, parent): super().__init__(section_name, parent) allowed = [hardware.name for hardware in opas.hardwares] self.items["OPA"] = pc.Combo(allowed) + class SpectrometerSectionWidget(AqnSectionWidget): def __init__(self, section_name, parent): super().__init__(section_name, parent) allowed = [hardware.name for hardware in spectrometers.hardwares] - self.items["Action"] = pc.Combo(["Scanned", "None", "Tracking", "Zero Order"], initial_value = "Scanned") + self.items["Action"] = pc.Combo( + ["Scanned", "None", "Tracking", "Zero Order"], initial_value="Scanned" + ) self.items["Spectrometer"] = pc.Combo(allowed) def on_update(self): self.items["Spectrometer"].set_disabled(self.items["Action"].read() == "None") + class ProcessingSectionWidget(AqnSectionWidget): def __init__(self, section_name, parent): super().__init__(section_name, parent) @@ -244,13 +260,14 @@ def __init__(self, section_name, parent): def on_update(self): self.items["Channel"].set_allowed_values(devices.control.channel_names) + class SpectralAxisSectionWidget(AqnSectionWidget): def __init__(self, section_name, parent): super().__init__(section_name, parent) self.items["Axis"] = pc.Combo() self.items["Width"] = pc.Number(initial_value=-250) self.items["Num"] = pc.Number(initial_value=51, decimals=0) - + def on_update(self): if self.parent["Spectrometer"]["Action"].read() == "Scanned": allowed = [self.parent["Spectrometer"]["Spectrometer"].read()] @@ -268,7 +285,7 @@ def on_update(self): allowed = [""] self.items["Axis"].set_allowed_values(allowed) self.items["Axis"].set_disabled(len(allowed) > 1) - + class MotorAxisSectionWidget(AqnSectionWidget): def __init__(self, section_name, parent): @@ -282,7 +299,5 @@ def on_update(self): self.items["Motor"].set_allowed_values(hardware.curve.dependent_names) - - def load(): return False diff --git a/somatic/modules/home.py b/somatic/modules/home.py index ec0668b7..ca5ebfdc 100644 --- a/somatic/modules/home.py +++ b/somatic/modules/home.py @@ -6,33 +6,32 @@ import project.classes as pc import project.widgets as pw import somatic.acquisition as acquisition + main_dir = g.main_dir.read() app = g.app.read() import hardware.opas.opas as opas - + ### define #################################################################### -module_name = 'HOME' +module_name = "HOME" ### custom classes ############################################################ -class MotorGUI(): - +class MotorGUI: def __init__(self, name, home): self.name = name self.input_table = pw.InputTable() self.input_table.add(name, None) self.home = pc.Bool(initial_value=home) - self.input_table.add('Home', self.home) + self.input_table.add("Home", self.home) -class OPA_GUI(): - +class OPA_GUI: def __init__(self, hardware, layout): self.hardware = hardware motor_names = self.hardware.motor_names @@ -43,37 +42,35 @@ def __init__(self, hardware, layout): layout.addWidget(motor.input_table) self.motors.append(motor) self.hide() # initialize hidden - + def hide(self): for motor in self.motors: motor.input_table.hide() - + def show(self): for motor in self.motors: motor.input_table.show() - ### Worker #################################################################### class Worker(acquisition.Worker): - def process(self, scan_folder): pass - + def run(self): # get OPA properties - opa_name = self.aqn.read('home', 'opa name') + opa_name = self.aqn.read("home", "opa name") opa_names = [h.name for h in opas.hardwares] opa_index = opa_names.index(opa_name) opa_hardware = opas.hardwares[opa_index] opa_friendly_name = opa_hardware.name curve = opa_hardware.curve - motor_names = self.aqn.read('home', 'motor names') + motor_names = self.aqn.read("home", "motor names") # motor for motor_index, motor_name in enumerate(motor_names): - if self.aqn.read(motor_name, 'home'): + if self.aqn.read(motor_name, "home"): opa_hardware.home_motor([motor_name]) opa_hardware.wait_until_still() if not self.stopped.read(): @@ -84,33 +81,32 @@ def run(self): class GUI(acquisition.GUI): - def create_frame(self): # shared settings input_table = pw.InputTable() allowed = [hardware.name for hardware in opas.hardwares] self.opa_combo = pc.Combo(allowed) - input_table.add('OPA', self.opa_combo) + input_table.add("OPA", self.opa_combo) self.opa_combo.updated.connect(self.on_opa_combo_updated) self.layout.addWidget(input_table) # motor settings self.opa_guis = [OPA_GUI(hardware, self.layout) for hardware in opas.hardwares] self.opa_guis[0].show() - + def load(self, aqn_path): aqn = wt.kit.INI(aqn_path) # shared settings - self.opa_combo.write(aqn.read('home', 'opa name')) + self.opa_combo.write(aqn.read("home", "opa name")) # motor settings opa = self.opa_guis[self.opa_combo.read_index()] - for motor, motor_name in zip(opa.motors, aqn.read('home', 'motor names')): - motor.home.write(aqn.read(motor_name, 'home')) + for motor, motor_name in zip(opa.motors, aqn.read("home", "motor names")): + motor.home.write(aqn.read(motor_name, "home")) # allow devices to read from aqn self.device_widget.load(aqn_path) def on_opa_combo_updated(self): self.show_opa_gui(self.opa_combo.read_index()) - + def save(self, aqn_path): aqn = wt.kit.INI(aqn_path) opa = self.opa_guis[self.opa_combo.read_index()] @@ -118,29 +114,38 @@ def save(self, aqn_path): for motor in opa.motors: if motor.home.read() == True: homed_motor_names.append(motor.name) - homed_motor_names = str(homed_motor_names).replace('\'', '') - aqn.write('info', 'description', 'HOME: {} {}'.format(self.opa_combo.read(), homed_motor_names)) + homed_motor_names = str(homed_motor_names).replace("'", "") + aqn.write( + "info", "description", "HOME: {} {}".format(self.opa_combo.read(), homed_motor_names) + ) # shared settings - aqn.add_section('home') - aqn.write('home', 'opa name', self.opa_combo.read()) - aqn.write('home', 'motor names', [motor.name for motor in self.opa_guis[self.opa_combo.read_index()].motors]) + aqn.add_section("home") + aqn.write("home", "opa name", self.opa_combo.read()) + aqn.write( + "home", + "motor names", + [motor.name for motor in self.opa_guis[self.opa_combo.read_index()].motors], + ) # motor settings for motor in opa.motors: aqn.add_section(motor.name) - aqn.write(motor.name, 'home', motor.home.read()) + aqn.write(motor.name, "home", motor.home.read()) # allow devices to save to aqn self.device_widget.save(aqn_path) - + def show_opa_gui(self, index): for gui in self.opa_guis: gui.hide() self.opa_guis[index].show() - + def update_mono_settings(self): pass + def mkGUI(): global gui gui = GUI(module_name) + + def load(): return True diff --git a/somatic/modules/motortune.py b/somatic/modules/motortune.py index 44eda03e..69eb3ae7 100644 --- a/somatic/modules/motortune.py +++ b/somatic/modules/motortune.py @@ -7,6 +7,7 @@ import numpy as np import matplotlib + matplotlib.pyplot.ioff() import WrightTools as wt @@ -16,43 +17,43 @@ import project.widgets as pw import somatic.acquisition as acquisition import project.ini_handler as ini_handler + main_dir = g.main_dir.read() -ini = ini_handler.Ini(os.path.join(main_dir, 'somatic', 'modules', 'motortune.ini')) +ini = ini_handler.Ini(os.path.join(main_dir, "somatic", "modules", "motortune.ini")) app = g.app.read() import hardware.opas.opas as opas import hardware.spectrometers.spectrometers as spectrometers import devices.devices as devices - + ### define #################################################################### -module_name = 'MOTORTUNE' +module_name = "MOTORTUNE" ### custom classes ############################################################ -class MotorGUI(): - +class MotorGUI: def __init__(self, name, center, width, number, use_tune_points): self.name = name self.use_tune_points = use_tune_points self.input_table = pw.InputTable() self.input_table.add(name, None) - allowed = ['Set', 'Scan', 'Static'] + allowed = ["Set", "Scan", "Static"] self.method = pc.Combo(allowed_values=allowed) if self.use_tune_points is not None: self.use_tune_points.updated.connect(self.update_disabled) self.method.updated.connect(self.update_disabled) - self.input_table.add('Method', self.method) + self.input_table.add("Method", self.method) self.center = pc.Number(initial_value=center) - self.input_table.add('Center', self.center) + self.input_table.add("Center", self.center) self.width = pc.Number(initial_value=width) - self.input_table.add('Width', self.width) + self.input_table.add("Width", self.width) self.npts = pc.Number(initial_value=number, decimals=0) - self.input_table.add('Number', self.npts) + self.input_table.add("Number", self.npts) self.update_disabled() def update_disabled(self): @@ -60,18 +61,17 @@ def update_disabled(self): self.width.set_disabled(True) self.npts.set_disabled(True) method = self.method.read() - if method == 'Set': + if method == "Set": self.center.set_disabled(self.use_tune_points.read()) - elif method == 'Scan': + elif method == "Scan": self.center.set_disabled(self.use_tune_points.read()) self.width.set_disabled(False) self.npts.set_disabled(False) - elif method == 'Static': + elif method == "Static": self.center.set_disabled(False) -class OPA_GUI(): - +class OPA_GUI: def __init__(self, hardware, layout, use_tune_points): self.hardware = hardware motor_names = self.hardware.motor_names @@ -82,28 +82,26 @@ def __init__(self, hardware, layout, use_tune_points): layout.addWidget(motor.input_table) self.motors.append(motor) self.hide() # initialize hidden - + def hide(self): for motor in self.motors: motor.input_table.hide() - + def show(self): for motor in self.motors: motor.input_table.show() - ### Worker #################################################################### class Worker(acquisition.Worker): - def process(self, scan_folder): - if not self.aqn.read('processing', 'do post process'): + if not self.aqn.read("processing", "do post process"): self.upload(self.scan_folders[self.scan_index], reference_image=None) return # get path - data_path = devices.data_path.read() + data_path = devices.data_path.read() # make data object data = wt.data.from_PyCMDS(data_path, verbose=False) data_path = pathlib.Path(data_path) @@ -116,119 +114,165 @@ def process(self, scan_folder): file_name = data_path.stem file_extension = data_path.suffix # make all images - channel = self.aqn.read('processing', 'channel') + channel = self.aqn.read("processing", "channel") image_fname = channel if data.ndim == 1: - filepaths = wt.artists.quick1D(data, channel=channel, autosave=True, save_directory=output_folder, - fname=image_fname, verbose=False) + filepaths = wt.artists.quick1D( + data, + channel=channel, + autosave=True, + save_directory=output_folder, + fname=image_fname, + verbose=False, + ) else: - filepaths = wt.artists.quick2D(data, -1, -2, channel=channel, autosave=True, save_directory=output_folder, - fname=image_fname, verbose=False) + filepaths = wt.artists.quick2D( + data, + -1, + -2, + channel=channel, + autosave=True, + save_directory=output_folder, + fname=image_fname, + verbose=False, + ) # get output image if len(filepaths) == 1: output_image_path = filepaths[0] else: - output_image_path = str(output_folder / 'animation.gif') + output_image_path = str(output_folder / "animation.gif") wt.artists.stitch_to_animation(images=filepaths, outpath=output_image_path) # upload - self.upload(self.scan_folders[self.scan_index], reference_image=output_image_path) - + self.upload(self.scan_folders[self.scan_index], reference_image=output_image_path) + def run(self): # assemble axes axes = [] # get OPA properties - opa_name = self.aqn.read('motortune', 'opa name') + opa_name = self.aqn.read("motortune", "opa name") opa_names = [h.name for h in opas.hardwares] opa_index = opa_names.index(opa_name) opa_hardware = opas.hardwares[opa_index] opa_friendly_name = opa_hardware.name curve = opa_hardware.curve - motor_names = self.aqn.read('motortune', 'motor names') - # tune points - if self.aqn.read('motortune', 'use tune points'): - motors_excepted = [] # list of indicies + motor_names = self.aqn.read("motortune", "motor names") + # tune points + if self.aqn.read("motortune", "use tune points"): + motors_excepted = [] # list of indicies for motor_name in motor_names: - if not self.aqn.read(motor_name, 'method') == 'Set': + if not self.aqn.read(motor_name, "method") == "Set": motors_excepted.append(motor_name) - if self.aqn.read('spectrometer', 'method') == 'Set': - identity = opa_friendly_name + '=wm' - hardware_dict = {opa_friendly_name: [opa_hardware, 'set_position_except', ['destination', motors_excepted]], - 'wm': [spectrometers.hardwares[0], 'set_position', None]} - axis = acquisition.Axis(curve.setpoints[:], curve.setpoints.units, opa_friendly_name, identity, hardware_dict) + if self.aqn.read("spectrometer", "method") == "Set": + identity = opa_friendly_name + "=wm" + hardware_dict = { + opa_friendly_name: [ + opa_hardware, + "set_position_except", + ["destination", motors_excepted], + ], + "wm": [spectrometers.hardwares[0], "set_position", None], + } + axis = acquisition.Axis( + curve.setpoints[:], + curve.setpoints.units, + opa_friendly_name, + identity, + hardware_dict, + ) axes.append(axis) else: - hardware_dict = {opa_friendly_name: [opa_hardware, 'set_position_except', ['destination', motors_excepted]]} - axis = acquisition.Axis(curve.setpoints[:], curve.setpoints.units, opa_friendly_name, opa_friendly_name, hardware_dict) + hardware_dict = { + opa_friendly_name: [ + opa_hardware, + "set_position_except", + ["destination", motors_excepted], + ] + } + axis = acquisition.Axis( + curve.setpoints[:], + curve.setpoints.units, + opa_friendly_name, + opa_friendly_name, + hardware_dict, + ) axes.append(axis) # motor for motor_name in motor_names: - if self.aqn.read(motor_name, 'method') == 'Scan': + if self.aqn.read(motor_name, "method") == "Scan": motor_units = None - name = '_'.join([opa_friendly_name, motor_name]) - width = self.aqn.read(motor_name, 'width')/2. - npts = self.aqn.read(motor_name, 'number') - if self.aqn.read('motortune', 'use tune points'): - center = 0. - identity = 'D'+name + name = "_".join([opa_friendly_name, motor_name]) + width = self.aqn.read(motor_name, "width") / 2.0 + npts = self.aqn.read(motor_name, "number") + if self.aqn.read("motortune", "use tune points"): + center = 0.0 + identity = "D" + name motor_positions = curve[motor_name][:] - kwargs = {'centers': motor_positions} + kwargs = {"centers": motor_positions} else: - center = self.aqn.read(motor_name, 'center') + center = self.aqn.read(motor_name, "center") identity = name kwargs = {} - points = np.linspace(center-width, center+width, npts) - hardware_dict = {name: [opa_hardware, 'set_motor', [motor_name, 'destination']]} - axis = acquisition.Axis(points, motor_units, name, identity, hardware_dict, **kwargs) + points = np.linspace(center - width, center + width, npts) + hardware_dict = {name: [opa_hardware, "set_motor", [motor_name, "destination"]]} + axis = acquisition.Axis( + points, motor_units, name, identity, hardware_dict, **kwargs + ) axes.append(axis) - elif self.aqn.read(motor_name, 'method') == 'Set': + elif self.aqn.read(motor_name, "method") == "Set": pass - elif self.aqn.read(motor_name, 'method') == 'Static': - opa_hardware.q.push('set_motor', [motor_name, self.aqn.read(motor_name, 'center')]) + elif self.aqn.read(motor_name, "method") == "Static": + opa_hardware.q.push("set_motor", [motor_name, self.aqn.read(motor_name, "center")]) # mono - if self.aqn.read('spectrometer', 'method') == 'Scan': - name = 'wm' - units = 'wn' - width = self.aqn.read('spectrometer', 'width')/2. - npts = self.aqn.read('spectrometer', 'number') - if self.aqn.read('motortune', 'use tune points'): - center = 0. - identity = 'D'+name + if self.aqn.read("spectrometer", "method") == "Scan": + name = "wm" + units = "wn" + width = self.aqn.read("spectrometer", "width") / 2.0 + npts = self.aqn.read("spectrometer", "number") + if self.aqn.read("motortune", "use tune points"): + center = 0.0 + identity = "D" + name curve = curve.copy() - curve.convert('wn') - #centers_shape = [a.points.size for a in axes] - #centers = np.transpose(curve.setpoints[:] * np.ones(centers_shape).T) - kwargs = {'centers': curve.setpoints[:]} + curve.convert("wn") + # centers_shape = [a.points.size for a in axes] + # centers = np.transpose(curve.setpoints[:] * np.ones(centers_shape).T) + kwargs = {"centers": curve.setpoints[:]} else: - center = self.aqn.read('spectrometer', 'center') - center = wt.units.convert(center, self.aqn.read('spectrometer', 'center units'), 'wn') + center = self.aqn.read("spectrometer", "center") + center = wt.units.convert( + center, self.aqn.read("spectrometer", "center units"), "wn" + ) identity = name kwargs = {} - points = np.linspace(center-width, center+width, npts) + points = np.linspace(center - width, center + width, npts) axis = acquisition.Axis(points, units, name, identity, **kwargs) axes.append(axis) - elif self.aqn.read('spectrometer', 'method') == 'Set': - if self.aqn.read('motortune', 'use tune points'): + elif self.aqn.read("spectrometer", "method") == "Set": + if self.aqn.read("motortune", "use tune points"): # already handled above pass else: - center = self.aqn.read('spectrometer', 'center') - center = wt.units.convert(center, self.aqn.read('spectrometer', 'center units'), 'wn') - spectrometers.hardwares[0].set_position(center, 'wn') - elif self.aqn.read('spectrometer', 'method') == 'Static': - center = self.aqn.read('spectrometer', 'center') - center = wt.units.convert(center, self.aqn.read('spectrometer', 'center units'), 'wn') - spectrometers.hardwares[0].set_position(center, 'wn') + center = self.aqn.read("spectrometer", "center") + center = wt.units.convert( + center, self.aqn.read("spectrometer", "center units"), "wn" + ) + spectrometers.hardwares[0].set_position(center, "wn") + elif self.aqn.read("spectrometer", "method") == "Static": + center = self.aqn.read("spectrometer", "center") + center = wt.units.convert(center, self.aqn.read("spectrometer", "center units"), "wn") + spectrometers.hardwares[0].set_position(center, "wn") # handle centers for axis_index, axis in enumerate(axes): centers_shape = [a.points.size for i, a in enumerate(axes) if not i == axis_index] ones = np.ones(centers_shape) - if hasattr(axis, 'centers'): + if hasattr(axis, "centers"): # arrays always follow axis.centers = np.transpose(axis.centers * ones.T) # launch - pre_wait_methods = [lambda: opa_hardware.q.push('wait_until_still'), - lambda: opa_hardware.q.push('get_motor_positions'), - lambda: opa_hardware.q.push('get_position')] + pre_wait_methods = [ + lambda: opa_hardware.q.push("wait_until_still"), + lambda: opa_hardware.q.push("get_motor_positions"), + lambda: opa_hardware.q.push("get_position"), + ] # do scan self.scan(axes, constants=[], pre_wait_methods=pre_wait_methods) if not self.stopped.read(): @@ -239,131 +283,147 @@ def run(self): class GUI(acquisition.GUI): - def create_frame(self): # shared settings input_table = pw.InputTable() allowed = [hardware.name for hardware in opas.hardwares] self.opa_combo = pc.Combo(allowed) - input_table.add('OPA', self.opa_combo) + input_table.add("OPA", self.opa_combo) self.opa_combo.updated.connect(self.on_opa_combo_updated) self.use_tune_points = pc.Bool(initial_value=True) - input_table.add('Use Tune Points', self.use_tune_points) + input_table.add("Use Tune Points", self.use_tune_points) self.layout.addWidget(input_table) # motor settings - self.opa_guis = [OPA_GUI(hardware, self.layout, self.use_tune_points) for hardware in opas.hardwares] + self.opa_guis = [ + OPA_GUI(hardware, self.layout, self.use_tune_points) for hardware in opas.hardwares + ] self.opa_guis[0].show() # mono settings - allowed = ['Set', 'Scan', 'Static'] + allowed = ["Set", "Scan", "Static"] self.mono_method_combo = pc.Combo(allowed, disable_under_module_control=True) self.mono_method_combo.updated.connect(self.update_mono_settings) - self.mono_center = pc.Number(initial_value=7000, units='wn', disable_under_module_control=True) - self.mono_width = pc.Number(initial_value=500, units='wn', disable_under_module_control=True) + self.mono_center = pc.Number( + initial_value=7000, units="wn", disable_under_module_control=True + ) + self.mono_width = pc.Number( + initial_value=500, units="wn", disable_under_module_control=True + ) self.mono_width.set_disabled_units(True) self.mono_npts = pc.Number(initial_value=51, decimals=0, disable_under_module_control=True) input_table = pw.InputTable() - input_table.add('Spectrometer', None) - input_table.add('Method', self.mono_method_combo) - input_table.add('Center', self.mono_center) - input_table.add('Width', self.mono_width) - input_table.add('Number', self.mono_npts) + input_table.add("Spectrometer", None) + input_table.add("Method", self.mono_method_combo) + input_table.add("Center", self.mono_center) + input_table.add("Width", self.mono_width) + input_table.add("Number", self.mono_npts) self.layout.addWidget(input_table) self.update_mono_settings() # processing input_table = pw.InputTable() - input_table.add('Processing', None) + input_table.add("Processing", None) self.do_post_process = pc.Bool(initial_value=True) - input_table.add('Process', self.do_post_process) + input_table.add("Process", self.do_post_process) # TODO: allowed values, update self.main_channel = pc.Combo() - input_table.add('Channel', self.main_channel) - self.layout.addWidget(input_table) - + input_table.add("Channel", self.main_channel) + self.layout.addWidget(input_table) + def load(self, aqn_path): aqn = wt.kit.INI(aqn_path) # shared settings - self.opa_combo.write(aqn.read('motortune', 'opa name')) - self.use_tune_points.write(aqn.read('motortune', 'use tune points')) + self.opa_combo.write(aqn.read("motortune", "opa name")) + self.use_tune_points.write(aqn.read("motortune", "use tune points")) # motor settings opa = self.opa_guis[self.opa_combo.read_index()] - for motor, motor_name in zip(opa.motors, aqn.read('motortune', 'motor names')): - motor.method.write(aqn.read(motor_name, 'method')) - motor.center.write(aqn.read(motor_name, 'center')) - motor.width.write(aqn.read(motor_name, 'width')) - motor.npts.write(aqn.read(motor_name, 'number')) + for motor, motor_name in zip(opa.motors, aqn.read("motortune", "motor names")): + motor.method.write(aqn.read(motor_name, "method")) + motor.center.write(aqn.read(motor_name, "center")) + motor.width.write(aqn.read(motor_name, "width")) + motor.npts.write(aqn.read(motor_name, "number")) # mono settings - self.mono_method_combo.write(aqn.read('spectrometer', 'method')) - self.mono_center.write(aqn.read('spectrometer', 'center')) - self.mono_width.write(aqn.read('spectrometer', 'width')) - self.mono_npts.write(aqn.read('spectrometer', 'number')) + self.mono_method_combo.write(aqn.read("spectrometer", "method")) + self.mono_center.write(aqn.read("spectrometer", "center")) + self.mono_width.write(aqn.read("spectrometer", "width")) + self.mono_npts.write(aqn.read("spectrometer", "number")) # processing - self.do_post_process.write(aqn.read('processing', 'do post process')) - self.main_channel.write(aqn.read('processing', 'channel')) + self.do_post_process.write(aqn.read("processing", "do post process")) + self.main_channel.write(aqn.read("processing", "channel")) # allow devices to read from aqn self.device_widget.load(aqn_path) - + def on_device_settings_updated(self): self.main_channel.set_allowed_values(devices.control.channel_names) - + def on_opa_combo_updated(self): self.show_opa_gui(self.opa_combo.read_index()) - + def save(self, aqn_path): aqn = wt.kit.INI(aqn_path) opa = self.opa_guis[self.opa_combo.read_index()] scanned_motor_names = [] for motor in opa.motors: - if motor.method == 'Scan': + if motor.method == "Scan": scanned_motor_names.append(motor.name) - scanned_motor_names = str(scanned_motor_names).replace('\'', '') - aqn.write('info', 'description', 'MOTORTUNE: {} {}'.format(self.opa_combo.read(), scanned_motor_names)) + scanned_motor_names = str(scanned_motor_names).replace("'", "") + aqn.write( + "info", + "description", + "MOTORTUNE: {} {}".format(self.opa_combo.read(), scanned_motor_names), + ) # shared settings - aqn.add_section('motortune') - aqn.write('motortune', 'opa name', self.opa_combo.read()) - aqn.write('motortune', 'motor names', [motor.name for motor in self.opa_guis[self.opa_combo.read_index()].motors]) - aqn.write('motortune', 'use tune points', self.use_tune_points.read()) + aqn.add_section("motortune") + aqn.write("motortune", "opa name", self.opa_combo.read()) + aqn.write( + "motortune", + "motor names", + [motor.name for motor in self.opa_guis[self.opa_combo.read_index()].motors], + ) + aqn.write("motortune", "use tune points", self.use_tune_points.read()) # motor settings for motor in opa.motors: aqn.add_section(motor.name) - aqn.write(motor.name, 'method', motor.method.read()) - aqn.write(motor.name, 'center', motor.center.read()) - aqn.write(motor.name, 'width', motor.width.read()) - aqn.write(motor.name, 'number', motor.npts.read()) + aqn.write(motor.name, "method", motor.method.read()) + aqn.write(motor.name, "center", motor.center.read()) + aqn.write(motor.name, "width", motor.width.read()) + aqn.write(motor.name, "number", motor.npts.read()) # mono settings - aqn.add_section('spectrometer') - aqn.write('spectrometer', 'method', self.mono_method_combo.read()) - aqn.write('spectrometer', 'center', self.mono_center.read()) - aqn.write('spectrometer', 'center units', self.mono_center.units) - aqn.write('spectrometer', 'width', self.mono_width.read()) - aqn.write('spectrometer', 'number', self.mono_npts.read()) + aqn.add_section("spectrometer") + aqn.write("spectrometer", "method", self.mono_method_combo.read()) + aqn.write("spectrometer", "center", self.mono_center.read()) + aqn.write("spectrometer", "center units", self.mono_center.units) + aqn.write("spectrometer", "width", self.mono_width.read()) + aqn.write("spectrometer", "number", self.mono_npts.read()) # processing - aqn.add_section('processing') - aqn.write('processing', 'do post process', self.do_post_process.read()) - aqn.write('processing', 'channel', self.main_channel.read()) + aqn.add_section("processing") + aqn.write("processing", "do post process", self.do_post_process.read()) + aqn.write("processing", "channel", self.main_channel.read()) # allow devices to save to aqn self.device_widget.save(aqn_path) - + def show_opa_gui(self, index): for gui in self.opa_guis: gui.hide() self.opa_guis[index].show() - + def update_mono_settings(self): self.mono_center.set_disabled(True) self.mono_width.set_disabled(True) self.mono_npts.set_disabled(True) method = self.mono_method_combo.read() - if method == 'Set': + if method == "Set": self.mono_center.set_disabled(self.use_tune_points.read()) - elif method == 'Scan': + elif method == "Scan": self.mono_center.set_disabled(self.use_tune_points.read()) self.mono_width.set_disabled(False) self.mono_npts.set_disabled(False) - elif method == 'Static': + elif method == "Static": self.mono_center.set_disabled(False) - -def mkGUI(): + + +def mkGUI(): global gui gui = GUI(module_name) + + def load(): return True diff --git a/somatic/modules/scan.py b/somatic/modules/scan.py index 269a8b97..44572f81 100644 --- a/somatic/modules/scan.py +++ b/somatic/modules/scan.py @@ -6,6 +6,7 @@ import numpy as np import matplotlib + matplotlib.pyplot.ioff() from PySide2 import QtWidgets @@ -16,96 +17,96 @@ import project.widgets as pw import somatic.acquisition as acquisition import project.ini_handler as ini_handler + main_dir = g.main_dir.read() -ini = ini_handler.Ini(os.path.join(main_dir, 'somatic', 'modules', 'scan.ini')) +ini = ini_handler.Ini(os.path.join(main_dir, "somatic", "modules", "scan.ini")) app = g.app.read() import hardware.spectrometers.spectrometers as spectrometers import hardware.delays.delays as delays import hardware.opas.opas as opas import hardware.filters.filters as filters + all_hardwares = opas.hardwares + spectrometers.hardwares + delays.hardwares + filters.hardwares import devices.devices as devices - + ### define #################################################################### -module_name = 'SCAN' +module_name = "SCAN" ### custom classes ############################################################ -class Axis(): - +class Axis: def __init__(self, units_kind, axis_index): print(filters.hardwares) self.units_kind = units_kind - if self.units_kind == 'energy': - self.units = 'wn' + if self.units_kind == "energy": + self.units = "wn" initial_start = 1500 initial_stop = 1200 - elif self.units_kind == 'delay': - self.units = 'ps' + elif self.units_kind == "delay": + self.units = "ps" initial_start = -1 initial_stop = 1 - elif self.units_kind == 'angle': - self.units = 'deg' - initial_start = 0. - initial_stop = 360. + elif self.units_kind == "angle": + self.units = "deg" + initial_start = 0.0 + initial_stop = 360.0 self.widget = pw.InputTable() - self.widget.add(str(axis_index) + ' (' + self.units_kind + ')', None) + self.widget.add(str(axis_index) + " (" + self.units_kind + ")", None) # start self.start = pc.Number(initial_value=initial_start, units=self.units) self.start.set_disabled_units(True) - self.widget.add('Initial', self.start) + self.widget.add("Initial", self.start) # stop self.stop = pc.Number(initial_value=initial_stop, units=self.units) self.stop.set_disabled_units(True) - self.widget.add('Final', self.stop) + self.widget.add("Final", self.stop) # number self.number = pc.Number(initial_value=51, decimals=0) - self.widget.add('Number', self.number) + self.widget.add("Number", self.number) # hardwares - if self.units_kind == 'energy': + if self.units_kind == "energy": hardware_objs = opas.hardwares + spectrometers.hardwares - elif self.units_kind == 'delay': + elif self.units_kind == "delay": hardware_objs = delays.hardwares - elif self.units_kind == 'angle': + elif self.units_kind == "angle": hardware_objs = filters.hardwares self.hardwares = {} for hw in hardware_objs: checkbox = pc.Bool() self.widget.add(hw.name, checkbox) self.hardwares[hw.name] = checkbox - + def get_name(self): - return '='.join([key for key in self.hardwares if self.hardwares[key].read()]) - + return "=".join([key for key in self.hardwares if self.hardwares[key].read()]) + def hide(self): self.widget.hide() - - -class Constant(): - + + +class Constant: def __init__(self): self.widget = pw.InputTable() - self.widget.add('Constant', None) + self.widget.add("Constant", None) # hardware name allowed_values = [h.name for h in all_hardwares] self.hardware_name_combo = pc.Combo(allowed_values=allowed_values) self.hardware_name_combo.write(spectrometers.hardwares[0].name) - #self.hardware_name_combo.set_disabled(True) - self.widget.add('Hardware', self.hardware_name_combo) + # self.hardware_name_combo.set_disabled(True) + self.widget.add("Hardware", self.hardware_name_combo) # expression opanames = [h.name for h in opas.hardwares] self.expression = pc.String(initial_value="+".join(opanames)) - self.widget.add('Expression', self.expression) + self.widget.add("Expression", self.expression) def get_name(self): - return self.hardware_name_combo.read() - + return self.hardware_name_combo.read() + def hide(self): self.widget.hide() @@ -114,15 +115,14 @@ def hide(self): class Worker(acquisition.Worker): - def process(self, scan_folder): # get path - data_path = devices.data_path.read() + data_path = devices.data_path.read() # make data object data = wt.data.from_PyCMDS(data_path, verbose=False) # decide which channels to make plots for - main_channel = self.aqn.read('processing', 'main channel') - if self.aqn.read('processing', 'process all channels'): + main_channel = self.aqn.read("processing", "main channel") + if self.aqn.read("processing", "process all channels"): channels = data.channel_names else: channels = [main_channel] @@ -141,45 +141,61 @@ def process(self, scan_folder): channel_index = data.channel_names.index(channel_name) image_fname = channel_name if data.ndim == 1: - outs = wt.artists.quick1D(data, channel=channel_index, autosave=True, save_directory=output_path, - fname=image_fname, verbose=False) + outs = wt.artists.quick1D( + data, + channel=channel_index, + autosave=True, + save_directory=output_path, + fname=image_fname, + verbose=False, + ) else: - outs = wt.artists.quick2D(data, -1, -2, channel=channel_index, autosave=True, save_directory=output_path, - fname=image_fname, verbose=False) + outs = wt.artists.quick2D( + data, + -1, + -2, + channel=channel_index, + autosave=True, + save_directory=output_path, + fname=image_fname, + verbose=False, + ) if channel_name == main_channel: outputs = outs # get output image if len(outputs) == 1: output_image_path = outputs[0] else: - output_image_path = output_path / 'animation.gif' + output_image_path = output_path / "animation.gif" wt.artists.stitch_to_animation(images=outputs, outpath=output_image_path) # upload self.upload(scan_folder, reference_image=str(output_image_path)) - + def run(self): # axes axes = [] - for axis_name in self.aqn.read('scan', 'axis names'): - start = self.aqn.read(axis_name, 'start') - stop = self.aqn.read(axis_name, 'stop') - number = self.aqn.read(axis_name, 'number') + for axis_name in self.aqn.read("scan", "axis names"): + start = self.aqn.read(axis_name, "start") + stop = self.aqn.read(axis_name, "stop") + number = self.aqn.read(axis_name, "number") points = np.linspace(start, stop, number) - units = self.aqn.read(axis_name, 'units') + units = self.aqn.read(axis_name, "units") axis = acquisition.Axis(points, units, axis_name, axis_name) axes.append(axis) # constants constants = [] - for constant_name in self.aqn.read('scan', 'constant names'): + for constant_name in self.aqn.read("scan", "constant names"): for hardware in all_hardwares: if hardware.name == constant_name: units = hardware.units - if wt.units.kind(units) == 'energy': - units = 'wn' + if wt.units.kind(units) == "energy": + units = "wn" break name = constant_name - identity = expression = self.aqn.read(constant_name, 'expression') - constant = acquisition.Constant(units, name, identity, expression=expression, static=False) + identity = expression = self.aqn.read(constant_name, "expression") + constant = acquisition.Constant( + units, name, identity, expression=expression, static=False + ) constants.append(constant) # do scan self.scan(axes, constants) @@ -187,12 +203,11 @@ def run(self): if not self.stopped.read(): self.finished.write(True) # only if acquisition successfull - + ### GUI ####################################################################### class GUI(acquisition.GUI): - def add_axis(self, units_kind): axis = Axis(units_kind, len(self.axes)) self.axes_container_widget.layout().addWidget(axis.widget) @@ -206,16 +221,20 @@ def add_buttons(self): button_container.layout().setMargin(0) # remove remove_button = QtWidgets.QPushButton() - remove_button.setText('REMOVE') + remove_button.setText("REMOVE") remove_button.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['stop']) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["stop"] + ) remove_button.setStyleSheet(StyleSheet) button_container.layout().addWidget(remove_button) # add add_button = QtWidgets.QPushButton() - add_button.setText('ADD') + add_button.setText("ADD") add_button.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['set']) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["set"] + ) add_button.setStyleSheet(StyleSheet) button_container.layout().addWidget(add_button) # finish @@ -223,7 +242,7 @@ def add_buttons(self): return [add_button, remove_button] def add_constant(self): - #if len(self.constants) == 1: return # temporary... + # if len(self.constants) == 1: return # temporary... constant = Constant() self.constants_container_widget.layout().addWidget(constant.widget) self.constants.append(constant) @@ -232,28 +251,28 @@ def create_frame(self): # axes self.axes = [] input_table = pw.InputTable() - input_table.add('Axes', None) + input_table.add("Axes", None) self.layout.addWidget(input_table) self.axes_container_widget = QtWidgets.QWidget() self.axes_container_widget.setLayout(QtWidgets.QVBoxLayout()) self.axes_container_widget.layout().setMargin(0) self.layout.addWidget(self.axes_container_widget) - add_energy_axis_button = pw.SetButton('ADD ENERGY AXIS') - add_energy_axis_button.clicked.connect(lambda: self.add_axis('energy')) + add_energy_axis_button = pw.SetButton("ADD ENERGY AXIS") + add_energy_axis_button.clicked.connect(lambda: self.add_axis("energy")) self.layout.addWidget(add_energy_axis_button) - add_delay_axis_button = pw.SetButton('ADD DELAY AXIS') - add_delay_axis_button.clicked.connect(lambda: self.add_axis('delay')) + add_delay_axis_button = pw.SetButton("ADD DELAY AXIS") + add_delay_axis_button.clicked.connect(lambda: self.add_axis("delay")) self.layout.addWidget(add_delay_axis_button) - add_delay_axis_button = pw.SetButton('ADD ANGLE AXIS') - add_delay_axis_button.clicked.connect(lambda: self.add_axis('angle')) + add_delay_axis_button = pw.SetButton("ADD ANGLE AXIS") + add_delay_axis_button.clicked.connect(lambda: self.add_axis("angle")) self.layout.addWidget(add_delay_axis_button) - remove_axis_button = pw.SetButton('REMOVE AXIS', 'stop') + remove_axis_button = pw.SetButton("REMOVE AXIS", "stop") remove_axis_button.clicked.connect(self.remove_axis) self.layout.addWidget(remove_axis_button) # constants self.constants = [] input_table = pw.InputTable() - input_table.add('Constants', None) + input_table.add("Constants", None) self.layout.addWidget(input_table) self.constants_container_widget = QtWidgets.QWidget() self.constants_container_widget.setLayout(QtWidgets.QVBoxLayout()) @@ -264,13 +283,18 @@ def create_frame(self): remove_constant_button.clicked.connect(self.remove_constant) # processing input_table = pw.InputTable() - input_table.add('Processing', None) - self.channel_combo = pc.Combo(allowed_values=devices.control.channel_names, ini=ini, section='main', option='main channel') - input_table.add('Main Channel', self.channel_combo) - self.process_all_channels = pc.Bool(ini=ini, section='main', option='process all channels') - input_table.add('Process All Channels', self.process_all_channels) + input_table.add("Processing", None) + self.channel_combo = pc.Combo( + allowed_values=devices.control.channel_names, + ini=ini, + section="main", + option="main channel", + ) + input_table.add("Main Channel", self.channel_combo) + self.process_all_channels = pc.Bool(ini=ini, section="main", option="process all channels") + input_table.add("Process All Channels", self.process_all_channels) self.layout.addWidget(input_table) - + def load(self, aqn_path): # clear old for axis in self.axes: @@ -283,39 +307,39 @@ def load(self, aqn_path): # read new aqn = wt.kit.INI(aqn_path) # axes - axis_names = aqn.read('scan', 'axis names') + axis_names = aqn.read("scan", "axis names") for axis_index, axis_name in enumerate(axis_names): - units = aqn.read(axis_name, 'units') + units = aqn.read(axis_name, "units") units_kind = None for kind, d in wt.units.dicts.items(): if units in d.keys(): units_kind = kind axis = Axis(units_kind, axis_index) - axis.start.write(aqn.read(axis_name, 'start')) - axis.stop.write(aqn.read(axis_name, 'stop')) - axis.number.write(aqn.read(axis_name, 'number')) - hardwares = aqn.read(axis_name, 'hardware') + axis.start.write(aqn.read(axis_name, "start")) + axis.stop.write(aqn.read(axis_name, "stop")) + axis.number.write(aqn.read(axis_name, "number")) + hardwares = aqn.read(axis_name, "hardware") for hardware in hardwares: axis.hardwares[hardware].write(True) self.axes.append(axis) self.axes_container_widget.layout().addWidget(axis.widget) # constants - constant_names = aqn.read('scan', 'constant names') + constant_names = aqn.read("scan", "constant names") for constant_index, constant_name in enumerate(constant_names): constant = Constant() - constant.hardware_name_combo.write(aqn.read(constant_name, 'hardware')) - constant.expression.write(aqn.read(constant_name, 'expression')) + constant.hardware_name_combo.write(aqn.read(constant_name, "hardware")) + constant.expression.write(aqn.read(constant_name, "expression")) self.constants.append(constant) self.constants_container_widget.layout().addWidget(constant.widget) # processing try: - self.channel_combo.write(aqn.read('processing', 'main channel')) + self.channel_combo.write(aqn.read("processing", "main channel")) except ValueError: pass # TODO: log warning or something - self.process_all_channels.write(aqn.read('processing', 'process all channels')) + self.process_all_channels.write(aqn.read("processing", "process all channels")) # allow devices to load settings self.device_widget.load(aqn_path) - + def on_device_settings_updated(self): self.channel_combo.set_allowed_values(devices.control.channel_names) @@ -338,39 +362,42 @@ def remove_constant(self): def save(self, aqn_path): aqn = wt.kit.INI(aqn_path) # general - axis_names = str([str(a.get_name()) for a in self.axes]).replace('\'', '') - aqn.write('info', 'description', 'SCAN: {}'.format(axis_names)) - aqn.add_section('scan') - aqn.write('scan', 'axis names', [a.get_name() for a in self.axes]) - aqn.write('scan', 'constant names', [c.get_name() for c in self.constants]) + axis_names = str([str(a.get_name()) for a in self.axes]).replace("'", "") + aqn.write("info", "description", "SCAN: {}".format(axis_names)) + aqn.add_section("scan") + aqn.write("scan", "axis names", [a.get_name() for a in self.axes]) + aqn.write("scan", "constant names", [c.get_name() for c in self.constants]) # axes for axis in self.axes: name = axis.get_name() aqn.add_section(name) - aqn.write(name, 'start', axis.start.read()) - aqn.write(name, 'stop', axis.stop.read()) - aqn.write(name, 'number', axis.number.read()) - aqn.write(name, 'units', axis.units) + aqn.write(name, "start", axis.start.read()) + aqn.write(name, "stop", axis.stop.read()) + aqn.write(name, "number", axis.number.read()) + aqn.write(name, "units", axis.units) hardwares = [] for key, bool_mutex in axis.hardwares.items(): if bool_mutex.read(): hardwares.append(key) - aqn.write(name, 'hardware', hardwares) + aqn.write(name, "hardware", hardwares) # constants for constant in self.constants: name = constant.get_name() aqn.add_section(name) - aqn.write(name, 'hardware', constant.hardware_name_combo.read()) - aqn.write(name, 'expression', constant.expression.read()) + aqn.write(name, "hardware", constant.hardware_name_combo.read()) + aqn.write(name, "expression", constant.expression.read()) # processing - aqn.add_section('processing') - aqn.write('processing', 'main channel', self.channel_combo.read()) - aqn.write('processing', 'process all channels', self.process_all_channels.read()) + aqn.add_section("processing") + aqn.write("processing", "main channel", self.channel_combo.read()) + aqn.write("processing", "process all channels", self.process_all_channels.read()) # allow devices to write settings self.device_widget.save(aqn_path) - + + def load(): return True -def mkGUI(): + + +def mkGUI(): global gui gui = GUI(module_name) diff --git a/somatic/modules/tune_holistic.py b/somatic/modules/tune_holistic.py index 66d199fe..6b2c1632 100644 --- a/somatic/modules/tune_holistic.py +++ b/somatic/modules/tune_holistic.py @@ -8,9 +8,9 @@ ### define #################################################################### -module_name = 'TUNE HOLISTIC' - - +module_name = "TUNE HOLISTIC" + + ### Worker #################################################################### @@ -31,22 +31,26 @@ def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config) curve, level=level, gtol=gtol, - #ltol=ltol, + # ltol=ltol, save_directory=scan_folder, ) - + ### GUI ####################################################################### + class GUI(abstract_tuning.GUI): def __init__(self, module_name): self.items = {} - self.items["Spectral Axis"] = abstract_tuning.SpectralAxisSectionWidget("Spectral Axis", self) + self.items["Spectral Axis"] = abstract_tuning.SpectralAxisSectionWidget( + "Spectral Axis", self + ) self.items["Motor0"] = ProxyMotorAxisSectionWidget("Motor0", self) self.items["Motor1"] = abstract_tuning.MotorAxisSectionWidget("Motor1", self) super().__init__(module_name) self.items["Processing"]["ltol"].set_disabled(True) + class ProxyMotorAxisSectionWidget(abstract_tuning.AqnSectionWidget): def __init__(self, section_name, parent): super().__init__(section_name, parent) @@ -56,9 +60,11 @@ def on_update(self): hardware = next(h for h in opas.hardwares if h.name == self.parent["OPA"]["OPA"].read()) self.items["Motor"].set_allowed_values(hardware.curve.dependent_names) + def load(): return True -def mkGUI(): + +def mkGUI(): global gui gui = GUI(module_name) diff --git a/somatic/modules/tune_intensity.py b/somatic/modules/tune_intensity.py index 54339c2e..10dcae3a 100644 --- a/somatic/modules/tune_intensity.py +++ b/somatic/modules/tune_intensity.py @@ -4,10 +4,9 @@ import somatic.modules.abstract_tuning as abstract_tuning - -module_name = 'TUNE INTENSITY' - - +module_name = "TUNE INTENSITY" + + class Worker(abstract_tuning.Worker): reference_image = "intensity.png" @@ -20,7 +19,12 @@ def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config) if level: data.level(channel, -1, 5) for axis in data.axis_expressions[2:]: - data.moment(axis, channel, moment=0, resultant=wt.kit.joint_shape(data[opa], data[f"{opa}_{dep}_points"])) + data.moment( + axis, + channel, + moment=0, + resultant=wt.kit.joint_shape(data[opa], data[f"{opa}_{dep}_points"]), + ) channel = -1 data.transform(opa, f"{opa}_{dep}_points") return attune.workup.intensity( @@ -34,16 +38,21 @@ def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config) save_directory=scan_folder, ) + class GUI(abstract_tuning.GUI): def __init__(self, module_name): self.items = {} self.items["Motor"] = abstract_tuning.MotorAxisSectionWidget("Motor", self) super().__init__(module_name) - self.items["Spectrometer"]["Action"].set_allowed_values(self.items["Spectrometer"]["Action"].allowed_values[1:]) + self.items["Spectrometer"]["Action"].set_allowed_values( + self.items["Spectrometer"]["Action"].allowed_values[1:] + ) + def load(): return True -def mkGUI(): + +def mkGUI(): global gui gui = GUI(module_name) diff --git a/somatic/modules/tune_setpoint.py b/somatic/modules/tune_setpoint.py index b2e868f6..1231c74f 100644 --- a/somatic/modules/tune_setpoint.py +++ b/somatic/modules/tune_setpoint.py @@ -19,9 +19,14 @@ def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config) if level: data.level(channel, -1, 5) curve.convert(data[spec].units) - data.moment(spec, moment=1, channel=channel, resultant=wt.kit.joint_shape(data[opa], data[f"{opa}_{dep}"])) + data.moment( + spec, + moment=1, + channel=channel, + resultant=wt.kit.joint_shape(data[opa], data[f"{opa}_{dep}"]), + ) channel = -1 - data.channels[-1].clip(data[opa].min()-1000, data[opa].max()+1000) + data.channels[-1].clip(data[opa].min() - 1000, data[opa].max() + 1000) data.channels[-1].null = data.channels[-1].min() data.transform(opa, f"{opa}_{dep}_points") return attune.workup.setpoint( @@ -29,9 +34,9 @@ def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config) channel, dep, curve, - #level=level, - #gtol=gtol, - #ltol=ltol, + # level=level, + # gtol=gtol, + # ltol=ltol, save_directory=scan_folder, ) diff --git a/somatic/modules/tune_test.py b/somatic/modules/tune_test.py index 6e082a4c..f2e33326 100644 --- a/somatic/modules/tune_test.py +++ b/somatic/modules/tune_test.py @@ -2,33 +2,34 @@ import somatic.modules.abstract_tuning as abstract_tuning -module_name = 'TUNE TEST' - +module_name = "TUNE TEST" + + class Worker(abstract_tuning.Worker): reference_image = "tune_test.png" - + def _process(self, data, curve, channel, gtol, ltol, level, scan_folder, config): opa = config["OPA"]["opa"] spec = config["Spectral Axis"]["axis"] data.transform(opa, f"{spec}-{opa}") return attune.workup.tune_test( - data, - channel, - curve, - level=level, - gtol=gtol, - ltol=ltol, - save_directory=scan_folder, + data, channel, curve, level=level, gtol=gtol, ltol=ltol, save_directory=scan_folder, ) + class GUI(abstract_tuning.GUI): def __init__(self, module_name): self.items = {} - self.items["Spectral Axis"] = abstract_tuning.SpectralAxisSectionWidget("Spectral Axis", self) + self.items["Spectral Axis"] = abstract_tuning.SpectralAxisSectionWidget( + "Spectral Axis", self + ) super().__init__(module_name) + def load(): return True -def mkGUI(): + + +def mkGUI(): global gui gui = GUI(module_name) diff --git a/somatic/modules/zero_tune.py b/somatic/modules/zero_tune.py index 4c61fc78..6a422158 100644 --- a/somatic/modules/zero_tune.py +++ b/somatic/modules/zero_tune.py @@ -6,6 +6,7 @@ import numpy as np import matplotlib + matplotlib.pyplot.ioff() from PySide2 import QtWidgets @@ -19,41 +20,42 @@ from somatic.modules.scan import Axis as ScanAxisGUI from somatic.modules.scan import Constant import project.ini_handler as ini_handler + main_dir = g.main_dir.read() -ini = ini_handler.Ini(os.path.join(main_dir, 'somatic', 'modules', 'zero_tune.ini')) +ini = ini_handler.Ini(os.path.join(main_dir, "somatic", "modules", "zero_tune.ini")) app = g.app.read() import hardware.spectrometers.spectrometers as spectrometers import hardware.delays.delays as delays import hardware.opas.opas as opas import hardware.filters.filters as filters + all_hardwares = opas.hardwares + spectrometers.hardwares + delays.hardwares + filters.hardwares import devices.devices as devices - + ### define #################################################################### -module_name = 'ZERO TUNE' - - +module_name = "ZERO TUNE" + + ### Worker #################################################################### class Worker(acquisition.Worker): - def process(self, scan_folder): - data_path = wt.kit.glob_handler('.data', folder=str(scan_folder))[0] + data_path = wt.kit.glob_handler(".data", folder=str(scan_folder))[0] data = wt.data.from_PyCMDS(data_path) - opa_name = self.aqn.read('opa', 'opa') + opa_name = self.aqn.read("opa", "opa") opa_names = [opa.name for opa in opas.hardwares] opa_index = opa_names.index(opa_name) opa = opas.hardwares[opa_index] - delays = self.aqn.read('delay', 'delays') - channel_name = self.aqn.read('processing', 'channel') + delays = self.aqn.read("delay", "delays") + channel_name = self.aqn.read("processing", "channel") # This can be simplified, I guess, as it is known which will occur in what order - color_units = [i.units for i in data.axes if wt.units.kind(i.units) == 'energy'][0] - delay_units = [i.units for i in data.axes if wt.units.kind(i.units) == 'delay'][0] + color_units = [i.units for i in data.axes if wt.units.kind(i.units) == "energy"][0] + delay_units = [i.units for i in data.axes if wt.units.kind(i.units) == "delay"][0] transform = list(data.axis_expressions)[:2] for axis in data.axis_expressions: if axis not in transform: @@ -61,7 +63,7 @@ def process(self, scan_folder): data.level(axis, 0, 5) data.moment(axis, channel) channel_name = -1 - for delay in delays: + for delay in delays: attune.workup.intensity( data, channel_name, @@ -74,43 +76,45 @@ def process(self, scan_folder): # upload self.upload(scan_folder) - + def run(self): axes = [] # OPA - opa_name = self.aqn.read('opa', 'opa') - npts = self.aqn.read('opa', 'npts') + opa_name = self.aqn.read("opa", "opa") + npts = self.aqn.read("opa", "npts") opa_names = [opa.name for opa in opas.hardwares] opa_index = opa_names.index(opa_name) opa_hardware = opas.hardwares[opa_index] opa_friendly_name = opa_hardware.name curve = opa_hardware.curve.copy() - curve.convert('wn') + curve.convert("wn") pts = np.linspace(curve.setpoints[:].min(), curve.setpoints[:].max(), npts) - axis = acquisition.Axis(pts, 'wn', opa_friendly_name, opa_friendly_name) + axis = acquisition.Axis(pts, "wn", opa_friendly_name, opa_friendly_name) axes.append(axis) # delay - axis_name = 'delay' - start = self.aqn.read(axis_name, 'start') - stop = self.aqn.read(axis_name, 'stop') - number = self.aqn.read(axis_name, 'number') + axis_name = "delay" + start = self.aqn.read(axis_name, "start") + stop = self.aqn.read(axis_name, "stop") + number = self.aqn.read(axis_name, "number") points = np.linspace(start, stop, number) - units = self.aqn.read(axis_name, 'units') - name = '='.join(self.aqn.read(axis_name, 'delays')) + units = self.aqn.read(axis_name, "units") + name = "=".join(self.aqn.read(axis_name, "delays")) axis = acquisition.Axis(points, units, name, name) axes.append(axis) - + constants = [] - for constant_name in self.aqn.read('scan', 'constant names'): + for constant_name in self.aqn.read("scan", "constant names"): for hardware in all_hardwares: if hardware.name == constant_name: units = hardware.units - if wt.units.kind(units) == 'energy': - units = 'wn' + if wt.units.kind(units) == "energy": + units = "wn" break name = constant_name - identity = expression = self.aqn.read(constant_name, 'expression') - constant = acquisition.Constant(units, name, identity, expression=expression, static=False) + identity = expression = self.aqn.read(constant_name, "expression") + constant = acquisition.Constant( + units, name, identity, expression=expression, static=False + ) constants.append(constant) # do scan self.scan(axes, constants) @@ -118,33 +122,32 @@ def run(self): if not self.stopped.read(): self.finished.write(True) # only if acquisition successfull - + ### GUI ####################################################################### class GUI(acquisition.GUI): - def create_frame(self): input_table = pw.InputTable() # opa combo allowed = [hardware.name for hardware in opas.hardwares] self.opa_combo = pc.Combo(allowed) - input_table.add('OPA', None) - input_table.add('OPA', self.opa_combo) + input_table.add("OPA", None) + input_table.add("OPA", self.opa_combo) self.npts_opa = pc.Number(decimals=0, initial_value=21) input_table.add("npts", self.npts_opa) # delay - self.delay = ScanAxisGUI('delay', "") + self.delay = ScanAxisGUI("delay", "") self.delay.start.write(-3) self.delay.stop.write(3) self.delay.number.write(21) - input_table.add('Delay', None) + input_table.add("Delay", None) self.layout.addWidget(input_table) self.layout.addWidget(self.delay.widget) # constants self.constants = [] input_table = pw.InputTable() - input_table.add('Constants', None) + input_table.add("Constants", None) self.layout.addWidget(input_table) self.constants_container_widget = QtWidgets.QWidget() self.constants_container_widget.setLayout(QtWidgets.QVBoxLayout()) @@ -155,20 +158,25 @@ def create_frame(self): remove_constant_button.clicked.connect(self.remove_constant) # processing input_table = pw.InputTable() - input_table.add('Processing', None) - self.channel_combo = pc.Combo(allowed_values=devices.control.channel_names, ini=ini, section='main', option='channel name') - input_table.add('Channel', self.channel_combo) + input_table.add("Processing", None) + self.channel_combo = pc.Combo( + allowed_values=devices.control.channel_names, + ini=ini, + section="main", + option="channel name", + ) + input_table.add("Channel", self.channel_combo) self.process_level = pc.Bool(initial_value=False) self.process_gtol = pc.Number(initial_value=0, decimals=5) self.process_ltol = pc.Number(initial_value=1e-2, decimals=5) - input_table.add('level', self.process_level) - input_table.add('gtol', self.process_gtol) - input_table.add('ltol', self.process_ltol) + input_table.add("level", self.process_level) + input_table.add("gtol", self.process_gtol) + input_table.add("ltol", self.process_ltol) # finish self.layout.addWidget(input_table) - + def add_constant(self): - #if len(self.constants) == 1: return # temporary... + # if len(self.constants) == 1: return # temporary... constant = Constant() self.constants_container_widget.layout().addWidget(constant.widget) self.constants.append(constant) @@ -181,16 +189,20 @@ def add_buttons(self): button_container.layout().setMargin(0) # remove remove_button = QtWidgets.QPushButton() - remove_button.setText('REMOVE') + remove_button.setText("REMOVE") remove_button.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['stop']) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["stop"] + ) remove_button.setStyleSheet(StyleSheet) button_container.layout().addWidget(remove_button) # add add_button = QtWidgets.QPushButton() - add_button.setText('ADD') + add_button.setText("ADD") add_button.setMinimumHeight(25) - StyleSheet = 'QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}'.replace('custom_color', colors['set']) + StyleSheet = "QPushButton{background:custom_color; border-width:0px; border-radius: 0px; font: bold 14px}".replace( + "custom_color", colors["set"] + ) add_button.setStyleSheet(StyleSheet) button_container.layout().addWidget(add_button) # finish @@ -202,24 +214,24 @@ def load(self, aqn_path): constant.hide() self.constants = [] aqn = wt.kit.INI(aqn_path) - self.opa_combo.write(aqn.read('opa', 'opa')) - self.npts_opa.write(aqn.read('opa', 'npts')) - self.channel_combo.write(aqn.read('processing', 'channel')) + self.opa_combo.write(aqn.read("opa", "opa")) + self.npts_opa.write(aqn.read("opa", "npts")) + self.channel_combo.write(aqn.read("processing", "channel")) self.process_level.write(aqn.read("process", "level")) self.process_gtol.write(aqn.read("process", "gtol")) self.process_ltol.write(aqn.read("process", "ltol")) - self.delay.start.write(aqn.read('delay', 'start')) - self.delay.stop.write(aqn.read('delay', 'stop')) - self.delay.number.write(aqn.read('delay', 'number')) + self.delay.start.write(aqn.read("delay", "start")) + self.delay.stop.write(aqn.read("delay", "stop")) + self.delay.number.write(aqn.read("delay", "number")) for key, mutex in self.delay.hardwares.items(): - mutex.write(key in aqn.read('delay', 'delays')) + mutex.write(key in aqn.read("delay", "delays")) # constants - constant_names = aqn.read('scan', 'constant names') + constant_names = aqn.read("scan", "constant names") for constant_index, constant_name in enumerate(constant_names): constant = Constant() - constant.hardware_name_combo.write(aqn.read(constant_name, 'hardware')) - constant.expression.write(aqn.read(constant_name, 'expression')) + constant.hardware_name_combo.write(aqn.read(constant_name, "hardware")) + constant.expression.write(aqn.read(constant_name, "expression")) self.constants.append(constant) self.constants_container_widget.layout().addWidget(constant.widget) # allow devices to load settings @@ -232,44 +244,49 @@ def remove_constant(self): self.constants_container_widget.layout().removeWidget(constant.widget) constant.hide() self.constants.pop(-1) - + def on_device_settings_updated(self): self.channel_combo.set_allowed_values(devices.control.channel_names) - + def save(self, aqn_path): aqn = wt.kit.INI(aqn_path) - aqn.add_section('opa') - aqn.write('opa', 'opa', self.opa_combo.read()) - aqn.write('opa', 'npts', self.npts_opa.read()) - aqn.add_section('delay') - aqn.write('delay', 'start', self.delay.start.read()) - aqn.write('delay', 'stop', self.delay.stop.read()) - aqn.write('delay', 'number', self.delay.number.read()) - aqn.write('delay', 'units', self.delay.units) + aqn.add_section("opa") + aqn.write("opa", "opa", self.opa_combo.read()) + aqn.write("opa", "npts", self.npts_opa.read()) + aqn.add_section("delay") + aqn.write("delay", "start", self.delay.start.read()) + aqn.write("delay", "stop", self.delay.stop.read()) + aqn.write("delay", "number", self.delay.number.read()) + aqn.write("delay", "units", self.delay.units) hardwares = [] for key, bool_mutex in self.delay.hardwares.items(): if bool_mutex.read(): hardwares.append(key) - aqn.write('delay', 'delays', hardwares) - aqn.write('info', 'description', '{} {} zero tune'.format(self.opa_combo.read(), hardwares)) + aqn.write("delay", "delays", hardwares) + aqn.write( + "info", "description", "{} {} zero tune".format(self.opa_combo.read(), hardwares) + ) # constants - aqn.add_section('scan') + aqn.add_section("scan") aqn.write("scan", "constant names", [c.get_name() for c in self.constants]) for constant in self.constants: name = constant.get_name() aqn.add_section(name) - aqn.write(name, 'hardware', constant.hardware_name_combo.read()) - aqn.write(name, 'expression', constant.expression.read()) - aqn.add_section('processing') - aqn.write('processing', 'channel', self.channel_combo.read()) - aqn.write("processing", 'level', self.process_level.read()) - aqn.write("processing", 'gtol', self.process_gtol.read()) - aqn.write("processing", 'ltol', self.process_ltol.read()) + aqn.write(name, "hardware", constant.hardware_name_combo.read()) + aqn.write(name, "expression", constant.expression.read()) + aqn.add_section("processing") + aqn.write("processing", "channel", self.channel_combo.read()) + aqn.write("processing", "level", self.process_level.read()) + aqn.write("processing", "gtol", self.process_gtol.read()) + aqn.write("processing", "ltol", self.process_ltol.read()) # allow devices to write settings self.device_widget.save(aqn_path) - + + def load(): return True -def mkGUI(): + + +def mkGUI(): global gui gui = GUI(module_name) diff --git a/somatic/order/ndindex.py b/somatic/order/ndindex.py index e577d746..ca8aeda6 100644 --- a/somatic/order/ndindex.py +++ b/somatic/order/ndindex.py @@ -1,5 +1,6 @@ import numpy as np + def process(destinations_list): # out out = [idx for idx in np.ndindex(destinations_list[0].arr.shape)] @@ -9,25 +10,25 @@ def process(destinations_list): slices = [] for i, idx in enumerate(np.ndindex(destinations_list[-1].arr.shape[:-1])): s = {} - s['index'] = destinations_list[-1].arr.shape[-1]*i - s['name'] = destinations_list[-1].hardware.name - s['units'] = destinations_list[-1].units - s['points'] = destinations_list[-1].arr[idx] - if destinations_list[-1].method == 'set_position': - s['use actual'] = True + s["index"] = destinations_list[-1].arr.shape[-1] * i + s["name"] = destinations_list[-1].hardware.name + s["units"] = destinations_list[-1].units + s["points"] = destinations_list[-1].arr[idx] + if destinations_list[-1].method == "set_position": + s["use actual"] = True else: - s['use actual'] = False + s["use actual"] = False slices.append(s) else: # 1D scan s = {} - s['index'] = 0 - s['name'] = destinations_list[0].hardware.name - s['units'] = destinations_list[0].units - s['points'] = destinations_list[0].arr - if destinations_list[0].method == 'set_position': - s['use actual'] = True + s["index"] = 0 + s["name"] = destinations_list[0].hardware.name + s["units"] = destinations_list[0].units + s["points"] = destinations_list[0].arr + if destinations_list[0].method == "set_position": + s["use actual"] = True else: - s['use actual'] = False + s["use actual"] = False slices = [s] return out, slices diff --git a/somatic/order/snake.py b/somatic/order/snake.py index 1b25cb81..a1230252 100644 --- a/somatic/order/snake.py +++ b/somatic/order/snake.py @@ -8,29 +8,34 @@ import numpy as np from matplotlib.cbook import flatten as flatten + # import project.project_globals as g ### Dummy hardware class for things that don't need the full proper class: -class HDW: - def __init__(self,kind): +class HDW: + def __init__(self, kind): assert type(kind) == str self.type = kind + ### Peramiterizing Traveling Salesman Problem + def ps_to_mm(t): - return t*.2998/2 + return t * 0.2998 / 2 + def m_pos(curve, destination_in_wavenumbers): - ''' Returns list of interators that defines order of points.''' + """ Returns list of interators that defines order of points.""" return curve.get_motor_positions(destination_in_wavenumbers) + class Path: # Point_grid is the (n+1)D array containing the list of the points. # Each array dimention is a potential scan dimention. - def __init__(self,point_grid,hws,units,start_pos=None): + def __init__(self, point_grid, hws, units, start_pos=None): self.grid = np.array(point_grid) self.shape = self.grid.shape self.hws = hws @@ -40,19 +45,19 @@ def __init__(self,point_grid,hws,units,start_pos=None): self.OPA_dictionary() - #self.set_indicies() - #self.calc_length() # finds total length + # self.set_indicies() + # self.calc_length() # finds total length return - def __cmp__(self,other): - return cmp(self.length,other.length) + def __cmp__(self, other): + return cmp(self.length, other.length) def OPA_dictionary(self): OPAc = [] for o in self.hws: - if o.type == 'Curve': + if o.type == "Curve": OPAc.append(o) - elif o.type == 'OPA': + elif o.type == "OPA": OPAc.append(o.curve) else: OPAc.append(None) @@ -61,50 +66,64 @@ def OPA_dictionary(self): for i in range(len(self.hws)): if OPAc[i]: color_dics.append(dict()) - colors = set(flatten(self.grid[:,:,hardwares.index(self.hws[i])])) + colors = set(flatten(self.grid[:, :, hardwares.index(self.hws[i])])) for color in colors: - color_dics[-1][color] = m_pos(OPAc[i],color) + color_dics[-1][color] = m_pos(OPAc[i], color) else: color_dics.append(None) self.cd = color_dics - def OPAd (self,h_index,color): + def OPAd(self, h_index, color): if any(self.cd[h_index]): return np.array(self.cd[h_index][color]) else: assert False - def p_plot(self, dim = [0,2], path=None, l=None): + def p_plot(self, dim=[0, 2], path=None, l=None): if not any(path): if any(self.path): path = self.path l = self.length else: - path = np.reshape(self.grid,[-1,self.grid.shape[-1]]) + path = np.reshape(self.grid, [-1, self.grid.shape[-1]]) - #assert type(path) == np.ndarray - #assert len(path.shape) == 2 + # assert type(path) == np.ndarray + # assert len(path.shape) == 2 assert path.shape[0] == np.product(self.grid.shape[:-1]) plt.figure() - plt.scatter(path[:,dim[0]],path[:,dim[1]]) - plt.xlabel(self.hws[dim[0]].type + ' (' + self.units[dim[0]] + ')') - plt.ylabel(self.hws[dim[1]].type + ' (' + self.units[dim[1]] + ')') + plt.scatter(path[:, dim[0]], path[:, dim[1]]) + plt.xlabel(self.hws[dim[0]].type + " (" + self.units[dim[0]] + ")") + plt.ylabel(self.hws[dim[1]].type + " (" + self.units[dim[1]] + ")") if l: try: - plt.title('Total Overhead time: ' + str(round(l,1)) + ' sec') - plt.text(0,-1,"Min Estimated data time: .5*"+ str(len(path)) + "=" + str(.5*len(path))+' seconds') - plt.text(0,-2,"Max Overhead percentage: " + str(round(100*(l)/(.5*len(path)+l),1)) + "%") + plt.title("Total Overhead time: " + str(round(l, 1)) + " sec") + plt.text( + 0, + -1, + "Min Estimated data time: .5*" + + str(len(path)) + + "=" + + str(0.5 * len(path)) + + " seconds", + ) + plt.text( + 0, + -2, + "Max Overhead percentage: " + + str(round(100 * (l) / (0.5 * len(path) + l), 1)) + + "%", + ) except TypeError: plt.title("Given length: " + str(l)) else: - plt.title('Length not given') + plt.title("Length not given") - plt.plot(list(path[:,dim[0]]),list(path[:,dim[1]])) + plt.plot(list(path[:, dim[0]]), list(path[:, dim[1]])) - def calc_length(self,path=None): - if path == None: # No path specified - path = np.reshape(self.grid,[-1,self.grid.shape[-1]]) + def calc_length(self, path=None): + if path == None: # No path specified + path = np.reshape(self.grid, [-1, self.grid.shape[-1]]) # Check that the path is a valid one @@ -116,14 +135,20 @@ def calc_length(self,path=None): total_time_f = 0 total_time_b = 0 - for i in range(len(path)-1): + for i in range(len(path) - 1): times_f = [] times_b = [] for h in range(len(self.hws)): - times_f.append(self.time_cost(h,self.grid[tuple(path[i])][h], - self.grid[tuple(path[i+1])][h])) - times_b.append(self.time_cost(h,self.grid[tuple(path[-i-1])][h], - self.grid[tuple(path[-i-2])][h])) + times_f.append( + self.time_cost( + h, self.grid[tuple(path[i])][h], self.grid[tuple(path[i + 1])][h] + ) + ) + times_b.append( + self.time_cost( + h, self.grid[tuple(path[-i - 1])][h], self.grid[tuple(path[-i - 2])][h] + ) + ) total_time_f += max(times_f) total_time_b += max(times_b) if total_time_f < total_time_b: @@ -137,74 +162,77 @@ def calc_length(self,path=None): self.length = tt self.path = path[::f] - return total_time_f,total_time_b - + return total_time_f, total_time_b - def time_cost(self,hw_idx, start, stop): - ''' + def time_cost(self, hw_idx, start, stop): + """ Function that determines the cost of moving a particular hardware a defined distance and direcction. This is the cost function used in the traveling salesman optimization. Returns time in seconds. If a hardware isn't listed, the difference in the start and stop values is returned. - ''' + """ hw = self.hws[hw_idx] units = self.units[hw_idx] - mono_cost = 1.45 # Number of seconds of extra time per high->low step + mono_cost = 1.45 # Number of seconds of extra time per high->low step # motor_cost = 0 - moter_speed = lambda dist: 10616.2-10151*np.exp(-.00015155*dist) - if round(start,2) == round(stop,2): + moter_speed = lambda dist: 10616.2 - 10151 * np.exp(-0.00015155 * dist) + if round(start, 2) == round(stop, 2): return 0 - elif hw.type == 'Curve' or hw.type == 'OPA': - m_start = self.OPAd(hw_idx,start) - m_stop = self.OPAd(hw_idx,stop) - dist = max([abs(m) for m in m_start-m_stop]) - return max(dist/moter_speed(dist),0.1) + elif hw.type == "Curve" or hw.type == "OPA": + m_start = self.OPAd(hw_idx, start) + m_stop = self.OPAd(hw_idx, stop) + dist = max([abs(m) for m in m_start - m_stop]) + return max(dist / moter_speed(dist), 0.1) - elif hw.type == 'Delay': - if units == 'ps': - dist = ps_to_mm(abs(stop-start)) - return max(dist/moter_speed(dist),0.1) - elif units == 'mm': - dist = abs(stop-start) - return max(dist/moter_speed(dist),0.1) + elif hw.type == "Delay": + if units == "ps": + dist = ps_to_mm(abs(stop - start)) + return max(dist / moter_speed(dist), 0.1) + elif units == "mm": + dist = abs(stop - start) + return max(dist / moter_speed(dist), 0.1) elif hw.type == "Motor": - dist = abs(stop-start) - return max(dist/moter_speed(dist),0.1) + dist = abs(stop - start) + return max(dist / moter_speed(dist), 0.1) - elif hw.type == 'Mono': - dist = stop-start + elif hw.type == "Mono": + dist = stop - start if dist < 0: dist = -dist - rate = lambda s: -0.00005*s*s + .0445*s+114.13 - if max(start,stop) > 1500: - return max(dist/(rate(stop/10)*10),.04) + rate = lambda s: -0.00005 * s * s + 0.0445 * s + 114.13 + if max(start, stop) > 1500: + return max(dist / (rate(stop / 10) * 10), 0.04) else: - return max(dist/(rate(stop)),.04) + return max(dist / (rate(stop)), 0.04) else: return mono_cost else: - return abs(start-stop) + return abs(start - stop) -class Snake: - def __init__(self,input_grid,hardwares,units,start_point = None): +class Snake: + def __init__(self, input_grid, hardwares, units, start_point=None): self.grid = input_grid self.hws = hardwares self.units = units self.start_point = start_point - try: assert len(self.grid.shape) == 3 - except: pass #Figure out how to handle more than 2D + try: + assert len(self.grid.shape) == 3 + except: + pass # Figure out how to handle more than 2D if any(start_point): - try: assert len(start_point) == len(units) - except: pass #Figure out how to encorporate starting/current position - self.mypath = Path(self.grid,self.hws,self.units,self.start_point) + try: + assert len(start_point) == len(units) + except: + pass # Figure out how to encorporate starting/current position + self.mypath = Path(self.grid, self.hws, self.units, self.start_point) def best(self): - ''' Finds and returns the best guess for the fasted scan''' + """ Finds and returns the best guess for the fasted scan""" self.costs = [] for p in self._linear1_(): @@ -217,47 +245,44 @@ def best(self): p = np.array(p) self.costs.append(self.mypath.calc_length(p)) - return self.mypath.path,self.mypath.length - + return self.mypath.path, self.mypath.length def plot_best(self): - self.mypath.p_plot([0,1]) + self.mypath.p_plot([0, 1]) return - def _linear1_(self): m = self.grid.shape[0] n = self.grid.shape[1] paths = [[] for i in range(4)] - '''### List Index and Snake styles, 1st Axis''' - for idx in np.ndindex(*[m,n]): - i,j = idx + """### List Index and Snake styles, 1st Axis""" + for idx in np.ndindex(*[m, n]): + i, j = idx paths[0].append(idx) - paths[1].append((i,n-j-1)) - if i%2 == 0: + paths[1].append((i, n - j - 1)) + if i % 2 == 0: paths[2].append(idx) - paths[3].append((i,n-j-1)) + paths[3].append((i, n - j - 1)) else: - paths[2].append((i,n-j-1)) + paths[2].append((i, n - j - 1)) paths[3].append(idx) return paths - def _linear2_(self): - '''List Index and Snake styles, 2nd Axis''' + """List Index and Snake styles, 2nd Axis""" m = self.grid.shape[0] n = self.grid.shape[1] paths = [[] for i in range(4)] - for idx in np.ndindex(*[n,m]): - i,j = idx - paths[0].append((j,i)) - paths[1].append((m-j-1,i)) - if i%2 == 0: - paths[2].append((j,i)) - paths[3].append((m-j-1,i)) + for idx in np.ndindex(*[n, m]): + i, j = idx + paths[0].append((j, i)) + paths[1].append((m - j - 1, i)) + if i % 2 == 0: + paths[2].append((j, i)) + paths[3].append((m - j - 1, i)) else: - paths[2].append((m-j-1,i)) - paths[3].append((j,i)) + paths[2].append((m - j - 1, i)) + paths[3].append((j, i)) return paths def _Diagonal_(self): @@ -265,33 +290,33 @@ def _Diagonal_(self): n = self.grid.shape[1] paths = [[] for i in range(8)] # Index array for diagonal checks - idx = np.array([[(i,j) for j in range(m)] for i in range(n)]) + idx = np.array([[(i, j) for j in range(m)] for i in range(n)]) idx_f = idx[::-1] # TL-BR is 8-11, TR-BL is 12-15 - tpd = lambda x,i: np.transpose(x.diagonal(i,0,1)) - for i in range(1-n,m): - paths[0].append(tpd(idx,i)) - paths[1].append(tpd(idx,i)[::-1]) - paths[4].append(tpd(idx_f,i)) - paths[5].append(tpd(idx_f,i)[::-1]) - if i%2 == 0: - paths[2].append(tpd(idx,i)[::-1]) - paths[3].append(tpd(idx,i)) - paths[6].append(tpd(idx_f,i)[::-1]) - paths[7].append(tpd(idx_f,i)) + tpd = lambda x, i: np.transpose(x.diagonal(i, 0, 1)) + for i in range(1 - n, m): + paths[0].append(tpd(idx, i)) + paths[1].append(tpd(idx, i)[::-1]) + paths[4].append(tpd(idx_f, i)) + paths[5].append(tpd(idx_f, i)[::-1]) + if i % 2 == 0: + paths[2].append(tpd(idx, i)[::-1]) + paths[3].append(tpd(idx, i)) + paths[6].append(tpd(idx_f, i)[::-1]) + paths[7].append(tpd(idx_f, i)) else: - paths[2].append(tpd(idx,i)) - paths[3].append(tpd(idx,i)[::-1]) - paths[6].append(tpd(idx_f,i)) - paths[7].append(tpd(idx_f,i)[::-1]) + paths[2].append(tpd(idx, i)) + paths[3].append(tpd(idx, i)[::-1]) + paths[6].append(tpd(idx_f, i)) + paths[7].append(tpd(idx_f, i)[::-1]) # Cleaning up the diagonal slices for p in range(8): - k = np.array([],dtype=int) + k = np.array([], dtype=int) for arr in paths[p]: - k = np.append(k,arr) - paths[p] = np.array([arr[::-1] for arr in k.reshape([-1,2])]) + k = np.append(k, arr) + paths[p] = np.array([arr[::-1] for arr in k.reshape([-1, 2])]) return paths @@ -303,13 +328,13 @@ def _Diagonal_(self): if testing: - #g.offline.get_saved() + # g.offline.get_saved() - if initialize: #g.offline.read(): + if initialize: # g.offline.read(): # import - a = 'C:\Users\Nathan\Documents\GitHub\PyCMDS\opas\pico\OPA1 curves\OPA1 - 2015.08.27 17_14_47.curve' - b = 'C:\Users\Nathan\Documents\GitHub\PyCMDS\opas\pico\OPA2 curves\OPA2 - 2015.08.27 17_16_16.curve' - c = 'C:\Users\Nathan\Documents\GitHub\PyCMDS\opas\pico\OPA3 curves\OPA3 - 2015.08.27 17_17_49.curve' + a = "C:\Users\Nathan\Documents\GitHub\PyCMDS\opas\pico\OPA1 curves\OPA1 - 2015.08.27 17_14_47.curve" + b = "C:\Users\Nathan\Documents\GitHub\PyCMDS\opas\pico\OPA2 curves\OPA2 - 2015.08.27 17_16_16.curve" + c = "C:\Users\Nathan\Documents\GitHub\PyCMDS\opas\pico\OPA3 curves\OPA3 - 2015.08.27 17_17_49.curve" # It might be faster (computer-wise) to translate all the opa points # into moter points only once. @@ -322,17 +347,16 @@ def _Diagonal_(self): OPA2 = Curve(b) OPA3 = Curve(c) - - MicroHR = HDW('Mono') - D1 = HDW('Delay') - D2 = HDW('Delay') + MicroHR = HDW("Mono") + D1 = HDW("Delay") + D2 = HDW("Delay") D3 = None if make_grid: ### Scan setup ################################################## - hardwares = [OPA1,OPA2,MicroHR] - u = ['wn','wn','wn'] - axis_pts = [(1600-1250)/5,(1600-1500)/5] + hardwares = [OPA1, OPA2, MicroHR] + u = ["wn", "wn", "wn"] + axis_pts = [(1600 - 1250) / 5, (1600 - 1500) / 5] OPA1_start = pc.Number(initial_value=1250, units=u[0]) OPA1_stop = pc.Number(initial_value=1600, units=u[0]) OPA1_pos = np.linspace(OPA1_start.read(), OPA1_stop.read(), axis_pts[0]) @@ -344,14 +368,14 @@ def _Diagonal_(self): axis1 = OPA1_pos axis2 = OPA2_pos - grid = np.transpose(np.array(np.meshgrid(axis1,axis2))) - new_grid = np.zeros(np.append(axis_pts,len(hardwares))) + grid = np.transpose(np.array(np.meshgrid(axis1, axis2))) + new_grid = np.zeros(np.append(axis_pts, len(hardwares))) for i in range(axis_pts[0]): for j in range(axis_pts[1]): - new_grid[i,j] = np.insert(grid[i][j],2,12500+grid[i][j][0]-grid[i][j][1]) + new_grid[i, j] = np.insert(grid[i][j], 2, 12500 + grid[i][j][0] - grid[i][j][1]) ### Using the Snake class ################################################# - answer = Snake(new_grid,hardwares,u) + answer = Snake(new_grid, hardwares, u) answer.best() answer.plot_best() diff --git a/somatic/queue.py b/somatic/queue.py index 896fbd18..32737757 100644 --- a/somatic/queue.py +++ b/somatic/queue.py @@ -24,6 +24,7 @@ import hardware.delays.delays as delays import hardware.opas.opas as opas import hardware.filters.filters as filters + all_hardwares = opas.hardwares + spectrometers.hardwares + delays.hardwares + filters.hardwares ### define #################################################################### @@ -34,7 +35,7 @@ main_window = g.main_window.read() somatic_folder = os.path.dirname(__file__) -saved_folder = os.path.join(somatic_folder, 'saved') +saved_folder = os.path.join(somatic_folder, "saved") data_folder = main_window.data_folder @@ -50,64 +51,62 @@ class Item(QtCore.QObject): updated = QtCore.Signal() - - def __init__(self, name='', info='', description=''): + + def __init__(self, name="", info="", description=""): QtCore.QObject.__init__(self) # basic information self.name = name # filled by user, up to 10 charachters long self.info = info # filled by user, can be arbitrarily long - self.description = description # filled programmatically, to be displayed in table + self.description = description # filled programmatically, to be displayed in table # status: can be one of 'ENQUEUED', 'RUNNING', 'COMPLETE', 'FAILED' - self.status = 'ENQUEUED' + self.status = "ENQUEUED" self.finished = pc.Bool(initial_value=False) # timestamps self.created = wt.kit.TimeStamp() self.started = None self.exited = None - + def write_to_ini(self, ini, section): pass class Acquisition(Item): - def __init__(self, aqn_path, module, **kwargs): Item.__init__(self, **kwargs) self.aqn_path = aqn_path - self.type = 'acquisition' + self.type = "acquisition" self.module = module self.url = None - + def write_to_ini(self, ini, section): - ini.write(section, 'path', self.aqn_path) - ini.write(section, 'url', self.url) + ini.write(section, "path", self.aqn_path) + ini.write(section, "url", self.url) class Device(Item): - def __init__(self, **kwargs): Item.__init__(self, **kwargs) - self.type = 'acquisition' + self.type = "acquisition" class Hardware(Item): - def __init__(self, hardwares, value, units, **kwargs): Item.__init__(self, **kwargs) - self.type = 'hardware' + self.type = "hardware" self.hardwares = [ah for ah in all_hardwares if ah.name in hardwares] self.value = value self.units = units - + def execute(self): for hw in self.hardwares: hw.set_position(self.value, self.units) g.hardware_waits.wait() def write_to_ini(self, ini, section): - ini.write(section, 'value', self.value) - ini.write(section, 'units', self.units) - ini.write(section, 'hardwares', [hw.name for hw in self.hardwares]) + ini.write(section, "value", self.value) + ini.write(section, "units", self.units) + ini.write(section, "hardwares", [hw.name for hw in self.hardwares]) + class Interrupt(Item): def __init__(self, **kwargs): @@ -116,23 +115,22 @@ def __init__(self, **kwargs): class Script(Item): - def __init__(self, **kwargs): Item.__init__(self, **kwargs) - self.type = 'script' + self.type = "script" class Wait(Item): - def __init__(self, operation, amount, **kwargs): Item.__init__(self, **kwargs) - self.type = 'wait' + self.type = "wait" self.operation = operation self.amount = amount - + def write_to_ini(self, ini, section): - ini.write(section, 'operation', self.operation) - ini.write(section, 'amount', self.amount) + ini.write(section, "operation", self.operation) + ini.write(section, "amount", self.amount) + ### worker #################################################################### @@ -145,18 +143,18 @@ def __init__(self, enqueued, busy, queue_status, queue_url, queue_index, queue_f self.enqueued = enqueued self.busy = busy self.queue_status = queue_status - self.fraction_complete = pc.Number(initial_value=0.) + self.fraction_complete = pc.Number(initial_value=0.0) self.queue_url = queue_url self.index = queue_index self.folder = queue_folder - + def check_busy(self, _=[]): if self.enqueued.read(): # there are items in enqueued time.sleep(0.1) # don't loop like crazy self.busy.write(True) else: - self.busy.write(False) - + self.busy.write(False) + @QtCore.Slot(str, list) def dequeue(self, method, inputs): """ @@ -166,25 +164,25 @@ def dequeue(self, method, inputs): """ args, kwargs = inputs if g.debug.read(): - print('worker dequeue:', method, inputs) + print("worker dequeue:", method, inputs) # the queue should only be adding items to execute item = args[0] g.queue_control.write(True) self.queue_status.going.write(True) - self.fraction_complete.write(0.) + self.fraction_complete.write(0.0) item.started = wt.kit.TimeStamp() - if item.type == 'acquisition': + if item.type == "acquisition": self.execute_acquisition(item) - elif item.type == 'device': + elif item.type == "device": self.execute_device(item) - elif item.type == 'hardware': + elif item.type == "hardware": self.execute_hardware(item) - elif item.type == 'wait': + elif item.type == "wait": self.execute_wait(item) - elif item.type == 'interrupt': + elif item.type == "interrupt": self.execute_interrupt(item) item.exited = wt.kit.TimeStamp() - self.fraction_complete.write(1.) + self.fraction_complete.write(1.0) self.queue_status.going.write(False) g.queue_control.write(False) self.action_complete.emit() @@ -192,7 +190,7 @@ def dequeue(self, method, inputs): self.enqueued.pop() if not self.enqueued.read(): self.check_busy([]) - + def execute_acquisition(self, item): # create acquisition worker object module = item.module @@ -203,54 +201,61 @@ def execute_acquisition(self, item): if g.google_drive_enabled.read(): g.google_drive_control.read().reserve_id(folder_name) url = g.google_drive_control.read().id_to_open_url(folder_name) - g.google_drive_control.read().create_folder(folder_name, self.folder.read(), folder_name) + g.google_drive_control.read().create_folder( + folder_name, self.folder.read(), folder_name + ) ini = wt.kit.INI(item.aqn_path) - ini.write('info', 'url', url) + ini.write("info", "url", url) item.url = url # run it try: worker.run() except Exception as error: # TODO: log error - print('ACQUISITION ERROR:', error) + print("ACQUISITION ERROR:", error) traceback.print_exc() # upload aqn file if g.google_drive_enabled.read(): - g.google_drive_control.read().create_file(path=str(item.aqn_path), parent_id=self.folder.read(), id_=str(item.aqn_path)) + g.google_drive_control.read().create_file( + path=str(item.aqn_path), parent_id=self.folder.read(), id_=str(item.aqn_path) + ) # send message on slack if g.slack_enabled.read(): name = os.path.split(folder_name)[1] - message = ':checkered_flag: acquisition complete - {0} - {1}'.format(name, item.url) + message = ":checkered_flag: acquisition complete - {0} - {1}".format(name, item.url) g.slack_control.read().send_message(message) def execute_device(self, item): # TODO: time.sleep(5) item.finished.write(False) - + def execute_hardware(self, item): item.execute() item.finished.write(True) - + def execute_script(self, item): # TODO: time.sleep(5) item.finished.write(False) - + def execute_wait(self, item): # get stop time tz = dateutil.tz.tzlocal() now = datetime.datetime.now(tz) - if item.operation == 'For': - h, m, s = [float(s) if s is not '' else 0. for s in item.amount.split(':')] - total_seconds = 3600.*h + 60.*m + s + if item.operation == "For": + h, m, s = [float(s) if s is not "" else 0.0 for s in item.amount.split(":")] + total_seconds = 3600.0 * h + 60.0 * m + s stop_time = now + datetime.timedelta(0, total_seconds) - elif item.operation == 'Until': + elif item.operation == "Until": inputs = {} - inputs['hour'], inputs['minute'], s = [int(s) if s is not '' else 0 for s in item.amount.split(':')] + inputs["hour"], inputs["minute"], s = [ + int(s) if s is not "" else 0 for s in item.amount.split(":") + ] stop_time = collections.OrderedDict() - stop_time['seconds'] = s + stop_time["seconds"] = s + def get(current, previous): if current in inputs.keys(): input = inputs[current] @@ -265,20 +270,21 @@ def get(current, previous): stop_time[current] = current_now else: stop_time[current] = current_now + 1 - previous = 'seconds' - keys = ['minute', 'hour', 'day', 'month', 'year'] + + previous = "seconds" + keys = ["minute", "hour", "day", "month", "year"] for key in keys: get(key, previous) previous = key - stop_time = datetime.datetime(*stop_time.values()[::-1]+[0, tz]) + stop_time = datetime.datetime(*stop_time.values()[::-1] + [0, tz]) # wait until stop time - total_time = (stop_time-now).total_seconds() + total_time = (stop_time - now).total_seconds() time_remaining = total_time while time_remaining > 0: time.sleep(1) now = datetime.datetime.now(tz) - time_remaining = (stop_time-now).total_seconds() - self.fraction_complete.write((total_time-time_remaining)/total_time) + time_remaining = (stop_time - now).total_seconds() + self.fraction_complete.write((total_time - time_remaining) / total_time) # check for pause while self.queue_status.pause.read(): self.queue_status.paused.write(True) @@ -287,26 +293,25 @@ def get(current, previous): return # send message on slack if g.slack_enabled.read(): - message = ':timer_clock: wait complete - {0}'.format(item.description) + message = ":timer_clock: wait complete - {0}".format(item.description) g.slack_control.read().send_message(message) - + item.finished.write(True) def execute_interrupt(self, item): self.queue_status.go.write(False) if g.slack_enabled.read(): - message = ':octagonal_sign: Interrupted - {0}\n{1}\nUse `run` command to continue'.format(item.description, item.info) + message = ":octagonal_sign: Interrupted - {0}\n{1}\nUse `run` command to continue".format( + item.description, item.info + ) g.slack_control.read().send_message(message) item.finished.write(True) - - ### queue class ############################################################### class QueueStatus(QtCore.QObject): - def __init__(self): QtCore.QObject.__init__(self) self.go = pc.Busy() @@ -315,32 +320,29 @@ def __init__(self): self.paused = pc.Busy() self.stop = pc.Busy() self.stopped = pc.Busy() - self.runtime = 0. # seconds + self.runtime = 0.0 # seconds self.last_started = None self.tz = dateutil.tz.tzlocal() - + def run_timer(self): self.last_started = datetime.datetime.now(self.tz) - + def stop_timer(self): now = datetime.datetime.now(self.tz) - self.runtime += (now-self.last_started).total_seconds() - + self.runtime += (now - self.last_started).total_seconds() + def get_runtime(self): - ''' + """ returns total seconds run - ''' + """ out = self.runtime if self.last_started is not None: now = datetime.datetime.now(self.tz) - out += (now-self.last_started).total_seconds() + out += (now - self.last_started).total_seconds() return out - - -class Queue(): - +class Queue: def __init__(self, name, gui, folder=None, url=None): self.name = name[:10] # cannot be more than 10 charachters self.gui = gui @@ -348,16 +350,16 @@ def __init__(self, name, gui, folder=None, url=None): self.timestamp = wt.kit.TimeStamp() # create queue folder if folder is None: - folder_name = ' '.join([self.timestamp.path, self.name]) + folder_name = " ".join([self.timestamp.path, self.name]) self.folder = pc.Value(os.path.join(g.main_window.read().data_folder, folder_name)) os.mkdir(self.folder.read()) else: self.folder = pc.Value(folder) folder_name = os.path.basename(self.folder.read()) # create queue file - self.ini_path = os.path.abspath(os.path.join(self.folder.read(), 'queue.ini')) + self.ini_path = os.path.abspath(os.path.join(self.folder.read(), "queue.ini")) if not os.path.isfile(self.ini_path): - with open(self.ini_path, 'a'): + with open(self.ini_path, "a"): os.utime(self.ini_path, None) # quickly create empty file self.ini = wt.kit.INI(self.ini_path) # I don't use ini_handler here # parameters and status indicators @@ -370,8 +372,12 @@ def __init__(self, name, gui, folder=None, url=None): if g.google_drive_enabled.read(): g.google_drive_control.read().reserve_id(self.folder.read()) self.url = g.google_drive_control.read().id_to_open_url(self.folder.read()) - g.google_drive_control.read().create_folder(path=self.folder.read(), id_=self.folder.read()) - g.google_drive_control.read().create_file(self.ini_path, self.folder.read(), self.ini_path) + g.google_drive_control.read().create_folder( + path=self.folder.read(), id_=self.folder.read() + ) + g.google_drive_control.read().create_file( + self.ini_path, self.folder.read(), self.ini_path + ) else: self.url = None else: @@ -379,7 +385,9 @@ def __init__(self, name, gui, folder=None, url=None): # initialize worker self.worker_enqueued = pc.Enqueued() self.worker_busy = pc.Busy() - self.worker = Worker(self.worker_enqueued, self.worker_busy, self.status, self.url, self.index, self.folder) + self.worker = Worker( + self.worker_enqueued, self.worker_busy, self.status, self.url, self.index, self.folder + ) self.worker.fraction_complete.updated.connect(self.update_progress) self.worker.action_complete.connect(self.on_action_complete) self.worker_thread = QtCore.QThread() @@ -388,9 +396,9 @@ def __init__(self, name, gui, folder=None, url=None): self.worker_q = pc.Q(self.worker_enqueued, self.worker_busy, self.worker) # message on slack if g.slack_enabled.read(): - message = ':baby: new queue created - {0} - {1}'.format(folder_name, self.url) + message = ":baby: new queue created - {0} - {1}".format(folder_name, self.url) g.slack_control.read().send_message(message) - + def _start_next_action(self): self.status.pause.write(False) self.status.paused.write(False) @@ -398,29 +406,36 @@ def _start_next_action(self): self.status.stopped.write(False) self.gui.progress_bar.begin_new_scan_timer() item = self.items[self.index.read()] - item.status = 'RUNNING' + item.status = "RUNNING" if isinstance(item, Interrupt): # This needs to run on the main thread to avoid Seg Fault if item.info.strip(): - msg = QtWidgets.QMessageBox(QtWidgets.QMessageBox.NoIcon, f"Interrupt: {item.name}", item.info, parent=self.gui.parent_widget) + msg = QtWidgets.QMessageBox( + QtWidgets.QMessageBox.NoIcon, + f"Interrupt: {item.name}", + item.info, + parent=self.gui.parent_widget, + ) msg.addButton("Resume Queue", QtWidgets.QMessageBox.ActionRole) msg.addButton("Dismiss", QtWidgets.QMessageBox.AcceptRole) msg.setModal(False) msg.buttonClicked.connect(self.resume_queue) msg.show() - self.worker_q.push('excecute', item) + self.worker_q.push("excecute", item) self.gui.message_widget.setText(item.description.upper()) def append_acquisition(self, aqn_path, update=True): # get properties ini = wt.kit.INI(aqn_path) - module_name = ini.read('info', 'module') - item_name = ini.read('info', 'name') - info = ini.read('info', 'info') - description = ini.read('info', 'description') + module_name = ini.read("info", "module") + item_name = ini.read("info", "name") + info = ini.read("info", "info") + description = ini.read("info", "description") module = self.gui.modules[module_name] # create item - acquisition = Acquisition(aqn_path, module, name=item_name, info=info, description=description) + acquisition = Acquisition( + aqn_path, module, name=item_name, info=info, description=description + ) # append and update self.items.append(acquisition) if update: @@ -428,7 +443,7 @@ def append_acquisition(self, aqn_path, update=True): def append_device(self): # TODO: - print('append_device') + print("append_device") def append_hardware(self, hardwares, value, units, name, info, description, update=True): hardware = Hardware(hardwares, value, units, name=name, info=info, description=description) @@ -438,7 +453,7 @@ def append_hardware(self, hardwares, value, units, name, info, description, upda def append_script(self): # TODO: - print('append_script') + print("append_script") def append_wait(self, operation, amount, name, info, description): # create item @@ -453,7 +468,7 @@ def append_interrupt(self, name, info, description): # append and update self.items.append(interrupt) self.update() - + def change_index(self, current_index, new_index): item = self.items.pop(current_index) if new_index < self.index.read(): @@ -461,27 +476,27 @@ def change_index(self, current_index, new_index): self.items.insert(new_index, item) self.update() return item - + def exit(self): # cleanly exit thread self.worker_thread.exit() self.worker_thread.quit() - + def get_runtime(self): seconds = self.status.get_runtime() m, s = divmod(seconds, 60) h, m = divmod(m, 60) - string = ':'.join([str(int(h)).zfill(3), str(int(m)).zfill(2), str(int(s)).zfill(2)]) + string = ":".join([str(int(h)).zfill(3), str(int(m)).zfill(2), str(int(s)).zfill(2)]) return string - def interrupt(self, option=None, message='Please choose how to proceed.'): - self.gui.queue_control.set_style('WAITING', 'stop') + def interrupt(self, option=None, message="Please choose how to proceed."): + self.gui.queue_control.set_style("WAITING", "stop") # pause self.status.pause.write(True) while not self.status.paused.read(): time.sleep(0.01) # ask user how to proceed - options = ['RESUME', 'SKIP', 'STOP'] + options = ["RESUME", "SKIP", "STOP"] self.gui.interrupt_choice_window.set_text(message) if option is None: index_chosen = self.gui.interrupt_choice_window.show() @@ -489,17 +504,17 @@ def interrupt(self, option=None, message='Please choose how to proceed.'): index_chosen = wt.kit.get_index(options, option) chosen = options[index_chosen] # proceed - if chosen == 'RESUME': + if chosen == "RESUME": self.status.pause.write(False) - elif chosen == 'SKIP': + elif chosen == "SKIP": self.status.stop.write(True) self.status.pause.write(False) - elif chosen == 'STOP': + elif chosen == "STOP": self.status.stop.write(True) self.status.go.write(False) self.status.pause.write(False) # wait for stop - if chosen in ['SKIP', 'STOP']: + if chosen in ["SKIP", "STOP"]: while not self.status.stopped.read(): time.sleep(0.01) # finish @@ -512,15 +527,17 @@ def finish(self): self.gui.on_queue_finished() self.update() if g.slack_enabled.read(): - g.slack_control.read().send_message(':bell: queue emptied - total runtime {}'.format(self.get_runtime())) + g.slack_control.read().send_message( + ":bell: queue emptied - total runtime {}".format(self.get_runtime()) + ) def on_action_complete(self): # update current item item = self.items[self.index.read()] if item.finished.read(): - item.status = 'COMPLETE' + item.status = "COMPLETE" else: - item.status = 'FAILED' + item.status = "FAILED" # onto next item self.index.write(self.index.read() + 1) queue_done = len(self.items) == self.index.read() @@ -541,7 +558,7 @@ def pop(self, index): def resume_queue(self, button): if not self.status.go.read() and button.text() == "Resume Queue": self.run() - + def run(self): # status self.status.run_timer() @@ -551,56 +568,61 @@ def run(self): self._start_next_action() # finish self.update() - + def update(self): # update ini self.ini.clear() - self.ini.add_section('info') - self.ini.write('info', 'PyCMDS version', g.version.read()) - self.ini.write('info', 'created', self.timestamp.RFC3339) - self.ini.write('info', 'runtime', self.get_runtime()) - self.ini.write('info', 'name', self.name) - self.ini.write('info', 'url', self.url) + self.ini.add_section("info") + self.ini.write("info", "PyCMDS version", g.version.read()) + self.ini.write("info", "created", self.timestamp.RFC3339) + self.ini.write("info", "runtime", self.get_runtime()) + self.ini.write("info", "name", self.name) + self.ini.write("info", "url", self.url) for index, item in enumerate(self.items): index_str = str(index).zfill(3) self.ini.add_section(index_str) - self.ini.write(index_str, 'type', item.type) - self.ini.write(index_str, 'name', item.name) - self.ini.write(index_str, 'info', item.info) - self.ini.write(index_str, 'description', item.description) - self.ini.write(index_str, 'status', item.status) - self.ini.write(index_str, 'created', item.created.RFC3339) + self.ini.write(index_str, "type", item.type) + self.ini.write(index_str, "name", item.name) + self.ini.write(index_str, "info", item.info) + self.ini.write(index_str, "description", item.description) + self.ini.write(index_str, "status", item.status) + self.ini.write(index_str, "created", item.created.RFC3339) if item.started is not None: - self.ini.write(index_str, 'started', item.started.RFC3339) + self.ini.write(index_str, "started", item.started.RFC3339) if item.exited is not None: - self.ini.write(index_str, 'exited', item.exited.RFC3339) + self.ini.write(index_str, "exited", item.exited.RFC3339) # allow item to write additional information item.write_to_ini(self.ini, index_str) if item.status != "ENQUEUED" and hasattr(item, "module"): # KFS: This is a slight bit of a hack to get around editing the queue file from worker thread # Rather than replacing the path in the queue when the file is copied, it is done here in update - path = os.path.join(self.folder.read(), " ".join([index_str, item.module.module_name, item.name]).rstrip()) + ".aqn" + path = ( + os.path.join( + self.folder.read(), + " ".join([index_str, item.module.module_name, item.name]).rstrip(), + ) + + ".aqn" + ) if os.path.exists(path): - self.ini.write(index_str, 'path', path) + self.ini.write(index_str, "path", path) # update display self.gui.update_ui() # upload ini if g.google_drive_enabled.read(): g.google_drive_control.read().update_file(self.ini_path, self.ini_path) - + def update_progress(self): # progress bar self.gui.progress_bar.set_fraction(self.worker.fraction_complete.read()) # queue timer runtime_string = self.get_runtime() self.gui.runtime.write(runtime_string) - + ### GUI ####################################################################### class GUI(QtCore.QObject): - def __init__(self, parent_widget, message_widget): QtCore.QObject.__init__(self) self.progress_bar = g.progress_bar @@ -611,27 +633,37 @@ def __init__(self, parent_widget, message_widget): parent_widget.layout().setContentsMargins(0, 10, 0, 0) self.layout = parent_widget.layout() self.create_frame() - self.interrupt_choice_window = pw.ChoiceWindow('QUEUE INTERRUPTED', button_labels=['RESUME', 'SKIP', 'STOP']) + self.interrupt_choice_window = pw.ChoiceWindow( + "QUEUE INTERRUPTED", button_labels=["RESUME", "SKIP", "STOP"] + ) # queue self.queue = None self.queue_status = QueueStatus() - + def add_button_to_table(self, i, j, text, color, method): # for some reason, my lambda function does not work when called outside # of a dedicated method - Blaise 2016-09-14 button = pw.SetButton(text, color=color) - button.setProperty('TableRowIndex', i) - button.clicked.connect(lambda: method(button.property('TableRowIndex'))) + button.setProperty("TableRowIndex", i) + button.clicked.connect(lambda: method(button.property("TableRowIndex"))) self.table.setCellWidget(i, j, button) return button - + def add_index_to_table(self, i, max_value): # for some reason, my lambda function does not work when called outside # of a dedicated method - Blaise 2016-09-14 index = QtWidgets.QDoubleSpinBox() - StyleSheet = 'QDoubleSpinBox{color: custom_color; font: 14px;}'.replace('custom_color', g.colors_dict.read()['text_light']) - StyleSheet += 'QScrollArea, QWidget{background: custom_color; border-color: black; border-radius: 0px;}'.replace('custom_color', g.colors_dict.read()['background']) - StyleSheet += 'QWidget:disabled{color: custom_color_1; font: 14px; border: 0px solid black; border-radius: 0px;}'.replace('custom_color_1', g.colors_dict.read()['text_disabled']).replace('custom_color_2', g.colors_dict.read()['widget_background']) + StyleSheet = "QDoubleSpinBox{color: custom_color; font: 14px;}".replace( + "custom_color", g.colors_dict.read()["text_light"] + ) + StyleSheet += "QScrollArea, QWidget{background: custom_color; border-color: black; border-radius: 0px;}".replace( + "custom_color", g.colors_dict.read()["background"] + ) + StyleSheet += "QWidget:disabled{color: custom_color_1; font: 14px; border: 0px solid black; border-radius: 0px;}".replace( + "custom_color_1", g.colors_dict.read()["text_disabled"] + ).replace( + "custom_color_2", g.colors_dict.read()["widget_background"] + ) index.setStyleSheet(StyleSheet) index.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) index.setSingleStep(1) @@ -639,11 +671,13 @@ def add_index_to_table(self, i, max_value): index.setMaximum(max_value) index.setAlignment(QtCore.Qt.AlignCenter) index.setValue(i) - index.setProperty('TableRowIndex', i) - index.editingFinished.connect(lambda: self.on_index_changed(index.property('TableRowIndex'), int(index.value()))) + index.setProperty("TableRowIndex", i) + index.editingFinished.connect( + lambda: self.on_index_changed(index.property("TableRowIndex"), int(index.value())) + ) self.table.setCellWidget(i, 0, index) - return index - + return index + def create_acquisition_frame(self): frame = QtWidgets.QWidget() frame.setLayout(QtWidgets.QVBoxLayout()) @@ -651,20 +685,20 @@ def create_acquisition_frame(self): layout.setMargin(0) layout.setContentsMargins(0, 0, 0, 0) # load aqn file - self.load_aqn_button = pw.SetButton('LOAD FROM FILE') + self.load_aqn_button = pw.SetButton("LOAD FROM FILE") self.load_aqn_button.clicked.connect(self.on_load_aqn) layout.addWidget(self.load_aqn_button) - + input_table = pw.InputTable() # module combobox self.module_combobox = pc.Combo() - input_table.add('Acquisition Module', self.module_combobox) + input_table.add("Acquisition Module", self.module_combobox) # name self.acquisition_name = pc.String(max_length=10) - input_table.add('Name', self.acquisition_name) + input_table.add("Name", self.acquisition_name) # info self.acquisition_info = pc.String() - input_table.add('Info', self.acquisition_info) + input_table.add("Info", self.acquisition_info) layout.addWidget(input_table) # module container widget self.module_container_widget = QtWidgets.QWidget() @@ -674,7 +708,7 @@ def create_acquisition_frame(self): module_layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.module_container_widget) # save aqn file - self.save_aqn_button = pw.SetButton('SAVE FILE') + self.save_aqn_button = pw.SetButton("SAVE FILE") self.save_aqn_button.clicked.connect(self.on_save_aqn) layout.addWidget(self.save_aqn_button) return frame @@ -687,13 +721,15 @@ def create_device_frame(self): # name and info input_table = pw.InputTable() self.device_name = pc.String(max_length=10) - input_table.add('Name', self.device_name) + input_table.add("Name", self.device_name) self.device_info = pc.String() - input_table.add('Info', self.device_info) - layout.addWidget(input_table) + input_table.add("Info", self.device_info) + layout.addWidget(input_table) # not implemented message - label = QtWidgets.QLabel('device not currently implemented') - StyleSheet = 'QLabel{color: custom_color; font: bold 14px}'.replace('custom_color', g.colors_dict.read()['text_light']) + label = QtWidgets.QLabel("device not currently implemented") + StyleSheet = "QLabel{color: custom_color; font: bold 14px}".replace( + "custom_color", g.colors_dict.read()["text_light"] + ) label.setStyleSheet(StyleSheet) layout.addWidget(label) return frame @@ -709,19 +745,19 @@ def create_frame(self): self.table = pw.TableWidget() self.table.verticalHeader().hide() self.table_cols = collections.OrderedDict() - self.table_cols['Index'] = 50 - self.table_cols['Type'] = 75 - self.table_cols['Status'] = 85 - self.table_cols['Started'] = 110 - self.table_cols['Exited'] = 110 - self.table_cols['Description'] = 200 # expanding - self.table_cols['Remove'] = 75 - self.table_cols['Load'] = 75 + self.table_cols["Index"] = 50 + self.table_cols["Type"] = 75 + self.table_cols["Status"] = 85 + self.table_cols["Started"] = 110 + self.table_cols["Exited"] = 110 + self.table_cols["Description"] = 200 # expanding + self.table_cols["Remove"] = 75 + self.table_cols["Load"] = 75 for i in range(len(self.table_cols.keys())): self.table.insertColumn(i) labels = list(self.table_cols.keys()) - labels[-1] = '' - labels[-2] = '' + labels[-1] = "" + labels[-2] = "" self.table.setHorizontalHeaderLabels(labels) self.table.horizontalHeader().setResizeMode(5, QtWidgets.QHeaderView.Stretch) self.table.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) @@ -729,7 +765,7 @@ def create_frame(self): self.table.setColumnWidth(i, width) display_layout.addWidget(self.table) # line ---------------------------------------------------------------- - line = pw.Line('V') + line = pw.Line("V") self.layout.addWidget(line) # controls ------------------------------------------------------------ settings_container_widget = QtWidgets.QWidget() @@ -743,34 +779,34 @@ def create_frame(self): self.layout.addWidget(settings_scroll_area) # new queue name input_table = pw.InputTable() - self.new_queue_name = pc.String('queue', max_length=10) - input_table.add('Create Queue', None) - input_table.add('New Name', self.new_queue_name) + self.new_queue_name = pc.String("queue", max_length=10) + input_table.add("Create Queue", None) + input_table.add("New Name", self.new_queue_name) settings_layout.addWidget(input_table) # new queue button - self.new_queue_button = pw.SetButton('MAKE NEW QUEUE') + self.new_queue_button = pw.SetButton("MAKE NEW QUEUE") self.new_queue_button.clicked.connect(self.create_new_queue) g.queue_control.disable_when_true(self.new_queue_button) settings_layout.addWidget(self.new_queue_button) # load button - self.load_button = pw.SetButton('OPEN QUEUE') + self.load_button = pw.SetButton("OPEN QUEUE") self.load_button.clicked.connect(self.on_open_queue) g.queue_control.disable_when_true(self.load_button) settings_layout.addWidget(self.load_button) # current queue name input_table = pw.InputTable() self.queue_name = pc.String(display=True) - input_table.add('Name', self.queue_name) + input_table.add("Name", self.queue_name) # current queue timestamp self.queue_timestamp = pc.String(display=True) - input_table.add('Timestamp', self.queue_timestamp) + input_table.add("Timestamp", self.queue_timestamp) settings_layout.addWidget(input_table) # horizontal line - line = pw.line('H') + line = pw.line("H") settings_layout.addWidget(line) # adjust queue label input_table = pw.InputTable() - input_table.add('Control Queue', None) + input_table.add("Control Queue", None) settings_layout.addWidget(input_table) # go button self.queue_control = pw.QueueControl() @@ -779,36 +815,36 @@ def create_frame(self): self.queue_control.setDisabled(True) # queue runtime input_table = pw.InputTable() - self.runtime = pc.String(initial_value='000:00:00', display=True) - input_table.add('Queue Runtime', self.runtime) + self.runtime = pc.String(initial_value="000:00:00", display=True) + input_table.add("Queue Runtime", self.runtime) settings_layout.addWidget(input_table) # horizontal line - line = pw.Line('H') + line = pw.Line("H") settings_layout.addWidget(line) # type combobox input_table = pw.InputTable() - allowed_values = ['Acquisition', 'Wait', 'Interrupt', 'Hardware', 'Device', 'Script'] - allowed_values.remove('Device') # not ready yet - allowed_values.remove('Script') # not ready yet + allowed_values = ["Acquisition", "Wait", "Interrupt", "Hardware", "Device", "Script"] + allowed_values.remove("Device") # not ready yet + allowed_values.remove("Script") # not ready yet self.type_combo = pc.Combo(allowed_values=allowed_values) self.type_combo.updated.connect(self.update_type) - input_table.add('Add to Queue', None) - input_table.add('Type', self.type_combo) + input_table.add("Add to Queue", None) + input_table.add("Type", self.type_combo) settings_layout.addWidget(input_table) # frames self.type_frames = collections.OrderedDict() - self.type_frames['Acquisition'] = self.create_acquisition_frame() - self.type_frames['Wait'] = self.create_wait_frame() - self.type_frames['Interrupt'] = self.create_interrupt_frame() - self.type_frames['Hardware'] = self.create_hardware_frame() - self.type_frames['Device'] = self.create_device_frame() - self.type_frames['Script'] = self.create_script_frame() + self.type_frames["Acquisition"] = self.create_acquisition_frame() + self.type_frames["Wait"] = self.create_wait_frame() + self.type_frames["Interrupt"] = self.create_interrupt_frame() + self.type_frames["Hardware"] = self.create_hardware_frame() + self.type_frames["Device"] = self.create_device_frame() + self.type_frames["Script"] = self.create_script_frame() for frame in self.type_frames.values(): settings_layout.addWidget(frame) frame.hide() self.update_type() # append button - self.append_button = pw.SetButton('APPEND TO QUEUE') + self.append_button = pw.SetButton("APPEND TO QUEUE") self.append_button.setDisabled(True) self.append_button.clicked.connect(self.on_append_to_queue) settings_layout.addWidget(self.append_button) @@ -823,10 +859,10 @@ def create_hardware_frame(self): # name and info input_table = pw.InputTable() self.hardware_name = pc.String(max_length=10) - input_table.add('Name', self.hardware_name) + input_table.add("Name", self.hardware_name) self.hardware_info = pc.String() - input_table.add('Info', self.hardware_info) - layout.addWidget(input_table) + input_table.add("Info", self.hardware_info) + layout.addWidget(input_table) self.hardware_hardwares = {} for hw in all_hardwares: checkbox = pc.Bool() @@ -848,7 +884,7 @@ def create_new_queue(self): self.queue = Queue(self.new_queue_name.read(), self) self.queue_name.write(self.queue.name) self.queue_timestamp.write(self.queue.timestamp.path[-5:]) - self.message_widget.setText('QUEUE NOT YET RUN') + self.message_widget.setText("QUEUE NOT YET RUN") self.queue.update() # will call self.update_ui def create_script_frame(self): @@ -859,11 +895,11 @@ def create_script_frame(self): layout.setContentsMargins(0, 0, 0, 0) input_table = pw.InputTable() self.script_name = pc.String(max_length=10) - input_table.add('Name', self.script_name) + input_table.add("Name", self.script_name) self.script_info = pc.String() - input_table.add('Info', self.script_info) + input_table.add("Info", self.script_info) self.script_path = pc.Filepath() - input_table.add('Script Path', self.script_path) + input_table.add("Script Path", self.script_path) layout.addWidget(input_table) return frame @@ -874,17 +910,17 @@ def create_wait_frame(self): layout.setContentsMargins(0, 0, 0, 0) input_table = pw.InputTable() self.wait_name = pc.String(max_length=10) - input_table.add('Name', self.wait_name) + input_table.add("Name", self.wait_name) self.wait_info = pc.String() - input_table.add('Info', self.wait_info) - allowed_values = ['For', 'Until'] + input_table.add("Info", self.wait_info) + allowed_values = ["For", "Until"] self.wait_operation = pc.Combo(allowed_values=allowed_values) - input_table.add('Operation', self.wait_operation) + input_table.add("Operation", self.wait_operation) self.wait_amount = pc.String() - input_table.add('Amount (H:M:S)', self.wait_amount) + input_table.add("Amount (H:M:S)", self.wait_amount) layout.addWidget(input_table) return frame - + def create_interrupt_frame(self): frame = QtWidgets.QWidget() frame.setLayout(QtWidgets.QVBoxLayout()) @@ -892,9 +928,9 @@ def create_interrupt_frame(self): layout.setContentsMargins(0, 0, 0, 0) input_table = pw.InputTable() self.interrupt_name = pc.String(max_length=10) - input_table.add('Name', self.interrupt_name) + input_table.add("Name", self.interrupt_name) self.interrupt_info = pc.String() - input_table.add('Info', self.interrupt_info) + input_table.add("Info", self.interrupt_info) layout.addWidget(input_table) return frame @@ -903,45 +939,55 @@ def get_status(self, full=False): make_field = g.slack_control.read().make_field make_attachment = g.slack_control.read().make_attachment if self.queue is None: - return ':information_desk_person: no queue has been created', {} + return ":information_desk_person: no queue has been created", {} else: - message = ':information_desk_person: {}'.format(self.message_widget.text()) + message = ":information_desk_person: {}".format(self.message_widget.text()) time_remaining_str = g.progress_bar.time_remaining.text() - if not time_remaining_str == '00:00:00': - message += ' - {} remaining'.format(time_remaining_str) + if not time_remaining_str == "00:00:00": + message += " - {} remaining".format(time_remaining_str) attachments = [] - colors = {'ENQUEUED': '#808080', - 'RUNNING': '#FFFF00', - 'COMPLETE': '#00FF00', - 'FAILED': '#FF0000'} + colors = { + "ENQUEUED": "#808080", + "RUNNING": "#FFFF00", + "COMPLETE": "#00FF00", + "FAILED": "#FF0000", + } # queue status fields = [] - fields.append(make_field('name', self.queue.name, short=True)) - fields.append(make_field('created', self.queue.timestamp.human, short=True)) - fields.append(make_field('runtime', self.queue.get_runtime(), short=True)) - fields.append(make_field('done/total', '/'.join([str(self.queue.index.read()), str(len(self.queue.items))]), short=True)) - fields.append(make_field('url', self.queue.url, short=False)) - attachments.append(make_attachment('', fields=fields, color='#00FFFF')) - # queue items + fields.append(make_field("name", self.queue.name, short=True)) + fields.append(make_field("created", self.queue.timestamp.human, short=True)) + fields.append(make_field("runtime", self.queue.get_runtime(), short=True)) + fields.append( + make_field( + "done/total", + "/".join([str(self.queue.index.read()), str(len(self.queue.items))]), + short=True, + ) + ) + fields.append(make_field("url", self.queue.url, short=False)) + attachments.append(make_attachment("", fields=fields, color="#00FFFF")) + # queue items for item_index, item in enumerate(self.queue.items): if not full and item.status != "RUNNING": continue - name = ' - '.join([str(item_index).zfill(3), item.type, item.description]) + name = " - ".join([str(item_index).zfill(3), item.type, item.description]) fields = [] if item.started is not None: - fields.append(make_field('started', item.started.human, short=True)) + fields.append(make_field("started", item.started.human, short=True)) if item.exited is not None: - fields.append(make_field('exited', item.exited.human, short=True)) - if item.type == 'acquisition' and item.status in ['COMPLETE', 'FAILED']: - fields.append(make_field('url', item.url, short=False)) - attachments.append(make_attachment('', title=name, fields=fields, color=colors[item.status])) + fields.append(make_field("exited", item.exited.human, short=True)) + if item.type == "acquisition" and item.status in ["COMPLETE", "FAILED"]: + fields.append(make_field("url", item.url, short=False)) + attachments.append( + make_attachment("", title=name, fields=fields, color=colors[item.status]) + ) return message, attachments - + def load_modules(self): # called by MainWindow.__init__ g.queue_control.write(False) if g.debug.read(): - print('load modules') + print("load modules") # create acquisition thread acquisition_thread = QtCore.QThread() g.scan_thread.write(acquisition_thread) @@ -950,18 +996,18 @@ def load_modules(self): # done from modules.ini # modules appear in order of import (order of appearance in ini) config = configparser.SafeConfigParser() - p = os.path.join(somatic_folder, 'modules.ini') + p = os.path.join(somatic_folder, "modules.ini") config.read(p) self.modules = collections.OrderedDict() - for name in config.options('load'): - if config.get('load', name) == 'True': - path = os.path.join(somatic_folder, 'modules', name + '.py') + for name in config.options("load"): + if config.get("load", name) == "True": + path = os.path.join(somatic_folder, "modules", name + ".py") module = imp.load_source(name, path) if module.load(): module.mkGUI() self.modules[module.module_name] = module self.module_container_widget.layout().addWidget(module.gui.frame) - if len(self.modules)>0: + if len(self.modules) > 0: # update module combo self.module_combobox.set_allowed_values(list(self.modules.keys())) self.module_combobox.updated.connect(self.on_module_combobox_updated) @@ -969,37 +1015,41 @@ def load_modules(self): def on_append_to_queue(self): current_type = self.type_combo.read() - if current_type == 'Acquisition': + if current_type == "Acquisition": p = self.save_aqn(self.queue.folder.read()) self.queue.append_acquisition(p) - elif current_type == 'Wait': + elif current_type == "Wait": name = self.wait_name.read() info = self.wait_info.read() operation = self.wait_operation.read() amount = self.wait_amount.read() - description = ' '.join(['wait', operation.lower(), amount]) - self.queue.append_wait(operation, amount, name=name, info=info, description=description) - elif current_type == 'Interrupt': + description = " ".join(["wait", operation.lower(), amount]) + self.queue.append_wait( + operation, amount, name=name, info=info, description=description + ) + elif current_type == "Interrupt": name = self.interrupt_name.read() info = self.interrupt_info.read() - description = f'INTERRUPT: {name}' + description = f"INTERRUPT: {name}" self.queue.append_interrupt(name=name, info=info, description=description) - elif current_type == 'Hardware': + elif current_type == "Hardware": name = self.hardware_name.read() info = self.hardware_info.read() - hardwares = [k for k,v in self.hardware_hardwares.items() if v.read()] + hardwares = [k for k, v in self.hardware_hardwares.items() if v.read()] value = self.hardware_value.read() units = self.hardware_units.read() description = "%s %f %s" % (hardwares, value, units) - self.queue.append_hardware(hardwares, value, units, name=name, info=info, description=description) - elif current_type == 'Device': + self.queue.append_hardware( + hardwares, value, units, name=name, info=info, description=description + ) + elif current_type == "Device": # TODO: self.queue.append_device() - elif current_type == 'Script': + elif current_type == "Script": # TODO: self.queue.append_script() else: - raise Warning('current_type not recognized in on_append_to_queue') + raise Warning("current_type not recognized in on_append_to_queue") # run queue if self.queue_status.go.read() and not self.queue_status.going.read(): self.queue.run() @@ -1015,10 +1065,10 @@ def on_queue_control_clicked(self): self.update_ui() def on_queue_finished(self): - self.queue_control.set_style('RUN QUEUE', 'go') + self.queue_control.set_style("RUN QUEUE", "go") def on_index_changed(self, row, new_index): - if isinstance(row,int): + if isinstance(row, int): index = row else: index = row.toInt()[0] # given as QVariant @@ -1027,65 +1077,65 @@ def on_index_changed(self, row, new_index): def on_load_aqn(self): # get path from user - caption = 'Choose an aqn file' - directory = os.path.join(somatic_folder, 'saved') - options = 'AQN (*.aqn);;All Files (*.*)' + caption = "Choose an aqn file" + directory = os.path.join(somatic_folder, "saved") + options = "AQN (*.aqn);;All Files (*.*)" p = file_dialog_handler.open_dialog(caption=caption, directory=directory, options=options) # load basic info ini = wt.kit.INI(p) - self.acquisition_name.write(ini.read('info', 'name')) - self.acquisition_info.write(ini.read('info', 'info')) - self.module_combobox.write(ini.read('info', 'module')) + self.acquisition_name.write(ini.read("info", "name")) + self.acquisition_info.write(ini.read("info", "info")) + self.module_combobox.write(ini.read("info", "module")) # allow module to load from file self.modules[self.module_combobox.read()].gui.load(p) def on_load_item(self, row): - if isinstance(row,int): + if isinstance(row, int): index = row else: index = row.toInt()[0] # given as QVariant item = self.queue.items[index] - if item.type == 'acquisition': - self.type_combo.write('Acquisition') + if item.type == "acquisition": + self.type_combo.write("Acquisition") # load basic info p = item.aqn_path aqn = wt.kit.INI(p) - self.acquisition_name.write(aqn.read('info', 'name')) - self.acquisition_info.write(aqn.read('info', 'info')) - self.module_combobox.write(aqn.read('info', 'module')) + self.acquisition_name.write(aqn.read("info", "name")) + self.acquisition_info.write(aqn.read("info", "info")) + self.module_combobox.write(aqn.read("info", "module")) # allow module to load from file self.modules[self.module_combobox.read()].gui.load(p) - elif item.type == 'device': + elif item.type == "device": raise NotImplementedError() - elif item.type == 'hardware': - self.type_combo.write('Hardware') + elif item.type == "hardware": + self.type_combo.write("Hardware") self.hardware_name.write(item.name) self.hardware_info.write(item.info) self.hardware_units.write(item.units) self.hardware_value.write(item.value) - for k,v in self.hardware_hardwares.items(): + for k, v in self.hardware_hardwares.items(): for h in item.hardwares: if k == h.name: v.write(True) - break; + break else: v.write(False) - elif item.type == 'interrupt': - self.type_combo.write('Wait') + elif item.type == "interrupt": + self.type_combo.write("Wait") self.interrupt_name.write(item.name) self.interrupt_info.write(item.info) self.interrupt_message.write(item.message) - elif item.type == 'script': + elif item.type == "script": raise NotImplementedError() - elif item.type == 'wait': - self.type_combo.write('Wait') + elif item.type == "wait": + self.type_combo.write("Wait") self.wait_name.write(item.name) self.wait_info.write(item.info) self.wait_operation.write(item.operation) self.wait_amount.write(item.amount) else: - raise Exception('item.type not recognized in queue.GUI.on_load_item') - + raise Exception("item.type not recognized in queue.GUI.on_load_item") + def on_module_combobox_updated(self): for module in self.modules.values(): module.gui.hide() @@ -1093,88 +1143,92 @@ def on_module_combobox_updated(self): def on_open_queue(self): # get queue folder - caption = 'Choose Queue directory' + caption = "Choose Queue directory" directory = data_folder f = file_dialog_handler.dir_dialog(caption=caption, directory=directory) - p = os.path.join(f, 'queue.ini') + p = os.path.join(f, "queue.ini") ini = wt.kit.INI(p) # choose operation if self.queue is None: - operation = 'REPLACE' + operation = "REPLACE" else: # ask user how to proceed - options = ['APPEND', 'REPLACE'] - choice_window = pw.ChoiceWindow('OPEN QUEUE', button_labels=options) + options = ["APPEND", "REPLACE"] + choice_window = pw.ChoiceWindow("OPEN QUEUE", button_labels=options) index_chosen = choice_window.show() operation = options[index_chosen] # prepare queue - if operation == 'REPLACE': + if operation == "REPLACE": if self.queue is not None: self.queue.exit() - name = ini.read('info', 'name') - url = ini.read('info', 'url') + name = ini.read("info", "name") + url = ini.read("info", "url") self.queue = Queue(name, self, folder=f, url=url) self.queue.status.run_timer() - runtime = ini.read('info', 'runtime') - h, m, s = [int(s) for s in runtime.split(':')] - self.queue.status.runtime = h*3600 + m*60 + s + runtime = ini.read("info", "runtime") + h, m, s = [int(s) for s in runtime.split(":")] + self.queue.status.runtime = h * 3600 + m * 60 + s # append items to queue i = 0 while True: section = str(i).zfill(3) try: - item_type = ini.read(section, 'type') + item_type = ini.read(section, "type") except: break - if item_type == 'acquisition': - p = ini.read(section, 'path') + if item_type == "acquisition": + p = ini.read(section, "path") self.queue.append_acquisition(p, update=False) - elif item_type == 'device': + elif item_type == "device": raise NotImplementedError - elif item_type == 'hardware': - name = ini.read(section, 'name') - info = ini.read(section, 'info') - description = ini.read(section, 'description') - hardwares = ini.read(section, 'hardwares') - value = ini.read(section, 'value') - units = ini.read(section, 'units') - self.queue.append_hardware(hardwares, value, units, name=name, info=info, description=description) - elif item_type == 'interrupt': - name = ini.read(section, 'name') - info = ini.read(section, 'info') - description = ini.read(section, 'description') + elif item_type == "hardware": + name = ini.read(section, "name") + info = ini.read(section, "info") + description = ini.read(section, "description") + hardwares = ini.read(section, "hardwares") + value = ini.read(section, "value") + units = ini.read(section, "units") + self.queue.append_hardware( + hardwares, value, units, name=name, info=info, description=description + ) + elif item_type == "interrupt": + name = ini.read(section, "name") + info = ini.read(section, "info") + description = ini.read(section, "description") self.queue.append_interrupt(name=name, info=info, description=description) - elif item_type == 'script': + elif item_type == "script": raise NotImplementedError - elif item_type == 'wait': - name = ini.read(section, 'name') - info = ini.read(section, 'info') - operation = ini.read(section, 'operation') - amount = ini.read(section, 'amount') - description = ini.read(section, 'description') - self.queue.append_wait(operation, amount, name=name, info=info, description=description) + elif item_type == "wait": + name = ini.read(section, "name") + info = ini.read(section, "info") + operation = ini.read(section, "operation") + amount = ini.read(section, "amount") + description = ini.read(section, "description") + self.queue.append_wait( + operation, amount, name=name, info=info, description=description + ) else: raise KeyError - if operation == 'REPLACE': + if operation == "REPLACE": item = self.queue.items[i] - status = ini.read(section, 'status') - if status == 'RUNNING': - item.status = 'FAILED' + status = ini.read(section, "status") + if status == "RUNNING": + item.status = "FAILED" item.started = wt.kit.TimeStamp() item.exited = wt.kit.TimeStamp() else: item.status = status - item.created = wt.kit.timestamp_from_RFC3339(ini.read(section, 'created')) - if ini.has_section('started'): - item.started = wt.kit.timestamp_from_RFC3339(ini.read(section, 'started')) - item.exited = wt.kit.timestamp_from_RFC3339(ini.read(section, 'exited')) - if item.status == 'COMPLETE': - item.finished.write(True) + item.created = wt.kit.timestamp_from_RFC3339(ini.read(section, "created")) + if ini.has_section("started"): + item.started = wt.kit.timestamp_from_RFC3339(ini.read(section, "started")) + item.exited = wt.kit.timestamp_from_RFC3339(ini.read(section, "exited")) + if item.status == "COMPLETE": + item.finished.write(True) i += 1 # manage queue index index = -1 for index, item in enumerate(self.queue.items): - if item.status == 'ENQUEUED': + if item.status == "ENQUEUED": break else: index += 1 @@ -1185,12 +1239,12 @@ def on_open_queue(self): self.queue_timestamp.write(self.queue.timestamp.path[-5:]) def on_remove_item(self, row): - if isinstance(row,int): + if isinstance(row, int): index = row else: index = row.toInt()[0] # given as QVariant self.queue.pop(index) - + def on_save_aqn(self): self.save_aqn(saved_folder) @@ -1200,25 +1254,25 @@ def save_aqn(self, folder): module_name = self.module_combobox.read() name = self.acquisition_name.read() timestamp = wt.kit.TimeStamp() - aqn_name = ' '.join([timestamp.path, module_name, name]).rstrip() + '.aqn' + aqn_name = " ".join([timestamp.path, module_name, name]).rstrip() + ".aqn" p = os.path.join(folder, aqn_name) # create file - with open(p, 'a'): + with open(p, "a"): os.utime(p, None) # quickly create empty file # fill with general information ini = wt.kit.INI(p) - ini.add_section('info') - ini.write('info', 'PyCMDS version', g.version.read()) - ini.write('info', 'created', timestamp.RFC3339) - ini.write('info', 'module', module_name) - ini.write('info', 'name', name) - ini.write('info', 'info', self.acquisition_info.read()) - ini.write('info', 'description', module_name) # optionally overwritten by module + ini.add_section("info") + ini.write("info", "PyCMDS version", g.version.read()) + ini.write("info", "created", timestamp.RFC3339) + ini.write("info", "module", module_name) + ini.write("info", "name", name) + ini.write("info", "info", self.acquisition_info.read()) + ini.write("info", "description", module_name) # optionally overwritten by module # fill with module specific information self.modules[module_name].gui.save(p) # finish return p - + def update_ui(self): # buttons ------------------------------------------------------------- if self.queue: @@ -1229,13 +1283,13 @@ def update_ui(self): self.queue_control.setDisabled(False) if queue_go: if queue_going: - self.queue_control.set_style('INTERRUPT QUEUE', 'stop') + self.queue_control.set_style("INTERRUPT QUEUE", "stop") else: - self.queue_control.set_style('STOP QUEUE', 'stop') - self.message_widget.setText('QUEUE WAITING') + self.queue_control.set_style("STOP QUEUE", "stop") + self.message_widget.setText("QUEUE WAITING") else: - self.queue_control.set_style('RUN QUEUE', 'go') - self.message_widget.setText('QUEUE STOPPED') + self.queue_control.set_style("RUN QUEUE", "go") + self.message_widget.setText("QUEUE STOPPED") # append button self.append_button.setDisabled(False) # table --------------------------------------------------------------- @@ -1246,8 +1300,8 @@ def update_ui(self): for i, item in enumerate(self.queue.items): self.table.insertRow(i) # index - index = self.add_index_to_table(i, len(self.queue.items)-1) - if not item.status == 'ENQUEUED': + index = self.add_index_to_table(i, len(self.queue.items) - 1) + if not item.status == "ENQUEUED": index.setDisabled(True) # type label = pw.Label(item.type) @@ -1279,11 +1333,11 @@ def update_ui(self): label.setToolTip(item.description) self.table.setCellWidget(i, 5, label) # remove - button = self.add_button_to_table(i, 6, 'REMOVE', 'stop', self.on_remove_item) - if not item.status == 'ENQUEUED': + button = self.add_button_to_table(i, 6, "REMOVE", "stop", self.on_remove_item) + if not item.status == "ENQUEUED": button.setDisabled(True) # load - button = self.add_button_to_table(i, 7, 'LOAD', 'go', self.on_load_item) + button = self.add_button_to_table(i, 7, "LOAD", "go", self.on_load_item) def update_type(self): for frame in self.type_frames.values():