From 7572c9ca640d57d79f95fa5af49b8b4c0515f147 Mon Sep 17 00:00:00 2001 From: chrin Date: Tue, 24 Sep 2024 10:34:51 +0200 Subject: [PATCH] inserted code for actual measurement --- src/analysis.py | 172 ++++++++++++++++++++++++++++++++++++++---------- src/gui.py | 86 +++++++++++++++++++++++- tina.json | 20 ++++-- tina.py | 42 +++++++----- tina.sh | 6 +- 5 files changed, 269 insertions(+), 57 deletions(-) diff --git a/src/analysis.py b/src/analysis.py index 1952e9e..4288224 100644 --- a/src/analysis.py +++ b/src/analysis.py @@ -1,6 +1,7 @@ """ Analysis class """ +from collections import OrderedDict from datetime import datetime import inspect import logging @@ -8,6 +9,7 @@ import math import os from statistics import mean import time +import timeit import matplotlib @@ -44,7 +46,9 @@ class AnalysisProcedure(QObject): self.settings = self.parent.settings self.cafe = self.parent.cafe self.cyca = self.parent.cyca - + self.check_status = self.parent.check_status + self.check_status_list = self.parent.check_status_list + self.daq_timeout = 10 self.logging = self.parent.logging self.logger = self.logging.getLogger(__name__) self.logger.debug("Logging activated in analysis procedure") @@ -52,6 +56,9 @@ class AnalysisProcedure(QObject): self.abort = False self.trigger_abort.connect(self.receive_abort) + #Hold PV names and their values + self.pv_value_dict = OrderedDict() + self.pv_dict = {} #Package the data as so: self.all_data = {} self.all_data['Input data'] = {} @@ -76,7 +83,7 @@ class AnalysisProcedure(QObject): self.N_turns = None #self.t_stepsize = 0.000000019750043 #0.00000002 self.rf_freq = 50.6328 #10**6 - self.rf_sample =2.5 #10**6 + self.rf_sample =3.0 #10**6 self.pulse_stepsize = 1/(self.rf_freq*10**6) self.t_stepsize = 1/(self.rf_sample*10**9) self.t_interval = math.ceil(self.pulse_stepsize/self.t_stepsize) @@ -120,27 +127,22 @@ class AnalysisProcedure(QObject): self.simulation = bool(self.input_data['simulation']) - print("INPUT:", self.input_data) self.rf_freq = float(self.input_data['freqrf']) - self.rf_sample = float(self.input_data['freqsampling']) - + + #2.5 MHz if oscilloscpe + if self.simulation: + self.rf_sample = 2.5 + mess = 'Sampling rate changed to 2.5 MHz for oscilloscope data' + self.parent.trigger_log_message.emit( + MsgSeverity.INFO.name, _pymodule, utils.line_no(), mess, {}) + else: + self.rf_sample = float(self.input_data['freqsampling']) + try: self.accelerator = self.input_data['accelerator'] - print("self.accelerator -1 ", self.accelerator, flush=True) - except KeyError as ex: - self.logger.debug("KeyError {0}".format(ex)) - print("self.accelerator-2", self.accelerator, flush=True) - try: - self.accelerator = self.input_data['qtabdata'] - print("self.accelerator-3", self.accelerator, flush=True) - except KeyError as ex: - self.logger.debug("KeyError {0}".format(ex)) - - try: - - print("self.accelerator-F", self.accelerator, flush=True) + self.harmonic_no = float( self.input_data[self.accelerator]['harmonic']) self.dTcable = float( @@ -154,13 +156,10 @@ class AnalysisProcedure(QObject): self.duty_cycle = float( self.input_data[self.accelerator]['dutycycle']) # * 0.01 - - print("logging info level==>", self.logger.getEffectiveLevel(), - flush=True) + self.loglevel = self.input_data['loggingLevel'] self.logger.setLevel(self.logging.getLevelName(self.loglevel)) - print("logging info level==>", self.logger.getEffectiveLevel(), - flush=True) + self.logger.info("INPUT PARAMETERS") self.logger.info("Accelerator: {0}".format(self.accelerator)) @@ -231,7 +230,7 @@ class AnalysisProcedure(QObject): input_data = all_data['Input_data'] #Read the input parameters self.initialize_input_parameters(input_data) - print("initiliaze", flush=True) + ambient_data = all_data['Ambient_data'] self.raw_data = all_data['Raw_data'] @@ -259,6 +258,19 @@ class AnalysisProcedure(QObject): self.time_stamp = datetime.fromtimestamp( time_in_seconds).strftime('%a %d-%m-%Y %H:%M:%S') + + ambient_data = { + 'Time in seconds': int(time_in_seconds), + 'Time stamp': self.time_stamp, + } + + + self.logger.debug("{0}".format(ambient_data)) + + #if self.simulation: + # return ambient_data + + #EPICS... handles = self.cafe.getHandles()[0] status = self.cafe.attachContext(handles[0]) @@ -274,20 +286,62 @@ class AnalysisProcedure(QObject): "Scan will not be initiated!"), _options) if self.abort: - self.aborting(_line()) + self.aborting(utils.line_no()) return {} self.parent.trigger_progressbar.emit(PROGRESS_THREAD_ERROR) return {} - ambient_data = { - 'Time in seconds': int(time_in_seconds), - 'Time stamp': self.time_stamp, - } + pv_list = [] + + for key, value in self.settings.data['PV'][self.accelerator].items(): + self.pv_value_dict[key] = OrderedDict() + self.pv_value_dict[key][value] =0 + self.pv_dict[key] = value + pv_list.append(value) - - self.logger.debug("{0}".format(ambient_data)) + + self.cafe.openPrepare() + handle_list = self.cafe.open(pv_list) + self.cafe.openNowAndWait(1.0) + + self.cafe.setGetActionWhenMonitorPolicyAllHandles( + self.cyca.GET_FROM_CACHE) + + value_list, status, status_list = self.cafe.getScalarList(handle_list) + + if self.debug: + for pv, val, stat in zip(pv_list, value_list, status_list): + print(pv, val, stat) + + if status != self.cyca.ICAFE_NORMAL: + self.check_status_list(_pymodule, "getScalarList", + pv_list, status_list, utils.line_no()) + + + ''' + if status != self.cyca.ICAFE_NORMAL: + _options = {} + for pv, stat in zip(pv_list, status_list): + if stat != self.cyca.ICAFE_NORMAL: + _mess = ("Error in 'get' for pv " + pv + ".") + _options['statusCode'] = ( + str(stat) + " " + self.cafe.getStatusCodeAsString(stat)) + _options['statusInfo'] = self.cafe.getStatusInfo(stat) + self.parent.trigger_log_message.emit( + MsgSeverity.ERROR.name, _pymodule, utils.line_no(), + _mess, _options) + ''' + + #Put values in dictionary for inspection + for i, (dict_key) in enumerate(self.pv_value_dict.keys()): + self.pv_value_dict[dict_key] = value_list[i] + + if self.debug: + print ("EPICS PVS==>", self.pv_value_dict, flush=True) + print ("No of turns", self.pv_value_dict['nturns']) + return ambient_data @@ -310,7 +364,7 @@ class AnalysisProcedure(QObject): #sys.exit() self.y1_pulse = (y1_peaks[1]['peak_heights']) self.y2_pulse = (y2_peaks[1]['peak_heights']) - print(type(self.y1_pulse), flush=True) + def measure(self): @@ -344,7 +398,58 @@ class AnalysisProcedure(QObject): self.y2_sample.append(float(val[2])) t_inc += self.t_stepsize - if self.simulation: + if not self.simulation: + #start DAQ + #Set + pv_daq_start = self.pv_dict['daqStart'] + pv_daq_state = self.pv_dict['daqState'] + pv_wf_entry = self.pv_dict['wfEntry'] + pv_wf_exit = self.pv_dict['wfExit'] + pv_wf = [pv_wf_entry, pv_wf_exit] + + stat = self.cafe.set(pv_daq_start, 1) + self.check_status(_pymodule, "set", pv_daq_start, stat, + utils.line_no()) + + #Monitor DAQ State + start = time.time() + + finished = False + while (time.time() - start) < self.daq_timeout: + value = self.cafe.getCache(pv_daq_state) + if value is None: + stat = self.cafe.getStatus(pv_daq_state) + self.check_status(_pymodule, "getCache", pv_daq_state, stat, + utils.line_no()) + elif value == "DONE": + finished = True + break + if self.abort: + self.aborting(utils.line_no()) + return None + + time.sleep(1.0) + + if not finished: + mess = ("DAQ not completed. Exceeded allowed " + + "time limit of {0}s".format(self.daq_timeout)) + self.parent.trigger_log_message.emit( + MsgSeverity.ERROR.name, _pymodule, utils.line_no(), + mess, {}) + return None + + #Read WF from EPICS and fill sample y1_sample, y2_sample + (self.y1_sample, self.y2_sample), status, status_list = self.cafe.getCompoundList( + pv_wf, cacheFlag=True) + if status != self.cyca.ICAFE_NORMAL: + self.check_status_list(_pymodule, "getCompoundListCache", + pv_wf, status_list, utils.line_no()) + + return None + + + + else: self.parent.trigger_progressbar.emit(20) print("open File", flush=True) file = open('/hipa/bd/data/measurements/tina/20240710-223007_2000.txt','r') @@ -361,6 +466,7 @@ class AnalysisProcedure(QObject): print("close File", flush=True) self.parent.trigger_progressbar.emit(60) extract_raw_data() + self.extract_peak_data() diff --git a/src/gui.py b/src/gui.py index d44d142..6a9f73d 100644 --- a/src/gui.py +++ b/src/gui.py @@ -6,8 +6,8 @@ from qtpy.QtCore import __version__ as QT_VERSION_STR from qtpy.QtCore import QEventLoop, Qt, QTimer, Slot from qtpy.QtWidgets import ( QApplication, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QMessageBox, - QPushButton, QTabBar, QTabWidget, QTableWidgetItem, QTextEdit, QVBoxLayout, - QWidget) + QPushButton, QStackedWidget, QTabBar, QTabWidget, QTableWidgetItem, + QTextEdit, QVBoxLayout, QWidget) from common.packages import elog @@ -30,10 +30,14 @@ class AppGui(QWidget): self.parent = parent self.cafe = self.parent.cafe self.cyca = self.parent.cyca + self.settings = self.parent.settings self.check_status = self.parent.check_status self.check_status_list = self.parent.check_status_list self.elog_enum = self.parent.elog_enum + self.accelerator_list = [self.parent.injector_2, + self.parent.ring_cyclotron] + self.send_to_log_window = self.parent.send_to_log_window self.show_log_message = self.parent.show_log_message self.statusbar = self.parent.statusbar @@ -52,3 +56,81 @@ class AppGui(QWidget): self.gui_frame.measurement_tab_wgt.setFixedHeight(460) self.gui_frame.operator_wgt.setFixedHeight(640) self.gui_frame.expert_wgt.setFixedHeight(240) + + self.daq_wgt = self.daq_group_qtabwidget(widget_type="QStackedWidget") + self.gui_frame.measurement_layout.addWidget( + self.daq_wgt, 0, 1, 1, 1, alignment=Qt.AlignTop) + + self.daq_wgt.setCurrentIndex(self.parent.default_idx) + self.daq_wgt.currentChanged.emit(self.parent.default_idx) + + self.gui_frame.line_sender_dict[ + 'accelerator'].currentChanged.connect(self.cb_accelerator) + + + def cb_accelerator(self, idx): + self.daq_wgt.setCurrentIndex(idx) + + def daq_group_qtabwidget(self, widget_type="QStackedWidget"): + accel_wgt_dict = {} + + if "QTabWidget" in widget_type: + accel_tab_widget = QTabWidget() + accel_tab_widget.setFont(self.font_gui) + accel_tab_widget.setStyleSheet("QTabBar {font-size: 10pt;}") + accel_tab_widget.tabBar().setShape(QTabBar.TriangularNorth) + + for i, accel in enumerate(self.accelerator_list): + accel_wgt_dict[accel] = self.daq_group(accel) + + accel_tab_widget.addTab(accel_wgt_dict[accel], accel) + color = self.settings.data['Parameters']['accelerator'][data][ + 'color'][i] + accel_tab_widget.tabBar().setTabTextColor(i, QColor(color)) + + else: + accel_tab_widget = QStackedWidget() + + for i, accel in enumerate(self.accelerator_list): + accel_wgt_dict[accel] = self.daq_group(accel) + accel_tab_widget.addWidget(accel_wgt_dict[accel]) + + accel_tab_widget.setFixedWidth(300) + accel_tab_widget.setFixedHeight(160) + return accel_tab_widget + + def daq_group(self, accel): + group_box = QGroupBox("{0} DAQ".format(accel)) + obj_name = "CYCLOTRON" if self.parent.ring_cyclotron in accel else \ + "INJECTOR" + group_box.setObjectName(obj_name) + vbox = QGridLayout() + pv_daq = [] + pv_daq.append(self.settings.data['PV'][accel]['daqStart']) + pv_daq.append(self.settings.data['PV'][accel]['daqState']) + + self.cafe.openPrepare() + self.cafe.open(pv_daq) + self.cafe.openNowAndWait(1.0) + + pv1 = CAQLabel(self, pv_name=pv_daq[0]) + pv2 = CAQLabel(self, pv_name=pv_daq[1]) + vbox.addWidget(QLabel('Start/Stop Status:'), 0, 0) + vbox.addWidget(QLabel('Acquisition State:'), 1, 0) + vbox.addWidget(pv1, 0, 1) + vbox.addWidget(pv2, 1, 1) + vbox.setContentsMargins(9, 19, 9, 9) + vbox.setSpacing(5) + vbox.setAlignment(Qt.AlignTop | Qt.AlignHCenter) + group_box.setFixedWidth(268) + group_box.setFixedHeight(100) + group_box.setFont(self.font_gui) + group_box.setAlignment(int(Qt.AlignTop | Qt.AlignHCenter)) + group_box.setLayout(vbox) + + qw = QWidget() + grid = QGridLayout() + grid.addWidget(group_box, 0, 0) + qw.setLayout(grid) + + return qw diff --git a/tina.json b/tina.json index 0ec32d4..8f7a045 100755 --- a/tina.json +++ b/tina.json @@ -14,7 +14,19 @@ "addDateToDir" : 0 }, "header" : ["SHIFT", "INJ2", "IP2", "IW2", "PK1", "PK2", "SINQ", "UCN"], - "PVnturns" : {"Injector": "PV-INJ:NTURNS", "Cyclotron": "PV-CYC:NTURNS"}, + "PV" : {"Injector": {"nturns": "PV-INJ:NTURNS", + "daqStart": "PV-INJ:DAQ-START", + "daqState": "PV-INJ:DAQ-STATE", + "wfEntry": "PV-INJ:WF-ENTRY", + "wfExit": "PV-INJ:WF-EXIT" + }, + "Cyclotron": {"nturns": "PV-CYC:NTURNS", + "daqStart": "PV-CYC:DAQ-START", + "daqState": "PV-CYC:DAQ-STATE", + "wfEntry": "PV-CYC:WF-ENTRY", + "wfExit": "PV-CYC:WF-EXIT" + } + }, "HIPA": ["Injector", "Ring"], "HIPA2": {"test": ["Injector", "Ring"]}, "QTabAccelerator":{ @@ -35,18 +47,18 @@ "facility": {"flag": 0, "data" : {"widget": "QComboBox", "text" : "Facility:", "link": ["HIPA"],"layout" : "Horizontal"}}, "freqrf" : {"flag": 1, "data":{ "widget": "QLineEdit", "text" :"RF Freq (10^6/s):", "value" : 50.6328 }}, - "freqsampling" : {"flag": 1, "data":{ "widget": "QLineRead", "text" :"Sampling Freq (GHz):", "value" : 2.5 }}, + "freqsampling" : {"flag": 1, "data":{ "widget": "QLineRead", "text" :"Sampling Freq (GHz):", "value" : 3.0 }}, "drawLine" : {"flag" : 1, "data":{ "widget": "QHLine", "text" : "None", "value" : "None"}}, "accelerator" : {"flag" : 1, "data":{ "widget": "QTabWidget", "text" : "Accelerator: ", "link" : "QTabAccelerator", "value" : 1, - "color" : ["#0080aa", "#0000ff"]}} + "color" : ["#008b8b", "#0047ab" ]}} }, "Expert":{ "debug": {"flag" : 1, "data":{ "widget": "None", "text" : "Debug", "value" : 0}}, - "simulation": {"flag" : 1, "data":{ "widget": "None", "text" : "Simulation", "value" : 1}} + "simulation": {"flag" : 1, "data":{ "widget": "None", "text" : "Oscilloscope", "value" : 1}} }, "GUI": { "resultsTabTitle" : "Plots", diff --git a/tina.py b/tina.py index 5ac9cba..9283740 100644 --- a/tina.py +++ b/tina.py @@ -13,7 +13,6 @@ from qtpy.QtWidgets import QApplication, QMessageBox from apps4ops.bdbase.base import BaseWindow from apps4ops.bdbase import h5_storage, utils -#from apps4ops.bdbase.utils import _line from apps4ops.bdbase.enumkind import Facility, MsgSeverity, UserMode from apps4ops.bdbase.helpbrowser import HelpBrowser from apps4ops.hipa.sendeloghipa import QSendToELOG @@ -46,8 +45,11 @@ class StartMain(BaseWindow): self.appname = _appname self.source_file = _abspath #required for HDF self.elog_enum = ElogHIPA() - - self.accelerator = self.ring_cyclotron #default + self.message_elog = None + self.default_idx = self.settings.data['Parameters']['accelerator'][ + 'data']['value'] + self.accelerator = self.ring_cyclotron if self.default_idx else \ + self.injector_2 #self.from_hdf = False in base class self.message = "" self.gui = AppGui(self) @@ -61,6 +63,7 @@ class StartMain(BaseWindow): delay = self.all_data["Processed data"]["delay"] except KeyError: self.message = "" + self.message_elog = "" return try: @@ -74,13 +77,22 @@ class StartMain(BaseWindow): _mess = "Reanalysis from HDF5. " if self.from_hdf else "" - - self.message = (_mess + + + self.message_elog = ( + _mess + ''' - The number of turns measured in the {0} = {1} ({2:.2f}) - lag = {3}, delay = {4:.3f} (\u00B5s) - '''.format(self.accelerator, int(self.no_turns), self.no_turns, - lag_full, delay*10**6)) + No. turns measured in the {0} = {1} ({2:.2f})
+ lag = {3}, delay = {4:.3f} \u00B5s
'''.format( + self.accelerator, int(self.no_turns), self.no_turns, + lag_full, delay*10**6)) + + self.message = ( + _mess + + ''' + No. turns measured in the {0} = {1} ({2:.2f}) + lag = {3}, delay = {4:.3f} \u00B5s'''.format( + self.accelerator, int(self.no_turns), self.no_turns, + lag_full, delay*10**6)) @@ -244,14 +256,14 @@ class StartMain(BaseWindow): ortIdx=self.ort_idx, effektIdx=self.effekt_idx, title=self.title, - message=self.message, + message=self.message_elog, attachFile=self.attach_files) time.sleep(0.5) self.prepare_elog_message() - - print(self.message, flush=True) + + print(self.message_elog, flush=True) if not self.all_data: QSendToELOG(self, logbook=self.logbook, @@ -262,7 +274,7 @@ class StartMain(BaseWindow): ortIdx=self.ort_idx, effektIdx=self.effekt_idx, title=self.title, - message=self.message, + message=self.message_elog, attachFile=self.attach_files) return @@ -303,7 +315,7 @@ class StartMain(BaseWindow): debug = True dry_run = False nturns = int(self.no_turns) - pv = self.settings.data["PVnturns"]["Cyclotron"] + pv = self.settings.data["PV"]["Cyclotron"]["nturns"] dict_bunch[pv] = nturns if not dry_run: status, status_list = self.send_to_epics(dict_bunch) @@ -372,7 +384,7 @@ if __name__ == "__main__": app = QApplication(sys.argv) splash = BaseWindow.initialize_application( - app, appname=_appname, delay=20, facility=Facility.HIPA) + app, appname=_appname, delay=5, facility=Facility.HIPA) myapp = StartMain() diff --git a/tina.sh b/tina.sh index 384de19..bbc3cb1 100755 --- a/tina.sh +++ b/tina.sh @@ -30,19 +30,19 @@ if [ "$1" ]; then echo "Using default version $PYTHON_VERSION" elif [ "$1" == "3.7" -o "$1" == "37" ]; then PYTHON_VERSION=3.7 - PYTHON_PATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.20.0-gcc-7.3.0/lib/${_EPICS_HOST_ARCH}:/hipa/bd/applications/deps/apps4ops/v1.11.0 + PYTHON_PATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.20.0-gcc-7.3.0/lib/${_EPICS_HOST_ARCH}:/hipa/bd/applications/deps/apps4ops/v1.12.0 module unload gcc module load gcc/7.3.0 elif [ "$1" == "3.8" -o "$1" == "38" ]; then PYTHON_VERSION=3.8 - PYTHON_PATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.19.3/lib/${_EPICS_HOST_ARCH}:/hipa/bd/applications/deps/apps4ops/v1.11.0 + PYTHON_PATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.19.3/lib/${_EPICS_HOST_ARCH}:/hipa/bd/applications/deps/apps4ops/v1.12.0 module unload gcc module load gcc/7.5.0 elif [ "$1" == "3.10" -o "$1" == "310" ]; then PYTHON_VERSION=3.10 - PYTHON_PATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.20.0-gcc-7.5.0/lib/${_EPICS_HOST_ARCH}:/hipa/bd/applications/deps/apps4ops/v1.11.0 + PYTHON_PATH=.:/opt/gfa/cafe/python/pycafe/cafe-1.20.0-gcc-7.5.0/lib/${_EPICS_HOST_ARCH}:/hipa/bd/applications/deps/apps4ops/v1.12.0 module unload gcc module load gcc/7.5.0 else