diff --git a/EmblModule.py b/EmblModule.py deleted file mode 100755 index 7f54300..0000000 --- a/EmblModule.py +++ /dev/null @@ -1,445 +0,0 @@ -import logging -import numpy -import os -import random -import struct -import time - -import yaml -#from scipy.misc import bytescale - -import zmq -from os.path import join -from pathlib import Path - -#import qsingleton #ZAC: orig. code -#from CoordinatesModel import CoordinatesModel #ZAC: orig. code -from app_config import AppCfg #settings, option, appsconf - -EMBL_RESULTS_TIMEOUT = "embl/results_timeout" - -EMBL_SAVE_FILES = "embl/save_files" - -#embl = appsconf["embl"] - -#import imageio -import numpy as np -from PyQt5 import QtCore -from PyQt5.QtCore import pyqtSignal, Qt, QObject, pyqtSlot, QPoint -from PyQt5.QtGui import QStandardItemModel, QCursor -from PyQt5.QtWidgets import ( - QWidget, - QVBoxLayout, - QHeaderView, - QPushButton, - QFormLayout, - QDoubleSpinBox, - QLabel, - QTableWidgetItem, - QLineEdit, - QTableWidget, - QTextEdit, - QProgressBar, - QHBoxLayout, - QSpinBox, - QTabWidget, - QTableView, - QMenu, - QProgressDialog, -) - -#import storage -from app_utils import assert_motor_positions - -#folders = storage.Folders() - -import logging -logger = logging.getLogger(__name__) - - -class EmblTaskResultTimeoutException(Exception): - pass - - -ZPOS, FPATH = range(2) - -# record separator -RS = 0x1e - - -#class EmblMessage(QObject, metaclass=qsingleton.Singleton): #ZAC: orig. code -class EmblMessage(QObject): - - def __init__(self, parent=None, **kwargs): - super(EmblMessage, self).__init__(parent, **kwargs) - return #ZAC: orig. code - if not embl["enabled"]: - return - context = zmq.Context() - logger.info("Connecting to server...") - self.socket = context.socket(zmq.REQ) - uri = embl["uri"] - logger.info(f"EMBL alignment server at: {uri}") - self.socket.connect(uri) - - def make_PAR(self, min: float, max: float, step: float, ppm: int, beam_xy: tuple): - puckid, sampleid = folders._prefix.split("_") - beam_x, beam_y = beam_xy - msg = ( - f"PAR{RS:c}{min}{RS:c}{max}{RS:c}{step}{RS:c}{ppm}{RS:c}{beam_x:.0f}{RS:c}{beam_y:.0f}{RS:c}{puckid}{RS:c}{sampleid}" - ) - logger.debug(f"PAR = {msg}") - self.socket.send_string(msg) - ans = self.socket.recv_string() - - def make_IMG(self, pos: float, img): - width, height = img.shape - msg = f"IMG{RS:c}{pos:.3f}{RS:c}{width}{RS:c}{height}" - logger.info(f"sending img header: {msg}") - self.socket.send_string(msg) - self.socket.recv_string() - logger.info( - f"about to send img shape={img.shape} type={img.dtype} pos = {pos} mm" - ) - self.socket.send(numpy.ascontiguousarray(img)) - logger.info(f"waiting for recv") - ans = self.socket.recv_string() - logger.info(f"received!") - - def finished(self): - self.make_STS("Finished") - - def aborted(self): - self.make_STS("Aborted") - - def make_STS(self, status): - msg = f"STS{RS:c}{status}" - self.socket.send_string(msg) - ans = self.socket.recv_string() - - def make_RES(self): - n = 1 - timeout = settings.value(EMBL_RESULTS_TIMEOUT, type=float) + time.time() - result = "failed" - while time.time() < timeout: - time.sleep(2.0) - logger.info(f"#{n}.requesting RES") - self.socket.send_string("RES") - result = self.socket.recv_string() - logger.info(f" RES = {result}") - if "Pending" != result: - break - n += 1 - return result - - -embl_tube = EmblMessage() - - -class EmblWidget(QWidget): - - def __init__(self, parent): - super(EmblWidget, self).__init__(parent) - - #parent.pixelsPerMillimeter.connect(self.save_ppm) - #parent.beamCameraCoordinatesChanged.connect(self.save_beam_coordinates) - self.setLayout(QVBoxLayout()) - - w = QWidget() - self.layout().addWidget(w) - w.setLayout(QFormLayout()) - w.layout().setLabelAlignment(Qt.AlignRight) - - self._startZ = QDoubleSpinBox() - self._startZ.setValue(0.6) - self._startZ.setSuffix(" mm") - self._startZ.setRange(-5, 5) - self._startZ.setSingleStep(0.1) - self._startZ.setDecimals(3) - - self._endZ = QDoubleSpinBox() - self._endZ.setValue(1.4) - self._endZ.setSuffix(" mm") - self._endZ.setRange(-5, 5) - self._endZ.setSingleStep(0.1) - self._endZ.setDecimals(3) - - self._stepZ = QDoubleSpinBox() - self._stepZ.setValue(0.050) - self._stepZ.setSuffix(" mm") - self._stepZ.setRange(0.005, 1.000) - self._stepZ.setSingleStep(0.010) - self._stepZ.setDecimals(3) - - self._resultsTimeout = QDoubleSpinBox() - self._resultsTimeout.setRange(1., 2000.) - self._resultsTimeout.setValue(60) - self._resultsTimeout.setSuffix(" seconds") - self._resultsTimeout.setDecimals(0) - - self._factors = QLineEdit("1 1 1") - but = QPushButton("update results") - but.clicked.connect(self.apply_factors) - - w.layout().addRow(QLabel("Start Z"), self._startZ) - w.layout().addRow(QLabel("End Z"), self._endZ) - w.layout().addRow(QLabel("Step"), self._stepZ) - w.layout().addRow(QLabel("Task Result Timeout"), self._resultsTimeout) - w.layout().addRow(QLabel("Factors"), self._factors) - w.layout().addRow(QLabel("Apply Factors"), but) - - - but = QPushButton("Scan Z") - but.clicked.connect(self.executeScan) - but.setAccessibleName("emblScanZ") - self.layout().addWidget(but) - - tabs = QTabWidget(self) - self.layout().addWidget(tabs) - - self._table = QTableWidget() - self._table.setColumnCount(2) - self._table.setHorizontalHeaderLabels(("Z (mm)", "File Path")) - self._table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.layout().addWidget(self._table) - tabs.addTab(self._table, "Z Scans") - tabs.setAccessibleName("embl_tabs") - tabs.setObjectName("embl_tabs") - - view = self._results_view = QTableView(self) - #view.setModel(CoordinatesModel()) #ZAC: orig. code - view.verticalHeader().show() - view.horizontalHeader().show() - view.setContextMenuPolicy(Qt.CustomContextMenu) - view.customContextMenuRequested.connect(self.results_menu) - tabs.addTab(view, "Results") - self._tabs = tabs - - def apply_factors(self): - self.populate_results(self._results) - - @pyqtSlot(float) - def save_ppm(self, ppm: float): - self._ppm = int(ppm) - - @pyqtSlot(float, float) - def save_beam_coordinates(self, bx: float, by: float): - logger.debug(f"saving beam_xy {bx} & {by}") - self._beam_xy = (int(bx), int(by)) - - @pyqtSlot(QPoint) - def results_menu(self, at_point): - table = self.sender() - model = table.model() - - index = table.indexAt(at_point) - if not index.isValid(): - return - coords = model.coords_at(index) - logger.debug(f"coord: {coords}") - menu = QMenu(table) - - gotoAction = menu.addAction("Go here") - if menu.exec_(QCursor.pos()) is gotoAction: - logger.info(f"going to: {index.row()} => {coords}") - self.goto_position(coords) - - def configure(self, motors, camera, zoom_device): - self._camera = camera - self._zoom_device = zoom_device - self.motors = motors - - def executeScan(self): - fx, fy, cx, cz, omega = self.motors - - x, y, z = fx.get_position(), fy.get_position(), cz.get_position() - logger.info(f"scan started at gonio: x,y,z = {x}, {y}, {z}") - - self._table.setRowCount(0) # clear previous information - - zs = self._startZ.value() - ze = self._endZ.value() - step = self._stepZ.value() - scan_config = { - "z-start": zs, - "z-end": ze + step, # inclusive last value - "z-step": step, - "ppm": self._ppm, - "beam_xy": self._beam_xy, - } - - self._gonio_at_start = (x, y, ze + step) - - base_Z = self.motors[3] # base_Z - camera = self._camera - - zvals = np.arange(zs, ze, step) - numZs = len(zvals) - - dlg = QProgressDialog(self) - dlg.setWindowModality(Qt.WindowModal) - dlg.setMinimumDuration(0) - dlg.setCancelButton(None) - dlg.setRange(0, 0) - dlg.setLabelText(f"EMBL Z-Scan
") - dlg.setAutoClose(True) - dlg.show() - dlg.setValue(random.randint(1, 20)) - self._progress_dialog = dlg - - self._acq_thread = AcquisitionThread(base_Z, camera, scan_config) - self._acq_thread.image_acquired.connect(self.addImage) - self._acq_thread.acquisition_finished.connect(self.acquisition_finished) - self._acq_thread.results_fetched.connect(self.populate_results) - self._acq_thread.message.connect( - lambda msg: dlg.setLabelText(f"EMBL Z-Scan
{msg}") - ) - self._acq_thread.start() - - def createModel(self, parent): - model = QStandardItemModel(0, 2, parent) - model.setHeaderData(ZPOS, QtCore.Qt.Horizontal, "Z (mm)") - model.setHeaderData(FPATH, QtCore.Qt.Horizontal, "Image Path") - self._model = model - return model - - def addImage(self, idx, zpos, fpath): - logger.info("zpos = {}, fpath = {}".format(zpos, fpath)) - rows = self._table.rowCount() - # table.setRowCount(rows + 1) - self._table.insertRow(rows) - item = QTableWidgetItem() - item.setText("{:.03f}".format(zpos)) - self._table.setItem(rows, ZPOS, item) - item = QTableWidgetItem() - item.setText(str(fpath)) - self._table.setItem(rows, FPATH, item) - self._table.resizeColumnsToContents() - - def acquisition_finished(self): - self._progress_dialog.reset() - - def goto_position(self, coords): - fx, fy, cx, cz, o = self.motors - tx, ty, bb, tz, to = coords - - logger.info(f"moving gonio to: {tx}, {ty}, {tz}") - fx.move(tx, wait=True, ignore_limits=True) - fy.move(ty, wait=True, ignore_limits=True) - cz.move(tz, wait=True, ignore_limits=True) - - @pyqtSlot(str) - def populate_results(self, results): - """Results.txt - 60.624%363.4026940025185%-768.32%-1052.52 - - angle between sample and camera, x, y, z - - :return: - """ - if "no results" in results: - return - - s1, s2, s3 = [int(c) for c in self._factors.text().split()] - - self._results = results - self.coords = [] - ox, oy, oz = self._gonio_at_start - - oz = self._endZ.value() - - for n, line in enumerate(results.split("\n")): - # o, z, y, x = [float(n) for n in line.split("%")] - omega, x, y, z = [float(n) for n in line.split("%")] - no, nx, ny, nz = [omega, ox + s1*x, oy + s2*y, oz + s3*z] - - self.coords.append([nx, ny, 0, nz, no]) - model = self._results_view.model() - model.update_coordinates(self.coords) - self._tabs.setCurrentIndex(1) - - -class AcquisitionThread(QtCore.QThread): - - image_acquired = pyqtSignal(int, float, str) - results_fetched = pyqtSignal(str) - message = pyqtSignal(str) - acquisition_finished = pyqtSignal() - - def __init__(self, z_motor, camera, scan_config): - QtCore.QThread.__init__(self) - self._scanconfig = scan_config - logger.debug(f"scanconfig: {scan_config}") - self.z_motor = z_motor - self.camera = camera - - def save_params(self, params): - fname = Path(folders.res_folder) / "z_scan" / "parameters.yaml" - - try: - with open(fname, "w") as fp: - yaml.dump(params, fp) - except: - logger.warning(f"failed to save z-scan parameter file: {fname}") - - def save_image(self, n, z, img): - if not option(EMBL_SAVE_FILES): - return - zp = f"{n:02d}_Z{z:.3f}".replace(".", "p") + ".png" - fname = Path(folders.res_folder) / "z_scan" / zp - try: - imageio.imsave(fname, img) - except: - logger.error(f"failed to write: {fname}") - return f"failed to write image {n}" - return fname - - def save_result(self, result): - if not option(EMBL_SAVE_FILES): - return - fname = Path(folders.res_folder) / "z_scan" / "result.txt" - with open(fname, "w") as fp: - fp.write(result) - - def make_folders(self): - if not option(EMBL_SAVE_FILES): - return - fold = Path(folders.res_folder) / "z_scan" - fold.mkdir(parents=True, exist_ok=True) - - def run(self): - self.make_folders() - cnf = self._scanconfig - zmin, zmax, zstep = cnf["z-start"], cnf["z-end"], cnf["z-step"] - zvals = np.arange(zmin, zmax, zstep) - num = len(zvals) - - logger.debug( - f"Z-scan: min/max/step {zmin}/{zmax}/{zstep} ppm={cnf['ppm']} beam_xy={cnf['beam_xy']}" - ) - logger.info(f"Z-vals: {', '.join([f'{z:.2f}' for z in zvals])}") - self.save_params(cnf) - embl_tube.make_PAR(zmin, zmax, zstep, cnf["ppm"], cnf["beam_xy"]) - - for n, z in enumerate(zvals): - idx = n + 1 - self.message.emit(f"{idx}/{num} Z ➠ {z:.2f}") - self.z_motor.move(z, ignore_limits=True, wait=True) - assert_motor_positions([(self.z_motor, z, 0.1)], timeout=3.) - self.message.emit(f"{idx}/{num} acquiring") - img = self.camera.get_image() - self.message.emit(f"{idx}/{num} acquired") - img = np.rot90(img, 1) - img = bytescale(img) - fname = self.save_image(idx, z, img) - self.image_acquired.emit(idx, z, str(fname)) # just to populate table - self.message.emit(f"{idx}/{num} sending") - embl_tube.make_IMG(z, img) - self.message.emit(f"{idx}/{num} sent") - self.message.emit(f"acquisition finished") - embl_tube.finished() - self.message.emit(f"waiting for results") - result = embl_tube.make_RES() - self.save_result(result) - self.results_fetched.emit(result) - self.acquisition_finished.emit() diff --git a/HelicalTable.py b/HelicalTable.py deleted file mode 100644 index 8c07bba..0000000 --- a/HelicalTable.py +++ /dev/null @@ -1,256 +0,0 @@ -import sys -import os -import logging -import csv -from PyQt5 import QtCore, QtGui - -import numpy as np - -logger = logging.getLogger("helical") - -from PyQt5.QtWidgets import ( - QTableWidget, - QApplication, - QMainWindow, - QTableWidgetItem, - QFileDialog, - QHeaderView, - QAbstractItemView, - QMenu) -from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal, QPoint, pyqtSlot - -DATA_ITEM = 1 - -START_OMEGA_0 = 0 -START_OMEGA_120 = 1 -START_OMEGA_240 = 2 -STOP_OMEGA_0 = 3 -STOP_OMEGA_120 = 4 -STOP_OMEGA_240 = 5 - -ROLE_XTAL_START = 1 + Qt.UserRole -ROLE_XTAL_END = 2 + Qt.UserRole - - -class HelicalTableWidget(QTableWidget): - gonioMoveRequest = pyqtSignal(float, float, float, float, float) - def __init__(self): - super().__init__() - self.check_change = True - self._scanAngularStep = 0.1 - self._scanHorizontalCount = 5 - self._scanVerticalCount = 10 - self._current_xtal = None - self._start_angle = 0.0 - self.init_ui() - - def startAngle(self) -> float: - return self._start_angle - - @pyqtSlot(float) - def setStartAngle(self, angle:float): - self._start_angle = angle - - def init_ui(self): - self.setColumnCount(6) - self.setEditTriggers(QAbstractItemView.NoEditTriggers) - self.resizeColumnsToContents() - self.setSelectionMode(QAbstractItemView.SingleSelection) - self.setSelectionBehavior(QAbstractItemView.SelectItems) - labels = [ - "0\nbx, bz\n(mm)", - "120\nbx, bz\n(mm)", - "240\nbx, bz\n(mm)", - "0\nbx, bz\n(mm)", - "120\nbx, bz\n(mm)", - "240\nbx, bz\n(mm)", - ] - self.setHorizontalHeaderLabels(labels) - - self.verticalHeader().resizeSections(QHeaderView.ResizeToContents) - self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - - self.cellChanged.connect(self.c_current) - self.show() - - def display_coords(self, x, y): - row = self.rowAt(y) - col = self.columnAt(x) - coords = self.gonio_coords_at(row, col) - omega = col % 3 * 120 - data = coords[omega] - logger.info("gonio at {}, {}: {}".format(row, col, data)) - - def goto_gonio_position(self, x, y): - row = self.rowAt(y) - col = self.columnAt(x) - coords = self.gonio_coords_at(row, col) - omega = col % 3 * 120 - data = coords[omega] - logger.info("move gonio to: {}".format(row, col, data)) - self.gonioMoveRequest.emit(*data) - - def remove_xtal(self, x, y): - row = self.rowAt(y) - col = self.columnAt(x) - logger.info("rowCount() = {}, removing row: {}".format(self.rowCount(), row)) - self.removeRow(row) - if self.rowCount() == 0: - self._current_xtal = None - logger.info("rowCount() = {}".format(self.rowCount())) - - def contextMenuEvent(self, event): - logger.info(event.pos()) - x = event.pos().x() - y = event.pos().y() - menu = QMenu(self) - gotoAction = menu.addAction("Move Gonio Here") - gotoAction.triggered.connect(lambda b: self.goto_gonio_position(x, y)) - removeAction = menu.addAction("Remove this line") - removeAction.triggered.connect(lambda b: self.remove_xtal(x, y)) - menu.popup(QtGui.QCursor.pos()) - - def setScanHorizontalCount(self, count: int): - logger.debug("horizontal count: {}".format(count)) - self._scanHorizontalCount = count - - def scanHorizontalCount(self) -> int: - return self._scanHorizontalCount - - def setScanVerticalCount(self, count: int): - logger.debug("vertical count: {}".format(count)) - self._scanVerticalCount = count - - def scanVerticalCount(self) -> int: - return self._scanVerticalCount - - def setScanAngularStep(self, step: float): - self._scanAngularStep = step - - def scanAngularStep(self) -> float: - return self._scanAngularStep - - def scanTotalRange(self) -> float: - return self._scanVerticalCount * self._scanHorizontalCount * self._scanAngularStep - - def gonio_coords_at(self, row, col): - role = ROLE_XTAL_START if col < 3 else ROLE_XTAL_END - coords = self.item(row, DATA_ITEM).data(role) - return coords - - def add_xtal(self): - row = self.rowCount() - self.setRowCount(row + 1) - self._current_xtal = row - print(row) - for n in range(self.columnCount()): - self.setItem(row, n, QTableWidgetItem("unset")) - - - def set_xtal_start(self, data: list): - """sets data to start position - - data = [fx, fy, bx, bz, omega] - - """ - self.set_data_point(ROLE_XTAL_START, data) - - def set_xtal_end(self, data: list): - self.set_data_point(ROLE_XTAL_END, data) - - def set_data_point(self, role: int, data: list): - if self._current_xtal is None: - self.add_xtal() - row, col = self._current_xtal, DATA_ITEM - - try: - coords = self.item(row, DATA_ITEM).data(role) - except: - print("empty coords; initializing...") - coords = None - - if coords is None: - coords = {} - - fx, fy, bx, bz, omega = data - o = int(omega) - coords[o] = data - print("coords = {}".format(coords)) - - if role == ROLE_XTAL_END: - col = 3 - else: - col = 0 - - for n in range(3): - omega = n * 120 - try: - fx, fy, bx, bz, omega = coords[omega] - info = "{bx:.3f} mm\n{bz:.3f} mm".format(bx=bx, bz=bz) - except: - info = "unset" - # self.item(row, col + n).setData(Qt.DisplayRole, info) - self.item(row, col + n).setText(info) - self.item(row, col + n).setToolTip(info) - - self.item(row, DATA_ITEM).setData(role, coords) - - def c_current(self): - if self.check_change: - row = self.currentRow() - col = self.currentColumn() - value = self.item(row, col) - # value = value.text() - - def load_datapoints(self): - self.check_change = False - path = QFileDialog.getOpenFileName( - self, "Open CSV", os.getenv("HOME"), "CSV(*.csv)" - ) - if path[0] != "": - with open(path[0], newline="") as csv_file: - self.setRowCount(0) - self.setColumnCount(10) - my_file = csv.reader(csv_file, delimiter=",", quotechar="|") - for row_data in my_file: - row = self.rowCount() - self.insertRow(row) - if len(row_data) > 10: - self.setColumnCount(len(row_data)) - for column, stuff in enumerate(row_data): - item = QTableWidgetItem(stuff) - self.setItem(row, column, item) - self.check_change = True - - def get_data(self, as_numpy=False): - """return a list of tuples with all defined data - - [ - (is_fiducial(boolean), x, y, gonio_x, gonio_y),... - ] - """ - data = [] - - for row in range(self.rowCount()): - start = self.item(row, DATA_ITEM).data(ROLE_XTAL_START) - end = self.item(row, DATA_ITEM).data(ROLE_XTAL_END) - - data.append([start, end]) - # if as_numpy: - # data = np.asarray(data) - return data - - -if __name__ == "__main__": - - class Sheet(QMainWindow): - def __init__(self): - super().__init__() - - self.form_widget = HelicalTableWidget() - self.setCentralWidget(self.form_widget) - self.show() - - app = QApplication(sys.argv) - sheet = Sheet() - sys.exit(app.exec_()) diff --git a/Makefile b/Makefile index 4c6784e..fb6d60c 100644 --- a/Makefile +++ b/Makefile @@ -22,12 +22,6 @@ init: -ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/PBTools.git $(APP)/SwissMX/PBTools' -ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/ppmac.git $(APP)/SwissMX/PBTools/ppmac' -rsync -vai simCamImg $(REMOTE):$(APP)/SwissMX/ -# -rsync -vai ../../PBTools $(REMOTE):$(APP)/SwissMX/ -# -ssh $(REMOTE) 'git clone -o psigithub git@git.psi.ch:epics_support_apps/PBTools.git $(APP)/PBTools' -# ssh $(REMOTE) 'pip3.6 install --user pandas zmq qtawesome' -# ssh $(REMOTE) '/opt/gfa/python-3.8/latest/bin/pip install --user pandas zmq qtawesome' -# ssh $(REMOTE) 'pip3.6 install --prefix /sf/cristallina/applications/SwissMX/module pandas zmq qtawesome' -# ssh $(REMOTE) '/opt/gfa/python-3.8/latest/bin/pip install --prefix /sf/cristallina/applications/SwissMX/module pandas zmq qtawesome' update: ssh $(REMOTE) 'cd $(APP)/SwissMX && git fetch psigithub && git reset psigithub/master --hard' diff --git a/ModuleFixTarget.py b/ModuleFixTarget.py index 2e01ba2..85d2f52 100644 --- a/ModuleFixTarget.py +++ b/ModuleFixTarget.py @@ -13,54 +13,17 @@ This contains a Widget to handle FixTargetFrames and fiducials, calculate final #https://stackoverflow.com/questions/27909658/json-encoder-and-decoder-for-complex-numpy-arrays -# import yaml -# class Dice(tuple): -# def __new__(cls, a, b): -# return tuple.__new__(cls, [a, b]) -# def __repr__(self): -# return "Dice(%s,%s)" % self -# d=Dice(3,6) -# print(d) -# print(yaml.dump(d)) -# def dice_representer(dumper, data): -# return dumper.represent_scalar(u'!dice', u'%sd%s' % data) -# yaml.add_representer(Dice, dice_representer) -# def dice_constructor(loader, node): -# value = loader.construct_scalar(node) -# a, b = map(int, value.split('d')) -# return Dice(a, b) -# yaml.add_constructor(u'!dice', dice_constructor) -# print(yaml.load("initial hit points: !dice 8d4")) - import logging _log=logging.getLogger(__name__) -import json, base64 #, os, pickle, yaml +import json, base64 import numpy as np import pyqtUsrObj as UsrGO import pyqtgraph as pg -from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal, pyqtSlot +from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal from PyQt5.QtWidgets import ( - QTableWidgetItem, - QFileDialog, - QGroupBox, - QWidget, - QGridLayout, - QTableWidget, - QAbstractItemView, - QItemDelegate, - QVBoxLayout, - QLabel, - QPushButton, - QApplication, - QMainWindow, - QHeaderView, - QLineEdit, - QSpinBox, - QMessageBox, - QAction, - QComboBox, - QCheckBox) + QFileDialog, QWidget, QGridLayout, QItemDelegate, QVBoxLayout, QPushButton, QApplication, + QMainWindow, QLineEdit, QMessageBox, QAction, QComboBox) class MyJsonEncoder(json.JSONEncoder): @@ -109,8 +72,6 @@ class MarkerDelegate(QItemDelegate): return comboBox def setEditorData(self, editor, index): - # pos = comboBox.findText(index.model().data(index), Qt.MatchExactly) - # comboBox.setCurrentIndex(pos) editor.setText("{}".format(index.model().data(index))) def setModelData(self, editor, model, index): @@ -158,27 +119,11 @@ class WndFixTarget(QWidget): btnSv.clicked.connect(lambda: self.save_file()) bl.addWidget(btnSv, 0, 1) - # but = QPushButton("Random Data") - # but.clicked.connect(self.generate_random_data) - # bl.addWidget(but, 4, 0) - # self._num_random_points = QSpinBox() - # self._num_random_points.setMinimum(2) - # self._num_random_points.setMaximum(10000) - # self._num_random_points.setValue(10) - # self._num_random_points.setSuffix(" points") - # bl.addWidget(self._num_random_points, 4, 1) - btnDump = QPushButton("dump") btnDump.clicked.connect(self.dump_data) bl.addWidget(btnDump, 0, 2) self._cbType=cb=QComboBox() - #cb.addItem("C") - #cb.addItem("C++") - #cb.addItems(["Fiducial", "FixTarget(12.5x12.5)", "FixTarget(23.0x23.0)", "FixTarget()", "Grid()"]) - - - #cb.currentIndexChanged.connect(self.selectionchange) bl.addWidget(cb, 1,0,1,1) self._txtParam=param=QLineEdit() @@ -196,23 +141,7 @@ class WndFixTarget(QWidget): bl.addWidget(btnFit, 2, 1,1,1) layout.addWidget(frame) - #self.markersTable.itemSelectionChanged.connect(self.selection_changed) - #self.markersTable.setContextMenuPolicy(Qt.ActionsContextMenu) - #deleteRowAction = QAction("Delete this row", self) - #deleteRowAction.triggered.connect(self.delete_selected) - #self.markersTable.addAction(deleteRowAction) - - #moveRequestAction = QAction("Move Here", self) - #moveRequestAction.triggered.connect(self.request_stage_movement) - #self.markersTable.addAction(moveRequestAction) - - #layout.addWidget(self.markersTable, stretch=2) - #self.connect_all_signals() - - #self._yamlFn=fn=os.path.expanduser('~/.config/PSI/SwissMX.yaml') - - #self._tree=tree=pg.DataTreeWidget(data=self._data) self._data=data self._tree=tree=pg.DataTreeWidget(data=data) layout.addWidget(tree, stretch=2) diff --git a/PrelocatedCoordinatesModel.py b/PrelocatedCoordinatesModel.py deleted file mode 100644 index 176767f..0000000 --- a/PrelocatedCoordinatesModel.py +++ /dev/null @@ -1,709 +0,0 @@ -# coding=utf-8 -import logging -import os -from os.path import join -from typing import List - -import numpy as np -try: - import pandas as pd -except ImportError as e: - print (f'{e} import failed') -#import transformations as tfs - -from PyQt5.QtCore import Qt, QFileInfo, pyqtSignal, pyqtSlot -from PyQt5.QtWidgets import ( - QTableWidgetItem, - QFileDialog, - QGroupBox, - QWidget, - QGridLayout, - QTableWidget, - QAbstractItemView, - QItemDelegate, - QVBoxLayout, - QLabel, - QPushButton, - QApplication, - QMainWindow, - QHeaderView, - QLineEdit, - QSpinBox, - QMessageBox, - QAction, - QCheckBox) - -logger = logging.getLogger(__name__) - -# from coord_library import conversions -#import conversions #ZAC: orig. code -from app_config import AppCfg - -#from storage import Folders #ZAC: orig. code -#folders = Folders() #ZAC: orig. code - -XY_Coord = List[float] - -DATA_ITEM = 1 -ORIGINAL_X = 1 -ORIGINAL_Y = 2 -GONIO_X = 3 -GONIO_Y = 4 - - -RoleGoniometerCoord_X = 1 + Qt.UserRole -RoleGoniometerCoord_Y = 2 + Qt.UserRole -RoleCameraCoord_X = 3 + Qt.UserRole -RoleCameraCoord_Y = 4 + Qt.UserRole -RoleOriginalCoord_X = 5 + Qt.UserRole -RoleOriginalCoord_Y = 6 + Qt.UserRole - - -def sort_cmass_3d(coord): - """sorts the 3D coordinates (np array 3 columns) with respect to their distane to the center of mass in 3d""" - cm = conversions.find_geo_center(coord) - # print cm - moved_coord = conversions.center_coord(coord, cm) - sorted_moved_coord = conversions.sort_center_3d(moved_coord) - minus_cm = np.multiply(cm, -1) - return conversions.center_coord(sorted_moved_coord, minus_cm) - - -def sort_cmass(coord): - """sorts the 2D coordinates (np array 2 columns) with respect to their distane to the center of mass""" - cm = conversions.find_geo_center(coord) - # print cm - moved_coord = conversions.center_coord(coord, cm) - sorted_moved_coord = conversions.sort_center(moved_coord) - minus_cm = np.multiply(cm, -1) - return conversions.center_coord(sorted_moved_coord, minus_cm) - - -class MarkerDelegate(QItemDelegate): - def createEditor(self, parent, option, index): - comboBox = QLineEdit(parent) - comboBox.editingFinished.connect(self.emitCommitData) - return comboBox - - def setEditorData(self, editor, index): - # pos = comboBox.findText(index.model().data(index), Qt.MatchExactly) - # comboBox.setCurrentIndex(pos) - editor.setText("{}".format(index.model().data(index))) - - def setModelData(self, editor, model, index): - print("model {}".format(model)) - print( - "delegate setData: {}x{} => {}".format( - index.row(), index.column(), editor.text() - ) - ) - model.setData(index, editor.text()) - model.setData(index, float(editor.text()), Qt.UserRole) - - def emitCommitData(self): - print("imagedelegate emitting") - self.commitData.emit(self.sender()) - - -class PrelocatedCoordinates(QWidget): - prefixSelected = pyqtSignal(str) - dataFileLoaded = pyqtSignal(str) - prelocatedDataUpdated = pyqtSignal() - markersDeleted = pyqtSignal() - markerAdded = pyqtSignal(bool, list) # emits is_fiducial(boolean), [x, y, cx, cy] - selectedRowChanged = pyqtSignal(int) - moveFastStageRequest = pyqtSignal(float, float) - - def __init__(self, parent=None): - super(PrelocatedCoordinates, self).__init__(parent) - self._xtals_transformed = True - - self._current_row = None - - layout = QVBoxLayout() - - self.setLayout(layout) - frame = QWidget() - bl = QGridLayout() - frame.setLayout(bl) - - self._label_prefix = QLabel("not set") - self._label_datafile = QLabel("not loaded") - self._label_datafile.setWordWrap(True) - bl.addWidget(QLabel("Prefix"), 0, 0) - bl.addWidget(self._label_prefix, 0, 1) - bl.addWidget(QLabel("Data File"), 1, 0) - bl.addWidget(self._label_datafile, 1, 1) - - but1 = QPushButton("Load Datafile") - but1.clicked.connect(lambda: self.loadMarkers(None)) - bl.addWidget(but1, 2, 0) - - but1 = QPushButton("Save Datafile") - but1.clicked.connect(lambda: self.saveDataAs()) - bl.addWidget(but1, 2, 1) - - but2 = QPushButton("Clear Data") - but2.clicked.connect(self.clearMarkers) - bl.addWidget(but2, 3, 0) - - # but = QPushButton("Random Data") - # but.clicked.connect(self.generate_random_data) - # bl.addWidget(but, 4, 0) - # self._num_random_points = QSpinBox() - # self._num_random_points.setMinimum(2) - # self._num_random_points.setMaximum(10000) - # self._num_random_points.setValue(10) - # self._num_random_points.setSuffix(" points") - # bl.addWidget(self._num_random_points, 4, 1) - - but = QPushButton("dump numpy") - but.clicked.connect(self.dump_numpy) - bl.addWidget(but, 5, 0) - - - # but = QPushButton("Dump to console") - # but.clicked.connect(self.dump_data) - # bl.addWidget(but, 10, 0, 1, 1) - - but = QCheckBox("collect fiducials") - but.setChecked(False) - but.setToolTip("Collect or not the fiducial positions.") - self._collect_fiducials = False - but.stateChanged.connect(self.set_collect_fiducials) - bl.addWidget(but, 10, 0, 1, 1) - - - but = QCheckBox("draw crystal marks") - but.setChecked(False) - self._draw_crystal_marks = False - but.stateChanged.connect(self.set_draw_crystal_marks) - bl.addWidget(but, 10, 1, 1, 1) - - - but = QPushButton("Transform") - but.clicked.connect(self.transform_non_fiducials_in_model) - bl.addWidget(but, 20, 0, 2, 2) - - layout.addWidget(frame) - self.markersTable = QTableWidget() - self.markersTable.setSelectionMode(QAbstractItemView.SingleSelection) - self.markersTable.setSelectionBehavior(QAbstractItemView.SelectRows) - self.markersTable.setItemDelegate(MarkerDelegate(self)) - - # self.markersTable.horizontalHeader().setDefaultSectionSize(80) - self.markersTable.setColumnCount(5) - self.markersTable.setHorizontalHeaderLabels( - ("Fiducial?", "orig X", "orig Y", "X", "Y") - ) - self.markersTable.horizontalHeader().setSectionResizeMode( - 0, QHeaderView.ResizeToContents - ) - self.markersTable.horizontalHeader().setSectionResizeMode( - 1, QHeaderView.ResizeToContents - ) - self.markersTable.horizontalHeader().setSectionResizeMode( - 2, QHeaderView.ResizeToContents - ) - self.markersTable.horizontalHeader().setSectionResizeMode( - 3, QHeaderView.ResizeToContents - ) - self.markersTable.horizontalHeader().setSectionResizeMode( - 4, QHeaderView.ResizeToContents - ) - self.markersTable.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - - self.markersTable.itemSelectionChanged.connect(self.selection_changed) - - self.markersTable.setContextMenuPolicy(Qt.ActionsContextMenu) - - deleteRowAction = QAction("Delete this row", self) - deleteRowAction.triggered.connect(self.delete_selected) - self.markersTable.addAction(deleteRowAction) - - moveRequestAction = QAction("Move Here", self) - moveRequestAction.triggered.connect(self.request_stage_movement) - self.markersTable.addAction(moveRequestAction) - - layout.addWidget(self.markersTable, stretch=2) - self.connect_all_signals() - - def delete_selected(self): - row = self._current_row - try: - row += 0 - except: - logger.warning("select a row first") - QMessageBox.warning( - self, - "Select a marker first", - "You must select a marker first before updating its goniometer position", - ) - return - self.markersTable.removeRow(row) - self.prelocatedDataUpdated.emit() - - def selection_changed(self): - row = self.markersTable.currentRow() - if row < 0: - return - self._current_row = row - self.selectedRowChanged.emit(row) - logger.debug("selection changed: current row {}".format(row)) - - def connect_all_signals(self): - self.prefixSelected.connect(lambda t: self._label_prefix.setText(t)) - self.dataFileLoaded.connect(lambda t: self._label_datafile.setText(t)) - - def markerItemChanged(self, item): - print(item.row(), item.column()) - - def set_fiducial_coords(self, camx, camy, gx, gy): - tbl = self.markersTable - row = self._current_row - try: - row += 0 - except: - logger.warning("select a row first") - QMessageBox.warning( - self, - "Select a marker first", - "You must select a marker first before updating its goniometer position", - ) - return - - origx = tbl.item(row, ORIGINAL_X).data(RoleOriginalCoord_X) - origy = tbl.item(row, ORIGINAL_Y).data(RoleOriginalCoord_Y) - - item = tbl.item(row, DATA_ITEM) - item.setData(RoleCameraCoord_X, camx) - item.setData(RoleCameraCoord_Y, camy) - item.setData(RoleGoniometerCoord_X, gx) - item.setData(RoleGoniometerCoord_Y, gy) - # item.setData(RoleOriginalCoord_X, origx) - # item.setData(RoleOriginalCoord_Y, origy) - # logger.debug(': [{}] = Original: {}, {} | Camera: {}, {} | Gonio: {}, {}'.format(1+row, origx, origy, camx, camy, gx, gy)) - logger.debug(f": [{1+row}] = Original: {origx}, {origy} | Camera: {camx}, {camy} | Gonio: {gx}, {gy}") - - - tbl.item(row, GONIO_X).setData(Qt.DisplayRole, f"{gx:8.5f} mm\n{camx:8.1f} px") - tbl.item(row, GONIO_Y).setData(Qt.DisplayRole, f"{gy:8.5f} mm\n{camy:8.1f} px") - - # mark row as a fiducial - tbl.item(row, 0).setCheckState(Qt.Checked) - tbl.item(row, 0).setData(Qt.UserRole, True) - tbl.selectRow(row + 1) - self.prelocatedDataUpdated.emit() - - def set_selected_gonio_coords(self, xy: XY_Coord): - tbl = self.markersTable - row = self._current_row - try: - row += 0 - except: - logger.warning("select a row first") - QMessageBox.warning( - self, - "Select a marker first", - "You must select a marker first before updating its goniometer position", - ) - return - - for n, v in enumerate(xy): - idx = 3 + n - tbl.setCurrentCell(row, idx) # gonio X - logger.debug("item: [{},{}] = {}".format(row, idx, v)) - item = tbl.currentItem() - item.setData(Qt.EditRole, "{:.3f}".format(v)) - item.setData(Qt.UserRole, v) - - # mark row as a fiducial - tbl.setCurrentCell(row, 0) - tbl.currentItem().setCheckState(Qt.Checked) - tbl.currentItem().setData(Qt.UserRole, True) - - def set_data_goniometer(self, row: int, xy: XY_Coord): - tbl = self.markersTable - - row = self._current_row - try: - row += 0 - except: - logger.warning("select a row first") - QMessageBox.warning( - self, - "Select a marker first", - "You must select a marker first before updating its goniometer position", - ) - return - - for n, v in enumerate(xy): - idx = 3 + n - tbl.setCurrentCell(row, idx) # gonio X - item = tbl.currentItem() - item.setData(Qt.EditRole, "{:.3f}".format(v)) - item.setData(Qt.UserRole, v) - - @pyqtSlot(int) - def set_draw_crystal_marks(self, val): - logger.info(f"{'' if val else 'not '}drawing crystal markers") - self._draw_crystal_marks = val - - @pyqtSlot(int) - def set_collect_fiducials(self, val): - logger.info(f"{'' if val else 'not '}collecting fiducials") - self._collect_fiducials = val - - def get_collection_targets(self): - return self.get_data(fiducials=self._collect_fiducials) - - - def get_data(self, fiducials=True, crystals=True, as_numpy=False): - """return a list of tuples with all defined data - - [ - (is_fiducial(boolean), x, y, gonio_x, gonio_y),... - ] - """ - data = [] - item = self.markersTable.item - - for row in range(self.markersTable.rowCount()): - is_fiducial = Qt.Checked == item(row, 0).checkState() - ditem = item(row, DATA_ITEM) - - x = ditem.data(RoleGoniometerCoord_X) - y = ditem.data(RoleGoniometerCoord_Y) - cx = ditem.data(RoleCameraCoord_X) - cy = ditem.data(RoleCameraCoord_Y) - origx = ditem.data(RoleOriginalCoord_X) - origy = ditem.data(RoleOriginalCoord_Y) - - if is_fiducial and fiducials: - data.append([is_fiducial, x, y, cx, cy, origx, origy]) - if not is_fiducial and crystals: - data.append([is_fiducial, x, y, cx, cy, origx, origy]) - - if as_numpy: - data = np.asarray(data) - return data - - def get_original_coordinates(self, fiducials=True): - """return a numpy array with the original prelocated coordinates of the fiducial entries""" - data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True) - data = data[:, 5:] - zeros = np.zeros(data.shape) - zeros[:, 1] = 1 - return np.concatenate((data, zeros), axis=1) - - def get_goniometer_coordinates(self, fiducials=True): - """return a numpy array with the goniometer coordinates of the fiducial entries""" - data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True) - data = data[:, 1:3] - zeros = np.zeros(data.shape) - zeros[:, 1] = 1 - return np.concatenate((data, zeros), axis=1) - - def get_camera_coordinates(self, fiducials=True): - """return a numpy array with the goniometer coordinates of the fiducial entries""" - data = self.get_data(fiducials=fiducials, crystals=not fiducials, as_numpy=True) - data = data[:, 3:5] - zeros = np.zeros(data.shape) - zeros[:, 1] = 1 - return np.concatenate((data, zeros), axis=1) - - def dump_matrix(self, M): - scale, shear, angles, translate, perspective = tfs.decompose_matrix(M) - angles_deg = [a * 180 / np.pi for a in angles] - - print("Transformation matrix Aerotech => SwissMX") - print(M) - print((" scale {:9.4f} {:9.4f} {:9.4f}".format(*scale))) - print((" shear {:9.4f} {:9.4f} {:9.4f}".format(*shear))) - print((" angles rad {:9.4f} {:9.4f} {:9.4f}".format(*angles))) - print((" angles deg {:9.4f} {:9.4f} {:9.4f}".format(*angles_deg))) - print((" translate {:9.4f} {:9.4f} {:9.4f}".format(*translate))) - print(("perspective {:9.4f} {:9.4f} {:9.4f}".format(*perspective))) - - def transform_non_fiducials_in_model(self): - forg = self.get_original_coordinates(fiducials=True) - fgon = self.get_goniometer_coordinates(fiducials=True) - fcam = self.get_camera_coordinates(fiducials=True) - - gmat = sort_cmass_3d(fgon) - omat = sort_cmass_3d(forg) - - try: - M_org2gon = tfs.superimposition_matrix(omat.T, gmat.T, scale=True) - M_org2cam = tfs.superimposition_matrix(forg.T, fcam.T, scale=True) - except: - QMessageBox.warning(self.parent(), title="failed to find superimposition matrix", text="Failed to find superimposition matrix.\n\tPlease try again.") - return - - # scale, shear, angles, translate, perspective = tfs.decompose_matrix(M_org2gon) - - org_data = self.get_original_coordinates(fiducials=False) - - gon_data = np.dot(M_org2gon, org_data.T) - cam_data = np.dot(M_org2cam, org_data.T) - - tbl = self.markersTable - num_fiducials = forg.shape[0] - - gon_data = (gon_data.T)[:, 0:2] # only X,Y matters - cam_data = (cam_data.T)[:, 0:2] # only X,Y matters - combined = np.concatenate((gon_data, cam_data), axis=1) - - item = self.markersTable.item # function alias - for row, data in enumerate( - combined, num_fiducials - ): # enumeration starts at *num_fiducials* - gx, gy, cx, cy = data - ditem = item(row, DATA_ITEM) - ditem.setData(RoleCameraCoord_X, cx) - ditem.setData(RoleCameraCoord_Y, cy) - ditem.setData(RoleGoniometerCoord_X, gx) - ditem.setData(RoleGoniometerCoord_Y, gy) - item(row, GONIO_X).setData(Qt.DisplayRole, f"{gx:8.5f} mm\n{cx:8.1f} px") - item(row, GONIO_Y).setData(Qt.DisplayRole, f"{gy:8.5f} mm\n{cy:8.1f} px") - self._xtals_transformed = True - self.prelocatedDataUpdated.emit() - - def request_stage_movement(self): - logger = logging.getLogger("preloc.move_stage") - row = self._current_row - x = self.markersTable.item(row, DATA_ITEM).data(RoleGoniometerCoord_X) - y = self.markersTable.item(row, DATA_ITEM).data(RoleGoniometerCoord_Y) - logger.info(f"request move gonio to {x:.3f}, {y:.3f} mm") - self.moveFastStageRequest.emit(x, y) - - def dump_numpy(self): - R = tfs.random_rotation_matrix(np.random.random(3)) - d = self.get_goniometer_coordinates() - print("dumping") - print(d) - dR = np.dot(R, d) - print(dR.T) - - def get_fiducials(self, as_numpy=False): - return self.get_data(crystals=False, as_numpy=as_numpy) - - def get_crystals(self, as_numpy=False): - return self.get_data(fiducials=False, as_numpy=as_numpy) - - def dump_data(self): - for ref, x, y, cx, cy, ox, oy in self.get_data(): - print(f"fiducial:{ref} [{x}, {y}, {cx}, {cy}]") - - def append_data(self, data: List): - """append data (a list of values) to the model - - len(data) == 2 => (X, Y) from prelocated coordinate - len(data) == 4 => (X, Y, GX, GY) plus gonio coordinates - len(data) == 5 => (fiducial?, X, Y, GX, GY) plus fiducial - """ - row = self.markersTable.rowCount() - self.markersTable.setRowCount(row + 1) - - data = list(data) - if len(data) == 2: - data.extend([0, 0]) - if len(data) == 4: - data.insert(0, False) # fiducial flag - self.addSingleMarker(row, data) - self.prelocatedDataUpdated.emit() - - def clearMarkers(self): - self.markersTable.setRowCount(0) - self.markersDeleted.emit() - - def generate_random_data(self): - import io - - data = io.StringIO() - npoints = self._num_random_points.value() - for n in range(npoints): - x, y, a, b = ( - np.random.randint(0, 2000), - np.random.randint(0, 2000), - np.random.randint(-4000, 4000) / 1000., - np.random.randint(-4000, 4000) / 1000., - ) - data.write("{}\t{}\t{}\t{}\n".format(x, y, a, b)) - data.seek(0) - data.name = "random.csv" - self.loadMarkers(data) - - def saveDataAs(self, filename=None): - # filename = folders.get_file("prelocated-save.dat") - data_folder = settings.value("folders/last_prelocation_folder") - if filename is None: - filename, _ = QFileDialog.getSaveFileName( - parent=None, - caption="Open CSV data file", - directory=data_folder, - filter="CSV Data Files (*.csv);;All Files (*)", - ) - - if not filename: - return - - settings.setValue("folders/last_prelocation_folder", QFileInfo(filename).canonicalPath()) - logger.info("Saving data in {}".format(filename)) - data = self.get_data(as_numpy=True) - df = pd.DataFrame(data) - df.to_csv(filename, float_format="%.6f") - - def addSingleMarker(self, row, marker): - is_fiducial, origx, origy, gx, gy = marker - logger.debug(f": [{1+row}] | Original: {origx}, {origy} | Gonio: {gx}, {gy}") - item0 = QTableWidgetItem() - item0.setData(Qt.UserRole, is_fiducial) - item0.setFlags(item0.flags() & ~Qt.ItemIsEditable) - item0.setCheckState(Qt.Checked if is_fiducial else Qt.Unchecked) - item0.setTextAlignment(Qt.AlignCenter) - - item1 = QTableWidgetItem("{:.1f}".format(origx)) - item1.setTextAlignment(Qt.AlignRight) - - item2 = QTableWidgetItem("{:.1f}".format(origy)) - item2.setTextAlignment(Qt.AlignRight) - - item3 = QTableWidgetItem("{:.3f} mm".format(gx)) - item3.setFlags(item3.flags() & ~Qt.ItemIsEditable) - item3.setTextAlignment(Qt.AlignRight) - - item4 = QTableWidgetItem("{:.3f} mm".format(gy)) - item4.setFlags(item4.flags() & ~Qt.ItemIsEditable) - item4.setTextAlignment(Qt.AlignRight) - - self.markersTable.setItem(row, 0, item0) - self.markersTable.setItem(row, ORIGINAL_X, item1) - self.markersTable.setItem(row, ORIGINAL_Y, item2) - self.markersTable.setItem(row, GONIO_X, item3) - self.markersTable.setItem(row, GONIO_Y, item4) - self.markerAdded.emit(is_fiducial, [origx, origy, gx, gy]) - - item = self.markersTable.item(row, DATA_ITEM) - item.setData(RoleCameraCoord_X, origx) # initially set to original - item.setData(RoleCameraCoord_Y, origy) # initially set to original - item.setData(RoleGoniometerCoord_X, gx) - item.setData(RoleGoniometerCoord_Y, gy) - item.setData(RoleOriginalCoord_X, origx) - item.setData(RoleOriginalCoord_Y, origy) - - def loadMarkers(self, filename=None): - logger = logging.getLogger("preloc.loadMarkers") - #def_folder = join(folders.pgroup_folder, "preloc_sheets") #ZAC: orig. code - def_folder ='' - data_folder = settings.value("folders/last_prelocation_folder", def_folder) - - if filename is None: - filename, _ = QFileDialog.getOpenFileName( - self, - "Open CSV data file", - data_folder, - "Any file.. (*.txt);;CSV Data Files (*.csv);;All Files (*)", - ) - - # filename = folders.get_file("preloc-in.csv") - - - if not filename: # cancelled dialog - return - - - try: - settings.setValue("folders/last_prelocation_folder", QFileInfo(filename).canonicalPath()) - settings.setValue("folders/last_prelocation_sheet", QFileInfo(filename).absolutePath()) - except TypeError as e: - pass - - self.clearMarkers() - - logger.info(f"loading prelocated coords from {filename}") - df = pd.read_csv(filename, comment="#", header=None, delim_whitespace=False, delimiter="[\t,;]") - - try: - prefix = QFileInfo(filename).baseName() - except: - prefix = filename.name - filename = prefix - - logger.info(f"prefix => {prefix}") - - gonio_coords_available = True - for data in df.as_matrix(): # FIXME FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead. - row = self.markersTable.rowCount() - self.markersTable.setRowCount(row + 1) - original = np.copy(data) - data = list(data) - - if len(data) in [2, 3]: - gonio_coords_available = False - data.extend([0, 0]) - - if len(data) == 4: - data.insert(0, False) # fiducial flag - elif len(data) == 5: # fiducial already there, convert to bool - data[0] = bool(data[0]) - else: - QMessageBox.warning( - self, - "Wrong number of points in data file", - "I was expecting either 2, 3, 4 or 5 data points per line." - "\n\nFailed around a line with: {}".format(list(original)), - ) - - self.addSingleMarker(row, data) - - self._xtals_transformed = False - self.prefixSelected.emit(prefix) - - # only emit this signal if goniometer coordinates already read from file - if gonio_coords_available: - logger.debug(f"dataFileLoaded.emit => {filename}") - self.dataFileLoaded.emit(filename) - - -""" -Signals QTableWidget -void cellActivated(int row, int column) -void cellChanged(int row, int column) -void cellClicked(int row, int column) -void cellDoubleClicked(int row, int column) -void cellEntered(int row, int column) -void cellPressed(int row, int column) -void currentCellChanged(int currentRow, int currentColumn, int previousRow, int previousColumn) -void currentItemChanged(QTableWidgetItem *current, QTableWidgetItem *previous) -void itemActivated(QTableWidgetItem *item) -void itemChanged(QTableWidgetItem *item) -void itemClicked(QTableWidgetItem *item) -void itemDoubleClicked(QTableWidgetItem *item) -void itemEntered(QTableWidgetItem *item) -void itemPressed(QTableWidgetItem *item) -void itemSelectionChanged() -""" - - -class MainWindow(QMainWindow): - def __init__(self, parent=None): - super(MainWindow, self).__init__(parent) - self.centralWidget = QWidget() - - self.markwi = PrelocatedCoordinates(parent=self) - - self.setCentralWidget(self.centralWidget) - mainLayout = QVBoxLayout() - mainLayout.addWidget(self.markwi) - self.centralWidget.setLayout(mainLayout) - - -if __name__ == "__main__": - - import sys - - app = QApplication(sys.argv) - mainWin = MainWindow() - mainWin.show() - sys.exit(app.exec_()) diff --git a/app_config.py b/app_config.py index 4b9b22f..2a69b6a 100644 --- a/app_config.py +++ b/app_config.py @@ -6,14 +6,11 @@ # #yaml is fixed and not altened by program import logging -import re - _log = logging.getLogger(__name__) -from PyQt5 import QtCore, QtGui from PyQt5.QtCore import QSettings from PyQt5.QtWidgets import QApplication, QMainWindow -import json +import json,re import numpy as np class MyJsonEncoder(json.JSONEncoder): @@ -636,206 +633,15 @@ verbose bits: for i,k in lut: cld[i].setValue(twk[k].get_val()) - #def cb_save(self): - # self._state=p.saveState() - - #def cb_restore(self): - # p=self._p - # add=p['Save/Restore functionality', 'Restore State', 'Add missing items'] - # rem=p['Save/Restore functionality', 'Restore State', 'Remove extra items'] - # p.restoreState(self._state, addChildren=add, removeChildren=rem) - -# ----------------------------- OBSOLETE ----------------------------- - -#inst_folder = Path(__file__).absolute().parent -#config_file = inst_folder / "swissmx.yaml" -#configs = yaml.load(config_file.read_text(),Loader=yaml.FullLoader) -#endstation = configs["configure_for"] -#appsconf = configs[endstation] -#simulated = appsconf.get("simulate", False) -#logger.info(f"configuring for endstation: {endstation.upper()}") - -#if simulated: -# logger.warning("SIMULATION is ACTIVE") -#css_file = inst_folder / "swissmx.css" - - - -#def font(name: str) -> str: -# p = Path(__file__).absolute().parent / "fonts" / name -# return str(p) - - -#def logo(size: int = 0) -> str: -# p = Path(__file__).absolute().parent / "logos" / "logo.png" -# if size: -# p = Path(__file__).absolute().parent / "logos" / f"tell_logo_{size}x{size}.png" -# return str(p) - - -# def dlg_geometry(self,obj): -# SPN=GenericDialog.Spinner -# app=QApplication.instance() -# cfg=app._cfg -# w, h = map(float,cfg.value(AppCfg.GEO_BEAM_SZ)) -# d = GenericDialog.GenericDialog( -# title="geometry", -# message="Enter the size of the beam in microns", -# inputs={ -# "bw": ("beam width um" ,w,SPN(w, min=1, max=200, suffix=" \u00B5m"),), -# "bh": ("beam height um",h,SPN(h, min=1, max=200, suffix=" \u00B5m"),), -# }, -# ) -# if d.exec(): -# results = d.results -# _log.info("Updating beamsize to {}".format(results)) -# bm_sz= (results["bw"], results["bh"]) -# _log.debug("types {}".format(type(w))) -# cfg.setValue(AppCfg.GEO_BEAM_SZ, bm_sz) -# cfg.sync() -# bm=obj._goBeamMarker -# bm.setSize(bm_sz) -# #self._beammark.set_beam_size((w, h)) -# -# def dlg_collimator_reference_positions(self): -# SPN=GenericDialog.Spinner -# app=QApplication.instance() -# cfg=app._cfg -# x_out = cfg.value(AppCfg.COL_DX , 0.0,type=float) -# y_out = cfg.value(AppCfg.COL_DY , 0.0,type=float) -# x_in = cfg.value(AppCfg.COL_X_IN, 0.0,type=float) -# y_in = cfg.value(AppCfg.COL_Y_IN, 0.0,type=float) -# d = GenericDialog.GenericDialog( -# title="Collimator configuration", -# message="Enter reference positions for the collimator", -# inputs={ -# AppCfg.COL_DX: ("Collimator out deltaX", x_out, SPN(x_out, decimals=3, min=-15.9, max=15.9, suffix=" mm"),), -# AppCfg.COL_DY: ("Collimator out deltaY", y_out, SPN(y_out, decimals=3, min=-15.9, max=15.9, suffix=" mm"),), -# AppCfg.COL_X_IN: ("Collimator in X", x_in, SPN(x_in, decimals=3, min=-15.9, max=15.9, suffix=" mm"),), -# AppCfg.COL_Y_IN: ("Collimator in Y", y_in, SPN(y_in, decimals=3, min=-15.9, max=15.9, suffix=" mm"),), -# }, -# ) -# if d.exec(): -# results = d.results -# _log.info("setting collimator reference positions {}".format(results)) -# for k, v in results.items(): -# cfg.setValue(k, v) -# cfg.sync() -# -# def dlg_backlight_positions(self): -# SPN=GenericDialog.Spinner -# app=QApplication.instance() -# cfg=app._cfg -# p_in = cfg.value(AppCfg.BKLGT_IN,0,type=int) -# p_out = cfg.value(AppCfg.BKLGT_OUT,0,type=int) -# d = GenericDialog.GenericDialog( -# title="Back Light configuration", -# message="Enter reference positions for the backlight", -# inputs={ -# AppCfg.BKLGT_IN: ("In position" , p_in , SPN(p_in, min=-30000, max=10), ), -# AppCfg.BKLGT_OUT: ("Out position", p_out, SPN(p_out, min=-1000, max=10), ), -# }, -# ) -# if d.exec(): -# results = d.results -# _log.info("setting back light reference positions {}".format(results)) -# for k, v in results.items(): -# cfg.setValue(k, v) -# cfg.sync() -# -# def dlg_cryojet_positions(self): -# p_in = settings.value(CRYOJET_NOZZLE_IN, type=float) -# p_out = settings.value(CRYOJET_NOZZLE_OUT, type=float) -# motion_enabled = option(CRYOJET_MOTION_ENABLED) -# d = GenericDialog( -# title="Cryojet Nozzle Configuration", -# message="Enter reference positions for the cryojet nozzle position", -# inputs={ -# CRYOJET_NOZZLE_IN: ("In position", p_in, Spinner(p_in, min=3, max=15)), -# CRYOJET_NOZZLE_OUT: ("Out position",p_out,Spinner(p_out, min=-1000, max=10),), -# CRYOJET_MOTION_ENABLED: ("Move Cryojet in Transitions",motion_enabled,Checkbox(motion_enabled, "move cryojet"),), -# }, -# ) -# if d.exec(): -# results = d.results -# _log.info("setting cryojet reference positions {}".format(results)) -# for k, v in results.items(): -# settings.setValue(k, v) -# settings.sync() -# -# def dlg_deltatau_parameters(self): -# SPN=GenericDialog.Spinner -# CB=GenericDialog.Checkbox -# app=QApplication.instance() -# cfg=app._cfg -# #dt1 = cfg.value(AppCfg.DT_HOST,'SAR-CPPM-EXPMX1') -# dt1 = cfg.value(AppCfg.DT_HOST) -# dt2 = cfg.value(AppCfg.DT_VEL_SCL, 1, type=float) -# dt3 = cfg.option(AppCfg.DT_SHOW_PLOTS) -# -# d = GenericDialog.GenericDialog( -# title="Delta Tau Parameters", -# message="These parameters affect the data collection.", -# inputs={ -# AppCfg.DT_HOST:("host name (host[:port:port_gather])", dt1, QLineEdit(),), -# AppCfg.DT_VEL_SCL: ("Velocity Scale (1=optimal, 0=zero vel at target)", dt2,SPN(dt2, min=0, max=1, suffix=""),), -# AppCfg.DT_SHOW_PLOTS: ("show plots after collection", dt3,CB(dt3, "active"),), -# #DELTATAU_SORT_POINTS: ("Sort pointshoot/prelocated coords", b,CB(b, "sort points"),), -# }, -# ) -# if d.exec(): -# results = d.results -# _log.info("setting delta tau parameters {}".format(results)) -# for k, v in results.items(): -# cfg.setValue(k, v) -# cfg.sync() -# -# def dlg_tell_mount_positions(self): -# AUTODRY_ENABLED = "tell/autodry_enabled" -# AUTODRY_MAXMOUNTS = "tell/autodry_max_number_of_mounts" -# AUTODRY_MAXTIME = "tell/autodry_max_time" -# -# SECS_HOURS = 60 * 60 -# -# enabled = option(AUTODRY_ENABLED) -# maxtime = settings.value(AUTODRY_MAXTIME, type=float) / SECS_HOURS -# maxmounts = settings.value(AUTODRY_MAXMOUNTS, type=int) -# -# d = GenericDialog.GenericDialog( -# title="TELL Settings", -# message="These control some features of the TELL sample changer", -# inputs={ -# AUTODRY_ENABLED: ("Auto dry", enabled, -# Checkbox(enabled, "enabled")), -# AUTODRY_MAXMOUNTS: ("Max. num. mounts between dry",maxmounts, -# Spinner(maxmounts, decimals=0, min=1, max=100, suffix=" mounts"),), -# AUTODRY_MAXTIME: ("Max. time between dry",maxtime, -# Spinner(maxtime, decimals=1, min=0.5, max=5, suffix=" hours"),), -# }, -# ) -# if d.exec(): -# results = d.results -# _log.info("setting tell parameters {}".format(results)) -# for k, v in results.items(): -# if k == AUTODRY_MAXTIME: -# v = v * SECS_HOURS -# settings.setValue(k, v) -# settings.sync() - -# ---------------------------------------------- - -## Start Qt event loop unless running in interactive mode or using pyside. if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') - import sys + from PyQt5 import QtCore app=QApplication([]) app._cfg=AppCfg() - w=WndParameter(None) w.show() - - + ## Start Qt event loop unless running in interactive mode or using pyside. if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): QApplication.instance().exec_() diff --git a/app_utils.py b/app_utils.py index f5e4278..cb6424b 100644 --- a/app_utils.py +++ b/app_utils.py @@ -1,9 +1,7 @@ -import time - import logging - _log=logging.getLogger(__name__) +import time from epics.ca import pend_event class PositionsNotReached(Exception): diff --git a/backlight.py b/backlight.py index b34fc5d..38d4223 100755 --- a/backlight.py +++ b/backlight.py @@ -10,9 +10,6 @@ import logging _log=logging.getLogger(__name__) import epics -#from app_config import settings -#from app_utils import assert_motor_positions - class Backlight(object): def __init__(self, prefix: str='SAR-EXPMX:MOT_BLGT',pos={'pos_in':-30500,'pos_out':1000,'pos_diode':-30500}): if prefix is None: @@ -44,7 +41,6 @@ class Backlight(object): m.move(target, ignore_limits=True, wait=wait) - if __name__ == "__main__": import time,os import argparse diff --git a/camera.py b/camera.py index 1450a76..1b0de63 100755 --- a/camera.py +++ b/camera.py @@ -41,10 +41,9 @@ Best regards import logging _log = logging.getLogger(__name__) -import enum, epics, time +import time, enum, epics import numpy as np - class Camera(enum.IntEnum): OFF = 0 RUNNING = 1 @@ -197,10 +196,6 @@ class epics_cam(object): elif k=='roi': pv_rxs=self.getPv('REGIONX_START');pv_rxe=self.getPv('REGIONX_END') pv_rys=self.getPv('REGIONY_START');pv_rye=self.getPv('REGIONY_END') - #pv_rxs.put(v[0], wait=False) - #pv_rxe.put(v[0]+v[2], wait=False) - #pv_rys.put(v[1], wait=False) - #pv_rye.put(v[1]+v[3], wait=False) param.append((pv_rxs,v[0])) param.append((pv_rxe,v[0]+v[2])) param.append((pv_rys,v[1])) @@ -277,9 +272,6 @@ class epics_cam(object): xx, yy = np.meshgrid(x, y) for i in range(t): - #imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin(yy+.01*i)**2)#+xx*t+yy*t) - #imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+.1*i)**2 + np.sin((1+.1*np.sin(.2*i))*yy+.001*i**2)**2)#+xx*t+yy*t) - #imgSeq[i,:,:] = 100*np.sqrt(np.sin(xx+2*np.sin(i/t*2*np.pi))**2 + np.sin(yy)**2) px=2*np.sin(i/t*2*np.pi) fx=1 py=2*np.sin(i/t*2*np.pi) @@ -323,7 +315,7 @@ class epics_cam(object): if __name__ == "__main__": - import time, os, PIL.Image, platform, subprocess + import os, PIL.Image, platform, subprocess import argparse logging.basicConfig(level=logging.DEBUG,format='%(name)s:%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') logging.getLogger('PIL').setLevel(logging.INFO) @@ -337,9 +329,6 @@ if __name__ == "__main__": else: # linux variants subprocess.call(('xdg-open', file)) - - - parser = argparse.ArgumentParser() parser.add_argument("--ui", "-u", help="qt test", type=int, default=0) parser.add_argument("--sim", "-s", help="simulation mode", type=int, default=None) @@ -355,20 +344,12 @@ if __name__ == "__main__": else: os.environ['EPICS_CA_ADDR_LIST'] ='129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066' - if not args.ui: cam = epics_cam(prefix=args.prefix) #cam._transformation=np.array(((-1,0),(0,1)),dtype=np.uint8) #ZAC: orig. code if args.prefix is None: cam.sim_gen(mode=args.sim) - #sz=(2448,2048) - #ctr=(1200,1400) - #sz=(1200,1000) - #cam.set_roi(int(ctr[0]-sz[0]/2),int(ctr[0]+sz[0]/2),int(ctr[1]-sz[1]/2),int(ctr[1]+sz[1]/2)) - #cam.set_exposure(3) - #cam.set_binning(1,1) - cam.run() n = 1 base = "/tmp/image_{:05d}.png" diff --git a/detector.py b/detector.py index a199bd5..2762a39 100644 --- a/detector.py +++ b/detector.py @@ -1,17 +1,8 @@ import logging _log=logging.getLogger(__name__) -#from glob import glob - from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot -#import eventer -#import qsingleton -#from detector_integration_api import DetectorIntegrationClient -#from app_config import settings, appsconf, simulated -#config = appsconf['jungfrau'] -#dia_client = DetectorIntegrationClient(config['uri']) - class JungfrauWaiter(QObject): finished = pyqtSignal() @@ -22,9 +13,11 @@ class JungfrauWaiter(QObject): def work(self): pass + class JungfrauMissingConfiguration(Exception): pass + class Jungfrau(QObject): pedestal_selected = pyqtSignal(str) configured = pyqtSignal() diff --git a/obsolete.py b/obsolete.py deleted file mode 100644 index 44b6f12..0000000 --- a/obsolete.py +++ /dev/null @@ -1,3050 +0,0 @@ - # **************** OBSOLETE AND/OR OLD STUFF **************** - -class WndSwissMx(QMainWindow, Ui_MainWindow): - - # **************** OBSOLETE AND/OR OLD STUFF **************** - - -# functions are prefixed with _OLD_ - def _OLD_build_daq_methods_grid_tab(self): - self._grids = [] - tab = self._tab_daq_method_grid - layout = tab.layout() # gridlayout - self._sb_grid_x_step.setValue(30) - self._sb_grid_y_step.setValue(30) - self._bt_add_grid.clicked.connect(self._OLD_daq_grid_add_grid) - self._bt_remove_all_grids.clicked.connect(self._OLD_daq_grid_remove_all) - self._find_targets_from_microscope_image.clicked.connect(self._OLD_daq_grid_findxtals) - self.addGridRequest.connect(self._OLD_daq_grid_add_grid) - self.gridUpdated.connect(self._OLD_daq_grid_update) - - def _OLD_build_daq_methods_prelocated_tab(self): - tab = self._tab_daq_method_prelocated - self.prelocationModule = PrelocatedCoordinatesModel.PrelocatedCoordinates(parent=self) - tab.layout().addWidget(self.prelocationModule) - self.prelocationModule.prefixSelected.connect(lambda prefix: self._le_prefix.setText(prefix)) - self.prelocationModule.dataFileLoaded.connect(self._OLD_daq_method_prelocated_update_markers) - self.prelocationModule.prelocatedDataUpdated.connect(self._OLD_daq_method_prelocated_update_markers) - self.prelocationModule.markersDeleted.connect(self._OLD_daq_method_prelocated_remove_markers) - self.fiducialPositionSelected.connect(self._OLD_daq_method_prelocated_set_fiducial) - self.appendPrelocatedPosition.connect(self._OLD_daq_method_prelocated_append_data) - self.prelocationModule.moveFastStageRequest.connect(self._OLD_move_fast_stage) - self._preloc_inspect_area = QPlainTextEdit() - tab.layout().addWidget(self._preloc_inspect_area) - - def _OLD_build_daq_methods_embl_tab(self): - app = QApplication.instance() - self._tab_daq_method_embl.setLayout(QVBoxLayout()) - layout = self._tab_daq_method_embl.layout() - #motors = self.get_gonio_motors() - self._embl_module = EmblWidget(self) #ZAC: orig. code - #self._embl_module.configure(motors, app._camera, app._zoom) - layout.addWidget(self._embl_module) - - def _OLD_create_helical_widgets(self): - tbox = self._helical_tablebox - htab = self._helical_scan_table = HelicalTableWidget() - htab.gonioMoveRequest.connect(self._OLD_move_gonio_to_position) - tbox.setLayout(QVBoxLayout()) - - grp = QWidget() - grp.setLayout(QFormLayout()) - le = QSpinBox() - le.setRange(1, 100) - le.setValue(htab.scanHorizontalCount()) - le.valueChanged.connect(lambda cnt: htab.setScanHorizontalCount(cnt)) - grp.layout().addRow("Horizontal Count", le) - - le = QSpinBox() - le.setRange(1, 100) - le.setValue(htab.scanVerticalCount()) - le.valueChanged.connect(lambda cnt: htab.setScanVerticalCount(cnt)) - grp.layout().addRow("Vertical Count", le) - - le = QDoubleSpinBox() - le.setRange(-180.0, 180.0) - le.setSingleStep(5.0) - le.setSuffix(" degrees") - le.valueChanged.connect(htab.setStartAngle) - grp.layout().addRow("Start angle", le) - - tbox.layout().addWidget(grp) - widgi = QWidget() - widgi.setLayout(QHBoxLayout()) - tbox.layout().addWidget(widgi) - - but = QPushButton("Add Crystal") - but.clicked.connect(htab.add_xtal) - widgi.layout().addWidget(but) - - but = QPushButton("Set START") - but.clicked.connect(lambda: htab.set_xtal_start(self.get_gonio_positions())) - widgi.layout().addWidget(but) - - but = QPushButton("Set END") - but.clicked.connect(lambda: htab.set_xtal_end(self.get_gonio_positions())) - widgi.layout().addWidget(but) - - tbox.layout().addWidget(htab) - - def _OLD_add_beam_marker(self): - app = QApplication.instance() - cfg = app._cfg - w, h = cfg.value(AppCfg.GEO_BEAM_SZ) - self._beammark = bm = CstROI.BeamMark([100, 100], (int(w), int(h)), parent=self) - tr=QtGui.QTransform() # prepare ImageItem transformation: - tr.rotate(30) - bm.setTransform(tr) # assign transform - self.vb.addItem(self._beammark) - bm=UsrGO.BeamMark([50, 120], [30, 20]) - self.vb.addItem(bm) - vi=UsrGO.Grid((120, -100), (200, 150), (30, 20), 2) - self.vb.addItem(vi) - - def _OLD_camera_pause_toggle(self): - app=QApplication.instance() - app._camera.pause() - - def _OLD_init_settings_tracker(self): - app=QApplication.instance() - cfg=app._cfg - _log.info("configuring widget persistence") - fields = { - # 'folder': (self._label_folder, str), - "project": (self._le_project, str), - "prefix": (self._le_prefix, str), - "actual_prefix": (self._label_actual_prefix, str), - "exposureTime": (self._dsb_exposure_time, float), - "oscillationAngle": (self._dsb_oscillation_step, float), - "blastRadius": (self._dsb_blast_radius, float), - } - for key, f_config in fields.items(): - widget, conv = f_config - value = cfg.value(key) - try: - wset, wget = widget.setText, widget.text - _log.debug("tracking text field {}".format(key)) - except AttributeError: - _log.debug("tracking {} number field {}".format(conv, key)) - wset, wget = widget.setValue, lambda fget=widget.value: conv(fget()) - except Exception as e: - _log.error(e) - - try: - wset(conv(value)) - except Exception as e: - _log.debug(e) - _log.warning('failed for "{}" updating field of type {} with {}'.format( key, type(widget), value)) - finally: - # _log.debug('wget = {}; wset = {}'.format(wget, wset)) - widget.editingFinished.connect(lambda w=widget, k=key, func_get=wget: self.persist_setting(k, func_get() ) ) - #self.storage_cascade_prefix(None) #ZAC: orig. code - - def _OLD_init_validators(self): - identifier_regex = QRegExp("[a-z-A-Z_0-9%]+") - self._le_project.setValidator(QRegExpValidator(identifier_regex, self._le_project)) - self._le_prefix.setValidator(QRegExpValidator(identifier_regex, self._le_prefix)) - - def _OLD_wire_storage(self): - self._le_prefix.textChanged.connect(self._OLD_storage_cascade_prefix) - self._le_prefix.textChanged.connect(lambda newtext: self.prefixChanged.emit(newtext)) - self._le_project.textChanged.connect(self._OLD_storage_cascade_prefix) - self._le_project.textChanged.connect(lambda newtext: self.projectChanged.emit(newtext)) - self._le_prefix.editingFinished.connect(self._OLD_prepare_daq_folder) - self._le_project.editingFinished.connect(self._OLD_prepare_daq_folder) - self.increaseRunNumberRequest.connect(self._OLD_increase_run_number) - - def _OLD_storage_cascade_prefix(self, val): - prefix = self._le_prefix.text() - if 0 == len(prefix): - _log.warning("empty prefix is not accepted") - self._le_prefix.setAccessibleName("invalid_input") - self._le_prefix.blockSignals(True) - self._le_prefix.setText("INVALID=>" + prefix) - QMessageBox.warning(self, "prefix is not valid", "Prefix is not valid!") - self._le_prefix.blockSignals(False) - - return - else: - self._le_prefix.setAccessibleName("") - project = self._le_project.text() - folders.set_prefix(prefix) - folders.set_project(project) - folders.run = settings.value("run_number", type=int) - self._label_runnumber.setText(f"{folders.run:04d}") - self._data_folder = folders.raw_folder - self.folderChanged.emit(folders.raw_folder) - self._label_actual_prefix.setText(folders.prefix) - self._label_folder.setText(folders.raw_folder) - - def _OLD_increase_run_number(self): - run = settings.value("run_number", type=int) - run += 1 - settings.setValue("run_number", run) - folders.run = run - self._label_runnumber.setText(f"{run:04d}") - - def _OLD_prepare_daq_folder(self): - global home, folders - prefix = folders.prefix - folder = folders.res_folder - if 0 == len(prefix): - return - - try: - os.makedirs(folder, 0o750, exist_ok=True) - except: - msg = "Failed to create folder: {}".format(folder) - _log.warning(msg) - QMessageBox.warning(self, "Screenshot: failed to create folder", "Failed to create output folder for screenshot!\n\n\tScreenshot not taken!",) - raise - - fname = os.path.join(folders.pgroup_folder, ".latest_raw") - try: - with open(fname, "w") as f: - f.write(folders.raw_folder) - _log.info("wrote: {}".format(fname)) - except: - _log.warning("failed writing {}".format(fname)) - - fname = os.path.join(folders.pgroup_folder, ".latest_res") - try: - with open(fname, "w") as f: - f.write(folders.res_folder) - _log.info("wrote: {}".format(fname)) - except: - _log.warning("failed writing {}".format(fname)) - - def _OLD_persist_setting(self, s, v): - app=QApplication.instance() - cfg=app._cfg - _log.debug("persisting {} = {}".format(s, v)) - cfg.setValue(s, v) - - def _OLD_method_changed(self, index): - method = self._tabs_daq_methods.currentWidget().accessibleName() - _log.info("method now => {}".format(method)) - - - - def _OLD_check_zescape(self): - msg = zescape.check() - if msg is None: - return - if "current" in msg: - _log.warning(f"current state: {self._esc_state}") - zescape.reply(self._esc_state) - elif "goto" in msg: - state = msg.split()[1].lower() - _log.warning(f"TELL requests to go to {state}") - try: - if "sampleexchange" in state: - _log.debug( - f"moving to mount with offset = {self._pin_mounting_offset}" - ) - self.move_gonio_to_mount_position(offset=self._pin_mounting_offset) - elif "samplealignment" in state: - self.cb_esc_sample_alignment() - except: - zescape.reply("Maintenance") - zescape.reply(self._esc_state) - else: # JSON - data = json.loads(msg) - if "sampleName" in data: - _log.debug(f"TELL SAMPLE DATA => {data}") - self.tell2storage(data) - zescape.reply("ack") - elif "pin_offset" in data: - _log.debug(f"TELL pin offset => {data}") - self._pin_mounting_offset = data["pin_offset"] - zescape.reply("ack") - elif "get_pin_offset" in data: - _log.debug(f"TELL get pin offset => {data}") - zescape.reply_json({"pin_offset": self._pin_mounting_offset}) - - def _OLD_tell2storage(self, sample): - _log.debug(f"2 TELL SAMPLE DATA => {type(sample)}") - self._le_prefix.setText(sample["sampleName"]) - self._le_project.setText(sample["sampleFolder"]) - tstf = folders.get_prefixed_file("_newsample") - self.storage_cascade_prefix(None) - _log.warning(f"sample info: {tstf}") - - def _OLD_is_task(self, task): - return task == self._active_task - - def _OLD_get_task_menu(self): - pass - - def _OLD_toggle_shutter(self, **kwargs): - if self._pv_shutter: - if 0 == self._pv_shutter.get(): - self._pv_shutter.put(1) - self._button_shutter.setText("shutter opened\n\u2622") - else: - self._pv_shutter.put(0) - self._button_shutter.setText("shutter closed\n\u2622") - elif self._has_pulse_picker: - pulsePicker.toggle() - - def _OLD_update_shutter_label(self, pvname, value, char_value, **kwargs): - if 0 == value: - self._button_shutter.setText("shutter closed") - else: - self._button_shutter.setText("shutter opened") - - def _OLD_build_sample_selection_tab(self): - self._sample_selection = sample_selection.SampleSelection(self) - self._sample_selection.move_to_mount_position = (self.move_gonio_to_mount_position) - self._tab_sample_selection.setLayout(QVBoxLayout()) - self._tab_sample_selection.layout().addWidget(self._sample_selection) - self._tab_sample_selection.layout().addStretch(2) - - def _OLD_build_embl_group(self): - grp = QGroupBox("EMBL Acquisition") - layout = QFormLayout() - grp.setLayout(layout) - layout.addWidget(QLabel("Prefix")) - self._embl_prefix = QLineEdit("img") - layout.addWidget(self._embl_prefix) - - def _OLD_abort_measurement(self, ev=None): - if settings.value(ACTIVATE_PULSE_PICKER): - pulsePicker.close() - jungfrau_detector.abort() - delta_tau.abort() - _log.debug("aborting measurement") - - def _OLD_trigger_detector(self, **kwargs): - if self._pv_shutter is not None: - self._pv_shutter.put(0) - # self._eiger_button_collect.show() - # self._eiger_button_abort.hide() - # self._eiger_now_collecting_label.setText( - # "Finished sequence id: {}\n" - # "Data in: Data10/{}".format( - # self._detector_sequence_id, self._eiger_now_collecting_file - # ) - # ) - - def _OLD_modify_camera_transform(self, t): - if t == "remove_all": - sample_camera.set_transformations([]) - elif t == "undo_last": - sample_camera._transformations.pop() - #elif type(t) ==type(camera.Transforms): #ZAC: orig. code - # sample_camera.append_transform(t) - try: - label = ", ".join([t.name for t in sample_camera._transformations]) - except: - label = "" - self._label_transforms.setText(label) - #settings.setValue(CAMERA_TRANSFORMATIONS, sample_camera._transformations) #ZAC: orig. code - - def _OLD_roi_add_line(self): - roi = pg.LineSegmentROI( - [200, 200], - [300, 300], - pen="r", - scaleSnap=True, - translateSnap=True, - rotateSnap=True, - removable=True, - ) - # roi.sigRegionChanged.connect(self.track_roi) - roi.sigRemoveRequested.connect(self.remove_roi) - self.vb.addItem(roi) - self._rois.append(roi) - - def _OLD_roi_add_rect(self): - roi = pg.RectROI( - [200, 200], - [50, 50], - pen="r", - scaleSnap=True, - translateSnap=True, - rotateSnap=True, - removable=True, - ) - roi.sigRegionChanged.connect(self.track_roi) - roi.sigRemoveRequested.connect(self.remove_roi) - self.vb.addItem(roi) - self._rois.append(roi) - - def _OLD_remove_roi(self, roi): - self.vb.removeItem(roi) - self._rois.remove(roi) - - def _OLD_prepare_microscope_page(self): - layout = self.microscope_page.layout() - container = QWidget() - hlay = QHBoxLayout() - container.setLayout(hlay) - layout.addWidget(container) - - def _OLD_update_beam_marker(self, zoom_lvl): - w, h = settings.value(BEAM_SIZE) - try: - bx = self.beamx_fitter(zoom_lvl) - by = self.beamy_fitter(zoom_lvl) - ok = True - except: - ok = False - _log.warning("beam marker not defined") - return - _log.debug("updating beam mark to {:.1f}x{:.1f}".format(bx, by)) - self.beamCameraCoordinatesChanged.emit(bx, by) - - def _OLD_update_beam_marker_fitters(self): - if len(self._beam_markers) > 2: - _log.debug("defining beam marker") - bx = [(n, x[0]) for n, x in self._beam_markers.items()] - by = [(n, x[1]) for n, x in self._beam_markers.items()] - nbx = np.asarray(bx).T - nby = np.asarray(by).T - bx_coefs = np.polyfit(nbx[0], nbx[1], 3) - by_coefs = np.polyfit(nby[0], nby[1], 3) - _log.debug(".... beam marker X coeficients {}".format(bx_coefs)) - _log.debug(".... beam marker Y coeficients {}".format(by_coefs)) - self.beamx_fitter = np.poly1d(bx_coefs) - self.beamy_fitter = np.poly1d(by_coefs) - - - def _OLD_append_to_beam_markers(self, x, y, zoom): - self._beam_markers[zoom] = (x, y) - _log.info("beam markers {}".format(self._beam_markers)) - settings.setValue(BEAM_MARKER_POSITIONS, self._beam_markers) - self.update_beam_marker_fitters() - - def _OLD_remove_beam_markers(self): - self._beam_markers = {} - self.beamx_fitter = None - self.beamy_fitter = None - - def _OLD_track_roi(self, roi): - x, y = roi.pos() - w, h = roi.size() - # area = roi.getArrayRegion(self._im, self.img) - # sum = np.sum(area) - # _log.info('{} => sum {}'.format((x,y), sum)) - bx, by = x + w / 2., y + h / 2. - _log.info("beam pos {}".format((bx, by))) - _log.info("marker pos = {} ; size = {}".format((x, y), (w, h))) - - def _OLD_toggle_mouse_tracking(self): - if self._mouse_tracking: - self.disengage_mouse_tracking() - else: - self.engage_mouse_tracking() - - def _OLD_engage_mouse_tracking(self): - self.glw.scene().sigMouseMoved.connect(self.cb_mouse_move) - self.glw.scene().sigMouseMoved.emit() - self._mouse_tracking = True - - def _OLD_disengage_mouse_tracking(self): - self.glw.scene().sigMouseMoved.disconnect(self.cb_mouse_move) - self._mouse_tracking = False - self._lb_coords.setText("") - - def _OLD_get_beam_mark_on_camera_xy(self): - app=QApplication.instance() - z = app._zoom.get_val() - try: - bx = self.beamx_fitter(z) - by = self.beamy_fitter(z) - except: - bx, by = 500, 500 - return (bx, by) - - def _OLD_move_gonio_to_position(self, fx, fy, bx, bz, omega): - self.tweakers["fast_x"].motor.move(fx, wait=False, ignore_limits=True) - self.tweakers["fast_y"].motor.move(fy, wait=False, ignore_limits=True) - self.tweakers["base_x"].motor.move(bx, wait=False, ignore_limits=True) - self.tweakers["base_z"].motor.move(bz, wait=False, ignore_limits=True) - self.tweakers["omega"].motor.move(omega, wait=False, ignore_limits=True) - - def _OLD_get_gonio_motors(self, as_json=False): - if as_json: - return { - "fast_x": self.tweakers["fast_x"].motor, - "fast_y": self.tweakers["fast_y"].motor, - "base_x": self.tweakers["base_x"].motor, - "base_z": self.tweakers["base_z"].motor, - "omega": self.tweakers["omega"].motor, - } - else: - return ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - - def _OLD_get_gonio_tweakers(self): - return ( - self.tweakers["fast_x"], - self.tweakers["fast_y"], - self.tweakers["base_x"], - self.tweakers["base_z"], - self.tweakers["omega"], - ) - - def _OLD_get_gonio_positions(self, as_json: bool = False): - fx, fy, cx, cz, omega = ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - - a, b, c, d, e = ( - fx.get_position(), - fy.get_position(), - cx.get_position(), - cz.get_position(), - omega.get_position(), - ) - if as_json: - return {"fx": a, "fy": b, "bx": c, "bz": d, "omega": e} - else: - return (a, b, c, d, e) - - def _OLD_escape_goToTellMountPosition(self): - self.move_gonio_to_mount_position() - self.lock_goniometer() - - def _OLD_move_gonio_to_mount_position(self, offset: float = 0.0): - fx, fy, cx, cz, omega = self.get_gonio_motors() - bmark = "bookmark_0" - try: - t_fx = float(settings.value(bmark + "/mount_fx")) - t_fy = -offset + float(settings.value(bmark + "/mount_fy")) - t_cx = float(settings.value(bmark + "/mount_cx")) - t_cz = float(settings.value(bmark + "/mount_cz")) - t_omega = float(settings.value(bmark + "/mount_omega")) - except: - raise IncompleteConfiguration("TELL sample changer mount position is not configured!!!") - fx.move(t_fx, wait=True, ignore_limits=True) - fy.move(t_fy, wait=True, ignore_limits=True) - cx.move(t_cx, wait=True, ignore_limits=True) - cz.move(t_cz, wait=True, ignore_limits=True) - omega.move(t_omega, wait=True, ignore_limits=True) - app_utils.assert_motor_positions( - [ - (fx, t_fx, 0.01), - (fy, t_fy, 0.01), - (cx, t_cx, 0.01), - (cz, t_cz, 0.01), - (omega, t_omega, 0.01), - ] - ) - self.cb_esc_sample_exchange() - - def _OLD_lock_goniometer(self): - # tell.set_in_mount_position(True) - res = QMessageBox.question(self, "", "Mount a sample from console and click ok once the sample is mounted.", QMessageBox.Ok, QMessageBox.Ok,) - res = QMessageBox.question(self, "", "Is the sample is mounted?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) - if res in (QMessageBox.Yes, QMessageBox.No): - # tell.set_in_mount_position(False) - pass - - @pyqtSlot(int) - def _OLD_saveBookmark(self, key: int): - """save a bookmark for the corresponding key is the Qt.Key_* code """ - fx, fy, cx, cz, omega = ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - bmark = "bookmark_{}".format(key) - if key == 0: - ans = QMessageBox.question(self, "Override TELL mount position", "This will overwrite the positions used for TELL MOUNTING!!!\n\n\tContinue ?",) - if ans != QMessageBox.Yes: - return - - _log.info( - "saving bookmark {}: {}, {}, {}, {}, {}".format( - bmark, - fx.get_position(), - fy.get_position(), - cx.get_position(), - cz.get_position(), - omega.get_position(), - ) - ) - settings.setValue(bmark + "/mount_fx", fx.get_position()) - settings.setValue(bmark + "/mount_fy", fy.get_position()) - settings.setValue(bmark + "/mount_cx", cx.get_position()) - settings.setValue(bmark + "/mount_cz", cz.get_position()) - settings.setValue(bmark + "/mount_omega", omega.get_position()) - - def _OLD_gotoBookmark(self, key: int): - """save a bookmark for the corresponding key""" - fx, fy, cx, cz, omega = ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - bmark = "bookmark_{}".format(key) - try: - t_fx = float(settings.value(bmark + "/mount_fx")) - t_fy = float(settings.value(bmark + "/mount_fy")) - t_cx = float(settings.value(bmark + "/mount_cx")) - t_cz = float(settings.value(bmark + "/mount_cz")) - t_omega = float(settings.value(bmark + "/mount_omega")) - except: - return - - fx.move(t_fx, wait=True, ignore_limits=True) - fy.move(t_fy, wait=True, ignore_limits=True) - cx.move(t_cx, wait=True, ignore_limits=True) - cz.move(t_cz, wait=True, ignore_limits=True) - omega.move(t_omega, wait=True, ignore_limits=True) - - def _OLD_move_cryojet_nozzle(self, pos): - cx = self.tweakers["cryo"] - if "in" == pos.lower(): - key = CRYOJET_NOZZLE_IN - elif "out" == pos.lower(): - key = CRYOJET_NOZZLE_OUT - - to_pos = settings.value(key, 1e10, type=float) - if to_pos > 1e9: - raise IncompleteConfiguration(f"CRYOJET configuration is incomplete! Missing {key}") - cx.move_abs(to_pos, assert_position=True) - - def _OLD_build_cryo_group(self, toolbox): - pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] - qutilities.add_item_to_toolbox( - toolbox, - "Cryojet", - widget_list=[ - self.get_tweaker(f"{pfx}:MOT_CRYO", alias="cryo", label="cryo X") - ], - ) - - def _OLD_build_wegde_group(self, toolbox): - pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] - qutilities.add_item_to_toolbox(toolbox,"Wedge Mover", - widget_list=[ - self.get_tweaker(f"{pfx}:MOT_WEDGE1", alias="wedge_1", label="wedge_1"), - self.get_tweaker(f"{pfx}:MOT_WEDGE2", alias="wedge_2", label="wedge_2"), - self.get_tweaker(f"{pfx}:MOT_WEDGE3", alias="wedge_3", label="wedge_3"), - self.get_tweaker(f"{pfx}:MOT_WEDGE4", alias="wedge_4", label="wedge_4"), - self.get_tweaker(f"{pfx}:MOT_WEDGEX", alias="wedge_x", label="wedge_x"), - self.get_tweaker(f"{pfx}:MOT_WEDGEY", alias="wedge_y", label="wedge_y"), - self.get_tweaker(f"{pfx}:MOT_WEDGEA", alias="wedge_a", label="wedge_a"), - self.get_tweaker(f"{pfx}:MOT_WEDGEB", alias="wedge_b", label="wedge_b"), - ], - ) - - def _OLD_build_slits_group(self, toolbox): - pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] - qutilities.add_item_to_toolbox( - toolbox, - "Slits", - widget_list=[ - self.get_tweaker(f"{pfx}10", alias="slit_right", label="left", mtype=1, ), - self.get_tweaker(f"{pfx}11", alias="slit_left", label="right", mtype=1,), - self.get_tweaker(f"{pfx}12", alias="slit_bottom", label="bottom", mtype=1,), - self.get_tweaker(f"{pfx}13",alias="slit_top",label="top",mtype=1,), - ], - ) - - def _OLD_assert_post_tube_position(self, pos): - x_up = settings.value("post_sample_tube/x_up", 1e10, type=float) - y_up = settings.value("post_sample_tube/y_up", 1e10, type=float) - x_down = settings.value("post_sample_tube/x_down", 1e10, type=float) - y_down = settings.value("post_sample_tube/y_down", 1e10, type=float) - dx = settings.value("post_sample_tube/dx", 1e10, type=float) - dy = settings.value("post_sample_tube/dy", 1e10, type=float) - tz_in = settings.value("post_sample_tube/z_in", 1e10, type=float) - tz_out = settings.value("post_sample_tube/z_out", 1e10, type=float) - - if (x_up + y_up + x_down + y_down + dx + dy + tz_in + tz_out) > 1e9: - raise Exception("miscofingured positions for post-sample tube") - - usy = self.tweakers["tube_usy"] - dsy = self.tweakers["tube_dsy"] - usx = self.tweakers["tube_usx"] - dsx = self.tweakers["tube_dsx"] - tbz = self.tweakers["tube_z"] - - if pos == "in": - yu = y_up - xu = x_up - yd = y_down - xd = x_down - z = tz_in - elif pos == "out": - yu = y_up + dy - xu = x_up + dx - yd = y_down + dy - xd = x_down + dx - z = tz_out - - app_utils.assert_tweaker_positions([ - (usy, yu, 0.1), - (dsy, yd, 0.1), - (usx, xu, 0.1), - (dsx, xd, 0.1), - (tbz, z, 0.1),],timeout=2.0, - ) - - def _OLD_add_tweaker(self, pv, alias=None, label=None, mtype="epics_motor", layout=None): - if layout is None: - layout = self._tweak_container.layout() - if mtype == "epics_motor": - m = MotorTweak() - else: - m = SmaractMotorTweak() - layout.addWidget(m) - m.connect_motor(pv, label) - self.tweakers[alias] = m - - def _OLD_done_sliding(self): - print("done sliding at {}".format(self.slider_fast_x.value())) - - def _OLD_daq_grid_add_grid(self, gx=None, gy=None): - grid_index = len(self._grids) - if gx in (False, None): - gx=self.tweakers["fast_x"].get_rbv() - gy=self.tweakers["fast_y"].get_rbv() - xstep = self._sb_grid_x_step.value() - ystep = self._sb_grid_y_step.value() - xoffset = self._sb_grid_x_offset.value() - yoffset = self._sb_grid_y_offset.value() - - app=QApplication.instance() - geo=app._geometry - oc=geo._opt_ctr - if xstep==0: - go=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2) - elif xstep==1: - go=UsrGO.FixTargetFrame((120, -100), (200, 150), tpl='test') - elif xstep==2: - v=geo.pos2pix((12.5, 0)) - l=np.linalg.norm(v) - go=UsrGO.FixTargetFrame(-oc, (l,l), tpl='12.5x12.5') - elif xstep==3: - v=geo.pos2pix((23, 0)) - l=np.linalg.norm(v) - go=UsrGO.FixTargetFrame(-oc, (l,l), tpl='23.0x23.0') - else: - _log.error('set xstep 0..2 for tests') - self.vb.addItem(go) - self._goTracked['objLst'].append(go) - - #grid = CstROI.Grid( x_step=xstep, y_step=ystep, x_offset=xoffset, y_offset=yoffset, gonio_xy=(gx, gy), grid_index=grid_index, parent=self,) - #self.vb.addItem(grid) - #grid.calculate_gonio_xy() - #grid.sigRemoveRequested.connect(lambda g=grid: self.remove_grid(g)) - - def _OLD_daq_grid_remove_all(self): - vb=self.vb - for go in self._goTracked['objLst']: - vb.removeItem(go) - self._goTracked['objLst']=[] - - def _OLD_grids_pause_stage_tracking(self): - for grid in self._grids: - grid.disable_stage_tracking() - - def _OLD_grids_start_stage_tracking(self): - for grid in self._grids: - grid.enable_stage_tracking() - - def _OLD_remove_grid(self, grid): - self.vb.removeItem(grid) - self._grids.remove(grid) - - - def _OLD_daq_grid_update(self, grid_index): - try: - grid = self._grids[grid_index] - except: - print("grid index not yet there") - return - points = grid.get_grid_targets() - num_points = len(points) - etime = float(settings.value("exposureTime")) - doc = f"grid_{grid_index} = [" - for n, pos in enumerate(points): - x, y = pos - doc += "[{:8.3f}, {:8.3f}],\n".format(x, y) - doc += "]" - self._grid_inspect_area.setPlainText(doc) - m = "Number of points: {}\nEstimated Time: {:.1f} minutes".format(num_points, num_points * etime / 60.) - self._label_grid_parameters.setText(m) - - def _OLD_daq_embl_collect_points(self): - coords = self._embl_module.coords - points = [[x, y] for x, y, bx, bz, o in coords] - points = np.array(points) - method = "trajectory" - xp = (1000 * points).astype(int) # microns then round int - params = (xp[:, 0].tolist(), xp[:, 1].tolist()) - self.daq_collect_points(points, visualizer_method=method, visualizer_params=params) - - def _OLD_daq_prelocated_collect_points(self): - points = [] - data = self.prelocationModule.get_collection_targets() - for n, cc in enumerate(data): - is_fiducial, gx, gy, cx, cy, ox, oy = cc - points.append([gx, gy]) - points = np.array(points) - method = "trajectory" - xp = (1000 * points).astype(int) # microns then round int - params = (xp[:, 0].tolist(), xp[:, 1].tolist()) - self.daq_collect_points(points, visualizer_method=method, visualizer_params=params) - - def _OLD_daq_grid_findxtals(self): - feature_size = self._sb_findxtals_feature_size.value() - image = sample_camera.get_image() - findObj(-image, objSize=feature_size, viz=1) - - def _OLD_check_jungfrau_save(self) -> bool: - if jungfrau_detector.is_running_detector(): - saveRaw = jungfrau_detector.is_saving_data() - - if not saveRaw: - box = QMessageBox() - box.setText("Jungfrau save data disabled!") - box.setInformativeText("Jungfrau save data is disabled!") - box.setIcon(QMessageBox.Warning) - box.setDetailedText("Choose to abort, enable and continue, or continue without saving raw data") - btContinue = box.addButton("Continue", QMessageBox.YesRole) - btAbort = box.addButton("OMG! Abort", QMessageBox.NoRole) - btEnable = box.addButton("Enable save and continue", QMessageBox.YesRole) - box.exec_() - ans = box.clickedButton() - if ans == btEnable: - jungfrau_detector.set_save_raw(True) - return True - elif ans == btAbort: - _log.info("not doing helical scan") - return False - return True - return True - - def _OLD_daq_collect_points(self, points, visualizer_method, visualizer_params): - app = QApplication.instance() - cfg = app._cfg - verbose=0xff - fn='/tmp/shapepath' - try: - dt=app._deltatau - except AttributeError: - app._deltatau=dt=deltatau.Deltatau() - try: - jf=app._jungfrau - except AttributeError: - app._jungfrau=jf=detector.Jungfrau() - - sp=dt._shapepath - sp.gen_grid_points(w=15, h=15, pitch=3, rnd=0, ofs=(0, +2000)) - #sp.gen_grid_points(w=5, h=10, pitch=1, rnd=0, ofs=(0, 0));sp.sort_points(False, 10);sp.points - sp.sort_points(False, 15); - sp.meta['pt2pt_time']=10 - sp.setup_gather() - sp.setup_sync(verbose=verbose&32, timeOfs=0.05) - sp.setup_coord_trf() # reset to shape path system - # sp.meta['pt2pt_time']=10 #put between setup_sync and setup_motion to have more motion points than FEL syncs - sp.setup_motion(fnPrg=fn+'.prg', mode=3, scale=1., dwell=10) - sp.homing() # homing if needed - sp.run() # start motion program - sp.wait_armed() # wait until motors are at first position - sp.trigger(0.5) # send a start trigger (if needed) ater given time - if not dt._comm is None: - while True: - p=int(sp.progress()) - if p<0: break - #print('progress %d/%d'%(p, num_pts)) - time.sleep(.1) - sp.gather_upload(fnRec=fn+'.npz') - #dp=deltatau.shapepath.DebugPlot(sp) - #dp.plot_gather(mode=11) - #plt.show(block=False) - #plt.show(block=True) - return - - - - task = self.active_task() - XDIR = -1 - - #folders.make_if_needed() - #if ( cfg.option(AppCfg.ACTIVATE_PULSE_PICKER) and not jungfrau_detector.is_running_detector()): - # if QMessageBox.No == QMessageBox.question(self, "X-rays but no Jungfrau", - # "X-rays will be used bu the Jungfrau will not run.\n\n\tContinue?",): - # _log.warning("user forgot to turn on the jungfrau") - # return - - #if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - # self.escape_goToDataCollection() - - points *= 1000 # delta tau uses micrometers - points[:, 0] *= XDIR # fast X axis is reversed - - - # sync_mode : default=2 - # 0 : no sync at all - # 1 : synchronize start - # 2 : synchronize start and adapt motion speed - # this function generates the code blocks: - # self.sync_wait and self.sync_run - # sync_wait can be put in the program to force a timing sync - # sync_run are the commands to run the whole program - # sync_flag if not using jungfrau =1 otherwise =0 - # D.O. shapepath.meta.update(sync_mode=2, sync_flag=1) - sp.meta.update(sync_mode=0, sync_flag=0) - - maxacq_points = 116508 - samp_time = 0.0002 # s - overhead_time = 0.1 - etime=10 - vscale=1.0 - #etime = settings.value("exposureTime", type=float) - #vscale = settings.value(DELTATAU_VELOCITY_SCALE, 1.0, type=float) - #sort_points = option(DELTATAU_SORT_POINTS) - - acq_per = int(np.ceil((etime * len(points) + overhead_time) / (maxacq_points * samp_time))) - _log.info(f"gather acquisotion period = {acq_per}") - _log.info(f"velocity scale {vscale}") - sp.setup_gather(acq_per=acq_per) - sp.setup_sync(verbose=True) - sp.setup_coord_trf() - - assert(points.dtcfgype==np.float64) - sp.points = points - - if TASK_GRID == task: - # width, height = visualizer_params - # _log.debug(f"grid: {width} x {height}") - # details_1 = [width] - # details_2 = [height] - # sp.sort_points(xy=False, grp_sz=height) - pass - elif task in (TASK_PRELOCATED, TASK_EMBL): - if sort_points: - shapepath.sort_points() - self.daq_method_prelocated_remove_markers() - details_1, details_2 = visualizer_params - - sp.setup_motion( - mode=3, # 1 = bad pvt 3 = pft (pvt via inverse fourier transform) - pt2pt_time=etime * 1000., - #fnPrg=folders.get_prefixed_file("_program.prg"), - scale=vscale, # velocity at target position scaling: 1=optimal speed, 0=zero speed - dwell=10, # milli-seconds wait - ) - sp.run() - - self.qprogress = QProgressDialog(self) - self.qprogress.setRange(0, 0) - self.qprogress.setLabelText("Acquiring GRID") - self.qprogress.setCancelButtonText("Abort Acquisition") - self.qprogress.canceled.connect(self.complete_daq) - self.qprogress.setWindowModality(Qt.WindowModal) - self.qprogress.setAutoClose(True) - self.qprogress.show() - - sequencer_steps = [lambda: self.grids_pause_stage_tracking()] - - if jungfrau_detector.is_running_detector(): - if not self.check_jungfrau_save(): - # user aborted run from save data dialog - return - - n_frames = ntrigger - uid = settings.value(EXPERIMENT_UID, type=int) - backend_extras = self.jungfrau.get_parameters() - backend_extras.update( - { - "swissmx_trajectory_method": visualizer_method, - "swissmx_trajectory_details_1": details_1, - "swissmx_trajectory_details_2": details_2, - } - ) - jungfrau_detector.set_number_of_frames(n_frames) - jungfrau_detector.set_data_owner_uid(uid) - sequencer_steps.extend( - [ - lambda: jungfrau_detector.configure( - n_frames=n_frames, - outfile=folders.prefix, - outdir=folders.raw_folder, - uid=uid, - backend_extras=backend_extras, - ), - lambda: jungfrau_detector.arm(), - ] - ) - - sequencer_steps.append(lambda: shapepath.wait_armed()) - if option(ACTIVATE_PULSE_PICKER): - sequencer_steps.append(lambda: pulsePicker.open()) - - # if settings.value("scanning/trigger_microscope_camera", type=bool): - # sample_camera.switch_to_trigger(True) - - sequencer_steps.append(lambda: shapepath.trigger(wait=0.5)) - - def _OLD_shapepath_progress(): - while True: - p = shapepath.progress() - if p < 0: - break - time.sleep(0.1) - self.qprogress.setLabelText(f"Acquiring GRID {p:.0f} / {ntrigger}") - _log.warning(f"motion complete!") - # sample_camera.stop_camera() - # sample_camera.switch_to_trigger(False) - # sample_camera.save_buffer_series(folders.prefix) - - sequencer_steps.append(shapepath_progress) - - if option(ACTIVATE_PULSE_PICKER): - sequencer_steps.append(lambda: pulsePicker.close()) - - sequencer_steps.append(lambda: jungfrau_detector.wait_finished()) - - sequencer_steps.append(lambda: self.grids_start_stage_tracking()) - - self.sequencer = Sequencer(steps=sequencer_steps) - self._thread = QThread() - self._thread.setObjectName("acquisition_thread") - self.sequencer.moveToThread(self._thread) - self.sequencer.finished.connect(self.daq_collect_points_wrapup) - self._thread.started.connect(self.sequencer.run_sequence) - self._thread.start() - - def _OLD_run_steps(self, steps, title, at_end=None, cancelable=False): - dlg = QProgressDialog(self) - dlg.setWindowTitle(title) - dlg.setWindowModality(Qt.WindowModal) - dlg.setMinimumDuration(0) - if not cancelable: - dlg.setCancelButton(None) - dlg.setRange(0, 0) - dlg.setLabelText(f"{title}
") - dlg.setAutoClose(True) - dlg.show() - dlg.setValue(random.randint(1, 20)) - class Runner(QObject): - finito = pyqtSignal() - timeoutExpired = pyqtSignal() - errorHappened = pyqtSignal(str) - result = pyqtSignal(str) - - def __init__(self, step_to_run): - super().__init__() - self.step = step_to_run - self.exception = None - self.done = False - - def run(self): - try: - self.step() - except Exception as e: - _log.debug(" +> step exception") - self.exception = str(e) - self.errorHappened.emit(str(e)) - self.finito.emit() - - - for n, step in enumerate(steps): - _log.info(f"running step {step.title}") - dlg.setLabelText(f"{title}
{step.title}") - dlg.setValue(n) - thread = QThread() - runner = Runner(step) - runner.moveToThread(thread) - thread.started.connect(runner.run) - runner.finito.connect(thread.quit) - thread.start() - while thread.isRunning(): - dlg.setValue(random.randint(1, 20)) - time.sleep(0.01) - if dlg.wasCanceled(): - # FIXME ensure we abort the running thread - break - - if dlg.wasCanceled(): - break - if runner.exception is not None: - QMessageBox.critical(self, step.title, str(runner.exception)) - break - - if dlg.wasCanceled(): - _log.error(f"sequence {title} was cancelled by user") - raise AcquisitionAbortedException(f"sequence {title} was cancelled by user") - - if at_end is not None: - at_end() - dlg.reset() - - def _OLD_daq_collect_points_wrapup(self): - self.qprogress.reset() - if self._thread.isRunning(): - self._thread.quit() - shapepath.gather_upload(os.path.join(folders.res_folder, folders.prefix + ".npz")) - - if option(DELTATAU_SHOW_PLOTS): - dp = DebugPlot(shapepath) - dp.plot_gather(mode=1) - pyplot.show() - - if TASK_PRELOCATED == self.active_task(): - self.daq_method_prelocated_update_markers() - - if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - self.cb_esc_sample_alignment() - - sequence = {"delta tau program": shapepath.prg, "points": shapepath.points.tolist(), "timestamp": tdstamp(),} - - sfname = folders.get_prefixed_file("_ScanInfo.json") - try: - with open(sfname, "w") as sf: - _log.info("writing scan info into: {}".format(sfname)) - sf.write(json.dumps(sequence)) - except: - _log.warning(f"failed to write scan info to {sfname}") - - self.re_connect_collect_button() - jungfrau_detector.abort() - self.increaseRunNumberRequest.emit() - - def _OLD_daq_collect_update_inspect(self, msg): - te = self._inspect - m = te.toPlainText() - te.setPlainText(m + msg + "\n") - te.verticalScrollBar().setValue(te.verticalScrollBar().maximum()) - - def _OLD_daq_helical_collect(self): - """[ - [{ - 0: (0.0, 1.238401694734829, 3.527, 0.936, 0.001), - 120: (0.0, 1.3890393596274455, -1.957242824091597, -0.5639999999999998, 120.001), - 240: (0.0, 1.3866130349657206, -1.1642619618562273, 3.105, 240.001) - }, - { - 0: (0.0, 1.238401694734829, 3.527, 0.936, 0.001), - 120: (0.0, 1.3890393596274455, -1.957242824091597, -0.5639999999999998, 120.001), - 240: (0.0, 1.3866130349657206, -1.1642619618562273, 3.105, 240.001) - }] - ] - """ - _log.info("executing collection") - htab = self._helical_scan_table - num_h = htab.scanHorizontalCount() - num_v = htab.scanVerticalCount() - - if ( settings.value(ACTIVATE_PULSE_PICKER) and not jungfrau_detector.is_running_detector()): - if QMessageBox.No == QMessageBox.question(self, "X-rays but no Jungfrau", - "X-rays will be used bu the Jungfrau will not run.\n\n\tContinue?",): - _log.warning("user forgot to turn on the jungfrau") - return - - if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - self.cb_esc_data_collection() - - folders.make_if_needed() - - data = htab.get_data() - _log.debug(data) - start, end = data[0] - FX, FY, BX, BZ, O = range(5) - x = ( - (-1000 * start[0][BX], -1000 * start[120][BX], -1000 * start[240][BX]), - (-1000 * end[0][BX], -1000 * end[120][BX], -1000 * end[240][BX]), - ) - y = (1000 * start[0][FY], 1000 * end[0][FY]) - z = ( - (-1000 * start[0][BZ], -1000 * start[120][BZ], -1000 * start[240][BZ]), - (-1000 * end[0][BZ], -1000 * end[120][BZ], -1000 * end[240][BZ]), - ) - - if jungfrau_detector.is_running_detector(): - if not self.check_jungfrau_save(): - return - saveRaw = jungfrau_detector.is_saving_data() - - _log.debug(f"x = {x}") - _log.debug(f"y = {y}") - _log.debug(f"z = {z}") - - oscillationAngle = settings.value("oscillationAngle", type=float) - exposureTime = 1000 * settings.value("exposureTime", type=float) - blastRadius = settings.value("blastRadius", type=float) - totalRange = num_v * num_h * oscillationAngle - - # sync_mode : default=2 - # 0 : no sync at all - # 1 : synchronize start - # 2 : synchronize start and adapt motion speed - # this function generates the code blocks: - # self.sync_wait and self.sync_run - # sync_wait can be put in the program to force a timing sync - # sync_run are the commands to run the whole program - # sync_flag if not using jungfrau =1 otherwise =0 - # D.O. helical.meta.update(sync_mode=2, sync_flag=1) - helical.meta.update(sync_mode=0, sync_flag=0) - helical.calcParam(x=x, y=y, z=z) - helical.setup_gather() - helical.setup_sync() - helical.setup_coord_trf() - mode = 1 - hRng = (-blastRadius * num_h, blastRadius * num_h) - w_start = 1000 * htab.startAngle() - wRng = (w_start, w_start + (totalRange * 1000)) - _log.info( - f"helical params mode={mode}, cnthor={num_h}, cntvert={num_v}, hrng={hRng}, wrng={wRng}" - ) - helical.setup_motion( - mode=mode, - cntHor=num_h, - cntVert=num_v, - hRng=hRng, - wRng=wRng, - pt2pt_time=exposureTime, - ) # hRng in micrometers - helical.run() - try: - with open(folders.get_prefixed_file("_helical_debug.cmd"), "w") as fd: - fd.write("calcParam(x={}, y={}, z={})".format(x, y, z)) - except: - pass - - self.qprogress = QProgressDialog(self) - self.qprogress.setRange(0, 0) - self.qprogress.setLabelText("Acquiring HELICAL") - self.qprogress.setCancelButtonText("Abort Acquisition") - self.qprogress.canceled.connect(self.complete_daq) - self.qprogress.setWindowModality(Qt.WindowModal) - self.qprogress.setAutoClose(True) - self.qprogress.show() - - sequencer_steps = [lambda: self.grids_pause_stage_tracking()] - - n_frames = num_h * num_v - if jungfrau_detector.is_running_detector(): - uid = settings.value(EXPERIMENT_UID, type=int) - backend_extras = self.jungfrau.get_parameters() - backend_extras.update( - { - "swissmx_trajectory_method": "grid", - "swissmx_trajectory_details_1": [-num_h], - "swissmx_trajectory_details_2": [num_v], - } - ) - - jungfrau_detector.set_number_of_frames(n_frames) - jungfrau_detector.set_data_owner_uid(uid) - sequencer_steps.extend( - [ - lambda: jungfrau_detector.configure( - n_frames=n_frames, - outfile=folders.prefix, - outdir=folders.raw_folder, - uid=uid, - backend_extras=backend_extras, - ), - lambda: jungfrau_detector.arm(), - ] - ) - - sequencer_steps.append(lambda: helical.wait_armed()) - if settings.value(ACTIVATE_PULSE_PICKER): - sequencer_steps.extend([lambda: pulsePicker.open(), lambda: pend_event(0.1)]) - - sequencer_steps.append(lambda: helical.trigger()) - - def _OLD_motion_progress(): - while True: - p = helical.progress() - if p < 0: - break - time.sleep(0.1) - self.qprogress.setLabelText(f"Acquiring HELICAL {p:.0f} / {n_frames}") - _log.warning(f"helical motion complete!") - - sequencer_steps.append(motion_progress) - - if settings.value(ACTIVATE_PULSE_PICKER): - sequencer_steps.append(lambda: pulsePicker.close()) - - sequencer_steps.append(lambda: self.grids_start_stage_tracking()) - - self.sequencer = Sequencer(steps=sequencer_steps) - self._thread = QThread() - self._thread.setObjectName("acquisition_thread") - self.sequencer.moveToThread(self._thread) - self.sequencer.finished.connect(self.daq_helical_collect_wrapup) - self._thread.started.connect(self.sequencer.run_sequence) - self._thread.start() - - def _OLD_daq_helical_collect_wrapup(self): - try: - self.qprogress.reset() - except: - pass - if self._thread.isRunning(): - self._thread.quit() - helical.gather_upload(os.path.join(folders.res_folder, folders.prefix + ".npz")) - - self.re_connect_collect_button() - jungfrau_detector.abort() - if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - self.cb_esc_sample_alignment() - self.increaseRunNumberRequest.emit() - - if option(DELTATAU_SHOW_PLOTS): - hsgui = HelicalScanGui(helical) - hsgui.interactive_anim() - - def _OLD_complete_daq(self): - _log.info("daq completed: cleaning up") - try: - self.qprogress.reset() - except: - pass - try: - if self._thread.isRunning(): - self._thread.quit() - except: - pass - finally: - self.abort_measurement() - self.re_connect_collect_button() - - def _OLD_re_connect_collect_button(self, callback=None, **kwargs): - _log.debug("re_connect_collect_button() {} => {}".format(callback, kwargs)) - return - # button = self._button_collect - # if callback is None: - # callback = self.execute_collection - # button.setAccessibleName("collect_button") - # kwargs["label"] = "Collect" - # - # try: - # button.disconnect() - # finally: - # button.clicked.connect(callback) - # - # if "accessibleName" in kwargs: - # button.setAccessibleName(kwargs["accessibleName"]) - # - # if "label" in kwargs: - # button.setText(kwargs["label"]) - # self.load_stylesheet() - - def _OLD_collect_abort_grid(self): - self._is_aborted = True - try: - self._eigerwaitthread._is_aborted = True - except: - pass - _log.warning("aborting grid scan") - self.abort_measurement() - delta_tau.abort() - jungfrau_detector.disarm() - self.re_connect_collect_button() - - def _OLD_create_escape_toolbar(self): - cont = self._wd_right - w = QGroupBox("Escape") - layout = QHBoxLayout() - w.setLayout(layout) - but = QPushButton("Exchange\nSample") - but.setAccessibleName("escape_button_se") - but.setObjectName("action_SampleExchange") - but.clicked.connect(self.cb_esc_sample_exchange) - layout.addWidget(but) - but = QPushButton("Alignment") - but.setAccessibleName("escape_button_sa") - but.clicked.connect(self.cb_esc_sample_alignment) - layout.addWidget(but) - but = QPushButton("Collection") - but.setAccessibleName("escape_button_dc") - but.clicked.connect(self.cb_esc_data_collection) - layout.addWidget(but) - cont.layout().addWidget(w) - - def _OLD_daq_method_prelocated_remove_markers(self): - try: - for m in self._marker_rois: - m.disconnect_signals() - self.vb.removeItem(m) - except Exception as e: - _log.warning("maybe failed removing markers: {}".format(e)) - self._marker_rois = [] - - def _OLD_pause_all_markers(self): - for m in self._marker_rois: - m.disconnect_signals() - - def _OLD_resume_all_markers(self): - for m in self._marker_rois: - m.reconnect_signals() - - def _OLD_daq_method_prelocated_update_markers(self): - self.daq_method_prelocated_remove_markers() - data = self.prelocationModule.get_data() - add_xtals = self.prelocationModule._xtals_transformed - draw_xtals = self.prelocationModule.set_draw_crystal_marks - vb = self.vb - self._marker_rois = [] - ppm = self.getPpm() - for n, cc in enumerate(data): - is_fiducial, gx, gy, cx, cy, ox, oy = cc - if not is_fiducial: - if not (add_xtals and draw_xtals): - continue - _log.debug(f"adding {'fiducial' if is_fiducial else 'xtal'} mark #{n}: {is_fiducial} {gx:.3f}, {gy:.3f}, {cx:.1f}, {cy:.1f}") - m = CstROI.CrystalCircle( - gonio_xy=(gx, gy), - parent=self, - model_row_index=n, - is_fiducial=is_fiducial, - ppm=ppm, - ) - # m.sigRegionChangeFinished.connect(lambda roi=m: self.daq_method_prelocated_update_model(roi)) - self._marker_rois.append(m) - vb.addItem(m) - for c in self._marker_rois: - c.reconnect_signals() - c.follow_stage() - - def _OLD_daq_method_prelocated_set_fiducial(self, camx, camy, gx, gy): - _log.debug(f"camx, camy: {camx}, {camy}, fx, fy: {gx, gy}") - self.prelocationModule.set_fiducial_coords(camx, camy, gx, gy) - - def _OLD_daq_method_prelocated_append_data(self, x, y, gx, gy): - _log.debug("appending to model: {} {}".format((x, y), (gx, gy))) - self.prelocationModule.append_data((x, y, gx, gy)) - self.daq_method_prelocated_update_markers() - - def _OLD_daq_method_prelocated_update_model(self, roi): - row = roi.get_model_row() - pos = roi.pos() - self.prelocationModule.set_data_camera(row, pos) - _log.debug("updating row {} => {}".format(row, pos)) - - def _OLD_daq_method_prelocated_add_reference(self): - self._references.append(pg.CircleROI()) - - def _OLD_move_fast_stage(self, x, y): - _log.info(f"received request to move gonio to x, y = {x:.3f}, {y:.3f} mm") - fx_motor, fy_motor, bx_motor, bz_motor, omega_motor = self.get_gonio_tweakers() - fx_motor.move_abs(x) - fy_motor.move_abs(y) - - def _OLD_toggle_maximized(self): - if self.isMaximized(): - self.showNormal() - else: - self.showMaximized() - - def _OLD_show_window_configuration(self): - _log.debug("maximized? {}".format(self.isMaximized())) - - def _OLD_update_user_and_storage(self): - global folders - pgroup = settings.value(EXPERIMENT_PGROUP, "not_set_yet") - diag = GenericDialog( title="P-group for experiment", message="Enter the p-group to be used", - inputs={EXPERIMENT_PGROUP: ("P-group", pgroup, QLineEdit(pgroup))}, use_buttons=False,) - diag.setModal(True) - - run_user = getpass.getuser() - - pgrp_re = re.compile(r"^p(?P\d{5})$") - - if not self.is_recently_active(): - diag.exec() - results = diag.results - for k, v in results.items(): - m = pgrp_re.match(v) - if m: - settings.setValue(k, v) - settings.setValue(EXPERIMENT_UID, int(m["uid"])) - else: - QMessageBox.critical(self, "wrong P-group format", "P-groups are in the format:\n\n\t\tp?????\n\n\twhere ? = digit",) - self.update_user_and_storage() - return - settings.sync() - folders.set_pgroup(settings.value(EXPERIMENT_PGROUP)) - try: - folders.check_permissons() - except: - folder = folders.pgroup_folder - pgroup = settings.value(EXPERIMENT_PGROUP) - box = QMessageBox() - box.setText("No Write Permission!") - box.setInformativeText("User {} has no write access to p-group {} folder:\n ➜ {}\n".format(run_user, pgroup, folder)) - box.setIcon(QMessageBox.Warning) - box.setDetailedText("The folder /sf/bernina/data/{pgroup}/res/ has to writable by the user {user}, currently running the SwissMX app.".format(pgroup=pgroup, user=run_user)) - btIgnore = box.addButton("Ignore", QMessageBox.NoRole) - btRetry = box.addButton("Le'me try again", QMessageBox.YesRole) - box.exec_() - ans = box.clickedButton() - if ans == btRetry: - self.update_user_and_storage() - elif ans == btIgnore: - _log.warning("no write access to pgroup but user didn't care") - - self._label_pgroup.setText(settings.value(EXPERIMENT_PGROUP)) - - def _OLD_is_recently_active(self): - last_active = settings.value("last_active", 0, type=float) - minutes_since_last = int((time.time() - last_active) / 60.0) - return minutes_since_last < 60 - - def _OLD_openPreferencesDialog(self): - PreferencesDialog(self).exec_() - - def _OLD_set_app_icon(self): - scriptDir = os.path.dirname(os.path.realpath(__file__)) - self.setWindowIcon(QtGui.QIcon(os.path.join(scriptDir + os.path.sep + "logo.png"))) - - def _OLD_set_widget_background_color(self, color): - """change a widget's color - :param color: - :return: - """ - try: - color = QtGui.QColor.colorNames().index(color) - except: - return - p = self.palette() - p.setColor(self.backgroundRole(), color) - self.setPalette(p) - -# functions are prefixed with _OLD_ - def _OLD_build_daq_methods_grid_tab(self): - self._grids = [] - tab = self._tab_daq_method_grid - layout = tab.layout() # gridlayout - self._sb_grid_x_step.setValue(30) - self._sb_grid_y_step.setValue(30) - self._bt_add_grid.clicked.connect(self._OLD_daq_grid_add_grid) - self._bt_remove_all_grids.clicked.connect(self._OLD_daq_grid_remove_all) - self._find_targets_from_microscope_image.clicked.connect(self._OLD_daq_grid_findxtals) - self.addGridRequest.connect(self._OLD_daq_grid_add_grid) - self.gridUpdated.connect(self._OLD_daq_grid_update) - - def _OLD_build_daq_methods_prelocated_tab(self): - tab = self._tab_daq_method_prelocated - self.prelocationModule = PrelocatedCoordinatesModel.PrelocatedCoordinates(parent=self) - tab.layout().addWidget(self.prelocationModule) - self.prelocationModule.prefixSelected.connect(lambda prefix: self._le_prefix.setText(prefix)) - self.prelocationModule.dataFileLoaded.connect(self._OLD_daq_method_prelocated_update_markers) - self.prelocationModule.prelocatedDataUpdated.connect(self._OLD_daq_method_prelocated_update_markers) - self.prelocationModule.markersDeleted.connect(self._OLD_daq_method_prelocated_remove_markers) - self.fiducialPositionSelected.connect(self._OLD_daq_method_prelocated_set_fiducial) - self.appendPrelocatedPosition.connect(self._OLD_daq_method_prelocated_append_data) - self.prelocationModule.moveFastStageRequest.connect(self._OLD_move_fast_stage) - self._preloc_inspect_area = QPlainTextEdit() - tab.layout().addWidget(self._preloc_inspect_area) - - def _OLD_build_daq_methods_embl_tab(self): - app = QApplication.instance() - self._tab_daq_method_embl.setLayout(QVBoxLayout()) - layout = self._tab_daq_method_embl.layout() - #motors = self.get_gonio_motors() - self._embl_module = EmblWidget(self) #ZAC: orig. code - #self._embl_module.configure(motors, app._camera, app._zoom) - layout.addWidget(self._embl_module) - - def _OLD_create_helical_widgets(self): - tbox = self._helical_tablebox - htab = self._helical_scan_table = HelicalTableWidget() - htab.gonioMoveRequest.connect(self._OLD_move_gonio_to_position) - tbox.setLayout(QVBoxLayout()) - - grp = QWidget() - grp.setLayout(QFormLayout()) - le = QSpinBox() - le.setRange(1, 100) - le.setValue(htab.scanHorizontalCount()) - le.valueChanged.connect(lambda cnt: htab.setScanHorizontalCount(cnt)) - grp.layout().addRow("Horizontal Count", le) - - le = QSpinBox() - le.setRange(1, 100) - le.setValue(htab.scanVerticalCount()) - le.valueChanged.connect(lambda cnt: htab.setScanVerticalCount(cnt)) - grp.layout().addRow("Vertical Count", le) - - le = QDoubleSpinBox() - le.setRange(-180.0, 180.0) - le.setSingleStep(5.0) - le.setSuffix(" degrees") - le.valueChanged.connect(htab.setStartAngle) - grp.layout().addRow("Start angle", le) - - tbox.layout().addWidget(grp) - widgi = QWidget() - widgi.setLayout(QHBoxLayout()) - tbox.layout().addWidget(widgi) - - but = QPushButton("Add Crystal") - but.clicked.connect(htab.add_xtal) - widgi.layout().addWidget(but) - - but = QPushButton("Set START") - but.clicked.connect(lambda: htab.set_xtal_start(self.get_gonio_positions())) - widgi.layout().addWidget(but) - - but = QPushButton("Set END") - but.clicked.connect(lambda: htab.set_xtal_end(self.get_gonio_positions())) - widgi.layout().addWidget(but) - - tbox.layout().addWidget(htab) - - def _OLD_add_beam_marker(self): - app = QApplication.instance() - cfg = app._cfg - w, h = cfg.value(AppCfg.GEO_BEAM_SZ) - self._beammark = bm = CstROI.BeamMark([100, 100], (int(w), int(h)), parent=self) - tr=QtGui.QTransform() # prepare ImageItem transformation: - tr.rotate(30) - bm.setTransform(tr) # assign transform - self.vb.addItem(self._beammark) - bm=UsrGO.BeamMark([50, 120], [30, 20]) - self.vb.addItem(bm) - vi=UsrGO.Grid((120, -100), (200, 150), (30, 20), 2) - self.vb.addItem(vi) - - def _OLD_camera_pause_toggle(self): - app=QApplication.instance() - app._camera.pause() - - def _OLD_init_settings_tracker(self): - app=QApplication.instance() - cfg=app._cfg - _log.info("configuring widget persistence") - fields = { - # 'folder': (self._label_folder, str), - "project": (self._le_project, str), - "prefix": (self._le_prefix, str), - "actual_prefix": (self._label_actual_prefix, str), - "exposureTime": (self._dsb_exposure_time, float), - "oscillationAngle": (self._dsb_oscillation_step, float), - "blastRadius": (self._dsb_blast_radius, float), - } - for key, f_config in fields.items(): - widget, conv = f_config - value = cfg.value(key) - try: - wset, wget = widget.setText, widget.text - _log.debug("tracking text field {}".format(key)) - except AttributeError: - _log.debug("tracking {} number field {}".format(conv, key)) - wset, wget = widget.setValue, lambda fget=widget.value: conv(fget()) - except Exception as e: - _log.error(e) - - try: - wset(conv(value)) - except Exception as e: - _log.debug(e) - _log.warning('failed for "{}" updating field of type {} with {}'.format( key, type(widget), value)) - finally: - # _log.debug('wget = {}; wset = {}'.format(wget, wset)) - widget.editingFinished.connect(lambda w=widget, k=key, func_get=wget: self.persist_setting(k, func_get() ) ) - #self.storage_cascade_prefix(None) #ZAC: orig. code - - def _OLD_init_validators(self): - identifier_regex = QRegExp("[a-z-A-Z_0-9%]+") - self._le_project.setValidator(QRegExpValidator(identifier_regex, self._le_project)) - self._le_prefix.setValidator(QRegExpValidator(identifier_regex, self._le_prefix)) - - def _OLD_wire_storage(self): - self._le_prefix.textChanged.connect(self._OLD_storage_cascade_prefix) - self._le_prefix.textChanged.connect(lambda newtext: self.prefixChanged.emit(newtext)) - self._le_project.textChanged.connect(self._OLD_storage_cascade_prefix) - self._le_project.textChanged.connect(lambda newtext: self.projectChanged.emit(newtext)) - self._le_prefix.editingFinished.connect(self._OLD_prepare_daq_folder) - self._le_project.editingFinished.connect(self._OLD_prepare_daq_folder) - self.increaseRunNumberRequest.connect(self._OLD_increase_run_number) - - def _OLD_storage_cascade_prefix(self, val): - prefix = self._le_prefix.text() - if 0 == len(prefix): - _log.warning("empty prefix is not accepted") - self._le_prefix.setAccessibleName("invalid_input") - self._le_prefix.blockSignals(True) - self._le_prefix.setText("INVALID=>" + prefix) - QMessageBox.warning(self, "prefix is not valid", "Prefix is not valid!") - self._le_prefix.blockSignals(False) - - return - else: - self._le_prefix.setAccessibleName("") - project = self._le_project.text() - folders.set_prefix(prefix) - folders.set_project(project) - folders.run = settings.value("run_number", type=int) - self._label_runnumber.setText(f"{folders.run:04d}") - self._data_folder = folders.raw_folder - self.folderChanged.emit(folders.raw_folder) - self._label_actual_prefix.setText(folders.prefix) - self._label_folder.setText(folders.raw_folder) - - def _OLD_increase_run_number(self): - run = settings.value("run_number", type=int) - run += 1 - settings.setValue("run_number", run) - folders.run = run - self._label_runnumber.setText(f"{run:04d}") - - def _OLD_prepare_daq_folder(self): - global home, folders - prefix = folders.prefix - folder = folders.res_folder - if 0 == len(prefix): - return - - try: - os.makedirs(folder, 0o750, exist_ok=True) - except: - msg = "Failed to create folder: {}".format(folder) - _log.warning(msg) - QMessageBox.warning(self, "Screenshot: failed to create folder", "Failed to create output folder for screenshot!\n\n\tScreenshot not taken!",) - raise - - fname = os.path.join(folders.pgroup_folder, ".latest_raw") - try: - with open(fname, "w") as f: - f.write(folders.raw_folder) - _log.info("wrote: {}".format(fname)) - except: - _log.warning("failed writing {}".format(fname)) - - fname = os.path.join(folders.pgroup_folder, ".latest_res") - try: - with open(fname, "w") as f: - f.write(folders.res_folder) - _log.info("wrote: {}".format(fname)) - except: - _log.warning("failed writing {}".format(fname)) - - def _OLD_persist_setting(self, s, v): - app=QApplication.instance() - cfg=app._cfg - _log.debug("persisting {} = {}".format(s, v)) - cfg.setValue(s, v) - - def _OLD_method_changed(self, index): - method = self._tabs_daq_methods.currentWidget().accessibleName() - _log.info("method now => {}".format(method)) - - - - def _OLD_check_zescape(self): - msg = zescape.check() - if msg is None: - return - if "current" in msg: - _log.warning(f"current state: {self._esc_state}") - zescape.reply(self._esc_state) - elif "goto" in msg: - state = msg.split()[1].lower() - _log.warning(f"TELL requests to go to {state}") - try: - if "sampleexchange" in state: - _log.debug( - f"moving to mount with offset = {self._pin_mounting_offset}" - ) - self.move_gonio_to_mount_position(offset=self._pin_mounting_offset) - elif "samplealignment" in state: - self.cb_esc_sample_alignment() - except: - zescape.reply("Maintenance") - zescape.reply(self._esc_state) - else: # JSON - data = json.loads(msg) - if "sampleName" in data: - _log.debug(f"TELL SAMPLE DATA => {data}") - self.tell2storage(data) - zescape.reply("ack") - elif "pin_offset" in data: - _log.debug(f"TELL pin offset => {data}") - self._pin_mounting_offset = data["pin_offset"] - zescape.reply("ack") - elif "get_pin_offset" in data: - _log.debug(f"TELL get pin offset => {data}") - zescape.reply_json({"pin_offset": self._pin_mounting_offset}) - - def _OLD_tell2storage(self, sample): - _log.debug(f"2 TELL SAMPLE DATA => {type(sample)}") - self._le_prefix.setText(sample["sampleName"]) - self._le_project.setText(sample["sampleFolder"]) - tstf = folders.get_prefixed_file("_newsample") - self.storage_cascade_prefix(None) - _log.warning(f"sample info: {tstf}") - - def _OLD_is_task(self, task): - return task == self._active_task - - def _OLD_get_task_menu(self): - pass - - def _OLD_toggle_shutter(self, **kwargs): - if self._pv_shutter: - if 0 == self._pv_shutter.get(): - self._pv_shutter.put(1) - self._button_shutter.setText("shutter opened\n\u2622") - else: - self._pv_shutter.put(0) - self._button_shutter.setText("shutter closed\n\u2622") - elif self._has_pulse_picker: - pulsePicker.toggle() - - def _OLD_update_shutter_label(self, pvname, value, char_value, **kwargs): - if 0 == value: - self._button_shutter.setText("shutter closed") - else: - self._button_shutter.setText("shutter opened") - - def _OLD_build_sample_selection_tab(self): - self._sample_selection = sample_selection.SampleSelection(self) - self._sample_selection.move_to_mount_position = (self.move_gonio_to_mount_position) - self._tab_sample_selection.setLayout(QVBoxLayout()) - self._tab_sample_selection.layout().addWidget(self._sample_selection) - self._tab_sample_selection.layout().addStretch(2) - - def _OLD_build_embl_group(self): - grp = QGroupBox("EMBL Acquisition") - layout = QFormLayout() - grp.setLayout(layout) - layout.addWidget(QLabel("Prefix")) - self._embl_prefix = QLineEdit("img") - layout.addWidget(self._embl_prefix) - - def _OLD_abort_measurement(self, ev=None): - if settings.value(ACTIVATE_PULSE_PICKER): - pulsePicker.close() - jungfrau_detector.abort() - delta_tau.abort() - _log.debug("aborting measurement") - - def _OLD_trigger_detector(self, **kwargs): - if self._pv_shutter is not None: - self._pv_shutter.put(0) - # self._eiger_button_collect.show() - # self._eiger_button_abort.hide() - # self._eiger_now_collecting_label.setText( - # "Finished sequence id: {}\n" - # "Data in: Data10/{}".format( - # self._detector_sequence_id, self._eiger_now_collecting_file - # ) - # ) - - def _OLD_modify_camera_transform(self, t): - if t == "remove_all": - sample_camera.set_transformations([]) - elif t == "undo_last": - sample_camera._transformations.pop() - #elif type(t) ==type(camera.Transforms): #ZAC: orig. code - # sample_camera.append_transform(t) - try: - label = ", ".join([t.name for t in sample_camera._transformations]) - except: - label = "" - self._label_transforms.setText(label) - #settings.setValue(CAMERA_TRANSFORMATIONS, sample_camera._transformations) #ZAC: orig. code - - def _OLD_roi_add_line(self): - roi = pg.LineSegmentROI( - [200, 200], - [300, 300], - pen="r", - scaleSnap=True, - translateSnap=True, - rotateSnap=True, - removable=True, - ) - # roi.sigRegionChanged.connect(self.track_roi) - roi.sigRemoveRequested.connect(self.remove_roi) - self.vb.addItem(roi) - self._rois.append(roi) - - def _OLD_roi_add_rect(self): - roi = pg.RectROI( - [200, 200], - [50, 50], - pen="r", - scaleSnap=True, - translateSnap=True, - rotateSnap=True, - removable=True, - ) - roi.sigRegionChanged.connect(self.track_roi) - roi.sigRemoveRequested.connect(self.remove_roi) - self.vb.addItem(roi) - self._rois.append(roi) - - def _OLD_remove_roi(self, roi): - self.vb.removeItem(roi) - self._rois.remove(roi) - - def _OLD_prepare_microscope_page(self): - layout = self.microscope_page.layout() - container = QWidget() - hlay = QHBoxLayout() - container.setLayout(hlay) - layout.addWidget(container) - - def _OLD_update_beam_marker(self, zoom_lvl): - w, h = settings.value(BEAM_SIZE) - try: - bx = self.beamx_fitter(zoom_lvl) - by = self.beamy_fitter(zoom_lvl) - ok = True - except: - ok = False - _log.warning("beam marker not defined") - return - _log.debug("updating beam mark to {:.1f}x{:.1f}".format(bx, by)) - self.beamCameraCoordinatesChanged.emit(bx, by) - - def _OLD_update_beam_marker_fitters(self): - if len(self._beam_markers) > 2: - _log.debug("defining beam marker") - bx = [(n, x[0]) for n, x in self._beam_markers.items()] - by = [(n, x[1]) for n, x in self._beam_markers.items()] - nbx = np.asarray(bx).T - nby = np.asarray(by).T - bx_coefs = np.polyfit(nbx[0], nbx[1], 3) - by_coefs = np.polyfit(nby[0], nby[1], 3) - _log.debug(".... beam marker X coeficients {}".format(bx_coefs)) - _log.debug(".... beam marker Y coeficients {}".format(by_coefs)) - self.beamx_fitter = np.poly1d(bx_coefs) - self.beamy_fitter = np.poly1d(by_coefs) - - - def _OLD_append_to_beam_markers(self, x, y, zoom): - self._beam_markers[zoom] = (x, y) - _log.info("beam markers {}".format(self._beam_markers)) - settings.setValue(BEAM_MARKER_POSITIONS, self._beam_markers) - self.update_beam_marker_fitters() - - def _OLD_remove_beam_markers(self): - self._beam_markers = {} - self.beamx_fitter = None - self.beamy_fitter = None - - def _OLD_track_roi(self, roi): - x, y = roi.pos() - w, h = roi.size() - # area = roi.getArrayRegion(self._im, self.img) - # sum = np.sum(area) - # _log.info('{} => sum {}'.format((x,y), sum)) - bx, by = x + w / 2., y + h / 2. - _log.info("beam pos {}".format((bx, by))) - _log.info("marker pos = {} ; size = {}".format((x, y), (w, h))) - - def _OLD_toggle_mouse_tracking(self): - if self._mouse_tracking: - self.disengage_mouse_tracking() - else: - self.engage_mouse_tracking() - - def _OLD_engage_mouse_tracking(self): - self.glw.scene().sigMouseMoved.connect(self.cb_mouse_move) - self.glw.scene().sigMouseMoved.emit() - self._mouse_tracking = True - - def _OLD_disengage_mouse_tracking(self): - self.glw.scene().sigMouseMoved.disconnect(self.cb_mouse_move) - self._mouse_tracking = False - self._lb_coords.setText("") - - def _OLD_get_beam_mark_on_camera_xy(self): - app=QApplication.instance() - z = app._zoom.get_val() - try: - bx = self.beamx_fitter(z) - by = self.beamy_fitter(z) - except: - bx, by = 500, 500 - return (bx, by) - - def _OLD_move_gonio_to_position(self, fx, fy, bx, bz, omega): - self.tweakers["fast_x"].motor.move(fx, wait=False, ignore_limits=True) - self.tweakers["fast_y"].motor.move(fy, wait=False, ignore_limits=True) - self.tweakers["base_x"].motor.move(bx, wait=False, ignore_limits=True) - self.tweakers["base_z"].motor.move(bz, wait=False, ignore_limits=True) - self.tweakers["omega"].motor.move(omega, wait=False, ignore_limits=True) - - def _OLD_get_gonio_motors(self, as_json=False): - if as_json: - return { - "fast_x": self.tweakers["fast_x"].motor, - "fast_y": self.tweakers["fast_y"].motor, - "base_x": self.tweakers["base_x"].motor, - "base_z": self.tweakers["base_z"].motor, - "omega": self.tweakers["omega"].motor, - } - else: - return ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - - def _OLD_get_gonio_tweakers(self): - return ( - self.tweakers["fast_x"], - self.tweakers["fast_y"], - self.tweakers["base_x"], - self.tweakers["base_z"], - self.tweakers["omega"], - ) - - def _OLD_get_gonio_positions(self, as_json: bool = False): - fx, fy, cx, cz, omega = ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - - a, b, c, d, e = ( - fx.get_position(), - fy.get_position(), - cx.get_position(), - cz.get_position(), - omega.get_position(), - ) - if as_json: - return {"fx": a, "fy": b, "bx": c, "bz": d, "omega": e} - else: - return (a, b, c, d, e) - - def _OLD_escape_goToTellMountPosition(self): - self.move_gonio_to_mount_position() - self.lock_goniometer() - - def _OLD_move_gonio_to_mount_position(self, offset: float = 0.0): - fx, fy, cx, cz, omega = self.get_gonio_motors() - bmark = "bookmark_0" - try: - t_fx = float(settings.value(bmark + "/mount_fx")) - t_fy = -offset + float(settings.value(bmark + "/mount_fy")) - t_cx = float(settings.value(bmark + "/mount_cx")) - t_cz = float(settings.value(bmark + "/mount_cz")) - t_omega = float(settings.value(bmark + "/mount_omega")) - except: - raise IncompleteConfiguration("TELL sample changer mount position is not configured!!!") - fx.move(t_fx, wait=True, ignore_limits=True) - fy.move(t_fy, wait=True, ignore_limits=True) - cx.move(t_cx, wait=True, ignore_limits=True) - cz.move(t_cz, wait=True, ignore_limits=True) - omega.move(t_omega, wait=True, ignore_limits=True) - app_utils.assert_motor_positions( - [ - (fx, t_fx, 0.01), - (fy, t_fy, 0.01), - (cx, t_cx, 0.01), - (cz, t_cz, 0.01), - (omega, t_omega, 0.01), - ] - ) - self.cb_esc_sample_exchange() - - def _OLD_lock_goniometer(self): - # tell.set_in_mount_position(True) - res = QMessageBox.question(self, "", "Mount a sample from console and click ok once the sample is mounted.", QMessageBox.Ok, QMessageBox.Ok,) - res = QMessageBox.question(self, "", "Is the sample is mounted?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No,) - if res in (QMessageBox.Yes, QMessageBox.No): - # tell.set_in_mount_position(False) - pass - - @pyqtSlot(int) - def _OLD_saveBookmark(self, key: int): - """save a bookmark for the corresponding key is the Qt.Key_* code """ - fx, fy, cx, cz, omega = ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - bmark = "bookmark_{}".format(key) - if key == 0: - ans = QMessageBox.question(self, "Override TELL mount position", "This will overwrite the positions used for TELL MOUNTING!!!\n\n\tContinue ?",) - if ans != QMessageBox.Yes: - return - - _log.info( - "saving bookmark {}: {}, {}, {}, {}, {}".format( - bmark, - fx.get_position(), - fy.get_position(), - cx.get_position(), - cz.get_position(), - omega.get_position(), - ) - ) - settings.setValue(bmark + "/mount_fx", fx.get_position()) - settings.setValue(bmark + "/mount_fy", fy.get_position()) - settings.setValue(bmark + "/mount_cx", cx.get_position()) - settings.setValue(bmark + "/mount_cz", cz.get_position()) - settings.setValue(bmark + "/mount_omega", omega.get_position()) - - def _OLD_gotoBookmark(self, key: int): - """save a bookmark for the corresponding key""" - fx, fy, cx, cz, omega = ( - self.tweakers["fast_x"].motor, - self.tweakers["fast_y"].motor, - self.tweakers["base_x"].motor, - self.tweakers["base_z"].motor, - self.tweakers["omega"].motor, - ) - bmark = "bookmark_{}".format(key) - try: - t_fx = float(settings.value(bmark + "/mount_fx")) - t_fy = float(settings.value(bmark + "/mount_fy")) - t_cx = float(settings.value(bmark + "/mount_cx")) - t_cz = float(settings.value(bmark + "/mount_cz")) - t_omega = float(settings.value(bmark + "/mount_omega")) - except: - return - - fx.move(t_fx, wait=True, ignore_limits=True) - fy.move(t_fy, wait=True, ignore_limits=True) - cx.move(t_cx, wait=True, ignore_limits=True) - cz.move(t_cz, wait=True, ignore_limits=True) - omega.move(t_omega, wait=True, ignore_limits=True) - - def _OLD_move_cryojet_nozzle(self, pos): - cx = self.tweakers["cryo"] - if "in" == pos.lower(): - key = CRYOJET_NOZZLE_IN - elif "out" == pos.lower(): - key = CRYOJET_NOZZLE_OUT - - to_pos = settings.value(key, 1e10, type=float) - if to_pos > 1e9: - raise IncompleteConfiguration(f"CRYOJET configuration is incomplete! Missing {key}") - cx.move_abs(to_pos, assert_position=True) - - def _OLD_build_cryo_group(self, toolbox): - pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] - qutilities.add_item_to_toolbox( - toolbox, - "Cryojet", - widget_list=[ - self.get_tweaker(f"{pfx}:MOT_CRYO", alias="cryo", label="cryo X") - ], - ) - - def _OLD_build_wegde_group(self, toolbox): - pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] - qutilities.add_item_to_toolbox(toolbox,"Wedge Mover", - widget_list=[ - self.get_tweaker(f"{pfx}:MOT_WEDGE1", alias="wedge_1", label="wedge_1"), - self.get_tweaker(f"{pfx}:MOT_WEDGE2", alias="wedge_2", label="wedge_2"), - self.get_tweaker(f"{pfx}:MOT_WEDGE3", alias="wedge_3", label="wedge_3"), - self.get_tweaker(f"{pfx}:MOT_WEDGE4", alias="wedge_4", label="wedge_4"), - self.get_tweaker(f"{pfx}:MOT_WEDGEX", alias="wedge_x", label="wedge_x"), - self.get_tweaker(f"{pfx}:MOT_WEDGEY", alias="wedge_y", label="wedge_y"), - self.get_tweaker(f"{pfx}:MOT_WEDGEA", alias="wedge_a", label="wedge_a"), - self.get_tweaker(f"{pfx}:MOT_WEDGEB", alias="wedge_b", label="wedge_b"), - ], - ) - - def _OLD_build_slits_group(self, toolbox): - pfx=QApplication.instance()._cfg.value(AppCfg.GBL_DEV_PREFIX)[0] - qutilities.add_item_to_toolbox( - toolbox, - "Slits", - widget_list=[ - self.get_tweaker(f"{pfx}10", alias="slit_right", label="left", mtype=1, ), - self.get_tweaker(f"{pfx}11", alias="slit_left", label="right", mtype=1,), - self.get_tweaker(f"{pfx}12", alias="slit_bottom", label="bottom", mtype=1,), - self.get_tweaker(f"{pfx}13",alias="slit_top",label="top",mtype=1,), - ], - ) - - def _OLD_assert_post_tube_position(self, pos): - x_up = settings.value("post_sample_tube/x_up", 1e10, type=float) - y_up = settings.value("post_sample_tube/y_up", 1e10, type=float) - x_down = settings.value("post_sample_tube/x_down", 1e10, type=float) - y_down = settings.value("post_sample_tube/y_down", 1e10, type=float) - dx = settings.value("post_sample_tube/dx", 1e10, type=float) - dy = settings.value("post_sample_tube/dy", 1e10, type=float) - tz_in = settings.value("post_sample_tube/z_in", 1e10, type=float) - tz_out = settings.value("post_sample_tube/z_out", 1e10, type=float) - - if (x_up + y_up + x_down + y_down + dx + dy + tz_in + tz_out) > 1e9: - raise Exception("miscofingured positions for post-sample tube") - - usy = self.tweakers["tube_usy"] - dsy = self.tweakers["tube_dsy"] - usx = self.tweakers["tube_usx"] - dsx = self.tweakers["tube_dsx"] - tbz = self.tweakers["tube_z"] - - if pos == "in": - yu = y_up - xu = x_up - yd = y_down - xd = x_down - z = tz_in - elif pos == "out": - yu = y_up + dy - xu = x_up + dx - yd = y_down + dy - xd = x_down + dx - z = tz_out - - app_utils.assert_tweaker_positions([ - (usy, yu, 0.1), - (dsy, yd, 0.1), - (usx, xu, 0.1), - (dsx, xd, 0.1), - (tbz, z, 0.1),],timeout=2.0, - ) - - def _OLD_add_tweaker(self, pv, alias=None, label=None, mtype="epics_motor", layout=None): - if layout is None: - layout = self._tweak_container.layout() - if mtype == "epics_motor": - m = MotorTweak() - else: - m = SmaractMotorTweak() - layout.addWidget(m) - m.connect_motor(pv, label) - self.tweakers[alias] = m - - def _OLD_done_sliding(self): - print("done sliding at {}".format(self.slider_fast_x.value())) - - def _OLD_daq_grid_add_grid(self, gx=None, gy=None): - grid_index = len(self._grids) - if gx in (False, None): - gx=self.tweakers["fast_x"].get_rbv() - gy=self.tweakers["fast_y"].get_rbv() - xstep = self._sb_grid_x_step.value() - ystep = self._sb_grid_y_step.value() - xoffset = self._sb_grid_x_offset.value() - yoffset = self._sb_grid_y_offset.value() - - app=QApplication.instance() - geo=app._geometry - oc=geo._opt_ctr - if xstep==0: - go=UsrGO.Grid((120, -100), (200, 150), (30, 22), 2) - elif xstep==1: - go=UsrGO.FixTargetFrame((120, -100), (200, 150), tpl='test') - elif xstep==2: - v=geo.pos2pix((12.5, 0)) - l=np.linalg.norm(v) - go=UsrGO.FixTargetFrame(-oc, (l,l), tpl='12.5x12.5') - elif xstep==3: - v=geo.pos2pix((23, 0)) - l=np.linalg.norm(v) - go=UsrGO.FixTargetFrame(-oc, (l,l), tpl='23.0x23.0') - else: - _log.error('set xstep 0..2 for tests') - self.vb.addItem(go) - self._goTracked['objLst'].append(go) - - #grid = CstROI.Grid( x_step=xstep, y_step=ystep, x_offset=xoffset, y_offset=yoffset, gonio_xy=(gx, gy), grid_index=grid_index, parent=self,) - #self.vb.addItem(grid) - #grid.calculate_gonio_xy() - #grid.sigRemoveRequested.connect(lambda g=grid: self.remove_grid(g)) - - def _OLD_daq_grid_remove_all(self): - vb=self.vb - for go in self._goTracked['objLst']: - vb.removeItem(go) - self._goTracked['objLst']=[] - - def _OLD_grids_pause_stage_tracking(self): - for grid in self._grids: - grid.disable_stage_tracking() - - def _OLD_grids_start_stage_tracking(self): - for grid in self._grids: - grid.enable_stage_tracking() - - def _OLD_remove_grid(self, grid): - self.vb.removeItem(grid) - self._grids.remove(grid) - - - def _OLD_daq_grid_update(self, grid_index): - try: - grid = self._grids[grid_index] - except: - print("grid index not yet there") - return - points = grid.get_grid_targets() - num_points = len(points) - etime = float(settings.value("exposureTime")) - doc = f"grid_{grid_index} = [" - for n, pos in enumerate(points): - x, y = pos - doc += "[{:8.3f}, {:8.3f}],\n".format(x, y) - doc += "]" - self._grid_inspect_area.setPlainText(doc) - m = "Number of points: {}\nEstimated Time: {:.1f} minutes".format(num_points, num_points * etime / 60.) - self._label_grid_parameters.setText(m) - - def _OLD_daq_embl_collect_points(self): - coords = self._embl_module.coords - points = [[x, y] for x, y, bx, bz, o in coords] - points = np.array(points) - method = "trajectory" - xp = (1000 * points).astype(int) # microns then round int - params = (xp[:, 0].tolist(), xp[:, 1].tolist()) - self.daq_collect_points(points, visualizer_method=method, visualizer_params=params) - - def _OLD_daq_prelocated_collect_points(self): - points = [] - data = self.prelocationModule.get_collection_targets() - for n, cc in enumerate(data): - is_fiducial, gx, gy, cx, cy, ox, oy = cc - points.append([gx, gy]) - points = np.array(points) - method = "trajectory" - xp = (1000 * points).astype(int) # microns then round int - params = (xp[:, 0].tolist(), xp[:, 1].tolist()) - self.daq_collect_points(points, visualizer_method=method, visualizer_params=params) - - def _OLD_daq_grid_findxtals(self): - feature_size = self._sb_findxtals_feature_size.value() - image = sample_camera.get_image() - findObj(-image, objSize=feature_size, viz=1) - - def _OLD_check_jungfrau_save(self) -> bool: - if jungfrau_detector.is_running_detector(): - saveRaw = jungfrau_detector.is_saving_data() - - if not saveRaw: - box = QMessageBox() - box.setText("Jungfrau save data disabled!") - box.setInformativeText("Jungfrau save data is disabled!") - box.setIcon(QMessageBox.Warning) - box.setDetailedText("Choose to abort, enable and continue, or continue without saving raw data") - btContinue = box.addButton("Continue", QMessageBox.YesRole) - btAbort = box.addButton("OMG! Abort", QMessageBox.NoRole) - btEnable = box.addButton("Enable save and continue", QMessageBox.YesRole) - box.exec_() - ans = box.clickedButton() - if ans == btEnable: - jungfrau_detector.set_save_raw(True) - return True - elif ans == btAbort: - _log.info("not doing helical scan") - return False - return True - return True - - def _OLD_daq_collect_points(self, points, visualizer_method, visualizer_params): - app = QApplication.instance() - cfg = app._cfg - verbose=0xff - fn='/tmp/shapepath' - try: - dt=app._deltatau - except AttributeError: - app._deltatau=dt=deltatau.Deltatau() - try: - jf=app._jungfrau - except AttributeError: - app._jungfrau=jf=detector.Jungfrau() - - sp=dt._shapepath - sp.gen_grid_points(w=15, h=15, pitch=3, rnd=0, ofs=(0, +2000)) - #sp.gen_grid_points(w=5, h=10, pitch=1, rnd=0, ofs=(0, 0));sp.sort_points(False, 10);sp.points - sp.sort_points(False, 15); - sp.meta['pt2pt_time']=10 - sp.setup_gather() - sp.setup_sync(verbose=verbose&32, timeOfs=0.05) - sp.setup_coord_trf() # reset to shape path system - # sp.meta['pt2pt_time']=10 #put between setup_sync and setup_motion to have more motion points than FEL syncs - sp.setup_motion(fnPrg=fn+'.prg', mode=3, scale=1., dwell=10) - sp.homing() # homing if needed - sp.run() # start motion program - sp.wait_armed() # wait until motors are at first position - sp.trigger(0.5) # send a start trigger (if needed) ater given time - if not dt._comm is None: - while True: - p=int(sp.progress()) - if p<0: break - #print('progress %d/%d'%(p, num_pts)) - time.sleep(.1) - sp.gather_upload(fnRec=fn+'.npz') - #dp=deltatau.shapepath.DebugPlot(sp) - #dp.plot_gather(mode=11) - #plt.show(block=False) - #plt.show(block=True) - return - - - - task = self.active_task() - XDIR = -1 - - #folders.make_if_needed() - #if ( cfg.option(AppCfg.ACTIVATE_PULSE_PICKER) and not jungfrau_detector.is_running_detector()): - # if QMessageBox.No == QMessageBox.question(self, "X-rays but no Jungfrau", - # "X-rays will be used bu the Jungfrau will not run.\n\n\tContinue?",): - # _log.warning("user forgot to turn on the jungfrau") - # return - - #if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - # self.escape_goToDataCollection() - - points *= 1000 # delta tau uses micrometers - points[:, 0] *= XDIR # fast X axis is reversed - - - # sync_mode : default=2 - # 0 : no sync at all - # 1 : synchronize start - # 2 : synchronize start and adapt motion speed - # this function generates the code blocks: - # self.sync_wait and self.sync_run - # sync_wait can be put in the program to force a timing sync - # sync_run are the commands to run the whole program - # sync_flag if not using jungfrau =1 otherwise =0 - # D.O. shapepath.meta.update(sync_mode=2, sync_flag=1) - sp.meta.update(sync_mode=0, sync_flag=0) - - maxacq_points = 116508 - samp_time = 0.0002 # s - overhead_time = 0.1 - etime=10 - vscale=1.0 - #etime = settings.value("exposureTime", type=float) - #vscale = settings.value(DELTATAU_VELOCITY_SCALE, 1.0, type=float) - #sort_points = option(DELTATAU_SORT_POINTS) - - acq_per = int(np.ceil((etime * len(points) + overhead_time) / (maxacq_points * samp_time))) - _log.info(f"gather acquisotion period = {acq_per}") - _log.info(f"velocity scale {vscale}") - sp.setup_gather(acq_per=acq_per) - sp.setup_sync(verbose=True) - sp.setup_coord_trf() - - assert(points.dtcfgype==np.float64) - sp.points = points - - if TASK_GRID == task: - # width, height = visualizer_params - # _log.debug(f"grid: {width} x {height}") - # details_1 = [width] - # details_2 = [height] - # sp.sort_points(xy=False, grp_sz=height) - pass - elif task in (TASK_PRELOCATED, TASK_EMBL): - if sort_points: - shapepath.sort_points() - self.daq_method_prelocated_remove_markers() - details_1, details_2 = visualizer_params - - sp.setup_motion( - mode=3, # 1 = bad pvt 3 = pft (pvt via inverse fourier transform) - pt2pt_time=etime * 1000., - #fnPrg=folders.get_prefixed_file("_program.prg"), - scale=vscale, # velocity at target position scaling: 1=optimal speed, 0=zero speed - dwell=10, # milli-seconds wait - ) - sp.run() - - self.qprogress = QProgressDialog(self) - self.qprogress.setRange(0, 0) - self.qprogress.setLabelText("Acquiring GRID") - self.qprogress.setCancelButtonText("Abort Acquisition") - self.qprogress.canceled.connect(self.complete_daq) - self.qprogress.setWindowModality(Qt.WindowModal) - self.qprogress.setAutoClose(True) - self.qprogress.show() - - sequencer_steps = [lambda: self.grids_pause_stage_tracking()] - - if jungfrau_detector.is_running_detector(): - if not self.check_jungfrau_save(): - # user aborted run from save data dialog - return - - n_frames = ntrigger - uid = settings.value(EXPERIMENT_UID, type=int) - backend_extras = self.jungfrau.get_parameters() - backend_extras.update( - { - "swissmx_trajectory_method": visualizer_method, - "swissmx_trajectory_details_1": details_1, - "swissmx_trajectory_details_2": details_2, - } - ) - jungfrau_detector.set_number_of_frames(n_frames) - jungfrau_detector.set_data_owner_uid(uid) - sequencer_steps.extend( - [ - lambda: jungfrau_detector.configure( - n_frames=n_frames, - outfile=folders.prefix, - outdir=folders.raw_folder, - uid=uid, - backend_extras=backend_extras, - ), - lambda: jungfrau_detector.arm(), - ] - ) - - sequencer_steps.append(lambda: shapepath.wait_armed()) - if option(ACTIVATE_PULSE_PICKER): - sequencer_steps.append(lambda: pulsePicker.open()) - - # if settings.value("scanning/trigger_microscope_camera", type=bool): - # sample_camera.switch_to_trigger(True) - - sequencer_steps.append(lambda: shapepath.trigger(wait=0.5)) - - def _OLD_shapepath_progress(): - while True: - p = shapepath.progress() - if p < 0: - break - time.sleep(0.1) - self.qprogress.setLabelText(f"Acquiring GRID {p:.0f} / {ntrigger}") - _log.warning(f"motion complete!") - # sample_camera.stop_camera() - # sample_camera.switch_to_trigger(False) - # sample_camera.save_buffer_series(folders.prefix) - - sequencer_steps.append(shapepath_progress) - - if option(ACTIVATE_PULSE_PICKER): - sequencer_steps.append(lambda: pulsePicker.close()) - - sequencer_steps.append(lambda: jungfrau_detector.wait_finished()) - - sequencer_steps.append(lambda: self.grids_start_stage_tracking()) - - self.sequencer = Sequencer(steps=sequencer_steps) - self._thread = QThread() - self._thread.setObjectName("acquisition_thread") - self.sequencer.moveToThread(self._thread) - self.sequencer.finished.connect(self.daq_collect_points_wrapup) - self._thread.started.connect(self.sequencer.run_sequence) - self._thread.start() - - def _OLD_run_steps(self, steps, title, at_end=None, cancelable=False): - dlg = QProgressDialog(self) - dlg.setWindowTitle(title) - dlg.setWindowModality(Qt.WindowModal) - dlg.setMinimumDuration(0) - if not cancelable: - dlg.setCancelButton(None) - dlg.setRange(0, 0) - dlg.setLabelText(f"{title}
") - dlg.setAutoClose(True) - dlg.show() - dlg.setValue(random.randint(1, 20)) - class Runner(QObject): - finito = pyqtSignal() - timeoutExpired = pyqtSignal() - errorHappened = pyqtSignal(str) - result = pyqtSignal(str) - - def __init__(self, step_to_run): - super().__init__() - self.step = step_to_run - self.exception = None - self.done = False - - def run(self): - try: - self.step() - except Exception as e: - _log.debug(" +> step exception") - self.exception = str(e) - self.errorHappened.emit(str(e)) - self.finito.emit() - - - for n, step in enumerate(steps): - _log.info(f"running step {step.title}") - dlg.setLabelText(f"{title}
{step.title}") - dlg.setValue(n) - thread = QThread() - runner = Runner(step) - runner.moveToThread(thread) - thread.started.connect(runner.run) - runner.finito.connect(thread.quit) - thread.start() - while thread.isRunning(): - dlg.setValue(random.randint(1, 20)) - time.sleep(0.01) - if dlg.wasCanceled(): - # FIXME ensure we abort the running thread - break - - if dlg.wasCanceled(): - break - if runner.exception is not None: - QMessageBox.critical(self, step.title, str(runner.exception)) - break - - if dlg.wasCanceled(): - _log.error(f"sequence {title} was cancelled by user") - raise AcquisitionAbortedException(f"sequence {title} was cancelled by user") - - if at_end is not None: - at_end() - dlg.reset() - - def _OLD_daq_collect_points_wrapup(self): - self.qprogress.reset() - if self._thread.isRunning(): - self._thread.quit() - shapepath.gather_upload(os.path.join(folders.res_folder, folders.prefix + ".npz")) - - if option(DELTATAU_SHOW_PLOTS): - dp = DebugPlot(shapepath) - dp.plot_gather(mode=1) - pyplot.show() - - if TASK_PRELOCATED == self.active_task(): - self.daq_method_prelocated_update_markers() - - if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - self.cb_esc_sample_alignment() - - sequence = {"delta tau program": shapepath.prg, "points": shapepath.points.tolist(), "timestamp": tdstamp(),} - - sfname = folders.get_prefixed_file("_ScanInfo.json") - try: - with open(sfname, "w") as sf: - _log.info("writing scan info into: {}".format(sfname)) - sf.write(json.dumps(sequence)) - except: - _log.warning(f"failed to write scan info to {sfname}") - - self.re_connect_collect_button() - jungfrau_detector.abort() - self.increaseRunNumberRequest.emit() - - def _OLD_daq_collect_update_inspect(self, msg): - te = self._inspect - m = te.toPlainText() - te.setPlainText(m + msg + "\n") - te.verticalScrollBar().setValue(te.verticalScrollBar().maximum()) - - def _OLD_daq_helical_collect(self): - """[ - [{ - 0: (0.0, 1.238401694734829, 3.527, 0.936, 0.001), - 120: (0.0, 1.3890393596274455, -1.957242824091597, -0.5639999999999998, 120.001), - 240: (0.0, 1.3866130349657206, -1.1642619618562273, 3.105, 240.001) - }, - { - 0: (0.0, 1.238401694734829, 3.527, 0.936, 0.001), - 120: (0.0, 1.3890393596274455, -1.957242824091597, -0.5639999999999998, 120.001), - 240: (0.0, 1.3866130349657206, -1.1642619618562273, 3.105, 240.001) - }] - ] - """ - _log.info("executing collection") - htab = self._helical_scan_table - num_h = htab.scanHorizontalCount() - num_v = htab.scanVerticalCount() - - if ( settings.value(ACTIVATE_PULSE_PICKER) and not jungfrau_detector.is_running_detector()): - if QMessageBox.No == QMessageBox.question(self, "X-rays but no Jungfrau", - "X-rays will be used bu the Jungfrau will not run.\n\n\tContinue?",): - _log.warning("user forgot to turn on the jungfrau") - return - - if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - self.cb_esc_data_collection() - - folders.make_if_needed() - - data = htab.get_data() - _log.debug(data) - start, end = data[0] - FX, FY, BX, BZ, O = range(5) - x = ( - (-1000 * start[0][BX], -1000 * start[120][BX], -1000 * start[240][BX]), - (-1000 * end[0][BX], -1000 * end[120][BX], -1000 * end[240][BX]), - ) - y = (1000 * start[0][FY], 1000 * end[0][FY]) - z = ( - (-1000 * start[0][BZ], -1000 * start[120][BZ], -1000 * start[240][BZ]), - (-1000 * end[0][BZ], -1000 * end[120][BZ], -1000 * end[240][BZ]), - ) - - if jungfrau_detector.is_running_detector(): - if not self.check_jungfrau_save(): - return - saveRaw = jungfrau_detector.is_saving_data() - - _log.debug(f"x = {x}") - _log.debug(f"y = {y}") - _log.debug(f"z = {z}") - - oscillationAngle = settings.value("oscillationAngle", type=float) - exposureTime = 1000 * settings.value("exposureTime", type=float) - blastRadius = settings.value("blastRadius", type=float) - totalRange = num_v * num_h * oscillationAngle - - # sync_mode : default=2 - # 0 : no sync at all - # 1 : synchronize start - # 2 : synchronize start and adapt motion speed - # this function generates the code blocks: - # self.sync_wait and self.sync_run - # sync_wait can be put in the program to force a timing sync - # sync_run are the commands to run the whole program - # sync_flag if not using jungfrau =1 otherwise =0 - # D.O. helical.meta.update(sync_mode=2, sync_flag=1) - helical.meta.update(sync_mode=0, sync_flag=0) - helical.calcParam(x=x, y=y, z=z) - helical.setup_gather() - helical.setup_sync() - helical.setup_coord_trf() - mode = 1 - hRng = (-blastRadius * num_h, blastRadius * num_h) - w_start = 1000 * htab.startAngle() - wRng = (w_start, w_start + (totalRange * 1000)) - _log.info( - f"helical params mode={mode}, cnthor={num_h}, cntvert={num_v}, hrng={hRng}, wrng={wRng}" - ) - helical.setup_motion( - mode=mode, - cntHor=num_h, - cntVert=num_v, - hRng=hRng, - wRng=wRng, - pt2pt_time=exposureTime, - ) # hRng in micrometers - helical.run() - try: - with open(folders.get_prefixed_file("_helical_debug.cmd"), "w") as fd: - fd.write("calcParam(x={}, y={}, z={})".format(x, y, z)) - except: - pass - - self.qprogress = QProgressDialog(self) - self.qprogress.setRange(0, 0) - self.qprogress.setLabelText("Acquiring HELICAL") - self.qprogress.setCancelButtonText("Abort Acquisition") - self.qprogress.canceled.connect(self.complete_daq) - self.qprogress.setWindowModality(Qt.WindowModal) - self.qprogress.setAutoClose(True) - self.qprogress.show() - - sequencer_steps = [lambda: self.grids_pause_stage_tracking()] - - n_frames = num_h * num_v - if jungfrau_detector.is_running_detector(): - uid = settings.value(EXPERIMENT_UID, type=int) - backend_extras = self.jungfrau.get_parameters() - backend_extras.update( - { - "swissmx_trajectory_method": "grid", - "swissmx_trajectory_details_1": [-num_h], - "swissmx_trajectory_details_2": [num_v], - } - ) - - jungfrau_detector.set_number_of_frames(n_frames) - jungfrau_detector.set_data_owner_uid(uid) - sequencer_steps.extend( - [ - lambda: jungfrau_detector.configure( - n_frames=n_frames, - outfile=folders.prefix, - outdir=folders.raw_folder, - uid=uid, - backend_extras=backend_extras, - ), - lambda: jungfrau_detector.arm(), - ] - ) - - sequencer_steps.append(lambda: helical.wait_armed()) - if settings.value(ACTIVATE_PULSE_PICKER): - sequencer_steps.extend([lambda: pulsePicker.open(), lambda: pend_event(0.1)]) - - sequencer_steps.append(lambda: helical.trigger()) - - def _OLD_motion_progress(): - while True: - p = helical.progress() - if p < 0: - break - time.sleep(0.1) - self.qprogress.setLabelText(f"Acquiring HELICAL {p:.0f} / {n_frames}") - _log.warning(f"helical motion complete!") - - sequencer_steps.append(motion_progress) - - if settings.value(ACTIVATE_PULSE_PICKER): - sequencer_steps.append(lambda: pulsePicker.close()) - - sequencer_steps.append(lambda: self.grids_start_stage_tracking()) - - self.sequencer = Sequencer(steps=sequencer_steps) - self._thread = QThread() - self._thread.setObjectName("acquisition_thread") - self.sequencer.moveToThread(self._thread) - self.sequencer.finished.connect(self.daq_helical_collect_wrapup) - self._thread.started.connect(self.sequencer.run_sequence) - self._thread.start() - - def _OLD_daq_helical_collect_wrapup(self): - try: - self.qprogress.reset() - except: - pass - if self._thread.isRunning(): - self._thread.quit() - helical.gather_upload(os.path.join(folders.res_folder, folders.prefix + ".npz")) - - self.re_connect_collect_button() - jungfrau_detector.abort() - if option(ACTIVATE_PULSE_PICKER) or not option(SKIP_ESCAPE_TRANSITIONS_IF_SAFE): - self.cb_esc_sample_alignment() - self.increaseRunNumberRequest.emit() - - if option(DELTATAU_SHOW_PLOTS): - hsgui = HelicalScanGui(helical) - hsgui.interactive_anim() - - def _OLD_complete_daq(self): - _log.info("daq completed: cleaning up") - try: - self.qprogress.reset() - except: - pass - try: - if self._thread.isRunning(): - self._thread.quit() - except: - pass - finally: - self.abort_measurement() - self.re_connect_collect_button() - - def _OLD_re_connect_collect_button(self, callback=None, **kwargs): - _log.debug("re_connect_collect_button() {} => {}".format(callback, kwargs)) - return - # button = self._button_collect - # if callback is None: - # callback = self.execute_collection - # button.setAccessibleName("collect_button") - # kwargs["label"] = "Collect" - # - # try: - # button.disconnect() - # finally: - # button.clicked.connect(callback) - # - # if "accessibleName" in kwargs: - # button.setAccessibleName(kwargs["accessibleName"]) - # - # if "label" in kwargs: - # button.setText(kwargs["label"]) - # self.load_stylesheet() - - def _OLD_collect_abort_grid(self): - self._is_aborted = True - try: - self._eigerwaitthread._is_aborted = True - except: - pass - _log.warning("aborting grid scan") - self.abort_measurement() - delta_tau.abort() - jungfrau_detector.disarm() - self.re_connect_collect_button() - - def _OLD_create_escape_toolbar(self): - cont = self._wd_right - w = QGroupBox("Escape") - layout = QHBoxLayout() - w.setLayout(layout) - but = QPushButton("Exchange\nSample") - but.setAccessibleName("escape_button_se") - but.setObjectName("action_SampleExchange") - but.clicked.connect(self.cb_esc_sample_exchange) - layout.addWidget(but) - but = QPushButton("Alignment") - but.setAccessibleName("escape_button_sa") - but.clicked.connect(self.cb_esc_sample_alignment) - layout.addWidget(but) - but = QPushButton("Collection") - but.setAccessibleName("escape_button_dc") - but.clicked.connect(self.cb_esc_data_collection) - layout.addWidget(but) - cont.layout().addWidget(w) - - def _OLD_daq_method_prelocated_remove_markers(self): - try: - for m in self._marker_rois: - m.disconnect_signals() - self.vb.removeItem(m) - except Exception as e: - _log.warning("maybe failed removing markers: {}".format(e)) - self._marker_rois = [] - - def _OLD_pause_all_markers(self): - for m in self._marker_rois: - m.disconnect_signals() - - def _OLD_resume_all_markers(self): - for m in self._marker_rois: - m.reconnect_signals() - - def _OLD_daq_method_prelocated_update_markers(self): - self.daq_method_prelocated_remove_markers() - data = self.prelocationModule.get_data() - add_xtals = self.prelocationModule._xtals_transformed - draw_xtals = self.prelocationModule.set_draw_crystal_marks - vb = self.vb - self._marker_rois = [] - ppm = self.getPpm() - for n, cc in enumerate(data): - is_fiducial, gx, gy, cx, cy, ox, oy = cc - if not is_fiducial: - if not (add_xtals and draw_xtals): - continue - _log.debug(f"adding {'fiducial' if is_fiducial else 'xtal'} mark #{n}: {is_fiducial} {gx:.3f}, {gy:.3f}, {cx:.1f}, {cy:.1f}") - m = CstROI.CrystalCircle( - gonio_xy=(gx, gy), - parent=self, - model_row_index=n, - is_fiducial=is_fiducial, - ppm=ppm, - ) - # m.sigRegionChangeFinished.connect(lambda roi=m: self.daq_method_prelocated_update_model(roi)) - self._marker_rois.append(m) - vb.addItem(m) - for c in self._marker_rois: - c.reconnect_signals() - c.follow_stage() - - def _OLD_daq_method_prelocated_set_fiducial(self, camx, camy, gx, gy): - _log.debug(f"camx, camy: {camx}, {camy}, fx, fy: {gx, gy}") - self.prelocationModule.set_fiducial_coords(camx, camy, gx, gy) - - def _OLD_daq_method_prelocated_append_data(self, x, y, gx, gy): - _log.debug("appending to model: {} {}".format((x, y), (gx, gy))) - self.prelocationModule.append_data((x, y, gx, gy)) - self.daq_method_prelocated_update_markers() - - def _OLD_daq_method_prelocated_update_model(self, roi): - row = roi.get_model_row() - pos = roi.pos() - self.prelocationModule.set_data_camera(row, pos) - _log.debug("updating row {} => {}".format(row, pos)) - - def _OLD_daq_method_prelocated_add_reference(self): - self._references.append(pg.CircleROI()) - - def _OLD_move_fast_stage(self, x, y): - _log.info(f"received request to move gonio to x, y = {x:.3f}, {y:.3f} mm") - fx_motor, fy_motor, bx_motor, bz_motor, omega_motor = self.get_gonio_tweakers() - fx_motor.move_abs(x) - fy_motor.move_abs(y) - - def _OLD_toggle_maximized(self): - if self.isMaximized(): - self.showNormal() - else: - self.showMaximized() - - def _OLD_show_window_configuration(self): - _log.debug("maximized? {}".format(self.isMaximized())) - - def _OLD_update_user_and_storage(self): - global folders - pgroup = settings.value(EXPERIMENT_PGROUP, "not_set_yet") - diag = GenericDialog( title="P-group for experiment", message="Enter the p-group to be used", - inputs={EXPERIMENT_PGROUP: ("P-group", pgroup, QLineEdit(pgroup))}, use_buttons=False,) - diag.setModal(True) - - run_user = getpass.getuser() - - pgrp_re = re.compile(r"^p(?P\d{5})$") - - if not self.is_recently_active(): - diag.exec() - results = diag.results - for k, v in results.items(): - m = pgrp_re.match(v) - if m: - settings.setValue(k, v) - settings.setValue(EXPERIMENT_UID, int(m["uid"])) - else: - QMessageBox.critical(self, "wrong P-group format", "P-groups are in the format:\n\n\t\tp?????\n\n\twhere ? = digit",) - self.update_user_and_storage() - return - settings.sync() - folders.set_pgroup(settings.value(EXPERIMENT_PGROUP)) - try: - folders.check_permissons() - except: - folder = folders.pgroup_folder - pgroup = settings.value(EXPERIMENT_PGROUP) - box = QMessageBox() - box.setText("No Write Permission!") - box.setInformativeText("User {} has no write access to p-group {} folder:\n ➜ {}\n".format(run_user, pgroup, folder)) - box.setIcon(QMessageBox.Warning) - box.setDetailedText("The folder /sf/bernina/data/{pgroup}/res/ has to writable by the user {user}, currently running the SwissMX app.".format(pgroup=pgroup, user=run_user)) - btIgnore = box.addButton("Ignore", QMessageBox.NoRole) - btRetry = box.addButton("Le'me try again", QMessageBox.YesRole) - box.exec_() - ans = box.clickedButton() - if ans == btRetry: - self.update_user_and_storage() - elif ans == btIgnore: - _log.warning("no write access to pgroup but user didn't care") - - self._label_pgroup.setText(settings.value(EXPERIMENT_PGROUP)) - - def _OLD_is_recently_active(self): - last_active = settings.value("last_active", 0, type=float) - minutes_since_last = int((time.time() - last_active) / 60.0) - return minutes_since_last < 60 - - def _OLD_openPreferencesDialog(self): - PreferencesDialog(self).exec_() - - def _OLD_set_app_icon(self): - scriptDir = os.path.dirname(os.path.realpath(__file__)) - self.setWindowIcon(QtGui.QIcon(os.path.join(scriptDir + os.path.sep + "logo.png"))) - - def _OLD_set_widget_background_color(self, color): - """change a widget's color - :param color: - :return: - """ - try: - color = QtGui.QColor.colorNames().index(color) - except: - return - p = self.palette() - p.setColor(self.backgroundRole(), color) - self.setPalette(p) diff --git a/psi_device.py b/psi_device.py index 665d481..f15be63 100644 --- a/psi_device.py +++ b/psi_device.py @@ -8,17 +8,15 @@ if __name__ == "__main__": logging.getLogger('matplotlib').setLevel(logging.INFO) if socket.gethostname()=='ganymede': - sys.path.insert(0, os.path.expanduser('~/Documents/prj/SwissFEL/PBTools')) + base=os.path.abspath(os.path.dirname(__file__)) + sys.path.insert(0, os.path.abspath(os.path.join(base,'../PBSwissMX/python'))) + sys.path.insert(0, os.path.abspath(os.path.join(base,'../../PBTools'))) else: - sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBTools') - sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBSwissMX/python') - #_log.info(sys.path) + base=os.path.abspath(os.path.dirname(__file__)) + sys.path.insert(0, os.path.join(base,'PBTools')) + sys.path.insert(0, os.path.join(base,'PBSwissMX/python')) elif socket.gethostname()!='ganymede': - #TODO: cleanup slic installation location - sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/mx/slic')) - #sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/slic/slic-package')) - - + sys.path.insert(0, os.path.expanduser('/sf/cristallina/applications/slic/slic-package')) from PyQt5.QtWidgets import (QApplication,) from app_config import AppCfg #settings, option, toggle_option @@ -105,12 +103,6 @@ class Deltatau: class Jungfrau: def __init__(self,sim=False): - #python /sf/jungfrau/applications/daq_client/daq_client.py -h - #python /sf/jungfrau/applications/daq_client/daq_client.py -p p19739 -t no_beam_test - # -c/sf/cristallina/config/channel_lists/channel_list_bs-e/sf/cristallina/config/channel_lists/channel_list_ca - # -f/sf/cristallina/config/jungfrau/jf_1d5M.json - # --start_pulseid 15382163895 --stop_pulseid 15382163905 - #rsync -vai gac-cristall@saresc-cons-03:/sf/jungfrau/applications/daq_client/daq_client.py . # setup slic parameters if sim: self._sim=True diff --git a/pyqtUsrObj.py b/pyqtUsrObj.py index 9fe187f..3c17aa0 100644 --- a/pyqtUsrObj.py +++ b/pyqtUsrObj.py @@ -18,7 +18,7 @@ _log=logging.getLogger(__name__) import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np -from PyQt5.QtGui import QPolygon,QPolygonF +from PyQt5.QtGui import QPolygonF from PyQt5.QtCore import Qt,QPointF,QLineF from PyQt5.QtWidgets import QMenu @@ -94,22 +94,12 @@ class Marker(UsrROI): #widget.signal.connect(slot_function) #self.sigRegionChangeFinished.connect(self.OnRgnChanged) - #def OnRgnChanged(self, event): - # print(event) - # obj_info(self) - def paint(self, p, *args): #pg.ROI.paint(self, p, *args) r=QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized() p.setRenderHint(QtGui.QPainter.Antialiasing) p.setPen(self.currentPen) p.translate(r.left(), r.top()) - #p.scale(r.width(), r.height()) # -> values x,y 0 to 1 - #f=p.font(); - #f.setPixelSize(50) - #p.setFont(f) - # p.drawText(0, 0, '{:.0f}x{:.0f}'.format(*tuple(self.size()))) - #p.drawText(0, 0, 'Thierry') p.scale(.01*r.width(), .01*r.height()) # -> values x,y 0 to 100 m=self._mode @@ -129,7 +119,6 @@ class Marker(UsrROI): ctr=tuple((self.pos()+self.size()/2)*1000) sz=tuple(self.size()*1000) p.drawText(ofx+5, ofy+45, '{:.1f}x{:.1f} um'.format(*sz)) - #p.drawText(5, -35, '{:.1f}'.format(ctr[0])) p.drawText(ofx+5, ofy+55,42,30,Qt.AlignRight, '{:.1f}'.format(ctr[0])) p.drawText(ofx+55, ofy+65, '{:.1f} um'.format(ctr[1])) @@ -145,8 +134,6 @@ class Marker(UsrROI): f=p.font(); f.setPixelSize(10) p.setFont(f) - #p.drawText(ofx+0, ofy+0, 'FFF') - #p.drawText(ofx+100, ofy+100, 'GGG') px=tuple(self.pos()+self.size()/2) p.drawText(ofx+18, ofy+10, 'optical center') p.drawText(ofx+5, ofy+80,42,30,Qt.AlignRight, '{:.1f}'.format(px[0])) @@ -184,17 +171,11 @@ class Fiducial(UsrROI): p.setPen(pg.mkPen(width=1, color=[255, 0, 0])) p.drawLine(pg.Point(50,10), pg.Point(50, 90)) p.drawLine(pg.Point(10,50), pg.Point(90, 50)) - #tr=p.transform() - #tr.setMatrix(tr.m11(), tr.m12(), tr.m13(), tr.m21(), -tr.m22(), tr.m23(), tr.m31(), tr.m32(), tr.m33()) - #p.setTransform(tr) f=p.font() f.setPixelSize(10) p.setFont(f) - #p.drawText(24, 20, 'beam marker') ctr=tuple(self.pos()+self.size()/2) sz=tuple(self.size()) - #print((*ctr,self._z)) - #p.drawText(5, 25, 'x{:.4g}\ny{:.4g}\nz{:.4g}'.format(*ctr,self._z)) p.drawText(52, 10,40,40,Qt.TextWordWrap, 'x{:.5g}\ny{:.5g}\nz{:.5g}'.format(*ctr,self._z)) def ctr(self): @@ -253,11 +234,6 @@ class Grid(UsrROI): x=i*px p.drawEllipse(QPointF(x,y), rx, ry) - #p.translate(r.left(), r.top()) - #p.scale(r.width(), r.height()) - #p.drawEllipse(0, 0, 1, 1) - #p.drawRect(0, 0, 1, 1) - def __repr__(self): s=f'{self.__class__.__name__}:(pos:{itr2str(self.pos())}, size:{itr2str(self.size())}, cnt:{self._cnt}, fidSize:{self._fidSz}, param:{self._param})' return s @@ -276,7 +252,6 @@ class Grid(UsrROI): def get_scan_param(self): 'returns scan parameters for scanning with deltatau. the format is as used for shapepath' scan=1 # snake motion Y fast, X slow (default) - #pos=np.array(self.pos()) cnt=np.array(self._cnt,np.int32) sz=np.array(self.size()) pitch=sz/cnt @@ -292,7 +267,6 @@ class Grid(UsrROI): for i in range(1, cnt[0], 2): yy[i]=yy[i][::-1] pts=np.array([xx.reshape(-1), yy.reshape(-1)], dtype=np.float64).transpose()*pitch - #pts+=pos param={'points':pts} param.update(self._param) assert(param.get('code_gen',0)==0) # this provides fully x,y motor coordinates @@ -348,8 +322,6 @@ class Path(UsrROI): r=self._rect p.setRenderHint(QtGui.QPainter.Antialiasing) p.setPen(self.currentPen) - #p.drawEllipse(0, 0, int(sz[0]), int(sz[1])) - #p.drawRect(0, 0, int(sz[0]), int(sz[1])) p.drawRect(QtCore.QRectF(0, 0, sz[0], sz[1]).normalized()) #obj_info(p) p.scale(sz[0]/r.width(), sz[1]/r.height()) @@ -470,19 +442,12 @@ class FixTargetFrame(UsrROI): self.addScaleHandle([1, 1], [0, 0]) self.addScaleHandle([0, 0], [1, 1]) self.addScaleRotateHandle([1, 0], [0, 0]) - #self.sigHoverEvent.connect(self.hover) -# def hover(self): -# _log.debug(f'hover {self}') def paint(self, p, *args): - #pg.ROI.paint(self, p, *args) sz=self.state['size'] - #nx, ny=self._cnt - #px, py=sz[0]/(nx-1), sz[1]/(ny-1) r=QtCore.QRectF(0, 0, sz[0], sz[1]).normalized() p.setRenderHint(QtGui.QPainter.Antialiasing) p.setPen(self.currentPen) - #p.drawRect(0, 0, int(sz[0]), int(sz[1])) p.drawRect(r) dscr=self._dscr @@ -496,8 +461,6 @@ class FixTargetFrame(UsrROI): ox,oy=g['pos'] px,py=g['pitch'] nx,ny=g['count'] - #x0=ox; x1=ox+(ny-1)*py - #y0=oy; y1=oy+(nx-1)*px x0=ox-.5*px; x1=ox+(nx-.5)*px y0=oy-.5*py; y1=oy+(ny-.5)*py for i in range(nx): @@ -558,10 +521,7 @@ class FixTargetFrame(UsrROI): scan=1 # snake motion Y fast, X slow (default) grid=self._dscr['grid'] self._dscr['size'] - #pos=np.array(self.pos()) cnt =np.array(grid['count'],np.int32) - #pos =np.array(grid['pos'],np.float64) - #pitch=np.array(grid['pitch'],np.float64) xx, yy=np.meshgrid(range(cnt[0]), range(cnt[1])) if scan==0: # snake motion X fast, Y slow for i in range(1,cnt[1],2): @@ -592,11 +552,6 @@ class FixTargetFrame(UsrROI): param={'grid':grid, 'points':pts, 'trf':trf} param.update(self._param) - # trf*'gridpos' -> motor pos in mm - # {'pos': [2080, 2080], 'pitch': [120, 120], 'count': [162, 162]} - #np.array((0,0,1))*trf grid 0,0 (top left) - #np.array((161,0,1))*trf # grid 161,0 (top right) - #np.array((161,161,1))*trf # grid 161,161 (bottom right) return param @@ -645,9 +600,6 @@ if __name__=='__main__': p.setRenderHint(QtGui.QPainter.Antialiasing) p.setPen(self.currentPen) - # p.translate(r.left(), r.top()) - # p.scale(r.width(), r.height()) - # p.drawRect(0, 0, 1, 1) p.drawRect(r) tr=p.worldTransform() obj_info(tr) @@ -702,15 +654,9 @@ if __name__=='__main__': def mouse_click_event(event): - #event.pos(): return Point(self.currentItem.mapFromScene(self._scenePos)) pos=event.pos() scn=event.scenePos() # there is a small black border, that makes the difference print(f'mouse-> scene pos:{pt2str(scn)} currentItem pos:{pt2str(pos)}') - #img=viImg.mapFromScene(scn) - #roi=viUsrRoi.mapFromScene(scn) - #print(f'mouse-> img:{pt2str(img)} roi:{pt2str(roi)}') - #childTree(vb) - #obj_info(viImg) m=int(event.modifiers()) o=event.currentItem if m&Qt.ShiftModifier: @@ -721,9 +667,6 @@ if __name__=='__main__': elif m&Qt.ControlModifier: tr=o.transform() obj_info(tr) - #tr.setMatrix(tr.m11(),tr.m12(),tr.m13()+100,tr.m21(),tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33()) - #tr.setMatrix(tr.m11(),tr.m12(),tr.m13(),tr.m21(),tr.m22(),tr.m23(),tr.m31(),tr.m32()+20,tr.m33()) - #tr.setMatrix(tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33()) tr.setMatrix(-tr.m11(),tr.m12(),tr.m13(),tr.m21(),-tr.m22(),tr.m23(),tr.m31(),tr.m32(),tr.m33()) obj_info(tr) o.setTransform(tr) @@ -774,24 +717,16 @@ if __name__=='__main__': viImg=pg.ImageItem(arr, border='y') vb.addItem(viImg) - # Custom ROI for selecting an image region - #viRoi=pg.ROI([20, -50], [60, 40]) - #viRoi=TxtROI([20, -50], [60, 40]) - #viRoi.addScaleHandle([1, 1], [0, 0]) - #viRoi.addScaleHandle([.7, .5], [0, 0]) - #vb.addItem(viRoi) viUsrRoi=Marker([50, 120], [30, 20],mode=0) vb.addItem(viUsrRoi) - #obj=Marker([250, 220], [30, 20],mode=1) - #vb.addItem(obj) + vi=Grid( (120,-100), (200,150), (30,20),2) tr=QtGui.QTransform() # prepare ImageItem transformation: tr.setMatrix(1, -.1, 0, .2, 1, 0, 10, 10, 1) vi.setTransform(tr) # assign transform - #vi=Grid( (50,10), (200,150), (6,4)) vb.addItem(vi) #vi= visual item grp=pg.ItemGroup() @@ -811,11 +746,6 @@ if __name__=='__main__': fiducial=np.array(((18, 7), (25, 16), (70, 20))) path=gen_swissmx_points(ofs=(10, 5), width=200) vi=Path((120,100),path,fiducial,fidScl) - #tr=QtGui.QTransform() # prepare ImageItem transformation: - #tr.setMatrix(1, 0, 0, - # 0, 1, 0, - # 10, 10, 1) - #vi.setTransform(tr) # assign transform vb.addItem(vi) vi=FixTargetFrame((100,300),(100,100),tpl='test') @@ -833,9 +763,6 @@ if __name__=='__main__': viRoi=pg.ROI([-200, -200], [100, 80],movable=True, rotatable=True, resizable=True) viRoi.addFreeHandle(pos=[.7, .5], axes=None, item=None, name=None, index=None) # rechteck , frei beweglich ??? verschwinden anch bewegung - #viRoi.addRotateFreeHandle([.7, .5], [0, 0], axes=None, item=None, name=None, index=None) # kreis ??? verschwinden anch erstem gebrauch - #viRoi.addRotateHandle([.7, .5], [0, 0], item=None, name=None, index=None) # kreis, nur rot - #viRoi.addScaleHandle([.7, .5], [0, 0], axes=None, item=None, name=None, lockAspect=False, index=None) # raute scale x,y #viRoi.addScaleRotateHandle([0, .5], [1, .5], item=None, name=None, index=None) # kreis #viRoi.addTranslateHandle([.7, .5], axes=None, item=None, name=None, index=None) #quadrat vb.addItem(viRoi) @@ -846,9 +773,6 @@ if __name__=='__main__': childTree(vb) w.scene().sigMouseClicked.connect(mouse_click_event) - #viImg.sigImageChanged - #print(vb.pos()) - #vb.setPos(50,50) if (sys.flags.interactive!=1) or not hasattr(QtCore, 'PYQT_VERSION'): QtGui.QApplication.instance().exec_() diff --git a/qutilities.py b/qutilities.py index 55fd37b..00ae2e9 100644 --- a/qutilities.py +++ b/qutilities.py @@ -1,44 +1,11 @@ from PyQt5 import QtWidgets, QtGui -from PyQt5.QtWidgets import QWidget, QSizePolicy, QVBoxLayout, QDoubleSpinBox, QMessageBox - -from app_config import AppCfg #option, toggle_option - - -def toggle_warn(key): - toggle_option(key) - m = f"Option {key} => {option(key)}" - QMessageBox.warning(None, m, m) +from PyQt5.QtWidgets import QWidget, QSizePolicy, QVBoxLayout, QMessageBox def horiz_spacer(): spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) return spacer - -def toggle_visibility(widget, state): - if state: - widget.show() - else: - widget.hide() - - -def get_sep_line(): - line = QtWidgets.QFrame() - line.setFixedHeight(2) - line.setFrameShadow(QtWidgets.QFrame.Sunken) - line.setFrameShape(QtWidgets.QFrame.HLine) - return line - - -def check_font_by_id(id): - for family in QtGui.QFontDatabase.applicationFontFamilies(id): - print(family) - - -def toggle_groupbox(gbox, state): - widget = gbox.layout().itemAt(0).widget() - widget.setVisible(state) - def add_item_to_toolbox(toolbox, label, widget_list=[]): block = QWidget() block.setAccessibleName(label) diff --git a/swissmx.py b/swissmx.py index 558be2d..7eabb46 100755 --- a/swissmx.py +++ b/swissmx.py @@ -22,7 +22,7 @@ bitmask for simulation: 0x100: Deltatau motion code """ -import logging +import logging,time,os,sys,socket class col: d='\033[0m' # default r='\033[31m' # red @@ -74,33 +74,22 @@ class logHandler(logging.StreamHandler): except Exception: self.handleError(record) - -# logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s', handlers=[logHandler()]) -#logging.getLogger('PyQt5.uic').setLevel(logging.INFO) -#logging.getLogger('requests').setLevel(logging.INFO) -#logging.getLogger('urllib3').setLevel(logging.INFO) -#logging.getLogger('paramiko').setLevel(logging.INFO) -#logging.getLogger('matplotlib').setLevel(logging.INFO) -#logging.getLogger('PIL').setLevel(logging.INFO) -#logging.getLogger('illumination').setLevel(logging.INFO) -#logging.getLogger('zoom').setLevel(logging.INFO) -#logging.getLogger('pbtools.misc.pp_comm').setLevel(logging.INFO) _log = logging.getLogger("swissmx") if __name__=="__main__": - import os,sys,socket if socket.gethostname()=='ganymede': base=os.path.abspath(os.path.dirname(__file__)) sys.path.insert(0, os.path.abspath(os.path.join(base,'../PBSwissMX/python'))) sys.path.insert(0, os.path.abspath(os.path.join(base,'../../PBTools'))) else: - sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBTools') - sys.path.insert(0, '/sf/cristallina/applications/SwissMX/PBSwissMX/python') + base=os.path.abspath(os.path.dirname(__file__)) + sys.path.insert(0, os.path.join(base,'PBTools')) + sys.path.insert(0, os.path.join(base,'PBSwissMX/python')) + -import time class timestamp(): def __init__(self): self.t=time.time() @@ -110,9 +99,9 @@ class timestamp(): self.t=t ts=timestamp() ts.log('Import part 1/8:') -import sys, os, time +import sys, os import json, re -import random, signal, subprocess +import signal, subprocess import matplotlib as mpl import matplotlib.pyplot as plt @@ -132,22 +121,18 @@ TASK_PRELOCATED = "prelocated" TASK_HELICAL = "helical" TASK_EMBL = "embl" ts.log('Import part 2/8:') - import ModuleFixTarget -import PrelocatedCoordinatesModel # ZAC: orig. code -from EmblModule import EmblWidget #ZAC: orig. code -from HelicalTable import HelicalTableWidget #ZAC: orig. code ts.log('Import part 3/8:') import qtawesome import qutilities from PyQt5 import QtCore, QtGui -from PyQt5.QtCore import Qt, pyqtSlot, QSize, QRegExp, pyqtSignal, QObject, QThread, QRectF,QT_VERSION_STR -from PyQt5.QtGui import QKeySequence, QPixmap, QRegExpValidator, QFont +from PyQt5.QtCore import Qt, pyqtSlot, QSize, pyqtSignal, QObject, QRectF,QT_VERSION_STR +from PyQt5.QtGui import QKeySequence, QPixmap from PyQt5.QtWidgets import ( - QAction, QApplication, QDoubleSpinBox, QFileDialog, QFormLayout, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, - QMessageBox, QPlainTextEdit, QProgressBar, QProgressDialog, QPushButton, QShortcut, QSizePolicy, QSpinBox, - QSplashScreen, QTextBrowser, QToolBox, QVBoxLayout, QWidget,) + QAction, QApplication, QFileDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, + QMessageBox, QProgressBar, QPushButton, QShortcut, QSizePolicy, + QSplashScreen, QToolBox, QVBoxLayout, QWidget,) from PyQt5.uic import loadUiType ts.log('Import part 4/8:') import pyqtUsrObj as UsrGO @@ -165,7 +150,6 @@ import app_utils from app_config import AppCfg,WndParameter #settings, option, toggle_option import epics -from epics.ca import pend_event import camera,backlight,zoom,illumination,geometry ts.log('Import part 7/8:') import psi_device diff --git a/zoom.py b/zoom.py index 308e6dc..34eab37 100755 --- a/zoom.py +++ b/zoom.py @@ -8,30 +8,18 @@ ''' ''' -import json import logging _log=logging.getLogger(__name__) import os -from PyQt5 import QtWidgets, uic -import PyQt5.QtWidgets as qtw from PyQt5.QtCore import pyqtSignal from PyQt5.QtWidgets import ( - QApplication, - QPushButton, - QGroupBox, - QGridLayout, - QLabel, - QDoubleSpinBox, - QSpinBox, - QVBoxLayout, - QHBoxLayout, - QCheckBox, + QApplication, QPushButton, QGroupBox, QGridLayout, QLabel, QDoubleSpinBox, QSpinBox, + QVBoxLayout, QHBoxLayout, QCheckBox, ) from PyQt5.uic import loadUiType import backlight, illumination, camera import epics -from app_config import AppCfg #settings Ui_Zoom, QWidget = loadUiType(os.path.join(os.path.dirname(__file__),"zoom.ui")) MIN_ZOOM = 1 @@ -50,22 +38,6 @@ class Zoom(QGroupBox, Ui_Zoom): def init_settings(self): app=QApplication.instance() - #cfg=app._cfg - #keys=cfg.allKeys() - #if cfg.ZOOM_BUTTONS in keys: - # buttons=json.loads(cfg.value(cfg.ZOOM_BUTTONS)) - #else: - # buttons=((1, "1"),(200, "200"),(400, "400"),(600, "600"),(800, "800"),(1000, "1000"),) - # cfg.setValue(cfg.ZOOM_BUTTONS,json.dumps(buttons)) - #self.get_zoom_pv = PV(zoom_api + ":ZOOM-RBV", callback=self.zoom_update_cb) - #self.status_pv = PV(zoom_api + ":ZOOM-STATUS", callback=self.zoom_status_cb) - #try: - # pv=app._zoom.getPv('POS_RB') - #except AttributeError as e: - # _log.debug('Simulated zoom') - #else: - # pv.callbacks ... = self.zoom_update_cb - # check also: pv.clear_auto_monitor() # disconnect PV monitor callback -> program exit faster. buttons=((1, "1"), (200, "200"), (400, "400"), (600, "600"), (800, "800"), (1000, "1000"),) zoom=QApplication.instance()._zoom @@ -80,7 +52,6 @@ class Zoom(QGroupBox, Ui_Zoom): self._zoom_spinner.setRange(MIN_ZOOM, MAX_ZOOM) self._zoom_spinner.setValue(current_zoom_value) self._zoom_spinner.editingFinished.connect(self.move_zoom_a) - # self._zoom_spinner.setSingleStep(SPINNER_SINGLE_STEP) self._zoom_spinner.setSingleStep(SPINNER_LARGE_STEP) _box = QWidget() _box.setLayout(QHBoxLayout()) @@ -178,14 +149,6 @@ class Zoom(QGroupBox, Ui_Zoom): self.slid.setSuffix(" ms") grid.addWidget(self.slid, 0, 1) - #grid.addWidget(QLabel("Acq.Mode"), 1, 0) - #cbox = QComboBox() - #for mode in Camera.AcquisitionMode: - # cbox.addItem(mode.name, mode) - #cbox.setCurrentIndex(cam.pv_acqmode.get()) - #cbox.currentIndexChanged.connect(self.update_camera_acqmode) - #grid.addWidget(cbox, 1, 1) - lbox.layout().addWidget(grp) self.slid.editingFinished.connect(lambda: self.update_exposure(self.slid.value())) @@ -270,21 +233,6 @@ class Zoom(QGroupBox, Ui_Zoom): self._zoom_spinner.blockSignals(False) self.zoomChanged.emit(float(value)) -# def get_zoom(self) -> int: -# zoom=QApplication.instance()._zoom -# pos = zoom.get() -# _log.debug("get_zoom(epics) => {}".format(pos)) -# return pos - -# def zoom_update_cb(self, pvname, value, char_value, **kwargs): -# self._zoom_spinner.blockSignals(True) -# self._zoom_spinner.setValue(value) -# self._zoom_spinner.blockSignals(False) - -# def zoom_status_cb(self, pvname, value, char_value, **kwargs): -# busy = bool(value) -# self.setDisabled(busy) - class QopticZoom(object): @@ -336,7 +284,7 @@ class QopticZoom(object): if __name__ == "__main__": - import time, os, PIL.Image, platform, subprocess + import sys, os import argparse logging.basicConfig(level=logging.DEBUG,format='%(levelname)s:%(module)s:%(lineno)d:%(funcName)s:%(message)s ') @@ -344,18 +292,11 @@ if __name__ == "__main__": parser.add_argument("--sim", "-s", help="simulate all devices", action='store_true') args = parser.parse_args() - import sys - _log.info('Arguments:{}'.format(args.__dict__)) os.environ['EPICS_CA_ADDR_LIST'] = '129.129.244.255 sf-saresc-cagw.psi.ch:5062 sf-saresc-cagw.psi.ch:5066' app = QApplication(sys.argv) from app_config import appsconf - #from PyQt5 import QtGui - #qtawesome.load_font("material","MaterialIcons-Regular.ttf","MaterialIcons-Regular.json","fonts/",) - #QtGui.QFontDatabase.addApplicationFont("fonts/Inconsolata-Bold.ttf") - #QtGui.QFontDatabase.addApplicationFont("fonts/Baloo-Regular.ttf") - if args.sim: app._backlight = backlight.Backlight(None) app._illumination = illumination.IlluminationControl(None) @@ -367,8 +308,6 @@ if __name__ == "__main__": app._zoom = QopticZoom() app._camera = camera.epics_cam() - - simulated = appsconf["microscope"]["zoom"].get("simulate", False) obj=Zoom()