plots labelled, save to and recall from hdf enabled

This commit is contained in:
2024-09-18 16:07:47 +02:00
parent 55795c0837
commit 19712a1801
3 changed files with 218 additions and 154 deletions

View File

@@ -25,12 +25,12 @@ matplotlib.use('Agg')
_pymodule = os.path.basename(__file__)
PROGRESS_BAR_THREAD_INIT = 0
PROGRESS_BAR_THREAD_START = 1
PROGRESS_BAR_THREAD_ABORTING = 2
PROGRESS_BAR_THREAD_ABORTED = 3
PROGRESS_BAR_THREAD_ERROR = 4
PROGRESS_BAR_THREAD_END = 100
PROGRESS_THREAD_INIT = 0
PROGRESS_THREAD_START = 1
PROGRESS_THREAD_ABORTING = 2
PROGRESS_THREAD_ABORTED = 3
PROGRESS_THREAD_ERROR = 4
PROGRESS_THREAD_END = 100
class AnalysisProcedure(QObject):
@@ -56,15 +56,15 @@ class AnalysisProcedure(QObject):
self.all_data = {}
self.all_data['Input data'] = {}
self.all_data['Ambient data'] = {}
self.all_data['Application Raw data'] = {}
#self.all_data['Application Raw data'] = {}
self.all_data['Processed data'] = {}
self.all_data['Figure data'] = {}
self.all_data['Raw data'] = {}
self.raw_data = {}
self.ring_cyclotron = 'Cyclotron'
self.injector_2 = 'Injector'
self.injector_2 = self.parent.injector_2
self.ring_cyclotron = self.parent.ring_cyclotron
#Declare input parameters
self.input_data = None
@@ -97,12 +97,12 @@ class AnalysisProcedure(QObject):
Set abort variable to interrupt measurement
"""
self.abort = True
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_ABORTING)
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_ABORTING)
def aborting(self, line_no):
self.abort = False
#mess = "Measurement aborted"
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_ABORTED)
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_ABORTED)
#########INITIALIZE THE INPUTS FOM THE GUI#######################
@@ -110,7 +110,8 @@ class AnalysisProcedure(QObject):
def initialize_input_parameters(self, input_data: dict):
self.input_data = input_data
self.all_data['Input data'] = self.input_data
if 'debug' in self.input_data.keys():
self.debug = self.input_data['debug']
@@ -142,7 +143,7 @@ class AnalysisProcedure(QObject):
print("self.accelerator-F", self.accelerator, flush=True)
self.harmonic_no = float(
self.input_data[self.accelerator]['harmonic'])
self.dTcable = int(
self.dTcable = float(
self.input_data[self.accelerator]['deltaTcable'])
self.dNpickup = int(
self.input_data[self.accelerator]['deltaNpickup'])
@@ -169,19 +170,17 @@ class AnalysisProcedure(QObject):
self.logger.info("Harmonic No. {0}".format(self.harmonic_no))
self.logger.info("dT Cable {0}".format(self.dTcable))
self.logger.info("dN Pickup {0}".format(self.dNpickup))
except KeyError as ex:
self.logger.debug("KeyError {0}".format(ex))
self.logger.error("KeyError {0}".format(ex))
except ValueError as ex:
self.logger.debug("ValueError {0}".format(ex))
self.logger.error("ValueError {0}".format(ex))
except Exception as ex:
self.logger.debug("Exception {0}".format(ex))
self.logger.error("Exception {0}".format(ex))
def measure_and_analyze(self, input_data=None):
'''
This method is initiated by the START button in Procedure panel
'''This method is initiated by the START button in Procedure panel
'''
if input_data is None:
mess = "No input parameters given; no measurement performed"
@@ -191,50 +190,38 @@ class AnalysisProcedure(QObject):
#Read the input parameters from the GUI
self.initialize_input_parameters(input_data)
#If Injector, add Not Implement QMessagge Box
if self.injector_2 in self.accelerator:
raise NotImplementedError
#Step 1 - Collect ambient data relate to the machine
self.all_data['Ambient data'] = self.collect_ambient_data()
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_START)
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_START)
#Step 2 - Perform measurement and return data for processing
self.raw_data = self.measure()
#print("raw data", self.raw_data)
if self.raw_data is None:
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_ERROR)
self.all_data['Raw data'] = self.measure()
if self.all_data['Raw data'] is None:
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_ERROR)
return None
self.all_data['Application Raw data'] = self.raw_data
#Step 3 - Process the raw data
self.all_data['Processed data'] = self.process()
#Step 4 - Provide plots
self.all_data['Figure data'] = self.make_figs()
#Step 5 - Package to all_data dictionary
#all_data = self.combine_data(self.all_data['Ambient data'], proc_data, fig_data)
#print("all data", all_data)
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_END)
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_END)
return self.all_data
def load_hdf_file(self, hdf_filename_loaded):
print("raw_data==>", hdf_filename_loaded, flush=True)
print("load_hdf_file==>", hdf_filename_loaded, flush=True)
raw_data = h5_storage.loadH5Recursive(hdf_filename_loaded)
self.raw_data = raw_data
print("loadH5Recursive", self.raw_data, flush=True)
print("loadH5Recursive", raw_data, flush=True)
return self.raw_data
return raw_data
def reanalyze(self, all_data):
@@ -248,16 +235,20 @@ class AnalysisProcedure(QObject):
ambient_data = all_data['Ambient_data']
self.raw_data = all_data['Raw_data']
self.all_data['Raw data'] = self.raw_data
ambient_data['Time in seconds'] = int(ambient_data['Time in seconds'])
self.parent.from_hdf = True
self.time_stamp = ambient_data['Time stamp']
proc_data = self.process(from_hdf5=True)
fig_data = self.make_figs()
all_data_new = self.combine_data(ambient_data, proc_data,
fig_data)
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_END)
return(all_data_new)
self.all_data['Ambient data'] = ambient_data
self.parent.from_hdf = True
self.all_data['Processed data'] = self.process(from_hdf5=True)
self.all_data['Figure data'] = self.make_figs()
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_END)
return(self.all_data)
def collect_ambient_data(self):
@@ -265,7 +256,7 @@ class AnalysisProcedure(QObject):
"""
# Time in seconds in an integer and can be stored in hdf5
time_in_seconds = time.time()
time_stamp = datetime.fromtimestamp(
self.time_stamp = datetime.fromtimestamp(
time_in_seconds).strftime('%a %d-%m-%Y %H:%M:%S')
#EPICS...
@@ -286,13 +277,13 @@ class AnalysisProcedure(QObject):
self.aborting(_line())
return {}
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_ERROR)
self.parent.trigger_progressbar.emit(PROGRESS_THREAD_ERROR)
return {}
ambient_data = {
'Time in seconds': int(time_in_seconds),
'Time stamp': time_stamp,
'Time stamp': self.time_stamp,
}
@@ -300,8 +291,35 @@ class AnalysisProcedure(QObject):
return ambient_data
def measure(self):
def extract_peak_data(self):
y1_peaks_pre = signal.find_peaks(self.y1_sample, height=0.005)
y1_peaks_avg = np.average(y1_peaks_pre[1]['peak_heights'])
y1_height = y1_peaks_avg * 0.666667
y2_peaks_pre = signal.find_peaks(self.y2_sample, height=0.005)
y2_peaks_avg = np.average(y2_peaks_pre[1]['peak_heights'])
y2_height = y2_peaks_avg * 0.666667
print("AVG = ", y1_height, y2_height, flush=True)
y1_peaks = signal.find_peaks(self.y1_sample, height=y1_height)
y2_peaks = signal.find_peaks(self.y2_sample, height=y2_height)
print("PEAKS==>", y1_peaks, y2_peaks, len(y1_peaks[0]), len(y2_peaks[0]), flush=True)
print(y1_peaks[1]['peak_heights'] ,flush=True)
#import sys
#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):
''' Enable DAQ and read in the collected data from EPICS
'''
if self.abort:
self.aborting(utils.line_no())
return None
self.parent.from_hdf = False
#Start and Stop Run
#Collect Data and out into numpy array
@@ -321,78 +339,63 @@ class AnalysisProcedure(QObject):
for count, entry in enumerate(self.content[5:]):
entry=entry.replace('\n','')
val=entry.split('\t')
self.t_sample.append(t_inc)
self.t_sample.append(float(t_inc))
self.y1_sample.append(float(val[1])*(-1))
self.y2_sample.append(float(val[2]))
t_inc += self.t_stepsize
y1_peaks = signal.find_peaks(self.y1_sample, height=0.03)
y2_peaks = signal.find_peaks(self.y2_sample, height=0.02)
print("PEAKS", y1_peaks, y2_peaks, len(y1_peaks[0]), len(y2_peaks[0]), flush=True)
print(y1_peaks[1]['peak_heights'] ,flush=True)
#import sys
#sys.exit()
self.y1_pulse = (y1_peaks[1]['peak_heights'])
self.y2_pulse = (y2_peaks[1]['peak_heights'])
def extract_peak_data():
index_max_y1 = np.argmax(self.y1_sample[0:int(self.t_interval*1.5)])
index_max_y2 = np.argmax(self.y2_sample[0:int(self.t_interval*1.5)])
index_max = min(index_max_y1, index_max_y2)
print(self.t_interval, index_max_y1, index_max_y2, flush=True)
start = self.t_interval - index_max
stop = min(len(self.y1_sample), len(self.y2_sample))
t_inc = 0
icount = 0
for val in range(start, stop, self.t_interval):
search_array1 = self.y1_sample[val:val+self.t_interval]
search_array2 = self.y2_sample[val:val+self.t_interval]
self.y1_pulse.append(np.array(search_array1).max())
self.y2_pulse.append(np.array(search_array2).max())
self.t_pulse.append(t_inc)
#t_inc += self.t_stepsize * self.t_interval
t_inc += self.pulse_stepsize
icount +=1
t_offset = icount/2
self.t_pulse = np.array(self.t_pulse) - t_offset*self.t_stepsize*self.t_interval
print("length====>", len(self.y1_pulse), len(self.y2_pulse) )
if self.simulation:
self.parent.trigger_progressbar.emit(20)
print("open File", flush=True)
file = open('/hipa/bd/data/measurements/tina/20240710-223007_2000.txt','r')
self.parent.trigger_progressbar.emit(40)
if self.abort:
file.close()
self.aborting(utils.line_no())
return None
self.content = file.readlines()
file.close()
if self.abort:
self.aborting(utils.line_no())
return None
print("close File", flush=True)
self.parent.trigger_progressbar.emit(60)
extract_raw_data()
#extract_peak_data()
self.extract_peak_data()
if self.abort:
self.aborting(utils.line_no())
return None
#extract_peak_data()
self.parent.trigger_progressbar.emit(70)
#Fill Raw data here
raw_data = {
'y1': self.y1_sample,
'y2': self.y2_sample,
't': self.t_sample
rawdata = {
'y1': list(self.y1_sample),
'y2': list(self.y2_sample),
't': list(self.t_sample),
}
return raw_data
return rawdata
def unpack_hdf_data(self):
self.y1_pulse = self.raw_data['y1']
self.y2_pulse = self.raw_data['y2']
self.y1_sample = self.raw_data['y1']
self.y2_sample = self.raw_data['y2']
self.t_sample = self.raw_data['t']
self.extract_peak_data()
def process(self, from_hdf5=False):
''' Process the collected data
'''
self.parent.trigger_progressbar.emit(PROGRESS_BAR_THREAD_START)
if self.abort:
self.aborting(utils.line_no())
return None
self.parent.trigger_progressbar.emit(80)
if from_hdf5:
self.unpack_hdf_data()
@@ -410,9 +413,9 @@ class AnalysisProcedure(QObject):
len(self.normalized_amplitude_envelope_2),
len(self.normalized_amplitude_envelope_1), mode='full')
self.lag_full = self.lags_full_array[np.argmax(self.corr_full)]
self.lag_full = int( self.lags_full_array[np.argmax(self.corr_full)])
#self.delay = self.lag_full * self.t_stepsize*self.t_interval
self.delay = self.lag_full * self.pulse_stepsize
self.delay = float (self.lag_full * self.pulse_stepsize)
print("lag", self.lag_full)
print("delay", self.delay, flush=True)
print("dTcable", self.dTcable, flush=True)
@@ -426,12 +429,17 @@ class AnalysisProcedure(QObject):
print("lag = {0}, delay = {1}, nturns={2}".format(
self.lag_full, self.delay, self.N_turns))
#Fill Raw data here
if self.abort:
self.aborting(utils.line_no())
return None
#Fill Processed data here
proc_data = {
'y1': self.y1_pulse,
'y2': self.y2_pulse,
't': self.t_pulse,
'y1': self.y1_pulse.tolist(),
'y2': self.y2_pulse.tolist(),
't_stepsize': self.pulse_stepsize,
'lag': self.lag_full,
'delay': self.delay,
'nturns': self.N_turns
@@ -440,6 +448,9 @@ class AnalysisProcedure(QObject):
return proc_data
def make_figs(self):
''' Figure construction with matplotlib
'''
fig, (ax) = plt.subplots(nrows=2, ncols=1, figsize=(18,9), layout='tight')
fig2, (ax2) = plt.subplots(nrows=1, ncols=1, figsize=(18,9))
fig.patch.set_facecolor('#FAF9F6')
@@ -451,44 +462,55 @@ class AnalysisProcedure(QObject):
#ax[0].ticklabel_format(useOffset=False, style='plain')
ax[0].plot(self.t_sample[s:e], self.y1_sample[s:e], 'r-', label='')
ax[0].plot(self.t_sample[s:e], self.y1_sample[s:e], '.r-', label='')
ax[1].plot(self.t_sample[s:e], self.y2_sample[s:e], '.r-', label='' )
ax[0].xaxis.set_major_locator(ticker.MultipleLocator(self.t_stepsize*self.t_interval))
ax[0].xaxis.set_major_locator(
ticker.MultipleLocator(self.t_stepsize*self.t_interval))
ax[0].set_xlabel('Time [s]')
ax[0].set_ylabel('Amplitude')
ax[0].set_title('Pulse at Entry')
ax[0].set_facecolor("lightgrey")
#ax[0].legend()
ax[0].grid(visible=True, which='major', axis='both', linestyle='--', linewidth=0.8)
ax[1].xaxis.set_major_locator(ticker.MultipleLocator(self.t_stepsize*self.t_interval))
ax[0].grid(visible=True, which='major', axis='both',
linestyle='--', linewidth=0.8)
ax[1].xaxis.set_major_locator(
ticker.MultipleLocator(self.t_stepsize*self.t_interval))
ax[1].set_xlabel('Time [s]')
ax[1].set_ylabel('Amplitude')
ax[1].set_title('Pulse at Exit')
ax[1].set_facecolor("lightgray")
ax[1].grid(visible=True, which='major', axis='both', linestyle='--', linewidth=0.8)
ax[1].grid(visible=True, which='major', axis='both',
linestyle='--', linewidth=0.8)
#ax[1].legend()
ax2.set_title('Cross-correlation between {0} Entrance and Exit'.format(
self.accelerator), fontsize=16)
ax2.set_ylabel('x-corr', fontsize=14)
ax2.set_xlabel('t (units of {0:.2f} ns)'.format(
self.pulse_stepsize*10**9), fontsize=14)
ax2.grid(visible=True, which='major', axis='both', linestyle='--',
linewidth=0.8)
ax2.set_facecolor("#F5F5F5")
ax2.plot(self.lags_full_array[:], self.corr_full[:])
xmin, xmax, ymin, ymax = ax2.axis()
lineStart = ymin #self.corr_full.min()
lineEnd = ymax #self.corr_full.max()
print("start end ", lineStart, lineEnd)
ax2.plot([1107, 1107], [lineStart, lineEnd], '-', color = 'r')
ax2.plot([self.lag_full, self.lag_full], [lineStart, lineEnd],
':', color = 'r')
ax2.set_ylim(lineStart, lineEnd)
#ax2[1].plot(self.lags_full_array[:], self.corr_full[:], 'yo')
text = "No of Turns = {0}".format(int(self.N_turns))
plt.figtext(0.65, 0.82, self.accelerator, weight='bold', fontsize=16)
plt.figtext(0.65, 0.77, text, weight='bold', fontsize=16)
plt.figtext(0.7, 0.72, "lag = {0}".format(self.lag_full), weight='normal',
fontsize=14)
text = 'delay = {0:.3f} (\u00B5s)'.format(self.delay*10**6)
plt.figtext(0.7, 0.67, text, weight='normal', fontsize=14)
if self.settings.data["GUI"]["showDate"]:
plt.figtext(0.75, 0.12, self.time_stamp, size='small')
fig_data = {'Canvas 1': [fig2], 'Canvas 2': [fig]}
return fig_data
def combine_data(self, ambient_data, proc_data, fig_data):
all_data = {'Input data': self.input_data}
all_data['Ambient data'] = ambient_data
all_data['Application Raw data'] = self.raw_data
all_data['Processed data'] = proc_data
all_data['Figure data'] = fig_data
all_data['Raw data'] = {}
return(all_data)

View File

@@ -51,6 +51,7 @@
"GUI": {
"resultsTabTitle" : "Plots",
"subResultsTabTitle" : ["Correlations", "Raw Data"],
"resultsSeq" : [1, 1]
"resultsSeq" : [1, 1],
"showDate" : 1
}
}

