From ea8d24cd117d6c116182a066bb15a638d2ff38b7 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 16:22:02 +1100 Subject: [PATCH 01/18] [BUG] fix build version number bug --- pyproject.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 249dc95..97c4099 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = [ - "setuptools>=42", - "wheel" -] +requires = ["wheel", "setuptools>=45", "setuptools_scm[toml]>=6.2"] build-backend = "setuptools.build_meta" +[tool.setuptools_scm] +write_to = "juno/_version.py" + [project] name = "juno" authors = [ @@ -12,7 +12,7 @@ authors = [ {name = "Patrick Cleeve", email = "Patrick.Cleeve@monash.edu"} ] readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.9" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", From b8049cb0faa3c3597a36d8ac1984478a862f034e Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 16:55:08 +1100 Subject: [PATCH 02/18] [BUG] Separation of simulation setup visualisation and config Fixes #50 --- juno/ui/SimulationSetup.py | 49 ++++++++++++++++----- juno/ui/qtdesigner_files/SimulationSetup.py | 26 ++++++----- juno/ui/qtdesigner_files/SimulationSetup.ui | 45 +++++++++++-------- 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/juno/ui/SimulationSetup.py b/juno/ui/SimulationSetup.py index 062154b..1d43670 100644 --- a/juno/ui/SimulationSetup.py +++ b/juno/ui/SimulationSetup.py @@ -26,19 +26,19 @@ def __init__(self, viewer: napari.Viewer = None, parent_gui=None): self.statusBar = QtWidgets.QStatusBar() self.setStatusBar(self.statusBar) self.setWindowTitle("Simulation Setup") - self.viewer: napari.Viewer = viewer self.simulation_config = {} self.SAVE_FROM_PARAMETER_SWEEP = False self.input_widgets = [] + self._validated_simulation_config = False self.setup_connections() self.update_all_displays() - self.showNormal() + self._update_ui_components() def setup_connections(self): @@ -52,13 +52,30 @@ def setup_connections(self): ) self.pushButton_sim_beam.clicked.connect(self.load_beam_config) self.pushButton_setup_parameter_sweep.clicked.connect(self.setup_parameter_sweep) + self.pushButton_visualise_simulation.clicked.connect(self.visualise_simulation) # actions self.actionLoad_Configuration.triggered.connect(self.load_simulation_config) self.actionSave_Configuration.triggered.connect(self.save_simulation_config) - # off by default - self.actionSave_Configuration.setEnabled(False) + def _update_ui_components(self): + + # clear viewer + self.viewer.layers.clear() + + # enable parameter sweep + self.pushButton_setup_parameter_sweep.setVisible(self._validated_simulation_config) + self.pushButton_setup_parameter_sweep.setEnabled(self._validated_simulation_config) + + # enable saving + self.actionSave_Configuration.setEnabled(self._validated_simulation_config) + + # enable visualisation + self.label_visualisation_scale.setVisible(self._validated_simulation_config) + self.spinBox_visualisation_scale.setVisible(self._validated_simulation_config) + self.pushButton_visualise_simulation.setVisible(self._validated_simulation_config) + self.pushButton_visualise_simulation.setEnabled(self._validated_simulation_config) + def update_all_displays(self): @@ -162,6 +179,10 @@ def load_simulation_config(self): load_stage_config_widgets(config, self.input_widgets) self.SIMULATION_CONFIG_LOADED = True + # update ui + self._validated_simulation_config = False + self._update_ui_components() + def update_status(self, msg= "Generating Simulation Configuration..."): """update status within button press...""" napari.utils.notifications.show_info(msg) @@ -177,11 +198,11 @@ def generate_simulation_config(self): self.read_stage_input_values() validation._validate_simulation_config(self.simulation_config) - napari.utils.notifications.show_info(f"Valid Simulation Configuration. Plotting Setup...") - self.draw_simulation_stage_display() + napari.utils.notifications.show_info(f"Valid Simulation Configuration.") - self.pushButton_setup_parameter_sweep.setEnabled(True) - self.actionSave_Configuration.setEnabled(True) + # update ui + self._validated_simulation_config = True + self._update_ui_components() napari.utils.notifications.show_info(f"Generate Simulation Configuration Finished.") @@ -192,7 +213,11 @@ def generate_simulation_config(self): - def draw_simulation_stage_display(self): + def visualise_simulation(self): + + self.pushButton_visualise_simulation.setEnabled(False) + self.pushButton_visualise_simulation.setText("Visualising...") + self.pushButton_visualise_simulation.setStyleSheet("background-color: orange") # TODO: find a way to make the viewing of this much more performant pixel_size = self.simulation_config["sim_parameters"]["pixel_size"] @@ -221,6 +246,10 @@ def draw_simulation_stage_display(self): # reset pixel_size self.simulation_config["sim_parameters"]["pixel_size"] = pixel_size + self.pushButton_visualise_simulation.setEnabled(False) + self.pushButton_visualise_simulation.setText("Visualise Simulation") + self.pushButton_visualise_simulation.setStyleSheet("background-color: gray") + def read_stage_input_values(self): stage_configs = [] @@ -332,8 +361,6 @@ def load_beam_config(self): def update_stage_input_display(self): - print("updating stage display") - sim_num_stages = int(self.spinBox_sim_num_stages.value()) input_layout = QVBoxLayout() diff --git a/juno/ui/qtdesigner_files/SimulationSetup.py b/juno/ui/qtdesigner_files/SimulationSetup.py index 8ffef05..c218986 100644 --- a/juno/ui/qtdesigner_files/SimulationSetup.py +++ b/juno/ui/qtdesigner_files/SimulationSetup.py @@ -43,19 +43,11 @@ def setupUi(self, MainWindow): self.label.setFont(font) self.label.setObjectName("label") self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1) - self.label_visualisation_scale = QtWidgets.QLabel(self.frame_2) - self.label_visualisation_scale.setObjectName("label_visualisation_scale") - self.gridLayout_3.addWidget(self.label_visualisation_scale, 2, 0, 1, 1) - self.spinBox_visualisation_scale = QtWidgets.QSpinBox(self.frame_2) - self.spinBox_visualisation_scale.setMinimum(1) - self.spinBox_visualisation_scale.setMaximum(1000) - self.spinBox_visualisation_scale.setObjectName("spinBox_visualisation_scale") - self.gridLayout_3.addWidget(self.spinBox_visualisation_scale, 2, 1, 1, 1) self.scrollArea = QtWidgets.QScrollArea(self.frame_2) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 366, 707)) + self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 366, 678)) self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") self.gridLayout_5 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) self.gridLayout_5.setObjectName("gridLayout_5") @@ -95,7 +87,7 @@ def setupUi(self, MainWindow): self.scrollArea_stages.setWidgetResizable(True) self.scrollArea_stages.setObjectName("scrollArea_stages") self.scrollAreaWidgetContents = QtWidgets.QWidget() - self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 326, 184)) + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 326, 167)) self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") self.scrollArea_stages.setWidget(self.scrollAreaWidgetContents) self.gridLayout_4.addWidget(self.scrollArea_stages, 17, 0, 4, 2) @@ -171,6 +163,17 @@ def setupUi(self, MainWindow): self.pushButton_setup_parameter_sweep.setEnabled(False) self.pushButton_setup_parameter_sweep.setObjectName("pushButton_setup_parameter_sweep") self.gridLayout_3.addWidget(self.pushButton_setup_parameter_sweep, 4, 0, 1, 2) + self.pushButton_visualise_simulation = QtWidgets.QPushButton(self.frame_2) + self.pushButton_visualise_simulation.setObjectName("pushButton_visualise_simulation") + self.gridLayout_3.addWidget(self.pushButton_visualise_simulation, 7, 0, 1, 2) + self.label_visualisation_scale = QtWidgets.QLabel(self.frame_2) + self.label_visualisation_scale.setObjectName("label_visualisation_scale") + self.gridLayout_3.addWidget(self.label_visualisation_scale, 5, 0, 1, 1) + self.spinBox_visualisation_scale = QtWidgets.QSpinBox(self.frame_2) + self.spinBox_visualisation_scale.setMinimum(1) + self.spinBox_visualisation_scale.setMaximum(1000) + self.spinBox_visualisation_scale.setObjectName("spinBox_visualisation_scale") + self.gridLayout_3.addWidget(self.spinBox_visualisation_scale, 5, 1, 1, 1) self.gridLayout_2.addWidget(self.frame_2, 0, 0, 1, 1) self.gridLayout.addWidget(self.frame, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) @@ -207,7 +210,6 @@ def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label.setText(_translate("MainWindow", "Simulation Setup")) - self.label_visualisation_scale.setText(_translate("MainWindow", "Downscale Visualisation Resolution")) self.label_sim_wavelength.setText(_translate("MainWindow", "Simulation Wavelength (m)")) self.label_sim_amplitude.setText(_translate("MainWindow", "Simulation Amplitude")) self.label_stage_parameters_title.setText(_translate("MainWindow", "Stage Parameters")) @@ -229,6 +231,8 @@ def retranslateUi(self, MainWindow): self.label_2.setText(_translate("MainWindow", "Logging Directory")) self.pushButton_generate_simulation.setText(_translate("MainWindow", "Generate Simulation")) self.pushButton_setup_parameter_sweep.setText(_translate("MainWindow", "Setup Parameter Sweep")) + self.pushButton_visualise_simulation.setText(_translate("MainWindow", "Visualise Simulation")) + self.label_visualisation_scale.setText(_translate("MainWindow", "Downscale Visualisation Resolution")) self.menuFile.setTitle(_translate("MainWindow", "File")) self.actionLoad_Configuration.setText(_translate("MainWindow", "Load Configuration")) self.actionSave_Configuration.setText(_translate("MainWindow", "Save Configuration")) diff --git a/juno/ui/qtdesigner_files/SimulationSetup.ui b/juno/ui/qtdesigner_files/SimulationSetup.ui index 31cb417..d1d817c 100644 --- a/juno/ui/qtdesigner_files/SimulationSetup.ui +++ b/juno/ui/qtdesigner_files/SimulationSetup.ui @@ -74,23 +74,6 @@ - - - - Downscale Visualisation Resolution - - - - - - - 1 - - - 1000 - - - @@ -102,7 +85,7 @@ 0 0 366 - 707 + 678 @@ -196,7 +179,7 @@ 0 0 326 - 184 + 167 @@ -354,6 +337,30 @@ + + + + Visualise Simulation + + + + + + + Downscale Visualisation Resolution + + + + + + + 1 + + + 1000 + + + From bfa3290e762d6ad8b66adcc62adec1691cf05cf1 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 17:09:37 +1100 Subject: [PATCH 03/18] [UI] update ui layout to fit on screen --- juno/ui/SimulationSetup.py | 2 +- juno/ui/qtdesigner_files/SimulationSetup.py | 310 +++++----- juno/ui/qtdesigner_files/SimulationSetup.ui | 596 ++++++++++---------- 3 files changed, 453 insertions(+), 455 deletions(-) diff --git a/juno/ui/SimulationSetup.py b/juno/ui/SimulationSetup.py index 1d43670..48e1b23 100644 --- a/juno/ui/SimulationSetup.py +++ b/juno/ui/SimulationSetup.py @@ -137,7 +137,7 @@ def save_simulation_config(self): with open(sim_config_filename, "w") as f: yaml.safe_dump(self.simulation_config, f) - self.statusBar.showMessage(f"Simulation config saved to {sim_config_filename}") + napari.utils.notifications.show_info(f"Simulation config saved to {sim_config_filename}") def load_simulation_config(self): diff --git a/juno/ui/qtdesigner_files/SimulationSetup.py b/juno/ui/qtdesigner_files/SimulationSetup.py index c218986..8d0992d 100644 --- a/juno/ui/qtdesigner_files/SimulationSetup.py +++ b/juno/ui/qtdesigner_files/SimulationSetup.py @@ -19,163 +19,163 @@ def setupUi(self, MainWindow): self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.frame = QtWidgets.QFrame(self.centralwidget) - self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame.setObjectName("frame") - self.gridLayout_2 = QtWidgets.QGridLayout(self.frame) - self.gridLayout_2.setContentsMargins(0, 0, 0, 0) - self.gridLayout_2.setSpacing(0) - self.gridLayout_2.setObjectName("gridLayout_2") - self.frame_2 = QtWidgets.QFrame(self.frame) - self.frame_2.setMaximumSize(QtCore.QSize(16777215, 16777215)) - self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_2.setObjectName("frame_2") - self.gridLayout_3 = QtWidgets.QGridLayout(self.frame_2) - self.gridLayout_3.setObjectName("gridLayout_3") - self.label = QtWidgets.QLabel(self.frame_2) - self.label.setMaximumSize(QtCore.QSize(16777215, 200)) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(True) - font.setWeight(75) - self.label.setFont(font) - self.label.setObjectName("label") - self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1) - self.scrollArea = QtWidgets.QScrollArea(self.frame_2) - self.scrollArea.setWidgetResizable(True) - self.scrollArea.setObjectName("scrollArea") - self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() - self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 366, 678)) - self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") - self.gridLayout_5 = QtWidgets.QGridLayout(self.scrollAreaWidgetContents_2) - self.gridLayout_5.setObjectName("gridLayout_5") - self.frame_4 = QtWidgets.QFrame(self.scrollAreaWidgetContents_2) - self.frame_4.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.frame_4.setFrameShadow(QtWidgets.QFrame.Raised) - self.frame_4.setObjectName("frame_4") - self.gridLayout_4 = QtWidgets.QGridLayout(self.frame_4) - self.gridLayout_4.setObjectName("gridLayout_4") - self.label_sim_wavelength = QtWidgets.QLabel(self.frame_4) - self.label_sim_wavelength.setObjectName("label_sim_wavelength") - self.gridLayout_4.addWidget(self.label_sim_wavelength, 7, 0, 1, 1) - spacerItem = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) - self.gridLayout_4.addItem(spacerItem, 21, 0, 1, 2) - self.label_sim_amplitude = QtWidgets.QLabel(self.frame_4) + self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) + self.tabWidget.setObjectName("tabWidget") + self.tab_simulation = QtWidgets.QWidget() + self.tab_simulation.setObjectName("tab_simulation") + self.gridLayout_6 = QtWidgets.QGridLayout(self.tab_simulation) + self.gridLayout_6.setObjectName("gridLayout_6") + self.lineEdit_log_dir = QtWidgets.QLineEdit(self.tab_simulation) + self.lineEdit_log_dir.setObjectName("lineEdit_log_dir") + self.gridLayout_6.addWidget(self.lineEdit_log_dir, 8, 1, 1, 1) + self.label_sim_amplitude = QtWidgets.QLabel(self.tab_simulation) self.label_sim_amplitude.setObjectName("label_sim_amplitude") - self.gridLayout_4.addWidget(self.label_sim_amplitude, 8, 0, 1, 1) - self.label_stage_parameters_title = QtWidgets.QLabel(self.frame_4) + self.gridLayout_6.addWidget(self.label_sim_amplitude, 5, 0, 1, 1) + self.label_options_title = QtWidgets.QLabel(self.tab_simulation) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) - self.label_stage_parameters_title.setFont(font) - self.label_stage_parameters_title.setObjectName("label_stage_parameters_title") - self.gridLayout_4.addWidget(self.label_stage_parameters_title, 14, 0, 1, 1) - self.label_sim_width = QtWidgets.QLabel(self.frame_4) + self.label_options_title.setFont(font) + self.label_options_title.setObjectName("label_options_title") + self.gridLayout_6.addWidget(self.label_options_title, 7, 0, 1, 1) + self.label_sim_width = QtWidgets.QLabel(self.tab_simulation) self.label_sim_width.setObjectName("label_sim_width") - self.gridLayout_4.addWidget(self.label_sim_width, 5, 0, 1, 1) - self.spinBox_sim_num_stages = QtWidgets.QSpinBox(self.frame_4) - self.spinBox_sim_num_stages.setMinimum(1) - self.spinBox_sim_num_stages.setMaximum(10) - self.spinBox_sim_num_stages.setSingleStep(1) - self.spinBox_sim_num_stages.setObjectName("spinBox_sim_num_stages") - self.gridLayout_4.addWidget(self.spinBox_sim_num_stages, 15, 1, 1, 1) - self.scrollArea_stages = QtWidgets.QScrollArea(self.frame_4) - self.scrollArea_stages.setMinimumSize(QtCore.QSize(0, 0)) - self.scrollArea_stages.setWidgetResizable(True) - self.scrollArea_stages.setObjectName("scrollArea_stages") - self.scrollAreaWidgetContents = QtWidgets.QWidget() - self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 326, 167)) - self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") - self.scrollArea_stages.setWidget(self.scrollAreaWidgetContents) - self.gridLayout_4.addWidget(self.scrollArea_stages, 17, 0, 4, 2) - self.label_sim_param_title = QtWidgets.QLabel(self.frame_4) + self.gridLayout_6.addWidget(self.label_sim_width, 2, 0, 1, 1) + self.label_sim_param_title = QtWidgets.QLabel(self.tab_simulation) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.label_sim_param_title.setFont(font) self.label_sim_param_title.setObjectName("label_sim_param_title") - self.gridLayout_4.addWidget(self.label_sim_param_title, 0, 0, 1, 2) - self.pushButton_sim_beam = QtWidgets.QPushButton(self.frame_4) - self.pushButton_sim_beam.setObjectName("pushButton_sim_beam") - self.gridLayout_4.addWidget(self.pushButton_sim_beam, 9, 1, 1, 1) - self.label_sim_beam = QtWidgets.QLabel(self.frame_4) + self.gridLayout_6.addWidget(self.label_sim_param_title, 0, 0, 1, 1) + self.lineEdit_sim_name = QtWidgets.QLineEdit(self.tab_simulation) + self.lineEdit_sim_name.setObjectName("lineEdit_sim_name") + self.gridLayout_6.addWidget(self.lineEdit_sim_name, 9, 1, 1, 1) + self.label_sim_beam = QtWidgets.QLabel(self.tab_simulation) self.label_sim_beam.setObjectName("label_sim_beam") - self.gridLayout_4.addWidget(self.label_sim_beam, 9, 0, 1, 1) - self.label_options_title = QtWidgets.QLabel(self.frame_4) - font = QtGui.QFont() - font.setPointSize(10) - font.setBold(True) - font.setWeight(75) - self.label_options_title.setFont(font) - self.label_options_title.setObjectName("label_options_title") - self.gridLayout_4.addWidget(self.label_options_title, 10, 0, 1, 1) - self.lineEdit_pixel_size = QtWidgets.QLineEdit(self.frame_4) + self.gridLayout_6.addWidget(self.label_sim_beam, 6, 0, 1, 1) + self.lineEdit_pixel_size = QtWidgets.QLineEdit(self.tab_simulation) self.lineEdit_pixel_size.setObjectName("lineEdit_pixel_size") - self.gridLayout_4.addWidget(self.lineEdit_pixel_size, 3, 1, 1, 1) - self.checkBox_save_plot = QtWidgets.QCheckBox(self.frame_4) + self.gridLayout_6.addWidget(self.lineEdit_pixel_size, 1, 1, 1, 1) + self.label_sim_wavelength = QtWidgets.QLabel(self.tab_simulation) + self.label_sim_wavelength.setObjectName("label_sim_wavelength") + self.gridLayout_6.addWidget(self.label_sim_wavelength, 4, 0, 1, 1) + self.label_sim_name = QtWidgets.QLabel(self.tab_simulation) + self.label_sim_name.setObjectName("label_sim_name") + self.gridLayout_6.addWidget(self.label_sim_name, 9, 0, 1, 1) + self.pushButton_sim_beam = QtWidgets.QPushButton(self.tab_simulation) + self.pushButton_sim_beam.setObjectName("pushButton_sim_beam") + self.gridLayout_6.addWidget(self.pushButton_sim_beam, 6, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.tab_simulation) + self.label_2.setObjectName("label_2") + self.gridLayout_6.addWidget(self.label_2, 8, 0, 1, 1) + self.lineEdit_sim_width = QtWidgets.QLineEdit(self.tab_simulation) + self.lineEdit_sim_width.setObjectName("lineEdit_sim_width") + self.gridLayout_6.addWidget(self.lineEdit_sim_width, 2, 1, 1, 1) + self.checkBox_save_plot = QtWidgets.QCheckBox(self.tab_simulation) self.checkBox_save_plot.setChecked(True) self.checkBox_save_plot.setObjectName("checkBox_save_plot") - self.gridLayout_4.addWidget(self.checkBox_save_plot, 13, 1, 1, 1) - self.lineEdit_sim_amplitude = QtWidgets.QLineEdit(self.frame_4) - self.lineEdit_sim_amplitude.setObjectName("lineEdit_sim_amplitude") - self.gridLayout_4.addWidget(self.lineEdit_sim_amplitude, 8, 1, 1, 1) - self.lineEdit_sim_name = QtWidgets.QLineEdit(self.frame_4) - self.lineEdit_sim_name.setObjectName("lineEdit_sim_name") - self.gridLayout_4.addWidget(self.lineEdit_sim_name, 12, 1, 1, 1) - self.label_sim_height = QtWidgets.QLabel(self.frame_4) - self.label_sim_height.setObjectName("label_sim_height") - self.gridLayout_4.addWidget(self.label_sim_height, 6, 0, 1, 1) - self.label_pixel_size = QtWidgets.QLabel(self.frame_4) - self.label_pixel_size.setObjectName("label_pixel_size") - self.gridLayout_4.addWidget(self.label_pixel_size, 3, 0, 1, 1) - self.lineEdit_sim_height = QtWidgets.QLineEdit(self.frame_4) + self.gridLayout_6.addWidget(self.checkBox_save_plot, 10, 1, 1, 1) + self.lineEdit_sim_height = QtWidgets.QLineEdit(self.tab_simulation) self.lineEdit_sim_height.setObjectName("lineEdit_sim_height") - self.gridLayout_4.addWidget(self.lineEdit_sim_height, 6, 1, 1, 1) - self.label_sim_num_stages = QtWidgets.QLabel(self.frame_4) - self.label_sim_num_stages.setObjectName("label_sim_num_stages") - self.gridLayout_4.addWidget(self.label_sim_num_stages, 15, 0, 1, 1) - self.lineEdit_sim_wavelength = QtWidgets.QLineEdit(self.frame_4) + self.gridLayout_6.addWidget(self.lineEdit_sim_height, 3, 1, 1, 1) + self.label_pixel_size = QtWidgets.QLabel(self.tab_simulation) + self.label_pixel_size.setObjectName("label_pixel_size") + self.gridLayout_6.addWidget(self.label_pixel_size, 1, 0, 1, 1) + self.lineEdit_sim_wavelength = QtWidgets.QLineEdit(self.tab_simulation) self.lineEdit_sim_wavelength.setObjectName("lineEdit_sim_wavelength") - self.gridLayout_4.addWidget(self.lineEdit_sim_wavelength, 7, 1, 1, 1) - self.lineEdit_log_dir = QtWidgets.QLineEdit(self.frame_4) - self.lineEdit_log_dir.setObjectName("lineEdit_log_dir") - self.gridLayout_4.addWidget(self.lineEdit_log_dir, 11, 1, 1, 1) - self.lineEdit_sim_width = QtWidgets.QLineEdit(self.frame_4) - self.lineEdit_sim_width.setObjectName("lineEdit_sim_width") - self.gridLayout_4.addWidget(self.lineEdit_sim_width, 5, 1, 1, 1) - self.label_sim_name = QtWidgets.QLabel(self.frame_4) - self.label_sim_name.setObjectName("label_sim_name") - self.gridLayout_4.addWidget(self.label_sim_name, 12, 0, 1, 1) - self.label_2 = QtWidgets.QLabel(self.frame_4) - self.label_2.setObjectName("label_2") - self.gridLayout_4.addWidget(self.label_2, 11, 0, 1, 1) - self.gridLayout_5.addWidget(self.frame_4, 0, 0, 1, 1) - self.scrollArea.setWidget(self.scrollAreaWidgetContents_2) - self.gridLayout_3.addWidget(self.scrollArea, 1, 0, 1, 2) - self.pushButton_generate_simulation = QtWidgets.QPushButton(self.frame_2) - self.pushButton_generate_simulation.setObjectName("pushButton_generate_simulation") - self.gridLayout_3.addWidget(self.pushButton_generate_simulation, 3, 0, 1, 2) - self.pushButton_setup_parameter_sweep = QtWidgets.QPushButton(self.frame_2) - self.pushButton_setup_parameter_sweep.setEnabled(False) - self.pushButton_setup_parameter_sweep.setObjectName("pushButton_setup_parameter_sweep") - self.gridLayout_3.addWidget(self.pushButton_setup_parameter_sweep, 4, 0, 1, 2) - self.pushButton_visualise_simulation = QtWidgets.QPushButton(self.frame_2) - self.pushButton_visualise_simulation.setObjectName("pushButton_visualise_simulation") - self.gridLayout_3.addWidget(self.pushButton_visualise_simulation, 7, 0, 1, 2) - self.label_visualisation_scale = QtWidgets.QLabel(self.frame_2) - self.label_visualisation_scale.setObjectName("label_visualisation_scale") - self.gridLayout_3.addWidget(self.label_visualisation_scale, 5, 0, 1, 1) + self.gridLayout_6.addWidget(self.lineEdit_sim_wavelength, 4, 1, 1, 1) + self.label_sim_height = QtWidgets.QLabel(self.tab_simulation) + self.label_sim_height.setObjectName("label_sim_height") + self.gridLayout_6.addWidget(self.label_sim_height, 3, 0, 1, 1) + self.lineEdit_sim_amplitude = QtWidgets.QLineEdit(self.tab_simulation) + self.lineEdit_sim_amplitude.setObjectName("lineEdit_sim_amplitude") + self.gridLayout_6.addWidget(self.lineEdit_sim_amplitude, 5, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + self.gridLayout_6.addItem(spacerItem, 11, 0, 1, 2) + self.tabWidget.addTab(self.tab_simulation, "") + self.tab_stages = QtWidgets.QWidget() + self.tab_stages.setObjectName("tab_stages") + self.gridLayout_7 = QtWidgets.QGridLayout(self.tab_stages) + self.gridLayout_7.setObjectName("gridLayout_7") + self.label_sim_num_stages = QtWidgets.QLabel(self.tab_stages) + self.label_sim_num_stages.setObjectName("label_sim_num_stages") + self.gridLayout_7.addWidget(self.label_sim_num_stages, 1, 0, 1, 1) + self.spinBox_sim_num_stages = QtWidgets.QSpinBox(self.tab_stages) + self.spinBox_sim_num_stages.setMinimum(1) + self.spinBox_sim_num_stages.setMaximum(10) + self.spinBox_sim_num_stages.setSingleStep(1) + self.spinBox_sim_num_stages.setObjectName("spinBox_sim_num_stages") + self.gridLayout_7.addWidget(self.spinBox_sim_num_stages, 1, 1, 1, 1) + self.label_stage_parameters_title = QtWidgets.QLabel(self.tab_stages) + font = QtGui.QFont() + font.setPointSize(10) + font.setBold(True) + font.setWeight(75) + self.label_stage_parameters_title.setFont(font) + self.label_stage_parameters_title.setObjectName("label_stage_parameters_title") + self.gridLayout_7.addWidget(self.label_stage_parameters_title, 0, 0, 1, 1) + self.scrollArea_stages = QtWidgets.QScrollArea(self.tab_stages) + self.scrollArea_stages.setMinimumSize(QtCore.QSize(0, 0)) + self.scrollArea_stages.setWidgetResizable(True) + self.scrollArea_stages.setObjectName("scrollArea_stages") + self.scrollAreaWidgetContents = QtWidgets.QWidget() + self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 364, 141)) + self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") + self.scrollArea_stages.setWidget(self.scrollAreaWidgetContents) + self.gridLayout_7.addWidget(self.scrollArea_stages, 2, 0, 1, 2) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_7.addItem(spacerItem1, 3, 0, 1, 2) + self.tabWidget.addTab(self.tab_stages, "") + self.gridLayout.addWidget(self.tabWidget, 1, 0, 1, 1) + self.frame = QtWidgets.QFrame(self.centralwidget) + self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame.setObjectName("frame") + self.gridLayout_2 = QtWidgets.QGridLayout(self.frame) + self.gridLayout_2.setContentsMargins(0, 0, 0, 0) + self.gridLayout_2.setSpacing(0) + self.gridLayout_2.setObjectName("gridLayout_2") + self.frame_2 = QtWidgets.QFrame(self.frame) + self.frame_2.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame_2.setObjectName("frame_2") + self.gridLayout_3 = QtWidgets.QGridLayout(self.frame_2) + self.gridLayout_3.setObjectName("gridLayout_3") self.spinBox_visualisation_scale = QtWidgets.QSpinBox(self.frame_2) self.spinBox_visualisation_scale.setMinimum(1) self.spinBox_visualisation_scale.setMaximum(1000) self.spinBox_visualisation_scale.setObjectName("spinBox_visualisation_scale") - self.gridLayout_3.addWidget(self.spinBox_visualisation_scale, 5, 1, 1, 1) + self.gridLayout_3.addWidget(self.spinBox_visualisation_scale, 8, 1, 1, 1) + self.label_visualisation_scale = QtWidgets.QLabel(self.frame_2) + self.label_visualisation_scale.setObjectName("label_visualisation_scale") + self.gridLayout_3.addWidget(self.label_visualisation_scale, 8, 0, 1, 1) + self.pushButton_visualise_simulation = QtWidgets.QPushButton(self.frame_2) + self.pushButton_visualise_simulation.setObjectName("pushButton_visualise_simulation") + self.gridLayout_3.addWidget(self.pushButton_visualise_simulation, 9, 0, 1, 2) + self.pushButton_setup_parameter_sweep = QtWidgets.QPushButton(self.frame_2) + self.pushButton_setup_parameter_sweep.setEnabled(False) + self.pushButton_setup_parameter_sweep.setObjectName("pushButton_setup_parameter_sweep") + self.gridLayout_3.addWidget(self.pushButton_setup_parameter_sweep, 6, 0, 1, 2) + self.pushButton_generate_simulation = QtWidgets.QPushButton(self.frame_2) + self.pushButton_generate_simulation.setObjectName("pushButton_generate_simulation") + self.gridLayout_3.addWidget(self.pushButton_generate_simulation, 2, 0, 1, 2) self.gridLayout_2.addWidget(self.frame_2, 0, 0, 1, 1) - self.gridLayout.addWidget(self.frame, 0, 0, 1, 1) + self.gridLayout.addWidget(self.frame, 8, 0, 1, 1) + self.label = QtWidgets.QLabel(self.centralwidget) + self.label.setMaximumSize(QtCore.QSize(16777215, 200)) + font = QtGui.QFont() + font.setPointSize(16) + font.setBold(True) + font.setWeight(75) + self.label.setFont(font) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem2, 9, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 408, 21)) @@ -195,44 +195,38 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) + self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) - MainWindow.setTabOrder(self.lineEdit_pixel_size, self.lineEdit_sim_width) - MainWindow.setTabOrder(self.lineEdit_sim_width, self.lineEdit_sim_height) - MainWindow.setTabOrder(self.lineEdit_sim_height, self.lineEdit_sim_wavelength) - MainWindow.setTabOrder(self.lineEdit_sim_wavelength, self.lineEdit_sim_amplitude) - MainWindow.setTabOrder(self.lineEdit_sim_amplitude, self.pushButton_sim_beam) - MainWindow.setTabOrder(self.pushButton_sim_beam, self.lineEdit_log_dir) - MainWindow.setTabOrder(self.lineEdit_log_dir, self.checkBox_save_plot) - MainWindow.setTabOrder(self.checkBox_save_plot, self.spinBox_sim_num_stages) - MainWindow.setTabOrder(self.spinBox_sim_num_stages, self.scrollArea_stages) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.label.setText(_translate("MainWindow", "Simulation Setup")) - self.label_sim_wavelength.setText(_translate("MainWindow", "Simulation Wavelength (m)")) self.label_sim_amplitude.setText(_translate("MainWindow", "Simulation Amplitude")) - self.label_stage_parameters_title.setText(_translate("MainWindow", "Stage Parameters")) + self.label_options_title.setText(_translate("MainWindow", "Simulation Options")) self.label_sim_width.setText(_translate("MainWindow", "Simulation Width (m)")) self.label_sim_param_title.setText(_translate("MainWindow", "Simulation Parameters")) - self.pushButton_sim_beam.setText(_translate("MainWindow", "...")) self.label_sim_beam.setText(_translate("MainWindow", "Simulation Beam")) - self.label_options_title.setText(_translate("MainWindow", "Simulation Options")) self.lineEdit_pixel_size.setText(_translate("MainWindow", "1e-6")) + self.label_sim_wavelength.setText(_translate("MainWindow", "Simulation Wavelength (m)")) + self.label_sim_name.setText(_translate("MainWindow", "Simulation Name")) + self.pushButton_sim_beam.setText(_translate("MainWindow", "...")) + self.label_2.setText(_translate("MainWindow", "Logging Directory")) + self.lineEdit_sim_width.setText(_translate("MainWindow", "1000e-6")) self.checkBox_save_plot.setText(_translate("MainWindow", "Save Plots")) - self.lineEdit_sim_amplitude.setText(_translate("MainWindow", "1")) - self.label_sim_height.setText(_translate("MainWindow", "Simulation Height (m)")) - self.label_pixel_size.setText(_translate("MainWindow", "Pixel Size (m)")) self.lineEdit_sim_height.setText(_translate("MainWindow", "1000e-6")) - self.label_sim_num_stages.setText(_translate("MainWindow", "Number of Stages")) + self.label_pixel_size.setText(_translate("MainWindow", "Pixel Size (m)")) self.lineEdit_sim_wavelength.setText(_translate("MainWindow", "488.e-9")) - self.lineEdit_sim_width.setText(_translate("MainWindow", "1000e-6")) - self.label_sim_name.setText(_translate("MainWindow", "Simulation Name")) - self.label_2.setText(_translate("MainWindow", "Logging Directory")) - self.pushButton_generate_simulation.setText(_translate("MainWindow", "Generate Simulation")) - self.pushButton_setup_parameter_sweep.setText(_translate("MainWindow", "Setup Parameter Sweep")) + self.label_sim_height.setText(_translate("MainWindow", "Simulation Height (m)")) + self.lineEdit_sim_amplitude.setText(_translate("MainWindow", "1")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_simulation), _translate("MainWindow", "Simulation")) + self.label_sim_num_stages.setText(_translate("MainWindow", "Number of Stages")) + self.label_stage_parameters_title.setText(_translate("MainWindow", "Stage Parameters")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_stages), _translate("MainWindow", "Stages")) + self.label_visualisation_scale.setText(_translate("MainWindow", "Downscale Visualisation By")) self.pushButton_visualise_simulation.setText(_translate("MainWindow", "Visualise Simulation")) - self.label_visualisation_scale.setText(_translate("MainWindow", "Downscale Visualisation Resolution")) + self.pushButton_setup_parameter_sweep.setText(_translate("MainWindow", "Setup Parameter Sweep")) + self.pushButton_generate_simulation.setText(_translate("MainWindow", "Generate Simulation")) + self.label.setText(_translate("MainWindow", "Simulation Setup")) self.menuFile.setTitle(_translate("MainWindow", "File")) self.actionLoad_Configuration.setText(_translate("MainWindow", "Load Configuration")) self.actionSave_Configuration.setText(_translate("MainWindow", "Save Configuration")) diff --git a/juno/ui/qtdesigner_files/SimulationSetup.ui b/juno/ui/qtdesigner_files/SimulationSetup.ui index d1d817c..6d1d87b 100644 --- a/juno/ui/qtdesigner_files/SimulationSetup.ui +++ b/juno/ui/qtdesigner_files/SimulationSetup.ui @@ -15,7 +15,256 @@ - + + + + 0 + + + + Simulation + + + + + + + + + Simulation Amplitude + + + + + + + + 10 + 75 + true + + + + Simulation Options + + + + + + + Simulation Width (m) + + + + + + + + 10 + 75 + true + + + + Simulation Parameters + + + + + + + + + + Simulation Beam + + + + + + + 1e-6 + + + + + + + Simulation Wavelength (m) + + + + + + + Simulation Name + + + + + + + ... + + + + + + + Logging Directory + + + + + + + 1000e-6 + + + + + + + Save Plots + + + true + + + + + + + 1000e-6 + + + + + + + Pixel Size (m) + + + + + + + 488.e-9 + + + + + + + Simulation Height (m) + + + + + + + 1 + + + + + + + Qt::Vertical + + + QSizePolicy::Maximum + + + + 20 + 60 + + + + + + + + + Stages + + + + + + Number of Stages + + + + + + + 1 + + + 10 + + + 1 + + + + + + + + 10 + 75 + true + + + + Stage Parameters + + + + + + + + 0 + 0 + + + + true + + + + + 0 + 0 + 364 + 141 + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QFrame::StyledPanel @@ -54,280 +303,31 @@ QFrame::Raised - - - - - 16777215 - 200 - - - - - 16 - 75 - true - + + + + 1 - - Simulation Setup + + 1000 - - - - true + + + + Downscale Visualisation By - - - - 0 - 0 - 366 - 678 - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - Simulation Wavelength (m) - - - - - - - Qt::Vertical - - - QSizePolicy::Maximum - - - - 20 - 60 - - - - - - - - Simulation Amplitude - - - - - - - - 10 - 75 - true - - - - Stage Parameters - - - - - - - Simulation Width (m) - - - - - - - 1 - - - 10 - - - 1 - - - - - - - - 0 - 0 - - - - true - - - - - 0 - 0 - 326 - 167 - - - - - - - - - - 10 - 75 - true - - - - Simulation Parameters - - - - - - - ... - - - - - - - Simulation Beam - - - - - - - - 10 - 75 - true - - - - Simulation Options - - - - - - - 1e-6 - - - - - - - Save Plots - - - true - - - - - - - 1 - - - - - - - - - - Simulation Height (m) - - - - - - - Pixel Size (m) - - - - - - - 1000e-6 - - - - - - - Number of Stages - - - - - - - 488.e-9 - - - - - - - - - - 1000e-6 - - - - - - - Simulation Name - - - - - - - Logging Directory - - - - - - - - - - + + - Generate Simulation + Visualise Simulation - + false @@ -337,27 +337,10 @@ - - - - Visualise Simulation - - - - - + + - Downscale Visualisation Resolution - - - - - - - 1 - - - 1000 + Generate Simulation @@ -367,6 +350,39 @@ + + + + + 16777215 + 200 + + + + + 16 + 75 + true + + + + Simulation Setup + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -399,18 +415,6 @@ - - lineEdit_pixel_size - lineEdit_sim_width - lineEdit_sim_height - lineEdit_sim_wavelength - lineEdit_sim_amplitude - pushButton_sim_beam - lineEdit_log_dir - checkBox_save_plot - spinBox_sim_num_stages - scrollArea_stages - From 2f6588aa9e83e4fad39f21f8f1a262d0de79be0f Mon Sep 17 00:00:00 2001 From: DavidDierickx Date: Wed, 1 Mar 2023 17:10:18 +1100 Subject: [PATCH 04/18] add custom capabilities --- juno/juno_custom/__init__.py | 0 juno/juno_custom/element_template.py | 25 ++ juno/juno_custom/elements/__init__.py | 0 juno/juno_custom/elements/axicon.py | 26 ++ juno/juno_custom/elements/focusing.py | 21 ++ juno/juno_custom/elements/lattice.py | 378 +++++++++++++++++++++ juno/juno_custom/elements/microlens.py | 51 +++ juno/juno_custom/elements/template.py | 23 ++ juno/juno_custom/elements/test.py | 38 +++ juno/juno_custom/main.py | 80 +++++ juno/juno_custom/system_config.yaml | 6 + juno/juno_custom/tools/beam_tools.py | 41 +++ juno/juno_custom/tools/element_tools.py | 74 ++++ juno/juno_custom/tools/simulation_tools.py | 104 ++++++ juno/juno_custom/ui/__init__.py | 0 juno/juno_custom/ui/main.py | 81 +++++ juno/juno_custom/ui/main.ui | 129 +++++++ juno/juno_custom/user_interface.py | 136 ++++++++ juno/juno_custom/utils.py | 23 ++ 19 files changed, 1236 insertions(+) create mode 100644 juno/juno_custom/__init__.py create mode 100644 juno/juno_custom/element_template.py create mode 100644 juno/juno_custom/elements/__init__.py create mode 100644 juno/juno_custom/elements/axicon.py create mode 100644 juno/juno_custom/elements/focusing.py create mode 100644 juno/juno_custom/elements/lattice.py create mode 100644 juno/juno_custom/elements/microlens.py create mode 100644 juno/juno_custom/elements/template.py create mode 100644 juno/juno_custom/elements/test.py create mode 100644 juno/juno_custom/main.py create mode 100644 juno/juno_custom/system_config.yaml create mode 100644 juno/juno_custom/tools/beam_tools.py create mode 100644 juno/juno_custom/tools/element_tools.py create mode 100644 juno/juno_custom/tools/simulation_tools.py create mode 100644 juno/juno_custom/ui/__init__.py create mode 100644 juno/juno_custom/ui/main.py create mode 100644 juno/juno_custom/ui/main.ui create mode 100644 juno/juno_custom/user_interface.py create mode 100644 juno/juno_custom/utils.py diff --git a/juno/juno_custom/__init__.py b/juno/juno_custom/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/juno/juno_custom/element_template.py b/juno/juno_custom/element_template.py new file mode 100644 index 0000000..22248bb --- /dev/null +++ b/juno/juno_custom/element_template.py @@ -0,0 +1,25 @@ +from abc import ABC, abstractmethod + +from juno import Lens + + +class ElementTemplate(ABC): + def __init__(self) -> None: + pass + + def __repr__(self) -> str: + return f"Custom Element: {self.name}" + + @abstractmethod + def generate_profile(self): + raise NotImplementedError("Custom elements must be modified in some way.") + + def analyse(self): + print("No analysis conducted.") + + @staticmethod + @abstractmethod + def __keys__() -> dict: + raise NotImplementedError( + "Custom elements must have a list of keys to generate a profile." + ) diff --git a/juno/juno_custom/elements/__init__.py b/juno/juno_custom/elements/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/juno/juno_custom/elements/axicon.py b/juno/juno_custom/elements/axicon.py new file mode 100644 index 0000000..d2d31e7 --- /dev/null +++ b/juno/juno_custom/elements/axicon.py @@ -0,0 +1,26 @@ +# from juno.Lens import Lens + +# from juno_custom.element_template import ElementTemplate + + +# AXICON_KEYS = ["height", "width", "exponent", "coefficient", "pixel_size"] + +# class Axicon(ElementTemplate): +# def __init__(self, lens: Lens) -> None: +# super().__init__(lens) +# self.name = "Axicon" + +# def __identifier__(self) -> str: +# return f"""Axicon""" + +# def __repr__(self) -> str: +# return f"""Axicon (Exponent = 1.0)""" + +# def generate_profile(self): +# self.lens.exponent = 1 + +# def analyse(self): +# print("Axicon analysis.") + +# def __keys__(self) -> list: +# return AXICON_KEYS \ No newline at end of file diff --git a/juno/juno_custom/elements/focusing.py b/juno/juno_custom/elements/focusing.py new file mode 100644 index 0000000..d42cc7b --- /dev/null +++ b/juno/juno_custom/elements/focusing.py @@ -0,0 +1,21 @@ +# from juno_custom.element_template import ElementTemplate +# from juno.Lens import Lens + +# FOCUSING_KEYS = ["height", "width", "exponent", "coefficient", "pixel_size"] + +# class FocusingLens(ElementTemplate): +# def __init__(self, lens: Lens) -> None: +# super().__init__(lens) +# self.name = "Focusing" + +# def __repr__(self) -> str: +# return f"""Focusing Lens (Exponent = 2.0)""" + +# def generate_profile(self): +# self.lens.exponent = 2 + +# def analyse(self): +# print("Focusing") + +# def __keys__(self) -> list: +# return FOCUSING_KEYS diff --git a/juno/juno_custom/elements/lattice.py b/juno/juno_custom/elements/lattice.py new file mode 100644 index 0000000..3fd5ce0 --- /dev/null +++ b/juno/juno_custom/elements/lattice.py @@ -0,0 +1,378 @@ +import numpy as np +from juno import utils as j_utils +from juno.Lens import Lens +from scipy import ndimage + +from juno_custom.element_template import ElementTemplate +import numpy as np +import matplotlib.pyplot as plt +from numpy.fft import fft2, ifftshift, fftshift +from scipy.interpolate import RectBivariateSpline, RegularGridInterpolator +from scipy.ndimage import interpolation +import os +import sys +from PIL import Image + +from numba import jit + +# name: [type, default, critical, fixed, description] +LATTICE_KEYS = { + "wave": [float, 0.488, True, False, "Wavelength of light in um"], + "NA_inner": [float, 0.42, True, False, "Inner NA of the mask aperture"], + "NA_outer": [float, 0.6, True, False, "Outer NA of the mask aperture"], + "spacing": [float, 0.97, True, False, "Spacing between the beams"], + "n_beam": [int, 46, True, False, "Number of beams"], + "crop": [float, 0.22, True, True, "Crop factor"], + "tilt": [float, 0, True, False, "Tilt of the pattern"], + "shift_x": [float, 0, True, False, "Shift of the pattern in x direction"], + "shift_y": [float, 0, True, False, "Shift of the pattern in y direction"], + "mag": [float, 167.364, True, False, "Magnification between SLM mask and sample"], + "pixel": [float, 13.62, True, False, "Pixel size of the element in um"], + "slm_xpix": [int, 1280, True, False, "Number of pixels in x direction"], + "slm_ypix": [int, 1024, True, False, "Number of pixels in y direction"], + "mode": [str, "binary", True, False, "Mode of the pattern (binary, pupil, intensity)"], +} + + +class Lattice(ElementTemplate): + def __init__(self) -> None: + super().__init__() + self.name = "Lattice" + + def __repr__(self) -> str: + return f"""Lattice Profile""" + + def generate_profile(self, params): + self.profile = linear_bessel_array( + show=False, + outdir=None, + pattern_only=True, + test=False, + save=False, + savefig=False, + path=None, + **params, + ) + + @staticmethod + def __keys__() -> dict: + return LATTICE_KEYS + + +def linear_bessel_array( + wave=0.488, + NA_inner=0.44, + NA_outer=0.55, + spacing=None, + n_beam="fill", + crop=0.22, + tilt=0, + shift_x=0, + shift_y=0, + mag=167.364, + pixel=13.662, + slm_xpix=1280, + slm_ypix=1024, + fillchip=0.95, + fudge=0.95, + show=False, + outdir=None, + pattern_only=True, + test=False, + save=False, + savefig=False, + mode="binary", + path=None, +): + + if path: + if save or savefig: + if not os.path.exists(path): + os.makedirs(path, exist_ok=True) + + # auto-choose good spacing + if not spacing: + spacing = fudge * wave / NA_inner + + # to fill the chip + if n_beam == "fill" and fillchip: + n_beam = int( + np.floor(1 + ((fillchip * (slm_xpix * (pixel / mag) / 2)) / spacing)) + ) + + # Populate real space array + dx = pixel / mag + x = np.arange(-(slm_xpix) / 2, (slm_xpix + 1) / 2, 1.0) * dx + y = x + + # for scipy interpolation functions, we don't use the meshgrid... + x_slm = np.linspace(x[0], x[-1], slm_xpix) + y_slm = x_slm + + # Populate k space array + dk = 2 * np.pi / (slm_xpix + 1) / dx + kx = np.arange(-(slm_xpix) / 2, (slm_xpix + 1) / 2, 1.0) * dk + ky = kx + [kx, ky] = np.meshgrid(kx, ky) + kr = np.sqrt(kx * kx + ky * ky) + + # Mask k-space array according to inner and outer NA + pupil_mask = (kr < NA_outer * (2 * np.pi / wave)) & ( + kr > NA_inner * (2 * np.pi / wave) + ) + + if path: + if save: + np.save(os.path.join(path, "pupil_mask"), pupil_mask) + if savefig: + plt.figure() + plt.imshow(pupil_mask) + plt.title("Pupil mask") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "pupil_mask.png")) + + # Generate array of bessel beams by applying phase ramps in k-space + pupil_field_ideal = pupil_mask.astype(np.complex128) + + f = kx * spacing * np.cos(tilt) + ky * spacing * np.sin(tilt) + + @jit(nopython=True) + def calc(v, ii): + A = np.exp(1j * f * ii) + np.exp(-1j * f * ii) + return v + np.multiply(pupil_mask, A) + + for ii in range(1, n_beam): + pupil_field_ideal = calc(pupil_field_ideal, ii) + pupil_field_ideal *= np.exp(1j * (kx * shift_x + ky * shift_y)) + + if path: + if save: + np.save(os.path.join(path, "pupil_field_ideal"), pupil_field_ideal) + if savefig: + plt.figure() + plt.imshow(np.abs(pupil_field_ideal)) + plt.title("Pupil field ideal") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "pupil_field_ideal.png")) + + # Ideal SLM field of fourier transform of pupil field + slm_field_ideal = fftshift(fft2(ifftshift(pupil_field_ideal))).real + slm_field_ideal /= np.max(np.max(np.abs(slm_field_ideal))) + + # TODO: Save ideal slm field + ideal = np.abs(slm_field_ideal * slm_field_ideal) + + if path: + if save: + np.save(os.path.join(path, "ideal"), ideal) + if savefig: + plt.figure() + plt.imshow(ideal) + plt.title("Ideal coherent bessel light sheet intensity") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "ideal.png")) + + # Display ideal intensity at sample (incorporates supersampling) + if show: + plt.figure() + plt.imshow(np.abs(slm_field_ideal * slm_field_ideal)) + plt.title("Ideal coherent bessel light sheet intensity") + plt.axis("image") + plt.colorbar() + + # Interpolate back onto SLM pixels and apply cropping factor + # interpolator = interp2d(x, x, slm_field_ideal) + interpolator = RectBivariateSpline(x, y, slm_field_ideal) + slm_pattern = interpolator(x_slm, y_slm) + + if path: + if save: + np.save(os.path.join(path, "slm_pattern"), slm_pattern) + if savefig: + plt.figure() + plt.imshow(slm_pattern) + plt.title("SLM pattern") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "slm_pattern.png")) + + # slm_pattern *= np.abs(slm_pattern) > crop + slm_pattern[np.abs(slm_pattern) < crop] = 0 + eps = np.finfo(float).eps + slm_pattern = np.sign(slm_pattern + eps) * np.pi / 2 + np.pi / 2 + + if path: + if save: + np.save(os.path.join(path, "slm_pattern_binary"), slm_pattern) + if savefig: + plt.figure() + plt.imshow(slm_pattern) + plt.title("SLM pattern binarised") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "slm_pattern_binary.png")) + + # Account for rectangular aspect ratio of SLM and convert phase to binary + low = int(np.floor((slm_xpix / 2) - (slm_ypix / 2) - 1)) + high = int(low + slm_ypix) + slm_pattern_final = (slm_pattern[low:high, :] / np.pi) != 0 + + if path: + if save: + np.save(os.path.join(path, "slm_pattern_binary_2"), slm_pattern_final) + if savefig: + plt.figure() + plt.imshow(slm_pattern_final) + plt.title("SLM pattern binary 2") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "slm_pattern_binary_2.png")) + + if outdir is not None: + outdir = os.path.abspath(os.path.expanduser(outdir)) + if os.path.isdir(outdir): + namefmt = ( + "{:.0f}_{:2d}b_s{:.2f}_c{:.2f}_na{:.0f}-{:.0f}_x{:02f}_y{:02f}_t{:0.3f}" + ) + name = namefmt.format( + wave * 1000, + n_beam * 2 - 1, + spacing, + crop, + 100 * NA_outer, + 100 * NA_inner, + shift_x, + shift_y, + tilt, + ) + name = name.replace(".", "p") + outpath = os.path.join(outdir, name + ".png") + + imout = Image.fromarray(slm_pattern_final.astype(np.uint8) * 255) + imout = imout.convert("1") + imout.save(outpath) + + if show: + plt.figure() + plt.imshow(slm_pattern, interpolation="nearest") + plt.title( + "Cropped and pixelated phase from SLM pattern exiting the polarizing beam splitter" + ) + plt.axis("image") + + plt.figure() + plt.imshow(slm_pattern_final, interpolation="nearest", cmap="gray") + plt.title("Binarized image to output to SLM") + + # if pattern_only: + # print(f'Mode: {mode}') + # if mode == 'binary': + # return slm_pattern_final #, intensity_final, pupil_field + # elif mode == 'pupil': + # return pupil_field + # elif mode == 'intensity': + # return intensity_final + # if show: + # plt.show() + # return slm_pattern_final + + # this method uses nearest neighbor like the matlab version + [xmesh, ymesh] = np.meshgrid(x, y) + coords = np.array([xmesh.flatten(), ymesh.flatten()]).T + interpolator = RegularGridInterpolator( + (x_slm, y_slm), slm_pattern, method="nearest" + ) + slm_pattern_cal = interpolator(coords) # supposed to be nearest neighbor + slm_pattern_cal = slm_pattern_cal.reshape(len(x), len(y)).T + slm_field = np.exp(1j * slm_pattern_cal) + + # at this point, matlab has complex component = 0.0i + + # Compute intensity impinging on annular mask + pupil_field_impinging = fftshift(fft2(ifftshift(slm_field))) + pupil_field_impinging_real = np.real( + pupil_field_impinging * np.conj(pupil_field_impinging) + ) + if path: + if save: + np.save( + os.path.join(path, "pupil_field_impinging_real"), + pupil_field_impinging_real, + ) + if savefig: + plt.figure() + plt.imshow(pupil_field_impinging_real) + plt.title("Real component of impinging pupil field") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "pupil_field_impinging_real.png")) + + # Compute intensity passing through annular mask + pupil_field = pupil_field_impinging * pupil_mask + pupil_field_real = np.real(pupil_field * np.conj(pupil_field)) + if path: + if save: + np.save(os.path.join(path, "pupil_field_real"), pupil_field_real) + if savefig: + plt.figure() + plt.imshow(pupil_field_real) + plt.title("Real part of pupil field") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "pupil_field_real.png")) + + if show: + plt.figure() + ax1 = plt.subplot(1, 2, 1) + plt.imshow( + (pupil_field_impinging * np.conj(pupil_field_impinging)).real, + interpolation="nearest", + cmap="inferno", + ) + plt.clim(0, (2 * n_beam - 1) * 3e6) + plt.title("Intensity impinging on annular mask") + plt.subplot(1, 2, 2, sharex=ax1) + plt.imshow( + (pupil_field * np.conj(pupil_field)).real, + interpolation="nearest", + cmap="inferno", + ) + plt.clim(0, (2 * n_beam - 1) * 3e6) + plt.title("Intensity after annular mask") + + # Compute intensity at sample + field_final = fftshift(fft2(ifftshift(pupil_field))) + intensity_final = (field_final * np.conj(field_final)).real + + if path: + if save: + np.save(os.path.join(path, "sample_intensity"), intensity_final) + if savefig: + plt.figure() + plt.imshow(intensity_final) + plt.title("Sample Intensity") + plt.axis("image") + plt.colorbar() + plt.savefig(os.path.join(path, "sample_intensity.png")) + + if show: + plt.figure() + plt.imshow(intensity_final, interpolation="nearest") + plt.title("Actual intensity at sample") + plt.axis("image") + plt.show() + + plt.close("all") + if test: + return pupil_field, slm_pattern_final, intensity_final + + # print(f"Mode: {mode}") + if mode == "binary": + return slm_pattern_final # , intensity_final, pupil_field + elif mode == "pupil": + return pupil_field_real + elif mode == "intensity": + return intensity_final diff --git a/juno/juno_custom/elements/microlens.py b/juno/juno_custom/elements/microlens.py new file mode 100644 index 0000000..ec87bb4 --- /dev/null +++ b/juno/juno_custom/elements/microlens.py @@ -0,0 +1,51 @@ +import numpy as np +from juno import utils as j_utils +from juno.Lens import Lens +from scipy import ndimage + +from juno_custom.element_template import ElementTemplate + +EXTENDED_KEYS = { + "pixel_size": [float, 1.e-6, True, False, "Pixel size of the element in m"], + "diameter": [float, 100.e-6, True, False, "Diameter of the element in m"], + "coefficient": [float, 10000, True, False, "Coefficient of the element"], + "escape_path": [float, 0.1, True, False, "Percentage of escape path"], + "exponent": [float, 2.3, True, False, "Exponent of the element"], +} + + +class ExtendedMicrolens(ElementTemplate): + def __init__(self) -> None: + super().__init__() + self.name = "ExtendedMicrolens" + + def __repr__(self) -> str: + return f"""Extended Microlens""" + + def generate_profile(self, params): + self.profile = generate_lens( + **params + ) + + def analyse(self): + print("Extended microlens capability") + + @staticmethod + def __keys__() -> list: + return EXTENDED_KEYS + + +def generate_lens(pixel_size, diameter, coefficient, escape_path, exponent): + n_pixels = j_utils._calculate_num_of_pixels(diameter, pixel_size) + radius = diameter / 2 + n_pixels_in_radius = n_pixels // 2 + 1 + radius_px = np.linspace(0, radius, n_pixels_in_radius) + profile = -coefficient * radius_px**exponent + profile -= np.min(profile) + profile = np.append(profile, np.zeros(int(escape_path * len(profile)))) + profile = np.append(np.flip(profile[1:]), profile) + profile = ndimage.gaussian_filter(profile, sigma=3) + profile = np.expand_dims(profile, 0).astype(np.float32) + + return profile + \ No newline at end of file diff --git a/juno/juno_custom/elements/template.py b/juno/juno_custom/elements/template.py new file mode 100644 index 0000000..c95656c --- /dev/null +++ b/juno/juno_custom/elements/template.py @@ -0,0 +1,23 @@ +from juno.Lens import Lens + +from element_template import ElementTemplate + +KEYS = [] + + +class CustomLens(ElementTemplate): + def __init__(self, lens: Lens) -> None: + super().__init__(lens) + self.name = "CustomLens" + + def __repr__(self) -> str: + return f"""Custom Lens""" + + def generate_profile(self): + pass + + def analyse(self): + print("Custom analysis.") + + def __keys__(self) -> list: + return KEYS diff --git a/juno/juno_custom/elements/test.py b/juno/juno_custom/elements/test.py new file mode 100644 index 0000000..530933f --- /dev/null +++ b/juno/juno_custom/elements/test.py @@ -0,0 +1,38 @@ +import numpy as np +from juno import utils as j_utils +from juno.Lens import Lens +from scipy import ndimage + +from juno_custom.element_template import ElementTemplate + +TEST_KEYS = { + "pixel_size": [float, 1.e-6, True, False, "Pixel Size"], + "diameter": [float, 0.42, True, False, "Diameter of the element"], + "coefficient": [float, 0.5, True, False, "Coefficient of the element"], + "escape_path": [float, 0.97, True, False, "Percentage of escape path"], + "exponent": [int, 46, True, False, "Exponent of the element"], +} + +class TestLens(ElementTemplate): + def __init__(self) -> None: + super().__init__() + self.name = "Test" + + def __repr__(self) -> str: + return f"""Test""" + + def generate_profile(self, params): + self.profile = generate_element(**params) + + def analyse(self): + print("Test analysis") + + @staticmethod + def __keys__() -> list: + return TEST_KEYS + + +def generate_element(pixel_size, diameter, coefficient, escape_path, exponent): + profile = np.zeros((1000, 1000)) + profile[450:550, 450:550] = 1 + return profile \ No newline at end of file diff --git a/juno/juno_custom/main.py b/juno/juno_custom/main.py new file mode 100644 index 0000000..2c407b4 --- /dev/null +++ b/juno/juno_custom/main.py @@ -0,0 +1,80 @@ +import os +import sys +from pprint import pprint +from juno import utils as j_utils +import itertools +from juno_custom.tools import element_tools, simulation_tools, beam_tools + +package_path = os.path.dirname(os.path.abspath(__file__)) + +MODES = ["simulation", "element"] + +def main(config_filename=None): + if config_filename is None: + raise ValueError("Config file must be provided.") + + # load config and append the system information + config = j_utils.load_yaml_config(config_filename=config_filename) + + if config.get("mode") is None: + raise ValueError("Mode must be provided.") + + if config.get("mode") not in MODES: + raise ValueError("Mode must be one of the following: {}".format(MODES)) + + system_config = simulation_tools.load_system_config(config=config, system_config_path="system_config.yaml") + config["system"] = system_config + + + if config.get("mode") == "simulation": + key_list = [] + config["lenses"] = [] + for i, element in enumerate(config["elements"]): + element_config = j_utils.load_yaml_config(config_filename=element["path"]) + config["lenses"].append({"name": element["name"]}) + for key, value in element_config.items(): + config["lenses"][i][key] = value + + if "keys" in config["lenses"][i]: + key_list.append(config["lenses"][i]["keys"]) + + key_list = list(itertools.chain(*key_list)) + + if len(key_list) > 0: + simulation_tools.iterate_through_parameter_combinations(config=config, key_list=key_list) + + pprint(config) + pprint(key_list) + return + + if not ( + "keys" in config + and config["keys"] is not None + and isinstance(config["keys"], list) + ): + run(config=config) + + elif len(config["keys"]) > 0: + simulation_tools.iterate_through_parameter_combinations(config=config) + +def run(config: dict, count=0): + + if config.get("mode") == "simulation": + for element in config["elements"]: + + + + config = beam_tools.generate_beam_config(config=config) + config = simulation_tools.generate_simulation_config(config=config) + + + element = element_tools.generate_element(config=config) + element.generate_profile() + + simulation_tools.save_outputs(config=config, profile=element.profile, count=count) + +if __name__ == "__main__": + if len(sys.argv) > 1: + main(sys.argv[1]) + else: + raise ValueError("Config file must be provided.") diff --git a/juno/juno_custom/system_config.yaml b/juno/juno_custom/system_config.yaml new file mode 100644 index 0000000..0e48d1b --- /dev/null +++ b/juno/juno_custom/system_config.yaml @@ -0,0 +1,6 @@ +linux: /home/dadie1/zt14/David/ +windows: C:/Users/User/Github/ + +creation_config_path: "" +juno_path: juno/juno/ +juno_custom_path: juno_custom/juno_custom/ diff --git a/juno/juno_custom/tools/beam_tools.py b/juno/juno_custom/tools/beam_tools.py new file mode 100644 index 0000000..f11cc67 --- /dev/null +++ b/juno/juno_custom/tools/beam_tools.py @@ -0,0 +1,41 @@ +import itertools +import os +import sys +import numpy as np + +import utils +import yaml +from juno import SimulationRunner, validation +from copy import deepcopy + +from juno_custom.tools import element_tools +from juno import utils as j_utils + +def generate_beam_config(config: dict): + if config.get("beam") is None or config["beam"].get("match"): + config = match_beam(config=config) + + return config + + +def match_beam(config: dict): + # TODO: check for spherical here? + beam_config = deepcopy(config.get("beam")) + beam_config["beam_type"] = config.get("beam_type") + beam_config["height"] = config.get("length") + beam_config["width"] = config.get("diameter") + beam_config["distance_mode"] = "Direct" + beam_config["source_distance"] = 1.e-9 + beam_config["n_steps"] = 2 + beam_config["numerical_aperture"] = 0.0 + beam_config["position_x"] = 0.0 + beam_config["position_y"] = 0.0 + beam_config["shape"] = config.get("lens_type") + beam_config["spread"] = "Plane" + beam_config["step_size"] = 0.0 + beam_config["tilt_x"] = 0.0 + beam_config["tilt_y"] = 0.0 + beam_config["theta"] = 0.0 + + config["beam"] = beam_config + return config diff --git a/juno/juno_custom/tools/element_tools.py b/juno/juno_custom/tools/element_tools.py new file mode 100644 index 0000000..9b38c05 --- /dev/null +++ b/juno/juno_custom/tools/element_tools.py @@ -0,0 +1,74 @@ +import glob +import importlib +import os + +from juno.Lens import Lens +from juno.Medium import Medium + +import juno_custom.elements +from juno_custom.element_template import ElementTemplate + +# These are the modules that will be ignored when importing custom lenses +IGNORED_MODULES = ["__init__", "template"] + + +def import_custom_elements(): + # get all the modules in the custom_lenses folder + module_names = [ + os.path.basename(f)[:-3] + for f in glob.glob(os.path.join(juno_custom.elements.__path__[0], "*.py")) + ] + + # iterate through the modules, removing any that have a substring in IGNORED_MODULES + module_names = [ + juno_custom.elements.__name__ + "." + module + for module in module_names + if not any([a in module for a in IGNORED_MODULES]) + ] + + # iterate through the modules and try to import them + for module_ in module_names: + try: + importlib.import_module(module_) + + except Exception as e: + print(f"Failed to import {module_}, reason being: {e}") + + +def get_custom_elements(): + import_custom_elements() + return ElementTemplate.__subclasses__() + + +def generate_base_element(config: dict): + diameter = config.get("diameter") + height = config.get("height") + medium = config.get("medium") + exponent = config.get("exponent") + base_element = Lens(diameter, height, exponent, Medium(medium)) + base_element.generate_profile(config.get("pixel_size")) + return base_element + + +def generate_element(config: dict): + base_element = generate_base_element(config=config) + element = ElementFactory.create_element( + element_type=config.get("element_type"), lens=base_element + ) + return element + + +def generate_element_config(config: dict): + config["lenses"] = {} + + +class ElementFactory: + @staticmethod + def create_element(element_type: str = None, lens: Lens = None): + if element_type is None: + raise ValueError("Element type must be provided.") + + for custom_element in get_custom_elements(): + if element_type.lower() == custom_element.__name__.lower(): + return custom_element(lens) + raise ValueError(f"Element type {element_type} not found.") diff --git a/juno/juno_custom/tools/simulation_tools.py b/juno/juno_custom/tools/simulation_tools.py new file mode 100644 index 0000000..44815b9 --- /dev/null +++ b/juno/juno_custom/tools/simulation_tools.py @@ -0,0 +1,104 @@ +import itertools +import os +import sys +import numpy as np + +import utils +import yaml +from juno import SimulationRunner, validation + +from juno_custom.tools import element_tools, beam_tools +from juno_custom import main +from juno import utils as j_utils +from copy import deepcopy + + +def get_parameter_combinations(config: dict, key_list: list): + sweep_keys = key_list + config = validation._validate_sweepable_parameters(config, sweep_keys) + kp = SimulationRunner.sweep_config_keys(config, sweep_keys) + param_combos = list(itertools.product(*kp)) + print(param_combos) + return param_combos + + +def iterate_through_parameter_combinations(config: dict, key_list: list): + param_combos = get_parameter_combinations(config=config, key_list=key_list) + # for i, param_combo in enumerate(param_combos): + # for j, key in enumerate(config["keys"]): + # if isinstance(param_combo[j], float): + # config[key] = float(param_combo[j]) + # elif isinstance(param_combo[j], str): + # config[key] = str(param_combo[j]) + + # main.run(config=config, count=i) + + +def save_outputs(config: dict, profile: np.ndarray, count=0): + save_config( + config, + os.path.join( + config["system"].get("configs_path"), "config_" + str(count) + ".yaml" + ), + ) + save_profile( + profile=profile, + filename=os.path.join( + config["system"].get("configs_path"), "profile_" + str(count) + ), + ) + + +def generate_simulation_config(config: dict): + if config.get("simulation_name") is None or config["sim_parameters"].get("match"): + config = match_simulation(config=config) + config["sim_parameters"]["pixel_size"] = config.get("pixel_size") + return config + + +def match_simulation(config: dict): + sim_config = deepcopy(config["sim_parameters"]) + # TODO: check for spherical here? + sim_config["sim_height"] = config.get("length") + sim_config["sim_width"] = config.get("diameter") + + config["sim_parameters"] = sim_config + + return config + + +def save_config(config: dict, filename: str): + if not os.path.exists(os.path.dirname(filename)): + os.makedirs(os.path.dirname(filename)) + with open(filename, "w") as f: + yaml.safe_dump(config, f, sort_keys=False) + + +def save_profile(profile: dict, filename: str): + np.save(filename, profile) + + +def load_system_config(config: dict, system_config_path: str = None): + + if system_config_path is None: + raise ValueError("System config path must be provided.") + + system_config = j_utils.load_yaml_config(config_filename=system_config_path) + + if sys.platform == "win32": + base_path = system_config.get("windows") + elif sys.platform == "linux": + base_path = system_config.get("linux") + else: + raise ValueError("Unknown operating system.") + + system_config["base_path"] = base_path + + system_config["configs_path"] = os.path.join( + system_config.get("base_path"), + system_config.get("juno_custom_path"), + "simulations", + config.get("directory_name"), + "configs", + ) + return system_config diff --git a/juno/juno_custom/ui/__init__.py b/juno/juno_custom/ui/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/juno/juno_custom/ui/main.py b/juno/juno_custom/ui/main.py new file mode 100644 index 0000000..e7d193b --- /dev/null +++ b/juno/juno_custom/ui/main.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'main.ui' +# +# Created by: PyQt5 UI code generator 5.15.7 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(316, 722) + self.centralwidget = QtWidgets.QWidget(MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.frameMainWindow = QtWidgets.QFrame(self.centralwidget) + self.frameMainWindow.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frameMainWindow.setFrameShadow(QtWidgets.QFrame.Raised) + self.frameMainWindow.setObjectName("frameMainWindow") + self.gridLayout_2 = QtWidgets.QGridLayout(self.frameMainWindow) + self.gridLayout_2.setObjectName("gridLayout_2") + self.frame_Options = QtWidgets.QFrame(self.frameMainWindow) + self.frame_Options.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_Options.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame_Options.setObjectName("frame_Options") + self.gridLayout_2.addWidget(self.frame_Options, 1, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 800, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem, 2, 1, 2, 1) + self.frame_Setup = QtWidgets.QFrame(self.frameMainWindow) + self.frame_Setup.setMinimumSize(QtCore.QSize(0, 120)) + self.frame_Setup.setMaximumSize(QtCore.QSize(16777215, 120)) + self.frame_Setup.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_Setup.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame_Setup.setObjectName("frame_Setup") + self.verticalLayout = QtWidgets.QVBoxLayout(self.frame_Setup) + self.verticalLayout.setObjectName("verticalLayout") + self.comboBox_Elements = QtWidgets.QComboBox(self.frame_Setup) + self.comboBox_Elements.setObjectName("comboBox_Elements") + self.verticalLayout.addWidget(self.comboBox_Elements) + self.gridLayout_2.addWidget(self.frame_Setup, 0, 1, 1, 1) + self.frame_Save = QtWidgets.QFrame(self.frameMainWindow) + self.frame_Save.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.frame_Save.setFrameShadow(QtWidgets.QFrame.Raised) + self.frame_Save.setObjectName("frame_Save") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame_Save) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.pushButton_GenerateProfile = QtWidgets.QPushButton(self.frame_Save) + self.pushButton_GenerateProfile.setObjectName("pushButton_GenerateProfile") + self.verticalLayout_2.addWidget(self.pushButton_GenerateProfile) + self.pushButton_SaveProfile = QtWidgets.QPushButton(self.frame_Save) + self.pushButton_SaveProfile.setObjectName("pushButton_SaveProfile") + self.verticalLayout_2.addWidget(self.pushButton_SaveProfile) + self.pushButton_SaveParameters = QtWidgets.QPushButton(self.frame_Save) + self.pushButton_SaveParameters.setObjectName("pushButton_SaveParameters") + self.verticalLayout_2.addWidget(self.pushButton_SaveParameters) + self.gridLayout_2.addWidget(self.frame_Save, 4, 1, 1, 1) + self.gridLayout.addWidget(self.frameMainWindow, 0, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 316, 21)) + self.menubar.setObjectName("menubar") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "CustomElement :: Designer")) + self.pushButton_GenerateProfile.setText(_translate("MainWindow", "Generate Profile")) + self.pushButton_SaveProfile.setText(_translate("MainWindow", "Save Profile")) + self.pushButton_SaveParameters.setText(_translate("MainWindow", "Save Parameters")) diff --git a/juno/juno_custom/ui/main.ui b/juno/juno_custom/ui/main.ui new file mode 100644 index 0000000..9b1de8f --- /dev/null +++ b/juno/juno_custom/ui/main.ui @@ -0,0 +1,129 @@ + + + MainWindow + + + + 0 + 0 + 316 + 722 + + + + CustomElement :: Designer + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + Qt::Vertical + + + + 20 + 800 + + + + + + + + + 0 + 120 + + + + + 16777215 + 120 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Generate Profile + + + + + + + Save Profile + + + + + + + Save Parameters + + + + + + + + + + + + + + + 0 + 0 + 316 + 21 + + + + + + + + diff --git a/juno/juno_custom/user_interface.py b/juno/juno_custom/user_interface.py new file mode 100644 index 0000000..d6432ca --- /dev/null +++ b/juno/juno_custom/user_interface.py @@ -0,0 +1,136 @@ +import napari +import numpy as np +import yaml +from napari.qt.threading import thread_worker +from PyQt5 import QtCore, QtGui, QtWidgets + +import juno_custom.tools.element_tools as element_tools +from juno_custom.ui import main as main_ui + + +class GuiMainWindow(main_ui.Ui_MainWindow, QtWidgets.QMainWindow): + def __init__(self, viewer: napari.Viewer = None): + super(GuiMainWindow, self).__init__() + self.setupUi(self) + self.viewer = viewer + self.params = dict() + + self.setup_viewer() + self.generate_element_list() + self.generate_options() + self.setup_connections() + + def setup_viewer(self): + self.viewer.window._qt_viewer.dockLayerList.setVisible(False) + self.viewer.window._qt_viewer.dockLayerControls.setVisible(False) + self.viewer.window._qt_viewer.dockConsole.setVisible(False) + + def setup_connections(self): + self.comboBox_Elements.currentTextChanged.connect(self.generate_options) + self.pushButton_GenerateProfile.clicked.connect(self.run_generate_profile) + self.pushButton_SaveProfile.clicked.connect(self.save_profile) + self.pushButton_SaveParameters.clicked.connect(self.save_parameters) + + def generate_element_list(self): + # import custom elements from elements folder + element_list = element_tools.get_custom_elements() + + self.comboBox_Elements.clear() + + self.elements = dict() + for element in element_list: + self.comboBox_Elements.addItem(element.__name__) + self.elements[element.__name__] = { + "class": element, + "keys": element.__keys__(), + } + + def generate_options(self): + element_name = self.comboBox_Elements.currentText() + print(f"Generating options for {element_name}...") + + # clear options frame + for widget in self.frame_Options.children(): + if isinstance(widget, QtWidgets.QWidget): + self.frame_Options.layout().removeWidget(widget) + widget.deleteLater() + + # re/set layout + if self.frame_Options.layout() is None: + self.frame_Options.setLayout(QtWidgets.QVBoxLayout()) + + self.params = dict() + self.lineedits = dict() + + # load in each key + for key, value in self.elements[element_name]["keys"].items(): + self.params[key] = None + + key_label = QtWidgets.QLabel(key) + key_label.setToolTip(value[4]) + + key_line_edit = QtWidgets.QLineEdit() + key_line_edit.setText(str(value[1])) + if value[3]: + key_line_edit.setEnabled(False) + self.lineedits[key] = key_line_edit + + self.frame_Options.layout().addWidget(key_label) + self.frame_Options.layout().addWidget(key_line_edit) + + def run_generate_profile(self): + self.pushButton_GenerateProfile.setEnabled(False) + element_name = self.comboBox_Elements.currentText() + params = self.get_parameters(element_name=element_name) + self.element = self.load_element(element_name) + + worker = self.generate_profile(params=params) + worker.signals.finished.connect(self.plot_profile) + worker.signals.finished.connect( + lambda: self.pushButton_GenerateProfile.setEnabled(True) + ) + worker.start() + + def get_parameters(self, element_name: str): + params = dict() + for key in self.params.keys(): + type_ = self.elements[element_name]["keys"][key][0] + params[key] = type_(self.lineedits[key].text()) + return params + + @thread_worker + def generate_profile(self, params): + self.element.generate_profile(params) + + def plot_profile(self): + self.viewer.layers.clear() + self.viewer.add_image(self.element.profile, colormap="gray", name="element") + + def load_element(self, element_name: str): + element = self.elements[element_name]["class"]() + return element + + def save_profile(self): + filename, _ = QtWidgets.QFileDialog.getSaveFileName( + self, "Save Profile", "", "Numpy Arrays (*.npy)" + ) + if filename: + np.save(filename, self.element.profile) + + def save_parameters(self): + filename, _ = QtWidgets.QFileDialog.getSaveFileName( + self, "Save Parameters", "", "YAML (*.yml *.yaml)" + ) + if filename: + parameters = self.get_parameters( + element_name=self.comboBox_Elements.currentText() + ) + with open(filename, "w") as f: + yaml.dump(parameters, f, sort_keys=False) + + +if __name__ == "__main__": + viewer = napari.Viewer(ndisplay=2) + user_interface = GuiMainWindow(viewer=viewer) + viewer.window.add_dock_widget(user_interface, area="right") + napari.run() diff --git a/juno/juno_custom/utils.py b/juno/juno_custom/utils.py new file mode 100644 index 0000000..2c0d937 --- /dev/null +++ b/juno/juno_custom/utils.py @@ -0,0 +1,23 @@ +import os + +import numpy as np +import yaml + + +def save_configuration(config: dict, profile: np.ndarray = None): + save_base = os.path.join(config["folder"], config["name"]) + + os.makedirs(config["folder"], exist_ok=True) + + with open(save_base + ".yaml", "w") as f: + yaml.safe_dump(config, f, sort_keys=False) + + if profile is not None: + np.save(save_base + ".npy", profile) + + +def load_configuration(config_filename: str): + with open(config_filename, "r") as f: + config = yaml.safe_load(f) + + return config From 4bf17d96817dbf239738e7713c131334e2aaeb43 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 17:34:52 +1100 Subject: [PATCH 05/18] [UI] remove gaussian z distance from options as it didnt do anything --- juno/ui/BeamCreation.py | 18 +++++++++--------- juno/ui/qtdesigner_files/BeamCreation.py | 13 +++++-------- juno/ui/qtdesigner_files/BeamCreation.ui | 19 ++++++++----------- 3 files changed, 22 insertions(+), 28 deletions(-) diff --git a/juno/ui/BeamCreation.py b/juno/ui/BeamCreation.py index cf5d93e..3aa9e0e 100644 --- a/juno/ui/BeamCreation.py +++ b/juno/ui/BeamCreation.py @@ -73,7 +73,7 @@ def setup_connections(self): self.lineEdit_gaussian_waist_x.textChanged.connect(self.update_visualisation) self.lineEdit_gaussian_waist_y.textChanged.connect(self.update_visualisation) self.lineEdit_gaussian_axial_z0.textChanged.connect(self.update_visualisation) - self.lineEdit_gaussian_axial_z_total.textChanged.connect(self.update_visualisation) + # self.lineEdit_gaussian_axial_z_total.textChanged.connect(self.update_visualisation) # simulation self.lineEdit_pixelsize.textChanged.connect(self.update_visualisation) @@ -131,7 +131,7 @@ def update_ui_from_config(self, config: dict): self.lineEdit_gaussian_waist_x.setText(str(config["gaussian_wx"])) self.lineEdit_gaussian_waist_y.setText(str(config["gaussian_wy"])) self.lineEdit_gaussian_axial_z0.setText(str(config["gaussian_z0"])) - self.lineEdit_gaussian_axial_z_total.setText(str(config["gaussian_z"])) + # self.lineEdit_gaussian_axial_z_total.setText(str(config["gaussian_z"])) # simulation if config["step_size"] is None: @@ -191,17 +191,17 @@ def load_configuration(self): if filename == "": return - # load beam config and validate - beam_config = utils.load_yaml_config(filename) - beam_config = validation._validate_default_beam_config(beam_config) - - # update ui try: + # load beam config and validate + beam_config = utils.load_yaml_config(filename) + beam_config = validation._validate_default_beam_config(beam_config) + + # update ui self.update_ui_from_config(beam_config) + self.update_visualisation() except: napari.utils.notifications.show_error(traceback.format_exc()) - self.update_visualisation() def save_configuration(self): @@ -266,7 +266,7 @@ def update_config(self): beam_config["gaussian_wx"] = float(self.lineEdit_gaussian_waist_x.text()) beam_config["gaussian_wy"] = float(self.lineEdit_gaussian_waist_y.text()) beam_config["gaussian_z0"] = float(self.lineEdit_gaussian_axial_z0.text()) - beam_config["gaussian_z"] = float(self.lineEdit_gaussian_axial_z_total.text()) + # beam_config["gaussian_z"] = float(self.lineEdit_gaussian_axial_z_total.text()) # sim parameters parameters_config["A"] = float(self.lineEdit_sim_amplitude.text()) diff --git a/juno/ui/qtdesigner_files/BeamCreation.py b/juno/ui/qtdesigner_files/BeamCreation.py index 3e4d70f..59ed0b3 100644 --- a/juno/ui/qtdesigner_files/BeamCreation.py +++ b/juno/ui/qtdesigner_files/BeamCreation.py @@ -160,9 +160,6 @@ def setupUi(self, MainWindow): self.tab.setObjectName("tab") self.gridLayout_7 = QtWidgets.QGridLayout(self.tab) self.gridLayout_7.setObjectName("gridLayout_7") - self.label_gaussian_z_total = QtWidgets.QLabel(self.tab) - self.label_gaussian_z_total.setObjectName("label_gaussian_z_total") - self.gridLayout_7.addWidget(self.label_gaussian_z_total, 5, 0, 1, 1) self.label_gaussian_header = QtWidgets.QLabel(self.tab) font = QtGui.QFont() font.setBold(True) @@ -187,15 +184,15 @@ def setupUi(self, MainWindow): self.gridLayout_7.addWidget(self.lineEdit_gaussian_axial_z0, 4, 1, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout_7.addItem(spacerItem1, 6, 0, 1, 2) - self.lineEdit_gaussian_axial_z_total = QtWidgets.QLineEdit(self.tab) - self.lineEdit_gaussian_axial_z_total.setObjectName("lineEdit_gaussian_axial_z_total") - self.gridLayout_7.addWidget(self.lineEdit_gaussian_axial_z_total, 5, 1, 1, 1) self.label_gaussian_z0 = QtWidgets.QLabel(self.tab) self.label_gaussian_z0.setObjectName("label_gaussian_z0") self.gridLayout_7.addWidget(self.label_gaussian_z0, 4, 0, 1, 1) self.label_gaussian_waist_y = QtWidgets.QLabel(self.tab) self.label_gaussian_waist_y.setObjectName("label_gaussian_waist_y") self.gridLayout_7.addWidget(self.label_gaussian_waist_y, 3, 0, 1, 1) + self.label_gaussian_z_total = QtWidgets.QLabel(self.tab) + self.label_gaussian_z_total.setObjectName("label_gaussian_z_total") + self.gridLayout_7.addWidget(self.label_gaussian_z_total, 5, 0, 1, 2) self.tabWidget.addTab(self.tab, "") self.tab_grating = QtWidgets.QWidget() self.tab_grating.setObjectName("tab_grating") @@ -295,7 +292,7 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(1) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): @@ -328,12 +325,12 @@ def retranslateUi(self, MainWindow): self.lineEdit_tilt_y.setText(_translate("MainWindow", "0.0")) self.label_tilt_header.setText(_translate("MainWindow", "Tilt")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_general), _translate("MainWindow", "General")) - self.label_gaussian_z_total.setText(_translate("MainWindow", "Total Distance (z)")) self.label_gaussian_header.setText(_translate("MainWindow", "Gaussian")) self.checkBox_gaussian_enabled.setText(_translate("MainWindow", "Enable Gaussian Beam")) self.label_gaussian_waist_x.setText(_translate("MainWindow", "Waist Radius (X)")) self.label_gaussian_z0.setText(_translate("MainWindow", "Axial Distance (z0)")) self.label_gaussian_waist_y.setText(_translate("MainWindow", "Waist Radius (Y)")) + self.label_gaussian_z_total.setText(_translate("MainWindow", "Total Distance (z) is controlled by propagation distance in the General tab.")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Gaussian")) self.label.setText(_translate("MainWindow", "Wavelength (m)")) self.label_pixelsize.setText(_translate("MainWindow", "Pixel Size")) diff --git a/juno/ui/qtdesigner_files/BeamCreation.ui b/juno/ui/qtdesigner_files/BeamCreation.ui index ed0bb41..6aa881a 100644 --- a/juno/ui/qtdesigner_files/BeamCreation.ui +++ b/juno/ui/qtdesigner_files/BeamCreation.ui @@ -51,7 +51,7 @@ QTabWidget::Rounded - 0 + 1 @@ -299,13 +299,6 @@ Gaussian - - - - Total Distance (z) - - - @@ -355,9 +348,6 @@ - - - @@ -372,6 +362,13 @@ + + + + Total Distance (z) is controlled by propagation distance in the General tab. + + + From c2fd40fc9f737d19b48a690c42d49a394e8305b3 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 18:02:23 +1100 Subject: [PATCH 06/18] [BUG] Simulation propagation distance being less than step size not caught in validation #48 --- juno/beam.py | 5 +++++ juno/ui/BeamCreation.py | 6 +++--- juno/ui/qtdesigner_files/BeamCreation.py | 2 +- juno/ui/qtdesigner_files/BeamCreation.ui | 2 +- tests/test_beam.py | 7 +++++++ 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/juno/beam.py b/juno/beam.py index e7cb610..d4f9eb6 100644 --- a/juno/beam.py +++ b/juno/beam.py @@ -381,6 +381,11 @@ def validate_beam_configuration(settings: BeamSettings): if settings.source_distance is None: raise ValueError(f"A source_distance must be provided for {settings.distance_mode}") + # check if step size greater than propagation distance + if settings.step_size is not None: + if settings.step_size > settings.source_distance: + raise ValueError(f"The step_size ({settings.step_size:.2e}m) must be less than the source_distance ({settings.source_distance:.2e}m) for {settings.distance_mode}.") + if settings.distance_mode == DistanceMode.Focal: if settings.beam_spread not in [BeamSpread.Converging, BeamSpread.Diverging]: raise ValueError(f"BeamSpread must be Converging, or Diverging for {settings.distance_mode} (currently {settings.beam_spread})") diff --git a/juno/ui/BeamCreation.py b/juno/ui/BeamCreation.py index 3aa9e0e..daaf973 100644 --- a/juno/ui/BeamCreation.py +++ b/juno/ui/BeamCreation.py @@ -370,9 +370,9 @@ def validate_beam_for_display(config: dict, parameters: SimulationParameters) -> for k in ["width", "height"]: if config["beam"][k] / parameters.pixel_size > BEAM_SHAPE_DISPLAY_LIMIT_PX: valid_beam = False - - if config["beam"]["n_steps"] > BEAM_N_STEPS_DISPLAY_LIMIT: - valid_beam = False + if "n_steps" in config["beam"]: + if config["beam"]["n_steps"] > BEAM_N_STEPS_DISPLAY_LIMIT: + valid_beam = False if "step_size" in config["beam"]: if config["beam"]["step_size"] < BEAM_STEP_SIZE_DISPLAY_LIMIT: valid_beam = False diff --git a/juno/ui/qtdesigner_files/BeamCreation.py b/juno/ui/qtdesigner_files/BeamCreation.py index 59ed0b3..218eb83 100644 --- a/juno/ui/qtdesigner_files/BeamCreation.py +++ b/juno/ui/qtdesigner_files/BeamCreation.py @@ -292,7 +292,7 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(1) + self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): diff --git a/juno/ui/qtdesigner_files/BeamCreation.ui b/juno/ui/qtdesigner_files/BeamCreation.ui index 6aa881a..03b164b 100644 --- a/juno/ui/qtdesigner_files/BeamCreation.ui +++ b/juno/ui/qtdesigner_files/BeamCreation.ui @@ -51,7 +51,7 @@ QTabWidget::Rounded - 1 + 0 diff --git a/tests/test_beam.py b/tests/test_beam.py index eeac441..a8c8b52 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -252,6 +252,13 @@ def test_validate_beam_configuration(beam_settings): with pytest.raises(ValueError): validate_beam_configuration(settings) + # distance mode direct with step size greater than source distance + settings.distance_mode = DistanceMode.Direct + settings.source_distance = 1e-3 + settings.step_size = 2e-3 + with pytest.raises(ValueError): + validate_beam_configuration(settings) + From 9a14d38d3e524ab73f83fb9a664845f505fe0fc4 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 18:02:50 +1100 Subject: [PATCH 07/18] small qol --- juno/ui/SimulationSetup.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/juno/ui/SimulationSetup.py b/juno/ui/SimulationSetup.py index 48e1b23..999d148 100644 --- a/juno/ui/SimulationSetup.py +++ b/juno/ui/SimulationSetup.py @@ -520,16 +520,11 @@ def load_stage_config_widgets(config, all_widgets): widgets[14].setText(str(stage_config["focal_distance_multiple"])) def main(): - """Launch the main application window. """ - application = QtWidgets.QApplication([]) import napari viewer = napari.Viewer(ndisplay=3) simulation_setup_ui = GUISimulationSetup(viewer=viewer) viewer.window.add_dock_widget(simulation_setup_ui, area='right') - - application.aboutToQuit.connect(simulation_setup_ui.disconnect) # cleanup & teardown - sys.exit(application.exec_()) - + napari.run() if __name__ == "__main__": main() From 0c098cd460c5c520afebc042e21da3c9979bc79e Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 18:25:24 +1100 Subject: [PATCH 08/18] [BUG] fix Flat elements not working in ElementCreator #52 --- juno/plotting.py | 3 ++- juno/ui/qtdesigner_files/ElementCreation.py | 8 +++++--- juno/ui/qtdesigner_files/ElementCreation.ui | 17 +++++++++++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/juno/plotting.py b/juno/plotting.py index 311f4db..096a746 100644 --- a/juno/plotting.py +++ b/juno/plotting.py @@ -653,8 +653,9 @@ def create_3d_lens(lens: Lens) -> da.Array: # scale profile by pixelsize lens_profile = lens.profile / lens.pixel_size # profile height in pixels - + l_max = int(np.max(lens_profile)) + l_max = max(l_max, 1) # make sure l_max is at least 1 arr3d = np.ones(shape=(l_max, lens_profile.shape[0], lens_profile.shape[1])) for y in range(lens.profile.shape[0]): diff --git a/juno/ui/qtdesigner_files/ElementCreation.py b/juno/ui/qtdesigner_files/ElementCreation.py index 75d59fd..224c865 100644 --- a/juno/ui/qtdesigner_files/ElementCreation.py +++ b/juno/ui/qtdesigner_files/ElementCreation.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'ElementCreation.ui' # -# Created by: PyQt5 UI code generator 5.15.7 +# Created by: PyQt5 UI code generator 5.15.4 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. @@ -258,9 +258,11 @@ def setupUi(self, MainWindow): self.checkBox_live_update.setObjectName("checkBox_live_update") self.gridLayout_2.addWidget(self.checkBox_live_update, 2, 0, 1, 1) self.gridLayout.addWidget(self.frame_main, 0, 0, 1, 1) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem2, 1, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 365, 20)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 365, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") @@ -283,7 +285,7 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(1) + self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): diff --git a/juno/ui/qtdesigner_files/ElementCreation.ui b/juno/ui/qtdesigner_files/ElementCreation.ui index dbddf0e..6ceef0c 100644 --- a/juno/ui/qtdesigner_files/ElementCreation.ui +++ b/juno/ui/qtdesigner_files/ElementCreation.ui @@ -30,7 +30,7 @@ QTabWidget::Rounded - 1 + 0 @@ -515,6 +515,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -523,7 +536,7 @@ 0 0 365 - 20 + 21 From efa629dd0258af6b6d4f19655fd39dbcfa67b7ed Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 18:27:45 +1100 Subject: [PATCH 09/18] add custom dev note --- juno/juno_custom/README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 juno/juno_custom/README.md diff --git a/juno/juno_custom/README.md b/juno/juno_custom/README.md new file mode 100644 index 0000000..f3d31b4 --- /dev/null +++ b/juno/juno_custom/README.md @@ -0,0 +1,4 @@ +# README + + +The tools in this directory are experimental and are not supported by the Juno team. They are provided as-is and are not guaranteed to work. If you find a bug, please report it on Github \ No newline at end of file From c037a0f737bffa4f80f3d4478709d41857510517 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 18:40:24 +1100 Subject: [PATCH 10/18] [PKG] bump version no, fix dependency --- juno/_version.py | 4 ++++ pyproject.toml | 2 +- setup.cfg | 6 +++--- 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 juno/_version.py diff --git a/juno/_version.py b/juno/_version.py new file mode 100644 index 0000000..649f7a6 --- /dev/null +++ b/juno/_version.py @@ -0,0 +1,4 @@ +# file generated by setuptools_scm +# don't change, don't track in version control +__version__ = version = '0.1.dev560+gefa629d.d20230301' +__version_tuple__ = version_tuple = (0, 1, 'dev560', 'gefa629d.d20230301') diff --git a/pyproject.toml b/pyproject.toml index 97c4099..4e72b28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ authors = [ {name = "Patrick Cleeve", email = "Patrick.Cleeve@monash.edu"} ] readme = "README.md" -requires-python = ">=3.9" +requires-python = ">=3.7" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", diff --git a/setup.cfg b/setup.cfg index 3d4ab29..b00f953 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,9 @@ [metadata] name = juno -version = 0.0.1 +version = 0.1.0 author = David Dierickx, Patrick Cleeve author_email = David.Dierickx1@monash.edu, Patrick.Cleeve@monash.edu -description = juno is python package for designing lenses by performing full wave simulations. +description = juno is python package for designing optical systems by performing full wave simulations. long_description = file: README.md long_description_content_type = text/markdown url = https://github.com/DeMarcoLab/juno @@ -16,7 +16,7 @@ classifiers = [options] packages = find: -python_requires = >=3.8 +python_requires = >=3.7 [options.entry_points] console_scripts = From abca7c64d9e0db5755ff967615bb3c2125da68b8 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 18:40:41 +1100 Subject: [PATCH 11/18] [UI] fixes Tab order #45 --- juno/ui/qtdesigner_files/BeamCreation.py | 33 ++++++++++++++++-- juno/ui/qtdesigner_files/BeamCreation.ui | 36 ++++++++++++++++++-- juno/ui/qtdesigner_files/ElementCreation.py | 31 +++++++++++++++++ juno/ui/qtdesigner_files/ElementCreation.ui | 34 ++++++++++++++++++ juno/ui/qtdesigner_files/JunoLauncher.py | 4 +++ juno/ui/qtdesigner_files/JunoLauncher.ui | 7 ++++ juno/ui/qtdesigner_files/SimulationSetup.py | 15 ++++++++ juno/ui/qtdesigner_files/SimulationSetup.ui | 18 ++++++++++ juno/ui/qtdesigner_files/VisualiseResults.py | 11 +++++- juno/ui/qtdesigner_files/VisualiseResults.ui | 9 +++++ 10 files changed, 191 insertions(+), 7 deletions(-) diff --git a/juno/ui/qtdesigner_files/BeamCreation.py b/juno/ui/qtdesigner_files/BeamCreation.py index 218eb83..f56cb9e 100644 --- a/juno/ui/qtdesigner_files/BeamCreation.py +++ b/juno/ui/qtdesigner_files/BeamCreation.py @@ -14,7 +14,7 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(396, 700) + MainWindow.resize(418, 700) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) @@ -275,7 +275,7 @@ def setupUi(self, MainWindow): self.gridLayout.addWidget(self.frame_main, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 396, 21)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 418, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") @@ -292,8 +292,35 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuFile.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(2) QtCore.QMetaObject.connectSlotsByName(MainWindow) + MainWindow.setTabOrder(self.tabWidget, self.lineEdit_name) + MainWindow.setTabOrder(self.lineEdit_name, self.lineEdit_beam_width) + MainWindow.setTabOrder(self.lineEdit_beam_width, self.lineEdit_beam_height) + MainWindow.setTabOrder(self.lineEdit_beam_height, self.lineEdit_shift_x) + MainWindow.setTabOrder(self.lineEdit_shift_x, self.lineEdit_shift_y) + MainWindow.setTabOrder(self.lineEdit_shift_y, self.comboBox_spread) + MainWindow.setTabOrder(self.comboBox_spread, self.comboBox_shape) + MainWindow.setTabOrder(self.comboBox_shape, self.comboBox_convergence) + MainWindow.setTabOrder(self.comboBox_convergence, self.lineEdit_convergence_value) + MainWindow.setTabOrder(self.lineEdit_convergence_value, self.comboBox_distance_mode) + MainWindow.setTabOrder(self.comboBox_distance_mode, self.lineEdit_distance_value) + MainWindow.setTabOrder(self.lineEdit_distance_value, self.lineEdit_tilt_x) + MainWindow.setTabOrder(self.lineEdit_tilt_x, self.lineEdit_tilt_y) + MainWindow.setTabOrder(self.lineEdit_tilt_y, self.checkBox_live_update) + MainWindow.setTabOrder(self.checkBox_live_update, self.pushButton_generate_beam) + MainWindow.setTabOrder(self.pushButton_generate_beam, self.checkBox_gaussian_enabled) + MainWindow.setTabOrder(self.checkBox_gaussian_enabled, self.lineEdit_gaussian_waist_x) + MainWindow.setTabOrder(self.lineEdit_gaussian_waist_x, self.lineEdit_gaussian_waist_y) + MainWindow.setTabOrder(self.lineEdit_gaussian_waist_y, self.lineEdit_gaussian_axial_z0) + MainWindow.setTabOrder(self.lineEdit_gaussian_axial_z0, self.lineEdit_pixelsize) + MainWindow.setTabOrder(self.lineEdit_pixelsize, self.lineEdit_sim_width) + MainWindow.setTabOrder(self.lineEdit_sim_width, self.lineEdit_sim_height) + MainWindow.setTabOrder(self.lineEdit_sim_height, self.lineEdit_sim_wavelength) + MainWindow.setTabOrder(self.lineEdit_sim_wavelength, self.lineEdit_sim_amplitude) + MainWindow.setTabOrder(self.lineEdit_sim_amplitude, self.comboBox_propagation_type) + MainWindow.setTabOrder(self.comboBox_propagation_type, self.lineEdit_propagation_step) + MainWindow.setTabOrder(self.lineEdit_propagation_step, self.lineEdit_medium) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate diff --git a/juno/ui/qtdesigner_files/BeamCreation.ui b/juno/ui/qtdesigner_files/BeamCreation.ui index 03b164b..f2cc59c 100644 --- a/juno/ui/qtdesigner_files/BeamCreation.ui +++ b/juno/ui/qtdesigner_files/BeamCreation.ui @@ -6,7 +6,7 @@ 0 0 - 396 + 418 700 @@ -51,7 +51,7 @@ QTabWidget::Rounded - 0 + 2 @@ -550,7 +550,7 @@ 0 0 - 396 + 418 21 @@ -575,6 +575,36 @@ + + tabWidget + lineEdit_name + lineEdit_beam_width + lineEdit_beam_height + lineEdit_shift_x + lineEdit_shift_y + comboBox_spread + comboBox_shape + comboBox_convergence + lineEdit_convergence_value + comboBox_distance_mode + lineEdit_distance_value + lineEdit_tilt_x + lineEdit_tilt_y + checkBox_live_update + pushButton_generate_beam + checkBox_gaussian_enabled + lineEdit_gaussian_waist_x + lineEdit_gaussian_waist_y + lineEdit_gaussian_axial_z0 + lineEdit_pixelsize + lineEdit_sim_width + lineEdit_sim_height + lineEdit_sim_wavelength + lineEdit_sim_amplitude + comboBox_propagation_type + lineEdit_propagation_step + lineEdit_medium + diff --git a/juno/ui/qtdesigner_files/ElementCreation.py b/juno/ui/qtdesigner_files/ElementCreation.py index 224c865..4fb96e7 100644 --- a/juno/ui/qtdesigner_files/ElementCreation.py +++ b/juno/ui/qtdesigner_files/ElementCreation.py @@ -287,6 +287,37 @@ def setupUi(self, MainWindow): self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) + MainWindow.setTabOrder(self.tabWidget, self.lineEdit_name) + MainWindow.setTabOrder(self.lineEdit_name, self.lineEdit_pixelsize) + MainWindow.setTabOrder(self.lineEdit_pixelsize, self.lineEdit_diameter) + MainWindow.setTabOrder(self.lineEdit_diameter, self.lineEdit_length) + MainWindow.setTabOrder(self.lineEdit_length, self.lineEdit_height) + MainWindow.setTabOrder(self.lineEdit_height, self.lineEdit_exponent) + MainWindow.setTabOrder(self.lineEdit_exponent, self.lineEdit_medium) + MainWindow.setTabOrder(self.lineEdit_medium, self.comboBox_type) + MainWindow.setTabOrder(self.comboBox_type, self.lineEdit_escape_path) + MainWindow.setTabOrder(self.lineEdit_escape_path, self.checkBox_invert_profile) + MainWindow.setTabOrder(self.checkBox_invert_profile, self.checkBox_live_update) + MainWindow.setTabOrder(self.checkBox_live_update, self.pushButton_generate_profile) + MainWindow.setTabOrder(self.pushButton_generate_profile, self.comboBox_truncation_mode) + MainWindow.setTabOrder(self.comboBox_truncation_mode, self.checkBox_use_truncation) + MainWindow.setTabOrder(self.checkBox_use_truncation, self.checkBox_grating_y_axis) + MainWindow.setTabOrder(self.checkBox_grating_y_axis, self.lineEdit_grating_depth) + MainWindow.setTabOrder(self.lineEdit_grating_depth, self.checkBox_grating_centred) + MainWindow.setTabOrder(self.checkBox_grating_centred, self.checkBox_aperture_invert) + MainWindow.setTabOrder(self.checkBox_aperture_invert, self.comboBox_grating_mode) + MainWindow.setTabOrder(self.comboBox_grating_mode, self.lineEdit_grating_inner_radius) + MainWindow.setTabOrder(self.lineEdit_grating_inner_radius, self.lineEdit_aperture_outer) + MainWindow.setTabOrder(self.lineEdit_aperture_outer, self.lineEdit_grating_distance) + MainWindow.setTabOrder(self.lineEdit_grating_distance, self.checkBox_use_aperture) + MainWindow.setTabOrder(self.checkBox_use_aperture, self.comboBox_aperture_mode) + MainWindow.setTabOrder(self.comboBox_aperture_mode, self.lineEdit_truncation_value) + MainWindow.setTabOrder(self.lineEdit_truncation_value, self.checkBox_grating_x_axis) + MainWindow.setTabOrder(self.checkBox_grating_x_axis, self.checkBox_truncation_aperture) + MainWindow.setTabOrder(self.checkBox_truncation_aperture, self.lineEdit_aperture_inner) + MainWindow.setTabOrder(self.lineEdit_aperture_inner, self.lineEdit_grating_blur) + MainWindow.setTabOrder(self.lineEdit_grating_blur, self.lineEdit_grating_width) + MainWindow.setTabOrder(self.lineEdit_grating_width, self.checkBox_use_grating) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate diff --git a/juno/ui/qtdesigner_files/ElementCreation.ui b/juno/ui/qtdesigner_files/ElementCreation.ui index 6ceef0c..81407f7 100644 --- a/juno/ui/qtdesigner_files/ElementCreation.ui +++ b/juno/ui/qtdesigner_files/ElementCreation.ui @@ -572,6 +572,40 @@ + + tabWidget + lineEdit_name + lineEdit_pixelsize + lineEdit_diameter + lineEdit_length + lineEdit_height + lineEdit_exponent + lineEdit_medium + comboBox_type + lineEdit_escape_path + checkBox_invert_profile + checkBox_live_update + pushButton_generate_profile + comboBox_truncation_mode + checkBox_use_truncation + checkBox_grating_y_axis + lineEdit_grating_depth + checkBox_grating_centred + checkBox_aperture_invert + comboBox_grating_mode + lineEdit_grating_inner_radius + lineEdit_aperture_outer + lineEdit_grating_distance + checkBox_use_aperture + comboBox_aperture_mode + lineEdit_truncation_value + checkBox_grating_x_axis + checkBox_truncation_aperture + lineEdit_aperture_inner + lineEdit_grating_blur + lineEdit_grating_width + checkBox_use_grating + diff --git a/juno/ui/qtdesigner_files/JunoLauncher.py b/juno/ui/qtdesigner_files/JunoLauncher.py index 864db20..dddb0b6 100644 --- a/juno/ui/qtdesigner_files/JunoLauncher.py +++ b/juno/ui/qtdesigner_files/JunoLauncher.py @@ -58,6 +58,10 @@ def setupUi(self, MainWindow): self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) + MainWindow.setTabOrder(self.pushButton_create_element, self.pushButton_create_beam) + MainWindow.setTabOrder(self.pushButton_create_beam, self.pushButton_setup_sim) + MainWindow.setTabOrder(self.pushButton_setup_sim, self.pushButton_run_simulation) + MainWindow.setTabOrder(self.pushButton_run_simulation, self.pushButton_view_results) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate diff --git a/juno/ui/qtdesigner_files/JunoLauncher.ui b/juno/ui/qtdesigner_files/JunoLauncher.ui index f211858..2f05d95 100644 --- a/juno/ui/qtdesigner_files/JunoLauncher.ui +++ b/juno/ui/qtdesigner_files/JunoLauncher.ui @@ -101,6 +101,13 @@ + + pushButton_create_element + pushButton_create_beam + pushButton_setup_sim + pushButton_run_simulation + pushButton_view_results + diff --git a/juno/ui/qtdesigner_files/SimulationSetup.py b/juno/ui/qtdesigner_files/SimulationSetup.py index 8d0992d..45cadae 100644 --- a/juno/ui/qtdesigner_files/SimulationSetup.py +++ b/juno/ui/qtdesigner_files/SimulationSetup.py @@ -197,6 +197,21 @@ def setupUi(self, MainWindow): self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) + MainWindow.setTabOrder(self.pushButton_visualise_simulation, self.lineEdit_pixel_size) + MainWindow.setTabOrder(self.lineEdit_pixel_size, self.lineEdit_sim_width) + MainWindow.setTabOrder(self.lineEdit_sim_width, self.lineEdit_sim_height) + MainWindow.setTabOrder(self.lineEdit_sim_height, self.lineEdit_sim_wavelength) + MainWindow.setTabOrder(self.lineEdit_sim_wavelength, self.lineEdit_sim_amplitude) + MainWindow.setTabOrder(self.lineEdit_sim_amplitude, self.pushButton_sim_beam) + MainWindow.setTabOrder(self.pushButton_sim_beam, self.lineEdit_log_dir) + MainWindow.setTabOrder(self.lineEdit_log_dir, self.lineEdit_sim_name) + MainWindow.setTabOrder(self.lineEdit_sim_name, self.checkBox_save_plot) + MainWindow.setTabOrder(self.checkBox_save_plot, self.tabWidget) + MainWindow.setTabOrder(self.tabWidget, self.spinBox_sim_num_stages) + MainWindow.setTabOrder(self.spinBox_sim_num_stages, self.scrollArea_stages) + MainWindow.setTabOrder(self.scrollArea_stages, self.pushButton_generate_simulation) + MainWindow.setTabOrder(self.pushButton_generate_simulation, self.pushButton_setup_parameter_sweep) + MainWindow.setTabOrder(self.pushButton_setup_parameter_sweep, self.spinBox_visualisation_scale) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate diff --git a/juno/ui/qtdesigner_files/SimulationSetup.ui b/juno/ui/qtdesigner_files/SimulationSetup.ui index 6d1d87b..372310e 100644 --- a/juno/ui/qtdesigner_files/SimulationSetup.ui +++ b/juno/ui/qtdesigner_files/SimulationSetup.ui @@ -415,6 +415,24 @@ + + pushButton_visualise_simulation + lineEdit_pixel_size + lineEdit_sim_width + lineEdit_sim_height + lineEdit_sim_wavelength + lineEdit_sim_amplitude + pushButton_sim_beam + lineEdit_log_dir + lineEdit_sim_name + checkBox_save_plot + tabWidget + spinBox_sim_num_stages + scrollArea_stages + pushButton_generate_simulation + pushButton_setup_parameter_sweep + spinBox_visualisation_scale + diff --git a/juno/ui/qtdesigner_files/VisualiseResults.py b/juno/ui/qtdesigner_files/VisualiseResults.py index 2c7b01f..7b82790 100644 --- a/juno/ui/qtdesigner_files/VisualiseResults.py +++ b/juno/ui/qtdesigner_files/VisualiseResults.py @@ -143,7 +143,16 @@ def setupUi(self, MainWindow): self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) - MainWindow.setTabOrder(self.pushButton_load_simulation, self.scroll_area_filter) + MainWindow.setTabOrder(self.pushButton_load_simulation, self.spinBox_num_filters) + MainWindow.setTabOrder(self.spinBox_num_filters, self.scroll_area_filter) + MainWindow.setTabOrder(self.scroll_area_filter, self.lineEdit_show_columns) + MainWindow.setTabOrder(self.lineEdit_show_columns, self.pushButton_reset_data) + MainWindow.setTabOrder(self.pushButton_reset_data, self.pushButton_filter_data) + MainWindow.setTabOrder(self.pushButton_filter_data, self.checkBox_log_plots) + MainWindow.setTabOrder(self.checkBox_log_plots, self.checkBox_show_all_simulations) + MainWindow.setTabOrder(self.checkBox_show_all_simulations, self.doubleSpinBox_scale) + MainWindow.setTabOrder(self.doubleSpinBox_scale, self.comboBox_napari_sim) + MainWindow.setTabOrder(self.comboBox_napari_sim, self.pushButton_update_visualisation) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate diff --git a/juno/ui/qtdesigner_files/VisualiseResults.ui b/juno/ui/qtdesigner_files/VisualiseResults.ui index 103f9f6..b042fdb 100644 --- a/juno/ui/qtdesigner_files/VisualiseResults.ui +++ b/juno/ui/qtdesigner_files/VisualiseResults.ui @@ -276,7 +276,16 @@ pushButton_load_simulation + spinBox_num_filters scroll_area_filter + lineEdit_show_columns + pushButton_reset_data + pushButton_filter_data + checkBox_log_plots + checkBox_show_all_simulations + doubleSpinBox_scale + comboBox_napari_sim + pushButton_update_visualisation From 8d0b8b61eefcd7b032a113e7ac060d9f65c4f568 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 19:08:53 +1100 Subject: [PATCH 12/18] [BUG] fixes Escape path dimensions don't match with specific pixel size/escape path combo #42 --- juno/Lens.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/juno/Lens.py b/juno/Lens.py index 783df75..f176d39 100644 --- a/juno/Lens.py +++ b/juno/Lens.py @@ -776,6 +776,12 @@ def calculate_escape_path_dimensions(lens: Lens, ep: float): lens_h, lens_w = lens.profile.shape ep_h, ep_w = int(lens_h * (1 + ep)), int(lens_w * (1 + ep)) + # ensure the escape path is odd + if ep_h % 2 == 0: + ep_h += 1 + if ep_w % 2 == 0: + ep_w += 1 + return (ep_h, ep_w) From cc8b5a99e860bfebfca63008a5850cb515ec3007 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 1 Mar 2023 19:09:17 +1100 Subject: [PATCH 13/18] [BUG] fixes Escape Path/Pixel Size bug #46 changed to spinbox with max limit to prevent confusion --- juno/ui/ElementCreation.py | 6 +++--- juno/ui/qtdesigner_files/ElementCreation.py | 12 ++++++------ juno/ui/qtdesigner_files/ElementCreation.ui | 18 ++++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/juno/ui/ElementCreation.py b/juno/ui/ElementCreation.py index 65d385c..1ef8f90 100644 --- a/juno/ui/ElementCreation.py +++ b/juno/ui/ElementCreation.py @@ -67,7 +67,7 @@ def setup_connections(self): self.lineEdit_height.textChanged.connect(self.update_visualisation) self.lineEdit_medium.textChanged.connect(self.update_visualisation) self.lineEdit_exponent.textChanged.connect(self.update_visualisation) - self.lineEdit_escape_path.textChanged.connect(self.update_visualisation) + self.doubleSpinBox_escape_path.valueChanged.connect(self.update_visualisation) self.comboBox_type.currentTextChanged.connect(self.update_visualisation) self.checkBox_invert_profile.stateChanged.connect(self.update_visualisation) self.lineEdit_name.textChanged.connect(self.update_visualisation) @@ -122,7 +122,7 @@ def update_ui_from_config(self, config: dict): self.lineEdit_height.setText(str(config["height"])) self.lineEdit_medium.setText(str(config["medium"])) self.lineEdit_exponent.setText(str(config["exponent"])) - self.lineEdit_escape_path.setText(str(config["escape_path"])) + self.doubleSpinBox_escape_path.setValue(float(config["escape_path"])) self.comboBox_type.setCurrentText(str(config["lens_type"]).capitalize()) self.checkBox_invert_profile.setChecked(bool(config["inverted"])) self.lineEdit_name.setText(str(config["name"])) @@ -337,7 +337,7 @@ def update_config(self): lens_config["diameter"] = float(self.lineEdit_diameter.text()) lens_config["exponent"] = float(self.lineEdit_exponent.text()) lens_config["inverted"] = bool(self.checkBox_invert_profile.isChecked()) - lens_config["escape_path"] = float(self.lineEdit_escape_path.text()) + lens_config["escape_path"] = float(self.doubleSpinBox_escape_path.value()) lens_config["length"] = float(self.lineEdit_length.text()) lens_config["lens_type"] = self.comboBox_type.currentText() lens_config["name"] = self.lineEdit_name.text() diff --git a/juno/ui/qtdesigner_files/ElementCreation.py b/juno/ui/qtdesigner_files/ElementCreation.py index 4fb96e7..7f23840 100644 --- a/juno/ui/qtdesigner_files/ElementCreation.py +++ b/juno/ui/qtdesigner_files/ElementCreation.py @@ -74,9 +74,6 @@ def setupUi(self, MainWindow): self.label_diameter = QtWidgets.QLabel(self.groupBox) self.label_diameter.setObjectName("label_diameter") self.gridLayout_3.addWidget(self.label_diameter, 2, 0, 1, 1) - self.lineEdit_escape_path = QtWidgets.QLineEdit(self.groupBox) - self.lineEdit_escape_path.setObjectName("lineEdit_escape_path") - self.gridLayout_3.addWidget(self.lineEdit_escape_path, 8, 1, 1, 1) self.lineEdit_exponent = QtWidgets.QLineEdit(self.groupBox) self.lineEdit_exponent.setObjectName("lineEdit_exponent") self.gridLayout_3.addWidget(self.lineEdit_exponent, 5, 1, 1, 1) @@ -98,6 +95,11 @@ def setupUi(self, MainWindow): self.checkBox_invert_profile = QtWidgets.QCheckBox(self.groupBox) self.checkBox_invert_profile.setObjectName("checkBox_invert_profile") self.gridLayout_3.addWidget(self.checkBox_invert_profile, 9, 0, 1, 2) + self.doubleSpinBox_escape_path = QtWidgets.QDoubleSpinBox(self.groupBox) + self.doubleSpinBox_escape_path.setMaximum(2.0) + self.doubleSpinBox_escape_path.setSingleStep(0.01) + self.doubleSpinBox_escape_path.setObjectName("doubleSpinBox_escape_path") + self.gridLayout_3.addWidget(self.doubleSpinBox_escape_path, 8, 1, 1, 1) self.gridLayout_4.addWidget(self.groupBox, 0, 0, 1, 1) self.tabWidget.addTab(self.tab_general, "") self.tab_grating = QtWidgets.QWidget() @@ -295,8 +297,7 @@ def setupUi(self, MainWindow): MainWindow.setTabOrder(self.lineEdit_height, self.lineEdit_exponent) MainWindow.setTabOrder(self.lineEdit_exponent, self.lineEdit_medium) MainWindow.setTabOrder(self.lineEdit_medium, self.comboBox_type) - MainWindow.setTabOrder(self.comboBox_type, self.lineEdit_escape_path) - MainWindow.setTabOrder(self.lineEdit_escape_path, self.checkBox_invert_profile) + MainWindow.setTabOrder(self.comboBox_type, self.checkBox_invert_profile) MainWindow.setTabOrder(self.checkBox_invert_profile, self.checkBox_live_update) MainWindow.setTabOrder(self.checkBox_live_update, self.pushButton_generate_profile) MainWindow.setTabOrder(self.pushButton_generate_profile, self.comboBox_truncation_mode) @@ -332,7 +333,6 @@ def retranslateUi(self, MainWindow): self.lineEdit_diameter.setText(_translate("MainWindow", "100e-6")) self.lineEdit_medium.setText(_translate("MainWindow", "2.348")) self.label_diameter.setText(_translate("MainWindow", "Diameter (m)")) - self.lineEdit_escape_path.setText(_translate("MainWindow", "0.0")) self.lineEdit_exponent.setText(_translate("MainWindow", "2.0")) self.label_exponent.setText(_translate("MainWindow", "Exponent")) self.lineEdit_height.setText(_translate("MainWindow", "50e-6")) diff --git a/juno/ui/qtdesigner_files/ElementCreation.ui b/juno/ui/qtdesigner_files/ElementCreation.ui index 81407f7..ed04e3f 100644 --- a/juno/ui/qtdesigner_files/ElementCreation.ui +++ b/juno/ui/qtdesigner_files/ElementCreation.ui @@ -135,13 +135,6 @@ - - - - 0.0 - - - @@ -191,6 +184,16 @@ + + + + 2.000000000000000 + + + 0.010000000000000 + + + @@ -582,7 +585,6 @@ lineEdit_exponent lineEdit_medium comboBox_type - lineEdit_escape_path checkBox_invert_profile checkBox_live_update pushButton_generate_profile From 80e67cfa52115f742a4b71579dd397339f3a31d8 Mon Sep 17 00:00:00 2001 From: DavidDierickx Date: Fri, 9 Jun 2023 15:37:00 +1000 Subject: [PATCH 14/18] updated light sheet measurement to start from max, not half --- juno/lightsheet/light_sheet.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/juno/lightsheet/light_sheet.py b/juno/lightsheet/light_sheet.py index 8aba843..45ea8ab 100644 --- a/juno/lightsheet/light_sheet.py +++ b/juno/lightsheet/light_sheet.py @@ -72,7 +72,11 @@ def calculate_longest_sheet(above_threshold): def calculate_sheet_size_pixels(image, threshold_value): + # FIND PEAK VALUE along center + centre_max = np.max(image[:, image.shape[1] // 2]) + index_max = np.where(image[:, image.shape[1] // 2] == centre_max)[0][0] cz = image.shape[0] // 2 + cz = index_max cx = image.shape[1] // 2 min_z, max_z = cz, cz From 2dbd9baed35ed57e300898b520e72c8419aefdbd Mon Sep 17 00:00:00 2001 From: DavidDierickx Date: Sat, 25 Nov 2023 21:55:40 +1100 Subject: [PATCH 15/18] config passing to main fix --- juno/run_simulation.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/juno/run_simulation.py b/juno/run_simulation.py index e06b435..4338063 100644 --- a/juno/run_simulation.py +++ b/juno/run_simulation.py @@ -6,15 +6,17 @@ def main(config_filename): - if len(sys.argv) >= 2: - config_filename = sys.argv[1] - else: - config_filename = os.path.join(os.path.dirname(juno.__file__), "config.yaml") + if config_filename is None: + if len(sys.argv) >= 2: + config_filename = sys.argv[1] + else: + config_filename = os.path.join(os.path.dirname(juno.__file__), "config.yaml") sim_runner = SimulationRunner.SimulationRunner(config_filename) sim_runner.setup_simulation() sim_runner.run_simulations() if __name__ == "__main__": - - main() + if len(sys.argv) >= 2: + config_filename = sys.argv[1] + main(config_filename) From 6cd7efe45365aa652c1ded3552078e592c6708be Mon Sep 17 00:00:00 2001 From: DavidDierickx Date: Sat, 25 Nov 2023 21:55:51 +1100 Subject: [PATCH 16/18] light sheet calculation fix --- juno/lightsheet/light_sheet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/juno/lightsheet/light_sheet.py b/juno/lightsheet/light_sheet.py index 45ea8ab..15b30c6 100644 --- a/juno/lightsheet/light_sheet.py +++ b/juno/lightsheet/light_sheet.py @@ -79,7 +79,7 @@ def calculate_sheet_size_pixels(image, threshold_value): cz = index_max cx = image.shape[1] // 2 - min_z, max_z = cz, cz + min_z, max_z = 0, image.shape[0] # find min, max values less than threshold for z_idx in range(cz, image.shape[0], 1): val = image[z_idx, cx] From c219dc4d139b3a7d30bfdad9bba2ea1136befea5 Mon Sep 17 00:00:00 2001 From: DavidDierickx Date: Sat, 25 Nov 2023 21:55:57 +1100 Subject: [PATCH 17/18] gitignore update --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ec34863..3d72cde 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,10 @@ juno.egg-info/PKG-INFO !mkdocs.yml # !docs.yml -!.github/workflows/* \ No newline at end of file +!.github/workflows/* + +# simulation generated files +*.png +*.json +*.csv +*.log From 780cdcfca46aa07a22877428057a1223cff4cb41 Mon Sep 17 00:00:00 2001 From: DavidDierickx Date: Sat, 25 Nov 2023 22:01:26 +1100 Subject: [PATCH 18/18] grating_blur ui fix --- juno/ui/ElementCreation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/juno/ui/ElementCreation.py b/juno/ui/ElementCreation.py index 1ef8f90..f266aeb 100644 --- a/juno/ui/ElementCreation.py +++ b/juno/ui/ElementCreation.py @@ -137,7 +137,7 @@ def update_ui_from_config(self, config: dict): self.checkBox_grating_x_axis.setChecked(bool(config["grating"]["x"])) self.checkBox_grating_y_axis.setChecked(bool(config["grating"]["y"])) self.checkBox_grating_centred.setChecked(bool(config["grating"]["centred"])) - self.lineEdit_grating_blur.setText(float(config["grating"]["blur"])) + self.lineEdit_grating_blur.setText(str(config["grating"]["blur"])) self.comboBox_grating_mode.setCurrentText(config["grating"]["mode"]) self.lineEdit_grating_inner_radius.setText(str(config["grating"]["inner_radius"]))