From c4329441c13e5182313e455467ac4246552e934f Mon Sep 17 00:00:00 2001 From: Nicole Date: Mon, 18 Dec 2023 17:37:15 -0800 Subject: [PATCH] Cleanup before doc merge (#124) * cleaning up mat2py directory * cleaning up data analysis dir * adding sphinx to requirements * cleaning up imports/formatting * adding matlab emit scan doc * updating tests imports and directories * removing old profile monitor files * updating cor_plot to corr_plot --- .../README.MD => docs/source/cor_plot.rst | 0 docs/source/index.rst | 3 + .../source/mat_emit_scan.rst | 3 + .../data_analysis/fitting/fit_gaussian.py | 317 ------------------ lcls_tools/common/devices/profile_monitor.py | 155 --------- .../common/devices/profmon_constants.py | 57 ---- lcls_tools/common/devices/screen.py | 6 +- .../image_processing/image_processing.py | 22 -- .../common/matlab2py/cor_plot/__init__.py | 0 ...plot_mat_scan.py => corr_plot_mat_scan.py} | 0 .../common/matlab2py/emit_scan/.gitattributes | 1 - .../common/matlab2py/emit_scan/__init__.py | 0 .../{emit_scan => }/mat_emit_scan.py | 0 .../common/matlab2py/{image => }/mat_image.py | 0 requirements.txt | 6 +- .../common/data_analysis/fitting/__init__.py | 0 .../fitting/test_fit_gaussian.py | 29 -- .../common/devices/test_constants.py | 0 .../common/devices/test_profile_monitor.py | 91 ----- .../image_processing/test_image_processing.py | 2 +- .../common/matlab2py/cor_plot/__init__.py | 0 .../common/matlab2py/emit_scan/__init__.py | 0 .../common/matlab2py/image/__init__.py | 0 ...mat_scan.py => test_corr_plot_mat_scan.py} | 2 +- .../{emit_scan => }/test_mat_emit_scan.py | 2 +- .../matlab2py/{image => }/test_mat_image.py | 2 +- 26 files changed, 20 insertions(+), 678 deletions(-) rename lcls_tools/common/matlab2py/cor_plot/README.MD => docs/source/cor_plot.rst (100%) rename lcls_tools/common/matlab2py/emit_scan/README.MD => docs/source/mat_emit_scan.rst (98%) delete mode 100755 lcls_tools/common/data_analysis/fitting/fit_gaussian.py delete mode 100644 lcls_tools/common/devices/profile_monitor.py delete mode 100644 lcls_tools/common/devices/profmon_constants.py delete mode 100644 lcls_tools/common/matlab2py/cor_plot/__init__.py rename lcls_tools/common/matlab2py/{cor_plot/cor_plot_mat_scan.py => corr_plot_mat_scan.py} (100%) delete mode 100644 lcls_tools/common/matlab2py/emit_scan/.gitattributes delete mode 100644 lcls_tools/common/matlab2py/emit_scan/__init__.py rename lcls_tools/common/matlab2py/{emit_scan => }/mat_emit_scan.py (100%) rename lcls_tools/common/matlab2py/{image => }/mat_image.py (100%) delete mode 100644 tests/unit_tests/lcls_tools/common/data_analysis/fitting/__init__.py delete mode 100644 tests/unit_tests/lcls_tools/common/data_analysis/fitting/test_fit_gaussian.py delete mode 100644 tests/unit_tests/lcls_tools/common/devices/test_constants.py delete mode 100644 tests/unit_tests/lcls_tools/common/devices/test_profile_monitor.py delete mode 100644 tests/unit_tests/lcls_tools/common/matlab2py/cor_plot/__init__.py delete mode 100644 tests/unit_tests/lcls_tools/common/matlab2py/emit_scan/__init__.py delete mode 100644 tests/unit_tests/lcls_tools/common/matlab2py/image/__init__.py rename tests/unit_tests/lcls_tools/common/matlab2py/{cor_plot/test_cor_plot_mat_scan.py => test_corr_plot_mat_scan.py} (97%) rename tests/unit_tests/lcls_tools/common/matlab2py/{emit_scan => }/test_mat_emit_scan.py (96%) rename tests/unit_tests/lcls_tools/common/matlab2py/{image => }/test_mat_image.py (98%) diff --git a/lcls_tools/common/matlab2py/cor_plot/README.MD b/docs/source/cor_plot.rst similarity index 100% rename from lcls_tools/common/matlab2py/cor_plot/README.MD rename to docs/source/cor_plot.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 37ac6a58..e850dbd2 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,6 +12,9 @@ Welcome to lcls-tools's documentation! devices.rst image_processing.rst + cor_plot.rst + emit_scan.rst + Indices and tables diff --git a/lcls_tools/common/matlab2py/emit_scan/README.MD b/docs/source/mat_emit_scan.rst similarity index 98% rename from lcls_tools/common/matlab2py/emit_scan/README.MD rename to docs/source/mat_emit_scan.rst index ec730e60..530dcc72 100644 --- a/lcls_tools/common/matlab2py/emit_scan/README.MD +++ b/docs/source/mat_emit_scan.rst @@ -1,3 +1,6 @@ +Loading Matlab Emittance Scans +================ + This utility can take an emittance scan .mat file and turn it into a python data object. The goal is to present the data from an emittance scan in a meaningful way. This utility has a test file that is used for testing, but we can use it for examples. All examples are run from this directory. Current example is using Python2.7 Example: 'test_scan.mat' diff --git a/lcls_tools/common/data_analysis/fitting/fit_gaussian.py b/lcls_tools/common/data_analysis/fitting/fit_gaussian.py deleted file mode 100755 index 846523c0..00000000 --- a/lcls_tools/common/data_analysis/fitting/fit_gaussian.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/local/lcls/package/python/current/bin/python -################################################################################ -# Modified version of John Sheppard's read_xcor_data script -# Reads in a matlab file of xcor data and fits gaussians to it -# Data must have column names posList, ampList, and ampstdList -################################################################################ - -from __future__ import division - -from pylab import array, plt, floor -from numpy import argsort, power, exp, zeros -from scipy.optimize import curve_fit -from operator import itemgetter - - -NUM_BUCKS = 10 -DEBUG = False - - -# An unfortunate consequence of defining step as max/numbucks is that the -# maximum point is in its own bucket (bucket 10), which would break a lot of -# stuff, so it necessitates the error checking -def get_bucket(val, step): - bucket = int(floor(val / step)) - return bucket if bucket < 10 else 9 # TODO: should this use NUM_BUCKS? - - -def find_max(data, run): - max_index = max(enumerate(data[run]), key=itemgetter(1))[0] - return run[max_index] - - -# The very ham-fisted way I'm coming up with a guess for the width of a given -# peak is to get the literal distance between the first element of the -# subsequent run and the last element of the previous run -def find_widths(xdata, peak_idxs, runs, run_map): - widths = [] - for peak_idx in peak_idxs: - run_idx = run_map[peak_idx] - - # If it's the first run, just double the distance between the peak and - # the first element of the next run - if run_idx == 0: - widths.append((xdata[runs[1][0]] - xdata[peak_idx]) * 2) - - # If it's the last run, just double the distance between the peak and - # the last element of the previous run - elif run_idx == len(runs) - 1: - widths.append((xdata[peak_idx] - xdata[runs[-2][-1]]) * 2) - - else: - widths.append(xdata[runs[run_idx + 1][0]] - xdata[runs[run_idx - 1][-1]]) - - return widths - - -# Modified from StackOverflow -def gen_gauss_sum(x, *params): - m = params[0] - b = params[1] - - y = [m * i + b for i in x] - - for i in range(2, len(params), 3): - ctr = params[i] - amp = params[i + 1] - wid = params[i + 2] - y = y + gaussian(x, ctr, wid, amp) - return y - - -def gaussian(x, ctr, wid, amp): - return amp * exp(-power(x - ctr, 2.0) / (2 * power(wid, 2.0))) - - -def get_slope(x1, y1, x2, y2): - return (y2 - y1) / (x2 - x1) - - -# Idea to add a line instead of a really short, fat gaussian was all Ahemd. -# Thanks, yo. You're great. -def find_line(zero_runs, runs, xdata, ydata): - x1, y1, x2, y2, m, _ = (0, 0, 0, 0, 0, 0) - - # This condition should only be possible if there are peaks on one or both - # extremes, or if there is no peak - if len(zero_runs) == 1: - zero_run = runs[zero_runs[0]] - # This should pull out the median index value of the run - x_ind1 = zero_run[argsort(ydata[zero_run])[len(zero_run) / 2]] - y1 = ydata[x_ind1] - - return [m, y1] - - # 0 shouldn't be possible given that the data is normalized to the lowest - # point, so it should otherwise be at least 2. - # Currently just fitting the first point of the first zero run and the last - # point of the last zero run. Could make it smarter by adding a sum of step - # functions, but that seems like overkill - else: - zero1 = runs[zero_runs[0]] - zero2 = runs[zero_runs[-1]] - - x_ind1 = zero1[argsort(ydata[zero1])[len(zero1) / 2]] - x1 = xdata[x_ind1] - y1 = ydata[x_ind1] - - x_ind2 = zero2[argsort(ydata[zero2])[len(zero2) / 2]] - x2 = xdata[x_ind2] - y2 = ydata[x_ind2] - - m = get_slope(x1, y1, x2, y2) - - return [m, y1 - m * x1] - - -# Every run has the potential to be a peak, but we limit it to the numPeaks -# largest ones -def get_peaks(data, num_peaks, runs): - # Should be doable in preprocessing - len_runs = map(lambda run: len(run), runs) - - # User-proofing. Could probably limit input - num_peaks = num_peaks if num_peaks <= len(runs) else len(runs) - - # Would be using linear argpartsort if we were running not 2013 builds. - # Can you tell I'm bitter? - ind = argsort(array(len_runs))[-num_peaks:] - - # This is inelegant - peak_idx, peaks = ([], []) - for run in array(runs)[ind]: - idx = find_max(data, run) - peak_idx.append(idx) - peaks.append(data[idx]) - - max_index, max_value = max(enumerate(data), key=itemgetter(1)) - - # Maybe unnecessary precaution to make sure that the max point is used in - # the fit (a run wouldn't be found if the peak were sufficiently narrow) - max_info = [] - if max_value not in peaks: - if peaks: - min_index = min(enumerate(peaks), key=itemgetter(1))[0] - peaks[min_index] = max_value - peak_idx[min_index] = max_index - else: - peak_idx.append(max_index) - peaks.append(max_value) - max_info = [max_index, max_value] - - return [peaks, peak_idx, max_info] - - -# Checking for inflection points doesn't work because some data points don't -# follow the trend line; this groups consecutive data points by bucket, which -# need to be recalculated following an adjustment. -def get_runs(data, step): - # runMap maps each data point to the run that contains it - zero_runs, non_zero_runs, runs, curr_run, run_map = ([], [], [], [], []) - curr_buck = get_bucket(data[0], step) - run_idx = 0 - - for idx, point in enumerate(data): - new_buck = get_bucket(point, step) - if new_buck == curr_buck: - curr_run.append(idx) - else: - # Plotting the end of a run - if DEBUG: - plt.axvline(x=idx) - - # Three points make a curve! - if len(curr_run) > 2: - runs.append(curr_run) - run_idx += 1 - if curr_buck == 0: - zero_runs.append(len(runs) - 1) - else: - non_zero_runs.append(curr_run) - - curr_run = [idx] - curr_buck = new_buck - - run_map.append(run_idx) - - # Effectively flushing the cache. There has to be a way to factor this out - if len(curr_run) > 2: - runs.append(curr_run) - if curr_buck == 0: - zero_runs.append(len(runs) - 1) - else: - non_zero_runs.append(curr_run) - - return [runs, zero_runs, non_zero_runs, run_map] - - -# A whole rigmarole to collapse multiple pedestals. -# It assumes that the pedestal is the bucket with the most elements -def adjust_data(data, step): - normalized_adjustment = 0 - - bucket_count = zeros(NUM_BUCKS) - bucket_contents = [[] for i in range(0, NUM_BUCKS)] - buckets = zeros(len(data)) - - for idx, element in enumerate(data): - bucket = get_bucket(element, step) - bucket_count[bucket] += 1 - bucket_contents[bucket] += [idx] - buckets[idx] = bucket - - zero_bucket = max(enumerate(bucket_count), key=itemgetter(1))[0] - - needs_adjustment = False - - for idx, bucket in enumerate(buckets): - if bucket < zero_bucket: - # Inefficient to set this every time, but eh - needs_adjustment = True - # Sets them arbitrarily to the value of the first element in the - # zero bucket, to eliminate the double pedestal - data[idx] = data[bucket_contents[zero_bucket][0]] - - if needs_adjustment: - normalized_adjustment = min(data[bucket_contents[zero_bucket]]) - data = data - normalized_adjustment - step = max(data) / NUM_BUCKS - - return [data, step, normalized_adjustment] - - -################################################################################ -# So this is a giant clusterfuck of logic where I try to autodetect peaks by -# detecting "runs" of points, defined as a group of 3 or more consecutive points -# that belong to the same bucket, while simultaneously tagging those runs that -# belong to the "zeroeth" bucket (the pedestal). -# -# Note that the format of the guess is a list of the form: -# [m, b, center_0, amplitude_0, width_0,..., center_k, amplitude_k, width_k] -# where m and b correspond to the line parameters in y = m*x + b -# and every following group of three corresponds to a gaussian -################################################################################ -def get_guess(xdata, ydata, step, use_zeros, num_peaks): - runs, zero_runs, non_zero_runs, run_map = get_runs(ydata, step) - - peaks, peak_idx, max_info = ( - get_peaks(ydata, num_peaks, non_zero_runs) - if not use_zeros - else get_peaks(ydata, num_peaks, runs) - ) - - # Gross error handling for the case where the max val isn't detected as a - # peak (making sure it's added to runs in the correct order) - if max_info: - max_idx = max_info[0] - if run_map[max_idx] >= len(runs): - runs.append(max_idx) - else: - runs[run_map[max_idx]].append(max_idx) - - # This plots my guesses for the peaks - if DEBUG: - for idx in peak_idx: - plt.axvline(x=idx) - - # Should rethink widths calculation, it's usually about 1/5 of acutal, - # which means the algorithm needs more iterations to get closer. - widths = find_widths(xdata, peak_idx, runs, run_map) - - guess = find_line(zero_runs, runs, xdata, ydata) - - # This plots my guess for the line - if DEBUG: - plt.plot([guess[0] * j + guess[1] for j in xdata], "--") - - for idx, amp in enumerate(peaks): - guess += [xdata[peak_idx[idx]], amp, widths[idx] / 4] - - # Plot my initial guesses for the gaussian(s) - if DEBUG: - plt.plot( - [ - gaussian(i, xdata[peak_idx[idx]], widths[idx] / 4, amp) - for i in xdata - ], - "--", - ) - - return [guess, len(runs) if use_zeros else len(non_zero_runs)] - - -def process_data(data): - first_adjustment = min(data) - - # Removing the pedestal - data = data - first_adjustment - - # Define the step size by the number of vertical buckets - step = max(data) / NUM_BUCKS - - data, step, normalized_adjustment = adjust_data(data, step) - - # This prints my vertical buckets - if DEBUG: - for i in range(1, NUM_BUCKS): - plt.plot([i * step for _ in range(0, len(data))]) - - total_adjustment = first_adjustment + normalized_adjustment - - return [data, total_adjustment, step] - - -def get_fit(data, x, guess): - # Someday the ability to bound the fit will be available... - # ...When we're no longer running builds from 2013 :P - return curve_fit(gen_gauss_sum, x, data, p0=guess)[0] diff --git a/lcls_tools/common/devices/profile_monitor.py b/lcls_tools/common/devices/profile_monitor.py deleted file mode 100644 index 0a12d3c3..00000000 --- a/lcls_tools/common/devices/profile_monitor.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/local/lcls/package/python/current/bin/python - -from epics import PV -import lcls_tools.common.devices.profmon_constants as pc -from time import sleep -from threading import Thread -from numpy import array_equal - - -# Implementation needs to be thought out, just a POC - - -def get_profile_monitors(): - """Return MAD names of all profile monitors that have models""" - return sorted(pc.PROFS.keys()) - - -class ProfMon(object): - """Generic Profile Monitor Object Class that references profile monitor MAD name""" - - def __init__(self, prof_name="OTR02"): - if prof_name not in pc.PROFS.keys(): - raise ValueError("You have not specified a valid profile monitor") - prof_dict = pc.PROFS[prof_name] - self._prof_name = prof_name - self._prof_set = PV(prof_dict["set"]) - self._prof_get = PV(prof_dict["get"]) - self._prof_image = PV(prof_dict["image"]) - self._prof_res = PV(prof_dict["res"]) - self._x_size = PV(prof_dict["xsize"]) - self._y_size = PV(prof_dict["ysize"]) - self._rate = PV(prof_dict["rate"]) - self._images = [] - self._data_thread = None - self._gathering_data = False - self._get_vars = self._prof_get.get_ctrlvars()["enum_strs"] - self._set_vars = self._prof_set.get_ctrlvars()["enum_strs"] - self._motion_state = self._get_vars[self._prof_get.get()] - self._prof_get.add_callback(self._state_clbk, index=1) - self._insert_clbk = None - self._extract_clbk = None - - def _state_clbk(self, pvName=None, value=None, char_value=None, **kw): - """Keep track of position/motion state""" - self._motion_state = self._get_vars[value] - - @property - def prof_name(self): - """Get the profile monitor MAD name""" - return self._prof_name - - @property - def cur_image(self): - """Get the current image array""" - return self._prof_image.get() - - @property - def saved_images(self): - """Get the images collected""" - return self._images - - @property - def resolution(self): - """Get the resolution""" - return self._prof_res.get() - - @property - def arr_dims(self): - """Get the x and y dimensions""" - return (self._x_size.get(), self._y_size.get()) - - @property - def rate(self): - """Get the current rate""" - return self._rate.get() - - @property - def motion_state(self): - """Get the current motion state of the profile monitor""" - return self._motion_state - - @property - def state(self): - """Get the overall state of the profile monitor""" - return self.__dict__ - - def insert(self, user_clbk=None): - """Generic call to insert profile monitor, can specify callback to be run""" - if self._motion_state == pc.IN: - print("{0}: {1}".format(self._prof_name, pc.ALREADY_INSERTED)) - return - - if user_clbk: - self._insert_clbk = user_clbk - - self._prof_get.add_callback(self._inserted, index=0) - self._prof_set.put(pc.IN) - - def _inserted(self, pv_name=None, value=None, char_value=None, **kw): - """Generic callback after profile monitor has been inserted, default""" - if self._get_vars[value] == pc.IN: - print("{0}: {1}".format(self._prof_name, pc.INSERTED)) - - if self._insert_clbk: - self._insert_clbk() - self._insert_clbk = None - - self._prof_get.remove_callback(index=0) - - def extract(self, usr_clbk=None): - """Extract profile monitor command, can specify callback to be run""" - if self._motion_state == pc.OUT: - print("{0}: {1}".format(self._prof_name, pc.ALREADY_EXTRACTED)) - return - - if usr_clbk: - self._extract_clbk = usr_clbk - - self._prof_get.add_callback(self._extracted, index=0) - self._prof_set.put(pc.OUT) - - def _extracted(self, pv_name=None, value=None, char_value=None, **kw): - """Generic Callback for profile monitor that has been extracted, default""" - if self._get_vars[value] == pc.OUT: - print("{0}: {1}".format(self._prof_name, pc.EXTRACTED)) - - if self._extract_clbk: - self._extract_clbk() - self._extract_clbk = None - - self._prof_get.remove_callback(index=0) - - def acquire_images(self, images=1): - """Start the thread""" - self._data_thread = Thread(target=self._collect_image_data, args=(images,)) - self._data_thread.start() - - def _collect_image_data(self, images, callback): - """Threaded data collection""" - self._gathering_data = True - delay = 1.0 / self._rate.get() # Rate must be in Hz - i = 0 - while i < images: - image = self._prof_image.get() - if len(self._images) > 0 and array_equal(image, self._images[-1]): - sleep(0.01) - else: - self._images.append(image) - sleep(delay) - i += 1 - if callback: - # Would want this to be pyqtSignal or Event notification type thing - callback() - self._gathering_data = False - return # No join, waste of a function diff --git a/lcls_tools/common/devices/profmon_constants.py b/lcls_tools/common/devices/profmon_constants.py deleted file mode 100644 index fd634697..00000000 --- a/lcls_tools/common/devices/profmon_constants.py +++ /dev/null @@ -1,57 +0,0 @@ -# There are likely redundancy issues and can be -# optimized further, this is just a POC. A Database would be nice -# to reference as this is Database schema - -# TODO: Make this a .yaml file for cleanliness and -# cross language reference if needed - -# Error Strings -ALREADY_INSERTED = "Profile Monitor is already inserted" -ALREADY_EXTRACTED = "Profile Monitor is already extracted" - -# Completed Action Strings -INSERTED = "Profile Monitor has been inserted" -EXTRACTED = "Profile Monitor has been extracted" - -# Profile Monitor State -IN = "IN" -OUT = "OUT" - -############# LCLS Profile Monitor ########### - - -def create_profmon_dict(base): - profmon_dict = { - "set": base + ":PNEUMATIC", - "get": base + ":TGT_STS", - "image": base + ":IMAGE", - "res": base + ":RESOLUTION", - "xsize": base + ":N_OF_COL", - "ysize": base + ":N_OF_ROW", - "rate": base + ":FRAME_RATE", - } - - return profmon_dict - - -# ROI_BITS, ROI_X/YBIN??? -def create_profmon2_dict(base): - profmon_dict = { - "set": base + ":PNEUMATIC", - "get": base + ":TGT_STS", - "image": base + ":Image:ArrayData", - "res": base + ":RESOLUTION", - "xsize": base + ":ArraySizeX_RBV", - "ysize": base + ":ArraySizeY_RBV", - "rate": base + ":FRAME_RATE", - } - - return profmon_dict - - -YAG01 = create_profmon_dict("YAGS:IN20:211") -OTR02 = create_profmon_dict("OTRS:IN20:571") -YAG01B = create_profmon2_dict("YAGS:GUNB:753") - -# Dict of Profile Monitors -PROFS = {"YAG01B": YAG01B, "YAG01": YAG01, "OTR02": OTR02} diff --git a/lcls_tools/common/devices/screen.py b/lcls_tools/common/devices/screen.py index b1a35671..868f00d6 100644 --- a/lcls_tools/common/devices/screen.py +++ b/lcls_tools/common/devices/screen.py @@ -77,7 +77,7 @@ def image(self) -> np.ndarray: @property def image_timestamp(self): - """get last timestamp for last PV activity""" + """Get last timestamp for last PV activity""" return self.controls_information.PVs.image.timestamp @property @@ -123,6 +123,10 @@ def last_save_filepath(self): """Location and filename for the last file saved by this screen (set in save_images())""" return self._last_save_filepath + def _inserted_check(): + """Check if the screen is inserted""" + return NotImplementedError + def _generate_new_filename(self, extension: Optional[str] = ".h5") -> str: """ Make a new filename for the HDF5 image file diff --git a/lcls_tools/common/image_processing/image_processing.py b/lcls_tools/common/image_processing/image_processing.py index 6f1e1ac7..dc5f810b 100644 --- a/lcls_tools/common/image_processing/image_processing.py +++ b/lcls_tools/common/image_processing/image_processing.py @@ -1,8 +1,5 @@ import numpy as np import scipy.ndimage as snd -from scipy import asarray -import matplotlib.pyplot as plt -import lcls_tools.common.data_analysis.fitting.fit_gaussian as fg def fliplr(image): @@ -46,22 +43,3 @@ def y_projection(image, subtract_baseline=True): return proj - min(proj) return proj - - -def gauss_func(x, a, x0, sigma): - return a * np.exp(-((x - x0) ** 2) / (2 * sigma**2)) - - -def gauss_fit(projection, plot=False): - x = asarray(range(len(projection))) - data, _, step = fg.process_data(projection) - guess = fg.get_guess(x, data, step, False, num_peaks=1)[0] - x0_x, a_x, sigma_x = fg.get_fit(data, x, guess)[2:] - - if plot: - plt.plot(x, projection, label="data") - plt.plot(x, gauss_func(x, a_x, x0_x, sigma_x), label="fit") - plt.legend() - plt.show() - - return x, a_x, x0_x, sigma_x diff --git a/lcls_tools/common/matlab2py/cor_plot/__init__.py b/lcls_tools/common/matlab2py/cor_plot/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/lcls_tools/common/matlab2py/cor_plot/cor_plot_mat_scan.py b/lcls_tools/common/matlab2py/corr_plot_mat_scan.py similarity index 100% rename from lcls_tools/common/matlab2py/cor_plot/cor_plot_mat_scan.py rename to lcls_tools/common/matlab2py/corr_plot_mat_scan.py diff --git a/lcls_tools/common/matlab2py/emit_scan/.gitattributes b/lcls_tools/common/matlab2py/emit_scan/.gitattributes deleted file mode 100644 index e4f9da3f..00000000 --- a/lcls_tools/common/matlab2py/emit_scan/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -test_scan.mat filter=lfs diff=lfs merge=lfs -text diff --git a/lcls_tools/common/matlab2py/emit_scan/__init__.py b/lcls_tools/common/matlab2py/emit_scan/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/lcls_tools/common/matlab2py/emit_scan/mat_emit_scan.py b/lcls_tools/common/matlab2py/mat_emit_scan.py similarity index 100% rename from lcls_tools/common/matlab2py/emit_scan/mat_emit_scan.py rename to lcls_tools/common/matlab2py/mat_emit_scan.py diff --git a/lcls_tools/common/matlab2py/image/mat_image.py b/lcls_tools/common/matlab2py/mat_image.py similarity index 100% rename from lcls_tools/common/matlab2py/image/mat_image.py rename to lcls_tools/common/matlab2py/mat_image.py diff --git a/requirements.txt b/requirements.txt index 84501ee1..4e917658 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,4 +7,8 @@ pyyaml requests pydantic h5py -scikit-learn \ No newline at end of file +sphinx +sphinx_rtd_theme +myst_parser +scikit-learn + diff --git a/tests/unit_tests/lcls_tools/common/data_analysis/fitting/__init__.py b/tests/unit_tests/lcls_tools/common/data_analysis/fitting/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit_tests/lcls_tools/common/data_analysis/fitting/test_fit_gaussian.py b/tests/unit_tests/lcls_tools/common/data_analysis/fitting/test_fit_gaussian.py deleted file mode 100644 index 44d7b7e9..00000000 --- a/tests/unit_tests/lcls_tools/common/data_analysis/fitting/test_fit_gaussian.py +++ /dev/null @@ -1,29 +0,0 @@ -from lcls_tools.common.data_analysis.fitting import fit_gaussian -import unittest - - -class TestFitGaussian(unittest.TestCase): - def setUp(self) -> None: - """Add objects that you want to use/setup per-test-case""" - return super().setUp() - - def tearDown(self) -> None: - """Add instructions for removing objects after each test case""" - return super().tearDown() - - def test_get_bucket_returns_nine_if_value_over_step_equal_to_ten(self): - """Checks that 9 is returned if the value/step greater than or equal to 10.""" - result = fit_gaussian.get_bucket(10, 1) - self.assertIsInstance(result, int) - self.assertEqual(result, 9) - - def test_get_bucket_returns_bucket_if_value_over_step_less_than_ten(self): - """Checks that val/step is returned if the value/step less than 10.""" - result = fit_gaussian.get_bucket(10, 2) - self.assertIsInstance(result, int) - self.assertEqual(result, 5) - - def test_get_bucket_returns_floor_of_value_over_step_when_less_than_10(self): - result = fit_gaussian.get_bucket(9.9, 1.5) - self.assertIsInstance(result, int) - self.assertEqual(result, 6) diff --git a/tests/unit_tests/lcls_tools/common/devices/test_constants.py b/tests/unit_tests/lcls_tools/common/devices/test_constants.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit_tests/lcls_tools/common/devices/test_profile_monitor.py b/tests/unit_tests/lcls_tools/common/devices/test_profile_monitor.py deleted file mode 100644 index dfb5bef5..00000000 --- a/tests/unit_tests/lcls_tools/common/devices/test_profile_monitor.py +++ /dev/null @@ -1,91 +0,0 @@ -# Built in -from unittest import mock, TestCase -import inspect - -# Local imports -import lcls_tools.common.devices.profmon_constants as pc -from lcls_tools.common.devices.profile_monitor import ( - ProfMon, - get_profile_monitors, -) - - -PROF = { - "set": "test:PNEUMATIC", - "get": "test:TGT_STS", - "image": "test:IMAGE", - "res": "test:RESOLUTION", - "xsize": "test:N_OF_COL", - "ysize": "test:N_OF_ROW", - "rate": "test:FRAME_RATE", -} - -PROF2 = { - "set": "test:PNEUMATIC", - "get": "test:TGT_STS", - "image": "test:Image:ArrayData", - "res": "test:RESOLUTION", - "xsize": "test:ArraySizeX_RBV", - "ysize": "test:ArraySizeY_RBV", - "rate": "test:FRAME_RATE", -} - -PROFS = ["OTR02", "YAG01B", "YAG01"] - - -class ProfileMonitorTest(TestCase): - ############ Constants ############ - - def test_create_profmon_dict(self): - """Typical LCLS style PV naming convention""" - self.assertEqual(pc.create_profmon_dict("test"), PROF) - - def test_create_profmon2_dict(self): - """New LCLS2 style PV naming convention""" - self.assertEqual(pc.create_profmon2_dict("test"), PROF2) - - def test_get_profile_monitors(self): - """To verify we haven't added any profs""" - self.assertEqual(get_profile_monitors(), sorted(PROFS)) - - ############# Object ############## - @mock.patch("epics.PV.get", new_callable=mock.Mock) - @mock.patch("epics.PV.get_ctrlvars", new_callable=mock.Mock) - def test_properties(self, mock_get_ctrl_vars, mock_pv_get): - """Test that all the properties we expect exist""" - mock_get_ctrl_vars.return_value = {"enum_strs": ["IN"]} - mock_pv_get.return_value = 0 - p = ProfMon() - self.assertEqual(isinstance(type(p).prof_name, property), True) - self.assertEqual(isinstance(type(p).cur_image, property), True) - self.assertEqual(isinstance(type(p).saved_images, property), True) - self.assertEqual(isinstance(type(p).resolution, property), True) - self.assertEqual(isinstance(type(p).arr_dims, property), True) - self.assertEqual(isinstance(type(p).rate, property), True) - self.assertEqual(isinstance(type(p).motion_state, property), True) - self.assertEqual(isinstance(type(p).state, property), True) - - @mock.patch("epics.PV.get", new_callable=mock.Mock) - @mock.patch("epics.PV.get_ctrlvars", new_callable=mock.Mock) - def test_methods(self, mock_get_ctrl_vars, mock_pv_get): - """Test that all the methods we expect exist""" - mock_get_ctrl_vars.return_value = {"enum_strs": ["IN"]} - mock_pv_get.return_value = 0 - p = ProfMon() - self.assertEqual(inspect.ismethod(p.insert), True) - self.assertEqual(inspect.ismethod(p._inserted), True) - self.assertEqual(inspect.ismethod(p.extract), True) - self.assertEqual(inspect.ismethod(p._extracted), True) - self.assertEqual(inspect.ismethod(p.acquire_images), True) - self.assertEqual(inspect.ismethod(p._collect_image_data), True) - - @mock.patch("epics.PV.get", new_callable=mock.Mock) - @mock.patch("epics.PV.get_ctrlvars", new_callable=mock.Mock) - def test_name(self, mock_get_ctrl_vars, mock_pv_get): - """Test that we get default name and can hand name in init arg""" - mock_get_ctrl_vars.return_value = {"enum_strs": ["IN"]} - mock_pv_get.return_value = 0 - p = ProfMon() - self.assertEqual(p.prof_name, "OTR02") - p = ProfMon("YAG01") - self.assertEqual(p.prof_name, "YAG01") diff --git a/tests/unit_tests/lcls_tools/common/image_processing/test_image_processing.py b/tests/unit_tests/lcls_tools/common/image_processing/test_image_processing.py index b453b945..5f6b8e57 100644 --- a/tests/unit_tests/lcls_tools/common/image_processing/test_image_processing.py +++ b/tests/unit_tests/lcls_tools/common/image_processing/test_image_processing.py @@ -2,7 +2,7 @@ import os import numpy as np import lcls_tools.common.image_processing as ip -from lcls_tools.common.matlab2py.image.mat_image import MatImage +from lcls_tools.common.matlab2py.mat_image import MatImage CAMERA = "CAMR:LGUN:210" diff --git a/tests/unit_tests/lcls_tools/common/matlab2py/cor_plot/__init__.py b/tests/unit_tests/lcls_tools/common/matlab2py/cor_plot/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit_tests/lcls_tools/common/matlab2py/emit_scan/__init__.py b/tests/unit_tests/lcls_tools/common/matlab2py/emit_scan/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit_tests/lcls_tools/common/matlab2py/image/__init__.py b/tests/unit_tests/lcls_tools/common/matlab2py/image/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/unit_tests/lcls_tools/common/matlab2py/cor_plot/test_cor_plot_mat_scan.py b/tests/unit_tests/lcls_tools/common/matlab2py/test_corr_plot_mat_scan.py similarity index 97% rename from tests/unit_tests/lcls_tools/common/matlab2py/cor_plot/test_cor_plot_mat_scan.py rename to tests/unit_tests/lcls_tools/common/matlab2py/test_corr_plot_mat_scan.py index 6cee1f41..419dad36 100644 --- a/tests/unit_tests/lcls_tools/common/matlab2py/cor_plot/test_cor_plot_mat_scan.py +++ b/tests/unit_tests/lcls_tools/common/matlab2py/test_corr_plot_mat_scan.py @@ -1,6 +1,6 @@ import os import unittest -from lcls_tools.common.matlab2py.cor_plot.cor_plot_mat_scan import ( +from lcls_tools.common.matlab2py.corr_plot_mat_scan import ( CorPlotMatScan as CPMS, ) diff --git a/tests/unit_tests/lcls_tools/common/matlab2py/emit_scan/test_mat_emit_scan.py b/tests/unit_tests/lcls_tools/common/matlab2py/test_mat_emit_scan.py similarity index 96% rename from tests/unit_tests/lcls_tools/common/matlab2py/emit_scan/test_mat_emit_scan.py rename to tests/unit_tests/lcls_tools/common/matlab2py/test_mat_emit_scan.py index b62023dd..59d3d5de 100644 --- a/tests/unit_tests/lcls_tools/common/matlab2py/emit_scan/test_mat_emit_scan.py +++ b/tests/unit_tests/lcls_tools/common/matlab2py/test_mat_emit_scan.py @@ -1,6 +1,6 @@ import os import unittest -from lcls_tools.common.matlab2py.emit_scan.mat_emit_scan import MatEmitScan as MES +from lcls_tools.common.matlab2py.mat_emit_scan import MatEmitScan as MES ITERS = 3 diff --git a/tests/unit_tests/lcls_tools/common/matlab2py/image/test_mat_image.py b/tests/unit_tests/lcls_tools/common/matlab2py/test_mat_image.py similarity index 98% rename from tests/unit_tests/lcls_tools/common/matlab2py/image/test_mat_image.py rename to tests/unit_tests/lcls_tools/common/matlab2py/test_mat_image.py index 344bb73c..b838c9ee 100644 --- a/tests/unit_tests/lcls_tools/common/matlab2py/image/test_mat_image.py +++ b/tests/unit_tests/lcls_tools/common/matlab2py/test_mat_image.py @@ -1,7 +1,7 @@ import unittest import numpy as np import os -from lcls_tools.common.matlab2py.image.mat_image import MatImage as MI +from lcls_tools.common.matlab2py.mat_image import MatImage as MI class MatImageTest(unittest.TestCase):