From 1dcd0ab1b57bc7d5eb17956cb265d791e30a4384 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 11:40:51 +1000 Subject: [PATCH 01/39] todo: msg --- autolamella/workflows/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autolamella/workflows/ui.py b/autolamella/workflows/ui.py index 0ad70d03..21fb21f7 100644 --- a/autolamella/workflows/ui.py +++ b/autolamella/workflows/ui.py @@ -23,7 +23,7 @@ def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLamellaUI response = ask_user(parent_ui, msg=msg, pos="Continue", mill=milling_enabled) stages = deepcopy(parent_ui.milling_widget.get_milling_stages()) else: - _update_status_ui(parent_ui, f"Milling {len(stages)} stages...") + _update_status_ui(parent_ui, f"Milling {len(stages)} stages...") # TODO: better feedback here, change to milling tab for progress bar parent_ui._MILLING_RUNNING = True parent_ui._run_milling_signal.emit() From f66ace9b614a3a795d235f0541ff94e6b07a8d6b Mon Sep 17 00:00:00 2001 From: Patrick Cleeve <80024299+patrickcleeve2@users.noreply.github.com> Date: Wed, 27 Sep 2023 12:19:56 +1000 Subject: [PATCH 02/39] V0.2 stop workflow button (#139) * tmp * final interupt set up * Update protocol-waffle.yaml * move abort checks inside ui functions * reset lamella stage after abprt * button fix * fix rewrite history --------- Co-authored-by: LucileNaegele --- autolamella/ui/AutoLamellaUI.py | 37 ++++++++++++++++++-- autolamella/ui/qt/AutoLamellaUI.py | 26 ++++++++------ autolamella/ui/qt/AutoLamellaUI.ui | 41 +++++++++++++--------- autolamella/workflows/core.py | 55 ++++++++++++++++++++++++++++-- autolamella/workflows/ui.py | 11 ++++++ 5 files changed, 137 insertions(+), 33 deletions(-) diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index f9c0ff4b..7c9dfc3a 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -89,7 +89,7 @@ def __init__(self, viewer: napari.Viewer) -> None: self.WAITING_FOR_UI_UPDATE: bool = False self._MILLING_RUNNING: bool = False self._WORKFLOW_RUNNING: bool = False - + self._ABORT_THREAD: bool = False # setup connections @@ -120,6 +120,9 @@ def setup_connections(self): self.pushButton_run_waffle_undercut.clicked.connect(lambda: self._run_workflow(workflow="undercut")) self.pushButton_run_setup_autolamella.clicked.connect(lambda: self._run_workflow(workflow="setup-lamella")) + self.pushButton_stop_workflow_thread.clicked.connect(self._stop_workflow_thread) + self.pushButton_stop_workflow_thread.setVisible(False) + self.pushButton_run_waffle_trench.setVisible(False) self.pushButton_run_autolamella.setVisible(False) self.pushButton_run_waffle_undercut.setVisible(False) @@ -1029,12 +1032,16 @@ def _confirm_det(self): if self.det_widget is not None: self.det_widget.confirm_button_clicked() + def _stop_workflow_thread(self): + self._ABORT_THREAD = True + napari.utils.notifications.show_error("Abort requested") + def _run_workflow(self, workflow: str) -> None: try: self.milling_widget.milling_position_changed.disconnect() except: pass - + self.worker = self._threaded_worker( microscope=self.microscope, settings=self.settings, @@ -1042,19 +1049,32 @@ def _run_workflow(self, workflow: str) -> None: workflow=workflow, ) self.worker.finished.connect(self._workflow_finished) + self.worker.errored.connect(self._workflow_aborted) self.worker.start() + def _workflow_aborted(self): + logging.info(f'Workflow aborted.') + self._WORKFLOW_RUNNING = False + self._ABORT_THREAD = False + + for lamella in self.experiment.positions: + if lamella.state.stage is not lamella.history[-1].stage: + lamella.state = deepcopy(lamella.history[-1]) + logging.info("restoring state for {}".format(lamella.info)) + def _workflow_finished(self): logging.info(f'Workflow finished.') self._WORKFLOW_RUNNING = False self.milling_widget.milling_position_changed.connect(self._update_milling_position) self.tabWidget.setCurrentIndex(0) + self.pushButton_stop_workflow_thread.setVisible(False) # clear the image settings save settings etc self.image_widget.checkBox_image_save_image.setChecked(False) self.image_widget.lineEdit_image_path.setText(self.experiment.path) self.image_widget.lineEdit_image_label.setText("default-image") + self.update_ui() def _ui_signal(self, info:dict) -> None: """Update the UI with the given information, ready for user interaction""" @@ -1101,11 +1121,22 @@ def _update_experiment(self, experiment: Experiment): @thread_worker def _threaded_worker(self, microscope: FibsemMicroscope, settings: MicroscopeSettings, experiment: Experiment, workflow: str="trench"): - + self._ABORT_THREAD = False self._WORKFLOW_RUNNING = True self.milling_widget._PATTERN_IS_MOVEABLE = True self.milling_widget._remove_all_stages() self.WAITING_FOR_USER_INTERACTION = False + self.pushButton_run_waffle_trench.setEnabled(False) + self.pushButton_run_waffle_undercut.setEnabled(False) + self.pushButton_run_setup_autolamella.setEnabled(False) + self.pushButton_run_autolamella.setEnabled(False) + self.pushButton_run_waffle_trench.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + self.pushButton_run_waffle_undercut.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + self.pushButton_run_setup_autolamella.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + self.pushButton_run_autolamella.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + + self.pushButton_stop_workflow_thread.setVisible(True) + self.pushButton_stop_workflow_thread.setStyleSheet(_stylesheets._RED_PUSHBUTTON_STYLE) self._set_instructions(f"Running {workflow.title()} workflow...", None, None) logging.info(f"RUNNING {workflow.upper()} WORKFLOW") diff --git a/autolamella/ui/qt/AutoLamellaUI.py b/autolamella/ui/qt/AutoLamellaUI.py index 1ac89e1d..107df937 100644 --- a/autolamella/ui/qt/AutoLamellaUI.py +++ b/autolamella/ui/qt/AutoLamellaUI.py @@ -26,15 +26,9 @@ def setupUi(self, MainWindow): self.gridLayout.setObjectName("gridLayout") self.label_instructions = QtWidgets.QLabel(self.centralwidget) self.label_instructions.setObjectName("label_instructions") - self.gridLayout.addWidget(self.label_instructions, 2, 0, 1, 1) + self.gridLayout.addWidget(self.label_instructions, 3, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem, 1, 0, 1, 2) - self.pushButton_no = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_no.setObjectName("pushButton_no") - self.gridLayout.addWidget(self.pushButton_no, 3, 1, 1, 1) - self.pushButton_yes = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_yes.setObjectName("pushButton_yes") - self.gridLayout.addWidget(self.pushButton_yes, 3, 0, 1, 1) + self.gridLayout.addItem(spacerItem, 2, 0, 1, 2) self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget.setObjectName("tabWidget") self.tab = QtWidgets.QWidget() @@ -386,9 +380,18 @@ def setupUi(self, MainWindow): self.formLayout_2.setWidget(24, QtWidgets.QFormLayout.SpanningRole, self.pushButton_update_protocol) self.tabWidget.addTab(self.tab_2, "") self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 2) + self.pushButton_yes = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_yes.setObjectName("pushButton_yes") + self.gridLayout.addWidget(self.pushButton_yes, 4, 0, 1, 1) + self.pushButton_no = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_no.setObjectName("pushButton_no") + self.gridLayout.addWidget(self.pushButton_no, 4, 1, 1, 1) + self.pushButton_stop_workflow_thread = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_stop_workflow_thread.setObjectName("pushButton_stop_workflow_thread") + self.gridLayout.addWidget(self.pushButton_stop_workflow_thread, 1, 0, 1, 2) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 521, 20)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 521, 21)) self.menubar.setObjectName("menubar") self.menuAutoLamella = QtWidgets.QMenu(self.menubar) self.menuAutoLamella.setObjectName("menuAutoLamella") @@ -435,8 +438,6 @@ def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label_instructions.setText(_translate("MainWindow", "Instructions")) - self.pushButton_no.setText(_translate("MainWindow", "No")) - self.pushButton_yes.setText(_translate("MainWindow", "Yes")) self.pushButton_run_setup_autolamella.setText(_translate("MainWindow", "Run Setup AutoLamella")) self.pushButton_remove_lamella.setText(_translate("MainWindow", "Remove Lamella")) self.label_title.setText(_translate("MainWindow", "AutoLamella")) @@ -475,6 +476,9 @@ def retranslateUi(self, MainWindow): self.checkBox_supervise_mill_polishing.setText(_translate("MainWindow", "Mill Polishing Stage")) self.pushButton_update_protocol.setText(_translate("MainWindow", "Update Protocol")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Protocol")) + self.pushButton_yes.setText(_translate("MainWindow", "Yes")) + self.pushButton_no.setText(_translate("MainWindow", "No")) + self.pushButton_stop_workflow_thread.setText(_translate("MainWindow", "Stop Workflow")) self.menuAutoLamella.setTitle(_translate("MainWindow", "File")) self.menuTools.setTitle(_translate("MainWindow", "Tools")) self.actionNew_Experiment.setText(_translate("MainWindow", "Create Experiment")) diff --git a/autolamella/ui/qt/AutoLamellaUI.ui b/autolamella/ui/qt/AutoLamellaUI.ui index fb778348..b435c429 100644 --- a/autolamella/ui/qt/AutoLamellaUI.ui +++ b/autolamella/ui/qt/AutoLamellaUI.ui @@ -33,14 +33,14 @@ - + Instructions - + Qt::Vertical @@ -53,20 +53,6 @@ - - - - No - - - - - - - Yes - - - @@ -931,6 +917,27 @@ + + + + Yes + + + + + + + No + + + + + + + Stop Workflow + + + @@ -939,7 +946,7 @@ 0 0 521 - 20 + 21 diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 97736ab9..27c56981 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -58,7 +58,7 @@ from autolamella.ui.AutoLamellaUI import AutoLamellaUI from fibsem import config as fcfg -from autolamella.workflows.ui import (_set_images_ui, _update_status_ui, _validate_det_ui_v2, _validate_mill_ui) +from autolamella.workflows.ui import (_set_images_ui, _update_status_ui, _validate_det_ui_v2, _validate_mill_ui, _check_for_abort) # CORE WORKFLOW STEPS @@ -84,6 +84,8 @@ def mill_trench( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) _update_status_ui(parent_ui, f"{lamella.info} Preparing Trench...") + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # define trench milling stage settings.image.beam_type = BeamType.ION @@ -93,6 +95,8 @@ def mill_trench( validate=validate, ) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # log the protocol lamella.protocol["trench"] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol["trench"]["point"] = stages[0].pattern.point.__to_dict__() @@ -102,6 +106,8 @@ def mill_trench( _update_status_ui(parent_ui, f"{lamella.info} Neutralising Sample Charge...") settings.image.beam_type = BeamType.ELECTRON calibration.auto_charge_neutralisation(microscope, settings.image) + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # refernce images log_status_message(lamella, "REFERENCE_IMAGES") @@ -137,11 +143,15 @@ def mill_undercut( _update_status_ui(parent_ui, f"{lamella.info} Moving to Undercut Position...") microscope.move_flat_to_beam(settings, BeamType.ELECTRON, _safe=True) # TODO: TEST UNSAFE MOVE + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # OFFSET FOR COMPUCENTRIC ROTATION X_OFFSET = settings.protocol["options"].get("compucentric_x_offset", 0) Y_OFFSET = settings.protocol["options"].get("compucentric_y_offset", 0) microscope.stable_move(settings, dx=X_OFFSET, dy=Y_OFFSET, beam_type=BeamType.ELECTRON) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # detect log_status_message(lamella, f"ALIGN_TRENCH") _update_status_ui(parent_ui, f"{lamella.info} Aligning Trench (Rotated)...") @@ -151,6 +161,8 @@ def mill_undercut( settings.image.save = True eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") features = [LamellaCentre()] det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info, position=lamella.state.microscope_state.absolute_position) @@ -161,6 +173,8 @@ def mill_undercut( dy=det.features[0].feature_m.y, beam_type=settings.image.beam_type ) + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # Align ion so it is coincident with the electron beam settings.image.beam_type = BeamType.ION @@ -176,6 +190,8 @@ def mill_undercut( dy=-det.features[0].feature_m.y, ) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # lamella should now be centred in ion beam settings.image.hfw = fcfg.REFERENCE_HFW_MEDIUM @@ -184,6 +200,7 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") method = settings.protocol.get("method", "autolamella-waffle") lamella.protocol["undercut"] = deepcopy(settings.protocol["undercut"]) @@ -201,6 +218,8 @@ def mill_undercut( _update_status_ui(parent_ui, f"{lamella.info} Tilting to Undercut Position...") microscope.move_stage_relative(FibsemStagePosition(t=np.deg2rad(UNDERCUT_ANGLE_DEG))) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # detect log_status_message(lamella, f"ALIGN_UNDERCUT_{_n}") settings.image.beam_type = BeamType.ION @@ -210,6 +229,7 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # get pattern scan_rotation = microscope.get("scan_rotation", beam_type=BeamType.ION) features = [LamellaTopEdge() if np.isclose(scan_rotation, 0) else LamellaBottomEdge()] @@ -236,6 +256,8 @@ def mill_undercut( msg=f"Press Run Milling to mill the Undercut {_n} for {lamella._petname}. Press Continue when done.", validate=validate, ) + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") undercut_stages.append(stages[0]) @@ -253,6 +275,8 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # optional return flat to electron beam (autoliftout) if settings.protocol["options"].get("return_to_eb_after_undercut", False): microscope.move_flat_to_beam(settings, BeamType.ELECTRON, _safe=True) @@ -265,12 +289,16 @@ def mill_undercut( features = [LamellaCentre()] det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # align vertical microscope.eucentric_move( settings, dx=det.features[0].feature_m.x, dy=-det.features[0].feature_m.y, ) + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # take reference images log_status_message(lamella, "REFERENCE_IMAGES") @@ -315,6 +343,8 @@ def mill_feature( settings.image.beam_type = BeamType.ION ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) _ALIGNMENT_ATTEMPTS = int(settings.protocol["lamella"].get("alignment_attempts", 1)) + + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") for i in range(_ALIGNMENT_ATTEMPTS): settings.image.label = f"alignment_target_{lamella.state.stage.name}_{i:02d}" @@ -324,6 +354,7 @@ def mill_feature( reduced_area=lamella.fiducial_area) settings.image.reduced_area = None + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") settings.image.hfw = fcfg.REFERENCE_HFW_SUPER settings.image.label = f"ref_{lamella.state.stage.name}_start" @@ -332,6 +363,8 @@ def mill_feature( _set_images_ui(parent_ui, eb_image, ib_image) _update_status_ui(parent_ui, f"{lamella.info} Preparing {_feature_name}...") + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # define notch/microexpansion log_status_message(lamella, "MILL_FEATURES") @@ -340,6 +373,8 @@ def mill_feature( validate=validate, ) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # log feature stages lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol[_feature_name]["point"] = stages[0].pattern.point.__to_dict__() @@ -357,7 +392,6 @@ def mill_feature( return lamella - def mill_lamella( microscope: FibsemMicroscope, settings: MicroscopeSettings, @@ -382,6 +416,8 @@ def mill_lamella( ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) _ALIGNMENT_ATTEMPTS = int(settings.protocol["lamella"].get("alignment_attempts", 1)) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + for i in range(_ALIGNMENT_ATTEMPTS): settings.image.label = f"alignment_target_{lamella.state.stage.name}_{i:02d}" settings.image.beam_type = BeamType.ION @@ -391,12 +427,15 @@ def mill_lamella( settings.image.reduced_area = None + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # take reference images _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") settings.image.label = f"ref_{lamella.state.stage.name}_start" eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # define feature log_status_message(lamella, "MILL_LAMELLA") @@ -431,6 +470,8 @@ def mill_lamella( validate=validate, ) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # TODO: refactor this so it is like the original protocol lamella.protocol[lamella.state.stage.name] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol[lamella.state.stage.name]["point"] = stages[0].pattern.point.__to_dict__() @@ -484,6 +525,8 @@ def setup_lamella( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # load the default protocol unless in lamella protocol protocol = lamella.protocol if "lamella" in lamella.protocol else settings.protocol lamella_position = Point.__from_dict__(protocol["lamella"].get("point", {"x": 0, "y": 0})) @@ -513,6 +556,8 @@ def setup_lamella( validate=True, # always validate, until we fix milling issue milling_enabled=False) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + from pprint import pprint print("-"*80) pprint(stages) @@ -538,6 +583,8 @@ def setup_lamella( deepcopy(stages[-n_fiducial].pattern.point), lamella.protocol["fiducial"]["stages"][0]["height"]) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # mill the fiducial fiducial_stage = patterning._get_milling_stages("fiducial", lamella.protocol, Point.__from_dict__(lamella.protocol["fiducial"]["point"])) stages =_validate_mill_ui(fiducial_stage, parent_ui, @@ -548,6 +595,8 @@ def setup_lamella( settings.image.reduced_area = lamella.fiducial_area print(f"REDUCED_AREA: ", lamella.fiducial_area) + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + # for alignment settings.image.beam_type = BeamType.ION settings.image.save = True @@ -557,6 +606,8 @@ def setup_lamella( ib_image = acquire.new_image(microscope, settings.image) settings.image.reduced_area = None + # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + log_status_message(lamella, "REFERENCE_IMAGES") _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") diff --git a/autolamella/workflows/ui.py b/autolamella/workflows/ui.py index 21fb21f7..11b93ccd 100644 --- a/autolamella/workflows/ui.py +++ b/autolamella/workflows/ui.py @@ -15,6 +15,10 @@ # CORE UI FUNCTIONS -> PROBS SEPARATE FILE +def _check_for_abort(parent_ui: AutoLamellaUI, msg: str = "Workflow aborted by user.") -> bool: + if parent_ui._ABORT_THREAD: + raise InterruptedError(msg) + def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLamellaUI, msg, validate: bool,milling_enabled: bool = True): _update_mill_stages_ui(parent_ui, stages=stages) @@ -44,6 +48,8 @@ def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLamellaUI def _update_mill_stages_ui( parent_ui: AutoLamellaUI, stages: list[FibsemMillingStage] = None ): + _check_for_abort(parent_ui, msg = f"Workflow aborted by user.") + INFO = { "msg": "Updating Milling Stages", "pos": None, @@ -96,6 +102,8 @@ def _set_images_ui( eb_image: FibsemImage = None, ib_image: FibsemImage = None, ): + _check_for_abort(parent_ui, msg = f"Workflow aborted by user.") + INFO = { "msg": "Updating Images", "pos": None, @@ -110,6 +118,9 @@ def _set_images_ui( def _update_status_ui(parent_ui: AutoLamellaUI, msg: str): + + _check_for_abort(parent_ui, msg = f"Workflow aborted by user.") + INFO = { "msg": msg, "pos": None, From 482d111d79e330a9d11057889ea446761b28b067 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 16:26:51 +1000 Subject: [PATCH 03/39] working autoliftout test --- autolamella/liftout/autoliftout.py | 217 +----------------- autolamella/liftout/config/config.py | 2 +- autolamella/liftout/protocol/protocol2.yaml | 4 +- .../liftout/protocol/protocol_serial.yaml | 2 +- autolamella/liftout/ui/AutoLiftoutUIv2.py | 18 +- autolamella/protocol/protocol.yaml | 3 +- autolamella/ui/AutoLamellaUI.py | 4 +- autolamella/workflows/core.py | 191 +++++++-------- docs/protocol.md | 3 +- 9 files changed, 104 insertions(+), 340 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 3e005591..354a8584 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -825,221 +825,6 @@ def reset_needle( calibration.set_microscope_state(microscope, lamella.landing_state) return lamella - - -def setup_lamella( - microscope: FibsemMicroscope, - settings: MicroscopeSettings, - lamella: Lamella, - parent_ui: AutoLiftoutUIv2, -) -> Lamella: - - # bookkeeping - validate = settings.protocol["options"]["supervise"].get("setup_lamella", True) - settings.image.save_path = lamella.path - - # move to the initial landing coordinates - if settings.protocol.get("method", "default") == "default": - microscope.set_microscope_state(lamella.landing_state) - - log_status_message(lamella, "MOVE_TO_POSITION") - _update_status_ui(parent_ui, f"{lamella.info} Moving to MillRoughCut Position...") - - # rotate_and_tilt_to_thinning_angle - settings.image.hfw = fcfg.REFERENCE_HFW_MEDIUM - - actions.move_to_lamella_angle(microscope=microscope, protocol=settings.protocol) - - # OFFSET FOR COMPUCENTRIC ROTATION - X_OFFSET = settings.protocol["options"].get("compucentric_x_offset", 0) - Y_OFFSET = settings.protocol["options"].get("compucentric_y_offset", 0) - microscope.stable_move(settings, dx=X_OFFSET, dy=Y_OFFSET, beam_type=BeamType.ELECTRON) - - # load the reference images - reference_images = lamella.get_reference_images(label=f"ref_{AutoLiftoutStage.Landing.name}_final") - - log_status_message(lamella, "ALIGN_LAMELLA") - _update_status_ui(parent_ui, f"{lamella.info} Aligning Reference Images...") - - # alignment.correct_stage_drift( - # microscope, - # settings, - # reference_images=reference_images, - # alignment=(BeamType.ION, BeamType.ION), - # rotate=True, - # xcorr_limit=(512, 512), - # ) - - # TODO: maybe do a detection to align instead - - - # TODO: make sure the hfw = 80e-6 - log_status_message(lamella, "SETUP_PATTERNS") - settings.image.hfw = fcfg.REFERENCE_HFW_SUPER - settings.image.label = f"ref_{lamella.state.stage.name}_start" - settings.image.save = True - eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) - _set_images_ui(parent_ui, eb_image, ib_image) - - - # load the default protocol unless in lamella protocol - protocol = lamella.protocol if "lamella" in lamella.protocol else settings.protocol - lamella_position = Point.__from_dict__(protocol["lamella"].get("point", {"x": 0, "y": 0})) - lamella_stages = patterning._get_milling_stages("lamella", protocol, lamella_position) - stages = deepcopy(lamella_stages) - - # fiducial - protocol = settings.protocol - fiducial_position = Point.__from_dict__(protocol["fiducial"].get("point", {"x": -25e-6, "y": 0})) - fiducial_stage = patterning._get_milling_stages("fiducial", protocol, fiducial_position) - stages += fiducial_stage - - stages =_validate_mill_ui(stages, parent_ui, - msg=f"Confirm the positions for the {lamella._petname} milling. Press Continue to Confirm.", - validate=True, - milling_enabled=False) # TODO: this mills the lamella, but we don't want that - - from pprint import pprint - print("-"*80) - pprint(stages) - print("-"*80) - - # lamella stages - lamella.protocol[AutoLiftoutStage.MillRoughCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[0])) - lamella.protocol[AutoLiftoutStage.MillRoughCut.name]["point"] = stages[0].pattern.point.__to_dict__() - - lamella.protocol[AutoLiftoutStage.MillRegularCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[1])) - lamella.protocol[AutoLiftoutStage.MillRegularCut.name]["point"] = stages[1].pattern.point.__to_dict__() - - lamella.protocol[AutoLiftoutStage.MillPolishingCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[2])) - lamella.protocol[AutoLiftoutStage.MillPolishingCut.name]["point"] = stages[2].pattern.point.__to_dict__() - - # save fiducial information - n_fiducial = len(fiducial_stage) - lamella.protocol["fiducial"] = deepcopy(patterning._get_protocol_from_stages(stages[-n_fiducial:])) - lamella.protocol["fiducial"]["point"] = stages[-n_fiducial].pattern.point.__to_dict__() - fiducial_area, _ = _calculate_fiducial_area_v2(ib_image, - deepcopy(stages[-n_fiducial].pattern.point), - lamella.protocol["fiducial"]["stages"][0]["height"]) - - # mill the fiducial - fiducial_stage = patterning._get_milling_stages("fiducial", lamella.protocol, Point.__from_dict__(lamella.protocol["fiducial"]["point"])) - stages =_validate_mill_ui(fiducial_stage, parent_ui, - msg=f"Milling Fiducial for {lamella._petname}.", - validate=validate) - - lamella.protocol["fiducial"] = deepcopy(patterning._get_protocol_from_stages(stages[0])) - lamella.protocol["fiducial"]["point"] = stages[0].pattern.point.__to_dict__() - lamella.protocol["fiducial"]["area"] = fiducial_area.__to_dict__() - - # set reduced area for fiducial alignment - settings.image.reduced_area = fiducial_area - print(f"REDUCED_AREA: ", fiducial_area) - - # for alignment - settings.image.beam_type = BeamType.ION - settings.image.save = True - settings.image.hfw = fcfg.REFERENCE_HFW_SUPER - settings.image.label = f"ref_alignment" - print(f"REDUCED_AREA: ", settings.image.reduced_area) - ib_image = acquire.new_image(microscope, settings.image) - settings.image.reduced_area = None - - log_status_message(lamella, "REFERENCE_IMAGES") - _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") - - # # take reference images - reference_images = acquire.take_set_of_reference_images( - microscope, - settings.image, - hfws=[fcfg.REFERENCE_HFW_HIGH, fcfg.REFERENCE_HFW_SUPER], - label=f"ref_{lamella.state.stage.name}_final", - ) - _set_images_ui(parent_ui, reference_images.high_res_eb, reference_images.high_res_ib) - - settings.image.hfw = fcfg.REFERENCE_HFW_ULTRA - settings.image.save = True - settings.image.label = f"ref_{lamella.state.stage.name}_final_ultra_res" - eb_image, ib_image = acquire.take_reference_images(microscope=microscope, image_settings=settings.image) - - return lamella - -def mill_lamella( - microscope: FibsemMicroscope, - settings: MicroscopeSettings, - lamella: Lamella, - parent_ui: AutoLiftoutUIv2 = None, -) -> Lamella: - - # validate = settings.protocol["options"]["supervise"].get("lamella", True) - settings.image.save_path = lamella.path - - # beam_shift alignment - log_status_message(lamella, "ALIGN_LAMELLA") - _update_status_ui(parent_ui, f"{lamella.info} Aligning Reference Images...") - - - fiducial_area = FibsemRectangle.__from_dict__(lamella.protocol["fiducial"]["area"]) - settings.image.save = True - settings.image.hfw = fcfg.REFERENCE_HFW_SUPER - settings.image.beam_type = BeamType.ION - settings.image.label = f"alignment_target_{lamella.state.stage.name}" - ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) - settings.image.beam_type = BeamType.ION - alignment.beam_shift_alignment(microscope, settings.image, - ref_image=ref_image, - reduced_area=fiducial_area) - - settings.image.reduced_area = None - - # take reference images - _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") - settings.image.label = f"ref_{lamella.state.stage.name}_start" - eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) - _set_images_ui(parent_ui, eb_image, ib_image) - - - # define feature - log_status_message(lamella, "MILL_LAMELLA") - stages = patterning._get_milling_stages( - lamella.state.stage.name, - lamella.protocol, - point=Point.__from_dict__(lamella.protocol[lamella.state.stage.name]["point"]) - ) - - supervise_map = { - AutoLiftoutStage.MillRoughCut: "mill_rough", - AutoLiftoutStage.MillRegularCut: "mill_regular", - AutoLiftoutStage.MillPolishingCut: "mill_polishing", - } - - validate = settings.protocol["options"]["supervise"].get(supervise_map[lamella.state.stage], True) - - # idx = stage_map[lamella.state.stage] - # stages = stages[idx] - - stages = _validate_mill_ui(stages, parent_ui, - msg=f"Press Run Milling ({lamella.state.stage.name}) to mill the Trenches for {lamella._petname}. Press Continue when done.", - validate=validate, - ) - - lamella.protocol[lamella.state.stage.name] = deepcopy(patterning._get_protocol_from_stages(stages)) - lamella.protocol[lamella.state.stage.name]["point"] = stages[0].pattern.point.__to_dict__() - - # take reference images - log_status_message(lamella, "REFERENCE_IMAGES") - _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") - reference_images = acquire.take_set_of_reference_images( - microscope=microscope, - image_settings=settings.image, - hfws=[fcfg.REFERENCE_HFW_HIGH, fcfg.REFERENCE_HFW_SUPER], - label=f"ref_{lamella.state.stage.name}_final", - ) - _set_images_ui(parent_ui, reference_images.high_res_eb, reference_images.high_res_ib) - - return lamella - - def run_setup_autoliftout( microscope: FibsemMicroscope, settings: MicroscopeSettings, @@ -1053,7 +838,7 @@ def run_setup_autoliftout( return experiment -from autolamella.workflows.core import mill_trench, mill_undercut +from autolamella.workflows.core import mill_trench, mill_undercut, mill_lamella, setup_lamella # autoliftout_workflow WORKFLOW_STAGES = { AutoLiftoutStage.Setup: run_setup_autoliftout, # TODO: split this further diff --git a/autolamella/liftout/config/config.py b/autolamella/liftout/config/config.py index 9ba96921..8e647e71 100644 --- a/autolamella/liftout/config/config.py +++ b/autolamella/liftout/config/config.py @@ -11,7 +11,7 @@ LOG_PATH = os.path.join(BASE_PATH, "log") EXPERIMENT_NAME = "AutoLiftout" -__AUTOLIFTOUT_METHODS__ = ["default", "serial-liftout"] +__AUTOLIFTOUT_METHODS__ = ["autoliftout-default", "autoliftout-serial-liftout"] __AUTOLIFTOUT_LIFTOUT_JOIN_METHODS__ = ["None", "Weld", "Platinum"] __AUTOLIFTOUT_LANDING_JOIN_METHODS__ = ["Weld"] diff --git a/autolamella/liftout/protocol/protocol2.yaml b/autolamella/liftout/protocol/protocol2.yaml index 2578586c..fcb0a1e5 100644 --- a/autolamella/liftout/protocol/protocol2.yaml +++ b/autolamella/liftout/protocol/protocol2.yaml @@ -44,7 +44,7 @@ ml: num_classes: 3 checkpoint: openfibsem-baseline-34.pt name: autoliftout-base-protocol -method: default +method: autoliftout-default options: batch_mode: true confirm_advance: true @@ -56,6 +56,7 @@ options: compucentric_x_offset: 50.0e-6 compucentric_y_offset: 25.0e-6 return_to_eb_after_undercut: True + alignment_attempts: 3.0 supervise: landing: true liftout: true @@ -82,7 +83,6 @@ platinum: hfw: 3.0e-05 length: 7.0e-06 time: 30.0 - sever: cleaning_cross_section: 0.0 depth: 3.0e-06 diff --git a/autolamella/liftout/protocol/protocol_serial.yaml b/autolamella/liftout/protocol/protocol_serial.yaml index 7953da4b..2c4bc5a4 100644 --- a/autolamella/liftout/protocol/protocol_serial.yaml +++ b/autolamella/liftout/protocol/protocol_serial.yaml @@ -29,7 +29,7 @@ ml: num_classes: 3 checkpoint: openfibsem-baseline-34.pt name: autoliftout-serial-protocol -method: serial-liftout +method: autoliftout-serial-liftout options: batch_mode: true confirm_advance: true diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index d57fab97..c7c00076 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -87,6 +87,7 @@ def __init__(self, viewer: napari.Viewer = None): self.USER_RESPONSE: bool = False self.WAITING_FOR_UI_UPDATE: bool = False self._WORKFLOW_RUNNING: bool = False + self._ABORT_THREAD: bool = False # setup connections self.setup_connections() @@ -184,14 +185,15 @@ def update_ui(self): _LAMELLA_UNDERCUT = _counter[AutoLiftoutStage.MillUndercut.name] > 0 _LIFTOUT_FINISHED = _counter[AutoLiftoutStage.Liftout.name] > 0 _LAMELLA_LANDED = _counter[AutoLiftoutStage.Landing.name] > 0 - _AUTOLAMELLA_PROGRESS = (_counter[AutoLiftoutStage.MillRoughCut.name] > 0 + _AUTOLAMELLA_PROGRESS = (_counter[AutoLiftoutStage.SetupPolish.name]>0 + or _counter[AutoLiftoutStage.MillRoughCut.name] > 0 or _counter[AutoLiftoutStage.MillRegularCut.name] > 0 or _counter[AutoLiftoutStage.MillPolishingCut.name] > 0) # setup experiment -> connect to microscope -> select lamella -> run autoliftout -> run polishing # METHOD - _METHOD = self.settings.protocol.get("method", "default") if _protocol_loaded else "default" + _METHOD = self.settings.protocol.get("method", "autoliftout-default") if _protocol_loaded else "autoliftout-default" # experiment loaded self.actionConnect_Microscope.setVisible(_experiment_loaded) @@ -201,14 +203,14 @@ def update_ui(self): # workflow buttons _SETUP_ENABLED = _microscope_connected and _protocol_loaded - _AUTOLIFTOUT_ENABLED = (_LAMELLA_SETUP or _LAMELLA_TRENCH or _LAMELLA_UNDERCUT or (_LIFTOUT_FINISHED and _METHOD=="default")) and _microscope_connected and _protocol_loaded + _AUTOLIFTOUT_ENABLED = (_LAMELLA_SETUP or _LAMELLA_TRENCH or _LAMELLA_UNDERCUT or (_LIFTOUT_FINISHED and _METHOD=="autoliftout-default")) and _microscope_connected and _protocol_loaded _SERIAL_LIFTOUT_LANDING_ENABLED = _LIFTOUT_FINISHED and _microscope_connected and _protocol_loaded _AUTOLAMELLA_ENABLED = (_LAMELLA_LANDED or _AUTOLAMELLA_PROGRESS) and _microscope_connected and _protocol_loaded self.pushButton_setup_autoliftout.setEnabled(_SETUP_ENABLED) self.pushButton_run_autoliftout.setEnabled(_AUTOLIFTOUT_ENABLED) self.pushButton_run_serial_liftout_landing.setEnabled(_SERIAL_LIFTOUT_LANDING_ENABLED) - self.pushButton_run_serial_liftout_landing.setVisible(_METHOD=="serial-liftout") + self.pushButton_run_serial_liftout_landing.setVisible(_METHOD=="autoliftout-serial-liftout") self.pushButton_run_polishing.setEnabled(_AUTOLAMELLA_ENABLED) # set stylesheets @@ -398,7 +400,7 @@ def update_ui_from_protocol(self, protocol: dict): # meta self.lineEdit_protocol_name.setText(self.settings.protocol.get("name", "autoliftout")) - self.comboBox_protocol_method.setCurrentText(self.settings.protocol.get("method", "default")) + self.comboBox_protocol_method.setCurrentText(self.settings.protocol.get("method", "autoliftout-default")) # options @@ -715,16 +717,16 @@ def _threaded_worker(self, microscope, settings, experiment, workflow="setup"): ) elif workflow == "autoliftout": - _METHOD = self.settings.protocol.get("method", "default") + _METHOD = self.settings.protocol.get("method", "autoliftout-default") - if _METHOD == "default": + if _METHOD == "autoliftout-default": self.experiment = autoliftout.run_autoliftout_workflow( microscope=microscope, settings=settings, experiment=experiment, parent_ui=self, ) - if _METHOD == "serial-liftout": + if _METHOD == "autoliftout-serial-liftout": from autolamella.liftout.workflows import serial as serial_workflow self.experiment = serial_workflow.run_serial_liftout_workflow( microscope=microscope, diff --git a/autolamella/protocol/protocol.yaml b/autolamella/protocol/protocol.yaml index 9f358a3a..2f94c752 100644 --- a/autolamella/protocol/protocol.yaml +++ b/autolamella/protocol/protocol.yaml @@ -24,7 +24,6 @@ fiducial: width: 1.0e-06 type: Fiducial lamella: - alignment_attempts: 3.0 lamella_height: 8.0e-07 lamella_width: 1.0e-05 stages: @@ -98,6 +97,8 @@ notch: vwidth: 2.0e-07 type: WaffleNotch options: + alignment_attempts: 3.0 + return_to_eb_after_undercut: False compucentric_x_offset: 50.0e-6 compucentric_y_offset: 25.0e-6 supervise: diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index 7c9dfc3a..75b9fee3 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -171,7 +171,7 @@ def update_protocol_ui(self): self.lineEdit_name.setText(self.settings.protocol["name"]) - self.beamshift_attempts.setValue(self.settings.protocol["lamella"]["alignment_attempts"]) + self.beamshift_attempts.setValue(self.settings.protocol["options"].get("alignment_attempts", 3)) self.doubleSpinBox_undercut_tilt.setValue(self.settings.protocol["undercut"]["tilt_angle"]) self.doubleSpinBox_undercut_step.setValue(self.settings.protocol["undercut"]["tilt_angle_step"]) @@ -203,7 +203,7 @@ def export_protocol_ui(self): if self._PROTOCOL_LOADED is False: return self.settings.protocol["name"] = self.lineEdit_name.text() - self.settings.protocol["lamella"]["alignment_attempts"] = int(self.beamshift_attempts.value()) + self.settings.protocol["options"]["alignment_attempts"] = int(self.beamshift_attempts.value()) self.settings.protocol["undercut"]["tilt_angle"] = self.doubleSpinBox_undercut_tilt.value() self.settings.protocol["undercut"]["tilt_angle_step"] = int(self.doubleSpinBox_undercut_step.value()) self.settings.protocol["notch"]["enabled"] = bool(self.comboBox_stress_relief.currentIndex() == 0) diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 27c56981..638d725b 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -58,7 +58,7 @@ from autolamella.ui.AutoLamellaUI import AutoLamellaUI from fibsem import config as fcfg -from autolamella.workflows.ui import (_set_images_ui, _update_status_ui, _validate_det_ui_v2, _validate_mill_ui, _check_for_abort) +from autolamella.workflows.ui import (_set_images_ui, _update_status_ui, _validate_det_ui_v2, _validate_mill_ui) # CORE WORKFLOW STEPS @@ -85,8 +85,6 @@ def mill_trench( _set_images_ui(parent_ui, eb_image, ib_image) _update_status_ui(parent_ui, f"{lamella.info} Preparing Trench...") - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # define trench milling stage settings.image.beam_type = BeamType.ION stages = patterning._get_milling_stages("trench", lamella.protocol, point=Point.__from_dict__(lamella.protocol["trench"]["point"])) @@ -95,8 +93,6 @@ def mill_trench( validate=validate, ) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # log the protocol lamella.protocol["trench"] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol["trench"]["point"] = stages[0].pattern.point.__to_dict__() @@ -107,8 +103,6 @@ def mill_trench( settings.image.beam_type = BeamType.ELECTRON calibration.auto_charge_neutralisation(microscope, settings.image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # refernce images log_status_message(lamella, "REFERENCE_IMAGES") reference_images = acquire.take_set_of_reference_images( @@ -143,14 +137,11 @@ def mill_undercut( _update_status_ui(parent_ui, f"{lamella.info} Moving to Undercut Position...") microscope.move_flat_to_beam(settings, BeamType.ELECTRON, _safe=True) # TODO: TEST UNSAFE MOVE - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # OFFSET FOR COMPUCENTRIC ROTATION X_OFFSET = settings.protocol["options"].get("compucentric_x_offset", 0) Y_OFFSET = settings.protocol["options"].get("compucentric_y_offset", 0) microscope.stable_move(settings, dx=X_OFFSET, dy=Y_OFFSET, beam_type=BeamType.ELECTRON) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # detect log_status_message(lamella, f"ALIGN_TRENCH") @@ -162,8 +153,6 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - features = [LamellaCentre()] det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info, position=lamella.state.microscope_state.absolute_position) @@ -174,8 +163,6 @@ def mill_undercut( beam_type=settings.image.beam_type ) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # Align ion so it is coincident with the electron beam settings.image.beam_type = BeamType.ION settings.image.hfw = fcfg.REFERENCE_HFW_MEDIUM @@ -190,8 +177,6 @@ def mill_undercut( dy=-det.features[0].feature_m.y, ) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # lamella should now be centred in ion beam settings.image.hfw = fcfg.REFERENCE_HFW_MEDIUM @@ -200,13 +185,11 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - method = settings.protocol.get("method", "autolamella-waffle") lamella.protocol["undercut"] = deepcopy(settings.protocol["undercut"]) N_UNDERCUTS = int(lamella.protocol["undercut"].get("tilt_angle_step", 1)) UNDERCUT_ANGLE_DEG = lamella.protocol["undercut"].get("tilt_angle", -5) - _UNDERCUT_V_OFFSET = lamella.protocol["undercut"].get("v_offset", 1e-6) + _UNDERCUT_V_OFFSET = lamella.protocol["undercut"].get("v_offset", 0e-6) undercut_stages = [] for i in range(N_UNDERCUTS): @@ -218,8 +201,6 @@ def mill_undercut( _update_status_ui(parent_ui, f"{lamella.info} Tilting to Undercut Position...") microscope.move_stage_relative(FibsemStagePosition(t=np.deg2rad(UNDERCUT_ANGLE_DEG))) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # detect log_status_message(lamella, f"ALIGN_UNDERCUT_{_n}") settings.image.beam_type = BeamType.ION @@ -229,7 +210,6 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # get pattern scan_rotation = microscope.get("scan_rotation", beam_type=BeamType.ION) features = [LamellaTopEdge() if np.isclose(scan_rotation, 0) else LamellaBottomEdge()] @@ -257,8 +237,6 @@ def mill_undercut( validate=validate, ) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - undercut_stages.append(stages[0]) # log undercut stages @@ -275,8 +253,6 @@ def mill_undercut( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # optional return flat to electron beam (autoliftout) if settings.protocol["options"].get("return_to_eb_after_undercut", False): microscope.move_flat_to_beam(settings, BeamType.ELECTRON, _safe=True) @@ -289,8 +265,6 @@ def mill_undercut( features = [LamellaCentre()] det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # align vertical microscope.eucentric_move( settings, @@ -298,8 +272,6 @@ def mill_undercut( dy=-det.features[0].feature_m.y, ) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # take reference images log_status_message(lamella, "REFERENCE_IMAGES") _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") @@ -326,12 +298,10 @@ def mill_feature( validate = settings.protocol["options"]["supervise"].get("features", True) settings.image.save_path = lamella.path - - if settings.protocol["fiducial"]["enabled"] is False: - lamella.fiducial_area = None + method = settings.protocol.get("method", "autolamella-waffle") # check if using notch or microexpansion - _feature_name = "notch" if settings.protocol["notch"]["enabled"] else "microexpansion" + _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" stages = patterning._get_milling_stages( _feature_name, lamella.protocol, point=Point.__from_dict__(lamella.protocol[_feature_name]["point"]) @@ -342,10 +312,8 @@ def mill_feature( settings.image.hfw = fcfg.REFERENCE_HFW_SUPER settings.image.beam_type = BeamType.ION ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) - _ALIGNMENT_ATTEMPTS = int(settings.protocol["lamella"].get("alignment_attempts", 1)) + _ALIGNMENT_ATTEMPTS = int(settings.protocol["options"].get("alignment_attempts", 3)) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - for i in range(_ALIGNMENT_ATTEMPTS): settings.image.label = f"alignment_target_{lamella.state.stage.name}_{i:02d}" settings.image.beam_type = BeamType.ION @@ -354,8 +322,6 @@ def mill_feature( reduced_area=lamella.fiducial_area) settings.image.reduced_area = None - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - settings.image.hfw = fcfg.REFERENCE_HFW_SUPER settings.image.label = f"ref_{lamella.state.stage.name}_start" settings.image.save = True @@ -363,8 +329,6 @@ def mill_feature( _set_images_ui(parent_ui, eb_image, ib_image) _update_status_ui(parent_ui, f"{lamella.info} Preparing {_feature_name}...") - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # define notch/microexpansion log_status_message(lamella, "MILL_FEATURES") @@ -373,8 +337,6 @@ def mill_feature( validate=validate, ) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - # log feature stages lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol[_feature_name]["point"] = stages[0].pattern.point.__to_dict__() @@ -406,17 +368,15 @@ def mill_lamella( _update_status_ui(parent_ui, f"{lamella.info} Aligning Reference Images...") # take reference image after milling fiducial - use_fiducial = settings.protocol["fiducial"]["enabled"] - if use_fiducial is False: - lamella.fiducial_area = None # TODO: make this better + # use_fiducial = settings.protocol["fiducial"].get("enabled", True) + # if use_fiducial is False: + # lamella.fiducial_area = None # TODO: make this better settings.image.save = True settings.image.hfw = fcfg.REFERENCE_HFW_SUPER settings.image.beam_type = BeamType.ION ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) - _ALIGNMENT_ATTEMPTS = int(settings.protocol["lamella"].get("alignment_attempts", 1)) - - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") + _ALIGNMENT_ATTEMPTS = int(settings.protocol["options"].get("alignment_attempts", 1)) for i in range(_ALIGNMENT_ATTEMPTS): settings.image.label = f"alignment_target_{lamella.state.stage.name}_{i:02d}" @@ -427,7 +387,6 @@ def mill_lamella( settings.image.reduced_area = None - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # take reference images _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") @@ -435,7 +394,6 @@ def mill_lamella( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # define feature log_status_message(lamella, "MILL_LAMELLA") @@ -445,19 +403,19 @@ def mill_lamella( # filter stage based on the current stage stage_map = { - AutoLamellaWaffleStage.MillRoughCut: 0, - AutoLamellaWaffleStage.MillRegularCut: 1, - AutoLamellaWaffleStage.MillPolishingCut: 2, + AutoLamellaWaffleStage.MillRoughCut.name: 0, + AutoLamellaWaffleStage.MillRegularCut.name: 1, + AutoLamellaWaffleStage.MillPolishingCut.name: 2, } supervise_map = { - AutoLamellaWaffleStage.MillRoughCut: "mill_rough", - AutoLamellaWaffleStage.MillRegularCut: "mill_regular", - AutoLamellaWaffleStage.MillPolishingCut: "mill_polishing", + AutoLamellaWaffleStage.MillRoughCut.name: "mill_rough", + AutoLamellaWaffleStage.MillRegularCut.name: "mill_regular", + AutoLamellaWaffleStage.MillPolishingCut.name: "mill_polishing", } - validate = settings.protocol["options"]["supervise"].get(supervise_map[lamella.state.stage], True) + validate = settings.protocol["options"]["supervise"].get(supervise_map[lamella.state.stage.name], True) - idx = stage_map[lamella.state.stage] + idx = stage_map[lamella.state.stage.name] if idx in [0, 1]: stages = [stages[idx]] else: @@ -469,9 +427,7 @@ def mill_lamella( msg=f"Press Run Milling to mill the Trenches for {lamella._petname}. Press Continue when done.", validate=validate, ) - - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - + # TODO: refactor this so it is like the original protocol lamella.protocol[lamella.state.stage.name] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol[lamella.state.stage.name]["point"] = stages[0].pattern.point.__to_dict__() @@ -514,9 +470,23 @@ def setup_lamella( validate = settings.protocol["options"]["supervise"].get("setup_lamella", True) settings.image.save_path = lamella.path + method = settings.protocol.get("method", "autolamella-waffle") + + + log_status_message(lamella, "ALIGN_LAMELLA") + _update_status_ui(parent_ui, f"{lamella.info} Aligning Lamella...") + + if method == "autoliftout-default": + from autolamella.liftout import actions - # if settings.protocol.get("method", "autolamella-waffle") == "autolamella-waffle": - # lamella = _align_lamella_coincident(microscope, settings, lamella, parent_ui, validate) + actions.move_to_lamella_angle(microscope, settings.protocol) + # OFFSET FOR COMPUCENTRIC ROTATION + X_OFFSET = settings.protocol["options"].get("compucentric_x_offset", 0) + Y_OFFSET = settings.protocol["options"].get("compucentric_y_offset", 0) + microscope.stable_move(settings, dx=X_OFFSET, dy=Y_OFFSET, beam_type=BeamType.ELECTRON) + + if method != "autolamella-default": + lamella = _align_lamella_coincident(microscope, settings, lamella, parent_ui, validate) log_status_message(lamella, "SETUP_PATTERNS") settings.image.hfw = fcfg.REFERENCE_HFW_SUPER @@ -525,8 +495,7 @@ def setup_lamella( eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - + # load the default protocol unless in lamella protocol protocol = lamella.protocol if "lamella" in lamella.protocol else settings.protocol lamella_position = Point.__from_dict__(protocol["lamella"].get("point", {"x": 0, "y": 0})) @@ -534,30 +503,31 @@ def setup_lamella( stages = deepcopy(lamella_stages) # feature - _feature_name = "notch" if settings.protocol["notch"]["enabled"] else "microexpansion" - protocol = lamella.protocol if _feature_name in lamella.protocol else settings.protocol - NOTCH_H_OFFSET = 0.5e-6 - feature_position = Point.__from_dict__(protocol[_feature_name].get("point", - {"x":lamella_position.x + stages[0].pattern.protocol["lamella_width"] / 2 + NOTCH_H_OFFSET, - "y": lamella_position.y} if _feature_name == "notch" else {"x": 0, "y": 0})) - feature_stage = patterning._get_milling_stages(_feature_name, protocol, feature_position) - stages += feature_stage + if method == "autolamella-waffle": + _feature_name = "notch" + protocol = lamella.protocol if _feature_name in lamella.protocol else settings.protocol + NOTCH_H_OFFSET = 0.5e-6 + feature_position = Point.__from_dict__(protocol[_feature_name].get("point", + {"x":lamella_position.x + stages[0].pattern.protocol["lamella_width"] / 2 + NOTCH_H_OFFSET, + "y": lamella_position.y} if _feature_name == "notch" else {"x": 0, "y": 0})) + feature_stage = patterning._get_milling_stages(_feature_name, protocol, feature_position) + stages += feature_stage # fiducial - if use_fiducial := settings.protocol["fiducial"]["enabled"]: - protocol = lamella.protocol if "fiducial" in lamella.protocol else settings.protocol - fiducial_position = Point.__from_dict__(protocol["fiducial"].get("point", {"x": 25e-6, "y": 0})) - fiducial_stage = patterning._get_milling_stages("fiducial", protocol, fiducial_position) - stages += fiducial_stage + protocol = lamella.protocol if "fiducial" in lamella.protocol else settings.protocol + FIDUCIAL_X_OFFSET = 25e-6 + if method == "autoliftout-default": + FIDUCIAL_X_OFFSET *= -1 + fiducial_position = Point.__from_dict__(protocol["fiducial"].get("point", {"x": FIDUCIAL_X_OFFSET, "y": 0})) + fiducial_stage = patterning._get_milling_stages("fiducial", protocol, fiducial_position) + stages += fiducial_stage if validate: stages =_validate_mill_ui(stages, parent_ui, msg=f"Confirm the positions for the {lamella._petname} milling. Press Continue to Confirm.", validate=True, # always validate, until we fix milling issue milling_enabled=False) - - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - + from pprint import pprint print("-"*80) pprint(stages) @@ -568,34 +538,41 @@ def setup_lamella( lamella.protocol["lamella"] = deepcopy(patterning._get_protocol_from_stages(stages[:n_lamella])) lamella.protocol["lamella"]["point"] = stages[0].pattern.point.__to_dict__() +# # TODO: integrate this style +# # lamella.protocol[AutoLiftoutStage.MillRoughCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[0])) +# # lamella.protocol[AutoLiftoutStage.MillRoughCut.name]["point"] = stages[0].pattern.point.__to_dict__() + +# # lamella.protocol[AutoLiftoutStage.MillRegularCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[1])) +# # lamella.protocol[AutoLiftoutStage.MillRegularCut.name]["point"] = stages[1].pattern.point.__to_dict__() + +# # lamella.protocol[AutoLiftoutStage.MillPolishingCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[2])) +# # lamella.protocol[AutoLiftoutStage.MillPolishingCut.name]["point"] = stages[2].pattern.point.__to_dict__() + # feature - n_features = len(feature_stage) - lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages[n_lamella:n_lamella+n_features])) - lamella.protocol[_feature_name]["point"] = stages[n_lamella].pattern.point.__to_dict__() + if method == "autolamella-waffle": + n_features = len(feature_stage) + lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages[n_lamella:n_lamella+n_features])) + lamella.protocol[_feature_name]["point"] = stages[n_lamella].pattern.point.__to_dict__() # fiducial - if use_fiducial: - # save fiducial information - n_fiducial = len(fiducial_stage) - lamella.protocol["fiducial"] = deepcopy(patterning._get_protocol_from_stages(stages[-n_fiducial:])) - lamella.protocol["fiducial"]["point"] = stages[-n_fiducial].pattern.point.__to_dict__() - lamella.fiducial_area, _ = _calculate_fiducial_area_v2(ib_image, - deepcopy(stages[-n_fiducial].pattern.point), - lamella.protocol["fiducial"]["stages"][0]["height"]) - - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") - - # mill the fiducial - fiducial_stage = patterning._get_milling_stages("fiducial", lamella.protocol, Point.__from_dict__(lamella.protocol["fiducial"]["point"])) - stages =_validate_mill_ui(fiducial_stage, parent_ui, - msg=f"Press Run Milling to mill the fiducial for {lamella._petname}. Press Continue when done.", - validate=validate) - - # set reduced area for fiducial alignment - settings.image.reduced_area = lamella.fiducial_area - print(f"REDUCED_AREA: ", lamella.fiducial_area) + # save fiducial information + n_fiducial = len(fiducial_stage) + lamella.protocol["fiducial"] = deepcopy(patterning._get_protocol_from_stages(stages[-n_fiducial:])) + lamella.protocol["fiducial"]["point"] = stages[-n_fiducial].pattern.point.__to_dict__() + lamella.fiducial_area, _ = _calculate_fiducial_area_v2(ib_image, + deepcopy(stages[-n_fiducial].pattern.point), + lamella.protocol["fiducial"]["stages"][0]["height"]) + + # mill the fiducial + fiducial_stage = patterning._get_milling_stages("fiducial", lamella.protocol, Point.__from_dict__(lamella.protocol["fiducial"]["point"])) + stages =_validate_mill_ui(fiducial_stage, parent_ui, + msg=f"Press Run Milling to mill the fiducial for {lamella._petname}. Press Continue when done.", + validate=validate) + + # set reduced area for fiducial alignment + settings.image.reduced_area = lamella.fiducial_area + print(f"REDUCED_AREA: ", lamella.fiducial_area) - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") # for alignment settings.image.beam_type = BeamType.ION @@ -605,8 +582,6 @@ def setup_lamella( print(f"REDUCED_AREA: ", settings.image.reduced_area) ib_image = acquire.new_image(microscope, settings.image) settings.image.reduced_area = None - - # _check_for_abort(parent_ui, msg = f"Aborted {lamella.info}") log_status_message(lamella, "REFERENCE_IMAGES") _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") diff --git a/docs/protocol.md b/docs/protocol.md index da9387e6..090b788f 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -36,6 +36,8 @@ ml: # machine learning parameters num_classes: 3 checkpoint: model4.pt #model4.pt options: + return_to_eb_after_undercut: True + alignment_attempts: 3 supervise: features: false lamella: true @@ -78,7 +80,6 @@ fiducial: rotation: 45 width: 1.0e-06 lamella: - alignment_attempts: 3.0 lamella_height: 8.0e-07 lamella_width: 1.0e-05 stages: From d80b735d876353277667ecd7b2488eb7bdd96c2d Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 16:55:10 +1000 Subject: [PATCH 04/39] refactor setuppolish->setuplamella for consistency --- autolamella/liftout/autoliftout.py | 4 ++-- autolamella/liftout/structures.py | 2 +- autolamella/liftout/ui/AutoLiftoutUIv2.py | 2 +- autolamella/liftout/workflows/serial.py | 2 +- autolamella/workflows/core.py | 5 ----- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 354a8584..cfcd2085 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -846,7 +846,7 @@ def run_setup_autoliftout( AutoLiftoutStage.MillUndercut: mill_undercut, AutoLiftoutStage.Liftout: liftout_lamella, AutoLiftoutStage.Landing: land_lamella, - AutoLiftoutStage.SetupPolish: setup_lamella, + AutoLiftoutStage.SetupLamella: setup_lamella, AutoLiftoutStage.MillRoughCut: mill_lamella, AutoLiftoutStage.MillRegularCut: mill_lamella, AutoLiftoutStage.MillPolishingCut: mill_lamella, @@ -1012,7 +1012,7 @@ def run_thinning_workflow( _update_status_ui(parent_ui, "Starting MillRoughCut Workflow...") lamella: Lamella for next_stage in [ - AutoLiftoutStage.SetupPolish, + AutoLiftoutStage.SetupLamella, AutoLiftoutStage.MillRoughCut, AutoLiftoutStage.MillRegularCut, AutoLiftoutStage.MillPolishingCut, diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index bcfc1026..f165143b 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -22,7 +22,7 @@ class AutoLiftoutStage(Enum): MillUndercut = auto() Liftout = auto() Landing = auto() - SetupPolish = auto() + SetupLamella = auto() MillRoughCut = auto() MillRegularCut = auto() MillPolishingCut = auto() diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index c7c00076..70fe7158 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -185,7 +185,7 @@ def update_ui(self): _LAMELLA_UNDERCUT = _counter[AutoLiftoutStage.MillUndercut.name] > 0 _LIFTOUT_FINISHED = _counter[AutoLiftoutStage.Liftout.name] > 0 _LAMELLA_LANDED = _counter[AutoLiftoutStage.Landing.name] > 0 - _AUTOLAMELLA_PROGRESS = (_counter[AutoLiftoutStage.SetupPolish.name]>0 + _AUTOLAMELLA_PROGRESS = (_counter[AutoLiftoutStage.SetupLamella.name]>0 or _counter[AutoLiftoutStage.MillRoughCut.name] > 0 or _counter[AutoLiftoutStage.MillRegularCut.name] > 0 or _counter[AutoLiftoutStage.MillPolishingCut.name] > 0) diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index fe7bf5cd..07de274d 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -408,7 +408,7 @@ def land_lamella( AutoLiftoutStage.MillUndercut: mill_undercut, AutoLiftoutStage.Liftout: liftout_lamella, AutoLiftoutStage.Landing: land_lamella, - AutoLiftoutStage.SetupPolish: setup_lamella, + AutoLiftoutStage.SetupLamella: setup_lamella, AutoLiftoutStage.MillRoughCut: mill_lamella, AutoLiftoutStage.MillRegularCut: mill_lamella, AutoLiftoutStage.MillPolishingCut: mill_lamella, diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 638d725b..7027b434 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -367,11 +367,6 @@ def mill_lamella( log_status_message(lamella, "ALIGN_LAMELLA") _update_status_ui(parent_ui, f"{lamella.info} Aligning Reference Images...") - # take reference image after milling fiducial - # use_fiducial = settings.protocol["fiducial"].get("enabled", True) - # if use_fiducial is False: - # lamella.fiducial_area = None # TODO: make this better - settings.image.save = True settings.image.hfw = fcfg.REFERENCE_HFW_SUPER settings.image.beam_type = BeamType.ION From 6be946cc6ea10187b6b408c1b6d35fece5c96cdf Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 17:30:27 +1000 Subject: [PATCH 05/39] updaet contact det in liftout --- autolamella/liftout/autoliftout.py | 89 +++++++++------------ autolamella/liftout/config/config.py | 2 +- autolamella/liftout/protocol/protocol2.yaml | 4 + autolamella/liftout/ui/AutoLiftoutUIv2.py | 9 --- 4 files changed, 41 insertions(+), 63 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index cfcd2085..342159f7 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -7,7 +7,7 @@ import os import napari import numpy as np -from fibsem import acquire, alignment, calibration, gis, milling, patterning +from fibsem import acquire, alignment, calibration, patterning from fibsem import utils as fibsem_utils from fibsem import validation from fibsem.detection import detection @@ -141,30 +141,6 @@ def liftout_lamella( lamella.protocol["join"] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol["join"]["point"] = stages[0].pattern.point.__to_dict__() - if (_JOINING_METHOD == "PLATINUM"): - # sputter platinum - if isinstance(microscope, ThermoMicroscope): - app_files = microscope.get_available_values(key="application_file") - - if settings.protocol["platinum"]["application_file"] not in app_files: - if "Pt dep" in app_files: - default_app_file = "Pt dep" - else: - default_app_file = app_files[0] - else: - default_app_file = settings.protocol["platinum"]["application_file"] - - settings.protocol["platinum"]["application_file"] = default_app_file - - settings.protocol["platinum"]["hfw"] = settings.protocol["platinum"][ - "whole_grid" - ]["hfw"] - gis.sputter_platinum( - microscope, - settings.protocol["platinum"], - default_application_file=settings.milling.application_file, - ) - logging.info( f"{lamella.state.stage.name}: lamella to needle joining complete." ) @@ -281,8 +257,6 @@ def land_needle_on_milled_lamella( microscope, settings, det, beam_type=settings.image.beam_type, move_x=False ) - # _set_images_ui(parent_ui, None, det.image) - # reference images settings.image.hfw = fcfg.REFERENCE_HFW_HIGH settings.image.save = True @@ -297,8 +271,6 @@ def land_needle_on_milled_lamella( pos="Continue", ) - # take image - # charge neutralisation to charge lamella settings.image.beam_type = BeamType.ION n_iter = int( @@ -306,7 +278,8 @@ def land_needle_on_milled_lamella( ) calibration.auto_charge_neutralisation( - microscope, settings.image, + microscope=microscope, + image_settings=settings.image, n_iterations=n_iter, discharge_settings = ImageSettings( resolution=[768, 512], @@ -320,6 +293,37 @@ def land_needle_on_milled_lamella( ) ) + X_LIFTOUT_CONTACT_OFFSET = settings.protocol["options"].get("liftout_contact_offset", 0.25e-6) + features = [NeedleTip(), LamellaLeftEdge()] + det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) + det._offset = Point(x=X_LIFTOUT_CONTACT_OFFSET, y=0) + detection.move_based_on_detection(microscope, settings, det, beam_type=settings.image.beam_type, move_y=False) + + _USE_CONTACT_DETECTION = settings.protocol["options"].get("liftout_contact_detection", False) + if _USE_CONTACT_DETECTION: + lamella = _liftout_contact_detection(microscope, settings, lamella, parent_ui, validate=validate) + + # move needle up in z to prevent bottoming out + dz = 0.5e-6 # positive is away from sample (up) + microscope.move_manipulator_corrected(dx=0, dy=dz, beam_type=BeamType.ION) + + # restore imaging settings + settings.image.gamma_enabled = True + settings.image.reduced_area = None + + acquire.take_set_of_reference_images( + microscope, + settings.image, + hfws=[fcfg.REFERENCE_HFW_HIGH, fcfg.REFERENCE_HFW_SUPER], + label=f"ref_{lamella.state.stage.name}_manipulator_landed", + ) + + return lamella + +def _liftout_contact_detection(microscope: FibsemMicroscope, settings: MicroscopeSettings, + lamella: Lamella, parent_ui: AutoLiftoutUIv2, validate: bool = True) -> Lamella: + + # measure brightness BRIGHTNESS_FACTOR = 1.2 settings.image.beam_type = BeamType.ION @@ -361,10 +365,6 @@ def land_needle_on_milled_lamella( above_brightness_threshold = brightness > mean_brightness * BRIGHTNESS_FACTOR - - # TODO: optionally run detection - - if above_brightness_threshold and validate is False: break # exit loop @@ -385,22 +385,6 @@ def land_needle_on_milled_lamella( iteration_count += 1 if iteration_count >= MAX_ITERATIONS: break - - # move needle up in z to prevent bottoming out - dz = 0.5e-6 # positive is away from sample (up) - microscope.move_manipulator_corrected(dx=0, dy=dz, beam_type=BeamType.ION) - - # restore imaging settings - settings.image.gamma_enabled = True - settings.image.reduced_area = None - - acquire.take_set_of_reference_images( - microscope, - settings.image, - hfws=[fcfg.REFERENCE_HFW_HIGH, fcfg.REFERENCE_HFW_SUPER], - label=f"ref_{lamella.state.stage.name}_manipulator_landed", - ) - return lamella @@ -859,7 +843,6 @@ def run_autoliftout_workflow( parent_ui: AutoLiftoutUIv2, ) -> Experiment: - BATCH_MODE = bool(settings.protocol["options"]["batch_mode"]) CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_advance"]) _update_status_ui(parent_ui, "Starting AutoLiftout Workflow...") @@ -872,10 +855,10 @@ def run_autoliftout_workflow( # batch mode workflow - if BATCH_MODE: + if True: for terminal_stage in [ AutoLiftoutStage.MillTrench, - # AutoLiftoutStage.MillUndercut, # TODO: maybe add this to config? + AutoLiftoutStage.MillUndercut, # TODO: maybe add this to config? ]: lamella: Lamella for lamella in experiment.positions: diff --git a/autolamella/liftout/config/config.py b/autolamella/liftout/config/config.py index 8e647e71..bea6d095 100644 --- a/autolamella/liftout/config/config.py +++ b/autolamella/liftout/config/config.py @@ -12,7 +12,7 @@ EXPERIMENT_NAME = "AutoLiftout" __AUTOLIFTOUT_METHODS__ = ["autoliftout-default", "autoliftout-serial-liftout"] -__AUTOLIFTOUT_LIFTOUT_JOIN_METHODS__ = ["None", "Weld", "Platinum"] +__AUTOLIFTOUT_LIFTOUT_JOIN_METHODS__ = ["None", "Weld"] __AUTOLIFTOUT_LANDING_JOIN_METHODS__ = ["Weld"] diff --git a/autolamella/liftout/protocol/protocol2.yaml b/autolamella/liftout/protocol/protocol2.yaml index fcb0a1e5..4c5a9cf8 100644 --- a/autolamella/liftout/protocol/protocol2.yaml +++ b/autolamella/liftout/protocol/protocol2.yaml @@ -50,6 +50,8 @@ options: confirm_advance: true landing_joining_method: Weld liftout_joining_method: None + liftout_contact_detection: True + liftout_contact_offset: 0.25e-6 landing_post_x_offset: 0.75e-6 lamella_start_position: autoliftout-pre-tilt-35-deg-grid-01-lamella landing_start_position: autoliftout-pre-tilt-35-deg-grid-02-landing @@ -57,6 +59,8 @@ options: compucentric_y_offset: 25.0e-6 return_to_eb_after_undercut: True alignment_attempts: 3.0 + liftout_charge_neutralisation_iterations: 35 + landing_charge_neutralisation_iterations: 100 supervise: landing: true liftout: true diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index 70fe7158..4d046316 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -28,15 +28,6 @@ from datetime import datetime from fibsem.ui import _stylesheets - -""" -TODO: - - Redo setup. Add and select lamella on main screen, rather than walkthrough? then how to select landing positions - - add more stages: LamellaSelected, LandingSelected - - Stop workflow button? how to implement - -""" - _DEV_MODE = False DEV_MICROSCOPE = "Demo" DEV_EXP_PATH = r"C:\Users\pcle0002\Documents\repos\autoliftout\liftout\log\DEV-TEST-SERIAL-01\experiment.yaml" From 04e3de08d4e600b53825c438f8b6459b8d66e4ce Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 17:31:24 +1000 Subject: [PATCH 06/39] update default protocols --- autolamella/liftout/protocol/config.yaml | 53 ---- .../{protocol2.yaml => protocol-base.yaml} | 0 ...rial.yaml => protocol-serial-liftout.yaml} | 0 autolamella/liftout/protocol/protocol.yaml | 296 ------------------ .../liftout/protocol/protocol_auto.yaml | 258 --------------- 5 files changed, 607 deletions(-) delete mode 100644 autolamella/liftout/protocol/config.yaml rename autolamella/liftout/protocol/{protocol2.yaml => protocol-base.yaml} (100%) rename autolamella/liftout/protocol/{protocol_serial.yaml => protocol-serial-liftout.yaml} (100%) delete mode 100644 autolamella/liftout/protocol/protocol.yaml delete mode 100644 autolamella/liftout/protocol/protocol_auto.yaml diff --git a/autolamella/liftout/protocol/config.yaml b/autolamella/liftout/protocol/config.yaml deleted file mode 100644 index 5619a1d2..00000000 --- a/autolamella/liftout/protocol/config.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# automation config variables - -# crosscorrelation -jcut_align_ref_trench: - xcorr_limit: - - 100 - - 100 - -jcut_align_ref_rotate: - xcorr_limit: - - 512 - - 512 - - 512 - - 100 - -jcut_align_ref: - xcorr_limit: - - 512 - - 100 - -jcut_align_ref_eucentric: - xcorr_limit: - - 512 - - 100 - -landing_align_ref: - xcorr_limit: - - 512 - - 100 - -# charge -trench_charge_steps: 20 # EB -jcut_charge_steps: 20 # EB -liftout_charge_steps: 20 # IB -landing_charge_steps: 50 # EB - - -# step size -liftout_needle_entry_x: 2.0e-6 -liftout_needle_entry_z_steps: 2 -liftout_needle_contact_x: 0.5e-6 -liftout_needle_contact_z: 0.5e-6 -liftout_needle_removal_x: 1.5e-6 -liftout_needle_removal_z: 10.e-6 - -landing_needle_removal_x: 0.5e-6 - -# contact -liftout_brightness_factor: 1.2 -liftout_contact_steps: 15 - -msg: - confirm_needle_entry: "Has the needle landed on the lamella? \nPress Yes to continue, or No to redo the final movement" \ No newline at end of file diff --git a/autolamella/liftout/protocol/protocol2.yaml b/autolamella/liftout/protocol/protocol-base.yaml similarity index 100% rename from autolamella/liftout/protocol/protocol2.yaml rename to autolamella/liftout/protocol/protocol-base.yaml diff --git a/autolamella/liftout/protocol/protocol_serial.yaml b/autolamella/liftout/protocol/protocol-serial-liftout.yaml similarity index 100% rename from autolamella/liftout/protocol/protocol_serial.yaml rename to autolamella/liftout/protocol/protocol-serial-liftout.yaml diff --git a/autolamella/liftout/protocol/protocol.yaml b/autolamella/liftout/protocol/protocol.yaml deleted file mode 100644 index 3eb8db1a..00000000 --- a/autolamella/liftout/protocol/protocol.yaml +++ /dev/null @@ -1,296 +0,0 @@ -flatten: - cleaning_cross_section: 1.0 - depth: 1.0e-05 - height: 2.5e-05 - milling_current: 2.8e-08 - scan_direction: LeftToRight - width: 2.0e-06 - rotation: 0.0 - hfw: 80.0e-6 -initial_position: - landing_grid: - coordinate_system: Raw - x: 0.00276265 - y: 0.0039354 - z: 0.031379 - landing_tilt_angle: 32.0 - relative_beam_shift_x: 2.0e-06 - sample_grid: - coordinate_system: Raw - x: -0.0032375 - y: 0.0039354 - z: 0.03095 -undercut: - cleaning_cross_section: 0.0 - depth: 5.5e-06 - h_offset: 4.0e-06 - undercut_angle: 6.0 - height: 9.0e-06 - milling_current: 7.6e-09 - rhs_height: 1.15e-05 - rotation: 0.0 - scan_direction: TopToBottom - trench_width: 2.0e-06 - width: 2.7e-05 - hfw: 80.0e-6 -horseshoe: - lamella_height: 9.999999999999999e-06 - lamella_width: 4.0e-05 - milling_current: 2.8e-08 - depth: 1.0e-05 - offset: 2.0e-06 - stages: - - lamella_height: 9.999999999999999e-06 - lamella_width: 4.0e-05 - milling_current: 2.8e-08 - depth: 1.0e-05 - offset: 2.0e-06 - rotation: 0.0 - scan_direction: TopToBottom - side_offset: 0.0 - side_width: 1.5e-05 - size_ratio: 1.0 - trench_height: 12.0e-06 - hfw: 80.0e-6 - - lamella_height: 9.999999999999999e-06 - lamella_width: 4.0e-05 - milling_current: 7.6e-09 - depth: 1.0e-05 - offset: 0.0 - rotation: 0.0 - scan_direction: TopToBottom - side_offset: 1.5e-05 - side_width: 5.0e-07 - size_ratio: 1.0 - trench_height: 2.4999999999999998e-06 - hfw: 80.0e-6 - rotation: 0.0 - scan_direction: TopToBottom - side_offset: 0.0 - side_width: 8.0e-06 - size_ratio: 1.0 - trench_height: 9.999999999999999e-06 -# lamella: -# cleaning_cross_section: 0.0 -# lamella_height: 9.999999999999999e-06 -# lamella_width: 3.0e-05 -# milling_current: 2.8e-08 -# depth: 1.0e-05 -# offset: 2.0e-06 -# stages: -# - cleaning_cross_section: 0.0 -# lamella_height: 9.999999999999999e-06 -# lamella_width: 3.0e-05 -# milling_current: 2.0e-09 -# depth: 1.5e-6 -# offset: 2.0e-06 -# rotation: 0.0 -# scan_direction: TopToBottom -# side_offset: 0.0 -# side_width: 1.5e-05 -# size_ratio: 1.0 -# trench_height: 4.0e-6 -# - cleaning_cross_section: 0.0 -# lamella_height: 9.999999999999999e-06 -# lamella_width: 3.0e-05 -# milling_current: 2.0e-09 -# depth: 1.0e-06 -# offset: 0.0 -# rotation: 0.0 -# scan_direction: TopToBottom -# side_offset: 1.5e-05 -# side_width: 5.0e-07 -# size_ratio: 1.0 -# trench_height: 2.4999999999999998e-06 -# rotation: 0.0 -# scan_direction: TopToBottom -# side_offset: 0.0 -# side_width: 8.0e-06 -# size_ratio: 1.0 -# trench_height: 9.999999999999999e-06 -lamella_state: - absolute_position: - coordinate_system: Raw - r: -2.28636643635382 - t: 0.2967058527613453 - x: 0.0023149166666666665 - y: -0.0019699166666666667 - z: 0.031954218106995884 - eb_settings: - beam_current: 5.0e-11 - beam_type: ELECTRON - dwell_time: 1.0e-06 - hfw: 0.00015 - resolution: [1536, 1024] - working_distance: 0.00391 - voltage: 2000 - ib_settings: - beam_current: 2.0e-11 - beam_type: ION - dwell_time: 1.0e-06 - hfw: 0.00015 - resolution: [1536, 1024] - working_distance: 0.0165 - voltage: 30000 - timestamp: 1669684862.642714 -landing_state: - absolute_position: - coordinate_system: Raw - r: -2.286298510029761 - t: 0.5585004974916625 - x: -0.003933166666666666 - y: -0.0023545 - z: 0.031787004886831276 - eb_settings: - beam_current: 5.0e-11 - beam_type: ELECTRON - dwell_time: 1.0e-06 - hfw: 0.0009 - resolution: [1536, 1024] - working_distance: 0.00391 - voltage: 2000 - ib_settings: - beam_current: 2.0e-11 - beam_type: ION - dwell_time: 1.0e-06 - hfw: 0.0009 - resolution: [1536, 1024] - working_distance: 0.0165 - voltage: 30000 - timestamp: 1669685109.759207 -ml: - cuda: 0.0 - encoder: resnet34 - num_classes: 3.0 - checkpoint: model4.pt -name: autoliftout -options: - supervise: - undercut: True - landing: True - liftout: True - polish: True - reset: True - thin: True - trench: True - batch_mode: 1.0 - confirm_advance: 1.0 - landing_joining_method: Weld - landing_removal_method: None - landing_surface: Half-Moon Grid - liftout_contact_direction: Horizontal - liftout_joining_method: None - liftout_charge_neutralisation_iterations: 35 - landing_charge_neutralisation_iterations: 100 -platinum: - application_file: cryo_Pt_dep - gas: Pt dep - position: Electron Default - beam_current: 5.0e-11 - dwell_time: 1.0e-06 - rate: 3.0e-10 - spot_size: 3.0e-06 - weld: - hfw: 0.0001 - length: 1.5e-05 - time: 30.0 - whole_grid: - hfw: 3.0e-05 - length: 7.0e-06 - time: 30.0 -polish_lamella: - dwell_time: 2.0e-07 - hfw: 5.0e-05 - lamella_height: 5.0e-07 - lamella_width: 1.7e-05 - milling_current: 6.0e-11 - depth: 4.0e-07 - offset: 0.0 - resolution: [3072, 2048] - rotation: 0.0 - rotation_angle: 50.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - tilt_offset: 1.0 - trench_height: 6.0e-07 - hfw: 80.0e-6 -sever: - cleaning_cross_section: 0.0 - depth: 3.0e-06 - height: 18.0e-06 - milling_current: 7.6e-09 - rotation: 0.0 - scan_direction: TopToBottom - width: 1.0e-06 - hfw: 80.0e-6 -sharpen: - bias: 2.5e-07 - cleaning_cross_section: 0.0 - depth: 9.999999999999999e-06 - height: 2.0e-06 - hfw: 0.00015 - milling_current: 2.8e-08 - needle_angle: 40.0 - rotation: 0.0 - scan_direction: TopToBottom - tip_angle: 35.0 - width: 2.9999999999999997e-05 -thin_lamella: - dwell_time: 2.0e-07 - hfw: 5.0e-05 - lamella_height: 1.0e-06 - lamella_width: 1.8e-05 - milling_current: 7.4e-10 - depth: 4.0e-07 - offset: 1.0e-06 - resolution: [3072, 2048] - rotation: 0.0 - rotation_angle: 49.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - trench_height: 4.5e-06 - stages: - - dwell_time: 2.0e-07 - hfw: 5.0e-05 - lamella_height: 1.0e-06 - lamella_width: 1.8e-05 - milling_current: 7.4e-10 - depth: 4.0e-07 - offset: 1.0e-06 - resolution: [3072, 2048] - rotation: 0.0 - rotation_angle: 49.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - trench_height: 4.5e-06 - hfw: 80.0e-6 - - dwell_time: 2.0e-07 - hfw: 5.0e-05 - lamella_height: 8.0e-07 - lamella_width: 1.8e-05 - milling_current: 2.0000000000000003e-10 - depth: 4.0e-07 - offset: 0.0 - resolution: [3072, 2048] - rotation: 0.0 - rotation_angle: 49.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - trench_height: 1.5e-06 - hfw: 80.0e-6 -weld: - cleaning_cross_section: 0.0 - depth: 2.0e-07 - height: 9.999999999999999e-06 - milling_current: 2.0e-09 - rotation: 0.0 - scan_direction: RightToLeft - width: 3.0e-06 - distance: 1.0e-06 - number: 3 - hfw: 80.0e-6 - diff --git a/autolamella/liftout/protocol/protocol_auto.yaml b/autolamella/liftout/protocol/protocol_auto.yaml deleted file mode 100644 index aa66b971..00000000 --- a/autolamella/liftout/protocol/protocol_auto.yaml +++ /dev/null @@ -1,258 +0,0 @@ -flatten: - centre_x: 0.0 - centre_y: 0.0 - cleaning_cross_section: 1.0 - depth: 1.0e-05 - height: 2.5e-05 - hfw: 8.0e-05 - milling_current: 2.8e-08 - pattern: Rectangle - rotation: 0.0 - scan_direction: LeftToRight - width: 2.0e-06 -horseshoe: - stages: - - depth: 1.0e-05 - hfw: 8.0e-05 - lamella_height: 9.999999999999999e-06 - lamella_width: 4.0e-05 - milling_current: 2.8e-08 - offset: 2.0e-06 - rotation: 0.0 - scan_direction: TopToBottom - side_offset: 0.0 - side_width: 1.5e-05 - size_ratio: 1.0 - trench_height: 1.2e-05 - - depth: 1.0e-05 - hfw: 8.0e-05 - lamella_height: 9.999999999999999e-06 - lamella_width: 4.0e-05 - milling_current: 7.6e-09 - offset: 0.0 - rotation: 0.0 - scan_direction: TopToBottom - side_offset: 1.5e-05 - side_width: 5.0e-07 - size_ratio: 1.0 - trench_height: 2.4999999999999998e-06 -initial_position: - landing_grid: - coordinate_system: Raw - x: 0.00276265 - y: 0.0039354 - z: 0.031379 - landing_tilt_angle: 32.0 - relative_beam_shift_x: 2.0e-06 - sample_grid: - coordinate_system: Raw - x: -0.0032375 - y: 0.0039354 - z: 0.03095 -lamella_state: - absolute_position: - coordinate_system: Raw - r: -2.28636643635382 - t: 0.2967058527613453 - x: 0.0023149166666666665 - y: -0.0019699166666666667 - z: 0.031954218106995884 - eb_settings: - beam_current: 5.0e-11 - beam_type: ELECTRON - dwell_time: 1.0e-06 - hfw: 0.00015 - resolution: - - 1536 - - 1024 - voltage: 2000 - working_distance: 0.00391 - ib_settings: - beam_current: 2.0e-11 - beam_type: ION - dwell_time: 1.0e-06 - hfw: 0.00015 - resolution: - - 1536 - - 1024 - voltage: 30000 - working_distance: 0.0165 - timestamp: 1669684862.642714 -landing_state: - absolute_position: - coordinate_system: Raw - r: -2.286298510029761 - t: 0.5585004974916625 - x: -0.003933166666666666 - y: -0.0023545 - z: 0.031787004886831276 - eb_settings: - beam_current: 5.0e-11 - beam_type: ELECTRON - dwell_time: 1.0e-06 - hfw: 0.0009 - resolution: - - 1536 - - 1024 - voltage: 2000 - working_distance: 0.00391 - ib_settings: - beam_current: 2.0e-11 - beam_type: ION - dwell_time: 1.0e-06 - hfw: 0.0009 - resolution: - - 1536 - - 1024 - voltage: 30000 - working_distance: 0.0165 - timestamp: 1669685109.759207 -ml: - encoder: resnet34 - num_classes: 3 - weights: C:\Users\pcle0002\Documents\repos\fibsem\fibsem\segmentation\models\model4.pt -name: autoliftout-auto -options: - batch_mode: true - confirm_advance: false - landing_joining_method: Weld - landing_surface: Half-Moon Grid - liftout_contact_direction: Horizontal - liftout_joining_method: None - supervise: - landing: false - liftout: false - polish: false - reset: false - thin: false - trench: false - undercut: false -platinum: - application_file: cryo_Pt_dep - beam_current: 5.0e-11 - dwell_time: 1.0e-06 - gas: Pt dep - position: Electron Default - rate: 3.0e-10 - spot_size: 3.0e-06 - weld: - hfw: 0.0001 - length: 1.5e-05 - time: 30.0 - whole_grid: - hfw: 3.0e-05 - length: 7.0e-06 - time: 30.0 -polish_lamella: - depth: 4.0e-07 - dwell_time: 2.0e-07 - hfw: 8.0e-05 - lamella_height: 5.0e-07 - lamella_width: 1.7e-05 - milling_current: 6.0e-11 - offset: 0.0 - resolution: - - 3072 - - 2048 - rotation: 0.0 - rotation_angle: 50.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - tilt_offset: 1.0 - trench_height: 6.0e-07 -sever: - cleaning_cross_section: 0.0 - depth: 3.0e-06 - height: 1.8e-05 - hfw: 8.0e-05 - milling_current: 7.6e-09 - rotation: 0.0 - scan_direction: TopToBottom - width: 1.0e-06 -sharpen: - bias: 2.5e-07 - cleaning_cross_section: 0.0 - depth: 9.999999999999999e-06 - height: 2.0e-06 - hfw: 0.00015 - milling_current: 2.8e-08 - needle_angle: 40.0 - rotation: 0.0 - scan_direction: TopToBottom - tip_angle: 35.0 - width: 2.9999999999999997e-05 -thin_lamella: - depth: 4.0e-07 - dwell_time: 2.0e-07 - hfw: 5.0e-05 - lamella_height: 1.0e-06 - lamella_width: 1.8e-05 - milling_current: 7.4e-10 - offset: 1.0e-06 - resolution: - - 3072 - - 2048 - rotation: 0.0 - rotation_angle: 49.0 - scan_direction: TopToBottom - size_ratio: 1.0 - stages: - - depth: 4.0e-07 - dwell_time: 2.0e-07 - hfw: 8.0e-05 - lamella_height: 1.0e-06 - lamella_width: 1.8e-05 - milling_current: 7.4e-10 - offset: 1.0e-06 - resolution: - - 3072 - - 2048 - rotation: 0.0 - rotation_angle: 49.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - trench_height: 4.5e-06 - - depth: 4.0e-07 - dwell_time: 2.0e-07 - hfw: 8.0e-05 - lamella_height: 8.0e-07 - lamella_width: 1.8e-05 - milling_current: 2.0000000000000003e-10 - offset: 0.0 - resolution: - - 3072 - - 2048 - rotation: 0.0 - rotation_angle: 49.0 - scan_direction: TopToBottom - size_ratio: 1.0 - tilt_angle: 20.0 - trench_height: 1.5e-06 - tilt_angle: 20.0 - trench_height: 4.5e-06 -undercut: - cleaning_cross_section: 0.0 - depth: 5.5e-06 - h_offset: 4.0e-06 - height: 9.0e-06 - hfw: 8.0e-05 - milling_current: 7.6e-09 - rhs_height: 1.15e-05 - rotation: 0.0 - scan_direction: TopToBottom - trench_width: 2.0e-06 - undercut_angle: 6.0 - width: 2.7e-05 -weld: - cleaning_cross_section: 0.0 - depth: 2.0e-07 - distance: 1.0e-06 - height: 9.999999999999999e-06 - hfw: 8.0e-05 - milling_current: 2.0e-09 - number: 3 - rotation: 0.0 - scan_direction: RightToLeft - width: 3.0e-06 From 0deceaba4bf87503a3853cf87b7119f62aced822 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 19:10:50 +1000 Subject: [PATCH 07/39] working serial liftout on hardware --- autolamella/liftout/autoliftout.py | 28 ++++++----- autolamella/liftout/config/config.py | 2 - .../protocol/protocol-serial-liftout.yaml | 38 +++++++-------- autolamella/liftout/ui/AutoLiftoutUIv2.py | 48 +++++-------------- autolamella/protocol/protocol-base.yaml | 2 +- autolamella/workflows/core.py | 4 +- 6 files changed, 47 insertions(+), 75 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 342159f7..72277177 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -48,6 +48,7 @@ from autolamella.workflows.core import log_status_message +# from autolamella.workflows.ui import _validate_mill_ui, _update_status_ui, _set_images_ui, ask_user, _validate_det_ui_v2 # autoliftout workflow functions @@ -934,7 +935,7 @@ def run_autoliftout_workflow( return experiment - +# TODO: REMOVE THIS def end_of_stage_update( microscope: FibsemMicroscope, experiment: Experiment, lamella: Lamella, parent_ui: AutoLiftoutUIv2, _save_state: bool = True ) -> Experiment: @@ -957,7 +958,7 @@ def end_of_stage_update( return experiment - +# TODO: REMOVE THIS def start_of_stage_update( microscope: FibsemMicroscope, lamella: Lamella, @@ -1021,7 +1022,7 @@ def run_thinning_workflow( return experiment - +# TODO: START_HERE: remove ui function, use core ui def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLiftoutUIv2, msg:str, validate: bool, milling_enabled: bool = True): _update_mill_stages_ui(parent_ui, stages=stages) @@ -1094,12 +1095,12 @@ def _validate_det_ui_v2(microscope, settings, features, parent_ui, validate:bool # I need this to happen in the parent thread for it to work correctly parent_ui.det_confirm_signal.emit(True) - image = acquire.last_image(microscope, settings.image.beam_type) - if settings.image.beam_type is BeamType.ELECTRON: - eb_image, ib_image = image, None - else: - eb_image, ib_image = None, image - _set_images_ui(parent_ui, eb_image=eb_image, ib_image=ib_image) + # image = acquire.last_image(microscope, settings.image.beam_type) + # if settings.image.beam_type is BeamType.ELECTRON: + # eb_image, ib_image = image, None + # else: + # eb_image, ib_image = None, image + # _set_images_ui(parent_ui, eb_image=eb_image, ib_image=ib_image) return det @@ -1219,6 +1220,12 @@ def select_initial_lamella_positions( lamella = Lamella(experiment.path, lamella_no) log_status_message(lamella, "STARTED") + # reference images + settings.image.hfw = fcfg.REFERENCE_HFW_MEDIUM + settings.image.save = False + eb_image,ib_image = acquire.take_reference_images(microscope, settings.image) + _set_images_ui(parent_ui, eb_image, ib_image) + log_status_message(lamella, "SELECT_LAMELLA_POSITION") stages = patterning._get_milling_stages("trench", settings.protocol) stages = _validate_mill_ui(stages, parent_ui, @@ -1359,15 +1366,12 @@ def select_lamella_positions( eb_image,ib_image = acquire.take_reference_images(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) - select_another = get_current_lamella(experiment, parent_ui) if select_another: lamella_start_position = fibsem_utils._get_position(settings.protocol["options"]["lamella_start_position"]) microscope._safe_absolute_stage_movement(lamella_start_position) - ask_user(parent_ui, msg=f"Move to the next lamella.", pos="Continue") - # allow the user to select additional lamella positions while select_another: logging.info(f"Selecting Lamella Position: {select_another}") diff --git a/autolamella/liftout/config/config.py b/autolamella/liftout/config/config.py index bea6d095..f5fcb052 100644 --- a/autolamella/liftout/config/config.py +++ b/autolamella/liftout/config/config.py @@ -3,8 +3,6 @@ import autolamella.liftout as liftout BASE_PATH = os.path.dirname(liftout.__file__) # TODO: fix this to be the root directory of the project -config_path = os.path.join(BASE_PATH, "config") -protocol_path = os.path.join(BASE_PATH, "protocol", "protocol.yaml") CONFIG_PATH = os.path.join(BASE_PATH, "config") SYSTEM_PATH = os.path.join(CONFIG_PATH, "system.yaml") PROTOCOL_PATH = os.path.join(BASE_PATH, "protocol", "protocol.yaml") diff --git a/autolamella/liftout/protocol/protocol-serial-liftout.yaml b/autolamella/liftout/protocol/protocol-serial-liftout.yaml index 2c4bc5a4..7d6227fc 100644 --- a/autolamella/liftout/protocol/protocol-serial-liftout.yaml +++ b/autolamella/liftout/protocol/protocol-serial-liftout.yaml @@ -26,16 +26,14 @@ trench: preset: "30 keV; 20 nA" ml: encoder: resnet34 - num_classes: 3 - checkpoint: openfibsem-baseline-34.pt + num_classes: 5 + checkpoint: autoliftout-serial-01-34.pt name: autoliftout-serial-protocol method: autoliftout-serial-liftout options: batch_mode: true confirm_advance: true - landing_joining_method: Weld - liftout_joining_method: None - landing_post_x_offset: 0.75e-6 + complete_undercut: False lamella_start_position: autoliftout-serial-pre-tilt-35-deg-grid-01-lamella landing_start_position: autoliftout-serial-pre-tilt-35-deg-grid-02-landing compucentric_x_offset: 50.0e-6 @@ -84,21 +82,18 @@ liftout_sever: type: "Rectangle" preset: "30 keV; 20 nA" undercut: - cleaning_cross_section: 0.0 - depth: 25.0e-06 - h_offset: 4.0e-06 - height: 9.0e-06 - hfw: 8.0e-05 - milling_current: 7.6e-09 - rhs_height: 1.0e-05 - rotation: 0.0 + application_file: autolamella + cleaning_cross_section: false + depth: 15.0e-06 + height: 5.0e-06 + hfw: 150.0e-6 + milling_current: 28.0e-09 + preset: 30 keV; 2.5 nA + tilt_angle: -10.0 + tilt_angle_step: 1.0 + width: 45.0e-6 scan_direction: TopToBottom - trench_width: 2.0e-06 - undercut_angle: 6.0 - width: 2.5e-05 - application_file: "autolamella" - type: "Rectangle" - preset: "30 keV; 20 nA" + type: Rectangle liftout_weld: height: 5.0e-6 width: 0.5e-6 @@ -110,7 +105,7 @@ liftout_weld: milling_current: 0.74e-09 hfw: 150.0e-6 application_file: "autolamella" - scan_direction: "BottomToTop" + scan_direction: "TopToBottom" type: "SpotWeldVertical" preset: "30 keV; 2.5 nA" adapter_weld: @@ -124,7 +119,7 @@ adapter_weld: milling_current: 0.74e-09 hfw: 150.0e-6 application_file: "autolamella" - scan_direction: "BottomToTop" + scan_direction: "TopToBottom" type: "SpotWeldVertical" preset: "30 keV; 2.5 nA" weld: @@ -223,7 +218,6 @@ fiducial: rotation: 45 width: 1.0e-06 type: "Fiducial" - # system # options # positions diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index 4d046316..702d616d 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -114,12 +114,10 @@ def setup_connections(self): self.comboBox_options_landing_start_position.addItems(_AVAILABLE_POSITIONS_) # workflow buttons - self.pushButton_setup_autoliftout.clicked.connect(self._run_workflow) - self.pushButton_run_autoliftout.clicked.connect(self._run_autoliftout_workflow) - self.pushButton_run_serial_liftout_landing.clicked.connect(self._run_serial_liftout_landing_workflow) - self.pushButton_run_polishing.clicked.connect(self._run_autolamella_workflow) - - + self.pushButton_setup_autoliftout.clicked.connect(lambda: self._run_workflow(workflow="setup")) + self.pushButton_run_autoliftout.clicked.connect(lambda: self._run_workflow(workflow="autoliftout")) + self.pushButton_run_serial_liftout_landing.clicked.connect(lambda: self._run_workflow(workflow="serial-liftout-landing")) + self.pushButton_run_polishing.clicked.connect(lambda: self._run_workflow(workflow="autolamella")) # interaction buttons self.pushButton_yes.clicked.connect(self.push_interaction_button) @@ -398,8 +396,8 @@ def update_ui_from_protocol(self, protocol: dict): options = self.settings.protocol["options"] self.checkBox_options_batch_mode.setChecked(bool(options["batch_mode"])) self.checkBox_options_confirm_next_stage.setChecked(bool(options["confirm_advance"])) - self.comboBox_options_liftout_joining_method.setCurrentText(options["liftout_joining_method"]) - self.comboBox_options_landing_joining_method.setCurrentText(options["landing_joining_method"]) + self.comboBox_options_liftout_joining_method.setCurrentText(options.get("liftout_joining_method", "None")) + self.comboBox_options_landing_joining_method.setCurrentText(options.get("landing_joining_method", "Weld")) self.comboBox_options_lamella_start_position.setCurrentText(options["lamella_start_position"]) self.comboBox_options_landing_start_position.setCurrentText(options["landing_start_position"]) @@ -428,8 +426,8 @@ def update_protocol_from_ui(self): self.settings.protocol["name"] = self.lineEdit_protocol_name.text() self.settings.protocol["method"] = self.comboBox_protocol_method.currentText() - # TODO: milling? - self.settings.protocol["options"] = { + # TODO: fix this for both methods + self.settings.protocol["options"].update({ "batch_mode": self.checkBox_options_batch_mode.isChecked(), "confirm_advance": self.checkBox_options_confirm_next_stage.isChecked(), "liftout_joining_method": self.comboBox_options_liftout_joining_method.currentText(), @@ -446,8 +444,8 @@ def update_protocol_from_ui(self): "mill_rough": self.checkBox_supervise_mill_rough.isChecked(), "mill_regular": self.checkBox_supervise_mill_regular.isChecked(), "mill_polishing": self.checkBox_supervise_mill_polishing.isChecked() - } - } + }} + ) self.settings.protocol["ml"] = { "encoder": self.lineEdit_protocol_ml_encoder.text(), @@ -612,33 +610,11 @@ def _confirm_det(self): if self.det_widget is not None: self.det_widget.confirm_button_clicked() - def _run_workflow(self): - self.worker = self._threaded_worker( - microscope=self.microscope, settings=self.settings, experiment=self.experiment, workflow="setup", - ) - self.worker.finished.connect(self._workflow_finished) - self.worker.start() - - def _run_autoliftout_workflow(self): - self.worker = self._threaded_worker( - microscope=self.microscope, settings=self.settings, experiment=self.experiment, workflow="autoliftout" - ) - self.worker.finished.connect(self._workflow_finished) - self.worker.start() - - def _run_serial_liftout_landing_workflow(self): - self.worker = self._threaded_worker( - microscope=self.microscope, settings=self.settings, experiment=self.experiment, workflow="serial-landing" - ) - self.worker.finished.connect(self._workflow_finished) - self.worker.start() - - def _run_autolamella_workflow(self): + def _run_workflow(self, workflow: str): self.worker = self._threaded_worker( - microscope=self.microscope, settings=self.settings, experiment=self.experiment, workflow="autolamella" + microscope=self.microscope, settings=self.settings, experiment=self.experiment, workflow=workflow, ) self.worker.finished.connect(self._workflow_finished) - self.worker.start() def _workflow_finished(self): diff --git a/autolamella/protocol/protocol-base.yaml b/autolamella/protocol/protocol-base.yaml index 77ab40dd..397e3006 100644 --- a/autolamella/protocol/protocol-base.yaml +++ b/autolamella/protocol/protocol-base.yaml @@ -3,6 +3,7 @@ name: autolamella-base-scan-rotation-0deg method: autolamella-default # waffle or default options: + alignment_attempts: 3.0 supervise: trench: false undercut: true @@ -41,7 +42,6 @@ trench: cleaning_cross_section: false lamella: - alignment_attempts: 3.0 lamella_width: 20.e-6 lamella_height: 800.e-9 stages: diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 7027b434..54c4fea3 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -498,8 +498,8 @@ def setup_lamella( stages = deepcopy(lamella_stages) # feature - if method == "autolamella-waffle": - _feature_name = "notch" + if "autolamella" in method: + _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" protocol = lamella.protocol if _feature_name in lamella.protocol else settings.protocol NOTCH_H_OFFSET = 0.5e-6 feature_position = Point.__from_dict__(protocol[_feature_name].get("point", From 8517cda8192557ce5f667ea392db63a8914cd0da Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 19:18:58 +1000 Subject: [PATCH 08/39] migrate to core ui --- autolamella/liftout/autoliftout.py | 311 ++++++++++++------------ autolamella/liftout/workflows/serial.py | 2 +- autolamella/workflows/ui.py | 11 + 3 files changed, 167 insertions(+), 157 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 72277177..41b0d473 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -24,10 +24,9 @@ detect_features, DetectedFeatures, ) -from fibsem.imaging import masks from fibsem import conversions from fibsem.imaging import utils as image_utils -from fibsem.microscope import FibsemMicroscope, ThermoMicroscope +from fibsem.microscope import FibsemMicroscope from fibsem.patterning import FibsemMillingStage, _get_milling_stages from fibsem.structures import ( BeamType, @@ -48,7 +47,7 @@ from autolamella.workflows.core import log_status_message -# from autolamella.workflows.ui import _validate_mill_ui, _update_status_ui, _set_images_ui, ask_user, _validate_det_ui_v2 +from autolamella.workflows.ui import _validate_mill_ui, _update_status_ui, _set_images_ui, ask_user, _validate_det_ui_v2 # autoliftout workflow functions @@ -1023,172 +1022,172 @@ def run_thinning_workflow( # TODO: START_HERE: remove ui function, use core ui -def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLiftoutUIv2, msg:str, validate: bool, milling_enabled: bool = True): +# def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLiftoutUIv2, msg:str, validate: bool, milling_enabled: bool = True): - _update_mill_stages_ui(parent_ui, stages=stages) +# _update_mill_stages_ui(parent_ui, stages=stages) - if validate: - response = ask_user(parent_ui, msg=msg, pos="Continue", mill=milling_enabled) - stages = deepcopy(parent_ui.milling_widget.get_milling_stages()) - else: - _update_status_ui(parent_ui, f"Milling {len(stages)} stages...") - parent_ui._MILLING_RUNNING = True - parent_ui._run_milling_signal.emit() +# if validate: +# response = ask_user(parent_ui, msg=msg, pos="Continue", mill=milling_enabled) +# stages = deepcopy(parent_ui.milling_widget.get_milling_stages()) +# else: +# _update_status_ui(parent_ui, f"Milling {len(stages)} stages...") +# parent_ui._MILLING_RUNNING = True +# parent_ui._run_milling_signal.emit() - logging.info(f"WAITING FOR MILLING TO FINISH... ") - while parent_ui._MILLING_RUNNING or parent_ui.image_widget.TAKING_IMAGES: +# logging.info(f"WAITING FOR MILLING TO FINISH... ") +# while parent_ui._MILLING_RUNNING or parent_ui.image_widget.TAKING_IMAGES: - time.sleep(1) +# time.sleep(1) - _update_status_ui( - parent_ui, f"Milling Complete: {len(stages)} stages completed." - ) - parent_ui.WAITING_FOR_UI_UPDATE = True +# _update_status_ui( +# parent_ui, f"Milling Complete: {len(stages)} stages completed." +# ) +# parent_ui.WAITING_FOR_UI_UPDATE = True - _update_mill_stages_ui(parent_ui, stages="clear") +# _update_mill_stages_ui(parent_ui, stages="clear") - logging.info(f"WAITING FOR UI UPDATE... ") - while parent_ui.WAITING_FOR_UI_UPDATE: - time.sleep(0.5) +# logging.info(f"WAITING FOR UI UPDATE... ") +# while parent_ui.WAITING_FOR_UI_UPDATE: +# time.sleep(0.5) - return stages +# return stages # TODO: think this can be consolidated into mill arg for ask_user? -def _update_mill_stages_ui(parent_ui: AutoLiftoutUIv2, stages: list[FibsemMillingStage] = None): - INFO = { - "msg": "Updating Milling Stages", - "pos": None, - "neg": None, - "det": None, - "eb_image": None, - "ib_image": None, - "movement": None, - "mill": None, - "stages": stages - } - - parent_ui.ui_signal.emit(INFO) - -def _validate_det_ui_v2(microscope, settings, features, parent_ui, validate:bool, msg: str = "Lamella") -> DetectedFeatures: +# def _update_mill_stages_ui(parent_ui: AutoLiftoutUIv2, stages: list[FibsemMillingStage] = None): +# INFO = { +# "msg": "Updating Milling Stages", +# "pos": None, +# "neg": None, +# "det": None, +# "eb_image": None, +# "ib_image": None, +# "movement": None, +# "mill": None, +# "stages": stages +# } + +# parent_ui.ui_signal.emit(INFO) + +# def _validate_det_ui_v2(microscope, settings, features, parent_ui, validate:bool, msg: str = "Lamella") -> DetectedFeatures: - feat_str = ", ".join([f.name for f in features]) - _update_status_ui( - parent_ui, f"{msg}: Detecting Features ({feat_str})..." - ) +# feat_str = ", ".join([f.name for f in features]) +# _update_status_ui( +# parent_ui, f"{msg}: Detecting Features ({feat_str})..." +# ) - det = detection.take_image_and_detect_features( - microscope=microscope, - settings=settings, - features=features, - ) - - if validate: - ask_user( - parent_ui, - msg=f"Confirm Feature Detection. Press Continue to proceed.", - pos="Continue", - det=det, - ) - - det = parent_ui.det_widget._get_detected_features() - - # I need this to happen in the parent thread for it to work correctly - parent_ui.det_confirm_signal.emit(True) +# det = detection.take_image_and_detect_features( +# microscope=microscope, +# settings=settings, +# features=features, +# ) + +# if validate: +# ask_user( +# parent_ui, +# msg=f"Confirm Feature Detection. Press Continue to proceed.", +# pos="Continue", +# det=det, +# ) + +# det = parent_ui.det_widget._get_detected_features() + +# # I need this to happen in the parent thread for it to work correctly +# parent_ui.det_confirm_signal.emit(True) - # image = acquire.last_image(microscope, settings.image.beam_type) - # if settings.image.beam_type is BeamType.ELECTRON: - # eb_image, ib_image = image, None - # else: - # eb_image, ib_image = None, image - # _set_images_ui(parent_ui, eb_image=eb_image, ib_image=ib_image) - - return det - - -def _set_images_ui( - parent_ui: AutoLiftoutUIv2, - eb_image: FibsemImage = None, - ib_image: FibsemImage = None, -): - - INFO = { - "msg": "Updating Images", - "pos": None, - "neg": None, - "det": None, - "eb_image": deepcopy(eb_image), - "ib_image": deepcopy(ib_image), - "movement": None, - "mill": None, - } - parent_ui.WAITING_FOR_UI_UPDATE = True - parent_ui.ui_signal.emit(INFO) - - logging.info(f"WAITING FOR UI UPDATE... ") - while parent_ui.WAITING_FOR_UI_UPDATE: - time.sleep(0.5) - - logging.info(f"UI UPDATE COMPLETE... ") - -def _update_status_ui(parent_ui: AutoLiftoutUIv2, msg: str): - if parent_ui is None: - logging.info(msg) - return - - INFO = { - "msg": msg, - "pos": None, - "neg": None, - "det": None, - "eb_image": None, - "ib_image": None, - "movement": None, - "mill": None, - } - parent_ui.ui_signal.emit(INFO) - -def ask_user( - parent_ui: AutoLiftoutUIv2, - msg: str, - pos: str, - neg: str = None, - image: bool = True, - movement: bool = True, - mill: bool = None, - det: DetectedFeatures = None, -) -> bool: - - INFO = { - "msg": msg, - "pos": pos, - "neg": neg, - "det": det, - "eb_image": None, - "ib_image": None, - "movement": movement, - "mill": mill, - } - parent_ui.ui_signal.emit(INFO) - - parent_ui.WAITING_FOR_USER_INTERACTION = True - logging.info("WAITING_FOR_USER_INTERACTION...") - while parent_ui.WAITING_FOR_USER_INTERACTION: - time.sleep(1) - # print("waiting for user interaction") - - INFO = { - "msg": "", - "pos": None, - "neg": None, - "det": None, - "eb_image": None, - "ib_image": None, - "movement": None, - "mill": None, - } - parent_ui.ui_signal.emit(INFO) - - return parent_ui.USER_RESPONSE +# # image = acquire.last_image(microscope, settings.image.beam_type) +# # if settings.image.beam_type is BeamType.ELECTRON: +# # eb_image, ib_image = image, None +# # else: +# # eb_image, ib_image = None, image +# # _set_images_ui(parent_ui, eb_image=eb_image, ib_image=ib_image) + +# return det + + +# def _set_images_ui( +# parent_ui: AutoLiftoutUIv2, +# eb_image: FibsemImage = None, +# ib_image: FibsemImage = None, +# ): + +# INFO = { +# "msg": "Updating Images", +# "pos": None, +# "neg": None, +# "det": None, +# "eb_image": deepcopy(eb_image), +# "ib_image": deepcopy(ib_image), +# "movement": None, +# "mill": None, +# } +# parent_ui.WAITING_FOR_UI_UPDATE = True +# parent_ui.ui_signal.emit(INFO) + +# logging.info(f"WAITING FOR UI UPDATE... ") +# while parent_ui.WAITING_FOR_UI_UPDATE: +# time.sleep(0.5) + +# logging.info(f"UI UPDATE COMPLETE... ") + +# def _update_status_ui(parent_ui: AutoLiftoutUIv2, msg: str): +# if parent_ui is None: +# logging.info(msg) +# return + +# INFO = { +# "msg": msg, +# "pos": None, +# "neg": None, +# "det": None, +# "eb_image": None, +# "ib_image": None, +# "movement": None, +# "mill": None, +# } +# parent_ui.ui_signal.emit(INFO) + +# def ask_user( +# parent_ui: AutoLiftoutUIv2, +# msg: str, +# pos: str, +# neg: str = None, +# image: bool = True, +# movement: bool = True, +# mill: bool = None, +# det: DetectedFeatures = None, +# ) -> bool: + +# INFO = { +# "msg": msg, +# "pos": pos, +# "neg": neg, +# "det": det, +# "eb_image": None, +# "ib_image": None, +# "movement": movement, +# "mill": mill, +# } +# parent_ui.ui_signal.emit(INFO) + +# parent_ui.WAITING_FOR_USER_INTERACTION = True +# logging.info("WAITING_FOR_USER_INTERACTION...") +# while parent_ui.WAITING_FOR_USER_INTERACTION: +# time.sleep(1) +# # print("waiting for user interaction") + +# INFO = { +# "msg": "", +# "pos": None, +# "neg": None, +# "det": None, +# "eb_image": None, +# "ib_image": None, +# "movement": None, +# "mill": None, +# } +# parent_ui.ui_signal.emit(INFO) + +# return parent_ui.USER_RESPONSE def get_current_lamella( diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index 07de274d..92be1717 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -38,7 +38,7 @@ from collections import Counter from autolamella.liftout.structures import Lamella, Experiment, AutoLiftoutState, AutoLiftoutStage from autolamella.liftout.autoliftout import log_status_message, start_of_stage_update, end_of_stage_update -from autolamella.liftout.autoliftout import ask_user, _update_status_ui, _validate_det_ui_v2, _update_mill_stages_ui, _set_images_ui, _validate_mill_ui +from autolamella.workflows.ui import ask_user, _update_status_ui, _validate_det_ui_v2, _set_images_ui, _validate_mill_ui from pprint import pprint diff --git a/autolamella/workflows/ui.py b/autolamella/workflows/ui.py index 11b93ccd..6d856329 100644 --- a/autolamella/workflows/ui.py +++ b/autolamella/workflows/ui.py @@ -94,6 +94,13 @@ def _validate_det_ui_v2( # I need this to happen in the parent thread for it to work correctly parent_ui.det_confirm_signal.emit(True) +# # image = acquire.last_image(microscope, settings.image.beam_type) +# # if settings.image.beam_type is BeamType.ELECTRON: +# # eb_image, ib_image = image, None +# # else: +# # eb_image, ib_image = None, image +# # _set_images_ui(parent_ui, eb_image=eb_image, ib_image=ib_image) + return det @@ -114,8 +121,12 @@ def _set_images_ui( "movement": None, "mill": None, } + parent_ui.WAITING_FOR_UI_UPDATE = True parent_ui.ui_signal.emit(INFO) + logging.info(f"WAITING FOR UI UPDATE... ") + while parent_ui.WAITING_FOR_UI_UPDATE: + time.sleep(0.5) def _update_status_ui(parent_ui: AutoLamellaUI, msg: str): From 083f010581cf06ec512de48bdac1a8f4ac2c8435 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 27 Sep 2023 19:27:35 +1000 Subject: [PATCH 09/39] rm common core --- autolamella/liftout/autoliftout.py | 223 +--------------------- autolamella/liftout/ui/AutoLiftoutUIv2.py | 2 +- 2 files changed, 2 insertions(+), 223 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 41b0d473..a1ecaa20 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -46,7 +46,7 @@ from fibsem import config as fcfg -from autolamella.workflows.core import log_status_message +from autolamella.workflows.core import log_status_message, start_of_stage_update, end_of_stage_update from autolamella.workflows.ui import _validate_mill_ui, _update_status_ui, _set_images_ui, ask_user, _validate_det_ui_v2 # autoliftout workflow functions @@ -934,57 +934,6 @@ def run_autoliftout_workflow( return experiment -# TODO: REMOVE THIS -def end_of_stage_update( - microscope: FibsemMicroscope, experiment: Experiment, lamella: Lamella, parent_ui: AutoLiftoutUIv2, _save_state: bool = True -) -> Experiment: - """Save the current microscope state configuration to disk, and log that the stage has been completed.""" - - # save state information - if _save_state: - lamella.state.microscope_state = microscope.get_current_microscope_state() - lamella.state.end_timestamp = datetime.timestamp(datetime.now()) - - # write history - lamella.history.append(deepcopy(lamella.state)) - - # update and save experiment - experiment.save() - - log_status_message(lamella, "FINISHED") - _update_status_ui(parent_ui, f"{lamella.info} Finished.") - - - return experiment - -# TODO: REMOVE THIS -def start_of_stage_update( - microscope: FibsemMicroscope, - lamella: Lamella, - next_stage: AutoLiftoutStage, - parent_ui: AutoLiftoutUIv2, - _restore_state: bool = True, -) -> Lamella: - """Check the last completed stage and reload the microscope state if required. Log that the stage has started.""" - last_completed_stage = lamella.state.stage - - # restore to the last state - if last_completed_stage.value == next_stage.value - 1 and _restore_state: - logging.info( - f"{lamella.info} restarting from end of stage: {last_completed_stage.name}" - ) - _update_status_ui(parent_ui, f"{lamella.info} Restoring to Last State...") - microscope.set_microscope_state(lamella.state.microscope_state) - - # set current state information - lamella.state.stage = next_stage - lamella.state.start_timestamp = datetime.timestamp(datetime.now()) - log_status_message(lamella, "STARTED") - _update_status_ui(parent_ui, f"{lamella.info} Starting...") - - return lamella - - def run_thinning_workflow( microscope: FibsemMicroscope, settings: MicroscopeSettings, @@ -1020,176 +969,6 @@ def run_thinning_workflow( return experiment - -# TODO: START_HERE: remove ui function, use core ui -# def _validate_mill_ui(stages: list[FibsemMillingStage], parent_ui: AutoLiftoutUIv2, msg:str, validate: bool, milling_enabled: bool = True): - -# _update_mill_stages_ui(parent_ui, stages=stages) - -# if validate: -# response = ask_user(parent_ui, msg=msg, pos="Continue", mill=milling_enabled) -# stages = deepcopy(parent_ui.milling_widget.get_milling_stages()) -# else: -# _update_status_ui(parent_ui, f"Milling {len(stages)} stages...") -# parent_ui._MILLING_RUNNING = True -# parent_ui._run_milling_signal.emit() - -# logging.info(f"WAITING FOR MILLING TO FINISH... ") -# while parent_ui._MILLING_RUNNING or parent_ui.image_widget.TAKING_IMAGES: - -# time.sleep(1) - -# _update_status_ui( -# parent_ui, f"Milling Complete: {len(stages)} stages completed." -# ) -# parent_ui.WAITING_FOR_UI_UPDATE = True - -# _update_mill_stages_ui(parent_ui, stages="clear") - -# logging.info(f"WAITING FOR UI UPDATE... ") -# while parent_ui.WAITING_FOR_UI_UPDATE: -# time.sleep(0.5) - -# return stages - -# TODO: think this can be consolidated into mill arg for ask_user? -# def _update_mill_stages_ui(parent_ui: AutoLiftoutUIv2, stages: list[FibsemMillingStage] = None): -# INFO = { -# "msg": "Updating Milling Stages", -# "pos": None, -# "neg": None, -# "det": None, -# "eb_image": None, -# "ib_image": None, -# "movement": None, -# "mill": None, -# "stages": stages -# } - -# parent_ui.ui_signal.emit(INFO) - -# def _validate_det_ui_v2(microscope, settings, features, parent_ui, validate:bool, msg: str = "Lamella") -> DetectedFeatures: - -# feat_str = ", ".join([f.name for f in features]) -# _update_status_ui( -# parent_ui, f"{msg}: Detecting Features ({feat_str})..." -# ) - -# det = detection.take_image_and_detect_features( -# microscope=microscope, -# settings=settings, -# features=features, -# ) - -# if validate: -# ask_user( -# parent_ui, -# msg=f"Confirm Feature Detection. Press Continue to proceed.", -# pos="Continue", -# det=det, -# ) - -# det = parent_ui.det_widget._get_detected_features() - -# # I need this to happen in the parent thread for it to work correctly -# parent_ui.det_confirm_signal.emit(True) - -# # image = acquire.last_image(microscope, settings.image.beam_type) -# # if settings.image.beam_type is BeamType.ELECTRON: -# # eb_image, ib_image = image, None -# # else: -# # eb_image, ib_image = None, image -# # _set_images_ui(parent_ui, eb_image=eb_image, ib_image=ib_image) - -# return det - - -# def _set_images_ui( -# parent_ui: AutoLiftoutUIv2, -# eb_image: FibsemImage = None, -# ib_image: FibsemImage = None, -# ): - -# INFO = { -# "msg": "Updating Images", -# "pos": None, -# "neg": None, -# "det": None, -# "eb_image": deepcopy(eb_image), -# "ib_image": deepcopy(ib_image), -# "movement": None, -# "mill": None, -# } -# parent_ui.WAITING_FOR_UI_UPDATE = True -# parent_ui.ui_signal.emit(INFO) - -# logging.info(f"WAITING FOR UI UPDATE... ") -# while parent_ui.WAITING_FOR_UI_UPDATE: -# time.sleep(0.5) - -# logging.info(f"UI UPDATE COMPLETE... ") - -# def _update_status_ui(parent_ui: AutoLiftoutUIv2, msg: str): -# if parent_ui is None: -# logging.info(msg) -# return - -# INFO = { -# "msg": msg, -# "pos": None, -# "neg": None, -# "det": None, -# "eb_image": None, -# "ib_image": None, -# "movement": None, -# "mill": None, -# } -# parent_ui.ui_signal.emit(INFO) - -# def ask_user( -# parent_ui: AutoLiftoutUIv2, -# msg: str, -# pos: str, -# neg: str = None, -# image: bool = True, -# movement: bool = True, -# mill: bool = None, -# det: DetectedFeatures = None, -# ) -> bool: - -# INFO = { -# "msg": msg, -# "pos": pos, -# "neg": neg, -# "det": det, -# "eb_image": None, -# "ib_image": None, -# "movement": movement, -# "mill": mill, -# } -# parent_ui.ui_signal.emit(INFO) - -# parent_ui.WAITING_FOR_USER_INTERACTION = True -# logging.info("WAITING_FOR_USER_INTERACTION...") -# while parent_ui.WAITING_FOR_USER_INTERACTION: -# time.sleep(1) -# # print("waiting for user interaction") - -# INFO = { -# "msg": "", -# "pos": None, -# "neg": None, -# "det": None, -# "eb_image": None, -# "ib_image": None, -# "movement": None, -# "mill": None, -# } -# parent_ui.ui_signal.emit(INFO) - -# return parent_ui.USER_RESPONSE - - def get_current_lamella( experiment: Experiment, parent_ui: AutoLiftoutUIv2 ) -> bool: diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index 702d616d..cecbbdc3 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -701,7 +701,7 @@ def _threaded_worker(self, microscope, settings, experiment, workflow="setup"): experiment=experiment, parent_ui=self, ) - elif workflow == "serial-landing": + elif workflow == "serial-liftout-landing": from autolamella.liftout.workflows import serial as serial_workflow self.experiment = serial_workflow.run_serial_liftout_landing( From bebde8d404a41ea5fa8482b5a9bb0f058873c817 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 08:42:27 +1000 Subject: [PATCH 10/39] bump version --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 06abf431..091fdccb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = autolamella -version = 0.2.4 +version = 0.2.5a0 author = Genevieve Buckley description = Automatated ion beam milling for cryo-electron microscopy sample preparation. long_description = file: README.md From 667b2a267d04577570e068314c1e22c69ca1ea6a Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 09:34:54 +1000 Subject: [PATCH 11/39] integrate landinggridcentre into serial workflow --- autolamella/liftout/workflows/serial.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index 92be1717..698fc616 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -12,6 +12,7 @@ LamellaRightEdge, NeedleTip, LandingPost, + LandingGridCentre, LamellaTopEdge, LamellaBottomEdge, CopperAdapterBottomEdge, @@ -269,7 +270,7 @@ def land_lamella( _set_images_ui(parent_ui, eb_image, ib_image) - # DETECT LAMELLA BOTTOM EDGE, LANDINGPOST_TOP + # DETECT LAMELLA BOTTOM EDGE, LandingGridCentre_TOP # align manipulator to top of lamella log_status_message(lamella, "NEEDLE_IB_DETECTION") _update_status_ui(parent_ui, f"{lamella.info} Moving Lamella to Landing Post...") @@ -284,7 +285,7 @@ def land_lamella( # DETECT COPPER ADAPTER, LAMELLA TOP scan_rotation = microscope.get("scan_rotation", beam_type=BeamType.ION) - features = [LamellaTopEdge() if np.isclose(scan_rotation, 0) else LamellaBottomEdge(), LandingPost()] # TODO: SCAN_ROTATION FOR LANDING_POST + features = [LamellaTopEdge() if np.isclose(scan_rotation, 0) else LamellaBottomEdge(), LandingGridCentre()] # TODO: SCAN_ROTATION FOR LANDING_POST det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) # hover 25um above the post @@ -303,7 +304,7 @@ def land_lamella( # settings.image.hfw = fcfg.REFERENCE_HFW_MEDIUM # # DETECT COPPER ADAPTER, LAMELLA TOP - # features = [LamellaTopEdge() if np.isclose(scan_rotation, 0) else LamellaBottomEdge(), LandingPost()] # TODO: SCAN_ROTATION FOR LANDING_POST + # features = [LamellaTopEdge() if np.isclose(scan_rotation, 0) else LamellaBottomEdge(), LandingGridCentre()] # TODO: SCAN_ROTATION FOR LANDING_POST # det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) # # MOVE TO LANDING POST From 96894ff1e0c8782662e8f01a879d54902886dfd4 Mon Sep 17 00:00:00 2001 From: LucileNaegele Date: Thu, 28 Sep 2023 13:43:12 +1000 Subject: [PATCH 12/39] V0.2 dev display lamellas ion beam (#141) Display all lamella positions within the view --------- Co-authored-by: Patrick Cleeve <80024299+patrickcleeve2@users.noreply.github.com> Co-authored-by: Patrick Cleeve --- autolamella/ui/AutoLamellaUI.py | 61 +++++++- autolamella/ui/qt/AutoLamellaUI.py | 130 +++++++++-------- autolamella/ui/qt/AutoLamellaUI.ui | 227 +++++++++++++++-------------- autolamella/ui/utils.py | 34 ++++- 4 files changed, 272 insertions(+), 180 deletions(-) diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index 75b9fee3..c7f323ed 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -12,7 +12,7 @@ from fibsem.microscope import FibsemMicroscope from fibsem.structures import ( MicroscopeSettings, - FibsemStagePosition, Point + FibsemStagePosition, Point, BeamType ) from fibsem.ui.FibsemImageSettingsWidget import FibsemImageSettingsWidget from fibsem.ui.FibsemMovementWidget import FibsemMovementWidget @@ -37,6 +37,7 @@ from PyQt5.QtCore import pyqtSignal from autolamella.ui import _stylesheets from collections import Counter +import numpy as np _DEV_MODE = False @@ -90,7 +91,8 @@ def __init__(self, viewer: napari.Viewer) -> None: self._MILLING_RUNNING: bool = False self._WORKFLOW_RUNNING: bool = False self._ABORT_THREAD: bool = False - + self.checkBox_show_lamella_in_view.setChecked(True) + self.checkBox_show_lamella_in_view.stateChanged.connect(self.update_lamella_ui) # setup connections self.setup_connections() @@ -351,7 +353,7 @@ def update_microscope_ui(self): self._microscope_ui_loaded = True self.milling_widget.milling_position_changed.connect(self._update_milling_position) self.milling_widget._milling_finished.connect(self._milling_finished) - + self.image_widget.picture_signal.connect(self.update_lamella_ui) else: if self.image_widget is None: return @@ -564,15 +566,25 @@ def update_ui(self): self.pushButton_run_autolamella.setVisible(True) self.pushButton_run_autolamella.setEnabled(_ENABLE_AUTOLAMELLA) - self.pushButton_run_waffle_trench.setStyleSheet(_stylesheets._GREEN_PUSHBUTTON_STYLE if _ENABLE_TRENCH else _stylesheets._DISABLED_PUSHBUTTON_STYLE) self.pushButton_run_waffle_undercut.setStyleSheet(_stylesheets._GREEN_PUSHBUTTON_STYLE if _ENABLE_UNDERCUT else _stylesheets._DISABLED_PUSHBUTTON_STYLE) self.pushButton_run_setup_autolamella.setStyleSheet(_stylesheets._GREEN_PUSHBUTTON_STYLE if _ENABLE_LAMELLA else _stylesheets._DISABLED_PUSHBUTTON_STYLE) self.pushButton_run_autolamella.setStyleSheet(_stylesheets._GREEN_PUSHBUTTON_STYLE if _ENABLE_AUTOLAMELLA else _stylesheets._DISABLED_PUSHBUTTON_STYLE) + if self._WORKFLOW_RUNNING: + self.pushButton_run_waffle_trench.setEnabled(False) + self.pushButton_run_waffle_undercut.setEnabled(False) + self.pushButton_run_setup_autolamella.setEnabled(False) + self.pushButton_run_autolamella.setEnabled(False) + self.pushButton_run_waffle_trench.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + self.pushButton_run_waffle_undercut.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + self.pushButton_run_setup_autolamella.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + self.pushButton_run_autolamella.setStyleSheet(_stylesheets._DISABLED_PUSHBUTTON_STYLE) + # Current Lamella Status if _lamella_selected: self.update_lamella_ui() + self.checkBox_show_lamella_in_view.setVisible(_lamella_selected) # instructions# TODO: update with autolamella instructions INSTRUCTIONS = {"NOT_CONNECTED": "Please connect to the microscope (System -> Connect to Microscope).", @@ -644,6 +656,9 @@ def update_lamella_ui(self): if self.experiment.positions == []: return + if self._WORKFLOW_RUNNING: + return + idx = self.comboBox_current_lamella.currentIndex() lamella: Lamella = self.experiment.positions[idx] @@ -671,6 +686,43 @@ def update_lamella_ui(self): self.pushButton_save_position.setEnabled(False) self.milling_widget._PATTERN_IS_MOVEABLE = True + if self.checkBox_show_lamella_in_view.isChecked(): + lamellas = [] + text = [] + positions = deepcopy(self.experiment.positions) + if self.image_widget.ib_image is not None: + fui._remove_all_layers(self.viewer, layer_type = napari.layers.points.points.Points) + for lamella in positions: + if method == "autolamella-waffle" and lamella.state.stage in [AutoLamellaWaffleStage.SetupTrench, AutoLamellaWaffleStage.ReadyTrench]: + lamella_centre = Point.__from_dict__(lamella.protocol.get("trench", {}).get("point", {"x": 0, "y": 0})) # centre of pattern in the image + else: + lamella_centre = Point.__from_dict__(lamella.protocol.get("lamella", {}).get("point", {"x": 0, "y": 0})) + + current_position = lamella.state.microscope_state.absolute_position + lamella_position = self.microscope._calculate_new_position( + settings=self.settings, + dx=lamella_centre.x, dy=lamella_centre.y, + beam_type=BeamType.ION, + base_position=current_position) + lamella_position.name = lamella._petname + lamellas.append(lamella_position) + + from fibsem.imaging._tile import _reproject_positions + points = _reproject_positions(self.image_widget.ib_image, lamellas, _bound = True) + for i in range(len(points)): + temp = Point(x= points[i].y, y =points[i].x) + temp.y += self.image_widget.eb_image.data.shape[1] #napari dimensions are swapped + temp.name = points[i].name + points[i] = temp + text.append(points[i].name) + position_text = { + "string": text, + "color": "lime", + "translation": np.array([-25, 0]) + } + self.viewer.add_points(points, text=position_text, size=10, symbol="x", face_color="lime", edge_color="white", name="lamella_positions") + else: + fui._remove_all_layers(self.viewer, layer_type = napari.layers.points.points.Points) # update the milling widget if self._WORKFLOW_RUNNING: self.milling_widget._PATTERN_IS_MOVEABLE = True @@ -1126,6 +1178,7 @@ def _threaded_worker(self, microscope: FibsemMicroscope, settings: MicroscopeSet self.milling_widget._PATTERN_IS_MOVEABLE = True self.milling_widget._remove_all_stages() self.WAITING_FOR_USER_INTERACTION = False + fui._remove_all_layers(self.viewer, layer_type = napari.layers.points.points.Points) self.pushButton_run_waffle_trench.setEnabled(False) self.pushButton_run_waffle_undercut.setEnabled(False) self.pushButton_run_setup_autolamella.setEnabled(False) diff --git a/autolamella/ui/qt/AutoLamellaUI.py b/autolamella/ui/qt/AutoLamellaUI.py index 107df937..2d3cb171 100644 --- a/autolamella/ui/qt/AutoLamellaUI.py +++ b/autolamella/ui/qt/AutoLamellaUI.py @@ -35,26 +35,10 @@ def setupUi(self, MainWindow): self.tab.setObjectName("tab") self.gridLayout_3 = QtWidgets.QGridLayout(self.tab) self.gridLayout_3.setObjectName("gridLayout_3") - self.pushButton_run_setup_autolamella = QtWidgets.QPushButton(self.tab) - self.pushButton_run_setup_autolamella.setObjectName("pushButton_run_setup_autolamella") - self.gridLayout_3.addWidget(self.pushButton_run_setup_autolamella, 20, 0, 1, 2) self.pushButton_remove_lamella = QtWidgets.QPushButton(self.tab) self.pushButton_remove_lamella.setStyleSheet("") self.pushButton_remove_lamella.setObjectName("pushButton_remove_lamella") self.gridLayout_3.addWidget(self.pushButton_remove_lamella, 7, 1, 1, 1) - self.label_title = QtWidgets.QLabel(self.tab) - font = QtGui.QFont() - font.setPointSize(12) - font.setBold(True) - font.setWeight(75) - self.label_title.setFont(font) - self.label_title.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) - self.label_title.setObjectName("label_title") - self.gridLayout_3.addWidget(self.label_title, 0, 0, 1, 1) - self.label_minimap = QtWidgets.QLabel(self.tab) - self.label_minimap.setText("") - self.label_minimap.setObjectName("label_minimap") - self.gridLayout_3.addWidget(self.label_minimap, 16, 0, 1, 2) self.label_setup_header = QtWidgets.QLabel(self.tab) font = QtGui.QFont() font.setPointSize(9) @@ -63,39 +47,11 @@ def setupUi(self, MainWindow): self.label_setup_header.setFont(font) self.label_setup_header.setObjectName("label_setup_header") self.gridLayout_3.addWidget(self.label_setup_header, 3, 0, 1, 1) - self.pushButton_go_to_lamella = QtWidgets.QPushButton(self.tab) - self.pushButton_go_to_lamella.setObjectName("pushButton_go_to_lamella") - self.gridLayout_3.addWidget(self.pushButton_go_to_lamella, 10, 1, 1, 1) - self.pushButton_run_waffle_undercut = QtWidgets.QPushButton(self.tab) - self.pushButton_run_waffle_undercut.setObjectName("pushButton_run_waffle_undercut") - self.gridLayout_3.addWidget(self.pushButton_run_waffle_undercut, 19, 0, 1, 2) self.pushButton_run_waffle_trench = QtWidgets.QPushButton(self.tab) self.pushButton_run_waffle_trench.setDefault(False) self.pushButton_run_waffle_trench.setFlat(False) self.pushButton_run_waffle_trench.setObjectName("pushButton_run_waffle_trench") - self.gridLayout_3.addWidget(self.pushButton_run_waffle_trench, 18, 0, 1, 2) - self.comboBox_lamella_history = QtWidgets.QComboBox(self.tab) - self.comboBox_lamella_history.setObjectName("comboBox_lamella_history") - self.gridLayout_3.addWidget(self.comboBox_lamella_history, 12, 0, 1, 1) - self.label_experiment_name = QtWidgets.QLabel(self.tab) - self.label_experiment_name.setObjectName("label_experiment_name") - self.gridLayout_3.addWidget(self.label_experiment_name, 1, 0, 1, 2) - self.pushButton_add_lamella = QtWidgets.QPushButton(self.tab) - self.pushButton_add_lamella.setObjectName("pushButton_add_lamella") - self.gridLayout_3.addWidget(self.pushButton_add_lamella, 7, 0, 1, 1) - self.comboBox_current_lamella = QtWidgets.QComboBox(self.tab) - self.comboBox_current_lamella.setObjectName("comboBox_current_lamella") - self.gridLayout_3.addWidget(self.comboBox_current_lamella, 8, 1, 1, 1) - self.label_current_lamella_header = QtWidgets.QLabel(self.tab) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label_current_lamella_header.setFont(font) - self.label_current_lamella_header.setObjectName("label_current_lamella_header") - self.gridLayout_3.addWidget(self.label_current_lamella_header, 8, 0, 1, 1) - self.pushButton_save_position = QtWidgets.QPushButton(self.tab) - self.pushButton_save_position.setObjectName("pushButton_save_position") - self.gridLayout_3.addWidget(self.pushButton_save_position, 10, 0, 1, 1) + self.gridLayout_3.addWidget(self.pushButton_run_waffle_trench, 19, 0, 1, 2) self.pushButton_run_autolamella = QtWidgets.QPushButton(self.tab) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) @@ -252,23 +208,70 @@ def setupUi(self, MainWindow): self.pushButton_run_autolamella.setDefault(False) self.pushButton_run_autolamella.setFlat(False) self.pushButton_run_autolamella.setObjectName("pushButton_run_autolamella") - self.gridLayout_3.addWidget(self.pushButton_run_autolamella, 22, 0, 1, 2) + self.gridLayout_3.addWidget(self.pushButton_run_autolamella, 23, 0, 1, 2) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_3.addItem(spacerItem1, 13, 0, 1, 2) + self.pushButton_add_lamella = QtWidgets.QPushButton(self.tab) + self.pushButton_add_lamella.setObjectName("pushButton_add_lamella") + self.gridLayout_3.addWidget(self.pushButton_add_lamella, 7, 0, 1, 1) + spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_3.addItem(spacerItem2, 18, 0, 1, 2) + self.pushButton_run_waffle_undercut = QtWidgets.QPushButton(self.tab) + self.pushButton_run_waffle_undercut.setObjectName("pushButton_run_waffle_undercut") + self.gridLayout_3.addWidget(self.pushButton_run_waffle_undercut, 20, 0, 1, 2) + self.label_title = QtWidgets.QLabel(self.tab) + font = QtGui.QFont() + font.setPointSize(12) + font.setBold(True) + font.setWeight(75) + self.label_title.setFont(font) + self.label_title.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.label_title.setObjectName("label_title") + self.gridLayout_3.addWidget(self.label_title, 0, 0, 1, 1) self.label_info = QtWidgets.QLabel(self.tab) self.label_info.setObjectName("label_info") - self.gridLayout_3.addWidget(self.label_info, 14, 0, 1, 2) + self.gridLayout_3.addWidget(self.label_info, 15, 0, 1, 2) + self.pushButton_go_to_lamella = QtWidgets.QPushButton(self.tab) + self.pushButton_go_to_lamella.setObjectName("pushButton_go_to_lamella") + self.gridLayout_3.addWidget(self.pushButton_go_to_lamella, 10, 1, 1, 1) self.label_protocol_name = QtWidgets.QLabel(self.tab) self.label_protocol_name.setObjectName("label_protocol_name") self.gridLayout_3.addWidget(self.label_protocol_name, 2, 0, 1, 2) - self.pushButton_revert_stage = QtWidgets.QPushButton(self.tab) - self.pushButton_revert_stage.setObjectName("pushButton_revert_stage") - self.gridLayout_3.addWidget(self.pushButton_revert_stage, 12, 1, 1, 1) + self.label_experiment_name = QtWidgets.QLabel(self.tab) + self.label_experiment_name.setObjectName("label_experiment_name") + self.gridLayout_3.addWidget(self.label_experiment_name, 1, 0, 1, 2) + self.label_minimap = QtWidgets.QLabel(self.tab) + self.label_minimap.setText("") + self.label_minimap.setObjectName("label_minimap") + self.gridLayout_3.addWidget(self.label_minimap, 17, 0, 1, 2) + self.comboBox_current_lamella = QtWidgets.QComboBox(self.tab) + self.comboBox_current_lamella.setObjectName("comboBox_current_lamella") + self.gridLayout_3.addWidget(self.comboBox_current_lamella, 8, 1, 1, 1) + self.pushButton_save_position = QtWidgets.QPushButton(self.tab) + self.pushButton_save_position.setObjectName("pushButton_save_position") + self.gridLayout_3.addWidget(self.pushButton_save_position, 10, 0, 1, 1) self.pushButton_fail_lamella = QtWidgets.QPushButton(self.tab) self.pushButton_fail_lamella.setObjectName("pushButton_fail_lamella") self.gridLayout_3.addWidget(self.pushButton_fail_lamella, 11, 1, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_3.addItem(spacerItem1, 13, 0, 1, 2) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_3.addItem(spacerItem2, 17, 0, 1, 2) + self.label_current_lamella_header = QtWidgets.QLabel(self.tab) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_current_lamella_header.setFont(font) + self.label_current_lamella_header.setObjectName("label_current_lamella_header") + self.gridLayout_3.addWidget(self.label_current_lamella_header, 8, 0, 1, 1) + self.comboBox_lamella_history = QtWidgets.QComboBox(self.tab) + self.comboBox_lamella_history.setObjectName("comboBox_lamella_history") + self.gridLayout_3.addWidget(self.comboBox_lamella_history, 12, 0, 1, 1) + self.pushButton_run_setup_autolamella = QtWidgets.QPushButton(self.tab) + self.pushButton_run_setup_autolamella.setObjectName("pushButton_run_setup_autolamella") + self.gridLayout_3.addWidget(self.pushButton_run_setup_autolamella, 21, 0, 1, 2) + self.pushButton_revert_stage = QtWidgets.QPushButton(self.tab) + self.pushButton_revert_stage.setObjectName("pushButton_revert_stage") + self.gridLayout_3.addWidget(self.pushButton_revert_stage, 12, 1, 1, 1) + self.checkBox_show_lamella_in_view = QtWidgets.QCheckBox(self.tab) + self.checkBox_show_lamella_in_view.setObjectName("checkBox_show_lamella_in_view") + self.gridLayout_3.addWidget(self.checkBox_show_lamella_in_view, 14, 0, 1, 1) self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") @@ -438,22 +441,23 @@ def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label_instructions.setText(_translate("MainWindow", "Instructions")) - self.pushButton_run_setup_autolamella.setText(_translate("MainWindow", "Run Setup AutoLamella")) self.pushButton_remove_lamella.setText(_translate("MainWindow", "Remove Lamella")) - self.label_title.setText(_translate("MainWindow", "AutoLamella")) self.label_setup_header.setText(_translate("MainWindow", "Setup")) - self.pushButton_go_to_lamella.setText(_translate("MainWindow", "Go to position")) - self.pushButton_run_waffle_undercut.setText(_translate("MainWindow", "Run Waffle Undercut Milling")) self.pushButton_run_waffle_trench.setText(_translate("MainWindow", "Run Waffle Trench Milling")) - self.label_experiment_name.setText(_translate("MainWindow", "Experiment:")) - self.pushButton_add_lamella.setText(_translate("MainWindow", "Add Lamella")) - self.label_current_lamella_header.setText(_translate("MainWindow", "Current Lamella")) - self.pushButton_save_position.setText(_translate("MainWindow", "Save Position")) self.pushButton_run_autolamella.setText(_translate("MainWindow", "Run AutoLamella")) + self.pushButton_add_lamella.setText(_translate("MainWindow", "Add Lamella")) + self.pushButton_run_waffle_undercut.setText(_translate("MainWindow", "Run Waffle Undercut Milling")) + self.label_title.setText(_translate("MainWindow", "AutoLamella")) self.label_info.setText(_translate("MainWindow", "No Lamella Selected")) + self.pushButton_go_to_lamella.setText(_translate("MainWindow", "Go to position")) self.label_protocol_name.setText(_translate("MainWindow", "Protocol:")) - self.pushButton_revert_stage.setText(_translate("MainWindow", "Time Travel To")) + self.label_experiment_name.setText(_translate("MainWindow", "Experiment:")) + self.pushButton_save_position.setText(_translate("MainWindow", "Save Position")) self.pushButton_fail_lamella.setText(_translate("MainWindow", "Mark Lamella As Failed")) + self.label_current_lamella_header.setText(_translate("MainWindow", "Current Lamella")) + self.pushButton_run_setup_autolamella.setText(_translate("MainWindow", "Run Setup AutoLamella")) + self.pushButton_revert_stage.setText(_translate("MainWindow", "Time Travel To")) + self.checkBox_show_lamella_in_view.setText(_translate("MainWindow", "Show Lamellas In View")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Experiment")) self.label_protocol_name_2.setText(_translate("MainWindow", "Name")) self.label_protocol_method.setText(_translate("MainWindow", "Method")) diff --git a/autolamella/ui/qt/AutoLamellaUI.ui b/autolamella/ui/qt/AutoLamellaUI.ui index b435c429..1abd8b12 100644 --- a/autolamella/ui/qt/AutoLamellaUI.ui +++ b/autolamella/ui/qt/AutoLamellaUI.ui @@ -63,13 +63,6 @@ Experiment - - - - Run Setup AutoLamella - - - @@ -80,30 +73,6 @@ - - - - - 12 - 75 - true - - - - AutoLamella - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - @@ -118,21 +87,7 @@ - - - - Go to position - - - - - - Run Waffle Undercut Milling - - - - Run Waffle Trench Milling @@ -145,47 +100,7 @@ - - - - - - - Experiment: - - - - - - - Add Lamella - - - - - - - - - - - 75 - true - - - - Current Lamella - - - - - - - Save Position - - - - + @@ -652,13 +567,77 @@ - + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Add Lamella + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Run Waffle Undercut Milling + + + + + + + + 12 + 75 + true + + + + AutoLamella + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + No Lamella Selected + + + + Go to position + + + @@ -666,10 +645,27 @@ - - + + - Time Travel To + Experiment: + + + + + + + + + + + + + + + + + Save Position @@ -680,31 +676,42 @@ - - - - Qt::Vertical + + + + + 75 + true + - - - 20 - 40 - + + Current Lamella - + - - - - Qt::Vertical + + + + + + + Run Setup AutoLamella - - - 20 - 40 - + + + + + + Time Travel To - + + + + + + Show Lamellas In View + + diff --git a/autolamella/ui/utils.py b/autolamella/ui/utils.py index 86816468..e9d2e633 100644 --- a/autolamella/ui/utils.py +++ b/autolamella/ui/utils.py @@ -4,8 +4,8 @@ from PyQt5 import QtWidgets from autolamella import config as cfg -from autolamella.structures import Experiment - +from autolamella.structures import Experiment, Lamella +from fibsem.structures import Point, FibsemImage, FibsemStagePosition def setup_experiment_ui_v2( parent_ui: QtWidgets.QMainWindow, new_experiment: bool = True @@ -69,4 +69,32 @@ def create_experiment_ui(parent, experiment = Experiment(path=PATH, name=NAME) experiment.save() - return experiment \ No newline at end of file + return experiment + + +def lamella_in_view(lamella: Lamella, lamella_centre: Point, ib_image: FibsemImage): + + # get effective lamella position + lamella_offset = FibsemStagePosition(x = lamella_centre.x, y = lamella_centre.y, z = 0) + lamella_position = lamella.state.microscope_state.absolute_position.__add__(lamella_offset) + + + + + # get image bounds + x = ib_image.metadata.microscope_state.absolute_position.x + z = ib_image.metadata.microscope_state.absolute_position.z + x_bounds = [0,0] + z_bounds = [0,0] + x_bounds[0] = x - ib_image.metadata.image_settings.resolution[0]/2 * ib_image.metadata.pixel_size.x + x_bounds[1] = x + ib_image.metadata.image_settings.resolution[0]/2 * ib_image.metadata.pixel_size.x + + z_bounds[0] = z - ib_image.metadata.image_settings.resolution[1]/2 * ib_image.metadata.pixel_size.y + z_bounds[1] = z + ib_image.metadata.image_settings.resolution[1]/2 * ib_image.metadata.pixel_size.y + + + # check if lamella is in view + if x_bounds[0] < lamella_position.x < x_bounds[1] and z_bounds[0] < lamella_position.z < z_bounds[1]: + return True, lamella_position + else: + return False, lamella_position From 8cb7c969d29e9741668ec120ce1674315e331b1a Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 13:51:43 +1000 Subject: [PATCH 13/39] todo: note --- autolamella/ui/AutoLamellaUI.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index c7f323ed..65bab920 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -690,6 +690,8 @@ def update_lamella_ui(self): lamellas = [] text = [] positions = deepcopy(self.experiment.positions) + + # TODO: we can wrap this up a bit, for re-use if self.image_widget.ib_image is not None: fui._remove_all_layers(self.viewer, layer_type = napari.layers.points.points.Points) for lamella in positions: From e952147f525180690c3b2194f5b244ac7eea1758 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 16:32:58 +1000 Subject: [PATCH 14/39] depreciate MillFeatures and MillRegularCut --- autolamella/liftout/autoliftout.py | 2 - autolamella/liftout/structures.py | 1 - autolamella/liftout/ui/AutoLiftoutUIv2.py | 1 - autolamella/liftout/workflows/serial.py | 1 - autolamella/structures.py | 2 - autolamella/ui/AutoLamellaUI.py | 4 +- autolamella/waffle.py | 6 +- autolamella/workflows/core.py | 126 +++++++--------------- 8 files changed, 39 insertions(+), 104 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index a1ecaa20..f46a84a4 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -832,7 +832,6 @@ def run_setup_autoliftout( AutoLiftoutStage.Landing: land_lamella, AutoLiftoutStage.SetupLamella: setup_lamella, AutoLiftoutStage.MillRoughCut: mill_lamella, - AutoLiftoutStage.MillRegularCut: mill_lamella, AutoLiftoutStage.MillPolishingCut: mill_lamella, } @@ -946,7 +945,6 @@ def run_thinning_workflow( for next_stage in [ AutoLiftoutStage.SetupLamella, AutoLiftoutStage.MillRoughCut, - AutoLiftoutStage.MillRegularCut, AutoLiftoutStage.MillPolishingCut, ]: for lamella in experiment.positions: diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index f165143b..81d61114 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -24,7 +24,6 @@ class AutoLiftoutStage(Enum): Landing = auto() SetupLamella = auto() MillRoughCut = auto() - MillRegularCut = auto() MillPolishingCut = auto() Finished = auto() diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index cecbbdc3..0d4ff3e1 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -176,7 +176,6 @@ def update_ui(self): _LAMELLA_LANDED = _counter[AutoLiftoutStage.Landing.name] > 0 _AUTOLAMELLA_PROGRESS = (_counter[AutoLiftoutStage.SetupLamella.name]>0 or _counter[AutoLiftoutStage.MillRoughCut.name] > 0 - or _counter[AutoLiftoutStage.MillRegularCut.name] > 0 or _counter[AutoLiftoutStage.MillPolishingCut.name] > 0) # setup experiment -> connect to microscope -> select lamella -> run autoliftout -> run polishing diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index 698fc616..ae7ed126 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -411,7 +411,6 @@ def land_lamella( AutoLiftoutStage.Landing: land_lamella, AutoLiftoutStage.SetupLamella: setup_lamella, AutoLiftoutStage.MillRoughCut: mill_lamella, - AutoLiftoutStage.MillRegularCut: mill_lamella, AutoLiftoutStage.MillPolishingCut: mill_lamella, } diff --git a/autolamella/structures.py b/autolamella/structures.py index 2ecfff45..969935b5 100644 --- a/autolamella/structures.py +++ b/autolamella/structures.py @@ -20,9 +20,7 @@ class AutoLamellaWaffleStage(Enum): MillUndercut = auto() SetupLamella = auto() ReadyLamella = auto() - MillFeatures = auto() MillRoughCut = auto() - MillRegularCut = auto() MillPolishingCut = auto() Finished = auto() PreSetupLamella = auto() diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index 65bab920..96971609 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -546,10 +546,8 @@ def update_ui(self): _READY_UNDERCUT = _counter[AutoLamellaWaffleStage.MillTrench.name] > 0 _READY_LAMELLA = _counter[AutoLamellaWaffleStage.SetupLamella.name] > 0 _READY_AUTOLAMELLA = _counter[AutoLamellaWaffleStage.ReadyLamella.name] > 0 - _READY_FEATURES = _counter[AutoLamellaWaffleStage.MillFeatures.name] > 0 _READY_ROUGH = _counter[AutoLamellaWaffleStage.MillRoughCut.name] > 0 - _READY_REGULAR = _counter[AutoLamellaWaffleStage.MillRegularCut.name] > 0 - _READY_AUTOLAMELLA = _READY_AUTOLAMELLA or _READY_FEATURES or _READY_ROUGH or _READY_REGULAR + _READY_AUTOLAMELLA = _READY_AUTOLAMELLA or _READY_ROUGH _ENABLE_TRENCH = _WAFFLE_METHOD and _READY_TRENCH _ENABLE_UNDERCUT = _WAFFLE_METHOD and _READY_UNDERCUT diff --git a/autolamella/waffle.py b/autolamella/waffle.py index 56771709..e7cd3df1 100644 --- a/autolamella/waffle.py +++ b/autolamella/waffle.py @@ -5,15 +5,13 @@ Experiment, ) from autolamella.ui.AutoLamellaUI import AutoLamellaUI -from autolamella.workflows.core import ( log_status_message, mill_trench, mill_undercut, mill_feature, mill_lamella, setup_lamella, start_of_stage_update, end_of_stage_update) +from autolamella.workflows.core import ( log_status_message, mill_trench, mill_undercut, mill_lamella, setup_lamella, start_of_stage_update, end_of_stage_update) WORKFLOW_STAGES = { AutoLamellaWaffleStage.MillTrench: mill_trench, AutoLamellaWaffleStage.MillUndercut: mill_undercut, AutoLamellaWaffleStage.ReadyLamella: setup_lamella, - AutoLamellaWaffleStage.MillFeatures: mill_feature, AutoLamellaWaffleStage.MillRoughCut: mill_lamella, - AutoLamellaWaffleStage.MillRegularCut: mill_lamella, AutoLamellaWaffleStage.MillPolishingCut: mill_lamella, } @@ -110,9 +108,7 @@ def run_lamella_milling( stages = [ - AutoLamellaWaffleStage.MillFeatures, AutoLamellaWaffleStage.MillRoughCut, - AutoLamellaWaffleStage.MillRegularCut, AutoLamellaWaffleStage.MillPolishingCut, ] for stage in stages: diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 54c4fea3..6e75a8d4 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -289,70 +289,6 @@ def mill_undercut( -def mill_feature( - microscope: FibsemMicroscope, - settings: MicroscopeSettings, - lamella: Lamella, - parent_ui: AutoLamellaUI = None, -) -> Lamella: - - validate = settings.protocol["options"]["supervise"].get("features", True) - settings.image.save_path = lamella.path - method = settings.protocol.get("method", "autolamella-waffle") - - # check if using notch or microexpansion - _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" - - stages = patterning._get_milling_stages( - _feature_name, lamella.protocol, point=Point.__from_dict__(lamella.protocol[_feature_name]["point"]) - ) - - log_status_message(lamella, "ALIGN_REFERENCE") - settings.image.save = True - settings.image.hfw = fcfg.REFERENCE_HFW_SUPER - settings.image.beam_type = BeamType.ION - ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) - _ALIGNMENT_ATTEMPTS = int(settings.protocol["options"].get("alignment_attempts", 3)) - - for i in range(_ALIGNMENT_ATTEMPTS): - settings.image.label = f"alignment_target_{lamella.state.stage.name}_{i:02d}" - settings.image.beam_type = BeamType.ION - alignment.beam_shift_alignment(microscope, settings.image, - ref_image=ref_image, - reduced_area=lamella.fiducial_area) - settings.image.reduced_area = None - - settings.image.hfw = fcfg.REFERENCE_HFW_SUPER - settings.image.label = f"ref_{lamella.state.stage.name}_start" - settings.image.save = True - eb_image, ib_image = acquire.take_reference_images(microscope, settings.image) - _set_images_ui(parent_ui, eb_image, ib_image) - _update_status_ui(parent_ui, f"{lamella.info} Preparing {_feature_name}...") - - # define notch/microexpansion - log_status_message(lamella, "MILL_FEATURES") - - stages = _validate_mill_ui(stages, parent_ui, - msg=f"Press Run Milling to mill the {_feature_name} for {lamella._petname}. Press Continue when done.", - validate=validate, - ) - - # log feature stages - lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages)) - lamella.protocol[_feature_name]["point"] = stages[0].pattern.point.__to_dict__() - - # take reference images - log_status_message(lamella, "REFERENCE_IMAGES") - reference_images = acquire.take_set_of_reference_images( - microscope=microscope, - image_settings=settings.image, - hfws=[fcfg.REFERENCE_HFW_MEDIUM, fcfg.REFERENCE_HFW_SUPER], - label=f"ref_{lamella.state.stage.name}_final", - ) - _set_images_ui(parent_ui, reference_images.high_res_eb, reference_images.high_res_ib) - - return lamella - def mill_lamella( microscope: FibsemMicroscope, @@ -362,6 +298,7 @@ def mill_lamella( ) -> Lamella: validate = settings.protocol["options"]["supervise"].get("lamella", True) settings.image.save_path = lamella.path + method = settings.protocol.get("method", "autolamella-waffle") # beam_shift alignment log_status_message(lamella, "ALIGN_LAMELLA") @@ -382,7 +319,6 @@ def mill_lamella( settings.image.reduced_area = None - # take reference images _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") settings.image.label = f"ref_{lamella.state.stage.name}_start" @@ -390,34 +326,46 @@ def mill_lamella( _set_images_ui(parent_ui, eb_image, ib_image) - # define feature - log_status_message(lamella, "MILL_LAMELLA") - stages = patterning._get_milling_stages( - "lamella", lamella.protocol, point=Point.__from_dict__(lamella.protocol["lamella"]["point"]) - ) - - # filter stage based on the current stage - stage_map = { - AutoLamellaWaffleStage.MillRoughCut.name: 0, - AutoLamellaWaffleStage.MillRegularCut.name: 1, - AutoLamellaWaffleStage.MillPolishingCut.name: 2, - } - supervise_map = { AutoLamellaWaffleStage.MillRoughCut.name: "mill_rough", - AutoLamellaWaffleStage.MillRegularCut.name: "mill_regular", AutoLamellaWaffleStage.MillPolishingCut.name: "mill_polishing", } validate = settings.protocol["options"]["supervise"].get(supervise_map[lamella.state.stage.name], True) + + # define feature + _MILL_FEATURES = bool("autolamella" in method) + if _MILL_FEATURES and lamella.state.stage.name == AutoLamellaWaffleStage.MillRoughCut.name: + log_status_message(lamella, "MILL_FEATURE") + + # check if using notch or microexpansion + _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" + + stages = patterning._get_milling_stages( + _feature_name, lamella.protocol, point=Point.__from_dict__(lamella.protocol[_feature_name]["point"]) + ) + + stages = _validate_mill_ui(stages, parent_ui, + msg=f"Press Run Milling to mill the {_feature_name} for {lamella._petname}. Press Continue when done.", + validate=validate, + ) + + # log feature stages + lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages)) + lamella.protocol[_feature_name]["point"] = stages[0].pattern.point.__to_dict__() - idx = stage_map[lamella.state.stage.name] - if idx in [0, 1]: - stages = [stages[idx]] + # mill lamella trenches + log_status_message(lamella, "MILL_LAMELLA") + stages = patterning._get_milling_stages("lamella", lamella.protocol, + point=Point.__from_dict__(lamella.protocol["lamella"]["point"])) + + if lamella.state.stage.name == AutoLamellaWaffleStage.MillPolishingCut.name: + stages = stages[-1] else: - stages = stages[idx:] - if not isinstance(stages, list): - stages = [stages] - + stages = stages[:-1] + + if not isinstance(stages, list): + stages = [stages] + stages = _validate_mill_ui(stages, parent_ui, msg=f"Press Run Milling to mill the Trenches for {lamella._petname}. Press Continue when done.", validate=validate, @@ -426,7 +374,7 @@ def mill_lamella( # TODO: refactor this so it is like the original protocol lamella.protocol[lamella.state.stage.name] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol[lamella.state.stage.name]["point"] = stages[0].pattern.point.__to_dict__() - + # take reference images log_status_message(lamella, "REFERENCE_IMAGES") _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") @@ -438,14 +386,14 @@ def mill_lamella( ) _set_images_ui(parent_ui, reference_images.high_res_eb, reference_images.high_res_ib) - if lamella.state.stage is AutoLamellaWaffleStage.MillPolishingCut: + if lamella.state.stage is AutoLamellaWaffleStage.MillPolishingCut and settings.protocol["options"].get("take_high_quality_reference_images", False): log_status_message(lamella, "HIGH_QUALITY_REFERENCE_IMAGES") _update_status_ui(parent_ui, f"{lamella.info} Acquiring High Quality Reference Images...") settings.image.hfw = fcfg.REFERENCE_HFW_SUPER settings.image.label = f"ref_{lamella.state.stage.name}_final_ultra" settings.image.save = True settings.image.resolution = fcfg.REFERENCE_RES_HIGH - settings.image.frame_integration = 16 + settings.image.frame_integration = 4 settings.image.beam_type = BeamType.ELECTRON eb_image = acquire.new_image(microscope, settings.image) _set_images_ui(parent_ui, eb_image, ib_image) From 2024bd55f3d1d86bfcd1157038e4ee574183b518 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 16:38:11 +1000 Subject: [PATCH 15/39] fix default protocol for consistency --- autolamella/protocol/protocol-base.yaml | 59 ++++--------------------- 1 file changed, 8 insertions(+), 51 deletions(-) diff --git a/autolamella/protocol/protocol-base.yaml b/autolamella/protocol/protocol-base.yaml index 397e3006..2f3e3f4e 100644 --- a/autolamella/protocol/protocol-base.yaml +++ b/autolamella/protocol/protocol-base.yaml @@ -1,6 +1,6 @@ name: autolamella-base-scan-rotation-0deg -method: autolamella-default # waffle or default +method: autolamella-default # autolamella-waffle or autolamella-default options: alignment_attempts: 3.0 @@ -14,6 +14,11 @@ options: mill_regular: true mill_polishing: true +ml: + encoder: resnet34 + num_classes: 3 + checkpoint: autolamella-05-34.pt + fiducial: enabled: true height: 10.e-6 @@ -28,29 +33,14 @@ fiducial: hfw: 80.e-6 -trench: - lamella_width: 22.e-6 - lamella_height: 30.0e-6 - milling_current: 28.0e-9 - trench_height: 32.e-6 - depth: 2.5e-6 - offset: 0.0e-6 - size_ratio: 2.0 - preset: "30 keV; 2.5 nA" # TESCAN only - hfw: 180.0e-6 - application_file: autolamella - cleaning_cross_section: false - lamella: - lamella_width: 20.e-6 - lamella_height: 800.e-9 stages: - application_file: autolamella cleaning_cross_section: false depth: 6.5e-07 dwell_time: 1.0e-06 hfw: 7.999999999999999e-05 - lamella_height: 8.0e-07 + lamella_height: 6.0e-07 lamella_width: 6.0e-06 milling_current: 7.4e-10 offset: 2.0e-06 @@ -65,7 +55,7 @@ lamella: depth: 6.5e-07 dwell_time: 1.0e-06 hfw: 7.999999999999999e-05 - lamella_height: 8.0e-07 + lamella_height: 6.0e-07 lamella_width: 6.0e-06 milling_current: 2.0e-10 offset: 5.0e-07 @@ -104,36 +94,3 @@ microexpansion: cleaning_cross_section: false lamella_width: 10.e-6 - - -notch: - enabled: false - vheight: 2.0e-6 - vwidth: 0.2e-6 - hwidth: 2.0e-6 - hheight: 0.2e-6 - depth: 5.0e-6 - distance: 5.0e-6 - flip: 0 - milling_current: 2.e-9 - preset: "30 keV; 2.5 nA" # TESCAN only - hfw: 80e-6 - application_file: autolamella - cleaning_cross_section: false - -undercut: - width: 10.e-6 - height: 4.e-6 - depth: 2.0e-6 - milling_current: 7.6e-9 - preset: "30 keV; 2.5 nA" # TESCAN only - hfw: 80.0e-6 - application_file: autolamella - tilt_angle: -10 - tilt_angle_step: 2 - cleaning_cross_section: false - -ml: - encoder: resnet34 - num_classes: 3 - checkpoint: autolamella-05-34.pt \ No newline at end of file From a693845ef4fb0be7e12ef8567e11f2ba673edc00 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 17:42:43 +1000 Subject: [PATCH 16/39] make final reference images optional --- .../liftout/protocol/protocol-base.yaml | 14 ++++--- .../protocol/protocol-serial-liftout.yaml | 3 ++ autolamella/protocol/protocol-base.yaml | 32 ++++++++++++++++ autolamella/protocol/protocol-waffle.yaml | 20 +++------- autolamella/protocol/protocol.yaml | 17 ++------- autolamella/workflows/core.py | 38 +++++++++++-------- 6 files changed, 74 insertions(+), 50 deletions(-) diff --git a/autolamella/liftout/protocol/protocol-base.yaml b/autolamella/liftout/protocol/protocol-base.yaml index 4c5a9cf8..168bec83 100644 --- a/autolamella/liftout/protocol/protocol-base.yaml +++ b/autolamella/liftout/protocol/protocol-base.yaml @@ -48,19 +48,23 @@ method: autoliftout-default options: batch_mode: true confirm_advance: true - landing_joining_method: Weld + lamella_start_position: autoliftout-pre-tilt-35-deg-grid-01-lamella liftout_joining_method: None liftout_contact_detection: True liftout_contact_offset: 0.25e-6 - landing_post_x_offset: 0.75e-6 - lamella_start_position: autoliftout-pre-tilt-35-deg-grid-01-lamella + liftout_charge_neutralisation_iterations: 35 landing_start_position: autoliftout-pre-tilt-35-deg-grid-02-landing + landing_joining_method: Weld + landing_post_x_offset: 0.75e-6 + landing_charge_neutralisation_iterations: 100 compucentric_x_offset: 50.0e-6 compucentric_y_offset: 25.0e-6 return_to_eb_after_undercut: True alignment_attempts: 3.0 - liftout_charge_neutralisation_iterations: 35 - landing_charge_neutralisation_iterations: 100 + alignment_at_milling_current: true + take_final_reference_images: true + take_final_high_quality_reference_images: true + take_final_overview_image: true supervise: landing: true liftout: true diff --git a/autolamella/liftout/protocol/protocol-serial-liftout.yaml b/autolamella/liftout/protocol/protocol-serial-liftout.yaml index 7d6227fc..1ff0c6ee 100644 --- a/autolamella/liftout/protocol/protocol-serial-liftout.yaml +++ b/autolamella/liftout/protocol/protocol-serial-liftout.yaml @@ -38,6 +38,9 @@ options: landing_start_position: autoliftout-serial-pre-tilt-35-deg-grid-02-landing compucentric_x_offset: 50.0e-6 compucentric_y_offset: 25.0e-6 + alignment_at_milling_current: true + take_final_reference_images: true + take_final_high_quality_reference_images: true landing_grid: x: 100.0e-6 y: 400.0e-6 diff --git a/autolamella/protocol/protocol-base.yaml b/autolamella/protocol/protocol-base.yaml index 2f3e3f4e..0e12c371 100644 --- a/autolamella/protocol/protocol-base.yaml +++ b/autolamella/protocol/protocol-base.yaml @@ -4,6 +4,10 @@ method: autolamella-default # autolamella-waffle or autolamella-default options: alignment_attempts: 3.0 + alignment_at_milling_current: true + take_final_reference_images: false + take_final_high_quality_reference_images: false + take_final_overview_image: true supervise: trench: false undercut: true @@ -94,3 +98,31 @@ microexpansion: cleaning_cross_section: false lamella_width: 10.e-6 +undercut: + application_file: autolamella + cleaning_cross_section: false + depth: 1.2e-06 + height: 16.0e-06 + hfw: 8.0e-05 + milling_current: 7.6e-09 + preset: 30 keV; 2.5 nA + tilt_angle: -5.0 + tilt_angle_step: 2.0 + width: 22.0e-6 + type: Rectangle + +notch: + application_file: autolamella + cleaning_cross_section: false + depth: 2.5e-06 + distance: 2.0e-06 + enabled: false + flip: 0 + hfw: 80e-6 + hheight: 2.0e-07 + hwidth: 4.0e-06 + milling_current: 2.0e-09 + preset: 30 keV; 2.5 nA + vheight: 2.0e-06 + vwidth: 2.0e-07 + type: WaffleNotch \ No newline at end of file diff --git a/autolamella/protocol/protocol-waffle.yaml b/autolamella/protocol/protocol-waffle.yaml index 9278805c..274d7e7d 100644 --- a/autolamella/protocol/protocol-waffle.yaml +++ b/autolamella/protocol/protocol-waffle.yaml @@ -24,9 +24,6 @@ fiducial: width: 1.0e-06 type: Fiducial lamella: - alignment_attempts: 3.0 - lamella_height: 8.0e-07 - lamella_width: 1.0e-05 stages: - application_file: autolamella cleaning_cross_section: true @@ -65,18 +62,6 @@ lamella: trench_height: 6.0e-07 type: Trench method: autolamella-waffle -microexpansion: - application_file: autolamella - cleaning_cross_section: false - depth: 1.0e-06 - distance: 1.0e-05 - height: 1.8e-05 - hfw: 200e-6 - lamella_width: 1.0e-05 - milling_current: 2.0e-09 - preset: 30 keV; 2.5 nA - width: 5.0e-07 - type: MicroExpansion ml: encoder: resnet34 num_classes: 3 @@ -98,6 +83,11 @@ notch: vwidth: 2.0e-07 type: WaffleNotch options: + alignment_attempts: 3.0 + alignment_at_milling_current: true + take_final_reference_images: true + take_final_high_quality_reference_images: false + take_final_overview_image: true compucentric_x_offset: 0.0e-6 compucentric_y_offset: 0.0e-6 supervise: diff --git a/autolamella/protocol/protocol.yaml b/autolamella/protocol/protocol.yaml index 2f94c752..a9e95300 100644 --- a/autolamella/protocol/protocol.yaml +++ b/autolamella/protocol/protocol.yaml @@ -24,8 +24,6 @@ fiducial: width: 1.0e-06 type: Fiducial lamella: - lamella_height: 8.0e-07 - lamella_width: 1.0e-05 stages: - application_file: autolamella cleaning_cross_section: true @@ -64,18 +62,6 @@ lamella: trench_height: 6.0e-07 type: Trench method: autolamella-waffle -microexpansion: - application_file: autolamella - cleaning_cross_section: false - depth: 1.0e-06 - distance: 1.0e-05 - height: 1.8e-05 - hfw: 200e-6 - lamella_width: 1.0e-05 - milling_current: 2.0e-09 - preset: 30 keV; 2.5 nA - width: 5.0e-07 - type: MicroExpansion ml: encoder: resnet34 num_classes: 3 @@ -97,6 +83,9 @@ notch: vwidth: 2.0e-07 type: WaffleNotch options: + alignment_at_milling_current: true + take_final_reference_images: true + take_final_high_quality_reference_images: true alignment_attempts: 3.0 return_to_eb_after_undercut: False compucentric_x_offset: 50.0e-6 diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 6e75a8d4..e2954f50 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -286,10 +286,6 @@ def mill_undercut( return lamella - - - - def mill_lamella( microscope: FibsemMicroscope, settings: MicroscopeSettings, @@ -300,6 +296,15 @@ def mill_lamella( settings.image.save_path = lamella.path method = settings.protocol.get("method", "autolamella-waffle") + + _take_reference_images = bool( + lamella.state.stage is AutoLamellaWaffleStage.MillRoughCut + or settings.protocol["options"].get("take_final_reference_images", True)) + _take_high_quality_ref = bool( + lamella.state.stage is AutoLamellaWaffleStage.MillPolishingCut + and settings.protocol["options"].get("take_final_high_quality_reference_images", False) + ) + # beam_shift alignment log_status_message(lamella, "ALIGN_LAMELLA") _update_status_ui(parent_ui, f"{lamella.info} Aligning Reference Images...") @@ -375,18 +380,19 @@ def mill_lamella( lamella.protocol[lamella.state.stage.name] = deepcopy(patterning._get_protocol_from_stages(stages)) lamella.protocol[lamella.state.stage.name]["point"] = stages[0].pattern.point.__to_dict__() - # take reference images - log_status_message(lamella, "REFERENCE_IMAGES") - _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") - reference_images = acquire.take_set_of_reference_images( - microscope=microscope, - image_settings=settings.image, - hfws=[fcfg.REFERENCE_HFW_HIGH, fcfg.REFERENCE_HFW_SUPER], - label=f"ref_{lamella.state.stage.name}_final", - ) - _set_images_ui(parent_ui, reference_images.high_res_eb, reference_images.high_res_ib) + if _take_reference_images: + # take reference images + log_status_message(lamella, "REFERENCE_IMAGES") + _update_status_ui(parent_ui, f"{lamella.info} Acquiring Reference Images...") + reference_images = acquire.take_set_of_reference_images( + microscope=microscope, + image_settings=settings.image, + hfws=[fcfg.REFERENCE_HFW_HIGH, fcfg.REFERENCE_HFW_SUPER], + label=f"ref_{lamella.state.stage.name}_final", + ) + _set_images_ui(parent_ui, reference_images.high_res_eb, reference_images.high_res_ib) - if lamella.state.stage is AutoLamellaWaffleStage.MillPolishingCut and settings.protocol["options"].get("take_high_quality_reference_images", False): + if _take_high_quality_ref: log_status_message(lamella, "HIGH_QUALITY_REFERENCE_IMAGES") _update_status_ui(parent_ui, f"{lamella.info} Acquiring High Quality Reference Images...") settings.image.hfw = fcfg.REFERENCE_HFW_SUPER @@ -396,7 +402,7 @@ def mill_lamella( settings.image.frame_integration = 4 settings.image.beam_type = BeamType.ELECTRON eb_image = acquire.new_image(microscope, settings.image) - _set_images_ui(parent_ui, eb_image, ib_image) + # _set_images_ui(parent_ui, eb_image, ib_image) settings.image.frame_integration = 1 # restore settings.image.resolution = fcfg.REFERENCE_RES_MEDIUM From ab0290d6c2ab3976fdd0ab5aec7d8b890087a27c Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 18:33:09 +1000 Subject: [PATCH 17/39] update protcol ui autolamella --- autolamella/protocol/protocol-base.yaml | 31 +---- autolamella/ui/AutoLamellaUI.py | 118 ++++++++++++------ autolamella/ui/qt/AutoLamellaUI.py | 127 ++++++++++--------- autolamella/ui/qt/AutoLamellaUI.ui | 156 +++++++++++++----------- 4 files changed, 228 insertions(+), 204 deletions(-) diff --git a/autolamella/protocol/protocol-base.yaml b/autolamella/protocol/protocol-base.yaml index 0e12c371..253e2f90 100644 --- a/autolamella/protocol/protocol-base.yaml +++ b/autolamella/protocol/protocol-base.yaml @@ -96,33 +96,4 @@ microexpansion: hfw: 200e-6 application_file: autolamella cleaning_cross_section: false - lamella_width: 10.e-6 - -undercut: - application_file: autolamella - cleaning_cross_section: false - depth: 1.2e-06 - height: 16.0e-06 - hfw: 8.0e-05 - milling_current: 7.6e-09 - preset: 30 keV; 2.5 nA - tilt_angle: -5.0 - tilt_angle_step: 2.0 - width: 22.0e-6 - type: Rectangle - -notch: - application_file: autolamella - cleaning_cross_section: false - depth: 2.5e-06 - distance: 2.0e-06 - enabled: false - flip: 0 - hfw: 80e-6 - hheight: 2.0e-07 - hwidth: 4.0e-06 - milling_current: 2.0e-09 - preset: 30 keV; 2.5 nA - vheight: 2.0e-06 - vwidth: 2.0e-07 - type: WaffleNotch \ No newline at end of file + lamella_width: 10.e-6 \ No newline at end of file diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index 96971609..bdea9954 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -64,6 +64,7 @@ def __init__(self, viewer: napari.Viewer) -> None: self._PROTOCOL_LOADED = False self._microscope_ui_loaded = False + self._UPDATING_PROTOCOL_UI = False self.experiment: Experiment = None self.worker = None @@ -91,8 +92,7 @@ def __init__(self, viewer: napari.Viewer) -> None: self._MILLING_RUNNING: bool = False self._WORKFLOW_RUNNING: bool = False self._ABORT_THREAD: bool = False - self.checkBox_show_lamella_in_view.setChecked(True) - self.checkBox_show_lamella_in_view.stateChanged.connect(self.update_lamella_ui) + # setup connections self.setup_connections() @@ -131,6 +131,9 @@ def setup_connections(self): self.pushButton_run_setup_autolamella.setVisible(False) self.pushButton_update_protocol.clicked.connect(self.export_protocol_ui) + + self.checkBox_show_lamella_in_view.setChecked(True) + self.checkBox_show_lamella_in_view.stateChanged.connect(self.update_lamella_ui) # system widget self.system_widget.set_stage_signal.connect(self.set_stage_parameters) @@ -163,68 +166,103 @@ def setup_connections(self): # comboboxes self.comboBox_method.addItems(cfg.__AUTOLAMELLA_METHODS__) - self.comboBox_stress_relief.addItems(["Notch","Microexpansion"]) # TODO: dont make this an option, just base it off the method - self.comboBox_alignment_with.addItems(["Fiducial", "No Fiducial"]) + self.comboBox_method.currentIndexChanged.connect(lambda: self.update_protocol_ui(False)) - def update_protocol_ui(self): + def update_protocol_ui(self, _load: bool=True): if self._PROTOCOL_LOADED is False: return - - self.lineEdit_name.setText(self.settings.protocol["name"]) - - self.beamshift_attempts.setValue(self.settings.protocol["options"].get("alignment_attempts", 3)) - self.doubleSpinBox_undercut_tilt.setValue(self.settings.protocol["undercut"]["tilt_angle"]) - self.doubleSpinBox_undercut_step.setValue(self.settings.protocol["undercut"]["tilt_angle_step"]) + if self._UPDATING_PROTOCOL_UI: + return - self.comboBox_stress_relief.setCurrentIndex(0) if self.settings.protocol["notch"]["enabled"] else self.comboBox_stress_relief.setCurrentIndex(1) + self._UPDATING_PROTOCOL_UI = True - method = self.settings.protocol["method"] - self.comboBox_method.setCurrentIndex(cfg.__AUTOLAMELLA_METHODS__.index(method.title())) # TODO: coerce this to be a supported method, alert the user if not + if _load: + method = self.settings.protocol["method"] + self.comboBox_method.setCurrentIndex(cfg.__AUTOLAMELLA_METHODS__.index(method.title())) # TODO: coerce this to be a supported method, alert the user if not + else: + method = self.comboBox_method.currentText().lower() - self.comboBox_alignment_with.setCurrentIndex(0) if self.settings.protocol["fiducial"]["enabled"] else self.comboBox_alignment_with.setCurrentIndex(1) + self.lineEdit_name.setText(self.settings.protocol.get("name", "autolamella-protocol")) + + # options + self.beamshift_attempts.setValue(self.settings.protocol["options"].get("alignment_attempts", 3)) + self.checkBox_align_at_milling_current.setChecked(self.settings.protocol["options"].get("alignment_at_milling_current", True)) + + self.checkBox_take_final_reference_images.setChecked(self.settings.protocol["options"].get("take_final_reference_images", True)) + self.checkBox_take_final_high_quality_reference.setChecked(self.settings.protocol["options"].get("take_final_high_quality_reference_images", False)) # supervision + self.checkBox_setup.setChecked(self.settings.protocol["options"]["supervise"].get("setup_lamella", True)) + self.checkBox_supervise_mill_rough.setChecked(self.settings.protocol["options"]["supervise"].get("mill_rough", True)) + self.checkBox_supervise_mill_polishing.setChecked(self.settings.protocol["options"]["supervise"].get("mill_polishing", True)) + + # WAFFLE ONLY + _WAFFLE_METHOD = method == "autolamella-waffle" + if _WAFFLE_METHOD: + # supervision + self.checkBox_trench.setChecked(self.settings.protocol["options"]["supervise"].get("trench", True)) + self.checkBox_undercut.setChecked(self.settings.protocol["options"]["supervise"].get("undercut", True)) + + # machine learning + self.lineEdit_ml_checkpoint.setText(self.settings.protocol.get("ml", {}).get("checkpoint", "autolamella-05-34.pt")) + self.lineEdit_ml_encoder.setText(self.settings.protocol.get("ml", {}).get("encoder", "resnet34")) + self.spinBox_ml_num_classes.setValue(self.settings.protocol.get("ml", {}).get("num_classes", 3)) + + # undercut + self.doubleSpinBox_undercut_tilt.setValue(self.settings.protocol.get("undercut", {}).get("tilt_angle", -5)) + self.doubleSpinBox_undercut_step.setValue(self.settings.protocol.get("undercut", {}).get("tilt_angle_step", 2)) + + self.checkBox_trench.setVisible(_WAFFLE_METHOD) + self.checkBox_undercut.setVisible(_WAFFLE_METHOD) - self.checkBox_trench.setChecked(self.settings.protocol["options"]["supervise"]["trench"]) - self.checkBox_undercut.setChecked(self.settings.protocol["options"]["supervise"]["undercut"]) - self.checkBox_setup.setChecked(self.settings.protocol["options"]["supervise"]["setup_lamella"]) - self.checkBox_features.setChecked(self.settings.protocol["options"]["supervise"]["features"]) - self.checkBox_supervise_mill_rough.setChecked(self.settings.protocol["options"]["supervise"]["mill_rough"]) - self.checkBox_supervise_mill_regular.setChecked(self.settings.protocol["options"]["supervise"]["mill_regular"]) - self.checkBox_supervise_mill_polishing.setChecked(self.settings.protocol["options"]["supervise"]["mill_polishing"]) + self.label_ml_header.setVisible(_WAFFLE_METHOD) + self.label_ml_checkpoint.setVisible(_WAFFLE_METHOD) + self.label_ml_num_classes.setVisible(_WAFFLE_METHOD) + self.label_ml_encoder.setVisible(_WAFFLE_METHOD) + self.lineEdit_ml_checkpoint.setVisible(_WAFFLE_METHOD) + self.lineEdit_ml_encoder.setVisible(_WAFFLE_METHOD) + self.spinBox_ml_num_classes.setVisible(_WAFFLE_METHOD) - # machine learning - self.lineEdit_ml_checkpoint.setText(self.settings.protocol["ml"]["checkpoint"]) - self.lineEdit_ml_encoder.setText(self.settings.protocol["ml"]["encoder"]) + self.doubleSpinBox_undercut_tilt.setVisible(_WAFFLE_METHOD) + self.doubleSpinBox_undercut_step.setVisible(_WAFFLE_METHOD) + self.label_protocol_undercut_tilt_angle.setVisible(_WAFFLE_METHOD) + self.label_protocol_undercut_tilt_step.setVisible(_WAFFLE_METHOD) + self._UPDATING_PROTOCOL_UI = False def export_protocol_ui(self): if self._PROTOCOL_LOADED is False: return self.settings.protocol["name"] = self.lineEdit_name.text() - self.settings.protocol["options"]["alignment_attempts"] = int(self.beamshift_attempts.value()) - self.settings.protocol["undercut"]["tilt_angle"] = self.doubleSpinBox_undercut_tilt.value() - self.settings.protocol["undercut"]["tilt_angle_step"] = int(self.doubleSpinBox_undercut_step.value()) - self.settings.protocol["notch"]["enabled"] = bool(self.comboBox_stress_relief.currentIndex() == 0) - self.settings.protocol["fiducial"]["enabled"] = bool(self.comboBox_alignment_with.currentIndex() == 0) self.settings.protocol["method"] = self.comboBox_method.currentText().lower() + + # options + self.settings.protocol["options"]["alignment_attempts"] = int(self.beamshift_attempts.value()) + self.settings.protocol["options"]["alignment_at_milling_current"] = self.checkBox_align_at_milling_current.isChecked() + self.settings.protocol["options"]["take_final_reference_images"] = self.checkBox_take_final_reference_images.isChecked() + self.settings.protocol["options"]["take_final_high_quality_reference_images"] = self.checkBox_take_final_high_quality_reference.isChecked() # supervision - - self.settings.protocol["options"]["supervise"]["trench"] = self.checkBox_trench.isChecked() - self.settings.protocol["options"]["supervise"]["undercut"] = self.checkBox_undercut.isChecked() self.settings.protocol["options"]["supervise"]["setup_lamella"] = self.checkBox_setup.isChecked() - self.settings.protocol["options"]["supervise"]["features"] = self.checkBox_features.isChecked() self.settings.protocol["options"]["supervise"]["mill_rough"] = self.checkBox_supervise_mill_rough.isChecked() - self.settings.protocol["options"]["supervise"]["mill_regular"] = self.checkBox_supervise_mill_regular.isChecked() self.settings.protocol["options"]["supervise"]["mill_polishing"] = self.checkBox_supervise_mill_polishing.isChecked() # machine learning - self.settings.protocol["ml"]["checkpoint"] = self.lineEdit_ml_checkpoint.text() - self.settings.protocol["ml"]["encoder"] = self.lineEdit_ml_encoder.text() + if self.settings.protocol["method"] == "autolamella-waffle": + + self.settings.protocol["options"]["supervise"]["trench"] = self.checkBox_trench.isChecked() + self.settings.protocol["options"]["supervise"]["undercut"] = self.checkBox_undercut.isChecked() + + self.settings.protocol["ml"]["checkpoint"] = self.lineEdit_ml_checkpoint.text() + self.settings.protocol["ml"]["encoder"] = self.lineEdit_ml_encoder.text() + self.settings.protocol["ml"]["num_classes"] = self.spinBox_ml_num_classes.value() + + # undercut + self.settings.protocol["undercut"]["tilt_angle"] = self.doubleSpinBox_undercut_tilt.value() + self.settings.protocol["undercut"]["tilt_angle_step"] = int(self.doubleSpinBox_undercut_step.value()) if self.sender() == self.actionSave_Protocol: path = fui._get_save_file_ui(msg='Save protocol', @@ -281,7 +319,7 @@ def setup_experiment(self): if os.path.exists(PROTOCOL_PATH): self.settings.protocol = utils.load_protocol(protocol_path=PROTOCOL_PATH) self._PROTOCOL_LOADED = True - self.update_protocol_ui() + self.update_protocol_ui(_load=True) self._update_lamella_combobox() self.update_ui() @@ -829,7 +867,7 @@ def load_protocol(self): self.settings.protocol = utils.load_protocol(protocol_path=PATH) self._PROTOCOL_LOADED = True - self.update_protocol_ui() + self.update_protocol_ui(_load=True) napari.utils.notifications.show_info( f"Loaded Protocol from {os.path.basename(PATH)}" ) @@ -894,7 +932,7 @@ def _auto_load(self): # load protocol self.settings.protocol = utils.load_protocol(protocol_path=DEV_PROTOCOL_PATH) self._PROTOCOL_LOADED = True - self.update_protocol_ui() + self.update_protocol_ui(_load=True) self.update_ui() return diff --git a/autolamella/ui/qt/AutoLamellaUI.py b/autolamella/ui/qt/AutoLamellaUI.py index 2d3cb171..db148dc1 100644 --- a/autolamella/ui/qt/AutoLamellaUI.py +++ b/autolamella/ui/qt/AutoLamellaUI.py @@ -29,6 +29,15 @@ def setupUi(self, MainWindow): self.gridLayout.addWidget(self.label_instructions, 3, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem, 2, 0, 1, 2) + self.pushButton_yes = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_yes.setObjectName("pushButton_yes") + self.gridLayout.addWidget(self.pushButton_yes, 4, 0, 1, 1) + self.pushButton_stop_workflow_thread = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_stop_workflow_thread.setObjectName("pushButton_stop_workflow_thread") + self.gridLayout.addWidget(self.pushButton_stop_workflow_thread, 1, 0, 1, 2) + self.pushButton_no = QtWidgets.QPushButton(self.centralwidget) + self.pushButton_no.setObjectName("pushButton_no") + self.gridLayout.addWidget(self.pushButton_no, 4, 1, 1, 1) self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget.setObjectName("tabWidget") self.tab = QtWidgets.QWidget() @@ -289,28 +298,29 @@ def setupUi(self, MainWindow): self.comboBox_method = QtWidgets.QComboBox(self.tab_2) self.comboBox_method.setObjectName("comboBox_method") self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.comboBox_method) + self.label_options_header = QtWidgets.QLabel(self.tab_2) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_options_header.setFont(font) + self.label_options_header.setObjectName("label_options_header") + self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.SpanningRole, self.label_options_header) self.label_protocol_undercut_tilt_angle = QtWidgets.QLabel(self.tab_2) self.label_protocol_undercut_tilt_angle.setObjectName("label_protocol_undercut_tilt_angle") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_angle) + self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_angle) self.doubleSpinBox_undercut_tilt = QtWidgets.QDoubleSpinBox(self.tab_2) self.doubleSpinBox_undercut_tilt.setMinimum(-180.0) self.doubleSpinBox_undercut_tilt.setMaximum(180.0) self.doubleSpinBox_undercut_tilt.setObjectName("doubleSpinBox_undercut_tilt") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_tilt) - self.label_undercut_tilt_step = QtWidgets.QLabel(self.tab_2) - self.label_undercut_tilt_step.setObjectName("label_undercut_tilt_step") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_undercut_tilt_step) + self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_tilt) + self.label_protocol_undercut_tilt_step = QtWidgets.QLabel(self.tab_2) + self.label_protocol_undercut_tilt_step.setObjectName("label_protocol_undercut_tilt_step") + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_step) self.doubleSpinBox_undercut_step = QtWidgets.QDoubleSpinBox(self.tab_2) self.doubleSpinBox_undercut_step.setMinimum(-180.0) self.doubleSpinBox_undercut_step.setMaximum(180.0) self.doubleSpinBox_undercut_step.setObjectName("doubleSpinBox_undercut_step") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_step) - self.label_stress_relief = QtWidgets.QLabel(self.tab_2) - self.label_stress_relief.setObjectName("label_stress_relief") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_stress_relief) - self.comboBox_stress_relief = QtWidgets.QComboBox(self.tab_2) - self.comboBox_stress_relief.setObjectName("comboBox_stress_relief") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.comboBox_stress_relief) + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_step) self.label_alignment_header = QtWidgets.QLabel(self.tab_2) font = QtGui.QFont() font.setBold(True) @@ -318,83 +328,77 @@ def setupUi(self, MainWindow): font.setWeight(75) self.label_alignment_header.setFont(font) self.label_alignment_header.setObjectName("label_alignment_header") - self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.SpanningRole, self.label_alignment_header) - self.label_protocol_align_with = QtWidgets.QLabel(self.tab_2) - self.label_protocol_align_with.setObjectName("label_protocol_align_with") - self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_protocol_align_with) - self.comboBox_alignment_with = QtWidgets.QComboBox(self.tab_2) - self.comboBox_alignment_with.setObjectName("comboBox_alignment_with") - self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.comboBox_alignment_with) + self.formLayout_2.setWidget(11, QtWidgets.QFormLayout.SpanningRole, self.label_alignment_header) self.beamShiftAttemptsLabel = QtWidgets.QLabel(self.tab_2) self.beamShiftAttemptsLabel.setObjectName("beamShiftAttemptsLabel") - self.formLayout_2.setWidget(11, QtWidgets.QFormLayout.LabelRole, self.beamShiftAttemptsLabel) + self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.LabelRole, self.beamShiftAttemptsLabel) self.beamshift_attempts = QtWidgets.QDoubleSpinBox(self.tab_2) self.beamshift_attempts.setObjectName("beamshift_attempts") - self.formLayout_2.setWidget(11, QtWidgets.QFormLayout.FieldRole, self.beamshift_attempts) + self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.FieldRole, self.beamshift_attempts) self.label_ml_header = QtWidgets.QLabel(self.tab_2) font = QtGui.QFont() font.setBold(True) font.setWeight(75) self.label_ml_header.setFont(font) self.label_ml_header.setObjectName("label_ml_header") - self.formLayout_2.setWidget(13, QtWidgets.QFormLayout.SpanningRole, self.label_ml_header) + self.formLayout_2.setWidget(17, QtWidgets.QFormLayout.SpanningRole, self.label_ml_header) self.label_ml_checkpoint = QtWidgets.QLabel(self.tab_2) self.label_ml_checkpoint.setObjectName("label_ml_checkpoint") - self.formLayout_2.setWidget(14, QtWidgets.QFormLayout.LabelRole, self.label_ml_checkpoint) + self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.LabelRole, self.label_ml_checkpoint) self.lineEdit_ml_checkpoint = QtWidgets.QLineEdit(self.tab_2) self.lineEdit_ml_checkpoint.setObjectName("lineEdit_ml_checkpoint") - self.formLayout_2.setWidget(14, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_checkpoint) + self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_checkpoint) self.label_ml_encoder = QtWidgets.QLabel(self.tab_2) self.label_ml_encoder.setObjectName("label_ml_encoder") - self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.LabelRole, self.label_ml_encoder) + self.formLayout_2.setWidget(19, QtWidgets.QFormLayout.LabelRole, self.label_ml_encoder) self.lineEdit_ml_encoder = QtWidgets.QLineEdit(self.tab_2) self.lineEdit_ml_encoder.setObjectName("lineEdit_ml_encoder") - self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_encoder) + self.formLayout_2.setWidget(19, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_encoder) self.label_supervise_header = QtWidgets.QLabel(self.tab_2) font = QtGui.QFont() font.setBold(True) font.setWeight(75) self.label_supervise_header.setFont(font) self.label_supervise_header.setObjectName("label_supervise_header") - self.formLayout_2.setWidget(16, QtWidgets.QFormLayout.SpanningRole, self.label_supervise_header) + self.formLayout_2.setWidget(21, QtWidgets.QFormLayout.SpanningRole, self.label_supervise_header) self.checkBox_trench = QtWidgets.QCheckBox(self.tab_2) self.checkBox_trench.setObjectName("checkBox_trench") - self.formLayout_2.setWidget(17, QtWidgets.QFormLayout.LabelRole, self.checkBox_trench) + self.formLayout_2.setWidget(22, QtWidgets.QFormLayout.LabelRole, self.checkBox_trench) self.checkBox_setup = QtWidgets.QCheckBox(self.tab_2) self.checkBox_setup.setObjectName("checkBox_setup") - self.formLayout_2.setWidget(17, QtWidgets.QFormLayout.FieldRole, self.checkBox_setup) + self.formLayout_2.setWidget(22, QtWidgets.QFormLayout.FieldRole, self.checkBox_setup) self.checkBox_undercut = QtWidgets.QCheckBox(self.tab_2) self.checkBox_undercut.setObjectName("checkBox_undercut") - self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.LabelRole, self.checkBox_undercut) - self.checkBox_features = QtWidgets.QCheckBox(self.tab_2) - self.checkBox_features.setObjectName("checkBox_features") - self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.FieldRole, self.checkBox_features) - self.checkBox_supervise_mill_rough = QtWidgets.QCheckBox(self.tab_2) - self.checkBox_supervise_mill_rough.setObjectName("checkBox_supervise_mill_rough") - self.formLayout_2.setWidget(19, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_rough) - self.checkBox_supervise_mill_regular = QtWidgets.QCheckBox(self.tab_2) - self.checkBox_supervise_mill_regular.setObjectName("checkBox_supervise_mill_regular") - self.formLayout_2.setWidget(20, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_regular) + self.formLayout_2.setWidget(23, QtWidgets.QFormLayout.LabelRole, self.checkBox_undercut) self.checkBox_supervise_mill_polishing = QtWidgets.QCheckBox(self.tab_2) self.checkBox_supervise_mill_polishing.setObjectName("checkBox_supervise_mill_polishing") - self.formLayout_2.setWidget(21, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_polishing) + self.formLayout_2.setWidget(24, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_polishing) self.pushButton_update_protocol = QtWidgets.QPushButton(self.tab_2) self.pushButton_update_protocol.setObjectName("pushButton_update_protocol") - self.formLayout_2.setWidget(24, QtWidgets.QFormLayout.SpanningRole, self.pushButton_update_protocol) + self.formLayout_2.setWidget(28, QtWidgets.QFormLayout.SpanningRole, self.pushButton_update_protocol) + self.checkBox_supervise_mill_rough = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_supervise_mill_rough.setObjectName("checkBox_supervise_mill_rough") + self.formLayout_2.setWidget(23, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_rough) + self.checkBox_take_final_reference_images = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_take_final_reference_images.setObjectName("checkBox_take_final_reference_images") + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.checkBox_take_final_reference_images) + self.checkBox_take_final_high_quality_reference = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_take_final_high_quality_reference.setObjectName("checkBox_take_final_high_quality_reference") + self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.checkBox_take_final_high_quality_reference) + self.checkBox_align_at_milling_current = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_align_at_milling_current.setObjectName("checkBox_align_at_milling_current") + self.formLayout_2.setWidget(14, QtWidgets.QFormLayout.FieldRole, self.checkBox_align_at_milling_current) + self.label_ml_num_classes = QtWidgets.QLabel(self.tab_2) + self.label_ml_num_classes.setObjectName("label_ml_num_classes") + self.formLayout_2.setWidget(20, QtWidgets.QFormLayout.LabelRole, self.label_ml_num_classes) + self.spinBox_ml_num_classes = QtWidgets.QSpinBox(self.tab_2) + self.spinBox_ml_num_classes.setObjectName("spinBox_ml_num_classes") + self.formLayout_2.setWidget(20, QtWidgets.QFormLayout.FieldRole, self.spinBox_ml_num_classes) self.tabWidget.addTab(self.tab_2, "") self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 2) - self.pushButton_yes = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_yes.setObjectName("pushButton_yes") - self.gridLayout.addWidget(self.pushButton_yes, 4, 0, 1, 1) - self.pushButton_no = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_no.setObjectName("pushButton_no") - self.gridLayout.addWidget(self.pushButton_no, 4, 1, 1, 1) - self.pushButton_stop_workflow_thread = QtWidgets.QPushButton(self.centralwidget) - self.pushButton_stop_workflow_thread.setObjectName("pushButton_stop_workflow_thread") - self.gridLayout.addWidget(self.pushButton_stop_workflow_thread, 1, 0, 1, 2) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 521, 21)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 521, 20)) self.menubar.setObjectName("menubar") self.menuAutoLamella = QtWidgets.QMenu(self.menubar) self.menuAutoLamella.setObjectName("menuAutoLamella") @@ -434,13 +438,16 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuTools.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(1) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.label_instructions.setText(_translate("MainWindow", "Instructions")) + self.pushButton_yes.setText(_translate("MainWindow", "Yes")) + self.pushButton_stop_workflow_thread.setText(_translate("MainWindow", "Stop Workflow")) + self.pushButton_no.setText(_translate("MainWindow", "No")) self.pushButton_remove_lamella.setText(_translate("MainWindow", "Remove Lamella")) self.label_setup_header.setText(_translate("MainWindow", "Setup")) self.pushButton_run_waffle_trench.setText(_translate("MainWindow", "Run Waffle Trench Milling")) @@ -461,11 +468,10 @@ def retranslateUi(self, MainWindow): self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Experiment")) self.label_protocol_name_2.setText(_translate("MainWindow", "Name")) self.label_protocol_method.setText(_translate("MainWindow", "Method")) + self.label_options_header.setText(_translate("MainWindow", "Options")) self.label_protocol_undercut_tilt_angle.setText(_translate("MainWindow", "Undercut Tilt Angle")) - self.label_undercut_tilt_step.setText(_translate("MainWindow", "Undercut Tilt Steps")) - self.label_stress_relief.setText(_translate("MainWindow", "Stress Relief")) + self.label_protocol_undercut_tilt_step.setText(_translate("MainWindow", "Undercut Tilt Steps")) self.label_alignment_header.setText(_translate("MainWindow", "Alignment")) - self.label_protocol_align_with.setText(_translate("MainWindow", "Align with: ")) self.beamShiftAttemptsLabel.setText(_translate("MainWindow", "Align attempts")) self.label_ml_header.setText(_translate("MainWindow", "Machine Learning")) self.label_ml_checkpoint.setText(_translate("MainWindow", "Checkpoint")) @@ -474,15 +480,14 @@ def retranslateUi(self, MainWindow): self.checkBox_trench.setText(_translate("MainWindow", "Trench Stage")) self.checkBox_setup.setText(_translate("MainWindow", "Setup Stage")) self.checkBox_undercut.setText(_translate("MainWindow", "Undercut Stage")) - self.checkBox_features.setText(_translate("MainWindow", "Features Stage")) - self.checkBox_supervise_mill_rough.setText(_translate("MainWindow", "Mill Rough Stage")) - self.checkBox_supervise_mill_regular.setText(_translate("MainWindow", "Mill Regular Stage")) self.checkBox_supervise_mill_polishing.setText(_translate("MainWindow", "Mill Polishing Stage")) self.pushButton_update_protocol.setText(_translate("MainWindow", "Update Protocol")) + self.checkBox_supervise_mill_rough.setText(_translate("MainWindow", "Mill Rough Stage")) + self.checkBox_take_final_reference_images.setText(_translate("MainWindow", "Take Final Reference Images")) + self.checkBox_take_final_high_quality_reference.setText(_translate("MainWindow", "Take Final High Quality Reference Image")) + self.checkBox_align_at_milling_current.setText(_translate("MainWindow", "Align at Milling Current")) + self.label_ml_num_classes.setText(_translate("MainWindow", "Num Classes")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Protocol")) - self.pushButton_yes.setText(_translate("MainWindow", "Yes")) - self.pushButton_no.setText(_translate("MainWindow", "No")) - self.pushButton_stop_workflow_thread.setText(_translate("MainWindow", "Stop Workflow")) self.menuAutoLamella.setTitle(_translate("MainWindow", "File")) self.menuTools.setTitle(_translate("MainWindow", "Tools")) self.actionNew_Experiment.setText(_translate("MainWindow", "Create Experiment")) diff --git a/autolamella/ui/qt/AutoLamellaUI.ui b/autolamella/ui/qt/AutoLamellaUI.ui index 1abd8b12..e24b9f50 100644 --- a/autolamella/ui/qt/AutoLamellaUI.ui +++ b/autolamella/ui/qt/AutoLamellaUI.ui @@ -53,10 +53,31 @@ + + + + Yes + + + + + + + Stop Workflow + + + + + + + No + + + - 0 + 1 @@ -740,14 +761,27 @@ - + + + + + 75 + true + + + + Options + + + + Undercut Tilt Angle - + -180.000000000000000 @@ -757,14 +791,14 @@ - - + + Undercut Tilt Steps - + -180.000000000000000 @@ -774,17 +808,7 @@ - - - - Stress Relief - - - - - - - + @@ -798,27 +822,17 @@ - - - - Align with: - - - - - - - + Align attempts - + - + @@ -831,27 +845,27 @@ - + Checkpoint - + - + Encoder - + - + @@ -864,87 +878,83 @@ - + Trench Stage - + Setup Stage - + Undercut Stage - - + + - Features Stage + Mill Polishing Stage - + + + + Update Protocol + + + + Mill Rough Stage - - + + - Mill Regular Stage + Take Final Reference Images - - + + - Mill Polishing Stage + Take Final High Quality Reference Image - - + + - Update Protocol + Align at Milling Current + + + + Num Classes + + + + + + - - - - Yes - - - - - - - No - - - - - - - Stop Workflow - - - @@ -953,7 +963,7 @@ 0 0 521 - 21 + 20 From 1ff217b13a80641d19421affb81e2e7dbeb211a8 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 28 Sep 2023 18:49:08 +1000 Subject: [PATCH 18/39] ui improvements --- autolamella/config.py | 2 +- autolamella/ui/AutoLamellaUI.py | 10 +- autolamella/ui/qt/AutoLamellaUI.py | 122 ++++++++++---------- autolamella/ui/qt/AutoLamellaUI.ui | 171 +++++++++++++---------------- 4 files changed, 146 insertions(+), 159 deletions(-) diff --git a/autolamella/config.py b/autolamella/config.py index 620a53bd..eeab1cce 100644 --- a/autolamella/config.py +++ b/autolamella/config.py @@ -72,6 +72,6 @@ ####### FEATURE FLAGS -_MINIMAP_VISUALISATION = True +_MINIMAP_VISUALISATION = False _AUTO_SYNC_MINIMAP = True _REGISTER_METADATA = True \ No newline at end of file diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index bdea9954..50e18180 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -170,10 +170,7 @@ def setup_connections(self): def update_protocol_ui(self, _load: bool=True): - if self._PROTOCOL_LOADED is False: - return - - if self._UPDATING_PROTOCOL_UI: + if not self._PROTOCOL_LOADED or self._UPDATING_PROTOCOL_UI: return self._UPDATING_PROTOCOL_UI = True @@ -528,6 +525,11 @@ def update_ui(self): _protocol_loaded = bool(self.settings is not None) and self._PROTOCOL_LOADED _lamella_selected = bool(self.experiment.positions) if _experiment_loaded else False + # force order: connect -> experiment -> protocol + self.tabWidget.setTabVisible(0, _microscope_connected) + self.tabWidget.setTabVisible(1, _protocol_loaded) + self.actionNew_Experiment.setVisible(_microscope_connected) + # setup experiment -> connect to microscope -> select lamella -> run autolamella self.pushButton_fail_lamella.setVisible(_lamella_selected) self.pushButton_revert_stage.setVisible(_lamella_selected) diff --git a/autolamella/ui/qt/AutoLamellaUI.py b/autolamella/ui/qt/AutoLamellaUI.py index db148dc1..033c7ba7 100644 --- a/autolamella/ui/qt/AutoLamellaUI.py +++ b/autolamella/ui/qt/AutoLamellaUI.py @@ -44,23 +44,11 @@ def setupUi(self, MainWindow): self.tab.setObjectName("tab") self.gridLayout_3 = QtWidgets.QGridLayout(self.tab) self.gridLayout_3.setObjectName("gridLayout_3") - self.pushButton_remove_lamella = QtWidgets.QPushButton(self.tab) - self.pushButton_remove_lamella.setStyleSheet("") - self.pushButton_remove_lamella.setObjectName("pushButton_remove_lamella") - self.gridLayout_3.addWidget(self.pushButton_remove_lamella, 7, 1, 1, 1) - self.label_setup_header = QtWidgets.QLabel(self.tab) - font = QtGui.QFont() - font.setPointSize(9) - font.setBold(True) - font.setWeight(75) - self.label_setup_header.setFont(font) - self.label_setup_header.setObjectName("label_setup_header") - self.gridLayout_3.addWidget(self.label_setup_header, 3, 0, 1, 1) - self.pushButton_run_waffle_trench = QtWidgets.QPushButton(self.tab) - self.pushButton_run_waffle_trench.setDefault(False) - self.pushButton_run_waffle_trench.setFlat(False) - self.pushButton_run_waffle_trench.setObjectName("pushButton_run_waffle_trench") - self.gridLayout_3.addWidget(self.pushButton_run_waffle_trench, 19, 0, 1, 2) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_3.addItem(spacerItem1, 17, 0, 1, 2) + self.comboBox_current_lamella = QtWidgets.QComboBox(self.tab) + self.comboBox_current_lamella.setObjectName("comboBox_current_lamella") + self.gridLayout_3.addWidget(self.comboBox_current_lamella, 8, 1, 1, 1) self.pushButton_run_autolamella = QtWidgets.QPushButton(self.tab) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) @@ -217,17 +205,17 @@ def setupUi(self, MainWindow): self.pushButton_run_autolamella.setDefault(False) self.pushButton_run_autolamella.setFlat(False) self.pushButton_run_autolamella.setObjectName("pushButton_run_autolamella") - self.gridLayout_3.addWidget(self.pushButton_run_autolamella, 23, 0, 1, 2) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_3.addItem(spacerItem1, 13, 0, 1, 2) - self.pushButton_add_lamella = QtWidgets.QPushButton(self.tab) - self.pushButton_add_lamella.setObjectName("pushButton_add_lamella") - self.gridLayout_3.addWidget(self.pushButton_add_lamella, 7, 0, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_3.addItem(spacerItem2, 18, 0, 1, 2) - self.pushButton_run_waffle_undercut = QtWidgets.QPushButton(self.tab) - self.pushButton_run_waffle_undercut.setObjectName("pushButton_run_waffle_undercut") - self.gridLayout_3.addWidget(self.pushButton_run_waffle_undercut, 20, 0, 1, 2) + self.gridLayout_3.addWidget(self.pushButton_run_autolamella, 22, 0, 1, 2) + self.label_experiment_name = QtWidgets.QLabel(self.tab) + self.label_experiment_name.setObjectName("label_experiment_name") + self.gridLayout_3.addWidget(self.label_experiment_name, 1, 0, 1, 2) + self.pushButton_go_to_lamella = QtWidgets.QPushButton(self.tab) + self.pushButton_go_to_lamella.setObjectName("pushButton_go_to_lamella") + self.gridLayout_3.addWidget(self.pushButton_go_to_lamella, 10, 1, 1, 1) + self.pushButton_remove_lamella = QtWidgets.QPushButton(self.tab) + self.pushButton_remove_lamella.setStyleSheet("") + self.pushButton_remove_lamella.setObjectName("pushButton_remove_lamella") + self.gridLayout_3.addWidget(self.pushButton_remove_lamella, 7, 1, 1, 1) self.label_title = QtWidgets.QLabel(self.tab) font = QtGui.QFont() font.setPointSize(12) @@ -237,28 +225,38 @@ def setupUi(self, MainWindow): self.label_title.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) self.label_title.setObjectName("label_title") self.gridLayout_3.addWidget(self.label_title, 0, 0, 1, 1) - self.label_info = QtWidgets.QLabel(self.tab) - self.label_info.setObjectName("label_info") - self.gridLayout_3.addWidget(self.label_info, 15, 0, 1, 2) - self.pushButton_go_to_lamella = QtWidgets.QPushButton(self.tab) - self.pushButton_go_to_lamella.setObjectName("pushButton_go_to_lamella") - self.gridLayout_3.addWidget(self.pushButton_go_to_lamella, 10, 1, 1, 1) + self.pushButton_save_position = QtWidgets.QPushButton(self.tab) + self.pushButton_save_position.setObjectName("pushButton_save_position") + self.gridLayout_3.addWidget(self.pushButton_save_position, 10, 0, 1, 1) self.label_protocol_name = QtWidgets.QLabel(self.tab) self.label_protocol_name.setObjectName("label_protocol_name") self.gridLayout_3.addWidget(self.label_protocol_name, 2, 0, 1, 2) - self.label_experiment_name = QtWidgets.QLabel(self.tab) - self.label_experiment_name.setObjectName("label_experiment_name") - self.gridLayout_3.addWidget(self.label_experiment_name, 1, 0, 1, 2) + self.pushButton_add_lamella = QtWidgets.QPushButton(self.tab) + self.pushButton_add_lamella.setObjectName("pushButton_add_lamella") + self.gridLayout_3.addWidget(self.pushButton_add_lamella, 7, 0, 1, 1) + self.pushButton_run_waffle_trench = QtWidgets.QPushButton(self.tab) + self.pushButton_run_waffle_trench.setDefault(False) + self.pushButton_run_waffle_trench.setFlat(False) + self.pushButton_run_waffle_trench.setObjectName("pushButton_run_waffle_trench") + self.gridLayout_3.addWidget(self.pushButton_run_waffle_trench, 18, 0, 1, 2) self.label_minimap = QtWidgets.QLabel(self.tab) self.label_minimap.setText("") self.label_minimap.setObjectName("label_minimap") - self.gridLayout_3.addWidget(self.label_minimap, 17, 0, 1, 2) - self.comboBox_current_lamella = QtWidgets.QComboBox(self.tab) - self.comboBox_current_lamella.setObjectName("comboBox_current_lamella") - self.gridLayout_3.addWidget(self.comboBox_current_lamella, 8, 1, 1, 1) - self.pushButton_save_position = QtWidgets.QPushButton(self.tab) - self.pushButton_save_position.setObjectName("pushButton_save_position") - self.gridLayout_3.addWidget(self.pushButton_save_position, 10, 0, 1, 1) + self.gridLayout_3.addWidget(self.label_minimap, 16, 0, 1, 2) + self.comboBox_lamella_history = QtWidgets.QComboBox(self.tab) + self.comboBox_lamella_history.setObjectName("comboBox_lamella_history") + self.gridLayout_3.addWidget(self.comboBox_lamella_history, 12, 0, 1, 1) + self.checkBox_show_lamella_in_view = QtWidgets.QCheckBox(self.tab) + self.checkBox_show_lamella_in_view.setObjectName("checkBox_show_lamella_in_view") + self.gridLayout_3.addWidget(self.checkBox_show_lamella_in_view, 13, 0, 1, 1) + self.label_setup_header = QtWidgets.QLabel(self.tab) + font = QtGui.QFont() + font.setPointSize(9) + font.setBold(True) + font.setWeight(75) + self.label_setup_header.setFont(font) + self.label_setup_header.setObjectName("label_setup_header") + self.gridLayout_3.addWidget(self.label_setup_header, 3, 0, 1, 1) self.pushButton_fail_lamella = QtWidgets.QPushButton(self.tab) self.pushButton_fail_lamella.setObjectName("pushButton_fail_lamella") self.gridLayout_3.addWidget(self.pushButton_fail_lamella, 11, 1, 1, 1) @@ -269,18 +267,18 @@ def setupUi(self, MainWindow): self.label_current_lamella_header.setFont(font) self.label_current_lamella_header.setObjectName("label_current_lamella_header") self.gridLayout_3.addWidget(self.label_current_lamella_header, 8, 0, 1, 1) - self.comboBox_lamella_history = QtWidgets.QComboBox(self.tab) - self.comboBox_lamella_history.setObjectName("comboBox_lamella_history") - self.gridLayout_3.addWidget(self.comboBox_lamella_history, 12, 0, 1, 1) + self.label_info = QtWidgets.QLabel(self.tab) + self.label_info.setObjectName("label_info") + self.gridLayout_3.addWidget(self.label_info, 14, 0, 1, 2) + self.pushButton_run_waffle_undercut = QtWidgets.QPushButton(self.tab) + self.pushButton_run_waffle_undercut.setObjectName("pushButton_run_waffle_undercut") + self.gridLayout_3.addWidget(self.pushButton_run_waffle_undercut, 19, 0, 1, 2) self.pushButton_run_setup_autolamella = QtWidgets.QPushButton(self.tab) self.pushButton_run_setup_autolamella.setObjectName("pushButton_run_setup_autolamella") - self.gridLayout_3.addWidget(self.pushButton_run_setup_autolamella, 21, 0, 1, 2) + self.gridLayout_3.addWidget(self.pushButton_run_setup_autolamella, 20, 0, 1, 2) self.pushButton_revert_stage = QtWidgets.QPushButton(self.tab) self.pushButton_revert_stage.setObjectName("pushButton_revert_stage") self.gridLayout_3.addWidget(self.pushButton_revert_stage, 12, 1, 1, 1) - self.checkBox_show_lamella_in_view = QtWidgets.QCheckBox(self.tab) - self.checkBox_show_lamella_in_view.setObjectName("checkBox_show_lamella_in_view") - self.gridLayout_3.addWidget(self.checkBox_show_lamella_in_view, 14, 0, 1, 1) self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") @@ -438,7 +436,7 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuTools.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(1) + self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): @@ -448,23 +446,23 @@ def retranslateUi(self, MainWindow): self.pushButton_yes.setText(_translate("MainWindow", "Yes")) self.pushButton_stop_workflow_thread.setText(_translate("MainWindow", "Stop Workflow")) self.pushButton_no.setText(_translate("MainWindow", "No")) - self.pushButton_remove_lamella.setText(_translate("MainWindow", "Remove Lamella")) - self.label_setup_header.setText(_translate("MainWindow", "Setup")) - self.pushButton_run_waffle_trench.setText(_translate("MainWindow", "Run Waffle Trench Milling")) self.pushButton_run_autolamella.setText(_translate("MainWindow", "Run AutoLamella")) - self.pushButton_add_lamella.setText(_translate("MainWindow", "Add Lamella")) - self.pushButton_run_waffle_undercut.setText(_translate("MainWindow", "Run Waffle Undercut Milling")) - self.label_title.setText(_translate("MainWindow", "AutoLamella")) - self.label_info.setText(_translate("MainWindow", "No Lamella Selected")) - self.pushButton_go_to_lamella.setText(_translate("MainWindow", "Go to position")) - self.label_protocol_name.setText(_translate("MainWindow", "Protocol:")) self.label_experiment_name.setText(_translate("MainWindow", "Experiment:")) + self.pushButton_go_to_lamella.setText(_translate("MainWindow", "Go to position")) + self.pushButton_remove_lamella.setText(_translate("MainWindow", "Remove Lamella")) + self.label_title.setText(_translate("MainWindow", "AutoLamella")) self.pushButton_save_position.setText(_translate("MainWindow", "Save Position")) + self.label_protocol_name.setText(_translate("MainWindow", "Protocol:")) + self.pushButton_add_lamella.setText(_translate("MainWindow", "Add Lamella")) + self.pushButton_run_waffle_trench.setText(_translate("MainWindow", "Run Waffle Trench Milling")) + self.checkBox_show_lamella_in_view.setText(_translate("MainWindow", "Show Lamellas In View")) + self.label_setup_header.setText(_translate("MainWindow", "Setup")) self.pushButton_fail_lamella.setText(_translate("MainWindow", "Mark Lamella As Failed")) self.label_current_lamella_header.setText(_translate("MainWindow", "Current Lamella")) + self.label_info.setText(_translate("MainWindow", "No Lamella Selected")) + self.pushButton_run_waffle_undercut.setText(_translate("MainWindow", "Run Waffle Undercut Milling")) self.pushButton_run_setup_autolamella.setText(_translate("MainWindow", "Run Setup AutoLamella")) self.pushButton_revert_stage.setText(_translate("MainWindow", "Time Travel To")) - self.checkBox_show_lamella_in_view.setText(_translate("MainWindow", "Show Lamellas In View")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Experiment")) self.label_protocol_name_2.setText(_translate("MainWindow", "Name")) self.label_protocol_method.setText(_translate("MainWindow", "Method")) diff --git a/autolamella/ui/qt/AutoLamellaUI.ui b/autolamella/ui/qt/AutoLamellaUI.ui index e24b9f50..8a5ee2cc 100644 --- a/autolamella/ui/qt/AutoLamellaUI.ui +++ b/autolamella/ui/qt/AutoLamellaUI.ui @@ -77,51 +77,30 @@ - 1 + 0 Experiment - - - - - - - Remove Lamella - - - - - - - - 9 - 75 - true - + + + + Qt::Vertical - - Setup + + + 20 + 40 + - + - - - - Run Waffle Trench Milling - - - false - - - false - - + + - + @@ -588,43 +567,27 @@ - - - - Qt::Vertical - - - - 20 - 40 - + + + + Experiment: - + - - + + - Add Lamella + Go to position - - - - Qt::Vertical - - - - 20 - 40 - + + + + - - - - - Run Waffle Undercut Milling + Remove Lamella @@ -645,48 +608,68 @@ - - + + - No Lamella Selected + Save Position - - + + - Go to position + Protocol: - - + + - Protocol: + Add Lamella - - + + - Experiment: + Run Waffle Trench Milling + + + false + + + false - + - - + + - - + + - Save Position + Show Lamellas In View + + + + + + + + 9 + 75 + true + + + + Setup @@ -710,10 +693,21 @@ - - + + + + No Lamella Selected + + - + + + + Run Waffle Undercut Milling + + + + Run Setup AutoLamella @@ -727,13 +721,6 @@ - - - - Show Lamellas In View - - - From 2c0972175f48b3d28c13ad430983defe49a6e092 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Mon, 2 Oct 2023 16:22:43 +1100 Subject: [PATCH 19/39] start migration of structures --- autolamella/liftout/structures.py | 5 ----- autolamella/structures.py | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index 81d61114..930cf6c7 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -42,7 +42,6 @@ def __init__(self, path: Path = None, name: str = cfg.EXPERIMENT_NAME, program: # TODO: user/data management (e.g. user, sample, id, etc.) - self.state = None self.positions: list[Lamella] = [] self.program = program @@ -64,9 +63,6 @@ def __to_dict__(self) -> dict: return state_dict - def update(self, lamella: 'Lamella') -> None: - self.save() - def save(self) -> None: """Save the experiment data to yaml file""" @@ -77,7 +73,6 @@ def __repr__(self) -> str: return f"""Experiment: Path: {self.path} - State: {self.state} Lamella: {len(self.positions)} """ diff --git a/autolamella/structures.py b/autolamella/structures.py index 969935b5..39be05b2 100644 --- a/autolamella/structures.py +++ b/autolamella/structures.py @@ -65,6 +65,10 @@ class Lamella: _petname: str = None protocol: dict = None _is_failure: bool = False + # lamella_state: MicroscopeState = None + # landing_state: MicroscopeState = None + # landing_selected: bool = False + # _id: str = None def __post_init__(self): From a52dca92d43d8728219909df86c3613233b5d8e8 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Mon, 2 Oct 2023 18:02:36 +1100 Subject: [PATCH 20/39] fix: align at milling current --- autolamella/ui/AutoLamellaUI.py | 4 +- autolamella/workflows/core.py | 87 +++++++++++++++++++++------------ 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index 50e18180..92223fff 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -793,7 +793,7 @@ def update_lamella_ui(self): lamella_position = Point.__from_dict__(protocol["lamella"].get("point", {"x": 0, "y": 0})) stages = patterning._get_milling_stages("lamella", protocol, lamella_position) - _feature_name = "notch" if self.settings.protocol["notch"]["enabled"] else "microexpansion" + _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" protocol = lamella.protocol if _feature_name in lamella.protocol else self.settings.protocol NOTCH_H_OFFSET = 0.5e-6 @@ -1103,7 +1103,7 @@ def _update_milling_protocol(self, idx: int, method: str, stage: AutoLamellaWaff self.experiment.positions[idx].protocol["lamella"]["point"] = stages[0].pattern.point.__to_dict__() # feature - _feature_name = "notch" if self.settings.protocol["notch"]["enabled"] else "microexpansion" + _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" self.experiment.positions[idx].protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages[n_lamella])) self.experiment.positions[idx].protocol[_feature_name]["point"] = stages[n_lamella].pattern.point.__to_dict__() diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index e2954f50..c14c3883 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -297,6 +297,13 @@ def mill_lamella( method = settings.protocol.get("method", "autolamella-waffle") + supervise_map = { + AutoLamellaWaffleStage.MillRoughCut.name: "mill_rough", + AutoLamellaWaffleStage.MillPolishingCut.name: "mill_polishing", + } + validate = settings.protocol["options"]["supervise"].get(supervise_map[lamella.state.stage.name], True) + + _align_at_milling_current = bool(settings.protocol["options"].get("alignment_at_milling_current", True)) _take_reference_images = bool( lamella.state.stage is AutoLamellaWaffleStage.MillRoughCut or settings.protocol["options"].get("take_final_reference_images", True)) @@ -305,6 +312,18 @@ def mill_lamella( and settings.protocol["options"].get("take_final_high_quality_reference_images", False) ) + # milling stages + stages = patterning._get_milling_stages("lamella", lamella.protocol, + point=Point.__from_dict__(lamella.protocol["lamella"]["point"])) + + if lamella.state.stage.name == AutoLamellaWaffleStage.MillPolishingCut.name: + stages = stages[-1] + else: + stages = stages[:-1] + + if not isinstance(stages, list): + stages = [stages] + # beam_shift alignment log_status_message(lamella, "ALIGN_LAMELLA") _update_status_ui(parent_ui, f"{lamella.info} Aligning Reference Images...") @@ -315,12 +334,15 @@ def mill_lamella( ref_image = FibsemImage.load(os.path.join(lamella.path, f"ref_alignment_ib.tif")) _ALIGNMENT_ATTEMPTS = int(settings.protocol["options"].get("alignment_attempts", 1)) - for i in range(_ALIGNMENT_ATTEMPTS): - settings.image.label = f"alignment_target_{lamella.state.stage.name}_{i:02d}" - settings.image.beam_type = BeamType.ION - alignment.beam_shift_alignment(microscope, settings.image, - ref_image=ref_image, - reduced_area=lamella.fiducial_area) + # beam alignment + alignment_current = stages[0].milling.milling_current if _align_at_milling_current else None + settings.image.label = f"alignment_target_{lamella.state.stage.name}" + _multi_step_alignment(microscope=microscope, + image_settings=settings.image, + ref_image=ref_image, + reduced_area=lamella.fiducial_area, + alignment_current=alignment_current, + steps=_ALIGNMENT_ATTEMPTS) settings.image.reduced_area = None @@ -331,12 +353,6 @@ def mill_lamella( _set_images_ui(parent_ui, eb_image, ib_image) - supervise_map = { - AutoLamellaWaffleStage.MillRoughCut.name: "mill_rough", - AutoLamellaWaffleStage.MillPolishingCut.name: "mill_polishing", - } - validate = settings.protocol["options"]["supervise"].get(supervise_map[lamella.state.stage.name], True) - # define feature _MILL_FEATURES = bool("autolamella" in method) if _MILL_FEATURES and lamella.state.stage.name == AutoLamellaWaffleStage.MillRoughCut.name: @@ -345,31 +361,21 @@ def mill_lamella( # check if using notch or microexpansion _feature_name = "notch" if method == "autolamella-waffle" else "microexpansion" - stages = patterning._get_milling_stages( + feature_stages = patterning._get_milling_stages( _feature_name, lamella.protocol, point=Point.__from_dict__(lamella.protocol[_feature_name]["point"]) ) - stages = _validate_mill_ui(stages, parent_ui, + feature_stages = _validate_mill_ui(feature_stages, parent_ui, msg=f"Press Run Milling to mill the {_feature_name} for {lamella._petname}. Press Continue when done.", validate=validate, ) # log feature stages - lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages)) - lamella.protocol[_feature_name]["point"] = stages[0].pattern.point.__to_dict__() + lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(feature_stages)) + lamella.protocol[_feature_name]["point"] = feature_stages[0].pattern.point.__to_dict__() # mill lamella trenches log_status_message(lamella, "MILL_LAMELLA") - stages = patterning._get_milling_stages("lamella", lamella.protocol, - point=Point.__from_dict__(lamella.protocol["lamella"]["point"])) - - if lamella.state.stage.name == AutoLamellaWaffleStage.MillPolishingCut.name: - stages = stages[-1] - else: - stages = stages[:-1] - - if not isinstance(stages, list): - stages = [stages] stages = _validate_mill_ui(stages, parent_ui, msg=f"Press Run Milling to mill the Trenches for {lamella._petname}. Press Continue when done.", @@ -490,15 +496,11 @@ def setup_lamella( # # TODO: integrate this style # # lamella.protocol[AutoLiftoutStage.MillRoughCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[0])) # # lamella.protocol[AutoLiftoutStage.MillRoughCut.name]["point"] = stages[0].pattern.point.__to_dict__() - -# # lamella.protocol[AutoLiftoutStage.MillRegularCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[1])) -# # lamella.protocol[AutoLiftoutStage.MillRegularCut.name]["point"] = stages[1].pattern.point.__to_dict__() - # # lamella.protocol[AutoLiftoutStage.MillPolishingCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[2])) # # lamella.protocol[AutoLiftoutStage.MillPolishingCut.name]["point"] = stages[2].pattern.point.__to_dict__() # feature - if method == "autolamella-waffle": + if "autolamella" in method: n_features = len(feature_stage) lamella.protocol[_feature_name] = deepcopy(patterning._get_protocol_from_stages(stages[n_lamella:n_lamella+n_features])) lamella.protocol[_feature_name]["point"] = stages[n_lamella].pattern.point.__to_dict__() @@ -667,4 +669,25 @@ def _align_lamella_coincident(microscope: FibsemMicroscope, settings: Microscope dy=-det.features[0].feature_m.y, ) - return lamella \ No newline at end of file + return lamella + +# TODO: move to fibsem +from fibsem.structures import ImageSettings +def _multi_step_alignment(microscope: FibsemMicroscope, image_settings: ImageSettings, + ref_image: FibsemImage, reduced_area: FibsemRectangle, alignment_current: float, steps:int = 3) -> None: + + # set alignment current + if alignment_current is not None: + initial_current = microscope.get("current", image_settings.beam_type) + microscope.set("current", alignment_current, image_settings.beam_type) + + base_label = image_settings.label + for i in range(steps): + image_settings.label = f"{base_label}_{i:02d}" + image_settings.beam_type = BeamType.ION + alignment.beam_shift_alignment(microscope, image_settings, + ref_image=ref_image, + reduced_area=reduced_area) + # reset beam current + if alignment_current is not None: + microscope.set("current", initial_current, image_settings.beam_type) \ No newline at end of file From 21f1415128cbee303303f4b188f48d3bcc3a3568 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 18:57:46 +1100 Subject: [PATCH 21/39] migrate multi-step alignment --- autolamella/workflows/core.py | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index c14c3883..c3403fbb 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -337,7 +337,7 @@ def mill_lamella( # beam alignment alignment_current = stages[0].milling.milling_current if _align_at_milling_current else None settings.image.label = f"alignment_target_{lamella.state.stage.name}" - _multi_step_alignment(microscope=microscope, + alignment._multi_step_alignment(microscope=microscope, image_settings=settings.image, ref_image=ref_image, reduced_area=lamella.fiducial_area, @@ -670,24 +670,3 @@ def _align_lamella_coincident(microscope: FibsemMicroscope, settings: Microscope ) return lamella - -# TODO: move to fibsem -from fibsem.structures import ImageSettings -def _multi_step_alignment(microscope: FibsemMicroscope, image_settings: ImageSettings, - ref_image: FibsemImage, reduced_area: FibsemRectangle, alignment_current: float, steps:int = 3) -> None: - - # set alignment current - if alignment_current is not None: - initial_current = microscope.get("current", image_settings.beam_type) - microscope.set("current", alignment_current, image_settings.beam_type) - - base_label = image_settings.label - for i in range(steps): - image_settings.label = f"{base_label}_{i:02d}" - image_settings.beam_type = BeamType.ION - alignment.beam_shift_alignment(microscope, image_settings, - ref_image=ref_image, - reduced_area=reduced_area) - # reset beam current - if alignment_current is not None: - microscope.set("current", initial_current, image_settings.beam_type) \ No newline at end of file From 7164db46626bde8d3e90638480b8e511a151f57b Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 19:21:42 +1100 Subject: [PATCH 22/39] refactor: eucentric_move -> vertical_move --- autolamella/liftout/autoliftout.py | 2 +- autolamella/liftout/workflows/serial.py | 2 +- autolamella/workflows/core.py | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index f46a84a4..8fb62753 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -93,7 +93,7 @@ def liftout_lamella( det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) # align vertical - microscope.eucentric_move( + microscope.vertical_move( settings, dx=det.features[0].feature_m.x, dy=-det.features[0].feature_m.y, diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index ae7ed126..02e33638 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -91,7 +91,7 @@ def liftout_lamella( det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) # align vertical - microscope.eucentric_move( + microscope.vertical_move( settings, dx=det.features[0].feature_m.x, dy=-det.features[0].feature_m.y, diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index c3403fbb..9500b061 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -171,7 +171,7 @@ def mill_undercut( det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info, position=lamella.state.microscope_state.absolute_position) # align vertical - microscope.eucentric_move( + microscope.vertical_move( settings, dx=det.features[0].feature_m.x, dy=-det.features[0].feature_m.y, @@ -266,7 +266,7 @@ def mill_undercut( det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info) # align vertical - microscope.eucentric_move( + microscope.vertical_move( settings, dx=det.features[0].feature_m.x, dy=-det.features[0].feature_m.y, @@ -663,7 +663,7 @@ def _align_lamella_coincident(microscope: FibsemMicroscope, settings: Microscope det = _validate_det_ui_v2(microscope, settings, features, parent_ui, validate, msg=lamella.info, position=lamella.state.microscope_state.absolute_position) # align vertical - microscope.eucentric_move( + microscope.vertical_move( settings, dx=det.features[0].feature_m.x, dy=-det.features[0].feature_m.y, From f98c81bac46704d1f45764b1d63ddbee36e20d09 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 19:22:20 +1100 Subject: [PATCH 23/39] bump requirements --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 32ee67ec..f6f11cb4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -fibsem>=0.2.3 \ No newline at end of file +fibsem>=0.2.5 \ No newline at end of file From d22da481b20b79b2d77f73386e744bdfc2d35b52 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 19:40:29 +1100 Subject: [PATCH 24/39] rm old ui --- autolamella/ui/UI.py | 644 ----------------------------- autolamella/ui/UI.ui | 961 ------------------------------------------- 2 files changed, 1605 deletions(-) delete mode 100644 autolamella/ui/UI.py delete mode 100644 autolamella/ui/UI.ui diff --git a/autolamella/ui/UI.py b/autolamella/ui/UI.py deleted file mode 100644 index a1e97534..00000000 --- a/autolamella/ui/UI.py +++ /dev/null @@ -1,644 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'Ui.ui' -# -# Created by: PyQt5 UI code generator 5.15.9 -# -# 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(920, 989) - MainWindow.setBaseSize(QtCore.QSize(0, 100)) - MainWindow.setWindowOpacity(1.0) - MainWindow.setAutoFillBackground(True) - MainWindow.setStyleSheet("") - MainWindow.setDocumentMode(False) - self.centralwidget = QtWidgets.QWidget(MainWindow) - self.centralwidget.setObjectName("centralwidget") - self.formLayout_3 = QtWidgets.QFormLayout(self.centralwidget) - self.formLayout_3.setObjectName("formLayout_3") - self.tabWidget_2 = QtWidgets.QTabWidget(self.centralwidget) - self.tabWidget_2.setObjectName("tabWidget_2") - self.tab_3 = QtWidgets.QWidget() - self.tab_3.setObjectName("tab_3") - self.formLayout = QtWidgets.QFormLayout(self.tab_3) - self.formLayout.setObjectName("formLayout") - self.label_3 = QtWidgets.QLabel(self.tab_3) - font = QtGui.QFont() - font.setPointSize(12) - font.setBold(True) - font.setWeight(75) - self.label_3.setFont(font) - self.label_3.setObjectName("label_3") - self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_3) - self.log_txt = QtWidgets.QPlainTextEdit(self.tab_3) - self.log_txt.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) - self.log_txt.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.log_txt.setObjectName("log_txt") - self.formLayout.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.log_txt) - self.tabWidget_2.addTab(self.tab_3, "") - self.tab_5 = QtWidgets.QWidget() - self.tab_5.setObjectName("tab_5") - self.verticalLayoutWidget = QtWidgets.QWidget(self.tab_5) - self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 0, 421, 261)) - self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) - self.verticalLayout.setContentsMargins(0, 0, 0, 0) - self.verticalLayout.setObjectName("verticalLayout") - self.instructions_textEdit = QtWidgets.QPlainTextEdit(self.verticalLayoutWidget) - font = QtGui.QFont() - font.setPointSize(10) - self.instructions_textEdit.setFont(font) - self.instructions_textEdit.setLineWidth(2) - self.instructions_textEdit.setReadOnly(True) - self.instructions_textEdit.setObjectName("instructions_textEdit") - self.verticalLayout.addWidget(self.instructions_textEdit) - self.tabWidget_2.addTab(self.tab_5, "") - self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.SpanningRole, self.tabWidget_2) - - self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) - self.tabWidget.setObjectName("tabWidget") - self.tab = QtWidgets.QWidget() - self.tab.setObjectName("tab") - self.gridLayout_3 = QtWidgets.QGridLayout(self.tab) - self.gridLayout_3.setObjectName("gridLayout_3") - self.remove_button = QtWidgets.QPushButton(self.tab) - self.remove_button.setStyleSheet("") - self.remove_button.setObjectName("remove_button") - self.gridLayout_3.addWidget(self.remove_button, 6, 1, 1, 1) - self.microexpansionCheckBox = QtWidgets.QCheckBox(self.tab) - self.microexpansionCheckBox.setObjectName("microexpansionCheckBox") - self.gridLayout_3.addWidget(self.microexpansionCheckBox, 8, 1, 1, 1) - self.go_to_lamella = QtWidgets.QPushButton(self.tab) - self.go_to_lamella.setObjectName("go_to_lamella") - self.gridLayout_3.addWidget(self.go_to_lamella, 13, 1, 1, 1) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_3.addItem(spacerItem, 21, 0, 1, 2) - - self.save_button = QtWidgets.QPushButton(self.tab) - self.save_button.setObjectName("save_button") - self.gridLayout_3.addWidget(self.save_button, 14, 0, 1, 2) - self.add_button = QtWidgets.QPushButton(self.tab) - self.add_button.setObjectName("add_button") - self.gridLayout_3.addWidget(self.add_button, 6, 0, 1, 1) - self.checkBox_show_trench = QtWidgets.QCheckBox(self.tab) - self.checkBox_show_trench.setObjectName("checkBox_show_trench") - self.gridLayout_3.addWidget(self.checkBox_show_trench, 9, 0, 1, 1) - self.label_protocol_name = QtWidgets.QLabel(self.tab) - self.label_protocol_name.setObjectName("label_protocol_name") - self.gridLayout_3.addWidget(self.label_protocol_name, 1, 0, 1, 1) - self.label_current_lamella_header = QtWidgets.QLabel(self.tab) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label_current_lamella_header.setFont(font) - self.label_current_lamella_header.setObjectName("label_current_lamella_header") - self.gridLayout_3.addWidget(self.label_current_lamella_header, 7, 0, 1, 1) - self.label_movement_instructions2 = QtWidgets.QLabel(self.tab) - self.label_movement_instructions2.setObjectName("label_movement_instructions2") - self.gridLayout_3.addWidget(self.label_movement_instructions2, 10, 0, 1, 1) - self.label_title = QtWidgets.QLabel(self.tab) - font = QtGui.QFont() - font.setPointSize(12) - - font.setBold(True) - font.setWeight(75) - self.label_title.setFont(font) - self.label_title.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) - self.label_title.setObjectName("label_title") - self.gridLayout_3.addWidget(self.label_title, 0, 0, 1, 1) - self.pushButton_run_waffle_trench = QtWidgets.QPushButton(self.tab) - self.pushButton_run_waffle_trench.setObjectName("pushButton_run_waffle_trench") - self.gridLayout_3.addWidget(self.pushButton_run_waffle_trench, 18, 0, 1, 2) - self.lamella_count_txt = QtWidgets.QPlainTextEdit(self.tab) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lamella_count_txt.sizePolicy().hasHeightForWidth()) - self.lamella_count_txt.setSizePolicy(sizePolicy) - self.lamella_count_txt.setMaximumSize(QtCore.QSize(16777215, 250)) - self.lamella_count_txt.setBaseSize(QtCore.QSize(0, 100)) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.lamella_count_txt.setFont(font) - self.lamella_count_txt.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.lamella_count_txt.setObjectName("lamella_count_txt") - self.gridLayout_3.addWidget(self.lamella_count_txt, 16, 0, 1, 2) - self.label_movement_instructions = QtWidgets.QLabel(self.tab) - self.label_movement_instructions.setObjectName("label_movement_instructions") - self.gridLayout_3.addWidget(self.label_movement_instructions, 12, 0, 1, 2) - self.comboBox_moving_pattern = QtWidgets.QComboBox(self.tab) - self.comboBox_moving_pattern.setEditable(False) - self.comboBox_moving_pattern.setObjectName("comboBox_moving_pattern") - self.comboBox_moving_pattern.addItem("") - self.comboBox_moving_pattern.addItem("") - self.gridLayout_3.addWidget(self.comboBox_moving_pattern, 10, 1, 1, 1) - self.protocol_txt = QtWidgets.QLabel(self.tab) - self.protocol_txt.setText("") - self.protocol_txt.setObjectName("protocol_txt") - self.gridLayout_3.addWidget(self.protocol_txt, 1, 1, 1, 1) - self.show_lamella = QtWidgets.QCheckBox(self.tab) - self.show_lamella.setChecked(False) - self.show_lamella.setTristate(False) - self.show_lamella.setObjectName("show_lamella") - self.gridLayout_3.addWidget(self.show_lamella, 8, 0, 1, 1) - self.pushButton_save_position = QtWidgets.QPushButton(self.tab) - self.pushButton_save_position.setObjectName("pushButton_save_position") - self.gridLayout_3.addWidget(self.pushButton_save_position, 13, 0, 1, 1) - self.pushButton_run_waffle_notch = QtWidgets.QPushButton(self.tab) - self.pushButton_run_waffle_notch.setObjectName("pushButton_run_waffle_notch") - self.gridLayout_3.addWidget(self.pushButton_run_waffle_notch, 19, 0, 1, 2) - self.label_setup_header = QtWidgets.QLabel(self.tab) - font = QtGui.QFont() - font.setPointSize(12) - font.setBold(True) - font.setWeight(75) - self.label_setup_header.setFont(font) - self.label_setup_header.setObjectName("label_setup_header") - self.gridLayout_3.addWidget(self.label_setup_header, 2, 0, 1, 1) - self.lamella_index = QtWidgets.QComboBox(self.tab) - self.lamella_index.setObjectName("lamella_index") - self.gridLayout_3.addWidget(self.lamella_index, 7, 1, 1, 1) - self.checkBox_show_notch = QtWidgets.QCheckBox(self.tab) - self.checkBox_show_notch.setObjectName("checkBox_show_notch") - self.gridLayout_3.addWidget(self.checkBox_show_notch, 9, 1, 1, 1) - self.run_button = QtWidgets.QPushButton(self.tab) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.run_button.setFont(font) - self.run_button.setStyleSheet("background-color: darkGreen") - self.run_button.setObjectName("run_button") - self.gridLayout_3.addWidget(self.run_button, 20, 0, 1, 2) - - self.tabWidget.addTab(self.tab, "") - self.tab_2 = QtWidgets.QWidget() - self.tab_2.setObjectName("tab_2") - self.formLayout_2 = QtWidgets.QFormLayout(self.tab_2) - self.formLayout_2.setObjectName("formLayout_2") - self.application_file_label = QtWidgets.QLabel(self.tab_2) - self.application_file_label.setObjectName("application_file_label") - self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.application_file_label) - self.comboBoxapplication_file = QtWidgets.QComboBox(self.tab_2) - self.comboBoxapplication_file.setObjectName("comboBoxapplication_file") - self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.comboBoxapplication_file) - self.beamShiftAttemptsLabel = QtWidgets.QLabel(self.tab_2) - self.beamShiftAttemptsLabel.setObjectName("beamShiftAttemptsLabel") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.beamShiftAttemptsLabel) - self.beamshift_attempts = QtWidgets.QDoubleSpinBox(self.tab_2) - self.beamshift_attempts.setObjectName("beamshift_attempts") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.beamshift_attempts) - self.label_6 = QtWidgets.QLabel(self.tab_2) - self.label_6.setObjectName("label_6") - self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_6) - self.comboBox_current_alignment = QtWidgets.QComboBox(self.tab_2) - self.comboBox_current_alignment.setObjectName("comboBox_current_alignment") - self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.comboBox_current_alignment) - self.scanDirectionLabel = QtWidgets.QLabel(self.tab_2) - self.scanDirectionLabel.setObjectName("scanDirectionLabel") - self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.scanDirectionLabel) - self.scanDirectionComboBox = QtWidgets.QComboBox(self.tab_2) - self.scanDirectionComboBox.setObjectName("scanDirectionComboBox") - self.formLayout_2.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.scanDirectionComboBox) - self.tabWidget_3 = QtWidgets.QTabWidget(self.tab_2) - self.tabWidget_3.setTabPosition(QtWidgets.QTabWidget.North) - self.tabWidget_3.setTabShape(QtWidgets.QTabWidget.Rounded) - self.tabWidget_3.setObjectName("tabWidget_3") - self.tab_8 = QtWidgets.QWidget() - self.tab_8.setObjectName("tab_8") - self.gridLayout_5 = QtWidgets.QGridLayout(self.tab_8) - self.gridLayout_5.setObjectName("gridLayout_5") - self.comboBox_trench_preset = QtWidgets.QComboBox(self.tab_8) - self.comboBox_trench_preset.setObjectName("comboBox_trench_preset") - self.gridLayout_5.addWidget(self.comboBox_trench_preset, 8, 1, 1, 1) - self.label_trench_preset = QtWidgets.QLabel(self.tab_8) - self.label_trench_preset.setObjectName("label_trench_preset") - self.gridLayout_5.addWidget(self.label_trench_preset, 8, 0, 1, 1) - self.doubleSpinBox_trench_trench_height = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_trench_height.setMaximum(1000.0) - self.doubleSpinBox_trench_trench_height.setSingleStep(0.01) - self.doubleSpinBox_trench_trench_height.setObjectName("doubleSpinBox_trench_trench_height") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_trench_height, 3, 1, 1, 1) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_5.addItem(spacerItem1, 9, 0, 1, 2) - self.label_trench_lamella_width = QtWidgets.QLabel(self.tab_8) - self.label_trench_lamella_width.setObjectName("label_trench_lamella_width") - self.gridLayout_5.addWidget(self.label_trench_lamella_width, 1, 0, 1, 1) - self.doubleSpinBox_trench_lamella_width = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_lamella_width.setMaximum(1000.0) - self.doubleSpinBox_trench_lamella_width.setSingleStep(0.01) - self.doubleSpinBox_trench_lamella_width.setObjectName("doubleSpinBox_trench_lamella_width") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_lamella_width, 1, 1, 1, 1) - self.doubleSpinBox_trench_milling_depth = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_milling_depth.setMaximum(1000.0) - self.doubleSpinBox_trench_milling_depth.setSingleStep(0.01) - self.doubleSpinBox_trench_milling_depth.setObjectName("doubleSpinBox_trench_milling_depth") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_milling_depth, 4, 1, 1, 1) - self.doubleSpinBox_trench_milling_current = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_milling_current.setMaximum(1000.0) - self.doubleSpinBox_trench_milling_current.setSingleStep(0.01) - self.doubleSpinBox_trench_milling_current.setObjectName("doubleSpinBox_trench_milling_current") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_milling_current, 7, 1, 1, 1) - self.label_trench_size_ratio = QtWidgets.QLabel(self.tab_8) - self.label_trench_size_ratio.setObjectName("label_trench_size_ratio") - self.gridLayout_5.addWidget(self.label_trench_size_ratio, 6, 0, 1, 1) - self.label_trench_milling_depth = QtWidgets.QLabel(self.tab_8) - self.label_trench_milling_depth.setObjectName("label_trench_milling_depth") - self.gridLayout_5.addWidget(self.label_trench_milling_depth, 4, 0, 1, 1) - self.doubleSpinBox_trench_lamella_height = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_lamella_height.setMaximum(1000.0) - self.doubleSpinBox_trench_lamella_height.setSingleStep(0.01) - self.doubleSpinBox_trench_lamella_height.setObjectName("doubleSpinBox_trench_lamella_height") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_lamella_height, 2, 1, 1, 1) - self.label_trench_lamella_height = QtWidgets.QLabel(self.tab_8) - self.label_trench_lamella_height.setObjectName("label_trench_lamella_height") - self.gridLayout_5.addWidget(self.label_trench_lamella_height, 2, 0, 1, 1) - self.doubleSpinBox_trench_size_ratio = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_size_ratio.setMaximum(1000.0) - self.doubleSpinBox_trench_size_ratio.setSingleStep(0.01) - self.doubleSpinBox_trench_size_ratio.setObjectName("doubleSpinBox_trench_size_ratio") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_size_ratio, 6, 1, 1, 1) - self.label_trench_trench_height = QtWidgets.QLabel(self.tab_8) - self.label_trench_trench_height.setObjectName("label_trench_trench_height") - self.gridLayout_5.addWidget(self.label_trench_trench_height, 3, 0, 1, 1) - self.label_trench_milling_current = QtWidgets.QLabel(self.tab_8) - self.label_trench_milling_current.setObjectName("label_trench_milling_current") - self.gridLayout_5.addWidget(self.label_trench_milling_current, 7, 0, 1, 1) - self.doubleSpinBox_trench_offset = QtWidgets.QDoubleSpinBox(self.tab_8) - self.doubleSpinBox_trench_offset.setMaximum(1000.0) - self.doubleSpinBox_trench_offset.setSingleStep(0.01) - self.doubleSpinBox_trench_offset.setObjectName("doubleSpinBox_trench_offset") - self.gridLayout_5.addWidget(self.doubleSpinBox_trench_offset, 5, 1, 1, 1) - self.label_trench_offset = QtWidgets.QLabel(self.tab_8) - self.label_trench_offset.setObjectName("label_trench_offset") - self.gridLayout_5.addWidget(self.label_trench_offset, 5, 0, 1, 1) - self.label = QtWidgets.QLabel(self.tab_8) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label.setFont(font) - self.label.setObjectName("label") - self.gridLayout_5.addWidget(self.label, 0, 0, 1, 2) - self.tabWidget_3.addTab(self.tab_8, "") - self.tab_4 = QtWidgets.QWidget() - self.tab_4.setObjectName("tab_4") - self.gridLayout = QtWidgets.QGridLayout(self.tab_4) - self.gridLayout.setObjectName("gridLayout") - self.widthLabel = QtWidgets.QLabel(self.tab_4) - self.widthLabel.setObjectName("widthLabel") - self.gridLayout.addWidget(self.widthLabel, 2, 0, 1, 1) - self.current_fiducial = QtWidgets.QDoubleSpinBox(self.tab_4) - self.current_fiducial.setMaximum(1000.0) - self.current_fiducial.setObjectName("current_fiducial") - self.gridLayout.addWidget(self.current_fiducial, 4, 1, 1, 1) - self.millingCurrentLabel = QtWidgets.QLabel(self.tab_4) - self.millingCurrentLabel.setObjectName("millingCurrentLabel") - self.gridLayout.addWidget(self.millingCurrentLabel, 4, 0, 1, 1) - self.presetLabel_2 = QtWidgets.QLabel(self.tab_4) - self.presetLabel_2.setObjectName("presetLabel_2") - self.gridLayout.addWidget(self.presetLabel_2, 5, 0, 1, 1) - self.depthLabel = QtWidgets.QLabel(self.tab_4) - self.depthLabel.setObjectName("depthLabel") - self.gridLayout.addWidget(self.depthLabel, 3, 0, 1, 1) - self.width_fiducial = QtWidgets.QDoubleSpinBox(self.tab_4) - self.width_fiducial.setMaximum(1000.0) - self.width_fiducial.setObjectName("width_fiducial") - self.gridLayout.addWidget(self.width_fiducial, 2, 1, 1, 1) - self.fiducial_length = QtWidgets.QDoubleSpinBox(self.tab_4) - self.fiducial_length.setMaximum(1000.0) - self.fiducial_length.setObjectName("fiducial_length") - self.gridLayout.addWidget(self.fiducial_length, 1, 1, 1, 1) - self.depth_fiducial = QtWidgets.QDoubleSpinBox(self.tab_4) - self.depth_fiducial.setMaximum(1000.0) - self.depth_fiducial.setObjectName("depth_fiducial") - self.gridLayout.addWidget(self.depth_fiducial, 3, 1, 1, 1) - self.lengthLabel = QtWidgets.QLabel(self.tab_4) - self.lengthLabel.setObjectName("lengthLabel") - self.gridLayout.addWidget(self.lengthLabel, 1, 0, 1, 1) - self.presetComboBox_fiducial = QtWidgets.QComboBox(self.tab_4) - self.presetComboBox_fiducial.setObjectName("presetComboBox_fiducial") - self.gridLayout.addWidget(self.presetComboBox_fiducial, 5, 1, 1, 1) - self.label_5 = QtWidgets.QLabel(self.tab_4) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label_5.setFont(font) - self.label_5.setObjectName("label_5") - self.gridLayout.addWidget(self.label_5, 0, 0, 1, 2) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem2, 6, 0, 1, 2) - self.tabWidget_3.addTab(self.tab_4, "") - self.tab_6 = QtWidgets.QWidget() - self.tab_6.setObjectName("tab_6") - self.gridLayout_2 = QtWidgets.QGridLayout(self.tab_6) - self.gridLayout_2.setObjectName("gridLayout_2") - self.stageLabel = QtWidgets.QLabel(self.tab_6) - self.stageLabel.setObjectName("stageLabel") - self.gridLayout_2.addWidget(self.stageLabel, 1, 0, 1, 1) - self.stage_lamella = QtWidgets.QComboBox(self.tab_6) - self.stage_lamella.setObjectName("stage_lamella") - self.stage_lamella.addItem("") - self.stage_lamella.addItem("") - self.stage_lamella.addItem("") - self.gridLayout_2.addWidget(self.stage_lamella, 1, 1, 1, 1) - self.lamella_width = QtWidgets.QDoubleSpinBox(self.tab_6) - self.lamella_width.setMaximum(1000.0) - self.lamella_width.setObjectName("lamella_width") - self.gridLayout_2.addWidget(self.lamella_width, 2, 1, 1, 1) - self.widthLabel_2 = QtWidgets.QLabel(self.tab_6) - self.widthLabel_2.setObjectName("widthLabel_2") - self.gridLayout_2.addWidget(self.widthLabel_2, 2, 0, 1, 1) - self.trenchHeightLabel = QtWidgets.QLabel(self.tab_6) - self.trenchHeightLabel.setObjectName("trenchHeightLabel") - self.gridLayout_2.addWidget(self.trenchHeightLabel, 4, 0, 1, 1) - self.lamella_height = QtWidgets.QDoubleSpinBox(self.tab_6) - self.lamella_height.setMaximum(1000.0) - self.lamella_height.setObjectName("lamella_height") - self.gridLayout_2.addWidget(self.lamella_height, 3, 1, 1, 1) - self.trench_height = QtWidgets.QDoubleSpinBox(self.tab_6) - self.trench_height.setMaximum(1000.0) - self.trench_height.setObjectName("trench_height") - self.gridLayout_2.addWidget(self.trench_height, 4, 1, 1, 1) - self.heightLabel = QtWidgets.QLabel(self.tab_6) - self.heightLabel.setObjectName("heightLabel") - self.gridLayout_2.addWidget(self.heightLabel, 3, 0, 1, 1) - self.depth_trench = QtWidgets.QDoubleSpinBox(self.tab_6) - self.depth_trench.setMaximum(1000.0) - self.depth_trench.setObjectName("depth_trench") - self.gridLayout_2.addWidget(self.depth_trench, 5, 1, 1, 1) - self.offset = QtWidgets.QDoubleSpinBox(self.tab_6) - self.offset.setObjectName("offset") - self.gridLayout_2.addWidget(self.offset, 6, 1, 1, 1) - self.size_ratio = QtWidgets.QDoubleSpinBox(self.tab_6) - self.size_ratio.setObjectName("size_ratio") - self.gridLayout_2.addWidget(self.size_ratio, 7, 1, 1, 1) - self.current_lamella = QtWidgets.QDoubleSpinBox(self.tab_6) - self.current_lamella.setMaximum(1000.0) - self.current_lamella.setObjectName("current_lamella") - self.gridLayout_2.addWidget(self.current_lamella, 8, 1, 1, 1) - self.presetComboBox = QtWidgets.QComboBox(self.tab_6) - self.presetComboBox.setObjectName("presetComboBox") - self.gridLayout_2.addWidget(self.presetComboBox, 9, 1, 1, 1) - self.label_9 = QtWidgets.QLabel(self.tab_6) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label_9.setFont(font) - self.label_9.setObjectName("label_9") - self.gridLayout_2.addWidget(self.label_9, 0, 0, 1, 2) - self.millingDepthLabel = QtWidgets.QLabel(self.tab_6) - self.millingDepthLabel.setObjectName("millingDepthLabel") - self.gridLayout_2.addWidget(self.millingDepthLabel, 5, 0, 1, 1) - self.offsetLabel = QtWidgets.QLabel(self.tab_6) - self.offsetLabel.setObjectName("offsetLabel") - self.gridLayout_2.addWidget(self.offsetLabel, 6, 0, 1, 1) - self.sizeRatioLabel = QtWidgets.QLabel(self.tab_6) - self.sizeRatioLabel.setObjectName("sizeRatioLabel") - self.gridLayout_2.addWidget(self.sizeRatioLabel, 7, 0, 1, 1) - self.millingCurrentLabel_2 = QtWidgets.QLabel(self.tab_6) - self.millingCurrentLabel_2.setObjectName("millingCurrentLabel_2") - self.gridLayout_2.addWidget(self.millingCurrentLabel_2, 8, 0, 1, 1) - self.presetLabel = QtWidgets.QLabel(self.tab_6) - self.presetLabel.setObjectName("presetLabel") - self.gridLayout_2.addWidget(self.presetLabel, 9, 0, 1, 1) - spacerItem3 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_2.addItem(spacerItem3, 10, 0, 1, 2) - self.tabWidget_3.addTab(self.tab_6, "") - self.tab_7 = QtWidgets.QWidget() - self.tab_7.setObjectName("tab_7") - self.gridLayout_4 = QtWidgets.QGridLayout(self.tab_7) - self.gridLayout_4.setObjectName("gridLayout_4") - self.micro_exp_distance = QtWidgets.QDoubleSpinBox(self.tab_7) - self.micro_exp_distance.setMaximum(10000.0) - self.micro_exp_distance.setObjectName("micro_exp_distance") - self.gridLayout_4.addWidget(self.micro_exp_distance, 3, 1, 1, 1) - self.micro_exp_height = QtWidgets.QDoubleSpinBox(self.tab_7) - self.micro_exp_height.setMaximum(1000.0) - self.micro_exp_height.setObjectName("micro_exp_height") - self.gridLayout_4.addWidget(self.micro_exp_height, 2, 1, 1, 1) - self.label_10 = QtWidgets.QLabel(self.tab_7) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label_10.setFont(font) - self.label_10.setObjectName("label_10") - self.gridLayout_4.addWidget(self.label_10, 0, 0, 1, 2) - self.heightLabel_2 = QtWidgets.QLabel(self.tab_7) - self.heightLabel_2.setObjectName("heightLabel_2") - self.gridLayout_4.addWidget(self.heightLabel_2, 2, 0, 1, 1) - self.micro_exp_width = QtWidgets.QDoubleSpinBox(self.tab_7) - self.micro_exp_width.setMaximum(1000.0) - self.micro_exp_width.setObjectName("micro_exp_width") - self.gridLayout_4.addWidget(self.micro_exp_width, 1, 1, 1, 1) - self.widthLabel_3 = QtWidgets.QLabel(self.tab_7) - self.widthLabel_3.setObjectName("widthLabel_3") - self.gridLayout_4.addWidget(self.widthLabel_3, 1, 0, 1, 1) - self.distanceLabel = QtWidgets.QLabel(self.tab_7) - self.distanceLabel.setObjectName("distanceLabel") - self.gridLayout_4.addWidget(self.distanceLabel, 3, 0, 1, 1) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_4.addItem(spacerItem4, 4, 0, 1, 2) - self.tabWidget_3.addTab(self.tab_7, "") - self.tab_9 = QtWidgets.QWidget() - self.tab_9.setObjectName("tab_9") - self.tabWidget_3.addTab(self.tab_9, "") - self.tab_10 = QtWidgets.QWidget() - self.tab_10.setObjectName("tab_10") - self.gridLayout_6 = QtWidgets.QGridLayout(self.tab_10) - self.gridLayout_6.setObjectName("gridLayout_6") - self.label_notch_header = QtWidgets.QLabel(self.tab_10) - self.label_notch_header.setObjectName("label_notch_header") - self.gridLayout_6.addWidget(self.label_notch_header, 0, 0, 1, 2) - self.label_notch_vwidth = QtWidgets.QLabel(self.tab_10) - self.label_notch_vwidth.setObjectName("label_notch_vwidth") - self.gridLayout_6.addWidget(self.label_notch_vwidth, 2, 0, 1, 1) - self.doubleSpinBox_notch_vwidth = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_vwidth.setObjectName("doubleSpinBox_notch_vwidth") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_vwidth, 2, 1, 1, 1) - self.label_notch_distance = QtWidgets.QLabel(self.tab_10) - self.label_notch_distance.setObjectName("label_notch_distance") - self.gridLayout_6.addWidget(self.label_notch_distance, 6, 0, 1, 1) - self.label_notch_milling_current = QtWidgets.QLabel(self.tab_10) - self.label_notch_milling_current.setObjectName("label_notch_milling_current") - self.gridLayout_6.addWidget(self.label_notch_milling_current, 7, 0, 1, 1) - self.label_notch_hheight = QtWidgets.QLabel(self.tab_10) - self.label_notch_hheight.setObjectName("label_notch_hheight") - self.gridLayout_6.addWidget(self.label_notch_hheight, 3, 0, 1, 1) - self.label_notch_depth = QtWidgets.QLabel(self.tab_10) - self.label_notch_depth.setObjectName("label_notch_depth") - self.gridLayout_6.addWidget(self.label_notch_depth, 5, 0, 1, 1) - self.doubleSpinBox_notch_vheight = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_vheight.setObjectName("doubleSpinBox_notch_vheight") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_vheight, 1, 1, 1, 1) - self.label_notch_vheight = QtWidgets.QLabel(self.tab_10) - self.label_notch_vheight.setObjectName("label_notch_vheight") - self.gridLayout_6.addWidget(self.label_notch_vheight, 1, 0, 1, 1) - self.doubleSpinBox_notch_hheight = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_hheight.setObjectName("doubleSpinBox_notch_hheight") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_hheight, 3, 1, 1, 1) - self.doubleSpinBox_notch_distance = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_distance.setObjectName("doubleSpinBox_notch_distance") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_distance, 6, 1, 1, 1) - self.doubleSpinBox_notch_milling_current = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_milling_current.setObjectName("doubleSpinBox_notch_milling_current") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_milling_current, 7, 1, 1, 1) - self.label_notch_hwidth = QtWidgets.QLabel(self.tab_10) - self.label_notch_hwidth.setObjectName("label_notch_hwidth") - self.gridLayout_6.addWidget(self.label_notch_hwidth, 4, 0, 1, 1) - self.doubleSpinBox_notch_depth = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_depth.setObjectName("doubleSpinBox_notch_depth") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_depth, 5, 1, 1, 1) - self.checkBox_notch_flip = QtWidgets.QCheckBox(self.tab_10) - self.checkBox_notch_flip.setObjectName("checkBox_notch_flip") - self.gridLayout_6.addWidget(self.checkBox_notch_flip, 8, 1, 1, 1) - self.doubleSpinBox_notch_hwidth = QtWidgets.QDoubleSpinBox(self.tab_10) - self.doubleSpinBox_notch_hwidth.setObjectName("doubleSpinBox_notch_hwidth") - self.gridLayout_6.addWidget(self.doubleSpinBox_notch_hwidth, 4, 1, 1, 1) - spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_6.addItem(spacerItem5, 9, 0, 1, 2) - self.tabWidget_3.addTab(self.tab_10, "") - self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.SpanningRole, self.tabWidget_3) - self.export_protocol = QtWidgets.QPushButton(self.tab_2) - self.export_protocol.setObjectName("export_protocol") - self.formLayout_2.setWidget(24, QtWidgets.QFormLayout.SpanningRole, self.export_protocol) - self.tabWidget.addTab(self.tab_2, "") - self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.tabWidget) - MainWindow.setCentralWidget(self.centralwidget) - self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 920, 21)) - self.menubar.setObjectName("menubar") - self.menuAutoLamella = QtWidgets.QMenu(self.menubar) - self.menuAutoLamella.setObjectName("menuAutoLamella") - self.menuTools = QtWidgets.QMenu(self.menubar) - self.menuTools.setObjectName("menuTools") - MainWindow.setMenuBar(self.menubar) - self.statusbar = QtWidgets.QStatusBar(MainWindow) - self.statusbar.setObjectName("statusbar") - MainWindow.setStatusBar(self.statusbar) - self.create_exp = QtWidgets.QAction(MainWindow) - self.create_exp.setObjectName("create_exp") - self.load_exp = QtWidgets.QAction(MainWindow) - self.load_exp.setObjectName("load_exp") - self.platinum = QtWidgets.QAction(MainWindow) - self.platinum.setObjectName("platinum") - self.action_load_protocol = QtWidgets.QAction(MainWindow) - self.action_load_protocol.setObjectName("action_load_protocol") - self.menuAutoLamella.addAction(self.create_exp) - self.menuAutoLamella.addAction(self.load_exp) - self.menuAutoLamella.addAction(self.action_load_protocol) - self.menuTools.addAction(self.platinum) - self.menubar.addAction(self.menuAutoLamella.menuAction()) - self.menubar.addAction(self.menuTools.menuAction()) - - self.retranslateUi(MainWindow) - self.tabWidget_2.setCurrentIndex(1) - self.tabWidget.setCurrentIndex(0) - self.tabWidget_3.setCurrentIndex(5) - - QtCore.QMetaObject.connectSlotsByName(MainWindow) - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.label_3.setText(_translate("MainWindow", "Console Log")) - self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_3), _translate("MainWindow", "Log")) - self.instructions_textEdit.setPlainText(_translate("MainWindow", "1. Create experiment (file menu) \n" -"2. Take images \n" -"3. Modify protocol if needed\n" -"4. Add lamella\n" -"5. Move to region of interest on the sample\n" -"6. Adjust lamella and fiducial positions\n" -"7. Save lamella\n" -"8. Check fiducial milling\n" -"9. Repeat 3-8 as needed\n" -"10. Run autolamella\n" -"")) - self.tabWidget_2.setTabText(self.tabWidget_2.indexOf(self.tab_5), _translate("MainWindow", "Instructions")) - self.remove_button.setText(_translate("MainWindow", "Remove Lamella")) - self.microexpansionCheckBox.setText(_translate("MainWindow", "Microexpansion Joints")) - self.go_to_lamella.setText(_translate("MainWindow", "Go to position")) - self.save_button.setText(_translate("MainWindow", "Mill Fiducial for current lamella")) - self.add_button.setText(_translate("MainWindow", "Add Lamella")) - self.checkBox_show_trench.setText(_translate("MainWindow", "Show Trench Pattern")) - self.label_protocol_name.setText(_translate("MainWindow", "Protocol Name")) - self.label_current_lamella_header.setText(_translate("MainWindow", "Current Lamella")) - self.label_movement_instructions2.setText(_translate("MainWindow", "Moving pattern :")) - self.label_title.setText(_translate("MainWindow", "Autolamella")) - self.pushButton_run_waffle_trench.setText(_translate("MainWindow", "Run Waffle Trench Milling")) - self.label_movement_instructions.setText(_translate("MainWindow", "Right click where you want the pattern centre to be.")) - self.comboBox_moving_pattern.setItemText(0, _translate("MainWindow", "Fiducial")) - self.comboBox_moving_pattern.setItemText(1, _translate("MainWindow", "Lamella")) - self.show_lamella.setText(_translate("MainWindow", "Show Lamella Pattern")) - self.pushButton_save_position.setText(_translate("MainWindow", "Save Position")) - self.pushButton_run_waffle_notch.setText(_translate("MainWindow", "Run Waffle Notch Milling")) - self.label_setup_header.setText(_translate("MainWindow", "Setup")) - self.checkBox_show_notch.setText(_translate("MainWindow", "Show Notch Pattern")) - self.run_button.setText(_translate("MainWindow", "Run AutoLamella")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Experiment")) - self.application_file_label.setText(_translate("MainWindow", "Application file")) - self.beamShiftAttemptsLabel.setText(_translate("MainWindow", "Beam shift attempts")) - self.label_6.setText(_translate("MainWindow", "Align at:")) - self.scanDirectionLabel.setText(_translate("MainWindow", "Scan Direction")) - self.label_trench_preset.setText(_translate("MainWindow", "Preset")) - self.label_trench_lamella_width.setText(_translate("MainWindow", "Lamella Width (um)")) - self.label_trench_size_ratio.setText(_translate("MainWindow", "Size Ratio")) - self.label_trench_milling_depth.setText(_translate("MainWindow", "Milling Depth (um)")) - self.label_trench_lamella_height.setText(_translate("MainWindow", "Lamella Height (um)")) - self.label_trench_trench_height.setText(_translate("MainWindow", "Trench Height (um)")) - self.label_trench_milling_current.setText(_translate("MainWindow", "Milling Current (nA)")) - self.label_trench_offset.setText(_translate("MainWindow", "Offset (um)")) - self.label.setText(_translate("MainWindow", "Trench Parameters")) - self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.tab_8), _translate("MainWindow", "Trench")) - self.widthLabel.setText(_translate("MainWindow", "Width (µm)")) - self.millingCurrentLabel.setText(_translate("MainWindow", "Milling current (nA)")) - self.presetLabel_2.setText(_translate("MainWindow", "Preset")) - self.depthLabel.setText(_translate("MainWindow", "Depth (µm)")) - self.lengthLabel.setText(_translate("MainWindow", "Length (µm)")) - self.label_5.setText(_translate("MainWindow", "Fiducial Parameters")) - self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.tab_4), _translate("MainWindow", "Fiducial")) - self.stageLabel.setText(_translate("MainWindow", "Stage")) - self.stage_lamella.setItemText(0, _translate("MainWindow", "1. Rough Cut")) - self.stage_lamella.setItemText(1, _translate("MainWindow", "2. Regular Cut")) - self.stage_lamella.setItemText(2, _translate("MainWindow", "3. Polishing Cut")) - self.widthLabel_2.setText(_translate("MainWindow", "Lamella width (µm)")) - self.trenchHeightLabel.setText(_translate("MainWindow", "Trench height (µm)")) - self.heightLabel.setText(_translate("MainWindow", "Lamella height (µm)")) - self.label_9.setText(_translate("MainWindow", "Lamella Parameters ")) - self.millingDepthLabel.setText(_translate("MainWindow", "Milling depth (µm)")) - self.offsetLabel.setText(_translate("MainWindow", "Offset (µm)")) - self.sizeRatioLabel.setText(_translate("MainWindow", "Size ratio")) - self.millingCurrentLabel_2.setText(_translate("MainWindow", "Milling current (nA)")) - self.presetLabel.setText(_translate("MainWindow", "Preset")) - self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.tab_6), _translate("MainWindow", "Lamella")) - self.label_10.setText(_translate("MainWindow", "Microexpansion Joints")) - self.heightLabel_2.setText(_translate("MainWindow", "Height (µm)")) - self.widthLabel_3.setText(_translate("MainWindow", "Width (µm)")) - self.distanceLabel.setText(_translate("MainWindow", "Distance (µm)")) - self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.tab_7), _translate("MainWindow", "MicroExpansion")) - self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.tab_9), _translate("MainWindow", "UnderCut")) - self.label_notch_header.setText(_translate("MainWindow", "Notch Parameters")) - self.label_notch_vwidth.setText(_translate("MainWindow", "Vertical Width (um)")) - self.label_notch_distance.setText(_translate("MainWindow", "Distance (um)")) - self.label_notch_milling_current.setText(_translate("MainWindow", "Milling Current (nA)")) - self.label_notch_hheight.setText(_translate("MainWindow", "Horizontal Height (um)")) - self.label_notch_depth.setText(_translate("MainWindow", "Milling Depth (um)")) - self.label_notch_vheight.setText(_translate("MainWindow", "Vertical Height (um)")) - self.label_notch_hwidth.setText(_translate("MainWindow", "Horizontal Width (um)")) - self.checkBox_notch_flip.setText(_translate("MainWindow", "Flip Pattern")) - self.tabWidget_3.setTabText(self.tabWidget_3.indexOf(self.tab_10), _translate("MainWindow", "Notch")) - self.export_protocol.setText(_translate("MainWindow", "Save protocol to file")) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Protocol")) - self.menuAutoLamella.setTitle(_translate("MainWindow", "File")) - self.menuTools.setTitle(_translate("MainWindow", "Tools")) - self.create_exp.setText(_translate("MainWindow", "Create Experiment")) - self.load_exp.setText(_translate("MainWindow", "Load Experiment")) - self.platinum.setText(_translate("MainWindow", "Splutter Platinum")) - self.action_load_protocol.setText(_translate("MainWindow", "Load Protocol")) diff --git a/autolamella/ui/UI.ui b/autolamella/ui/UI.ui deleted file mode 100644 index 5e312cab..00000000 --- a/autolamella/ui/UI.ui +++ /dev/null @@ -1,961 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 521 - 857 - - - - - 0 - 100 - - - - MainWindow - - - 1.000000000000000 - - - true - - - - - - false - - - - - - - 0 - - - - Experiment - - - - - - - - - - - - - Save Position - - - - - - - Instructions - - - - - - - Go to position - - - - - - - Yes - - - - - - - - 12 - 75 - true - - - - Setup - - - - - - - - - - Remove Lamella - - - - - - - Protocol Name - - - - - - - - 0 - 0 - - - - - 16777215 - 250 - - - - - 0 - 100 - - - - - 75 - true - - - - Qt::ScrollBarAlwaysOff - - - - - - - - 12 - 75 - true - - - - Autolamella - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - Run Waffle Trench Milling - - - - - - - Run Waffle Notch Milling - - - - - - - No - - - - - - - - 75 - true - - - - Current Lamella - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - 75 - true - - - - background-color: darkGreen - - - Run AutoLamella - - - - - - - Add Lamella - - - - - - - - Protocol - - - - - - Application file - - - - - - - - - - Beam shift attempts - - - - - - - - - - Align at: - - - - - - - - - - Scan Direction - - - - - - - - - - QTabWidget::North - - - QTabWidget::Rounded - - - 0 - - - - Trench - - - - - - - - - Preset - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Lamella Width (um) - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - Size Ratio - - - - - - - Milling Depth (um) - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - Lamella Height (um) - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - Trench Height (um) - - - - - - - Milling Current (nA) - - - - - - - 1000.000000000000000 - - - 0.010000000000000 - - - - - - - Offset (um) - - - - - - - - 75 - true - - - - Trench Parameters - - - - - - - - Fiducial - - - - - - Width (µm) - - - - - - - 1000.000000000000000 - - - - - - - Milling current (nA) - - - - - - - Preset - - - - - - - Depth (µm) - - - - - - - 1000.000000000000000 - - - - - - - 1000.000000000000000 - - - - - - - 1000.000000000000000 - - - - - - - Length (µm) - - - - - - - - - - - 75 - true - - - - Fiducial Parameters - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Lamella - - - - - - Stage - - - - - - - - 1. Rough Cut - - - - - 2. Regular Cut - - - - - 3. Polishing Cut - - - - - - - - 1000.000000000000000 - - - - - - - Lamella width (µm) - - - - - - - Trench height (µm) - - - - - - - 1000.000000000000000 - - - - - - - 1000.000000000000000 - - - - - - - Lamella height (µm) - - - - - - - 1000.000000000000000 - - - - - - - - - - - - - 1000.000000000000000 - - - - - - - - - - - 75 - true - - - - Lamella Parameters - - - - - - - Milling depth (µm) - - - - - - - Offset (µm) - - - - - - - Size ratio - - - - - - - Milling current (nA) - - - - - - - Preset - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - MicroExpansion - - - - - - 10000.000000000000000 - - - - - - - 1000.000000000000000 - - - - - - - - 75 - true - - - - Microexpansion Joints - - - - - - - Height (µm) - - - - - - - 1000.000000000000000 - - - - - - - Width (µm) - - - - - - - Distance (µm) - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - UnderCut - - - - - Notch - - - - - - Notch Parameters - - - - - - - Vertical Width (um) - - - - - - - - - - Distance (um) - - - - - - - Milling Current (nA) - - - - - - - Horizontal Height (um) - - - - - - - Milling Depth (um) - - - - - - - - - - Vertical Height (um) - - - - - - - - - - - - - - - - Horizontal Width (um) - - - - - - - - - - Flip Pattern - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - Save protocol to file - - - - - - - - - - - - - 0 - 0 - 521 - 20 - - - - - File - - - - - - - - Tools - - - - - - - - - - Create Experiment - - - - - Load Experiment - - - - - Splutter Platinum - - - - - Load Protocol - - - - - - From bf7d5fbf8dab64a8f7c553c3c5d7f925b4dbb228 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 20:00:04 +1100 Subject: [PATCH 25/39] update uis --- autolamella/liftout/autoliftout.py | 2 +- .../liftout/protocol/protocol-base.yaml | 2 - autolamella/liftout/ui/AutoLiftoutUIv2.py | 8 +- autolamella/liftout/ui/qt/AutoLiftoutUIv2.py | 265 +++++++------- autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui | 338 ++++++++---------- autolamella/liftout/workflows/serial.py | 4 +- autolamella/ui/AutoLamellaUI.py | 46 ++- autolamella/ui/qt/AutoLamellaUI.py | 147 +++++--- autolamella/ui/qt/AutoLamellaUI.ui | 196 +++++++--- 9 files changed, 574 insertions(+), 434 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 8fb62753..caebe4cf 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -842,7 +842,7 @@ def run_autoliftout_workflow( parent_ui: AutoLiftoutUIv2, ) -> Experiment: - CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_advance"]) + CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_next_stage"]) _update_status_ui(parent_ui, "Starting AutoLiftout Workflow...") logging.info( diff --git a/autolamella/liftout/protocol/protocol-base.yaml b/autolamella/liftout/protocol/protocol-base.yaml index 168bec83..13022636 100644 --- a/autolamella/liftout/protocol/protocol-base.yaml +++ b/autolamella/liftout/protocol/protocol-base.yaml @@ -68,12 +68,10 @@ options: supervise: landing: true liftout: true - reset: true trench: false undercut: true setup_lamella: true mill_rough: true - mill_regular: true mill_polishing: true platinum: application_file: cryo_Pt_dep diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index 0d4ff3e1..d5917edb 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -394,7 +394,7 @@ def update_ui_from_protocol(self, protocol: dict): # options options = self.settings.protocol["options"] self.checkBox_options_batch_mode.setChecked(bool(options["batch_mode"])) - self.checkBox_options_confirm_next_stage.setChecked(bool(options["confirm_advance"])) + self.checkBox_options_confirm_next_stage.setChecked(bool(options["confirm_next_stage"])) self.comboBox_options_liftout_joining_method.setCurrentText(options.get("liftout_joining_method", "None")) self.comboBox_options_landing_joining_method.setCurrentText(options.get("landing_joining_method", "Weld")) @@ -406,10 +406,8 @@ def update_ui_from_protocol(self, protocol: dict): self.checkBox_supervise_mill_undercut.setChecked(bool(options["supervise"]["undercut"])) self.checkBox_supervise_liftout.setChecked(bool(options["supervise"]["liftout"])) self.checkBox_supervise_landing.setChecked(bool(options["supervise"]["landing"])) - self.checkBox_supervise_reset.setChecked(bool(options["supervise"]["reset"])) self.checkBox_supervise_setup_lamella.setChecked(bool(options["supervise"]["setup_lamella"])) self.checkBox_supervise_mill_rough.setChecked(bool(options["supervise"]["mill_rough"])) - self.checkBox_supervise_mill_regular.setChecked(bool(options["supervise"]["mill_regular"])) self.checkBox_supervise_mill_polishing.setChecked(bool(options["supervise"]["mill_polishing"])) # ml @@ -428,7 +426,7 @@ def update_protocol_from_ui(self): # TODO: fix this for both methods self.settings.protocol["options"].update({ "batch_mode": self.checkBox_options_batch_mode.isChecked(), - "confirm_advance": self.checkBox_options_confirm_next_stage.isChecked(), + "confirm_next_stage": self.checkBox_options_confirm_next_stage.isChecked(), "liftout_joining_method": self.comboBox_options_liftout_joining_method.currentText(), "landing_joining_method": self.comboBox_options_landing_joining_method.currentText(), "lamella_start_position": self.comboBox_options_lamella_start_position.currentText(), @@ -438,10 +436,8 @@ def update_protocol_from_ui(self): "undercut": self.checkBox_supervise_mill_undercut.isChecked(), "liftout": self.checkBox_supervise_liftout.isChecked(), "landing": self.checkBox_supervise_landing.isChecked(), - "reset": self.checkBox_supervise_reset.isChecked(), "setup_lamella": self.checkBox_supervise_setup_lamella.isChecked(), "mill_rough": self.checkBox_supervise_mill_rough.isChecked(), - "mill_regular": self.checkBox_supervise_mill_regular.isChecked(), "mill_polishing": self.checkBox_supervise_mill_polishing.isChecked() }} ) diff --git a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py index fcb5192c..35eda0d0 100644 --- a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py @@ -14,7 +14,7 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(450, 819) + MainWindow.resize(470, 855) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) @@ -42,17 +42,12 @@ def setupUi(self, MainWindow): self.general.setObjectName("general") self.gridLayout_2 = QtWidgets.QGridLayout(self.general) self.gridLayout_2.setObjectName("gridLayout_2") - self.comboBox_lamella_history = QtWidgets.QComboBox(self.general) - self.comboBox_lamella_history.setObjectName("comboBox_lamella_history") - self.gridLayout_2.addWidget(self.comboBox_lamella_history, 7, 0, 1, 1) - self.label_info = QtWidgets.QLabel(self.general) - self.label_info.setObjectName("label_info") - self.gridLayout_2.addWidget(self.label_info, 8, 0, 1, 2) - spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_2.addItem(spacerItem, 14, 0, 1, 2) - self.pushButton_revert_stage = QtWidgets.QPushButton(self.general) - self.pushButton_revert_stage.setObjectName("pushButton_revert_stage") - self.gridLayout_2.addWidget(self.pushButton_revert_stage, 7, 1, 1, 1) + self.checkBox_current_lamella_landing_selected = QtWidgets.QCheckBox(self.general) + self.checkBox_current_lamella_landing_selected.setObjectName("checkBox_current_lamella_landing_selected") + self.gridLayout_2.addWidget(self.checkBox_current_lamella_landing_selected, 6, 0, 1, 1) + self.label_lamella_detail = QtWidgets.QLabel(self.general) + self.label_lamella_detail.setObjectName("label_lamella_detail") + self.gridLayout_2.addWidget(self.label_lamella_detail, 5, 0, 1, 2) self.label_lamella_header = QtWidgets.QLabel(self.general) font = QtGui.QFont() font.setBold(True) @@ -60,81 +55,64 @@ def setupUi(self, MainWindow): self.label_lamella_header.setFont(font) self.label_lamella_header.setObjectName("label_lamella_header") self.gridLayout_2.addWidget(self.label_lamella_header, 2, 0, 1, 2) - self.pushButton_setup_autoliftout = QtWidgets.QPushButton(self.general) - self.pushButton_setup_autoliftout.setObjectName("pushButton_setup_autoliftout") - self.gridLayout_2.addWidget(self.pushButton_setup_autoliftout, 10, 0, 1, 2) - self.label_lamella_detail = QtWidgets.QLabel(self.general) - self.label_lamella_detail.setObjectName("label_lamella_detail") - self.gridLayout_2.addWidget(self.label_lamella_detail, 5, 0, 1, 2) + self.label_experiment_name = QtWidgets.QLabel(self.general) + self.label_experiment_name.setObjectName("label_experiment_name") + self.gridLayout_2.addWidget(self.label_experiment_name, 0, 0, 1, 2) + self.comboBox_current_lamella = QtWidgets.QComboBox(self.general) + self.comboBox_current_lamella.setObjectName("comboBox_current_lamella") + self.gridLayout_2.addWidget(self.comboBox_current_lamella, 3, 1, 1, 1) + self.label_info = QtWidgets.QLabel(self.general) + self.label_info.setObjectName("label_info") + self.gridLayout_2.addWidget(self.label_info, 8, 0, 1, 2) + self.pushButton_revert_stage = QtWidgets.QPushButton(self.general) + self.pushButton_revert_stage.setObjectName("pushButton_revert_stage") + self.gridLayout_2.addWidget(self.pushButton_revert_stage, 7, 1, 1, 1) self.label_protocol_name = QtWidgets.QLabel(self.general) self.label_protocol_name.setObjectName("label_protocol_name") self.gridLayout_2.addWidget(self.label_protocol_name, 1, 0, 1, 2) self.pushButton_run_polishing = QtWidgets.QPushButton(self.general) self.pushButton_run_polishing.setObjectName("pushButton_run_polishing") self.gridLayout_2.addWidget(self.pushButton_run_polishing, 13, 0, 1, 2) - self.pushButton_run_autoliftout = QtWidgets.QPushButton(self.general) - self.pushButton_run_autoliftout.setObjectName("pushButton_run_autoliftout") - self.gridLayout_2.addWidget(self.pushButton_run_autoliftout, 11, 0, 1, 2) - spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_2.addItem(spacerItem1, 9, 0, 1, 2) - self.comboBox_current_lamella = QtWidgets.QComboBox(self.general) - self.comboBox_current_lamella.setObjectName("comboBox_current_lamella") - self.gridLayout_2.addWidget(self.comboBox_current_lamella, 3, 1, 1, 1) self.label_current_lamella = QtWidgets.QLabel(self.general) self.label_current_lamella.setObjectName("label_current_lamella") self.gridLayout_2.addWidget(self.label_current_lamella, 3, 0, 1, 1) - self.label_experiment_name = QtWidgets.QLabel(self.general) - self.label_experiment_name.setObjectName("label_experiment_name") - self.gridLayout_2.addWidget(self.label_experiment_name, 0, 0, 1, 2) - self.checkBox_current_lamella_landing_selected = QtWidgets.QCheckBox(self.general) - self.checkBox_current_lamella_landing_selected.setObjectName("checkBox_current_lamella_landing_selected") - self.gridLayout_2.addWidget(self.checkBox_current_lamella_landing_selected, 6, 0, 1, 1) + self.comboBox_lamella_history = QtWidgets.QComboBox(self.general) + self.comboBox_lamella_history.setObjectName("comboBox_lamella_history") + self.gridLayout_2.addWidget(self.comboBox_lamella_history, 7, 0, 1, 1) + self.pushButton_setup_autoliftout = QtWidgets.QPushButton(self.general) + self.pushButton_setup_autoliftout.setObjectName("pushButton_setup_autoliftout") + self.gridLayout_2.addWidget(self.pushButton_setup_autoliftout, 10, 0, 1, 2) + self.pushButton_run_autoliftout = QtWidgets.QPushButton(self.general) + self.pushButton_run_autoliftout.setObjectName("pushButton_run_autoliftout") + self.gridLayout_2.addWidget(self.pushButton_run_autoliftout, 11, 0, 1, 2) self.checkBox_current_lamella_failure = QtWidgets.QCheckBox(self.general) self.checkBox_current_lamella_failure.setObjectName("checkBox_current_lamella_failure") self.gridLayout_2.addWidget(self.checkBox_current_lamella_failure, 6, 1, 1, 1) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_2.addItem(spacerItem, 9, 0, 1, 2) self.pushButton_run_serial_liftout_landing = QtWidgets.QPushButton(self.general) self.pushButton_run_serial_liftout_landing.setObjectName("pushButton_run_serial_liftout_landing") self.gridLayout_2.addWidget(self.pushButton_run_serial_liftout_landing, 12, 0, 1, 2) - self.tabWidget.addTab(self.general, "") self.tabProtocol = QtWidgets.QWidget() self.tabProtocol.setObjectName("tabProtocol") self.gridLayout_3 = QtWidgets.QGridLayout(self.tabProtocol) self.gridLayout_3.setObjectName("gridLayout_3") - self.label_options_landing_joining_method = QtWidgets.QLabel(self.tabProtocol) - self.label_options_landing_joining_method.setObjectName("label_options_landing_joining_method") - self.gridLayout_3.addWidget(self.label_options_landing_joining_method, 7, 0, 1, 1) - self.label_options_lamella_start_position = QtWidgets.QLabel(self.tabProtocol) - self.label_options_lamella_start_position.setObjectName("label_options_lamella_start_position") - self.gridLayout_3.addWidget(self.label_options_lamella_start_position, 4, 0, 1, 1) - self.checkBox_options_confirm_next_stage = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_options_confirm_next_stage.setChecked(True) - self.checkBox_options_confirm_next_stage.setObjectName("checkBox_options_confirm_next_stage") - self.gridLayout_3.addWidget(self.checkBox_options_confirm_next_stage, 3, 1, 1, 1) self.comboBox_options_landing_joining_method = QtWidgets.QComboBox(self.tabProtocol) self.comboBox_options_landing_joining_method.setObjectName("comboBox_options_landing_joining_method") self.gridLayout_3.addWidget(self.comboBox_options_landing_joining_method, 7, 1, 1, 1) - self.label_protocol_ml_checkpoint = QtWidgets.QLabel(self.tabProtocol) - self.label_protocol_ml_checkpoint.setObjectName("label_protocol_ml_checkpoint") - self.gridLayout_3.addWidget(self.label_protocol_ml_checkpoint, 10, 0, 1, 1) - self.label_options_landing_start_position = QtWidgets.QLabel(self.tabProtocol) - self.label_options_landing_start_position.setObjectName("label_options_landing_start_position") - self.gridLayout_3.addWidget(self.label_options_landing_start_position, 6, 0, 1, 1) - self.spinBox_protocol_ml_num_classes = QtWidgets.QSpinBox(self.tabProtocol) - self.spinBox_protocol_ml_num_classes.setObjectName("spinBox_protocol_ml_num_classes") - self.gridLayout_3.addWidget(self.spinBox_protocol_ml_num_classes, 11, 1, 1, 1) - self.checkBox_supervise_mill_trench = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_supervise_mill_trench.setObjectName("checkBox_supervise_mill_trench") - self.gridLayout_3.addWidget(self.checkBox_supervise_mill_trench, 13, 0, 1, 1) - self.label_options_liftout_joining_method = QtWidgets.QLabel(self.tabProtocol) - self.label_options_liftout_joining_method.setObjectName("label_options_liftout_joining_method") - self.gridLayout_3.addWidget(self.label_options_liftout_joining_method, 5, 0, 1, 1) - self.checkBox_supervise_setup_lamella = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_supervise_setup_lamella.setObjectName("checkBox_supervise_setup_lamella") - self.gridLayout_3.addWidget(self.checkBox_supervise_setup_lamella, 13, 1, 1, 1) - self.checkBox_supervise_reset = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_supervise_reset.setObjectName("checkBox_supervise_reset") - self.gridLayout_3.addWidget(self.checkBox_supervise_reset, 17, 0, 1, 1) + self.label_protocol_name_2 = QtWidgets.QLabel(self.tabProtocol) + self.label_protocol_name_2.setObjectName("label_protocol_name_2") + self.gridLayout_3.addWidget(self.label_protocol_name_2, 0, 0, 1, 1) + self.lineEdit_protocol_ml_checkpoint = QtWidgets.QLineEdit(self.tabProtocol) + self.lineEdit_protocol_ml_checkpoint.setObjectName("lineEdit_protocol_ml_checkpoint") + self.gridLayout_3.addWidget(self.lineEdit_protocol_ml_checkpoint, 10, 1, 1, 1) + self.label_protocol_method = QtWidgets.QLabel(self.tabProtocol) + self.label_protocol_method.setObjectName("label_protocol_method") + self.gridLayout_3.addWidget(self.label_protocol_method, 1, 0, 1, 1) + self.label_options_landing_joining_method = QtWidgets.QLabel(self.tabProtocol) + self.label_options_landing_joining_method.setObjectName("label_options_landing_joining_method") + self.gridLayout_3.addWidget(self.label_options_landing_joining_method, 7, 0, 1, 1) self.label_protocol_options_header = QtWidgets.QLabel(self.tabProtocol) font = QtGui.QFont() font.setBold(True) @@ -142,48 +120,50 @@ def setupUi(self, MainWindow): self.label_protocol_options_header.setFont(font) self.label_protocol_options_header.setObjectName("label_protocol_options_header") self.gridLayout_3.addWidget(self.label_protocol_options_header, 2, 0, 1, 2) - self.checkBox_supervise_mill_regular = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_supervise_mill_regular.setObjectName("checkBox_supervise_mill_regular") - self.gridLayout_3.addWidget(self.checkBox_supervise_mill_regular, 15, 1, 1, 1) - self.pushButton_update_protocol = QtWidgets.QPushButton(self.tabProtocol) - self.pushButton_update_protocol.setObjectName("pushButton_update_protocol") - self.gridLayout_3.addWidget(self.pushButton_update_protocol, 18, 0, 1, 2) + self.label_protocol_ml_header_2 = QtWidgets.QLabel(self.tabProtocol) + self.label_protocol_ml_header_2.setObjectName("label_protocol_ml_header_2") + self.gridLayout_3.addWidget(self.label_protocol_ml_header_2, 9, 0, 1, 1) self.checkBox_supervise_mill_rough = QtWidgets.QCheckBox(self.tabProtocol) self.checkBox_supervise_mill_rough.setObjectName("checkBox_supervise_mill_rough") self.gridLayout_3.addWidget(self.checkBox_supervise_mill_rough, 14, 1, 1, 1) - self.checkBox_supervise_mill_polishing = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_supervise_mill_polishing.setObjectName("checkBox_supervise_mill_polishing") - self.gridLayout_3.addWidget(self.checkBox_supervise_mill_polishing, 16, 1, 1, 1) - self.comboBox_options_liftout_joining_method = QtWidgets.QComboBox(self.tabProtocol) - self.comboBox_options_liftout_joining_method.setObjectName("comboBox_options_liftout_joining_method") - self.gridLayout_3.addWidget(self.comboBox_options_liftout_joining_method, 5, 1, 1, 1) - self.label_protocol_ml_num_classes = QtWidgets.QLabel(self.tabProtocol) - self.label_protocol_ml_num_classes.setObjectName("label_protocol_ml_num_classes") - self.gridLayout_3.addWidget(self.label_protocol_ml_num_classes, 11, 0, 1, 1) - self.label_protocol_name_2 = QtWidgets.QLabel(self.tabProtocol) - self.label_protocol_name_2.setObjectName("label_protocol_name_2") - self.gridLayout_3.addWidget(self.label_protocol_name_2, 0, 0, 1, 1) self.checkBox_supervise_landing = QtWidgets.QCheckBox(self.tabProtocol) self.checkBox_supervise_landing.setObjectName("checkBox_supervise_landing") self.gridLayout_3.addWidget(self.checkBox_supervise_landing, 16, 0, 1, 1) + self.spinBox_protocol_ml_num_classes = QtWidgets.QSpinBox(self.tabProtocol) + self.spinBox_protocol_ml_num_classes.setObjectName("spinBox_protocol_ml_num_classes") + self.gridLayout_3.addWidget(self.spinBox_protocol_ml_num_classes, 11, 1, 1, 1) + self.checkBox_supervise_liftout = QtWidgets.QCheckBox(self.tabProtocol) + self.checkBox_supervise_liftout.setObjectName("checkBox_supervise_liftout") + self.gridLayout_3.addWidget(self.checkBox_supervise_liftout, 15, 0, 1, 1) + self.comboBox_options_liftout_joining_method = QtWidgets.QComboBox(self.tabProtocol) + self.comboBox_options_liftout_joining_method.setObjectName("comboBox_options_liftout_joining_method") + self.gridLayout_3.addWidget(self.comboBox_options_liftout_joining_method, 5, 1, 1, 1) + self.comboBox_options_lamella_start_position = QtWidgets.QComboBox(self.tabProtocol) + self.comboBox_options_lamella_start_position.setObjectName("comboBox_options_lamella_start_position") + self.gridLayout_3.addWidget(self.comboBox_options_lamella_start_position, 4, 1, 1, 1) + self.label_protocol_ml_header = QtWidgets.QLabel(self.tabProtocol) + font = QtGui.QFont() + font.setBold(True) + font.setWeight(75) + self.label_protocol_ml_header.setFont(font) + self.label_protocol_ml_header.setObjectName("label_protocol_ml_header") + self.gridLayout_3.addWidget(self.label_protocol_ml_header, 8, 0, 1, 1) self.checkBox_options_batch_mode = QtWidgets.QCheckBox(self.tabProtocol) self.checkBox_options_batch_mode.setChecked(True) self.checkBox_options_batch_mode.setObjectName("checkBox_options_batch_mode") self.gridLayout_3.addWidget(self.checkBox_options_batch_mode, 3, 0, 1, 1) - spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout_3.addItem(spacerItem2, 19, 0, 1, 2) - self.comboBox_options_landing_start_position = QtWidgets.QComboBox(self.tabProtocol) - self.comboBox_options_landing_start_position.setObjectName("comboBox_options_landing_start_position") - self.gridLayout_3.addWidget(self.comboBox_options_landing_start_position, 6, 1, 1, 1) - self.lineEdit_protocol_ml_checkpoint = QtWidgets.QLineEdit(self.tabProtocol) - self.lineEdit_protocol_ml_checkpoint.setObjectName("lineEdit_protocol_ml_checkpoint") - self.gridLayout_3.addWidget(self.lineEdit_protocol_ml_checkpoint, 10, 1, 1, 1) - self.lineEdit_protocol_ml_encoder = QtWidgets.QLineEdit(self.tabProtocol) - self.lineEdit_protocol_ml_encoder.setObjectName("lineEdit_protocol_ml_encoder") - self.gridLayout_3.addWidget(self.lineEdit_protocol_ml_encoder, 9, 1, 1, 1) + self.label_options_landing_start_position = QtWidgets.QLabel(self.tabProtocol) + self.label_options_landing_start_position.setObjectName("label_options_landing_start_position") + self.gridLayout_3.addWidget(self.label_options_landing_start_position, 6, 0, 1, 1) self.checkBox_supervise_mill_undercut = QtWidgets.QCheckBox(self.tabProtocol) self.checkBox_supervise_mill_undercut.setObjectName("checkBox_supervise_mill_undercut") self.gridLayout_3.addWidget(self.checkBox_supervise_mill_undercut, 14, 0, 1, 1) + self.comboBox_options_landing_start_position = QtWidgets.QComboBox(self.tabProtocol) + self.comboBox_options_landing_start_position.setObjectName("comboBox_options_landing_start_position") + self.gridLayout_3.addWidget(self.comboBox_options_landing_start_position, 6, 1, 1, 1) + self.label_options_lamella_start_position = QtWidgets.QLabel(self.tabProtocol) + self.label_options_lamella_start_position.setObjectName("label_options_lamella_start_position") + self.gridLayout_3.addWidget(self.label_options_lamella_start_position, 4, 0, 1, 1) self.label_protocol_supervision_header = QtWidgets.QLabel(self.tabProtocol) font = QtGui.QFont() font.setBold(True) @@ -191,41 +171,52 @@ def setupUi(self, MainWindow): self.label_protocol_supervision_header.setFont(font) self.label_protocol_supervision_header.setObjectName("label_protocol_supervision_header") self.gridLayout_3.addWidget(self.label_protocol_supervision_header, 12, 0, 1, 2) - self.checkBox_supervise_liftout = QtWidgets.QCheckBox(self.tabProtocol) - self.checkBox_supervise_liftout.setObjectName("checkBox_supervise_liftout") - self.gridLayout_3.addWidget(self.checkBox_supervise_liftout, 15, 0, 1, 1) - self.label_protocol_ml_header = QtWidgets.QLabel(self.tabProtocol) - font = QtGui.QFont() - font.setBold(True) - font.setWeight(75) - self.label_protocol_ml_header.setFont(font) - self.label_protocol_ml_header.setObjectName("label_protocol_ml_header") - self.gridLayout_3.addWidget(self.label_protocol_ml_header, 8, 0, 1, 1) - self.label_protocol_ml_header_2 = QtWidgets.QLabel(self.tabProtocol) - self.label_protocol_ml_header_2.setObjectName("label_protocol_ml_header_2") - self.gridLayout_3.addWidget(self.label_protocol_ml_header_2, 9, 0, 1, 1) - self.comboBox_options_lamella_start_position = QtWidgets.QComboBox(self.tabProtocol) - self.comboBox_options_lamella_start_position.setObjectName("comboBox_options_lamella_start_position") - self.gridLayout_3.addWidget(self.comboBox_options_lamella_start_position, 4, 1, 1, 1) - self.label_protocol_method = QtWidgets.QLabel(self.tabProtocol) - self.label_protocol_method.setObjectName("label_protocol_method") - self.gridLayout_3.addWidget(self.label_protocol_method, 1, 0, 1, 1) + self.checkBox_supervise_mill_trench = QtWidgets.QCheckBox(self.tabProtocol) + self.checkBox_supervise_mill_trench.setObjectName("checkBox_supervise_mill_trench") + self.gridLayout_3.addWidget(self.checkBox_supervise_mill_trench, 13, 0, 1, 1) + self.checkBox_supervise_setup_lamella = QtWidgets.QCheckBox(self.tabProtocol) + self.checkBox_supervise_setup_lamella.setObjectName("checkBox_supervise_setup_lamella") + self.gridLayout_3.addWidget(self.checkBox_supervise_setup_lamella, 13, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout_3.addItem(spacerItem1, 18, 0, 1, 2) + self.pushButton_update_protocol = QtWidgets.QPushButton(self.tabProtocol) + self.pushButton_update_protocol.setObjectName("pushButton_update_protocol") + self.gridLayout_3.addWidget(self.pushButton_update_protocol, 17, 0, 1, 2) + self.label_protocol_ml_num_classes = QtWidgets.QLabel(self.tabProtocol) + self.label_protocol_ml_num_classes.setObjectName("label_protocol_ml_num_classes") + self.gridLayout_3.addWidget(self.label_protocol_ml_num_classes, 11, 0, 1, 1) + self.checkBox_options_confirm_next_stage = QtWidgets.QCheckBox(self.tabProtocol) + self.checkBox_options_confirm_next_stage.setChecked(True) + self.checkBox_options_confirm_next_stage.setObjectName("checkBox_options_confirm_next_stage") + self.gridLayout_3.addWidget(self.checkBox_options_confirm_next_stage, 3, 1, 1, 1) + self.label_options_liftout_joining_method = QtWidgets.QLabel(self.tabProtocol) + self.label_options_liftout_joining_method.setObjectName("label_options_liftout_joining_method") + self.gridLayout_3.addWidget(self.label_options_liftout_joining_method, 5, 0, 1, 1) self.lineEdit_protocol_name = QtWidgets.QLineEdit(self.tabProtocol) self.lineEdit_protocol_name.setObjectName("lineEdit_protocol_name") self.gridLayout_3.addWidget(self.lineEdit_protocol_name, 0, 1, 1, 1) + self.label_protocol_ml_checkpoint = QtWidgets.QLabel(self.tabProtocol) + self.label_protocol_ml_checkpoint.setObjectName("label_protocol_ml_checkpoint") + self.gridLayout_3.addWidget(self.label_protocol_ml_checkpoint, 10, 0, 1, 1) + self.lineEdit_protocol_ml_encoder = QtWidgets.QLineEdit(self.tabProtocol) + self.lineEdit_protocol_ml_encoder.setObjectName("lineEdit_protocol_ml_encoder") + self.gridLayout_3.addWidget(self.lineEdit_protocol_ml_encoder, 9, 1, 1, 1) self.comboBox_protocol_method = QtWidgets.QComboBox(self.tabProtocol) self.comboBox_protocol_method.setObjectName("comboBox_protocol_method") self.gridLayout_3.addWidget(self.comboBox_protocol_method, 1, 1, 1, 1) + self.checkBox_supervise_mill_polishing = QtWidgets.QCheckBox(self.tabProtocol) + self.checkBox_supervise_mill_polishing.setObjectName("checkBox_supervise_mill_polishing") + self.gridLayout_3.addWidget(self.checkBox_supervise_mill_polishing, 15, 1, 1, 1) self.tabWidget.addTab(self.tabProtocol, "") self.gridLayout.addWidget(self.tabWidget, 1, 0, 1, 2) self.label_instructions = QtWidgets.QLabel(self.centralwidget) self.label_instructions.setObjectName("label_instructions") self.gridLayout.addWidget(self.label_instructions, 6, 0, 1, 2) - spacerItem3 = QtWidgets.QSpacerItem(20, 244, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.gridLayout.addItem(spacerItem3, 5, 0, 1, 2) + spacerItem2 = QtWidgets.QSpacerItem(20, 244, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.gridLayout.addItem(spacerItem2, 5, 0, 1, 2) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 450, 21)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 470, 21)) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) self.menuFile.setObjectName("menuFile") @@ -267,44 +258,42 @@ def retranslateUi(self, MainWindow): self.label_title.setText(_translate("MainWindow", "AutoLiftout")) self.pushButton_yes.setText(_translate("MainWindow", "Yes")) self.pushButton_no.setText(_translate("MainWindow", "No")) + self.checkBox_current_lamella_landing_selected.setText(_translate("MainWindow", "Landing Selected")) + self.label_lamella_detail.setText(_translate("MainWindow", "TextLabel")) + self.label_lamella_header.setText(_translate("MainWindow", "Lamella")) + self.label_experiment_name.setText(_translate("MainWindow", "Experiment:")) self.label_info.setText(_translate("MainWindow", "No Lamella Selected")) self.pushButton_revert_stage.setText(_translate("MainWindow", "Time Travel To")) - self.label_lamella_header.setText(_translate("MainWindow", "Lamella")) - self.pushButton_setup_autoliftout.setText(_translate("MainWindow", "Setup AutoLiftout")) - self.label_lamella_detail.setText(_translate("MainWindow", "TextLabel")) self.label_protocol_name.setText(_translate("MainWindow", "Protocol: ")) self.pushButton_run_polishing.setText(_translate("MainWindow", "Run AutoLamella")) - self.pushButton_run_autoliftout.setText(_translate("MainWindow", "Run AutoLiftout")) self.label_current_lamella.setText(_translate("MainWindow", "Current Lamella")) - self.label_experiment_name.setText(_translate("MainWindow", "Experiment:")) - self.checkBox_current_lamella_landing_selected.setText(_translate("MainWindow", "Landing Selected")) + self.pushButton_setup_autoliftout.setText(_translate("MainWindow", "Setup AutoLiftout")) + self.pushButton_run_autoliftout.setText(_translate("MainWindow", "Run AutoLiftout")) self.checkBox_current_lamella_failure.setText(_translate("MainWindow", "Failure")) self.pushButton_run_serial_liftout_landing.setText(_translate("MainWindow", "Run Serial Liftout Landing")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.general), _translate("MainWindow", "General")) + self.label_protocol_name_2.setText(_translate("MainWindow", "Name")) + self.label_protocol_method.setText(_translate("MainWindow", "Method")) self.label_options_landing_joining_method.setText(_translate("MainWindow", "Landing Joining Method")) - self.label_options_lamella_start_position.setText(_translate("MainWindow", "Lamella Start Position")) - self.checkBox_options_confirm_next_stage.setText(_translate("MainWindow", "Confirm Next Stage")) - self.label_protocol_ml_checkpoint.setText(_translate("MainWindow", "Checkpoint")) - self.label_options_landing_start_position.setText(_translate("MainWindow", "Landing Start Position")) - self.checkBox_supervise_mill_trench.setText(_translate("MainWindow", "Mill Trench")) - self.label_options_liftout_joining_method.setText(_translate("MainWindow", "Liftout Joining Method")) - self.checkBox_supervise_setup_lamella.setText(_translate("MainWindow", "Setup Lamella")) - self.checkBox_supervise_reset.setText(_translate("MainWindow", "Reset Manipulator")) self.label_protocol_options_header.setText(_translate("MainWindow", "Options")) - self.checkBox_supervise_mill_regular.setText(_translate("MainWindow", "Mill Regular Cut")) - self.pushButton_update_protocol.setText(_translate("MainWindow", "Update Protocol")) + self.label_protocol_ml_header_2.setText(_translate("MainWindow", "Encoder")) self.checkBox_supervise_mill_rough.setText(_translate("MainWindow", "Mill Rough Cut")) - self.checkBox_supervise_mill_polishing.setText(_translate("MainWindow", "Mill Polishing Cut")) - self.label_protocol_ml_num_classes.setText(_translate("MainWindow", "Number of Classes")) - self.label_protocol_name_2.setText(_translate("MainWindow", "Name")) self.checkBox_supervise_landing.setText(_translate("MainWindow", "Land Lamella")) + self.checkBox_supervise_liftout.setText(_translate("MainWindow", "Liftout Lamella")) + self.label_protocol_ml_header.setText(_translate("MainWindow", "Machine Learning")) self.checkBox_options_batch_mode.setText(_translate("MainWindow", "Batch Mode")) + self.label_options_landing_start_position.setText(_translate("MainWindow", "Landing Start Position")) self.checkBox_supervise_mill_undercut.setText(_translate("MainWindow", "Mill Undercut")) + self.label_options_lamella_start_position.setText(_translate("MainWindow", "Lamella Start Position")) self.label_protocol_supervision_header.setText(_translate("MainWindow", "Supervision")) - self.checkBox_supervise_liftout.setText(_translate("MainWindow", "Liftout Lamella")) - self.label_protocol_ml_header.setText(_translate("MainWindow", "Machine Learning")) - self.label_protocol_ml_header_2.setText(_translate("MainWindow", "Encoder")) - self.label_protocol_method.setText(_translate("MainWindow", "Method")) + self.checkBox_supervise_mill_trench.setText(_translate("MainWindow", "Mill Trench")) + self.checkBox_supervise_setup_lamella.setText(_translate("MainWindow", "Setup Lamella")) + self.pushButton_update_protocol.setText(_translate("MainWindow", "Update Protocol")) + self.label_protocol_ml_num_classes.setText(_translate("MainWindow", "Number of Classes")) + self.checkBox_options_confirm_next_stage.setText(_translate("MainWindow", "Confirm Next Stage")) + self.label_options_liftout_joining_method.setText(_translate("MainWindow", "Liftout Joining Method")) + self.label_protocol_ml_checkpoint.setText(_translate("MainWindow", "Checkpoint")) + self.checkBox_supervise_mill_polishing.setText(_translate("MainWindow", "Mill Polishing Cut")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabProtocol), _translate("MainWindow", "Protocol")) self.label_instructions.setText(_translate("MainWindow", "Instructions")) self.menuFile.setTitle(_translate("MainWindow", "File")) diff --git a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui index eace7399..5132ec11 100644 --- a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui +++ b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui @@ -6,8 +6,8 @@ 0 0 - 450 - 819 + 470 + 855 @@ -62,34 +62,17 @@ General - - - - - + + - No Lamella Selected + Landing Selected - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + + - Time Travel To + TextLabel @@ -106,18 +89,27 @@ - - - + + - Setup AutoLiftout + Experiment: - - + + + + + - TextLabel + No Lamella Selected + + + + + + + Time Travel To @@ -135,30 +127,6 @@ - - - - - TextLabel - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - @@ -166,17 +134,20 @@ - - + + + + + - Experiment: + Setup AutoLiftout - - + + - Landing Selected + Run AutoLiftout @@ -187,6 +158,19 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -201,75 +185,30 @@ Protocol - - - - Landing Joining Method - - - - - - - Lamella Start Position - - - - - - - Confirm Next Stage - - - true - - - - - - - Checkpoint - - - - - - - Landing Start Position - - - - - - - - + + - Mill Trench + Name - - - - Liftout Joining Method - - + + - - + + - Setup Lamella + Method - - + + - Reset Manipulator + Landing Joining Method @@ -286,17 +225,10 @@ - - - - Mill Regular Cut - - - - - + + - Update Protocol + Encoder @@ -307,34 +239,39 @@ - - + + - Mill Polishing Cut + Land Lamella - - + + - - + + - Number of Classes + Liftout Lamella - - - - Name - - + + - - + + + + + + + + 75 + true + + - Land Lamella + Machine Learning @@ -348,32 +285,27 @@ - - - - Qt::Vertical + + + + Landing Start Position - - - 20 - 40 - + + + + + + Mill Undercut - + - - - - - - - - + + - Mill Undercut + Lamella Start Position @@ -390,49 +322,87 @@ - - + + - Liftout Lamella + Mill Trench - - - - - 75 - true - + + + + Setup Lamella + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + - Machine Learning + Update Protocol - - + + - Encoder + Number of Classes - - + + + + Confirm Next Stage + + + true + + - - + + - Method + Liftout Joining Method + + + + Checkpoint + + + + + + + + + + Mill Polishing Cut + + + @@ -464,7 +434,7 @@ 0 0 - 450 + 470 21 diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index 02e33638..26e83929 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -422,7 +422,7 @@ def run_serial_liftout_workflow( ) -> Experiment: """Run the serial AutoLiftout workflow for a given experiment. """ BATCH_MODE = bool(settings.protocol["options"]["batch_mode"]) - CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_advance"]) + CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_next_stage"]) _update_status_ui(parent_ui, "Starting AutoLiftout Workflow...") logging.info( @@ -486,7 +486,7 @@ def run_serial_liftout_landing( ) -> Experiment: """Run the serial AutoLiftout workflow for landing a given experiment. """ BATCH_MODE = bool(settings.protocol["options"]["batch_mode"]) - CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_advance"]) + CONFIRM_WORKFLOW_ADVANCE = bool(settings.protocol["options"]["confirm_next_stage"]) _update_status_ui(parent_ui, "Starting Serial Liftout (Landing) Workflow...") logging.info( diff --git a/autolamella/ui/AutoLamellaUI.py b/autolamella/ui/AutoLamellaUI.py index 92223fff..9bf80c4c 100644 --- a/autolamella/ui/AutoLamellaUI.py +++ b/autolamella/ui/AutoLamellaUI.py @@ -227,6 +227,32 @@ def update_protocol_ui(self, _load: bool=True): self.label_protocol_undercut_tilt_angle.setVisible(_WAFFLE_METHOD) self.label_protocol_undercut_tilt_step.setVisible(_WAFFLE_METHOD) + + # autoliftout components + _AUTOLIFTOUT_METHOD = "autoliftout" in method + self.checkBox_options_confirm_next_stage.setVisible(_AUTOLIFTOUT_METHOD) + self.label_options_lamella_start_position.setVisible(_AUTOLIFTOUT_METHOD) + self.label_options_liftout_joining_method.setVisible(_AUTOLIFTOUT_METHOD) + self.label_options_landing_start_position.setVisible(_AUTOLIFTOUT_METHOD) + self.label_options_landing_joining_method.setVisible(_AUTOLIFTOUT_METHOD) + self.comboBox_options_lamella_start_position.setVisible(_AUTOLIFTOUT_METHOD) + self.comboBox_options_liftout_joining_method.setVisible(_AUTOLIFTOUT_METHOD) + self.comboBox_options_landing_start_position.setVisible(_AUTOLIFTOUT_METHOD) + self.comboBox_options_landing_joining_method.setVisible(_AUTOLIFTOUT_METHOD) + self.checkBox_supervise_liftout.setVisible(_AUTOLIFTOUT_METHOD) + self.checkBox_supervise_landing.setVisible(_AUTOLIFTOUT_METHOD) + if _AUTOLIFTOUT_METHOD: + self.checkBox_options_confirm_next_stage.setChecked(self.settings.protocol["options"].get("confirm_next_stage", True)) + self.comboBox_options_liftout_joining_method.setCurrentText(self.settings.protocol["options"].get("liftout_joining_method", "None")) + self.comboBox_options_landing_joining_method.setCurrentText(self.settings.protocol["options"].get("landing_joining_method", "Weld")) + + self.comboBox_options_lamella_start_position.setCurrentText(self.settings.protocol["options"]["lamella_start_position"]) + self.comboBox_options_landing_start_position.setCurrentText(self.settings.protocol["options"]["landing_start_position"]) + + # supervision + self.checkBox_supervise_liftout.setChecked(bool(self.settings.protocol["options"]["supervise"].get("liftout", True))) + self.checkBox_supervise_landing.setChecked(bool(self.settings.protocol["options"]["supervise"].get("landing", True))) + self._UPDATING_PROTOCOL_UI = False def export_protocol_ui(self): @@ -247,12 +273,13 @@ def export_protocol_ui(self): self.settings.protocol["options"]["supervise"]["mill_rough"] = self.checkBox_supervise_mill_rough.isChecked() self.settings.protocol["options"]["supervise"]["mill_polishing"] = self.checkBox_supervise_mill_polishing.isChecked() - # machine learning - if self.settings.protocol["method"] == "autolamella-waffle": + if self.settings.protocol["method"] in ["autolamella-waffle", "autoliftout-default", "autoliftout-serial-liftout"]: + # supervision self.settings.protocol["options"]["supervise"]["trench"] = self.checkBox_trench.isChecked() self.settings.protocol["options"]["supervise"]["undercut"] = self.checkBox_undercut.isChecked() + # machine learning self.settings.protocol["ml"]["checkpoint"] = self.lineEdit_ml_checkpoint.text() self.settings.protocol["ml"]["encoder"] = self.lineEdit_ml_encoder.text() self.settings.protocol["ml"]["num_classes"] = self.spinBox_ml_num_classes.value() @@ -261,6 +288,21 @@ def export_protocol_ui(self): self.settings.protocol["undercut"]["tilt_angle"] = self.doubleSpinBox_undercut_tilt.value() self.settings.protocol["undercut"]["tilt_angle_step"] = int(self.doubleSpinBox_undercut_step.value()) + if self.settings.protocol["method"] in ["autoliftout-default", "autoliftout-serial-liftout"]: + + # supervision + self.settings.protocol["options"]["confirm_next_stage"] = self.checkBox_options_confirm_next_stage.isChecked() + self.settings.protocol["options"]["supervise"]["liftout"] = self.checkBox_supervise_liftout.isChecked() + self.settings.protocol["options"]["supervise"]["landing"] = self.checkBox_supervise_landing.isChecked() + + # joining methods + self.settings.protocol["options"]["liftout_joining_method"] = self.comboBox_options_liftout_joining_method.currentText() + self.settings.protocol["options"]["landing_joining_method"] = self.comboBox_options_landing_joining_method.currentText() + + # start positions + self.settings.protocol["options"]["lamella_start_position"] = self.comboBox_options_lamella_start_position.currentText() + self.settings.protocol["options"]["landing_start_position"] = self.comboBox_options_landing_start_position.currentText() + if self.sender() == self.actionSave_Protocol: path = fui._get_save_file_ui(msg='Save protocol', path = cfg.PROTOCOL_PATH, diff --git a/autolamella/ui/qt/AutoLamellaUI.py b/autolamella/ui/qt/AutoLamellaUI.py index 033c7ba7..1ab80f75 100644 --- a/autolamella/ui/qt/AutoLamellaUI.py +++ b/autolamella/ui/qt/AutoLamellaUI.py @@ -24,14 +24,14 @@ def setupUi(self, MainWindow): self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") - self.label_instructions = QtWidgets.QLabel(self.centralwidget) - self.label_instructions.setObjectName("label_instructions") - self.gridLayout.addWidget(self.label_instructions, 3, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.gridLayout.addItem(spacerItem, 2, 0, 1, 2) self.pushButton_yes = QtWidgets.QPushButton(self.centralwidget) self.pushButton_yes.setObjectName("pushButton_yes") self.gridLayout.addWidget(self.pushButton_yes, 4, 0, 1, 1) + self.label_instructions = QtWidgets.QLabel(self.centralwidget) + self.label_instructions.setObjectName("label_instructions") + self.gridLayout.addWidget(self.label_instructions, 3, 0, 1, 1) self.pushButton_stop_workflow_thread = QtWidgets.QPushButton(self.centralwidget) self.pushButton_stop_workflow_thread.setObjectName("pushButton_stop_workflow_thread") self.gridLayout.addWidget(self.pushButton_stop_workflow_thread, 1, 0, 1, 2) @@ -288,6 +288,11 @@ def setupUi(self, MainWindow): self.label_protocol_name_2.setObjectName("label_protocol_name_2") self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_protocol_name_2) self.lineEdit_name = QtWidgets.QLineEdit(self.tab_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_name.sizePolicy().hasHeightForWidth()) + self.lineEdit_name.setSizePolicy(sizePolicy) self.lineEdit_name.setObjectName("lineEdit_name") self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.lineEdit_name) self.label_protocol_method = QtWidgets.QLabel(self.tab_2) @@ -305,20 +310,39 @@ def setupUi(self, MainWindow): self.formLayout_2.setWidget(4, QtWidgets.QFormLayout.SpanningRole, self.label_options_header) self.label_protocol_undercut_tilt_angle = QtWidgets.QLabel(self.tab_2) self.label_protocol_undercut_tilt_angle.setObjectName("label_protocol_undercut_tilt_angle") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_angle) + self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_angle) self.doubleSpinBox_undercut_tilt = QtWidgets.QDoubleSpinBox(self.tab_2) self.doubleSpinBox_undercut_tilt.setMinimum(-180.0) self.doubleSpinBox_undercut_tilt.setMaximum(180.0) self.doubleSpinBox_undercut_tilt.setObjectName("doubleSpinBox_undercut_tilt") - self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_tilt) + self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_tilt) self.label_protocol_undercut_tilt_step = QtWidgets.QLabel(self.tab_2) self.label_protocol_undercut_tilt_step.setObjectName("label_protocol_undercut_tilt_step") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_step) - self.doubleSpinBox_undercut_step = QtWidgets.QDoubleSpinBox(self.tab_2) - self.doubleSpinBox_undercut_step.setMinimum(-180.0) - self.doubleSpinBox_undercut_step.setMaximum(180.0) - self.doubleSpinBox_undercut_step.setObjectName("doubleSpinBox_undercut_step") - self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_step) + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_protocol_undercut_tilt_step) + self.label_options_lamella_start_position = QtWidgets.QLabel(self.tab_2) + self.label_options_lamella_start_position.setObjectName("label_options_lamella_start_position") + self.formLayout_2.setWidget(13, QtWidgets.QFormLayout.LabelRole, self.label_options_lamella_start_position) + self.comboBox_options_lamella_start_position = QtWidgets.QComboBox(self.tab_2) + self.comboBox_options_lamella_start_position.setObjectName("comboBox_options_lamella_start_position") + self.formLayout_2.setWidget(13, QtWidgets.QFormLayout.FieldRole, self.comboBox_options_lamella_start_position) + self.label_options_liftout_joining_method = QtWidgets.QLabel(self.tab_2) + self.label_options_liftout_joining_method.setObjectName("label_options_liftout_joining_method") + self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.LabelRole, self.label_options_liftout_joining_method) + self.comboBox_options_liftout_joining_method = QtWidgets.QComboBox(self.tab_2) + self.comboBox_options_liftout_joining_method.setObjectName("comboBox_options_liftout_joining_method") + self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.FieldRole, self.comboBox_options_liftout_joining_method) + self.label_options_landing_start_position = QtWidgets.QLabel(self.tab_2) + self.label_options_landing_start_position.setObjectName("label_options_landing_start_position") + self.formLayout_2.setWidget(17, QtWidgets.QFormLayout.LabelRole, self.label_options_landing_start_position) + self.comboBox_options_landing_start_position = QtWidgets.QComboBox(self.tab_2) + self.comboBox_options_landing_start_position.setObjectName("comboBox_options_landing_start_position") + self.formLayout_2.setWidget(17, QtWidgets.QFormLayout.FieldRole, self.comboBox_options_landing_start_position) + self.label_options_landing_joining_method = QtWidgets.QLabel(self.tab_2) + self.label_options_landing_joining_method.setObjectName("label_options_landing_joining_method") + self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.LabelRole, self.label_options_landing_joining_method) + self.comboBox_options_landing_joining_method = QtWidgets.QComboBox(self.tab_2) + self.comboBox_options_landing_joining_method.setObjectName("comboBox_options_landing_joining_method") + self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.FieldRole, self.comboBox_options_landing_joining_method) self.label_alignment_header = QtWidgets.QLabel(self.tab_2) font = QtGui.QFont() font.setBold(True) @@ -326,77 +350,103 @@ def setupUi(self, MainWindow): font.setWeight(75) self.label_alignment_header.setFont(font) self.label_alignment_header.setObjectName("label_alignment_header") - self.formLayout_2.setWidget(11, QtWidgets.QFormLayout.SpanningRole, self.label_alignment_header) + self.formLayout_2.setWidget(23, QtWidgets.QFormLayout.SpanningRole, self.label_alignment_header) + self.checkBox_align_at_milling_current = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_align_at_milling_current.setObjectName("checkBox_align_at_milling_current") + self.formLayout_2.setWidget(26, QtWidgets.QFormLayout.FieldRole, self.checkBox_align_at_milling_current) self.beamShiftAttemptsLabel = QtWidgets.QLabel(self.tab_2) self.beamShiftAttemptsLabel.setObjectName("beamShiftAttemptsLabel") - self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.LabelRole, self.beamShiftAttemptsLabel) + self.formLayout_2.setWidget(27, QtWidgets.QFormLayout.LabelRole, self.beamShiftAttemptsLabel) self.beamshift_attempts = QtWidgets.QDoubleSpinBox(self.tab_2) self.beamshift_attempts.setObjectName("beamshift_attempts") - self.formLayout_2.setWidget(15, QtWidgets.QFormLayout.FieldRole, self.beamshift_attempts) + self.formLayout_2.setWidget(27, QtWidgets.QFormLayout.FieldRole, self.beamshift_attempts) self.label_ml_header = QtWidgets.QLabel(self.tab_2) font = QtGui.QFont() font.setBold(True) font.setWeight(75) self.label_ml_header.setFont(font) self.label_ml_header.setObjectName("label_ml_header") - self.formLayout_2.setWidget(17, QtWidgets.QFormLayout.SpanningRole, self.label_ml_header) + self.formLayout_2.setWidget(29, QtWidgets.QFormLayout.SpanningRole, self.label_ml_header) self.label_ml_checkpoint = QtWidgets.QLabel(self.tab_2) self.label_ml_checkpoint.setObjectName("label_ml_checkpoint") - self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.LabelRole, self.label_ml_checkpoint) + self.formLayout_2.setWidget(30, QtWidgets.QFormLayout.LabelRole, self.label_ml_checkpoint) self.lineEdit_ml_checkpoint = QtWidgets.QLineEdit(self.tab_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_ml_checkpoint.sizePolicy().hasHeightForWidth()) + self.lineEdit_ml_checkpoint.setSizePolicy(sizePolicy) self.lineEdit_ml_checkpoint.setObjectName("lineEdit_ml_checkpoint") - self.formLayout_2.setWidget(18, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_checkpoint) + self.formLayout_2.setWidget(30, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_checkpoint) self.label_ml_encoder = QtWidgets.QLabel(self.tab_2) self.label_ml_encoder.setObjectName("label_ml_encoder") - self.formLayout_2.setWidget(19, QtWidgets.QFormLayout.LabelRole, self.label_ml_encoder) + self.formLayout_2.setWidget(31, QtWidgets.QFormLayout.LabelRole, self.label_ml_encoder) self.lineEdit_ml_encoder = QtWidgets.QLineEdit(self.tab_2) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.lineEdit_ml_encoder.sizePolicy().hasHeightForWidth()) + self.lineEdit_ml_encoder.setSizePolicy(sizePolicy) self.lineEdit_ml_encoder.setObjectName("lineEdit_ml_encoder") - self.formLayout_2.setWidget(19, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_encoder) + self.formLayout_2.setWidget(31, QtWidgets.QFormLayout.FieldRole, self.lineEdit_ml_encoder) + self.label_ml_num_classes = QtWidgets.QLabel(self.tab_2) + self.label_ml_num_classes.setObjectName("label_ml_num_classes") + self.formLayout_2.setWidget(32, QtWidgets.QFormLayout.LabelRole, self.label_ml_num_classes) + self.spinBox_ml_num_classes = QtWidgets.QSpinBox(self.tab_2) + self.spinBox_ml_num_classes.setObjectName("spinBox_ml_num_classes") + self.formLayout_2.setWidget(32, QtWidgets.QFormLayout.FieldRole, self.spinBox_ml_num_classes) self.label_supervise_header = QtWidgets.QLabel(self.tab_2) font = QtGui.QFont() font.setBold(True) font.setWeight(75) self.label_supervise_header.setFont(font) self.label_supervise_header.setObjectName("label_supervise_header") - self.formLayout_2.setWidget(21, QtWidgets.QFormLayout.SpanningRole, self.label_supervise_header) + self.formLayout_2.setWidget(33, QtWidgets.QFormLayout.SpanningRole, self.label_supervise_header) self.checkBox_trench = QtWidgets.QCheckBox(self.tab_2) self.checkBox_trench.setObjectName("checkBox_trench") - self.formLayout_2.setWidget(22, QtWidgets.QFormLayout.LabelRole, self.checkBox_trench) + self.formLayout_2.setWidget(34, QtWidgets.QFormLayout.LabelRole, self.checkBox_trench) self.checkBox_setup = QtWidgets.QCheckBox(self.tab_2) self.checkBox_setup.setObjectName("checkBox_setup") - self.formLayout_2.setWidget(22, QtWidgets.QFormLayout.FieldRole, self.checkBox_setup) + self.formLayout_2.setWidget(34, QtWidgets.QFormLayout.FieldRole, self.checkBox_setup) self.checkBox_undercut = QtWidgets.QCheckBox(self.tab_2) self.checkBox_undercut.setObjectName("checkBox_undercut") - self.formLayout_2.setWidget(23, QtWidgets.QFormLayout.LabelRole, self.checkBox_undercut) + self.formLayout_2.setWidget(35, QtWidgets.QFormLayout.LabelRole, self.checkBox_undercut) + self.checkBox_supervise_mill_rough = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_supervise_mill_rough.setObjectName("checkBox_supervise_mill_rough") + self.formLayout_2.setWidget(35, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_rough) + self.checkBox_supervise_liftout = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_supervise_liftout.setEnabled(True) + self.checkBox_supervise_liftout.setObjectName("checkBox_supervise_liftout") + self.formLayout_2.setWidget(36, QtWidgets.QFormLayout.LabelRole, self.checkBox_supervise_liftout) self.checkBox_supervise_mill_polishing = QtWidgets.QCheckBox(self.tab_2) self.checkBox_supervise_mill_polishing.setObjectName("checkBox_supervise_mill_polishing") - self.formLayout_2.setWidget(24, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_polishing) + self.formLayout_2.setWidget(36, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_polishing) + self.checkBox_supervise_landing = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_supervise_landing.setEnabled(True) + self.checkBox_supervise_landing.setObjectName("checkBox_supervise_landing") + self.formLayout_2.setWidget(37, QtWidgets.QFormLayout.LabelRole, self.checkBox_supervise_landing) self.pushButton_update_protocol = QtWidgets.QPushButton(self.tab_2) self.pushButton_update_protocol.setObjectName("pushButton_update_protocol") - self.formLayout_2.setWidget(28, QtWidgets.QFormLayout.SpanningRole, self.pushButton_update_protocol) - self.checkBox_supervise_mill_rough = QtWidgets.QCheckBox(self.tab_2) - self.checkBox_supervise_mill_rough.setObjectName("checkBox_supervise_mill_rough") - self.formLayout_2.setWidget(23, QtWidgets.QFormLayout.FieldRole, self.checkBox_supervise_mill_rough) + self.formLayout_2.setWidget(40, QtWidgets.QFormLayout.SpanningRole, self.pushButton_update_protocol) + self.doubleSpinBox_undercut_step = QtWidgets.QDoubleSpinBox(self.tab_2) + self.doubleSpinBox_undercut_step.setMinimum(-180.0) + self.doubleSpinBox_undercut_step.setMaximum(180.0) + self.doubleSpinBox_undercut_step.setObjectName("doubleSpinBox_undercut_step") + self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_undercut_step) self.checkBox_take_final_reference_images = QtWidgets.QCheckBox(self.tab_2) self.checkBox_take_final_reference_images.setObjectName("checkBox_take_final_reference_images") - self.formLayout_2.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.checkBox_take_final_reference_images) + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.checkBox_take_final_reference_images) self.checkBox_take_final_high_quality_reference = QtWidgets.QCheckBox(self.tab_2) self.checkBox_take_final_high_quality_reference.setObjectName("checkBox_take_final_high_quality_reference") - self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.checkBox_take_final_high_quality_reference) - self.checkBox_align_at_milling_current = QtWidgets.QCheckBox(self.tab_2) - self.checkBox_align_at_milling_current.setObjectName("checkBox_align_at_milling_current") - self.formLayout_2.setWidget(14, QtWidgets.QFormLayout.FieldRole, self.checkBox_align_at_milling_current) - self.label_ml_num_classes = QtWidgets.QLabel(self.tab_2) - self.label_ml_num_classes.setObjectName("label_ml_num_classes") - self.formLayout_2.setWidget(20, QtWidgets.QFormLayout.LabelRole, self.label_ml_num_classes) - self.spinBox_ml_num_classes = QtWidgets.QSpinBox(self.tab_2) - self.spinBox_ml_num_classes.setObjectName("spinBox_ml_num_classes") - self.formLayout_2.setWidget(20, QtWidgets.QFormLayout.FieldRole, self.spinBox_ml_num_classes) + self.formLayout_2.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.checkBox_take_final_high_quality_reference) + self.checkBox_options_confirm_next_stage = QtWidgets.QCheckBox(self.tab_2) + self.checkBox_options_confirm_next_stage.setObjectName("checkBox_options_confirm_next_stage") + self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.checkBox_options_confirm_next_stage) self.tabWidget.addTab(self.tab_2, "") self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 2) MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 521, 20)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 521, 21)) self.menubar.setObjectName("menubar") self.menuAutoLamella = QtWidgets.QMenu(self.menubar) self.menuAutoLamella.setObjectName("menuAutoLamella") @@ -436,14 +486,14 @@ def setupUi(self, MainWindow): self.menubar.addAction(self.menuTools.menuAction()) self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(1) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.label_instructions.setText(_translate("MainWindow", "Instructions")) self.pushButton_yes.setText(_translate("MainWindow", "Yes")) + self.label_instructions.setText(_translate("MainWindow", "Instructions")) self.pushButton_stop_workflow_thread.setText(_translate("MainWindow", "Stop Workflow")) self.pushButton_no.setText(_translate("MainWindow", "No")) self.pushButton_run_autolamella.setText(_translate("MainWindow", "Run AutoLamella")) @@ -469,22 +519,29 @@ def retranslateUi(self, MainWindow): self.label_options_header.setText(_translate("MainWindow", "Options")) self.label_protocol_undercut_tilt_angle.setText(_translate("MainWindow", "Undercut Tilt Angle")) self.label_protocol_undercut_tilt_step.setText(_translate("MainWindow", "Undercut Tilt Steps")) + self.label_options_lamella_start_position.setText(_translate("MainWindow", "Lamella Start Position")) + self.label_options_liftout_joining_method.setText(_translate("MainWindow", "Liftout Joining Method")) + self.label_options_landing_start_position.setText(_translate("MainWindow", "Landing Start Position")) + self.label_options_landing_joining_method.setText(_translate("MainWindow", "Landing Joining Method")) self.label_alignment_header.setText(_translate("MainWindow", "Alignment")) + self.checkBox_align_at_milling_current.setText(_translate("MainWindow", "Align at Milling Current")) self.beamShiftAttemptsLabel.setText(_translate("MainWindow", "Align attempts")) self.label_ml_header.setText(_translate("MainWindow", "Machine Learning")) self.label_ml_checkpoint.setText(_translate("MainWindow", "Checkpoint")) self.label_ml_encoder.setText(_translate("MainWindow", "Encoder")) + self.label_ml_num_classes.setText(_translate("MainWindow", "Num Classes")) self.label_supervise_header.setText(_translate("MainWindow", "Supervision")) self.checkBox_trench.setText(_translate("MainWindow", "Trench Stage")) self.checkBox_setup.setText(_translate("MainWindow", "Setup Stage")) self.checkBox_undercut.setText(_translate("MainWindow", "Undercut Stage")) + self.checkBox_supervise_mill_rough.setText(_translate("MainWindow", "Mill Rough Stage")) + self.checkBox_supervise_liftout.setText(_translate("MainWindow", "Liftout Lamella")) self.checkBox_supervise_mill_polishing.setText(_translate("MainWindow", "Mill Polishing Stage")) + self.checkBox_supervise_landing.setText(_translate("MainWindow", "Land Lamella")) self.pushButton_update_protocol.setText(_translate("MainWindow", "Update Protocol")) - self.checkBox_supervise_mill_rough.setText(_translate("MainWindow", "Mill Rough Stage")) self.checkBox_take_final_reference_images.setText(_translate("MainWindow", "Take Final Reference Images")) self.checkBox_take_final_high_quality_reference.setText(_translate("MainWindow", "Take Final High Quality Reference Image")) - self.checkBox_align_at_milling_current.setText(_translate("MainWindow", "Align at Milling Current")) - self.label_ml_num_classes.setText(_translate("MainWindow", "Num Classes")) + self.checkBox_options_confirm_next_stage.setText(_translate("MainWindow", "Confirm Next Stage")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Protocol")) self.menuAutoLamella.setTitle(_translate("MainWindow", "File")) self.menuTools.setTitle(_translate("MainWindow", "Tools")) diff --git a/autolamella/ui/qt/AutoLamellaUI.ui b/autolamella/ui/qt/AutoLamellaUI.ui index 8a5ee2cc..4d5e20b6 100644 --- a/autolamella/ui/qt/AutoLamellaUI.ui +++ b/autolamella/ui/qt/AutoLamellaUI.ui @@ -33,13 +33,6 @@ - - - - Instructions - - - @@ -60,6 +53,13 @@ + + + + Instructions + + + @@ -77,7 +77,7 @@ - 0 + 1 @@ -736,7 +736,14 @@ - + + + + 0 + 0 + + + @@ -761,14 +768,14 @@ - + Undercut Tilt Angle - + -180.000000000000000 @@ -778,24 +785,54 @@ - + Undercut Tilt Steps - - - - -180.000000000000000 + + + + Lamella Start Position - - 180.000000000000000 + + + + + + + + + Liftout Joining Method + + + + + + + + + + Landing Start Position + + + + + + + + + + Landing Joining Method - + + + + @@ -809,17 +846,24 @@ - + + + + Align at Milling Current + + + + Align attempts - + - + @@ -832,27 +876,51 @@ - + Checkpoint - - + + + + + 0 + 0 + + + - + Encoder - - + + + + + 0 + 0 + + + + + + + + Num Classes + + + + + - + @@ -865,79 +933,99 @@ - + Trench Stage - + Setup Stage - + Undercut Stage - + + + + Mill Rough Stage + + + + + + + true + + + Liftout Lamella + + + + Mill Polishing Stage - - + + + + true + - Update Protocol + Land Lamella - - + + - Mill Rough Stage + Update Protocol + + + -180.000000000000000 + + + 180.000000000000000 + + + + Take Final Reference Images - + Take Final High Quality Reference Image - - - - Align at Milling Current - - - - - + + - Num Classes + Confirm Next Stage - - - @@ -950,7 +1038,7 @@ 0 0 521 - 20 + 21 From b5341bbfec1d27ed0cb45e0ad7d5975b9b0f3d3d Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 20:05:05 +1100 Subject: [PATCH 26/39] update protocols --- autolamella/liftout/protocol/protocol-base.yaml | 2 +- autolamella/liftout/protocol/protocol-serial-liftout.yaml | 2 +- autolamella/protocol/protocol-waffle.yaml | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/autolamella/liftout/protocol/protocol-base.yaml b/autolamella/liftout/protocol/protocol-base.yaml index 13022636..f6c351c2 100644 --- a/autolamella/liftout/protocol/protocol-base.yaml +++ b/autolamella/liftout/protocol/protocol-base.yaml @@ -47,7 +47,7 @@ name: autoliftout-base-protocol method: autoliftout-default options: batch_mode: true - confirm_advance: true + confirm_next_stage: true lamella_start_position: autoliftout-pre-tilt-35-deg-grid-01-lamella liftout_joining_method: None liftout_contact_detection: True diff --git a/autolamella/liftout/protocol/protocol-serial-liftout.yaml b/autolamella/liftout/protocol/protocol-serial-liftout.yaml index 1ff0c6ee..181dc239 100644 --- a/autolamella/liftout/protocol/protocol-serial-liftout.yaml +++ b/autolamella/liftout/protocol/protocol-serial-liftout.yaml @@ -32,7 +32,7 @@ name: autoliftout-serial-protocol method: autoliftout-serial-liftout options: batch_mode: true - confirm_advance: true + confirm_next_stage: true complete_undercut: False lamella_start_position: autoliftout-serial-pre-tilt-35-deg-grid-01-lamella landing_start_position: autoliftout-serial-pre-tilt-35-deg-grid-02-landing diff --git a/autolamella/protocol/protocol-waffle.yaml b/autolamella/protocol/protocol-waffle.yaml index 274d7e7d..2ecf2c84 100644 --- a/autolamella/protocol/protocol-waffle.yaml +++ b/autolamella/protocol/protocol-waffle.yaml @@ -91,12 +91,10 @@ options: compucentric_x_offset: 0.0e-6 compucentric_y_offset: 0.0e-6 supervise: - features: true setup_lamella: true trench: true undercut: true mill_rough: true - mill_regular: true mill_polishing: true trench: application_file: autolamella From cb4463d11227a0359690dafaeb61d41672ad9f2f Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 21:02:40 +1100 Subject: [PATCH 27/39] migrate to single enum --- autolamella/waffle.py | 4 ++-- autolamella/workflows/core.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/autolamella/waffle.py b/autolamella/waffle.py index e7cd3df1..0f0a063c 100644 --- a/autolamella/waffle.py +++ b/autolamella/waffle.py @@ -29,7 +29,7 @@ def run_trench_milling( lamella = start_of_stage_update( microscope, lamella, - AutoLamellaWaffleStage(lamella.state.stage.value + 1), + AutoLamellaWaffleStage.MillTrench, parent_ui=parent_ui ) @@ -84,7 +84,7 @@ def run_setup_lamella( lamella = start_of_stage_update( microscope, lamella, - AutoLamellaWaffleStage(lamella.state.stage.value + 1), + AutoLamellaWaffleStage.ReadyLamella, parent_ui=parent_ui ) diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index 9500b061..bb214db6 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -494,10 +494,10 @@ def setup_lamella( lamella.protocol["lamella"]["point"] = stages[0].pattern.point.__to_dict__() # # TODO: integrate this style -# # lamella.protocol[AutoLiftoutStage.MillRoughCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[0])) -# # lamella.protocol[AutoLiftoutStage.MillRoughCut.name]["point"] = stages[0].pattern.point.__to_dict__() -# # lamella.protocol[AutoLiftoutStage.MillPolishingCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[2])) -# # lamella.protocol[AutoLiftoutStage.MillPolishingCut.name]["point"] = stages[2].pattern.point.__to_dict__() +# # lamella.protocol[AutoLamellaWaffleStage.MillRoughCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[0])) +# # lamella.protocol[AutoLamellaWaffleStage.MillRoughCut.name]["point"] = stages[0].pattern.point.__to_dict__() +# # lamella.protocol[AutoLamellaWaffleStage.MillPolishingCut.name] = deepcopy(patterning._get_protocol_from_stages(stages[2])) +# # lamella.protocol[AutoLamellaWaffleStage.MillPolishingCut.name]["point"] = stages[2].pattern.point.__to_dict__() # feature if "autolamella" in method: From c53558615d99bd26940b0ad4c5425cb2b218b4db Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Sun, 8 Oct 2023 21:41:19 +1100 Subject: [PATCH 28/39] depreciate AutoLiftoutStage --- autolamella/liftout/autoliftout.py | 67 ++++++++++++++--------- autolamella/liftout/structures.py | 23 ++------ autolamella/liftout/ui/AutoLiftoutUIv2.py | 18 +++--- autolamella/liftout/ui/utils.py | 4 +- autolamella/liftout/workflows/serial.py | 36 ++++++------ autolamella/structures.py | 12 ++-- autolamella/workflows/core.py | 10 ++++ 7 files changed, 94 insertions(+), 76 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index caebe4cf..596960e4 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -41,7 +41,7 @@ from fibsem.ui import windows as fibsem_ui_windows from autolamella.liftout import actions -from autolamella.liftout.structures import AutoLiftoutStage, Experiment, Lamella +from autolamella.liftout.structures import AutoLamellaWaffleStage, Experiment, Lamella from autolamella.liftout.ui.AutoLiftoutUIv2 import AutoLiftoutUIv2 from fibsem import config as fcfg @@ -208,7 +208,7 @@ def land_needle_on_milled_lamella( settings: MicroscopeSettings, lamella: Lamella, validate: bool, - parent_ui: AutoLiftoutStage, + parent_ui: AutoLamellaWaffleStage, ) -> Lamella: # bookkeeping settings.image.save_path = lamella.path @@ -815,24 +815,25 @@ def run_setup_autoliftout( experiment: Experiment, parent_ui: AutoLiftoutUIv2, ) -> Experiment: - logging.info(f"INIT | {AutoLiftoutStage.Setup.name} | STARTED") + logging.info(f"INIT | {AutoLamellaWaffleStage.SetupTrench.name} | STARTED") # select the lamella and landing positions experiment = select_lamella_positions(microscope, settings, experiment, parent_ui) return experiment -from autolamella.workflows.core import mill_trench, mill_undercut, mill_lamella, setup_lamella +from autolamella.workflows.core import mill_trench, mill_undercut, mill_lamella, setup_lamella, pass_through_stage # autoliftout_workflow WORKFLOW_STAGES = { - AutoLiftoutStage.Setup: run_setup_autoliftout, # TODO: split this further - AutoLiftoutStage.MillTrench: mill_trench, - AutoLiftoutStage.MillUndercut: mill_undercut, - AutoLiftoutStage.Liftout: liftout_lamella, - AutoLiftoutStage.Landing: land_lamella, - AutoLiftoutStage.SetupLamella: setup_lamella, - AutoLiftoutStage.MillRoughCut: mill_lamella, - AutoLiftoutStage.MillPolishingCut: mill_lamella, + AutoLamellaWaffleStage.SetupTrench: run_setup_autoliftout, # TODO: split this further + AutoLamellaWaffleStage.MillTrench: mill_trench, + AutoLamellaWaffleStage.MillUndercut: mill_undercut, + AutoLamellaWaffleStage.LiftoutLamella: liftout_lamella, + AutoLamellaWaffleStage.LandLamella: land_lamella, + AutoLamellaWaffleStage.SetupLamella: setup_lamella, + AutoLamellaWaffleStage.ReadyLamella: pass_through_stage, + AutoLamellaWaffleStage.MillRoughCut: mill_lamella, + AutoLamellaWaffleStage.MillPolishingCut: mill_lamella, } def run_autoliftout_workflow( @@ -856,8 +857,8 @@ def run_autoliftout_workflow( # batch mode workflow if True: for terminal_stage in [ - AutoLiftoutStage.MillTrench, - AutoLiftoutStage.MillUndercut, # TODO: maybe add this to config? + AutoLamellaWaffleStage.MillTrench, + AutoLamellaWaffleStage.MillUndercut, # TODO: maybe add this to config? ]: lamella: Lamella for lamella in experiment.positions: @@ -865,7 +866,7 @@ def run_autoliftout_workflow( continue # skip failures while lamella.state.stage.value < terminal_stage.value: - next_stage = AutoLiftoutStage(lamella.state.stage.value + 1) + next_stage = AutoLamellaWaffleStage(lamella.state.stage.value + 1) # update image settings (save in correct directory) settings.image.save_path = lamella.path @@ -894,9 +895,9 @@ def run_autoliftout_workflow( if lamella.is_failure: continue # skip failures - while lamella.state.stage.value < AutoLiftoutStage.Landing.value: + while lamella.state.stage.value < AutoLamellaWaffleStage.LandLamella.value: - next_stage = AutoLiftoutStage(lamella.state.stage.value + 1) + next_stage = AutoLamellaWaffleStage(lamella.state.stage.value + 1) if CONFIRM_WORKFLOW_ADVANCE: msg = ( f"""Continue Lamella {(lamella._petname)} from {next_stage.name}?""" @@ -933,6 +934,7 @@ def run_autoliftout_workflow( return experiment +# TODO: separate the _run_setup_lamella_workflow so we dont have to do sily passthrough step def run_thinning_workflow( microscope: FibsemMicroscope, settings: MicroscopeSettings, @@ -943,25 +945,32 @@ def run_thinning_workflow( _update_status_ui(parent_ui, "Starting MillRoughCut Workflow...") lamella: Lamella for next_stage in [ - AutoLiftoutStage.SetupLamella, - AutoLiftoutStage.MillRoughCut, - AutoLiftoutStage.MillPolishingCut, + AutoLamellaWaffleStage.SetupLamella, + AutoLamellaWaffleStage.ReadyLamella, + AutoLamellaWaffleStage.MillRoughCut, + AutoLamellaWaffleStage.MillPolishingCut, ]: for lamella in experiment.positions: if lamella.is_failure: continue if lamella.state.stage.value == next_stage.value - 1: + + _restore_state = next_stage != AutoLamellaWaffleStage.ReadyLamella + _save_state = next_stage != AutoLamellaWaffleStage.ReadyLamella + lamella = start_of_stage_update( - microscope, lamella, next_stage=next_stage, parent_ui=parent_ui + microscope, lamella, next_stage=next_stage, parent_ui=parent_ui, + _restore_state=_restore_state ) WORKFLOW_STAGES[next_stage](microscope, settings, lamella,parent_ui) - experiment = end_of_stage_update(microscope, experiment, lamella, parent_ui) + experiment = end_of_stage_update(microscope, experiment, lamella, parent_ui, + _save_state=_save_state) # finish the experiment for lamella in experiment.positions: - if lamella.state.stage == AutoLiftoutStage.MillPolishingCut: - lamella = start_of_stage_update(microscope, lamella, next_stage=AutoLiftoutStage.Finished, parent_ui=parent_ui, _restore_state=False) + if lamella.state.stage == AutoLamellaWaffleStage.MillPolishingCut: + lamella = start_of_stage_update(microscope, lamella, next_stage=AutoLamellaWaffleStage.Finished, parent_ui=parent_ui, _restore_state=False) experiment = end_of_stage_update(microscope, experiment, lamella, parent_ui, _save_state=False) @@ -1181,11 +1190,17 @@ def finish_setup_autoliftout( parent_ui._set_instructions(msg="Ready for AutoLiftout", pos=None, neg=None) for lamella in experiment.positions: - if lamella.state.stage == AutoLiftoutStage.Setup: + if lamella.state.stage == AutoLamellaWaffleStage.SetupTrench: experiment = end_of_stage_update(microscope, experiment, lamella, parent_ui, _save_state=False) + # administrative details + lamella = start_of_stage_update(microscope, lamella, next_stage=AutoLamellaWaffleStage.ReadyTrench, parent_ui=parent_ui, _restore_state=False) + experiment = end_of_stage_update(microscope, experiment, lamella, parent_ui, _save_state=False) + + + logging.info(f"Selected {len(experiment.positions)} lamella for autoliftout.") - logging.info(f"INIT | {AutoLiftoutStage.Setup.name} | FINISHED") + logging.info(f"INIT | {AutoLamellaWaffleStage.SetupTrench.name} | FINISHED") diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index 930cf6c7..32112d68 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -14,19 +14,8 @@ ReferenceImages, Point) from autolamella.liftout.config import config as cfg - - -class AutoLiftoutStage(Enum): - Setup = auto() - MillTrench = auto() - MillUndercut = auto() - Liftout = auto() - Landing = auto() - SetupLamella = auto() - MillRoughCut = auto() - MillPolishingCut = auto() - Finished = auto() - +from autolamella.structures import AutoLamellaWaffleStage + class Experiment: def __init__(self, path: Path = None, name: str = cfg.EXPERIMENT_NAME, program: str = "AutoLiftout", method: str = "AutoLiftout") -> None: @@ -214,7 +203,7 @@ def __to_dict__(self): state_dict = { "id": str(self._id), "petname": self._petname, - "number": self._number, + "_number": self._number, "base_path": self.base_path, "path": self.path, "landing_selected": self.landing_selected, @@ -286,7 +275,7 @@ def get_reference_images(self, label: str) -> ReferenceImages: @dataclass class AutoLiftoutState(FibsemState): - stage: AutoLiftoutStage = AutoLiftoutStage.Setup + stage: AutoLamellaWaffleStage = AutoLamellaWaffleStage.SetupTrench microscope_state: MicroscopeState = MicroscopeState() start_timestamp: float = datetime.timestamp(datetime.now()) end_timestamp: float = None @@ -306,7 +295,7 @@ def __to_dict__(self) -> dict: def __from_dict__(self, state_dict: dict) -> 'AutoLiftoutState': autoliftout_state = AutoLiftoutState( - stage=AutoLiftoutStage[state_dict["stage"]], + stage=AutoLamellaWaffleStage[state_dict["stage"]], microscope_state=MicroscopeState.__from_dict__(state_dict["microscope_state"]), start_timestamp=state_dict["start_timestamp"], end_timestamp=state_dict["end_timestamp"], @@ -329,7 +318,7 @@ def __from_dict__(self, state_dict: dict) -> 'AutoLiftoutState': # lamella_ref_images: ReferenceImages # landing_ref_images: ReferenceImages # state: AutoLiftoutState -# stage: AutoLiftoutStage +# stage: AutoLamellaWaffleStage # microscope_state: MicroscopeState # eb_settings: BeamSettings # ib_settings: BeamSettings diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index d5917edb..e5a52de5 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -21,7 +21,7 @@ from PyQt5.QtCore import pyqtSignal from autolamella.liftout.config import config as cfg -from autolamella.liftout.structures import AutoLiftoutStage, Experiment, Lamella +from autolamella.liftout.structures import AutoLamellaWaffleStage, Experiment, Lamella from autolamella.liftout.ui import utils as ui_utils from autolamella.liftout.ui.qt import AutoLiftoutUIv2 @@ -169,14 +169,14 @@ def update_ui(self): _AUTOLAMELLA_PROGRESS = False if self.experiment is not None: _counter = Counter([p.state.stage.name for p in self.experiment.positions]) - _LAMELLA_SETUP = _counter[AutoLiftoutStage.Setup.name] > 0 - _LAMELLA_TRENCH = _counter[AutoLiftoutStage.MillTrench.name] > 0 - _LAMELLA_UNDERCUT = _counter[AutoLiftoutStage.MillUndercut.name] > 0 - _LIFTOUT_FINISHED = _counter[AutoLiftoutStage.Liftout.name] > 0 - _LAMELLA_LANDED = _counter[AutoLiftoutStage.Landing.name] > 0 - _AUTOLAMELLA_PROGRESS = (_counter[AutoLiftoutStage.SetupLamella.name]>0 - or _counter[AutoLiftoutStage.MillRoughCut.name] > 0 - or _counter[AutoLiftoutStage.MillPolishingCut.name] > 0) + _LAMELLA_SETUP = _counter[AutoLamellaWaffleStage.ReadyTrench.name] > 0 + _LAMELLA_TRENCH = _counter[AutoLamellaWaffleStage.MillTrench.name] > 0 + _LAMELLA_UNDERCUT = _counter[AutoLamellaWaffleStage.MillUndercut.name] > 0 + _LIFTOUT_FINISHED = _counter[AutoLamellaWaffleStage.LiftoutLamella.name] > 0 + _LAMELLA_LANDED = _counter[AutoLamellaWaffleStage.LandLamella.name] > 0 + _AUTOLAMELLA_PROGRESS = (_counter[AutoLamellaWaffleStage.SetupLamella.name]>0 + or _counter[AutoLamellaWaffleStage.MillRoughCut.name] > 0 + or _counter[AutoLamellaWaffleStage.MillPolishingCut.name] > 0) # setup experiment -> connect to microscope -> select lamella -> run autoliftout -> run polishing diff --git a/autolamella/liftout/ui/utils.py b/autolamella/liftout/ui/utils.py index 877ffc9d..1b936ef8 100644 --- a/autolamella/liftout/ui/utils.py +++ b/autolamella/liftout/ui/utils.py @@ -190,9 +190,9 @@ def create_overview_image(experiment: Experiment) -> np.ndarray: def get_completion_stats(experiment: Experiment) -> tuple: """Get the current completetion stats for lifout""" - from liftout.structures import AutoLiftoutStage + from liftout.structures import AutoLamellaWaffleStage - n_stages = AutoLiftoutStage.Finished.value # init and failure dont count + n_stages = AutoLamellaWaffleStage.Finished.value # init and failure dont count lam: Lamella active_lam = 0 diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index 26e83929..6c638423 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -32,12 +32,12 @@ ) import numpy as np from autolamella.liftout import actions -from autolamella.liftout.structures import AutoLiftoutStage, Experiment, Lamella +from autolamella.liftout.structures import AutoLamellaWaffleStage, Experiment, Lamella from autolamella.liftout.ui.AutoLiftoutUIv2 import AutoLiftoutUIv2 from fibsem import config as fcfg from collections import Counter -from autolamella.liftout.structures import Lamella, Experiment, AutoLiftoutState, AutoLiftoutStage +from autolamella.liftout.structures import Lamella, Experiment, AutoLiftoutState, AutoLamellaWaffleStage from autolamella.liftout.autoliftout import log_status_message, start_of_stage_update, end_of_stage_update from autolamella.workflows.ui import ask_user, _update_status_ui, _validate_det_ui_v2, _set_images_ui, _validate_mill_ui @@ -405,13 +405,13 @@ def land_lamella( # serial workflow functions SERIAL_WORKFLOW_STAGES = { - AutoLiftoutStage.MillTrench: mill_trench, - AutoLiftoutStage.MillUndercut: mill_undercut, - AutoLiftoutStage.Liftout: liftout_lamella, - AutoLiftoutStage.Landing: land_lamella, - AutoLiftoutStage.SetupLamella: setup_lamella, - AutoLiftoutStage.MillRoughCut: mill_lamella, - AutoLiftoutStage.MillPolishingCut: mill_lamella, + AutoLamellaWaffleStage.MillTrench: mill_trench, + AutoLamellaWaffleStage.MillUndercut: mill_undercut, + AutoLamellaWaffleStage.LiftoutLamella: liftout_lamella, + AutoLamellaWaffleStage.LandLamella: land_lamella, + AutoLamellaWaffleStage.SetupLamella: setup_lamella, + AutoLamellaWaffleStage.MillRoughCut: mill_lamella, + AutoLamellaWaffleStage.MillPolishingCut: mill_lamella, } def run_serial_liftout_workflow( @@ -439,8 +439,8 @@ def run_serial_liftout_workflow( logging.info(f"Skipping {lamella._petname} due to failure.") continue # skip failures - while lamella.state.stage.value < AutoLiftoutStage.Liftout.value: - next_stage = AutoLiftoutStage(lamella.state.stage.value + 1) + while lamella.state.stage.value < AutoLamellaWaffleStage.LiftoutLamella.value: + next_stage = AutoLamellaWaffleStage(lamella.state.stage.value + 1) if CONFIRM_WORKFLOW_ADVANCE: msg = ( f"""Continue Lamella {(lamella._petname)} from {next_stage.name}?""" @@ -518,9 +518,9 @@ def run_serial_liftout_landing( # see where we are in the workflow _counter = Counter([p.state.stage.name for p in experiment.positions]) - land_idx = _counter[AutoLiftoutStage.Landing.name] + land_idx = _counter[AutoLamellaWaffleStage.LandLamella.name] # count how many at finished - finished_idx = _counter[AutoLiftoutStage.Finished.name] + finished_idx = _counter[AutoLamellaWaffleStage.Finished.name] # start of workflow response = ask_user(parent_ui, msg=f"Land Another Lamella? ({land_idx} Lamella Landed, {finished_idx} Lamella Finished)", pos="Continue", neg="Finish") @@ -534,10 +534,10 @@ def run_serial_liftout_landing( # advance workflow lamella = start_of_stage_update(microscope, lamella, - next_stage=AutoLiftoutStage.Landing, parent_ui=parent_ui) + next_stage=AutoLamellaWaffleStage.LandLamella, parent_ui=parent_ui) # run the next workflow stage - lamella = SERIAL_WORKFLOW_STAGES[AutoLiftoutStage.Landing]( + lamella = SERIAL_WORKFLOW_STAGES[AutoLamellaWaffleStage.LandLamella]( microscope=microscope, settings=settings, lamella=lamella, @@ -552,7 +552,7 @@ def run_serial_liftout_landing( # land another lamella? _counter = Counter([p.state.stage.name for p in experiment.positions]) - land_idx = _counter[AutoLiftoutStage.Landing.name] + land_idx = _counter[AutoLamellaWaffleStage.LandLamella.name] response = ask_user(parent_ui, msg=f"Land Another Lamella? ({land_idx} Lamella Landed), {finished_idx} Lamella Finished)", pos="Continue", neg="Finish") @@ -564,7 +564,7 @@ def _create_lamella(microscope: FibsemMicroscope, experiment: Experiment, positi # create a new lamella for landing _counter = Counter([p.state.stage.name for p in experiment.positions]) - land_idx = _counter[AutoLiftoutStage.Landing.name] + land_idx = _counter[AutoLamellaWaffleStage.LandLamella.name] print("COUNTER: ", _counter, land_idx) @@ -573,7 +573,7 @@ def _create_lamella(microscope: FibsemMicroscope, experiment: Experiment, positi log_status_message(lamella, "CREATION") # set state - lamella.state.stage = AutoLiftoutStage.Liftout + lamella.state.stage = AutoLamellaWaffleStage.LiftoutLamella lamella.state.microscope_state = microscope.get_current_microscope_state() lamella.state.microscope_state.absolute_position = deepcopy(positions[land_idx]) lamella.landing_state = deepcopy(lamella.state.microscope_state) diff --git a/autolamella/structures.py b/autolamella/structures.py index 39be05b2..acb7ea15 100644 --- a/autolamella/structures.py +++ b/autolamella/structures.py @@ -18,14 +18,15 @@ class AutoLamellaWaffleStage(Enum): ReadyTrench = auto() MillTrench = auto() MillUndercut = auto() + LiftoutLamella = auto() + LandLamella = auto() SetupLamella = auto() ReadyLamella = auto() MillRoughCut = auto() MillPolishingCut = auto() Finished = auto() PreSetupLamella = auto() - LiftoutLamella = auto() - LandLamella = auto() + @@ -101,14 +102,17 @@ def info(self): @classmethod def __from_dict__(cls, data): state = LamellaState().__from_dict__(data["state"]) - fiducial_area = FibsemRectangle.__from_dict__(data["fiducial_area"]) + if data.get("fiducial_area", None) is None: + fiducial_area = None + else: + fiducial_area = FibsemRectangle.__from_dict__(data["fiducial_area"]) return cls( _petname=data["petname"], state=state, path=data["path"], fiducial_area=fiducial_area, protocol=data.get("protocol", {}), - _number=data["_number"], + _number=data.get("_number", data.get("number", 0)), history=[LamellaState().__from_dict__(state) for state in data["history"]], _is_failure=data.get("_is_failure", False), ) diff --git a/autolamella/workflows/core.py b/autolamella/workflows/core.py index bb214db6..436c44cf 100644 --- a/autolamella/workflows/core.py +++ b/autolamella/workflows/core.py @@ -65,6 +65,16 @@ def log_status_message(lamella: Lamella, step: str): logging.debug(f"STATUS | {lamella._petname} | {lamella.state.stage.name} | {step}") + +def pass_through_stage( + microscope: FibsemMicroscope, + settings: MicroscopeSettings, + lamella: Lamella, + parent_ui: AutoLamellaUI = None, +) -> Lamella: + # pass through stage + return lamella + # mill trench def mill_trench( microscope: FibsemMicroscope, From e785b65189799b0e113a90c87a699ef097fbd300 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Mon, 9 Oct 2023 16:15:50 +1100 Subject: [PATCH 29/39] re-arrange config / protocols --- autolamella/liftout/config/config.py | 13 ++++++++----- .../protocol-autoliftout-base.yaml} | 0 .../protocol-autoliftout-yeast.yaml} | 0 .../protocol/protocol-serial-liftout.yaml | 0 4 files changed, 8 insertions(+), 5 deletions(-) rename autolamella/{liftout/protocol/protocol-base.yaml => protocol/protocol-autoliftout-base.yaml} (100%) rename autolamella/{liftout/protocol/protocol_yeast.yaml => protocol/protocol-autoliftout-yeast.yaml} (100%) rename autolamella/{liftout => }/protocol/protocol-serial-liftout.yaml (100%) diff --git a/autolamella/liftout/config/config.py b/autolamella/liftout/config/config.py index f5fcb052..9a012c5c 100644 --- a/autolamella/liftout/config/config.py +++ b/autolamella/liftout/config/config.py @@ -2,11 +2,14 @@ import autolamella.liftout as liftout -BASE_PATH = os.path.dirname(liftout.__file__) # TODO: fix this to be the root directory of the project -CONFIG_PATH = os.path.join(BASE_PATH, "config") -SYSTEM_PATH = os.path.join(CONFIG_PATH, "system.yaml") -PROTOCOL_PATH = os.path.join(BASE_PATH, "protocol", "protocol.yaml") -LOG_PATH = os.path.join(BASE_PATH, "log") +from autolamella.config import BASE_PATH, CONFIG_PATH, SYSTEM_PATH, PROTOCOL_PATH, LOG_PATH + + +# BASE_PATH = os.path.dirname(liftout.__file__) # TODO: fix this to be the root directory of the project +# CONFIG_PATH = os.path.join(BASE_PATH, "config") +# SYSTEM_PATH = os.path.join(CONFIG_PATH, "system.yaml") +# PROTOCOL_PATH = os.path.join(BASE_PATH, "protocol", "protocol.yaml") +# LOG_PATH = os.path.join(BASE_PATH, "log") EXPERIMENT_NAME = "AutoLiftout" __AUTOLIFTOUT_METHODS__ = ["autoliftout-default", "autoliftout-serial-liftout"] diff --git a/autolamella/liftout/protocol/protocol-base.yaml b/autolamella/protocol/protocol-autoliftout-base.yaml similarity index 100% rename from autolamella/liftout/protocol/protocol-base.yaml rename to autolamella/protocol/protocol-autoliftout-base.yaml diff --git a/autolamella/liftout/protocol/protocol_yeast.yaml b/autolamella/protocol/protocol-autoliftout-yeast.yaml similarity index 100% rename from autolamella/liftout/protocol/protocol_yeast.yaml rename to autolamella/protocol/protocol-autoliftout-yeast.yaml diff --git a/autolamella/liftout/protocol/protocol-serial-liftout.yaml b/autolamella/protocol/protocol-serial-liftout.yaml similarity index 100% rename from autolamella/liftout/protocol/protocol-serial-liftout.yaml rename to autolamella/protocol/protocol-serial-liftout.yaml From 5b00b7c93ee71d48f303a45f61d16d1f3fa1de27 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Mon, 9 Oct 2023 16:20:27 +1100 Subject: [PATCH 30/39] depreciate AutoLiftoutState --- autolamella/liftout/config/system.yaml | 78 -------------------- autolamella/liftout/structures.py | 95 ++----------------------- autolamella/liftout/workflows/serial.py | 2 +- autolamella/structures.py | 8 +-- 4 files changed, 12 insertions(+), 171 deletions(-) delete mode 100644 autolamella/liftout/config/system.yaml diff --git a/autolamella/liftout/config/system.yaml b/autolamella/liftout/config/system.yaml deleted file mode 100644 index 574c37e3..00000000 --- a/autolamella/liftout/config/system.yaml +++ /dev/null @@ -1,78 +0,0 @@ -apply_settings_on_startup: false -connect_to_microscope_on_startup: false -load_positions_on_startup: false -model: - electron: - enabled: true - gis: - enabled: true - multichem: true - ion: - enabled: true - can_select_plasma_gas: true - manipulator: - enabled: true - positions: - calibrated: true - parking: - x: -0.008918395 - y: 0.0006548000000000001 - z: -0.004848865 - standby: - x: 0.0 - y: 0.0 - z: 0.00545 - working: - x: 0.0 - y: 0.0 - z: 0.00585 - rotation: false - tilt: false - stage: - enabled: true - rotation: true - tilt: true -system: - description: test - electron: - current: 50.0000000000000002e-12 - detector_mode: SecondaryElectrons - detector_type: E-T - eucentric_height: 0.0039 - voltage: 2000 - id: '123' - ion: - current: 2.0000000000000002e-11 - detector_mode: SecondaryElectrons - detector_type: SE - eucentric_height: 0.0165 - plasma_gas: Argon - voltage: 30000 - ip_address: 10.0.0.1 - manufacturer: Demo - name: S8252G - stage: - needle_stage_height_limit: 0.0037 - pre_tilt: 35.0 - rotation_flat_to_electron: 49.0 - rotation_flat_to_ion: 229.0 - tilt_flat_to_electron: 0.0 - tilt_flat_to_ion: 52.0 - version: 0.2.1a1 -user: - imaging: - autocontrast: true - beam_type: ELECTRON - dwell_time: 1.0e-06 - gamma: false - hfw: 0.00015 - imaging_current: 2.0000000000000002e-11 - resolution: - - 1536 - - 1024 - save: false - milling: - dwell_time: 1.0e-06 - milling_current: 2.0e-09 - rate: 3.0000000000000004e-09 - spot_size: 5.0000000000000004e-08 diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index 32112d68..c391ddbb 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -14,7 +14,7 @@ ReferenceImages, Point) from autolamella.liftout.config import config as cfg -from autolamella.structures import AutoLamellaWaffleStage +from autolamella.structures import AutoLamellaWaffleStage, LamellaState class Experiment: def __init__(self, path: Path = None, name: str = cfg.EXPERIMENT_NAME, program: str = "AutoLiftout", method: str = "AutoLiftout") -> None: @@ -179,10 +179,10 @@ def __init__(self, path: Path, number: int = 0, _petname: str = None) -> None: self.protocol: dict = {} - self.state: AutoLiftoutState = AutoLiftoutState() + self.state: LamellaState = LamellaState() # state history - self.history: list[AutoLiftoutState] = [] + self.history: list[LamellaState] = [] def __repr__(self) -> str: @@ -236,7 +236,7 @@ def load_reference_image(self, fname) -> FibsemImage: def __from_dict__(path: str, lamella_dict: dict) -> 'Lamella': lamella = Lamella( - path=path, number=lamella_dict["number"], _petname=lamella_dict["petname"] + path=path, number=lamella_dict.get("number", lamella_dict.get("_number", 0)), _petname=lamella_dict["petname"] ) lamella._petname = lamella_dict["petname"] @@ -252,11 +252,11 @@ def __from_dict__(path: str, lamella_dict: dict) -> 'Lamella': lamella.protocol = deepcopy(lamella_dict.get("protocol", {})) # load current state - lamella.state = AutoLiftoutState.__from_dict__(lamella_dict["state"]) + lamella.state = LamellaState.__from_dict__(lamella_dict["state"]) # load history lamella.history = [ - AutoLiftoutState.__from_dict__(state_dict) + LamellaState.__from_dict__(state_dict) for state_dict in lamella_dict["history"] ] @@ -271,85 +271,4 @@ def get_reference_images(self, label: str) -> ReferenceImages: high_res_ib=self.load_reference_image(f"{label}_high_res_ib"), ) - return reference_images - -@dataclass -class AutoLiftoutState(FibsemState): - stage: AutoLamellaWaffleStage = AutoLamellaWaffleStage.SetupTrench - microscope_state: MicroscopeState = MicroscopeState() - start_timestamp: float = datetime.timestamp(datetime.now()) - end_timestamp: float = None - - def __to_dict__(self) -> dict: - - state_dict = { - "stage": self.stage.name, - "microscope_state": self.microscope_state.__to_dict__(), - "start_timestamp": self.start_timestamp, - "end_timestamp": self.end_timestamp, - } - - return state_dict - - @classmethod - def __from_dict__(self, state_dict: dict) -> 'AutoLiftoutState': - - autoliftout_state = AutoLiftoutState( - stage=AutoLamellaWaffleStage[state_dict["stage"]], - microscope_state=MicroscopeState.__from_dict__(state_dict["microscope_state"]), - start_timestamp=state_dict["start_timestamp"], - end_timestamp=state_dict["end_timestamp"], - ) - - return autoliftout_state - - - - - -# Experiment: -# data_path: Path -# -# positions: [Lamella, Lamella, Lamella] - -# Lamella -# lamella_state: MicroscopeState -# landing_state: MicroscopeState -# lamella_ref_images: ReferenceImages -# landing_ref_images: ReferenceImages -# state: AutoLiftoutState -# stage: AutoLamellaWaffleStage -# microscope_state: MicroscopeState -# eb_settings: BeamSettings -# ib_settings: BeamSettings -# absolute_position: StagePosition - - -######################## UTIL ######################## - - -def create_experiment(experiment_name: str, path: Path = None): - - # create unique experiment name - exp_name = f"{experiment_name}-{fibsem_utils.current_timestamp()}" - - # create experiment data struture - experiment = Experiment(path=path, name=exp_name) - - # save experiment to disk - experiment.save() - - return experiment - - -def load_experiment(path: Path) -> Experiment: - - sample_fname = os.path.join(path, "experiment.yaml") - - if not os.path.exists(sample_fname): - raise ValueError(f"No experiment file found for this path: {path}") - - return Experiment.load(fname=sample_fname) - - - + return reference_images \ No newline at end of file diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index 6c638423..e6c35e69 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -37,7 +37,7 @@ from fibsem import config as fcfg from collections import Counter -from autolamella.liftout.structures import Lamella, Experiment, AutoLiftoutState, AutoLamellaWaffleStage +from autolamella.liftout.structures import Lamella, Experiment, LamellaState, AutoLamellaWaffleStage from autolamella.liftout.autoliftout import log_status_message, start_of_stage_update, end_of_stage_update from autolamella.workflows.ui import ask_user, _update_status_ui, _validate_det_ui_v2, _set_images_ui, _validate_mill_ui diff --git a/autolamella/structures.py b/autolamella/structures.py index acb7ea15..51898601 100644 --- a/autolamella/structures.py +++ b/autolamella/structures.py @@ -66,10 +66,10 @@ class Lamella: _petname: str = None protocol: dict = None _is_failure: bool = False - # lamella_state: MicroscopeState = None - # landing_state: MicroscopeState = None - # landing_selected: bool = False - # _id: str = None + lamella_state: MicroscopeState = None + landing_state: MicroscopeState = None + landing_selected: bool = False + _id: str = None def __post_init__(self): From 65e0d5719f148f17875286b137a8e543c8d3a2ba Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Mon, 9 Oct 2023 16:21:37 +1100 Subject: [PATCH 31/39] rm unused --- autolamella/liftout/structures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index c391ddbb..a0dc6867 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -10,7 +10,7 @@ import petname import yaml from fibsem import utils as fibsem_utils -from fibsem.structures import (FibsemImage, FibsemState, MicroscopeState, +from fibsem.structures import (FibsemImage,MicroscopeState, ReferenceImages, Point) from autolamella.liftout.config import config as cfg From 5cce5d439d7e1122fe9afe241ede8aca2a75d916 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Mon, 9 Oct 2023 16:54:17 +1100 Subject: [PATCH 32/39] depreciate liftout structures --- autolamella/liftout/autoliftout.py | 6 +- autolamella/liftout/structures.py | 275 +------------ autolamella/liftout/ui/AutoLiftoutUIv2.py | 8 +- autolamella/liftout/ui/utils.py | 2 +- autolamella/liftout/workflows/serial.py | 2 +- autolamella/notebook.ipynb | 454 ---------------------- autolamella/structures.py | 63 ++- 7 files changed, 67 insertions(+), 743 deletions(-) delete mode 100644 autolamella/notebook.ipynb diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 596960e4..07199a09 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -862,7 +862,7 @@ def run_autoliftout_workflow( ]: lamella: Lamella for lamella in experiment.positions: - if lamella.is_failure: + if lamella._is_failure: continue # skip failures while lamella.state.stage.value < terminal_stage.value: @@ -892,7 +892,7 @@ def run_autoliftout_workflow( # standard workflow lamella: Lamella for lamella in experiment.positions: - if lamella.is_failure: + if lamella._is_failure: continue # skip failures while lamella.state.stage.value < AutoLamellaWaffleStage.LandLamella.value: @@ -951,7 +951,7 @@ def run_thinning_workflow( AutoLamellaWaffleStage.MillPolishingCut, ]: for lamella in experiment.positions: - if lamella.is_failure: + if lamella._is_failure: continue if lamella.state.stage.value == next_stage.value - 1: diff --git a/autolamella/liftout/structures.py b/autolamella/liftout/structures.py index a0dc6867..28757f8c 100644 --- a/autolamella/liftout/structures.py +++ b/autolamella/liftout/structures.py @@ -1,274 +1 @@ -import os -import uuid -from copy import deepcopy -from dataclasses import dataclass -from datetime import datetime -from enum import Enum, auto -from pathlib import Path - -import pandas as pd -import petname -import yaml -from fibsem import utils as fibsem_utils -from fibsem.structures import (FibsemImage,MicroscopeState, - ReferenceImages, Point) - -from autolamella.liftout.config import config as cfg -from autolamella.structures import AutoLamellaWaffleStage, LamellaState - -class Experiment: - def __init__(self, path: Path = None, name: str = cfg.EXPERIMENT_NAME, program: str = "AutoLiftout", method: str = "AutoLiftout") -> None: - - - self.name: str = name - self._id = str(uuid.uuid4()) - self.path: Path = fibsem_utils.make_logging_directory(path=path, name=name) - self.log_path: Path = fibsem_utils.configure_logging( - path=self.path, log_filename="logfile" - ) - self._created_at: float = datetime.timestamp(datetime.now()) - - - # TODO: user/data management (e.g. user, sample, id, etc.) - - self.positions: list[Lamella] = [] - - self.program = program - self.method = method - - - def __to_dict__(self) -> dict: - - state_dict = { - "name": self.name, - "_id": self._id, - "path": self.path, - "log_path": self.log_path, - "positions": [lamella.__to_dict__() for lamella in self.positions], - "created_at": self._created_at, - "program": self.program, - "method": self.method, - } - - return state_dict - - def save(self) -> None: - """Save the experiment data to yaml file""" - - with open(os.path.join(self.path, "experiment.yaml"), "w") as f: - yaml.dump(self.__to_dict__(), f, indent=4) - - def __repr__(self) -> str: - - return f"""Experiment: - Path: {self.path} - Lamella: {len(self.positions)} - """ - - def __to_dataframe__(self) -> pd.DataFrame: - - lamella_list = [] - lamella: Lamella - for lamella in self.positions: - - # lamella - lamella_dict = { - "experiment_name": self.name, - "experiment_path": self.path, - "experiment_created_at": self._created_at, - "experiment_id": self._id, - "program": self.program, - "method": self.method, - "number": lamella._number, - "petname": lamella._petname, - "path": lamella.path, - "lamella.x": lamella.lamella_state.absolute_position.x, - "lamella.y": lamella.lamella_state.absolute_position.y, - "lamella.z": lamella.lamella_state.absolute_position.z, - "lamella.r": lamella.lamella_state.absolute_position.r, - "lamella.t": lamella.lamella_state.absolute_position.t, - "lamella.coordinate_system": lamella.lamella_state.absolute_position.coordinate_system, - "landing.x": lamella.landing_state.absolute_position.x, - "landing.y": lamella.landing_state.absolute_position.y, - "landing.z": lamella.landing_state.absolute_position.z, - "landing.r": lamella.landing_state.absolute_position.r, - "landing.t": lamella.landing_state.absolute_position.t, - "landing.coordinate_system": lamella.landing_state.absolute_position.coordinate_system, - "landing_selected": lamella.landing_selected, - "current_stage": lamella.state.stage.name, - "last_timestamp": lamella.state.microscope_state.timestamp, - "history: ": len(lamella.history), - - } - - lamella_list.append(lamella_dict) - - df = pd.DataFrame.from_dict(lamella_list) - - return df - - - def to_dataframe_v2(self) -> pd.DataFrame: - - edict = { - "name": self.name, - "path": self.path, - "date": self._created_at, - "experiment_id": self._id, - "program": self.program, - "method": self.method, - "num_lamella": len(self.positions), - } - - df = pd.DataFrame([edict]) - - return df - - @staticmethod - def load(fname: Path) -> 'Experiment': - """Load a sample from disk.""" - - # read and open existing yaml file - if os.path.exists(fname): - with open(fname, "r") as f: - ddict = yaml.safe_load(f) - else: - raise FileNotFoundError(f"No file with name {fname} found.") - - # create sample - path = os.path.dirname(ddict["path"]) - name = ddict["name"] - experiment = Experiment(path=path, name=name) - experiment._created_at = ddict.get("created_at", None) - experiment._id = ddict.get("_id", "NULL") - experiment.program = ddict.get("program", "AutoLiftout") - experiment.method = ddict.get("method", "AutoLiftout") # TODO: implement - - # load lamella from dict - for lamella_dict in ddict["positions"]: - lamella = Lamella.__from_dict__(path=experiment.path, lamella_dict=lamella_dict) - experiment.positions.append(deepcopy(lamella)) - - return experiment - -# TODO: move to fibsem? -# TODO: need to inherit the state class? -class Lamella: - def __init__(self, path: Path, number: int = 0, _petname: str = None) -> None: - - self._number: int = number - self._id = str(uuid.uuid4()) - if _petname is None: - self._petname = f"{self._number:02d}-{petname.generate(2)}" - else: - self._petname = _petname - self._created_at: float = datetime.timestamp(datetime.now()) - - # filesystem - self.base_path = path - self.path = os.path.join(self.base_path, self._petname) - os.makedirs(self.path, exist_ok=True) - - self.lamella_state: MicroscopeState = MicroscopeState() - self.landing_state: MicroscopeState = MicroscopeState() - - self.landing_selected: bool = False - self.is_failure: bool = False - - # lamella specific protocol - self.protocol: dict = {} - - - self.state: LamellaState = LamellaState() - - # state history - self.history: list[LamellaState] = [] - - def __repr__(self) -> str: - - return f""" - Lamella {self._number} ({self._petname}). - Lamella Coordinates: {self.lamella_state.absolute_position}, - Landing Coordinates: {self.landing_state.absolute_position}, - Current Stage: {self.state.stage}, - History: {len(self.history)} stages completed ({[state.stage.name for state in self.history]}). - """ - - @property - def info(self): - return f"Lamella {self._petname} [{self.state.stage.name}]" - - def __to_dict__(self): - - state_dict = { - "id": str(self._id), - "petname": self._petname, - "_number": self._number, - "base_path": self.base_path, - "path": self.path, - "landing_selected": self.landing_selected, - "is_failure": self.is_failure, - "lamella_state": self.lamella_state.__to_dict__(), - "landing_state": self.landing_state.__to_dict__(), - "state": self.state.__to_dict__(), - "protocol": self.protocol, - "history": [state.__to_dict__() for state in self.history], - "created_at": self._created_at, - } - - return state_dict - - def load_reference_image(self, fname) -> FibsemImage: - """Load a specific reference image for this lamella from disk - Args: - fname: str - the filename of the reference image to load - Returns: - adorned_img: AdornedImage - the reference image loaded as an AdornedImage - """ - - adorned_img = FibsemImage.load(os.path.join(self.path, f"{fname}.tif")) - - return adorned_img - - @staticmethod - def __from_dict__(path: str, lamella_dict: dict) -> 'Lamella': - - lamella = Lamella( - path=path, number=lamella_dict.get("number", lamella_dict.get("_number", 0)), _petname=lamella_dict["petname"] - ) - - lamella._petname = lamella_dict["petname"] - lamella._id = lamella_dict["id"] - - # load stage positions from yaml - lamella.lamella_state = MicroscopeState.__from_dict__(lamella_dict["lamella_state"]) - lamella.landing_state = MicroscopeState.__from_dict__(lamella_dict["landing_state"]) - lamella.landing_selected = bool(lamella_dict["landing_selected"]) - lamella.is_failure = bool(lamella_dict.get("is_failure", False)) - - # load protocol - lamella.protocol = deepcopy(lamella_dict.get("protocol", {})) - - # load current state - lamella.state = LamellaState.__from_dict__(lamella_dict["state"]) - - # load history - lamella.history = [ - LamellaState.__from_dict__(state_dict) - for state_dict in lamella_dict["history"] - ] - - return lamella - - # convert to method - def get_reference_images(self, label: str) -> ReferenceImages: - reference_images = ReferenceImages( - low_res_eb=self.load_reference_image(f"{label}_low_res_eb"), - high_res_eb=self.load_reference_image(f"{label}_high_res_eb"), - low_res_ib=self.load_reference_image(f"{label}_low_res_ib"), - high_res_ib=self.load_reference_image(f"{label}_high_res_ib"), - ) - - return reference_images \ No newline at end of file +from autolamella.structures import AutoLamellaWaffleStage, LamellaState, Lamella, Experiment diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index e5a52de5..353e70a6 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -214,7 +214,7 @@ def update_ui(self): msg = "\nLamella Info:\n" for lamella in self.experiment.positions: - failure_msg = f" (Failure)" if lamella.is_failure else f" (Active)" + failure_msg = f" (Failure)" if lamella._is_failure else f" (Active)" msg += f"Lamella {lamella._petname} \t\t {lamella.state.stage.name} \t{failure_msg} \n" self.label_info.setText(msg) @@ -274,10 +274,10 @@ def _update_lamella_ui(self): msg = "" msg += f"{lamella.info}" - msg += f" (Failure)" if lamella.is_failure else f" (Active)" + msg += f" (Failure)" if lamella._is_failure else f" (Active)" self.label_lamella_detail.setText(msg) self.checkBox_current_lamella_landing_selected.setChecked(lamella.landing_selected) - self.checkBox_current_lamella_failure.setChecked(lamella.is_failure) + self.checkBox_current_lamella_failure.setChecked(lamella._is_failure) def _to_str(state): return f"{state.stage.name} ({datetime.fromtimestamp(state.end_timestamp).strftime('%I:%M%p')})" @@ -293,7 +293,7 @@ def _update_lamella_info(self): # TODO: add a failure note here lamella = self.experiment.positions[self.comboBox_current_lamella.currentIndex()] lamella.landing_selected = self.checkBox_current_lamella_landing_selected.isChecked() - lamella.is_failure = self.checkBox_current_lamella_failure.isChecked() + lamella._is_failure = self.checkBox_current_lamella_failure.isChecked() self.experiment.save() self._update_lamella_ui() diff --git a/autolamella/liftout/ui/utils.py b/autolamella/liftout/ui/utils.py index 1b936ef8..af088f01 100644 --- a/autolamella/liftout/ui/utils.py +++ b/autolamella/liftout/ui/utils.py @@ -200,7 +200,7 @@ def get_completion_stats(experiment: Experiment) -> tuple: for lam in experiment.positions: # dont count failure - if lam.is_failure or lam.state.stage.value == 99: + if lam._is_failure or lam.state.stage.value == 99: continue active_lam += 1 diff --git a/autolamella/liftout/workflows/serial.py b/autolamella/liftout/workflows/serial.py index e6c35e69..f7a6101b 100644 --- a/autolamella/liftout/workflows/serial.py +++ b/autolamella/liftout/workflows/serial.py @@ -435,7 +435,7 @@ def run_serial_liftout_workflow( # standard workflow lamella: Lamella for lamella in experiment.positions: - if lamella.is_failure: + if lamella._is_failure: logging.info(f"Skipping {lamella._petname} due to failure.") continue # skip failures diff --git a/autolamella/notebook.ipynb b/autolamella/notebook.ipynb deleted file mode 100644 index d585a625..00000000 --- a/autolamella/notebook.ipynb +++ /dev/null @@ -1,454 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "from fibsem import utils, acquire, milling, conversions, structures\n", - "\n", - "from fibsem.structures import BeamType, Point, FibsemRectangle\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "microscope, settings = utils.setup_session(config_path=r\"C:\\Users\\Admin\\Github\\autolamella\\autolamella\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "settings.image.beam_type = BeamType.ION\n", - "ref_image = acquire.new_image(microscope, settings.image)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "\n", - "\n", - "\n", - "pixelsize = ref_image.metadata.pixel_size.x\n", - "fiducial_centre = Point(-50e-6, -10e-6)\n", - "fiducial_length = 30e-6 # microscope_settings.protocol[\"fiducial\"][\"length\"] \n", - "fiducial_area = calculate_fiducial_area(settings, fiducial_centre, fiducial_length, pixelsize)\n", - "\n", - "print(fiducial_area)\n", - "\n", - "settings.image.reduced_area = fiducial_area\n", - "image = acquire.new_image(microscope, settings.image)\n", - "print(image.metadata.image_settings.reduced_area)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Minimap\n", - "Position Display" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "from fibsem import utils, acquire, milling, conversions, structures\n", - "from fibsem.structures import FibsemImage, BeamType\n", - "import os\n", - "from fibsem.imaging import _tile\n", - "\n", - "import matplotlib.pyplot as plt\n", - "from autolamella.structures import Experiment\n", - "\n", - "# microscope, settings = utils.setup_session()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "PATH = r\"C:\\Users\\Admin\\Github\\autolamella\\autolamella\\log\\TEST_DEV_01\"\n", - "# EXP_PATH = r\"C:\\Users\\Admin\\Github\\autolamella\\autolamella\\log\\HANNAH-WAFFLE-26072023\\experiment.yaml\"\n", - "exp = Experiment.load(os.path.join(PATH, \"experiment.yaml\"))\n", - "# image = FibsemImage.load(os.path.join(PATH, \"overview-image-ion-auto-gamma.tif\"))\n", - "ion_image = FibsemImage.load(os.path.join(PATH, \"overview-ion-start.tif\"))\n", - "# ion_image = FibsemImage.load(os.path.join(PATH, \"overview-ion-trench.tif\"))\n", - "\n", - "plt.imshow(ion_image.data, cmap=\"gray\")\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from autolamella.tools.data import create_history_dataframe, calculate_statistics_dataframe\n", - "import plotly.express as px\n", - "import pandas as pd\n", - "\n", - "\n", - "pd.set_option('display.max_rows', 300)\n", - "\n", - "df_experiment, df_history, df_beam_shift, df_steps, df_stage = calculate_statistics_dataframe(PATH)\n", - "\n", - "# display(df_steps)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig = px.bar(df_history, x=\"stage\", y=\"duration\", color=\"petname\", barmode=\"group\", hover_data=df.columns)\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# display(df_stage)\n", - "\n", - "df_stage_filter = df_stage[df_stage[\"stage\"] != \"Setup\"]\n", - "# drop relative moves \n", - "df_stage_filter = df_stage_filter[df_stage_filter[\"type\"] != \"relative\"]\n", - "\n", - "# drop x=0, y=0\n", - "df_stage_filter = df_stage_filter[df_stage_filter[\"x\"] != 0]\n", - "df_stage_filter = df_stage_filter[df_stage_filter[\"y\"] != 0]\n", - "\n", - "\n", - "px.line(df_stage_filter, x=\"x\", y=\"y\", color=\"stage\",symbol=\"lamella\", title=\"Stage History\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# display(df_steps)\n", - "\n", - "fig = px.bar(df_steps, x=\"lamella\", y=\"duration\", color=\"step\", title=\"Step Duration\", barmode=\"stack\", facet_col=\"stage\")\n", - "\n", - "fig.show()\n", - "# plot time series with x= step_n and y = timestamp with step as hover text\n", - "df_steps.dropna(inplace=True)\n", - "df_steps.duration =df_steps.duration.astype(int)\n", - "\n", - "# convert timestamp to datetime, aus timezone \n", - "df_steps.timestamp = pd.to_datetime(df_steps.timestamp, unit=\"s\")\n", - "\n", - "# convert timestamp to australian timezone\n", - "df_steps.timestamp = df_steps.timestamp.dt.tz_localize(\"UTC\").dt.tz_convert(\"Australia/Sydney\")\n", - "\n", - "fig = px.scatter(df_steps, x=\"step_n\", y=\"timestamp\", color=\"stage\", symbol=\"lamella\",\n", - " title=\"AutoLamella Timeline\", \n", - " hover_name=\"stage\", hover_data=[\"lamella\", \"step_n\", \"step\"],)\n", - " # size = \"duration\", size_max=20)\n", - "\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "from autolamella.tools.data import create_history_dataframe\n", - "df = create_history_dataframe(exp)\n", - "display(df)\n", - "\n", - "import plotly.express as px\n", - "\n", - "fig = px.bar(df, x=\"petname\", y=\"duration\", color=\"stage\", barmode=\"group\", hover_data=df.columns)\n", - "fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "positions = {\n", - " \"MillTrench\": [],\n", - " \"MillUndercut\": [],\n", - " \"ReadyLamella\": [],\n", - "}\n", - "for lamella in exp.positions:\n", - " for state in lamella.history:\n", - " \n", - " if state.stage.name in positions.keys():\n", - " positions[state.stage.name].append(state.microscope_state.absolute_position)\n", - " positions[state.stage.name][-1].name = f\"{lamella._petname}\"# [{state.stage.name}]\"\n", - "\n", - "# pprint(positions)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "key = \"MillTrench\"\n", - "fig = _tile._plot_positions(ion_image, positions[key], show=True)\n", - "fig.savefig(os.path.join(PATH, f\"overview-positions-{key.lower()}.png\"), dpi=300, bbox_inches='tight')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig = _tile._plot_positions(eb_image, positions[\"MillUndercut\"], show=True)\n", - "fig.savefig(os.path.join(PATH, \"overview-positions-mill-undercut.png\"), dpi=300, bbox_inches='tight')\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig = _tile._plot_positions(eb_image, positions[\"ReadyLamella\"], show=True)\n", - "fig.savefig(os.path.join(PATH, \"overview-positions-mill-lamella.png\"), dpi=300, bbox_inches='tight')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "_n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "\n", - "from fibsem import utils, acquire\n", - "from fibsem.structures import FibsemRectangle, MicroscopeState, Point, BeamType, FibsemImage\n", - "from autolamella import waffle as wfl\n", - "from autolamella.structures import Experiment, Lamella\n", - "import os\n", - "import glob\n", - "\n", - "from fibsem.imaging import _tile\n", - "from pprint import pprint \n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "PATH = r\"C:\\Users\\Admin\\Github\\autolamella\\autolamella\\log\\HANNAH-WAFFLE-02-02082023\"\n", - "\n", - "TILE_PATH = \"overview-ion-grid01\"\n", - "\n", - "\n", - "\n", - "filenames0 = sorted(glob.glob(os.path.join(PATH, TILE_PATH, \"tile_0*.tif\")))\n", - "filenames1 = sorted(glob.glob(os.path.join(PATH, TILE_PATH, \"tile_1*.tif\")))\n", - "filenames2 = sorted(glob.glob(os.path.join(PATH, TILE_PATH, \"tile_2*.tif\")))\n", - "filenames3 = sorted(glob.glob(os.path.join(PATH, TILE_PATH, \"tile_3*.tif\")))\n", - "\n", - "\n", - "\n", - "images= [[FibsemImage.load(fname) for fname in filenames0], \n", - " [FibsemImage.load(fname) for fname in filenames1],\n", - " [FibsemImage.load(fname) for fname in filenames2],\n", - " [FibsemImage.load(fname) for fname in filenames3]]\n", - "# big_image = FibsemImage.load(os.path.join(PATH, TILE_PATH, f\"big_image_ib.tif\"))\n", - "\n", - "\n", - "\n", - "# plot all images as a grid\n", - "\n", - "fig, ax = plt.subplots(4,4, figsize=(10,10))\n", - "\n", - "for i in range(4):\n", - " for j in range(4):\n", - " ax[i,j].imshow(images[i][j].data, cmap=\"gray\")\n", - " ax[i,j].axis(\"off\")\n", - "\n", - "plt.subplots_adjust(wspace=0, hspace=0)\n", - "plt.show()\n", - "\n", - "# ddict = utils.load_yaml(os.path.join(PATH, TILE_PATH, f\"{TILE_PATH}.yaml\"))\n", - "# ddict[\"images\"] = images\n", - "# ddict[\"big_image\"] = big_image\n", - "# ddict[\"prev-label\"] = \"overivew-ion-grid02-clahe\"\n", - "\n", - "# from fibsem.structures import ImageSettings\n", - "\n", - "# ddict[\"image_settings\"] = ImageSettings.__from_dict__(ddict[\"image_settings\"])\n", - "# ddict[\"start_state\"] = MicroscopeState.__from_dict__(ddict[\"start_state\"])\n", - "# pprint(ddict)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "image = _tile._stitch_images(ddict[\"images\"], ddict, overlap=0)\n", - "\n", - "\n", - "tile_image = FibsemImage.load(os.path.join(PATH, f\"{TILE_PATH}.tif\"))\n", - "\n", - "# plot\n", - "import matplotlib.pyplot as plt\n", - "fig, ax = plt.subplots(1, 2, figsize=(30, 15))\n", - "ax[0].imshow(image.data, cmap=\"gray\")\n", - "ax[1].imshow(tile_image.data, cmap=\"gray\")\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "\n", - "# create a grid of lines on a blank image\n", - "\n", - "grid_shape = (4*1024, 4*1024)\n", - "arr = np.zeros(shape=grid_shape, dtype=np.uint8)\n", - "\n", - "\n", - "# create grid, grid bars thickness = 10px\n", - "BAR_THICKNESS_PX = 50\n", - "BAR_SPACING_PX = 170\n", - "for i in range(0, arr.shape[0], BAR_SPACING_PX ):\n", - " arr[i:i+BAR_THICKNESS_PX, :] = 255\n", - " arr[:, i:i+BAR_THICKNESS_PX] = 255\n", - "\n", - "import tifffile as tff\n", - "PATH = r\"C:\\Users\\Admin\\Github\\autolamella\\autolamella\\log\\HANNAH-WAFFLE-02-02082023\"\n", - "\n", - "tff.imwrite(os.path.join(PATH, \"grid-bar.tif\"), arr)\n", - "\n", - "fig = plt.figure(figsize=(15, 15))\n", - "plt.imshow(arr, cmap=\"gray\")\n", - "plt.axis(\"off\")\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "fibsem", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.12" - }, - "orig_nbformat": 4 - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/autolamella/structures.py b/autolamella/structures.py index 51898601..66ad9216 100644 --- a/autolamella/structures.py +++ b/autolamella/structures.py @@ -9,8 +9,9 @@ import pandas as pd import petname import yaml -from fibsem.structures import FibsemRectangle, MicroscopeState +from fibsem.structures import FibsemRectangle, MicroscopeState, FibsemImage, ReferenceImages import uuid +from autolamella import config as cfg class AutoLamellaWaffleStage(Enum): @@ -66,8 +67,8 @@ class Lamella: _petname: str = None protocol: dict = None _is_failure: bool = False - lamella_state: MicroscopeState = None - landing_state: MicroscopeState = None + lamella_state: MicroscopeState = MicroscopeState() + landing_state: MicroscopeState = MicroscopeState() landing_selected: bool = False _id: str = None @@ -93,6 +94,10 @@ def __to_dict__(self): "_number": self._number, "history": [state.__to_dict__() for state in self.history] if self.history is not False else [], "_is_failure": self._is_failure, + "lamella_state": self.lamella_state.__to_dict__(), + "landing_state": self.landing_state.__to_dict__(), + "landing_selected": self.landing_selected, + "id": str(self._id), } @property @@ -106,19 +111,51 @@ def __from_dict__(cls, data): fiducial_area = None else: fiducial_area = FibsemRectangle.__from_dict__(data["fiducial_area"]) + return cls( _petname=data["petname"], + _id=data.get("id", None), state=state, path=data["path"], fiducial_area=fiducial_area, protocol=data.get("protocol", {}), _number=data.get("_number", data.get("number", 0)), history=[LamellaState().__from_dict__(state) for state in data["history"]], - _is_failure=data.get("_is_failure", False), + _is_failure=data.get("_is_failure", data.get("is_failure", False)), + lamella_state = MicroscopeState.__from_dict__(data.get("lamella_state", MicroscopeState().__to_dict__())), # tmp solution + landing_state = MicroscopeState.__from_dict__(data.get("landing_state", MicroscopeState().__to_dict__())), # tmp solution + landing_selected = bool(data.get("landing_selected", False)), ) + + def load_reference_image(self, fname) -> FibsemImage: + """Load a specific reference image for this lamella from disk + Args: + fname: str + the filename of the reference image to load + Returns: + adorned_img: AdornedImage + the reference image loaded as an AdornedImage + """ + + adorned_img = FibsemImage.load(os.path.join(self.path, f"{fname}.tif")) + + return adorned_img + + # convert to method + def get_reference_images(self, label: str) -> ReferenceImages: + reference_images = ReferenceImages( + low_res_eb=self.load_reference_image(f"{label}_low_res_eb"), + high_res_eb=self.load_reference_image(f"{label}_high_res_eb"), + low_res_ib=self.load_reference_image(f"{label}_low_res_ib"), + high_res_ib=self.load_reference_image(f"{label}_high_res_ib"), + ) + + return reference_images + class Experiment: - def __init__(self, path: Path, name: str = "AutoLamella", method="autolamella-default") -> None: + def __init__(self, path: Path = None, name: str = cfg.EXPERIMENT_NAME, program: str = "AutoLiftout", method: str = "AutoLiftout") -> None: + self.name: str = name self._id = str(uuid.uuid4()) @@ -129,7 +166,8 @@ def __init__(self, path: Path, name: str = "AutoLamella", method="autolamella-de self._created_at: float = datetime.timestamp(datetime.now()) self.positions: list[Lamella] = [] - self.program = "AutoLamella" + + self.program = program self.method = method def __to_dict__(self) -> dict: @@ -183,8 +221,21 @@ def __to_dataframe__(self) -> pd.DataFrame: "lamella.r": lamella.state.microscope_state.absolute_position.r, "lamella.t": lamella.state.microscope_state.absolute_position.t, "last_timestamp": lamella.state.microscope_state.timestamp, # dont know if this is the correct timestamp to use here + "current_stage": lamella.state.stage.name, } + if "autoliftout" in self.method: + ldict.update({ + "landing.x": lamella.landing_state.absolute_position.x, + "landing.y": lamella.landing_state.absolute_position.y, + "landing.z": lamella.landing_state.absolute_position.z, + "landing.r": lamella.landing_state.absolute_position.r, + "landing.t": lamella.landing_state.absolute_position.t, + "landing.coordinate_system": lamella.landing_state.absolute_position.coordinate_system, + "landing_selected": lamella.landing_selected, + "history: ": len(lamella.history),} + ) + exp_data.append(ldict) df = pd.DataFrame(exp_data) From b822bf99b76ad73c229f931a22ccdf72eba224e4 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Tue, 10 Oct 2023 14:35:14 +1100 Subject: [PATCH 33/39] bump version --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 091fdccb..ecc8e8e5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = autolamella -version = 0.2.5a0 +version = 0.2.5 author = Genevieve Buckley description = Automatated ion beam milling for cryo-electron microscopy sample preparation. long_description = file: README.md From 39c7f832239c5efe9f5c7f7f709ba7936d1d8e60 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Tue, 10 Oct 2023 17:16:31 +1100 Subject: [PATCH 34/39] migrate health monitor to fibsem --- autolamella/liftout/ui/README.md | 7 -- autolamella/tools/_parser.py | 72 ---------------- autolamella/tools/telemetry.py | 141 ------------------------------- 3 files changed, 220 deletions(-) delete mode 100644 autolamella/liftout/ui/README.md delete mode 100644 autolamella/tools/_parser.py delete mode 100644 autolamella/tools/telemetry.py diff --git a/autolamella/liftout/ui/README.md b/autolamella/liftout/ui/README.md deleted file mode 100644 index d2980e14..00000000 --- a/autolamella/liftout/ui/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# GUI - -Write changes from QT Designer to UI - -``` -pyuic5 main.ui - o main.py -``` \ No newline at end of file diff --git a/autolamella/tools/_parser.py b/autolamella/tools/_parser.py deleted file mode 100644 index 2b0f29c9..00000000 --- a/autolamella/tools/_parser.py +++ /dev/null @@ -1,72 +0,0 @@ - -import pandas as pd -import numpy as np - -def _parse_health_monitor_data(path: str) -> pd.DataFrame: - # PATH = "health-monitor/data2.csv" - - df = pd.read_csv(path, skiprows=5) - - # display(df) - - - # header = system - # row 0 = subsystem - # row 1 = component - # row 2 = parameter - # row 3 = unit - # row 4 = type - - # col 0 = date - # col 1 = timestamp - - df_headers = df.iloc[0:5, 2:] - df_data = df.iloc[6:, :] - - systems = df_headers.columns.values - subsystems = df_headers.iloc[0, :].values - components = df_headers.iloc[1, :].values - parameters = df_headers.iloc[2, :].values - units = df_headers.iloc[3, :].values - types = df_headers.iloc[4, :].values - - type_map = { - "Int": np.uint8, - "Float": np.float32, - "String": str, - "Boolean": bool, - "DateTime": np.datetime64, - } - - new_columns = ["Date", "Time"] - new_columns_type = ["datetime64", "datetime64"] - for subsystem, component, parameter, unit, type in zip(subsystems, components, parameters, units, types): - new_columns.append(f"{subsystem}.{component}.{parameter} ({unit})") - new_columns_type.append(type_map[type]) - - df_data.columns = new_columns - - # replace all values of "NaN" with np.nan - df_data = df_data.replace("NaN", np.nan) - - # drop columns with all NaN values - # df_data = df_data.dropna(axis=0, how="all") - # df_data = df_data.astype(dict(zip(new_columns, new_columns_type))) - - # combine date and time columns - df_data["datetime"] = pd.to_datetime(df_data["Date"] + " " + df_data["Time"]) - - # set timezone to Aus/Sydney for datetime column - # df_data["datetime"] = df_data["datetime"].dt.tz_localize("UTC").dt.tz_convert("Australia/Sydney") - - # drop Date and Time columns - df_data = df_data.drop(columns=["Date", "Time"]) - - - # print duplicate columns - # drop duplicate columns - df_data = df_data.loc[:,~df_data.columns.duplicated()] - print(df_data.columns[df_data.columns.duplicated()]) - - - return df_data diff --git a/autolamella/tools/telemetry.py b/autolamella/tools/telemetry.py deleted file mode 100644 index 147f3425..00000000 --- a/autolamella/tools/telemetry.py +++ /dev/null @@ -1,141 +0,0 @@ -import streamlit as st - -from autolamella.tools import _parser - -import plotly.express as px - - -st.set_page_config(layout="wide", page_title="AutoLamella Telemetry") -st.title("AutoLamella Telemetry") - - -DEFAULT_PATH = r"C:\Users\Admin\Github\fibsem\scratch\health-monitor\data2.csv" - -PATH = st.text_input("Path to telemetry data", DEFAULT_PATH) - -@st.cache_data -def _load_data(PATH): - return _parser._parse_health_monitor_data(PATH) - -df_data = _load_data(PATH) - - - -tabs = st.tabs(["Raw Data", "Filter Data", "Beam On/Off"]) - -with tabs[0]: - # st.write(df_data) - st.write("### RAW DATA ###") - -with tabs[1]: - - # FILTER BY SUBSYSTEM - st.write("### FILTER BY SUBSYSTEM ###") - - subsystems = df_data.columns.str.split(".").str[0].unique().tolist() - subsystem = st.selectbox("Select Subsystem", subsystems) - # also keep datetime column - subsystem_cols = ["datetime"] + [col for col in df_data.columns if subsystem in col] - - - # TODO: filter once only for all - - - df_subsystem = df_data[subsystem_cols] - # drop rows with all NaN values excluding datetime column - # drop columns with all NaN values excluding datetime column - df_subsystem = df_subsystem.dropna(axis=0, how="all", subset=df_subsystem.columns[1:]) - df_subsystem = df_subsystem.dropna(axis=1, how="all") - - # filter by component - components = df_subsystem.columns.str.split(".").str[1].unique().tolist() - - component_list = st.multiselect("Select Components", ["ALL"] + components, default=["ALL"]) - if "ALL" not in component_list: - component_cols = ["datetime"] - for comp in component_list: - component_cols += [col for col in df_subsystem.columns if comp in col ] - df_subsystem = df_subsystem[component_cols] - - - # filter by parameter - parameters = df_subsystem.columns.str.split(".").str[2].unique().tolist() - parameter_list = st.multiselect("Select Parameters", ["ALL"] + parameters, default=["ALL"]) - if "ALL" not in parameter_list: - parameter_cols = ["datetime"] - for param in parameter_list: - parameter_cols += [col for col in df_subsystem.columns if param in col ] - df_subsystem = df_subsystem[parameter_cols] - - - df_subsystem = df_subsystem.dropna(axis=0, how="all", subset=df_subsystem.columns[1:]) - df_subsystem = df_subsystem.dropna(axis=1, how="all") - - if len(df_subsystem) > 0: - - st.write(subsystem, component_list, parameter_list) - st.write(f"{len(df_subsystem)} rows, {len(df_subsystem.columns)-1} columns ({subsystem})") - st.write(df_subsystem) - - fig = px.line(df_subsystem, x="datetime", y=df_subsystem.columns[1:], title=f"Health Monitor Data - {subsystem}") - st.plotly_chart(fig, use_container_width=True) - else: - st.write("No data to display") - - -with tabs[2]: - - #### Beam Is On, Is Blanked #### - - fig_cols = st.columns(2) - - - # select columns with beam on and beam blanked - for filter_str in ["Beam Is On", "Is Blanked"]: - - cols = ["datetime"] + [col for col in df_data.columns if filter_str in col] # or "Beam Is On" in col - st.write(cols) - df_beam = df_data[cols] - - df_beam = df_beam.dropna(axis=0, how="all", subset=df_beam.columns[1:]) - df_beam = df_beam.dropna(axis=1, how="all") - - # fillna with the previous row values - df_beam = df_beam.fillna(method="ffill") - # calculate duration - df_beam["duration"] = df_beam["datetime"].diff().dt.total_seconds() - df_beam = df_beam.dropna(axis=0, how="any", subset=df_beam.columns[1:]) - # st.dataframe(df_beam) - - - # group by beam on and beam blanked - fib_columns = [col for col in df_beam.columns if "FIB" in col] - sem_columns = [col for col in df_beam.columns if "SEM" in col] - # st.write(fib_columns, sem_columns) - - df_groupby_fib = df_beam.groupby(fib_columns).agg({"duration": "sum"}).reset_index() - df_groupby_sem = df_beam.groupby(sem_columns).agg({"duration": "sum"}).reset_index() - - fig_cols[0].write(df_groupby_sem) - fig_cols[1].write(df_groupby_fib) - - # convert duration to hours - df_groupby_fib["duration"] = df_groupby_fib["duration"] / 3600 - df_groupby_sem["duration"] = df_groupby_sem["duration"] / 3600 - - - # plot as piecharts - - fig_fib = px.pie(df_groupby_fib, values="duration", title=f"FIB Beam {filter_str}", names=fib_columns[0], hover_data=df_groupby_fib.columns) - fig_sem = px.pie(df_groupby_sem, values="duration", title=f"SEM Beam {filter_str}", names=sem_columns[0], hover_data=df_groupby_sem.columns) - - # show names on figure - fig_fib.update_traces(textposition='inside', textinfo='percent+label') - fig_sem.update_traces(textposition='inside', textinfo='percent+label') - - - fig_cols[0].plotly_chart(fig_sem, use_container_width=True) - fig_cols[1].plotly_chart(fig_fib, use_container_width=True) - - - From a2027dd69e588475720cccbec09a06890629ea54 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 11 Oct 2023 13:31:39 +1100 Subject: [PATCH 35/39] fix: lamella creation path --- autolamella/liftout/autoliftout.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index 07199a09..e8f13bad 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -1002,7 +1002,7 @@ def select_initial_lamella_positions( # create lamella lamella_no = max(len(experiment.positions) + 1, 1) - lamella = Lamella(experiment.path, lamella_no) + lamella = Lamella(path=experiment.path, _number=lamella_no) log_status_message(lamella, "STARTED") # reference images From 9de9813ec46dec26a22482c0644e261bf08bee25 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 11 Oct 2023 17:16:06 +1100 Subject: [PATCH 36/39] modify base protocol depth --- autolamella/protocol/protocol-autoliftout-base.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/autolamella/protocol/protocol-autoliftout-base.yaml b/autolamella/protocol/protocol-autoliftout-base.yaml index f6c351c2..2aedf960 100644 --- a/autolamella/protocol/protocol-autoliftout-base.yaml +++ b/autolamella/protocol/protocol-autoliftout-base.yaml @@ -11,7 +11,7 @@ flatten: type: "Rectangle" trench: stages: - - depth: 4.0e-6 + - depth: 2.0e-6 hfw: 8.0e-05 lamella_height: 9.999999999999999e-06 lamella_width: 4.0e-05 @@ -25,7 +25,7 @@ trench: trench_height: 1.2e-05 application_file: "autolamella" type: "Horseshoe" - - depth: 3.0e-6 + - depth: 2.0e-6 hfw: 8.0e-05 lamella_height: 9.999999999999999e-06 lamella_width: 4.0e-05 From 7bd5d4029f91ec4281bc6aa17dd1add097db1910 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Thu, 12 Oct 2023 11:42:38 +1100 Subject: [PATCH 37/39] update protocol --- autolamella/liftout/ui/AutoLiftoutUIv2.py | 1 + autolamella/protocol/protocol-autoliftout-base.yaml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index 353e70a6..6af83c70 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -682,6 +682,7 @@ def _threaded_worker(self, microscope, settings, experiment, workflow="setup"): _METHOD = self.settings.protocol.get("method", "autoliftout-default") if _METHOD == "autoliftout-default": + settings.image.gamma_enabled = True self.experiment = autoliftout.run_autoliftout_workflow( microscope=microscope, settings=settings, diff --git a/autolamella/protocol/protocol-autoliftout-base.yaml b/autolamella/protocol/protocol-autoliftout-base.yaml index 2aedf960..1e759cac 100644 --- a/autolamella/protocol/protocol-autoliftout-base.yaml +++ b/autolamella/protocol/protocol-autoliftout-base.yaml @@ -41,8 +41,8 @@ trench: type: "Horseshoe" ml: encoder: resnet34 - num_classes: 3 - checkpoint: openfibsem-baseline-34.pt + num_classes: 5 + checkpoint: autolamella-mega-01-nc5-34.pt name: autoliftout-base-protocol method: autoliftout-default options: From bc297cfbf6440549a40005e7cae29391c7c57536 Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 18 Oct 2023 11:14:26 +1100 Subject: [PATCH 38/39] bump protocols --- autolamella/protocol/protocol-autoliftout-base.yaml | 2 +- autolamella/protocol/protocol-serial-liftout.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/autolamella/protocol/protocol-autoliftout-base.yaml b/autolamella/protocol/protocol-autoliftout-base.yaml index 1e759cac..a28ad163 100644 --- a/autolamella/protocol/protocol-autoliftout-base.yaml +++ b/autolamella/protocol/protocol-autoliftout-base.yaml @@ -42,7 +42,7 @@ trench: ml: encoder: resnet34 num_classes: 5 - checkpoint: autolamella-mega-01-nc5-34.pt + checkpoint: autolamella-mega-latest.pt name: autoliftout-base-protocol method: autoliftout-default options: diff --git a/autolamella/protocol/protocol-serial-liftout.yaml b/autolamella/protocol/protocol-serial-liftout.yaml index 181dc239..af1167be 100644 --- a/autolamella/protocol/protocol-serial-liftout.yaml +++ b/autolamella/protocol/protocol-serial-liftout.yaml @@ -27,7 +27,7 @@ trench: ml: encoder: resnet34 num_classes: 5 - checkpoint: autoliftout-serial-01-34.pt + checkpoint: autolamella-mega-latest.pt name: autoliftout-serial-protocol method: autoliftout-serial-liftout options: From 18fc3850e3575a0dc9e89f800ee0f95a2521d58b Mon Sep 17 00:00:00 2001 From: Patrick Cleeve Date: Wed, 18 Oct 2023 12:13:20 +1100 Subject: [PATCH 39/39] add ui calibrate maniplator --- autolamella/liftout/autoliftout.py | 44 +++++++++----------- autolamella/liftout/ui/AutoLiftoutUIv2.py | 39 ++++++++++++++++- autolamella/liftout/ui/qt/AutoLiftoutUIv2.py | 8 ++++ autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui | 12 ++++++ 4 files changed, 77 insertions(+), 26 deletions(-) diff --git a/autolamella/liftout/autoliftout.py b/autolamella/liftout/autoliftout.py index e8f13bad..99b51136 100644 --- a/autolamella/liftout/autoliftout.py +++ b/autolamella/liftout/autoliftout.py @@ -1219,36 +1219,30 @@ def validate_needle_insertion( +# -# TODO: MOVE TO FIBSEM -def _calculate_fiducial_area_v2(image: FibsemImage, fiducial_centre: Point, fiducial_length:float)->tuple[FibsemRectangle, bool]: - pixelsize = image.metadata.pixel_size.x - - fiducial_centre.y = -fiducial_centre.y - fiducial_centre_px = conversions.convert_point_from_metres_to_pixel( - fiducial_centre, pixelsize - ) +def _prepare_manipulator_autoliftout(microscope: FibsemMicroscope, settings: MicroscopeSettings, parent_ui: AutoLiftoutUIv2): - rcx = fiducial_centre_px.x / image.metadata.image_settings.resolution[0] + 0.5 - rcy = fiducial_centre_px.y / image.metadata.image_settings.resolution[1] + 0.5 + # tilt stage flat - fiducial_length_px = ( - conversions.convert_metres_to_pixels(fiducial_length, pixelsize) * 1.5 # SCALE_FACTOR - ) - h_offset = fiducial_length_px / image.metadata.image_settings.resolution[0] / 2 - v_offset = fiducial_length_px / image.metadata.image_settings.resolution[1] / 2 + # move needle to the centre + + # detect tip + + # create rectangle pattern at tip - left = rcx - h_offset - top = rcy - v_offset - width = 2 * h_offset - height = 2 * v_offset + # mill - if left < 0 or (left + width) > 1 or top < 0 or (top + height) > 1: - flag = True - else: - flag = False + return + + +def _prepare_manipulator_serial_liftout(microscope: FibsemMicroscope, settings: MicroscopeSettings, parent_ui: AutoLiftoutUIv2): - fiducial_area = FibsemRectangle(left, top, width, height) + return + +PREPARE_MANIPULATOR_WORKFLOW = { + "autoliftout": _prepare_manipulator_autoliftout, + "serial-lfitout": _prepare_manipulator_serial_liftout +} - return fiducial_area, flag \ No newline at end of file diff --git a/autolamella/liftout/ui/AutoLiftoutUIv2.py b/autolamella/liftout/ui/AutoLiftoutUIv2.py index 6af83c70..e0fadcb5 100644 --- a/autolamella/liftout/ui/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/AutoLiftoutUIv2.py @@ -102,7 +102,9 @@ def setup_connections(self): self.actionLoad_Protocol.triggered.connect(self.load_protocol) self.actionSave_Protocol.triggered.connect(self.update_protocol_from_ui) self.actionCryo_Sputter.triggered.connect(self._cryo_sputter) - + self.actionCalibrate_Manipulator.triggered.connect(lambda: self._run_workflow(workflow="calibrate-manipulator")) + self.actionPrepare_Manipulator.triggered.connect(lambda: self._run_workflow(workflow="prepare-manipulator")) + # protocol self.pushButton_update_protocol.clicked.connect(self.update_protocol_from_ui) self.comboBox_protocol_method.addItems(cfg.__AUTOLIFTOUT_METHODS__) @@ -188,6 +190,8 @@ def update_ui(self): self.actionLoad_Protocol.setVisible(_experiment_loaded) self.actionSave_Protocol.setVisible(_protocol_loaded) self.actionCryo_Sputter.setVisible(_protocol_loaded) + self.actionCalibrate_Manipulator.setVisible(_protocol_loaded) + self.actionPrepare_Manipulator.setVisible(_protocol_loaded) # workflow buttons _SETUP_ENABLED = _microscope_connected and _protocol_loaded @@ -502,6 +506,28 @@ def setup_experiment(self) -> None: napari.utils.notifications.show_info( f"Experiment {self.experiment.name} loaded." ) + + # TODO: enable this + # register metadata + # if fcfg._REGISTER_METADATA: + # import autolamella #NB: microscope needs to be connected beforehand + # futils._register_metadata( + # microscope=self.microscope, + # application_software="autolamella", + # application_software_version=autolamella.__version__, + # experiment_name=self.experiment.name, + # experiment_method = "autoliftout") # TODO: add method to experiment + + # # automatically re-load protocol if available + if not new_experiment and self.settings is not None: + # try to load protocol from file + PROTOCOL_PATH = os.path.join(self.experiment.path, "protocol.yaml") + if os.path.exists(PROTOCOL_PATH): + self.settings.protocol = futils.load_protocol(protocol_path=PROTOCOL_PATH) + self._PROTOCOL_LOADED = True + self.update_ui_from_protocol(self.settings.protocol) + + self.update_ui() def load_protocol(self): @@ -715,6 +741,17 @@ def _threaded_worker(self, microscope, settings, experiment, workflow="setup"): experiment=experiment, parent_ui=self, ) + elif workflow == "calibrate-manipulator": + from fibsem import calibration + calibration._calibrate_manipulator_thermo(microscope = microscope, settings = settings, parent_ui = self) + + napari.utils.notification.show_info(f"Calibrated Manipulator") + + elif workflow == "prepare-manipulator": + + _METHOD = self.settings.protocol.get("method", "autoliftout-default") + napari.utils.notification.show_warning(f"Prepare Manipulator ({_METHOD}) is Not Yet Implemented") + else: raise ValueError(f"Unknown workflow: {workflow}") diff --git a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py index 35eda0d0..8f974b6f 100644 --- a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py +++ b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.py @@ -240,11 +240,17 @@ def setupUi(self, MainWindow): self.actionSave_Protocol.setObjectName("actionSave_Protocol") self.actionCryo_Sputter = QtWidgets.QAction(MainWindow) self.actionCryo_Sputter.setObjectName("actionCryo_Sputter") + self.actionCalibrate_Manipulator = QtWidgets.QAction(MainWindow) + self.actionCalibrate_Manipulator.setObjectName("actionCalibrate_Manipulator") + self.actionPrepare_Manipulator = QtWidgets.QAction(MainWindow) + self.actionPrepare_Manipulator.setObjectName("actionPrepare_Manipulator") self.menuFile.addAction(self.actionNew_Experiment) self.menuFile.addAction(self.actionLoad_Experiment) self.menuFile.addAction(self.actionLoad_Protocol) self.menuFile.addAction(self.actionSave_Protocol) self.menuTools.addAction(self.actionCryo_Sputter) + self.menuTools.addAction(self.actionCalibrate_Manipulator) + self.menuTools.addAction(self.actionPrepare_Manipulator) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuTools.menuAction()) @@ -305,3 +311,5 @@ def retranslateUi(self, MainWindow): self.actionConnect_Microscope.setText(_translate("MainWindow", "Connect Microscope")) self.actionSave_Protocol.setText(_translate("MainWindow", "Save Protocol")) self.actionCryo_Sputter.setText(_translate("MainWindow", "Cryo Sputter")) + self.actionCalibrate_Manipulator.setText(_translate("MainWindow", "Calibrate Manipulator")) + self.actionPrepare_Manipulator.setText(_translate("MainWindow", "Prepare Manipulator")) diff --git a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui index 5132ec11..b2aa7c0e 100644 --- a/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui +++ b/autolamella/liftout/ui/qt/AutoLiftoutUIv2.ui @@ -452,6 +452,8 @@ Tools + + @@ -492,6 +494,16 @@ Cryo Sputter + + + Calibrate Manipulator + + + + + Prepare Manipulator + +