Source code for gui.widget_main_window

import os, sys, inspect

if __name__ == "__main__":
    # Add directories to path for imports

    currentdir = os.path.dirname(
        os.path.abspath(inspect.getfile(inspect.currentframe()))
    )
    parentdir = os.path.dirname(currentdir)

    sys.path.insert(0, os.path.join(currentdir, "ui_files"))
    sys.path.insert(0, parentdir)
    sys.path.insert(0, os.path.join(parentdir, "hardware_interfaces"))
    sys.path.insert(0, os.path.join(parentdir, "experiments"))

import logging
logger = logging.getLogger(__name__)

import numpy as np

# PyQt imports
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import QRunnable, QThreadPool, pyqtSignal, QObject

# Import Qt Threading wrapper
from qt_multithreading_wrapper import Worker

# Import RegEx input validators
from regex_validators import *

# Import of file made from UI designer
from ui_main_window import Ui_MainWindow

from hardware_properties import HardwareProperties

# Import hardware modules
from triax import Triax as Spectrometer
from pi_control import PiController, PiStage
from analog_digital_converter import AnalogDigitalConverter as ADC
from interferometer_counter import InterferometerCounter
from thorlabs_mc2000 import ChopperController as Chopper
from newport_control import NewportControl as MicrometerScrew
from shutter import Shutter
from polarizer import Polarizer
from fpas import Fpas
from fabry_perot import FabryPerot

# Data processing
from data_processing import PixelResponseLinearization as PRL
from data_processing import ChopperStateFinder as CSF

# Import saving module
from save_data import SaveData
from save_data import Background

# Plotting with Matplotlib
import matplotlib

matplotlib.use("Qt5Agg")
from matplotlib.backends.backend_qt5agg import (
    FigureCanvasQTAgg,
    NavigationToolbar2QT as NavigationToolbar,
)
from matplotlib.figure import Figure
from widget_mpl import MplCanvas

# Multiprocessing
import multiprocessing
from multiprocessing import Process, Queue

# Import contextmanager class to dynamically initialize devices.
from contextlib import ExitStack

# Import json
import json

# Import experiments
from show_spectrum import ShowSpectrum
from show_signal import ShowSignal
from show_signal_wobbler import ShowSignalWobbler
from scan_t_zero_interleaves import ScanTZeroInterleaves
from scan_t_zero_wobbler import ScanTZeroWobbler
from show_wobbler_states import ShowWobblerStates
from vis_pump_ir_probe import VisPumpIrProbe
from vis_pump_ir_probe_split_sample import VisPumpIrProbeSplitSample
from bb_ir_pump_ir_probe_interleaves import BBIrPumpIrProbeInterleaves
from fabry_perot_2d_ir_interleaves import FabryPerot2dIrInterleaves
from show_viper import ShowViper
from show_viper_wobbler import ShowViperWobbler
from bb_viper_interleaves import BbViperInterleaves
from bb_viper_wobbler import BbViperWobbler
from fabry_perot_viper_interleaves import FabryPerotViperInterleaves
from ft_2d_ir import Ft2dIr
from ft_viper import FtViper

# #* Uncomment if an experiment needs to be debugged
# #* / troubleshooted. If implemented correctly it reloads
# #* the corresponding experiment module everytime
# #* Start Button is pressed.
# from importlib import reload
# #* Additionally add following import:
# # import xyz_experiment
# #* Add the following to the corresponding
# #* method in the MainWindow class:
# # global xyz_experiment
# # xyz_experiment = reload(xyz_experiment)
# #* Change the instanciation of the corresponding
# #* experiment within its MainWindow method from
# # self.experiment = XYZExperiment(...)
# #* to
# # self.experiment = xyz_experiment.XYZExperiment(...)
# #* (there should be a way more elegant way of doing this
# #* but this will work for sure.)
# #* You might also want to set the corresponding daemons
# #* within the experiment module to True. This will
# #* fix seeing broken pipe error when the garbage collector
# #* does its job.


[docs]class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): def __init__( self, hw, hw_path, *args, username="Tenshinhan", adc=None, pi_stage=None, spectrometer=None, fpas=None, interferometer_counter=None, chopper=None, shutter=None, polarizer=None, mu_screw=None, fabry_perot=None, prl=None, csf=None, obj=None, **kwargs ): super(QtWidgets.QMainWindow, self).__init__(*args, **kwargs) self.setupUi(self) self.setWindowTitle("Jagan - A. Kondratiev, A.R. Thun, G. Wille") self.setWindowIcon(QtGui.QIcon("gui/icon.png")) #! ----------------- self.threadpool = QThreadPool() # Set maximum number of threads to 10 self.threadpool.setMaxThreadCount(1000) # Add attributes self.hw = hw self.hw_path = hw_path # Pixel response linearisation self.prl = prl # Chopper State Finder self.csf = csf # Username self.username = username # Set up default paths on GUI self.groupBox_file.set_default_paths(self.hw) # Set up default path for the delay editor self.widget_delayfile.set_default_paths(self.hw) # Create instance of handler for MCT background files self.background_handler = Background(self.hw.paths.background) # Load experiments into comboBox self.add_experiments() # Set middle pixel to be default pixel for which to show # statistics self.groupBox_stats.lineEdit_stats_pixel.setText( str(self.hw.mct_array.default_pixel) ) # Connect Signals # -------------------START------------------------------- # Setup corresponding experiment when it was changed self.comboBox_experiments.currentIndexChanged.connect(self.setup_experiment) # Setup collection of background self.groupBox_exp.pushButton_exp_background.clicked.connect( self.collect_background ) # Setup saving new t zero to json file self.groupBox_pi_control.pushButton_pi_reset_t_zero.clicked.connect( self.save_t_zero_to_json ) # Connect Signals # -------------------END------------------------------- # Hand over main window to read me file editor self.widget_readmefile.mw_obj = self # Initialize QTimer for updating the GUI values very n seconds self.update_values_timer = QtCore.QTimer() # Start a QTimer which updates the GUI every 1 seconds Connect # it to update_values self.update_values_timer.timeout.connect(self.update_values) # Activate elements on GUI # -------------START------------------------- # Hand over adc object if adc: self.groupBox_adc.adc = adc self.groupBox_adc.setEnabled(True) self.groupBox_adc.update_values() # Hand over pi object if pi_stage: self.groupBox_pi_control.pi_stage = pi_stage # Load all stages into combobox self.groupBox_pi_control.update_combobox() self.groupBox_pi_control.setEnabled(True) self.groupBox_pi_control.update_values() # Hand over spectrometer/ triax object if spectrometer: self.groupBox_triax.triax = spectrometer self.groupBox_triax.setEnabled(True) self.groupBox_triax.update_values() # Set default slit toggle values from hardware properties self.groupBox_triax.lineEdit_triax_slit_toggle_1.setText( str(hw.spectrometer.slit_toggle[0]) ) self.groupBox_triax.lineEdit_triax_slit_toggle_2.setText( str(hw.spectrometer.slit_toggle[1]) ) # Hand over Interferometer counter object This thing has no # interface if interferometer_counter: self.interferometer_counter = interferometer_counter # Hand over FPAS if fpas: self.groupBox_fpas.fpas = fpas self.groupBox_fpas.setEnabled(True) # self.groupBox_fpas.update_values() # Hand over chopper if chopper: self.groupBox_chopper.chopper = chopper # Load all stages into combobox self.groupBox_chopper.update_combobox() self.groupBox_chopper.setEnabled(True) self.groupBox_chopper.update_values() # Hand over shutter if shutter: self.groupBox_shutter.shutter = shutter # Load all stages into combobox self.groupBox_shutter.update_combobox() self.groupBox_shutter.setEnabled(True) self.groupBox_shutter.update_values() # Hand over shutter if polarizer: self.groupBox_polarizer.polarizer = polarizer # Load all stages into combobox self.groupBox_polarizer.update_combobox() self.groupBox_polarizer.setEnabled(True) self.groupBox_polarizer.update_values() # Hand over Mu Screw if mu_screw: self.groupBox_newport.mu_screw = mu_screw self.groupBox_newport.setEnabled(True) self.groupBox_newport.update_values() # Hand over Fabry Perot if fabry_perot: self.groupBox_fabry_perot.fabry_perot = fabry_perot self.groupBox_fabry_perot.widget_pyqtgraph = ( self.stackedWidget_plotting_pyqtgraph ) self.groupBox_fabry_perot.setEnabled(True) self.groupBox_fabry_perot.update_values() # Activate elements on GUI # -------------END------------------------- # Make start button work # * This needs to be called after # * "Activate elements on GUI" # * otherwise GUI elements won't # * deactivate properly the first # * time you press start self.setup_experiment()
[docs] def add_experiments(self): """ Loads experiments from json file into drop down menu. """ with open(self.hw.paths.experiments) as json_file: self.experiments = json.load(json_file) for key, val in self.experiments.items(): val = val["active"][0] # Only if experiments was specified as "active" add it # to GUI if val == 1: self.comboBox_experiments.addItem(key)
[docs] def setup_experiment(self): # Disconnect old signals before reconnecting new signals The try # except statement is used because .disconnect raises an Error # if there were no signals connected in the first place. try: self.groupBox_exp.pushButton_toggle_meas.clicked.disconnect() except Exception: pass # Change text to start accordingly self.groupBox_exp.pushButton_toggle_meas.setText("START MEASUREMENT") # Remove save file text self.groupBox_file.lineEdit_file_save_name.setText("") # Setup new Queue that will receive experiment info (scan idx, # delay idx...) and statistics information (standard deviation # etc.) self.info_queue = Queue() # Setup function that will continuously update statistics # groupBox and experiment GroupBox self.update_experiment_info() # Setup GUI activation / deactivation self.gui_activator = GUIActivation() # Setup everything for corresponding experiment Add GUI elements # that need to be disabled in every case Dropdown menu for # experiments self.gui_activator.add(self.comboBox_experiments) # Button to collect background self.gui_activator.add(self.groupBox_exp.pushButton_exp_background) # File path groupBox self.gui_activator.add(self.groupBox_file) # Fabry Perot GroupBox self.gui_activator.add(self.groupBox_fabry_perot.lineEdit_fp_pixel) self.gui_activator.add(self.groupBox_fabry_perot.lineEdit_fp_wavenumber) self.gui_activator.add(self.groupBox_fabry_perot.lineEdit_fp_wavelength) self.gui_activator.add(self.groupBox_adc) if self.comboBox_experiments.currentText() == "Show Spectrum": # Connect Start Measurement Button to show spectrum # experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.show_spectrum) # Uncheck save checkboxes because we usually don't want to # save show spectrum data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for show spectrum relevant GUI elements to gui # activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) if self.comboBox_experiments.currentText() == "Show Signal (UV/VIS-Pump)": # Connect Start Measurement Button to show signal experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.show_signal_vis_pump ) # Uncheck save checkboxes because we usually don't want to # save show signal data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for show signal relevant GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) if self.comboBox_experiments.currentText() == "Show Signal (IR-Pump)": # Connect Start Measurement Button to show signal experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.show_signal_ir_pump ) # Uncheck save checkboxes because we usually don't want to # save show signal data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for show signal relevant GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) if ( self.comboBox_experiments.currentText() == "Show Signal (IR-Pump with Wobbler)" ): # Connect Start Measurement Button to Show Signal (IR-Pump # with Wobbler) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.show_signal_ir_pump_wobbler ) # Uncheck save checkboxes because we usually don't want to # save Show Signal (IR-Pump with Wobbler) data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for Show Signal (IR-Pump with Wobbler) relevant GUI # elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) if ( self.comboBox_experiments.currentText() == "Show VIPER - colorful experiment" ): # Connect Start Measurement Button to Show VIPER - colorful # experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.show_viper) # Uncheck save checkboxes because we usually don't want to # save Show VIPER - colorful experiment data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for show signal relevant GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) if self.comboBox_experiments.currentText() == "Show VIPER (Wobbler)": # Connect Start Measurement Button to Show VIPER (Wobbler) # experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.show_viper_wobbler ) # Uncheck save checkboxes because we usually don't want to # save Show VIPER (Wobbler) experiment data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for show signal relevant GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) if self.comboBox_experiments.currentText() == "Scan t zero (Interleaves)": # Connect Start Measurement Button to scan t_zero # (Interleaves) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.scan_t_zero_interleaves ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # scan t zero (Interleaves) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Set text of save_file lineEdit in case it was not # specified if self.groupBox_file.lineEdit_file_save_name.text() == "": self.groupBox_file.lineEdit_file_save_name.setText( "scan_t_zero_interleaves" ) # Add for scan t zero (Interleaves) relevant GUI elements to # gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_exp.lineEdit_exp_interleave) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "Scan t zero (Wobbler)": # Connect Start Measurement Button to scan t_zero # (Interleaves) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.scan_t_zero_wobbler ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # scan t zero (Interleaves) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Set text of save_file lineEdit in case it was not # specified if self.groupBox_file.lineEdit_file_save_name.text() == "": self.groupBox_file.lineEdit_file_save_name.setText( "scan_t_zero_wobbler" ) # Add for scan t zero (Interleaves) relevant GUI elements to # gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) if self.comboBox_experiments.currentText() == "Show Wobbler States": # Connect Start Measurement Button to show wobbler # experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.show_wobbler_states ) # Uncheck save checkboxes because we usually don't want to # save show wobbler data self.groupBox_file.checkBox_file_save.setChecked(False) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for show wobbler relevant GUI elements to gui # activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) if self.comboBox_experiments.currentText() == "UV/VIS-Pump IR-Probe": # Connect Start Measurement Button to UV/VIS-Pump IR-Probe # experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.vis_pump_ir_probe ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # UV/VIS-Pump IR-Probe information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for UV/VIS-Pump IR-Probe relevant GUI elements to gui # activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_shutter) if ( self.comboBox_experiments.currentText() == "UV/VIS-Pump IR-Probe (Split Sample)" ): # Connect Start Measurement Button to UV/VIS-Pump IR-Probe # (Split Sample) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.vis_pump_ir_probe_split_sample ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # UV/VIS-Pump IR-Probe (Split Sample) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for UV/VIS-Pump IR-Probe (Split Sample) relevant GUI # elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_newport) self.gui_activator.add(self.groupBox_shutter) if ( self.comboBox_experiments.currentText() == "Broadband IR-Pump IR-Probe (Interleaves)" ): # Connect Start Measurement Button to Broadband-IR-Pump # IR-Probe (Interleaves) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.bb_ir_pump_ir_probe_intl ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # Broadband IR-Pump IR-Probe (Interleaves) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for Broadband IR-Pump IR-Probe (Interleaves) relevant # GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "2D-IR Fabry Perot (Interleaves)": # Connect Start Measurement Button to 2D-IR Fabry Perot # (Interleaves) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.fabry_perot_2d_ir_intl ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # 2D-IR Fabry Perot (Interleaves) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for 2D-IR Fabry Perot (Interleaves) relevant GUI # elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_fabry_perot) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "Broadband VIPER (Interleaves)": # Connect Start Measurement Button to Broadband VIPER # (Interleaves) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.bb_viper_intl) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # Broadband VIPER (Interleaves) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for Broadband VIPER (Interleaves) relevant GUI # elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "Broadband VIPER (Wobbler)": # Connect Start Measurement Button to Broadband VIPER # (Wobbler) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.bb_viper_wobbler ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # Broadband VIPER (Wobbler) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for Broadband VIPER (Wobbler) relevant GUI elements to # gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "Fabry Perot VIPER (Interleaves)": # Connect Start Measurement Button to Fabry Perot VIPER # (Interleaves) experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.fabry_perot_viper_intl ) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # Fabry Perot VIPER (Interleaves) information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for Fabry Perot VIPER (Interleaves) relevant GUI # elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_fabry_perot) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "FT-2D-IR": # Connect Start Measurement Button to FT-2D-IR experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.ft_2d_ir) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # FT-2D-IR information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for FT-2D-IR relevant GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_shutter) if self.comboBox_experiments.currentText() == "FT-VIPER": # Connect Start Measurement Button to FT-VIPER experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.ft_viper) # Connect Start Measurement Button to timer self.groupBox_exp.pushButton_toggle_meas.clicked.connect( lambda: self.update_values_timer.start(100) ) # Check save checkboxes because we usually want to save the # FT-2D-IR information self.groupBox_file.checkBox_file_save.setChecked(True) self.groupBox_file.checkBox_file_save_raw.setChecked(False) # Add for FT-2D-IR relevant GUI elements to gui activator self.gui_activator.add(self.groupBox_adc) self.gui_activator.add(self.tab_fpas) self.gui_activator.add(self.groupBox_chopper) self.gui_activator.add(self.groupBox_pi_control) self.gui_activator.add(self.groupBox_triax) self.gui_activator.add(self.groupBox_shutter) # * This signal and slot need to be connected in the END of this # * function # * Otherwise measurement will start and directly stop again. # Connect to signal such that the button changes to a stop # measurement button once it was clicked self.groupBox_exp.pushButton_toggle_meas.clicked.connect( self.set_to_stop_measurement )
[docs] def set_to_stop_measurement(self): # Change Start Button to Stop Button Remove slot to start # experiment self.groupBox_exp.pushButton_toggle_meas.clicked.disconnect() # and replace it with slot to stop experiment self.groupBox_exp.pushButton_toggle_meas.clicked.connect(self.stop) # Change text accordingly self.groupBox_exp.pushButton_toggle_meas.setText("STOP MEASUREMENT")
[docs] def create_SaveData(self, delays, pump_pixels=None): """ Creates an instance of SaveData to pass to an experiment with the parameters specified in the GUI. Always call this method before creating an instance of an experiment. Args: delays (ndarray): Delays in the experiment. If this is not applicable to experiment, pass None. pump_pixels (ndarray, optional): Pump pixels in the experiment. If this is not applicable to experiment, pass None. Defaults to None. Returns: SaveData: Instance of SaveData that is handed to an experiment. """ if self.groupBox_file.checkBox_file_save.isChecked(): # Get indicator whether raw data should be saved save_raw_data = self.groupBox_file.checkBox_file_save_raw.isChecked() # Instantiate saver object. This need to be a local variable! # If it is defined on a global scope or as an attribute, # data could be saved even if that is not required. saver = SaveData( self.groupBox_file.lineEdit_file_save_path.text(), self.groupBox_file.lineEdit_file_save_name.text(), self.username, delays=delays, pump_pixels=pump_pixels, raw_data=save_raw_data, ) # force update of setupinfo text self.widget_readmefile.fill_standard_fields() # "settings" contents must be updated automatically when # experiment counter increases "settings" content is shown # on the readme editor page, but cannot be modified there # "notes" is the content of the former readme editor window # and is *only* modified by the user, not by the software saver.save_readme( self.widget_readmefile.plainTextEdit_setupinfo.toPlainText(), "setupinfo", ) saver.save_readme( self.widget_readmefile.plainTextEdit_notes.toPlainText(), "notes" ) saver.save_hwconfig(hwconfigpath=os.path.dirname(self.hw_path), name="hwconfigxxx") return saver else: return None
[docs] def save_t_zero_to_json(self): """ Save new t zero of stage that is currently open/active on GUI to json file. """ # Get active stage active_stage = self.groupBox_pi_control.comboBox_pi_control.currentText() # Get new t_zero new_t_zero = float(self.groupBox_pi_control.lineEdit_pi_pos_mm.text()) # Navigate to pi instruments in json file pi_dict = self.hw.hardware_properties["pi instruments"] # Find the active stage in the (json) dictionary for controller in pi_dict: for stage in pi_dict[controller]["stages"]: if pi_dict[controller]["stages"][stage]["name"][0] == active_stage: # Change value in dictionary pi_dict[controller]["stages"][stage]["t zero"][0] = new_t_zero # Save / Overwrite json file with open(self.hw_path, "w") as fp: json.dump(self.hw.hardware_properties, fp, indent=4)
[docs] def collect_background(self): """ Collects background and saves it to path specified in json file. """ def run(self): logger.info("Collecting background data.") # Acquire data self.groupBox_adc.adc.read() # We save all the data (also from channels that are not # pixels) because this will make data processing easier in # the experiments background = np.average(self.groupBox_adc.adc.data, axis=1) self.background_handler.save_background(background) work = Worker(run, self) work.signals.started.connect(lambda: self.setDisabled(True)) work.signals.finished.connect(lambda: self.setEnabled(True)) self.threadpool.start(work)
[docs] def show_spectrum(self): # We pass None because the show spectrum experiment does not # incorporate delays. saver = self.create_SaveData(None) # Initialize Experiment self.experiment = ShowSpectrum( self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def show_signal_ir_pump(self): # We pass None because the show signal experiment does not # incorporate delays. saver = self.create_SaveData(None) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["Show Signal (IR-Pump)"]["chopper name"][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = ShowSignal( self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def show_signal_ir_pump_wobbler(self): # We pass None because the show signal experiment does not # incorporate delays. saver = self.create_SaveData(None) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["Show Signal (IR-Pump with Wobbler)"][ "chopper name" ][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = ShowSignalWobbler( self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, chopper_info, self.hw.wobbler.frequency, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def show_signal_vis_pump(self): # We pass None because the show signal experiment does not # incorporate delays. saver = self.create_SaveData(None) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["Show Signal (UV/VIS-Pump)"]["chopper name"][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = ShowSignal( self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def show_viper(self): # We pass None because the Show VIPER - colorful experiment # experiment does not incorporate delays. saver = self.create_SaveData(None) # Get names of choppers needed for this experiment and then get # chopper infos out of hardware properties file # -IR Chopper- ir_chopper_name = self.experiments["Show VIPER - colorful experiment"][ "ir chopper name" ][0] ir_chopper_info = self.hw.hardware_properties["chopper"][ir_chopper_name] # -UV/VIS Chopper- vis_chopper_name = self.experiments["Show VIPER - colorful experiment"][ "vis chopper name" ][0] vis_chopper_info = self.hw.hardware_properties["chopper"][vis_chopper_name] # Initialize Experiment self.experiment = ShowViper( self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, ir_chopper_info, vis_chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def show_viper_wobbler(self): # We pass None because the Show VIPER (Wobbler) experiment does # not incorporate delays. saver = self.create_SaveData(None) # Get names of choppers needed for this experiment and then get # chopper infos out of hardware properties file # -IR Chopper- ir_chopper_name = self.experiments["Show VIPER (Wobbler)"]["ir chopper name"][0] ir_chopper_info = self.hw.hardware_properties["chopper"][ir_chopper_name] # -UV/VIS Chopper- vis_chopper_name = self.experiments["Show VIPER (Wobbler)"]["vis chopper name"][ 0 ] vis_chopper_info = self.hw.hardware_properties["chopper"][vis_chopper_name] # Initialize Experiment self.experiment = ShowViperWobbler( self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, ir_chopper_info, vis_chopper_info, self.hw.wobbler.frequency, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def scan_t_zero_interleaves(self): # Scan t_zero for the currently active stage for this, figure # out currently active stage and load appropriate delay file active_stage = self.groupBox_pi_control.comboBox_pi_control.currentText() # Get appropriate path if "IR" in active_stage: delay_file_path = self.groupBox_file.lineEdit_file_ir.text() # Get name of chopper needed for this stage chopper_name = self.experiments["Scan t zero (Interleaves)"][ "ir chopper name" ][0] elif "UV/VIS" in active_stage: delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Get name of chopper needed for this stage chopper_name = self.experiments["Scan t zero (Interleaves)"][ "vis chopper name" ][0] elif "interferometer" in active_stage: logger.error( "Scan t zero is not available for this stage {}! Aborting.".format( active_stage ) ) self.setup_experiment() return # Load delay file try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for scan t zero.".format( delay_file_path ) ) self.setup_experiment() return # Get number of interleaves to measure if self.groupBox_exp.lineEdit_exp_interleave.text() == "": interleaves = 1 else: interleaves = int(self.groupBox_exp.lineEdit_exp_interleave.text()) # Initialize saver saver = self.create_SaveData(delays[:, 0]) # Get chopper info out of hardware properties file chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = ScanTZeroInterleaves( self.stackedWidget_plotting_pyqtgraph, delays, interleaves, self.groupBox_adc.adc, self.groupBox_pi_control.pi_stage[active_stage], self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def scan_t_zero_wobbler(self): # Scan t_zero for the currently active stage for this, figure # out currently active stage and load appropriate delay file active_stage = self.groupBox_pi_control.comboBox_pi_control.currentText() # Get appropriate path if "IR" in active_stage: delay_file_path = self.groupBox_file.lineEdit_file_ir.text() # Get name of chopper needed for this stage chopper_name = self.experiments["Scan t zero (Interleaves)"][ "ir chopper name" ][0] elif "UV/VIS" in active_stage: delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Get name of chopper needed for this stage chopper_name = self.experiments["Scan t zero (Interleaves)"][ "vis chopper name" ][0] elif "interferometer" in active_stage: logger.error( "Scan t zero is not available for this stage {}! Aborting.".format( active_stage ) ) self.setup_experiment() return # Load delay file try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for scan t zero.".format( delay_file_path ) ) self.setup_experiment() return # Initialize saver saver = self.create_SaveData(delays[:, 0]) # Get chopper info out of hardware properties file chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = ScanTZeroWobbler( self.stackedWidget_plotting_pyqtgraph, delays, self.groupBox_adc.adc, self.groupBox_pi_control.pi_stage[active_stage], self.prl, chopper_info, self.hw.wobbler.frequency, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def show_wobbler_states(self): # We pass None because the show wobbler experiment does not # incorporate delays. saver = self.create_SaveData(None) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["Show Wobbler States"]["chopper name"][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = ShowWobblerStates( self.hw.wobbler.frequency, self.stackedWidget_plotting_pyqtgraph, self.groupBox_adc.adc, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def ft_2d_ir(self): # Load delay file delay_file_path = self.groupBox_file.lineEdit_file_ir.text() try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for FT-2D-IR.".format( delay_file_path ) ) self.setup_experiment() return # Initialize saver saver = self.create_SaveData(delays[:, 0]) # Initialize wavegen try: coherence_time = float( self.groupBox_pi_control.lineEdit_pi_wave_coherence.text() ) frequency = float( self.groupBox_pi_control.lineEdit_pi_wave_frequency.text() ) speed_up_down = float( self.groupBox_pi_control.lineEdit_pi_wave_speed_up_down.text() ) overshoot_factor = float( self.groupBox_pi_control.lineEdit_pi_overshoot_factor.text() ) self.groupBox_pi_control.pi_stage[ "interferometer stage" ].setup_coherence_time_scan( coherence_time, frequency, speed_up_down, overshoot_factor=overshoot_factor, ) except Exception: logger.error( "Wavegeneration for interferometer stage could not be initialized. Aborting." ) self.setup_experiment() return # Initialize Experiment self.experiment = Ft2dIr( self.stackedWidget_plotting_pyqtgraph, delays, self.groupBox_adc.adc, self.groupBox_pi_control.pi_stage["IR delay stage"], self.groupBox_pi_control.pi_stage["interferometer stage"], self.interferometer_counter, self.prl, self.hw.he_ne_laser.wavelength, self.hw.wobbler.frequency, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def ft_viper(self): # Fourier Transform VIPER Get stages ir_stage = self.groupBox_pi_control.pi_stage["IR delay stage"] vis_stage = self.groupBox_pi_control.pi_stage["UV/VIS delay stage"] # Load appropriate delay files ir_delay_file_path = self.groupBox_file.lineEdit_file_ir.text() vis_delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Load IR delay file try: ir_delays = np.loadtxt(ir_delay_file_path) except Exception: logger.error( "IR delay file {} could not be loaded for FT-VIPER.".format( ir_delay_file_path ) ) self.setup_experiment() return # Load UV/VIS delay file try: vis_delays = np.loadtxt(vis_delay_file_path) except Exception: logger.error( "UV/VIS delay file {} could not be loaded for FT-VIPER.".format( vis_delay_file_path ) ) self.setup_experiment() return # Check whether both delay files have same amount of entries. # Otherwise the experiment cannot run (both delay stages are # moved at the same time) if ir_delays.shape[0] != vis_delays.shape[0]: logger.error( "UV/VIS and IR delay file do not have the same length. Aborting. (FT-VIPER)" ) return # Initialize saver saver = self.create_SaveData(ir_delays[:, 0]) # -UV/VIS Chopper- vis_chopper_name = self.experiments["FT-VIPER"]["vis chopper name"][0] vis_chopper_info = self.hw.hardware_properties["chopper"][vis_chopper_name] # Get VIS Shutter to block VIS Pump during movement of stages vis_shutter = self.groupBox_shutter.shutter["UV-VIS Shutter"] # Initialize wavegen for interferometer try: coherence_time = float( self.groupBox_pi_control.lineEdit_pi_wave_coherence.text() ) frequency = float( self.groupBox_pi_control.lineEdit_pi_wave_frequency.text() ) speed_up_down = float( self.groupBox_pi_control.lineEdit_pi_wave_speed_up_down.text() ) overshoot_factor = float( self.groupBox_pi_control.lineEdit_pi_overshoot_factor.text() ) self.groupBox_pi_control.pi_stage[ "interferometer stage" ].setup_coherence_time_scan( coherence_time, frequency, speed_up_down, overshoot_factor=overshoot_factor, ) except Exception: logger.error( "Wavegeneration for interferometer stage could not be initialized. Aborting." ) self.setup_experiment() return # Initialize Experiment self.experiment = FtViper( self.stackedWidget_plotting_pyqtgraph, vis_delays, ir_delays, self.groupBox_adc.adc, vis_stage, ir_stage, self.groupBox_pi_control.pi_stage["interferometer stage"], self.interferometer_counter, self.prl, vis_chopper_info, self.hw.he_ne_laser.wavelength, self.hw.wobbler.frequency, self.background_handler, self.groupBox_triax.triax, self.groupBox_newport.mu_screw, vis_shutter, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def vis_pump_ir_probe(self): # UV/VIS-Pump IR-Probe stage and shutter stage = self.groupBox_pi_control.pi_stage["UV/VIS delay stage"] shutter = self.groupBox_shutter.shutter["UV-VIS Shutter"] delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Load delay file try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for UV/VIS-Pump IR-Probe.".format( delay_file_path ) ) self.setup_experiment() return # Initialize saver saver = self.create_SaveData(delays[:, 0]) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["UV/VIS-Pump IR-Probe"]["chopper name"][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = VisPumpIrProbe( self.stackedWidget_plotting_pyqtgraph, delays, self.groupBox_adc.adc, stage, shutter, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def vis_pump_ir_probe_split_sample(self): # UV/VIS-Pump IR-Probe (split sample) stage and shutter stage = self.groupBox_pi_control.pi_stage["UV/VIS delay stage"] shutter = self.groupBox_shutter.shutter["UV-VIS Shutter"] delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Load delay file try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for UV/VIS-Pump IR-Probe.".format( delay_file_path ) ) self.setup_experiment() return # Load positions positions = np.zeros(2) # Lower bound corresponds to position 0 This should contain the # background sample positions[0] = self.groupBox_newport.mu_screw.lower_bound # Upper bound corresponds to position 1 This should contain the # actual sample of interest positions[1] = self.groupBox_newport.mu_screw.upper_bound # Initialize saver saver = self.create_SaveData(delays[:, 0]) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["UV/VIS-Pump IR-Probe (Split Sample)"][ "chopper name" ][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Initialize Experiment self.experiment = VisPumpIrProbeSplitSample( self.stackedWidget_plotting_pyqtgraph, delays, positions, self.groupBox_adc.adc, stage, self.groupBox_newport.mu_screw, shutter, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def bb_ir_pump_ir_probe_intl(self): # Broadband IR-Pump IR-Probe (Interleaves) for the currently # active stage for this, figure out currently active stage and # load appropriate delay file stage = self.groupBox_pi_control.pi_stage["IR delay stage"] delay_file_path = self.groupBox_file.lineEdit_file_ir.text() # Load delay file try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for Broadband IR-Pump IR-Probe (Interleaves).".format( delay_file_path ) ) self.setup_experiment() return # Initialize saver saver = self.create_SaveData(delays[:, 0]) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["Broadband IR-Pump IR-Probe (Interleaves)"][ "chopper name" ][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Get number of interleaves to measure if self.groupBox_exp.lineEdit_exp_interleave.text() == "": interleaves = 1 else: interleaves = int(self.groupBox_exp.lineEdit_exp_interleave.text()) # Initialize Experiment self.experiment = BBIrPumpIrProbeInterleaves( self.stackedWidget_plotting_pyqtgraph, delays, interleaves, self.groupBox_adc.adc, stage, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def fabry_perot_2d_ir_intl(self): # 2D-IR Fabry Perot (Interleaves) for the currently active stage # for this, figure out currently active stage and load # appropriate delay file stage = self.groupBox_pi_control.pi_stage["IR delay stage"] shutter = self.groupBox_shutter.shutter["IR Shutter"] delay_file_path = self.groupBox_file.lineEdit_file_ir.text() # Load delay file try: delays = np.loadtxt(delay_file_path) except Exception: logger.error( "Delay file {} could not be loaded for 2D-IR Fabry Perot (Interleaves).".format( delay_file_path ) ) self.setup_experiment() return pump_pixel_path = self.groupBox_file.lineEdit_file_fp.text() # Load Fabry Perot pump pixel file try: pump_pixels = np.loadtxt(pump_pixel_path) except Exception: logger.error( "Pump pixel file {} could not be loaded for 2D-IR Fabry Perot (Interleaves).".format( pump_pixel_path ) ) self.setup_experiment() return # Initialize saver saver = self.create_SaveData(delays[:, 0], pump_pixels=pump_pixels[:, 0]) # Get name of chopper needed for this experiment and then get # chopper info out of hardware properties file chopper_name = self.experiments["2D-IR Fabry Perot (Interleaves)"][ "chopper name" ][0] chopper_info = self.hw.hardware_properties["chopper"][chopper_name] # Get number of interleaves to measure if self.groupBox_exp.lineEdit_exp_interleave.text() == "": interleaves = 1 else: interleaves = int(self.groupBox_exp.lineEdit_exp_interleave.text()) # Initialize Experiment self.experiment = FabryPerot2dIrInterleaves( self.stackedWidget_plotting_pyqtgraph, delays, pump_pixels, interleaves, self.groupBox_adc.adc, stage, self.prl, chopper_info, self.background_handler, self.groupBox_triax.triax, self.groupBox_fabry_perot.fabry_perot, shutter, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def bb_viper_intl(self): # Broadband VIPER (Interleaves) Get stages ir_stage = self.groupBox_pi_control.pi_stage["IR delay stage"] vis_stage = self.groupBox_pi_control.pi_stage["UV/VIS delay stage"] # Load appropriate delay files ir_delay_file_path = self.groupBox_file.lineEdit_file_ir.text() vis_delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Load IR delay file try: ir_delays = np.loadtxt(ir_delay_file_path) except Exception: logger.error( "IR delay file {} could not be loaded for Broadband VIPER (Interleaves).".format( ir_delay_file_path ) ) self.setup_experiment() return # Load UV/VIS delay file try: vis_delays = np.loadtxt(vis_delay_file_path) except Exception: logger.error( "UV/VIS delay file {} could not be loaded for Broadband VIPER (Interleaves).".format( vis_delay_file_path ) ) self.setup_experiment() return # Check whether both delay files have same amount of entries. # Otherwise the experiment cannot run (both delay stages are # moved at the same time) if ir_delays.shape[0] != vis_delays.shape[0]: logger.error( "UV/VIS and IR delay file do not have the same length. Aborting. (Broadband VIPER (Interleaves))" ) return # Initialize saver saver = self.create_SaveData(ir_delays[:, 0]) # Get VIS Shutter to block VIS Pump during movement of stages vis_shutter = self.groupBox_shutter.shutter["UV-VIS Shutter"] # Get number of interleaves to measure if self.groupBox_exp.lineEdit_exp_interleave.text() == "": interleaves = 1 else: interleaves = int(self.groupBox_exp.lineEdit_exp_interleave.text()) # Get names of choppers needed for this experiment and then get # chopper infos out of hardware properties file # -IR Chopper- ir_chopper_name = self.experiments["Broadband VIPER (Interleaves)"][ "ir chopper name" ][0] ir_chopper_info = self.hw.hardware_properties["chopper"][ir_chopper_name] # -UV/VIS Chopper- vis_chopper_name = self.experiments["Broadband VIPER (Interleaves)"][ "vis chopper name" ][0] vis_chopper_info = self.hw.hardware_properties["chopper"][vis_chopper_name] # Initialize Experiment self.experiment = BbViperInterleaves( self.stackedWidget_plotting_pyqtgraph, vis_delays, ir_delays, interleaves, self.groupBox_adc.adc, vis_stage, ir_stage, self.prl, vis_chopper_info, ir_chopper_info, self.background_handler, self.groupBox_triax.triax, self.groupBox_newport.mu_screw, vis_shutter, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def bb_viper_wobbler(self): # Broadband VIPER (Wobbler) Get stages ir_stage = self.groupBox_pi_control.pi_stage["IR delay stage"] vis_stage = self.groupBox_pi_control.pi_stage["UV/VIS delay stage"] # Load appropriate delay files ir_delay_file_path = self.groupBox_file.lineEdit_file_ir.text() vis_delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Load IR delay file try: ir_delays = np.loadtxt(ir_delay_file_path) except Exception: logger.error( "IR delay file {} could not be loaded for Broadband VIPER (Wobbler).".format( ir_delay_file_path ) ) self.setup_experiment() return # Load UV/VIS delay file try: vis_delays = np.loadtxt(vis_delay_file_path) except Exception: logger.error( "UV/VIS delay file {} could not be loaded for Broadband VIPER (Wobbler).".format( vis_delay_file_path ) ) self.setup_experiment() return # Check whether both delay files have same amount of entries. # Otherwise the experiment cannot run (both delay stages are # moved at the same time) if ir_delays.shape[0] != vis_delays.shape[0]: logger.error( "UV/VIS and IR delay file do not have the same length. Aborting. (Broadband VIPER (Wobbler))" ) return # Initialize saver saver = self.create_SaveData(ir_delays[:, 0]) # Get VIS Shutter to block VIS Pump during movement of stages vis_shutter = self.groupBox_shutter.shutter["UV-VIS Shutter"] # Get names of choppers needed for this experiment and then get # chopper infos out of hardware properties file # -IR Chopper- ir_chopper_name = self.experiments["Broadband VIPER (Wobbler)"][ "ir chopper name" ][0] ir_chopper_info = self.hw.hardware_properties["chopper"][ir_chopper_name] # -UV/VIS Chopper- vis_chopper_name = self.experiments["Broadband VIPER (Wobbler)"][ "vis chopper name" ][0] vis_chopper_info = self.hw.hardware_properties["chopper"][vis_chopper_name] # Initialize Experiment self.experiment = BbViperWobbler( self.stackedWidget_plotting_pyqtgraph, vis_delays, ir_delays, self.groupBox_adc.adc, vis_stage, ir_stage, self.prl, vis_chopper_info, ir_chopper_info, self.hw.wobbler.frequency, self.background_handler, self.groupBox_triax.triax, self.groupBox_newport.mu_screw, vis_shutter, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def fabry_perot_viper_intl(self): # Broadband VIPER (Interleaves) Get stages ir_stage = self.groupBox_pi_control.pi_stage["IR delay stage"] vis_stage = self.groupBox_pi_control.pi_stage["UV/VIS delay stage"] # Load appropriate delay files ir_delay_file_path = self.groupBox_file.lineEdit_file_ir.text() vis_delay_file_path = self.groupBox_file.lineEdit_file_uv.text() # Load IR delay file try: ir_delays = np.loadtxt(ir_delay_file_path) except Exception: logger.error( "IR delay file {} could not be loaded for Fabry Perot VIPER (Interleaves).".format( ir_delay_file_path ) ) self.setup_experiment() return # Load UV/VIS delay file try: vis_delays = np.loadtxt(vis_delay_file_path) except Exception: logger.error( "UV/VIS delay file {} could not be loaded for Fabry Perot VIPER (Interleaves).".format( vis_delay_file_path ) ) self.setup_experiment() return # Check whether both delay files have same amount of entries. # Otherwise the experiment cannot run (both delay stages are # moved at the same time) if ir_delays.shape[0] != vis_delays.shape[0]: logger.error( "UV/VIS and IR delay file do not have the same length. Aborting. (Fabry Perot VIPER (Interleaves))" ) return # Load pump pixels file pump_pixel_path = self.groupBox_file.lineEdit_file_fp.text() # Load Fabry Perot pump pixel file try: pump_pixels = np.loadtxt(pump_pixel_path) except Exception: logger.error( "Pump pixel file {} could not be loaded for Fabry Perot VIPER (Interleaves).".format( pump_pixel_path ) ) self.setup_experiment() return # Initialize saver saver = self.create_SaveData(ir_delays[:, 0], pump_pixels=pump_pixels[:, 0]) # Get VIS Shutter to block VIS Pump during movement of stages vis_shutter = self.groupBox_shutter.shutter["UV-VIS Shutter"] # Get IR Shutter to let IR Pump light fall on detector to tune # fabry perot ir_shutter = self.groupBox_shutter.shutter["IR Shutter"] # Get number of interleaves to measure if self.groupBox_exp.lineEdit_exp_interleave.text() == "": interleaves = 1 else: interleaves = int(self.groupBox_exp.lineEdit_exp_interleave.text()) # Get names of choppers needed for this experiment and then get # chopper infos out of hardware properties file # -IR Chopper- ir_chopper_name = self.experiments["Fabry Perot VIPER (Interleaves)"][ "ir chopper name" ][0] ir_chopper_info = self.hw.hardware_properties["chopper"][ir_chopper_name] # -UV/VIS Chopper- vis_chopper_name = self.experiments["Fabry Perot VIPER (Interleaves)"][ "vis chopper name" ][0] vis_chopper_info = self.hw.hardware_properties["chopper"][vis_chopper_name] # Initialize Experiment self.experiment = FabryPerotViperInterleaves( self.stackedWidget_plotting_pyqtgraph, vis_delays, ir_delays, pump_pixels, interleaves, self.groupBox_adc.adc, vis_stage, ir_stage, self.prl, vis_chopper_info, ir_chopper_info, self.background_handler, self.groupBox_triax.triax, self.groupBox_fabry_perot.fabry_perot, ir_shutter, self.groupBox_newport.mu_screw, vis_shutter, self.info_queue, saver, ) # Start experiment # Start processes and threads self.experiment.start() # Show pyqtgraph in stacked widget self.stackedWidget_plotting.setCurrentIndex(1) # Deactivate certain elements of GUI on start self.gui_activator.toggle_activation(False)
[docs] def stop(self): def run(): # Tell acquisition to stop self.experiment.acquisition.shutdown() # Wait for all processing to complete # self.experiment.secondary_processing.join() self.experiment.acquisition.join() #!!! work = Worker(run) # Hinder people from smashing the stop button work.signals.started.connect( lambda: self.groupBox_exp.pushButton_toggle_meas.setDisabled(True) ) # Re-enable button once acquisition was stopped work.signals.finished.connect( lambda: self.groupBox_exp.pushButton_toggle_meas.setEnabled(True) ) # Re-enable GUI elements work.signals.finished.connect( self.gui_activator.signals.experiment_finished.emit ) # Update values on GUI work.signals.finished.connect(self.update_values) # Stop the update values QTimer work.signals.finished.connect(self.update_values_timer.stop) # Reset start button functionality. work.signals.finished.connect(self.setup_experiment) self.threadpool.start(work)
[docs] def update_values(self): self.groupBox_pi_control.update_values() self.groupBox_adc.update_values() self.groupBox_fabry_perot.update_values() self.groupBox_triax.update_values() self.groupBox_shutter.update_values() self.groupBox_polarizer.update_values() self.groupBox_newport.update_values()
[docs] def update_experiment_info(self): def run(self): while True: data_container = self.info_queue.get() # Break out of loop once acquisition was stopped if type(data_container) == str: if data_container == "stop": break # EXPERIMENT INFO # Extract information of which scan is processed etc and # transform it to strings if "scan index" in data_container: scan_idx = str(data_container["scan index"]) else: # If experiment does not use any delay clear delay # lineEdit scan_idx = "" if "delay index" in data_container: delay_idx = str(data_container["delay index"]) else: # If experiment does not use any delay clear delay # lineEdit delay_idx = "" if "interleave index" in data_container: interleave_idx = str(data_container["interleave index"]) else: # If experiment does not use any delay clear delay # lineEdit interleave_idx = "" # Emit signals that contain corresponding data self.groupBox_exp.signals.new_scan.emit(scan_idx) self.groupBox_exp.signals.new_delay.emit(delay_idx) self.groupBox_exp.signals.new_interleave.emit(interleave_idx) # STATISTICS # Get the pixel that was selected in GUI try: selected_pixel = int( self.groupBox_stats.lineEdit_stats_pixel.text() ) except Exception: selected_pixel = self.hw.mct_array.default_pixel # Check whether selected pixel is out of range Set to # highest possible pixel if self.hw.mct_array.number_of_pixels <= selected_pixel: selected_pixel = self.hw.mct_array.number_of_pixels - 1 # Set text in lineEdit self.groupBox_stats.lineEdit_stats_pixel.setText( str(selected_pixel) ) # Extract the statistical information for the pixel that # was selected in GUI and transform to string. (This # needs to be done because the corresponding signal, as # well as the lineEdit only accept strings) avg_intensity = "{:.4e}".format( data_container["average intensity"][selected_pixel] ) std_intensity = "{:.4e}".format( data_container["std intensity"][selected_pixel] ) # Extract the statistical information over all pixel and # states (the states depend on the underlying # experiment) and transform to string. (This needs to be # done because the corresponding signal, as well as the # lineEdit only accept strings) In some cases the # selected pixel index will be out ouf range for the # arrays (because they are generally half the number of # total pixels) # - in that case divide by two if self.hw.mct_array.number_of_pixels_per_row <= selected_pixel: selected_pixel = selected_pixel // 2 # Get wavenumber of selected pixel current_wavenumber = "{:.4e}".format( data_container["probe axis"][selected_pixel] ) # Average over all states' average relative intensity mean_state_intensity = "{:.4e}".format( data_container["mean state intensity"][selected_pixel] ) # Average over all states' standard deviation mean_state_std = "{:.4e}".format( data_container["mean state std"][selected_pixel] ) # Extract the statistical information concerning the # shot to shot signal - if it can and was calculated for # the experiment if "s2s signal amplitude" in data_container: signal_amplitude = "{:.4e}".format( data_container["s2s signal amplitude"] ) else: signal_amplitude = "" if "s2s signal average std" in data_container: avg_std_signal = "{:.4e}".format( data_container["s2s signal average std"] ) else: avg_std_signal = "" # Emit signals that contain corresponding data self.groupBox_stats.signals.new_mean_intensity.emit(avg_intensity) self.groupBox_stats.signals.new_std_intensity.emit(std_intensity) self.groupBox_stats.signals.new_mean_state_intensity.emit( mean_state_intensity ) self.groupBox_stats.signals.new_mean_state_std.emit(mean_state_std) self.groupBox_stats.signals.new_signal_amplitude.emit(signal_amplitude) self.groupBox_stats.signals.new_signal_std.emit(avg_std_signal) self.groupBox_stats.signals.new_wavenumber.emit(current_wavenumber) work = Worker(run, self) self.threadpool.start(work)
[docs]class GUIActivation:
[docs] class Signals(QObject): experiment_finished = pyqtSignal()
def __init__(self): self.signals = self.Signals() self.gui_elements = {} self.signals.experiment_finished.connect(lambda: self.toggle_activation(True))
[docs] def add(self, gui_element): self.gui_elements[gui_element] = gui_element.isEnabled()
[docs] def toggle_activation(self, toggle): """ Toggles the deactivation/ reactivation of the GUI elements that should not be accessed during the routine. Args: toggle (bool): True to enable. False to disable. """ for gui_element, was_enabled in self.gui_elements.items(): # Only reactive elements on GUI that were # active before if was_enabled: gui_element.setEnabled(toggle)
[docs]def main(hw_path: str, username: str): hw = HardwareProperties(hw_path) with ExitStack() as stack: # ------------------------------------------------------------ # ANALOG TO DIGITAL CONVERTER if hasattr(hw, "adc"): # Add to context manager adc = stack.enter_context( ADC( hw.adc.device_name, hw.adc.input_configuration_path, hw.adc.samples_to_acquire, hw.adc.trigger_source, hw.adc.sampling_rate, hw.adc.laser_frequency, ) ) else: adc = None # ------------------------------------------------------------ #! This is better done iteratively # ------------------------------------------------------------ # STAGES FROM PI if hasattr(hw, "pi_instruments"): # Initialize dictionaries to hand over pi_controller = {} pi_stage = {} # DELAY CONTROLLER ---------------------------------------- if hasattr(hw.pi_instruments, "delay_stage_controller"): # Shorten name for convenience delay_controller = hw.pi_instruments.delay_stage_controller # Add to context manager pi_controller[delay_controller.name] = stack.enter_context( PiController( delay_controller.model, delay_controller.stage_names, pci_board_number=delay_controller.pci_board_number, name=delay_controller.name, ) ) # DELAY STAGES ---------------------------------------- # IR if hasattr(delay_controller.stages, "ir_delay_stage"): # Shorten name for convenience ir_stage = delay_controller.stages.ir_delay_stage # Add to context manager pi_stage[ir_stage.name] = stack.enter_context( PiStage( pi_controller[delay_controller.name], ir_stage.axis, ir_stage.t_zero, ir_stage.direction, ir_stage.path_factor, ir_stage.initial_velocity, name=ir_stage.name, ) ) # UV / VIS if hasattr(delay_controller.stages, "vis_delay_stage"): # Shorten name for convenience vis_stage = delay_controller.stages.vis_delay_stage # Add to context manager pi_stage[vis_stage.name] = stack.enter_context( PiStage( pi_controller[delay_controller.name], vis_stage.axis, vis_stage.t_zero, vis_stage.direction, vis_stage.path_factor, vis_stage.initial_velocity, name=vis_stage.name, ) ) # ------------------------------------------------------ # ---------------------------------------------------------- # INTERFEROMETER CONTROLLER --------------------------------- if hasattr(hw.pi_instruments, "interferometer_controller"): # Shorten name for convenience interferometer_controller = hw.pi_instruments.interferometer_controller pi_controller[interferometer_controller.name] = stack.enter_context( PiController( interferometer_controller.model, interferometer_controller.stage_names, com_port=interferometer_controller.port, name=interferometer_controller.name, ) ) # INTERFEROMETER STAGE --------------------------------- if hasattr(interferometer_controller.stages, "interferometer_stage"): # Shorten name for convenience interferometer_stage = ( interferometer_controller.stages.interferometer_stage ) # Add to context manager pi_stage[interferometer_stage.name] = stack.enter_context( PiStage( pi_controller[interferometer_controller.name], interferometer_stage.axis, interferometer_stage.t_zero, interferometer_stage.direction, interferometer_stage.path_factor, interferometer_stage.initial_velocity, name=interferometer_stage.name, ) ) # ------------------------------------------------------ # ---------------------------------------------------------- else: pi_controller = None pi_stage = None # -------------------------------------------------------------- # SPECTROMETER if hasattr(hw, "spectrometer"): # Add to context manager spectrometer = stack.enter_context( Spectrometer(hwconfig=hw, init=True) # Spectrometer( # port = hw.spectrometer.port, # turret = hw.spectrometer.active_turret, # tgratings = getattr(hw.spectrometer, hw.spectrometer.active_turret), # step_slit = hw.spectrometer.step_slit, # gamma = hw.spectrometer.gamma, # d = hw.spectrometer.d, # f = hw.spectrometer.focal_length, # init = True # ) ) else: spectrometer = None # ------------------------------------------------------------ # FPAS if hasattr(hw, "fpas"): # Add to context manager fpas = stack.enter_context( Fpas( port=hw.fpas.port, integration_time=hw.fpas.integration_time, integration_delay=hw.fpas.delay_time, json_path=hw.fpas.path, ) ) else: fpas = None # ------------------------------------------------------------ # Interferometer Counter Electronics if hasattr(hw, "interferometer_counter"): #! Initializing the Interferometer Counter requires #! an adc and the interferometer stage # Add to context manager interferometer_stage_name = ( hw.pi_instruments.interferometer_controller.stages.interferometer_stage.name ) interferometer_counter = stack.enter_context( InterferometerCounter( hw.interferometer_counter.port, pi_stage[interferometer_stage_name], adc, hw.interferometer_counter.config_path, name=hw.interferometer_counter.name, ) ) else: interferometer_counter = None # ------------------------------------------------------------ # Chopper if hasattr(hw, "chopper"): # Initialize dict chopper = {} # ------------------------------------------------- for att in dir(hw.chopper): # shorten variable names device = getattr(hw.chopper, att) if hasattr(device, "port"): # Add to context manager chopper[device.name] = stack.enter_context( Chopper(device.port, name=device.name) ) # ------------------------------------------------- else: chopper = None # ------------------------------------------------------------ # Load chopper voltage config for Chopper State Finder class # which is required for all "chopped" experiments if hasattr(hw.paths, "chopper_voltage_config"): csf = CSF(getattr(hw.paths, "chopper_voltage_config")) else: csf = None # Shutter if hasattr(hw, "shutter"): # Initialize dict shutter = {} # ------------------------------------------------- for att in dir(hw.shutter): # shorten variable names device = getattr(hw.shutter, att) if hasattr(device, "device_name"): # Add to context manager shutter[device.name] = stack.enter_context( Shutter( device.device_name, device.channel, waiting_time=device.waiting_time, default_position=device.default_position, open_electrical_state=device.open_electrical_state, name=device.name, ) ) # ------------------------------------------------- else: shutter = None # ------------------------------------------------------------ # Polarizer if hasattr(hw, "polarizer"): # Initialize dict polarizer = {} # ------------------------------------------------- for att in dir(hw.polarizer): # shorten variable names device = getattr(hw.polarizer, att) if hasattr(device, "device_name"): # Add to context manager shutter[device.name] = stack.enter_context( Shutter( device.device_name, device.channel, waiting_time=device.waiting_time, default_position=device.default_position, open_electrical_state=device.open_electrical_state, name=device.name, ) ) else: polarizer = None # ------------------------------------------------------------ # # Micrometer Screw if hasattr(hw, "micrometer_screw"): # Add to context manager mu_screw = stack.enter_context( MicrometerScrew( port=hw.micrometer_screw.port, reference_time=hw.micrometer_screw.reference_time, lower_bound=hw.micrometer_screw.lower_bound, upper_bound=hw.micrometer_screw.upper_bound, ) ) else: mu_screw = None # ------------------------------------------------------------ # Pixel Response Linearization for Fabry Perot functionality if hasattr(hw.paths, "pixel_linearization"): prl = PRL(getattr(hw.paths, "pixel_linearization")) else: prl = None # ------------------------------------------------------------ # Fabry Perot if hasattr(hw, "fabry_perot"): # Add to context manager fabry_perot = stack.enter_context( FabryPerot( hw.fabry_perot.device_name, hw.fabry_perot.channel, hw.fabry_perot.init_voltage, hw.fabry_perot.voltage_range, adc, shutter[hw.shutter.ir_shutter.name], spectrometer, hw, prl, name=hw.fabry_perot.name, ) ) else: fabry_perot = None # ------------------------------------------------------------ app = QtWidgets.QApplication(sys.argv) app.setStyle("Fusion") window = MainWindow( hw, hw_path, username=username, adc=adc, pi_stage=pi_stage, fpas=fpas, chopper=chopper, shutter=shutter, interferometer_counter=interferometer_counter, spectrometer=spectrometer, mu_screw=mu_screw, prl=prl, csf=csf, fabry_perot=fabry_perot, ) window.showMaximized() app.exec()
# ---------------------------- Testing if __name__ == "__main__": # Change directory to parent dir of this file os.chdir(parentdir) # Logger Settings import logging import logging.config logging.config.fileConfig("logging.conf") logger = logging.getLogger(__name__) logger.info("Logging started from main") hw_path = "./hardware_config_files/i-lab_hardware_properties.json" username = "Tenshinhan" main(hw_path, username)