diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa96c50
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.class
+*.pyc
+*/__pycache__/*
+nb/PSSS/nbproject/private
+nb/PSSS/build
+nb/PSSS/dist
diff --git a/nb/PSSS/nbproject/private/config.properties b/nb/PSSS/nbproject/private/config.properties
deleted file mode 100644
index e69de29..0000000
diff --git a/nb/PSSS/nbproject/private/private.properties b/nb/PSSS/nbproject/private/private.properties
deleted file mode 100644
index ecf6f54..0000000
--- a/nb/PSSS/nbproject/private/private.properties
+++ /dev/null
@@ -1,8 +0,0 @@
-compile.on.save=true
-do.depend=false
-do.jar=true
-do.jlink=false
-javac.debug=true
-javadoc.preview=true
-jlink.strip=false
-user.properties.file=/afs/psi.ch/user/g/gobbo_a/.netbeans/12.2/build.properties
diff --git a/nb/PSSS/nbproject/private/private.xml b/nb/PSSS/nbproject/private/private.xml
deleted file mode 100644
index 4750962..0000000
--- a/nb/PSSS/nbproject/private/private.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/plugins/PSSS$1.class b/plugins/PSSS$1.class
deleted file mode 100644
index 71bd3a3..0000000
Binary files a/plugins/PSSS$1.class and /dev/null differ
diff --git a/plugins/PSSS$2.class b/plugins/PSSS$2.class
deleted file mode 100644
index 8b40abc..0000000
Binary files a/plugins/PSSS$2.class and /dev/null differ
diff --git a/plugins/PSSS$3.class b/plugins/PSSS$3.class
deleted file mode 100644
index 5d27748..0000000
Binary files a/plugins/PSSS$3.class and /dev/null differ
diff --git a/plugins/PSSS$4.class b/plugins/PSSS$4.class
deleted file mode 100644
index e19db9c..0000000
Binary files a/plugins/PSSS$4.class and /dev/null differ
diff --git a/plugins/PSSS$5.class b/plugins/PSSS$5.class
deleted file mode 100644
index bf4a464..0000000
Binary files a/plugins/PSSS$5.class and /dev/null differ
diff --git a/plugins/PSSS$6.class b/plugins/PSSS$6.class
deleted file mode 100644
index 50706c2..0000000
Binary files a/plugins/PSSS$6.class and /dev/null differ
diff --git a/plugins/PSSS$7.class b/plugins/PSSS$7.class
deleted file mode 100644
index 6735e76..0000000
Binary files a/plugins/PSSS$7.class and /dev/null differ
diff --git a/plugins/PSSS$8.class b/plugins/PSSS$8.class
deleted file mode 100644
index 682d694..0000000
Binary files a/plugins/PSSS$8.class and /dev/null differ
diff --git a/plugins/PSSS$9.class b/plugins/PSSS$9.class
deleted file mode 100644
index 14e14ee..0000000
Binary files a/plugins/PSSS$9.class and /dev/null differ
diff --git a/plugins/PSSS.class b/plugins/PSSS.class
deleted file mode 100644
index 54b4ad5..0000000
Binary files a/plugins/PSSS.class and /dev/null differ
diff --git a/script/cpython/psss.py b/script/cpython/psss.py
new file mode 100755
index 0000000..e5ce177
--- /dev/null
+++ b/script/cpython/psss.py
@@ -0,0 +1,45 @@
+import numpy as np
+from scipy.optimize import curve_fit
+import sys
+
+
+def gaus(x, a, x0, sigma, offset):
+ return offset + a * np.exp(-(x - x0) ** 2 / (2 * sigma ** 2))
+
+#Return [amp, mean_val, sigma, offset]
+def fit_energy(e_from, e_to, steps, num_shots, data):
+ energy_range = np.linspace(e_from, e_to, steps)
+ energy_range_fit = np.linspace(energy_range[0], energy_range[-1], len(energy_range)*10)
+ centre_line_out = data[:,:,int(data.shape[2]/2)].mean(axis=1)
+ try:
+ popt,pcov = curve_fit(gaus,energy_range,centre_line_out,p0=[1,energy_range[np.argmax(centre_line_out)],energy_range.mean()*1e-3,1e3*num_shots])
+ except:
+ raise Exception('Fit failed: spectrum might not be near scan range center \n' + str(sys.exc_info()[1]))
+ #print('Fit failed: spectrum might not be near scan range center')
+ #return None
+ max_ind = np.argmax(centre_line_out)
+ max_photon_energy=energy_range[max_ind]
+ print(max_photon_energy)
+ return popt, centre_line_out
+
+
+#Return [amp, mean_val, sigma, offset]
+def fit_crystal_height(xstal_from, xstal_to, steps, data):
+ xstal_range = np.linspace(xstal_from, xstal_to, steps)
+ projection = data.mean(axis=1).mean(axis=1)
+ offset = np.mean(projection[0:100])
+ signal_centre = xstal_range[np.argmax(projection)]
+ xstal_range_fit = np.linspace(xstal_range[0], xstal_range[-1], len(xstal_range)*10)
+ try:
+ popt,pcov = curve_fit(gaus,xstal_range,projection,p0=[100,signal_centre,-0.2,offset])
+ except:
+ raise Exception('Fit failed: spectrum might not be near scan range center \n' + str(sys.exc_info()[1]))
+ #print('Fit failed: spectrum might not be near scan range center')
+ #return None
+ return popt, projection
+
+
+def get_signal_centre(data, data_range):
+ projection = data.mean(axis=1).mean(axis=1)
+ signal_centre = data_range[np.argmax(projection)]
+ return signal_centre, projection
diff --git a/script/cpython/psss_plot.py b/script/cpython/psss_plot.py
new file mode 100755
index 0000000..27080e2
--- /dev/null
+++ b/script/cpython/psss_plot.py
@@ -0,0 +1,32 @@
+import numpy as np
+import matplotlib.pyplot as plt
+
+
+def gaus(x, a, x0, sigma, offset):
+ return offset + a * np.exp(-(x - x0) ** 2 / (2 * sigma ** 2))
+
+def plot_energy(E_from, E_to, steps, Scan_spec, popt, measured_offset):
+ Energy_range = np.linspace(E_from, E_to, steps)
+ centre_line_out = Scan_spec[:,:,int(Scan_spec.shape[2]/2)].mean(axis=1)
+ Energy_range_fit = np.linspace(Energy_range[0], Energy_range[-1], len(Energy_range)*10)
+
+
+ plt.figure(figsize=[10,5])
+ plt.subplot(121)
+ plt.title('PSSS scan of set photon energy')
+ plt.pcolormesh(np.arange(0,Scan_spec.shape[2]), Energy_range, Scan_spec.mean(axis=1),cmap='CMRmap')
+ plt.vlines(int(Scan_spec.shape[2]/2), Energy_range[0], Energy_range[-1],linestyles='--', colors='orange')
+ plt.xlim([0,Scan_spec.shape[2]])
+ plt.xlabel('Camera pixel')
+ plt.ylabel('Set PSSS energy [eV] \n SARFE10-PSSS059:ENERGY')
+
+ plt.subplot(122)
+ plt.title('At camera centre pixel %1i \nCalibrated energy = %.1f [eV]\n Offset from machine = %.1f [eV]'%(int(Scan_spec.shape[2]/2),popt[1],measured_offset))
+ plt.plot(centre_line_out,Energy_range,linewidth = 2, color = 'orange',label ='measured')
+ try:
+ plt.plot(gaus(Energy_range_fit,*popt),Energy_range_fit,'r:',label='fit')
+ except:
+ pass
+ plt.xticks([])
+ plt.legend()
+ plt.grid(True)
\ No newline at end of file
diff --git a/script/cpython/wrapper.py b/script/cpython/wrapper.py
new file mode 100755
index 0000000..5aa4031
--- /dev/null
+++ b/script/cpython/wrapper.py
@@ -0,0 +1,36 @@
+from jeputils import *
+
+RELOAD_CPYTHON = not App.isDetached()
+
+def fit_energy(e_from, e_to, steps, num_shots, data):
+ data = to_array(data, 'd')
+ dims = [len(data), len(data[0]), len(data[0][0])]
+ data = Convert.flatten(data)
+ arr = to_npa(data, dims)
+ popt, centre_line_out = call_jep("cpython/psss", "fit_energy", [e_from, e_to, steps, num_shots, arr], reload=RELOAD_CPYTHON)
+ return popt.getData(), centre_line_out.getData()
+
+def fit_crystal_height(xstal_from, xstal_to, steps, data):
+ data = to_array(data, 'd')
+ dims = [len(data), len(data[0]), len(data[0][0])]
+ data = Convert.flatten(data)
+ arr = to_npa(data, dims)
+ popt, projection = call_jep("cpython/psss", "fit_crystal_height", [xstal_from, xstal_to, steps, arr], reload=RELOAD_CPYTHON)
+ return popt.getData(), projection.getData()
+
+def get_signal_centre(data, data_range):
+ data = to_array(data, 'd')
+ dims = [len(data), len(data[0]), len(data[0][0])]
+ data = Convert.flatten(data)
+ arr = to_npa(data, dims)
+ data_range = to_npa(to_array(data_range, 'd'))
+ signal_centre, projection = call_jep("cpython/psss", "get_signal_centre", [arr, data_range], reload=RELOAD_CPYTHON)
+ return signal_centre, projection.getData()
+
+def plot_energy(e_from, e_to, steps, data, popt, measured_offset):
+ data = to_array(data, 'd')
+ dims = [len(data), len(data[0]), len(data[0][0])]
+ data = Convert.flatten(data)
+ arr = to_npa(data, dims)
+ ret = call_jep("cpython/psss_plot", "plot_energy", [e_from, e_to, steps, arr, popt, measured_offset], reload=RELOAD_CPYTHON)
+ return ret
diff --git a/script/local.py b/script/local.py
index 39306ed..6ce8712 100755
--- a/script/local.py
+++ b/script/local.py
@@ -2,6 +2,183 @@
# Deployment specific global definitions - executed after startup.py
###################################################################################################
+from mathutils import estimate_peak_indexes, fit_gaussians, create_fit_point_list
+from mathutils import fit_polynomial,fit_gaussian, fit_harmonic, calculate_peaks, fit_gaussian_offset
+from mathutils import PolynomialFunction, Gaussian, HarmonicOscillator, GaussianOffset
+from plotutils import plot_function, plot_data
+
+import java.awt.Color as Color
run("psss/psss")
+###################################################################################################
+# DRY RUN
+###################################################################################################
+def set_dry_run(value):
+ global dry_run
+ dry_run = value
+
+def is_dry_run():
+ if "dry_run" in globals():
+ return True if dry_run else False
+ return False
+
+
+###################################################################################################
+# Machine utilities
+###################################################################################################
+
+def is_laser_on():
+ return (caget ("SIN-TIMAST-TMA:Beam-Las-Delay-Sel",'d') == 0 )
+
+def is_timing_ok():
+ return caget("SIN-TIMAST-TMA:SOS-COUNT-CHECK") == 0
+
+def get_repetition_rate():
+ return caget("SIN-TIMAST-TMA:Evt-15-Freq-I")
+
+
+###################################################################################################
+# Shortcut to maths utilities
+###################################################################################################
+
+def gfit(ydata, xdata = None):
+ """
+ Gaussian fit
+ """
+ if xdata is None:
+ xdata = frange(0, len(ydata), 1)
+ #ydata = to_list(ydata)
+ #xdata = to_list(xdata)
+ max_y= max(ydata)
+ index_max = ydata.index(max_y)
+ max_x= xdata[index_max]
+ print "Max index:" + str(index_max),
+ print " x:" + str(max_x),
+ print " y:" + str(max_y)
+ gaussians = fit_gaussians(ydata, xdata, [index_max,])
+ (norm, mean, sigma) = gaussians[0]
+ p = plot([ydata],["data"],[xdata], title="Fit" )[0]
+ fitted_gaussian_function = Gaussian(norm, mean, sigma)
+ scale_x = [float(min(xdata)), float(max(xdata)) ]
+ points = max((len(xdata)+1), 100)
+ resolution = (scale_x[1]-scale_x[0]) / points
+ fit_y = []
+ fit_x = frange(scale_x[0],scale_x[1],resolution, True)
+ for x in fit_x:
+ fit_y.append(fitted_gaussian_function.value(x))
+ p.addSeries(LinePlotSeries("fit"))
+ p.getSeries(1).setData(fit_x, fit_y)
+
+ if abs(mean - xdata[index_max]) < ((scale_x[0] + scale_x[1])/2):
+ print "Mean -> " + str(mean)
+ p.addMarker(mean, None, "Mean="+str(round(norm,2)), Color.MAGENTA.darker())
+ return (norm, mean, sigma)
+ else:
+ p.addMarker(max_x, None, "Max="+str(round(max_x,2)), Color.GRAY)
+ print "Invalid gaussian fit: " + str(mean)
+ return (None, None, None)
+
+
+def hfit(ydata, xdata = None):
+ """
+ Harmonic fit
+ """
+ if xdata is None:
+ xdata = frange(0, len(ydata), 1)
+
+ max_y= max(ydata)
+ index_max = ydata.index(max_y)
+ max_x= xdata[index_max]
+
+ start,end = min(xdata), max(xdata)
+ (amplitude, angular_frequency, phase) = fit_harmonic(ydata, xdata)
+ fitted_harmonic_function = HarmonicOscillator(amplitude, angular_frequency, phase)
+
+ print "amplitude = ", amplitude
+ print "angular frequency = ", angular_frequency
+ print "phase = ", phase
+
+ f = angular_frequency/ (2* math.pi)
+ print "frequency = ", f
+
+ resolution = 4.00 # 1.00
+ fit_y = []
+ for x in frange(start,end,resolution, True):
+ fit_y.append(fitted_harmonic_function.value(x))
+ fit_x = frange(start, end+resolution, resolution)
+
+ p = plot(ydata,"data", xdata, title="HFit")[0]
+ p.addSeries(LinePlotSeries("fit"))
+ p.getSeries(1).setData(fit_x, fit_y)
+
+ #m = (phase + math.pi)/ angular_frequency
+ m = -phase / angular_frequency
+ if (m