85
tina.py
View File

@@ -34,7 +34,9 @@ _appname = "Tina"
class StartMain(BaseWindow):
trigger_log_message = Signal(str, str, int, str, dict)
ring_cyclotron = 'Cyclotron'
injector_2 = 'Injector'
def __init__(self, parent=None):
super().__init__(
parent=parent, pymodule=_pymodule, appversion=_appversion,
@@ -44,7 +46,8 @@ class StartMain(BaseWindow):
self.appname = _appname
self.source_file = _abspath #required for HDF
self.elog_enum = ElogHIPA()
self.accelerator = 'Cyclotron'
self.accelerator = self.ring_cyclotron #default
#self.from_hdf = False in base class
self.message = ""
self.gui = AppGui(self)
@@ -53,10 +56,13 @@ class StartMain(BaseWindow):
"""Prepare results message
"""
try:
self.no_turns = self.all_data["Processed data"]["nturns"]
except KeyError as ex:
self.no_turns = 0
self.no_turns = self.all_data["Processed data"]["nturns"]
lag_full = self.all_data["Processed data"]["lag"]
delay = self.all_data["Processed data"]["delay"]
except KeyError:
self.message = ""
return
try:
self.accelerator = self.all_data["Input data"]["accelerator"]
except KeyError as ex:
@@ -70,8 +76,11 @@ class StartMain(BaseWindow):
_mess = "Reanalysis from HDF5. " if self.from_hdf else ""
self.message = (_mess +
"The number of turns measured in the {0} = {1} ({2:.2f})".format(
self.accelerator, int(self.no_turns), self.no_turns))
'''
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))
@@ -103,14 +112,39 @@ class StartMain(BaseWindow):
self.logbook = "Sandkasten" if simulation else "HIPA"
self.title = _title
def verify_analysis_preconditions(self):
if self.injector_2 in self.input_parameters['accelerator']:
mess = ("Measurement procedure for Injector 2 \n" +
"has not yet been implementented.")
QMessageBox.information(self, "Injector 2", mess, QMessageBox.Ok)
QApplication.processEvents()
return False
return True
@Slot()
def analysis_thread_finished(self):
BaseWindow.analysis_thread_finished(self)
if self.all_data is not None:
if self.all_data['Figure data'] is not None:
self.gui_frame.central_tab_widget.setCurrentIndex(1)
try:
if self.all_data['Figure data'] is not None:
self.gui_frame.central_tab_widget.setCurrentIndex(1)
except KeyError:
print("No analysis performed")
return
else:
print("thread finished with no data")
ncanvas = len(self.settings.data["GUI"]["subResultsTabTitle"])
dict_fig = {}
dict_fig['Figure data'] = {}
for i in range(0, ncanvas):
canvas = "Canvas {0}".format(i+1)
dict_fig['Figure data'][canvas] = None
#Delete old figures
self.gui.gui_frame.canvas_update(dict_fig['Figure data'])
return
self.prepare_results_message()
self.show_log_message(MsgSeverity.INFO, _pymodule, utils.line_no(),
self.message)
@@ -122,7 +156,7 @@ class StartMain(BaseWindow):
self.show_log_message(MsgSeverity.INFO, _pymodule, utils.line_no(),
self.message)
'''
@Slot()
def save_to_hdf_dialog(self):
@@ -135,7 +169,7 @@ class StartMain(BaseWindow):
return False
BaseWindow.save_to_hdf_dialog(self)
'''
@Slot()
@@ -168,18 +202,26 @@ class StartMain(BaseWindow):
"""
if self.all_data is not None:
#All but 'Figure data'
self.all_data['Raw data']['Input_data'] = self.all_data[
print("add_to_hdf")
#print(self.all_data['Rawdata'], flush=True)
#print("raw data==========>", self.all_data['Raw data']['y1'][0:5], flush=True)
#print("raw data==========>", self.all_data['Raw data']['y2'][0:5], flush=True)
#print("raw data==========>", self.all_data['Rawdata']['t'][0:5], flush=True)
_all_data = {}
_all_data ['Raw data'] = {}
print("add_to_hdf//")
_all_data['Raw data']['Input_data'] = self.all_data[
'Input data']
self.all_data['Raw data']['Ambient_data'] = self.all_data[
_all_data['Raw data']['Ambient_data'] = self.all_data[
'Ambient data']
self.all_data['Raw data']['Processed_data'] = self.all_data[
_all_data['Raw data']['Processed_data'] = self.all_data[
'Processed data']
self.all_data['Raw data']['Raw_data'] = self.all_data[
'Application Raw data']
#self.all_data['Raw_data'] = self.all_data['Application Raw data']
_all_data['Raw data']['Raw_data'] = self.all_data[
'Raw data']
#_all_data['Raw_data'] = self.all_data['Rawdata']
#del self.all_data['Figure data']
h5_storage.saveH5Recursive(
self.hdf_filename, self.all_data['Raw data'], dataH5)
self.hdf_filename, _all_data['Raw data'], dataH5)
@Slot()
def send_to_elog(self):
@@ -247,7 +289,6 @@ class StartMain(BaseWindow):
def save_to_epics(self):
""" Write the number of turns calculated to an EPICS PV
"""
print(self.all_data)
if not BaseWindow.verify_save_to_epics(self):
return False
if self.from_hdf: