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)