Skip to content

Commit be78d92

Browse files
Merge pull request SarthakJariwala#19 from SarthakJariwala/development
Improvements to Lifetime Analysis Code
2 parents fc88ae7 + ee8b496 commit be78d92

File tree

6 files changed

+222
-185
lines changed

6 files changed

+222
-185
lines changed

PythonGUI_apps/DataBrowser.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,10 @@ def load_app(self):
8585

8686

8787
def run():
88+
app = QtGui.QApplication(sys.argv)#.instance()
89+
app.setStyle("Fusion")
8890
win = MainWindow()
89-
QtGui.QApplication.instance().exec_()
91+
sys.exit(app.exec_())
9092
return
9193

9294
run()

PythonGUI_apps/Lifetime_analysis/Fit_functions.py

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
from scipy.optimize import differential_evolution
1010
from scipy.special import gamma
1111

12-
def stretch_exp_fit(TRPL, t, Tc = (0,1e5), Beta = (0,1), A = (0,1e6)):
12+
def stretch_exp_fit(TRPL, t, Tc = (0,1e5), Beta = (0,1), A = (0,1e6), noise=(0,1e6)):
1313

14-
def exp_stretch(t, tc, beta, a):
15-
return (a * np.exp(-((1.0 / tc) * t) ** beta))
14+
def exp_stretch(t, tc, beta, a, noise):
15+
return ((a * np.exp(-((1.0 / tc) * t) ** beta)) + noise)
1616

1717
def avg_tau_from_exp_stretch(tc, beta):
1818
return (tc / beta) * gamma(1.0 / beta)
@@ -25,13 +25,14 @@ def residuals(params):#params are the parameters to be adjusted by differential
2525
tc = params[0]
2626
beta = params[1]
2727
a = params[2]
28+
noise = params[3]
2829

29-
PL_sim = exp_stretch(t,tc,beta,a)
30+
PL_sim = exp_stretch(t,tc,beta,a, noise)
3031

31-
Resid= np.sqrt(np.sum(((PL_sim-TRPL)**2)/(np.sqrt(PL_sim)**2)))
32+
Resid= np.sum(((PL_sim-TRPL)**2)/(np.sqrt(TRPL)**2))
3233
return Resid #returns the difference between the PL data and simulated data
3334

34-
bounds = [Tc, Beta, A]
35+
bounds = [Tc, Beta, A, noise]
3536

3637
result = differential_evolution(residuals, bounds)
3738
return result.x
@@ -41,20 +42,21 @@ def residuals(params):#params are the parameters to be adjusted by differential
4142
tc = p[0]
4243
beta = p[1]
4344
a = p[2]
45+
noise = p[3]
4446

45-
PL_fit = exp_stretch(t,tc,beta,a)
47+
PL_fit = exp_stretch(t,tc,beta,a, noise)
4648

4749
avg_tau = avg_tau_from_exp_stretch(tc,beta)
4850

49-
return tc, beta, a, avg_tau, PL_fit
51+
return tc, beta, a, avg_tau, PL_fit, noise
5052

51-
def double_exp_fit(TRPL, t, tau1_bounds=(0,100), a1_bounds=(0,1e5), tau2_bounds=(0,100), a2_bounds=(0,1e5)):
53+
def double_exp_fit(TRPL, t, tau1_bounds=(0,1000), a1_bounds=(0,1e6), tau2_bounds=(0,10000), a2_bounds=(0,1e5), noise=(0,1e6)):
5254

5355
def single_exp(t, tau, a):
54-
return (a * np.exp(-((1.0 / tau)*t) ))
56+
return (a * np.exp(-((1.0 / tau)*t)))
5557

56-
def double_exp(t, tau1, a1, tau2, a2):
57-
return ((single_exp(t, tau1, a1)) + (single_exp(t, tau2, a2)))
58+
def double_exp(t, tau1, a1, tau2, a2, noise):
59+
return ((single_exp(t, tau1, a1)) + (single_exp(t, tau2, a2)) + noise)
5860

5961
def avg_tau_from_double_exp(tau1, a1, tau2, a2):
6062
return (((tau1*a1) + (tau2*a2))/(a1+a2))
@@ -68,13 +70,14 @@ def residuals(params):#params are the parameters to be adjusted by differential
6870
a1 = params[1]
6971
tau2 = params[2]
7072
a2 = params[3]
73+
noise = params[4]
7174

72-
PL_sim = double_exp(t,tau1, a1, tau2, a2)
75+
PL_sim = double_exp(t,tau1, a1, tau2, a2, noise)
7376

74-
Resid= np.sqrt(np.sum(((PL_sim-TRPL)**2)/(np.sqrt(PL_sim)**2)))
77+
Resid= np.sum(((PL_sim-TRPL)**2)/(np.sqrt(TRPL)**2))
7578
return Resid #returns the difference between the PL data and simulated data
7679

77-
bounds = [tau1_bounds, a1_bounds, tau2_bounds, a2_bounds]
80+
bounds = [tau1_bounds, a1_bounds, tau2_bounds, a2_bounds, noise]
7881

7982
result = differential_evolution(residuals, bounds)
8083
return result.x
@@ -85,17 +88,18 @@ def residuals(params):#params are the parameters to be adjusted by differential
8588
a1 = p[1]
8689
tau2 = p[2]
8790
a2 = p[3]
91+
noise = p[4]
8892

89-
PL_fit = double_exp(t, tau1, a1, tau2, a2)
93+
PL_fit = double_exp(t, tau1, a1, tau2, a2, noise)
9094

9195
avg_tau = avg_tau_from_double_exp(tau1, a1, tau2, a2)
9296

93-
return tau1, a1, tau2, a2, avg_tau, PL_fit
97+
return tau1, a1, tau2, a2, avg_tau, PL_fit, noise
9498

95-
def single_exp_fit(TRPL, t, tau_bounds=(0,1000), a_bounds=(0,1e5)):
99+
def single_exp_fit(TRPL, t, tau_bounds=(0,10000), a_bounds=(0,1e6), noise=(0,1e6)):
96100

97-
def single_exp(t, tau, a):
98-
return (a * np.exp(-((1.0 / tau)*t) ))
101+
def single_exp(t, tau, a, noise):
102+
return (a * np.exp(-((1.0 / tau)*t) ) + noise)
99103

100104
def Diff_Ev_Fit_singleExp(TRPL):
101105
TRPL = TRPL
@@ -104,13 +108,14 @@ def residuals(params):#params are the parameters to be adjusted by differential
104108
#Variable Rates
105109
tau = params[0]
106110
a = params[1]
111+
noise = params[2]
107112

108-
PL_sim = single_exp(t, tau, a)
113+
PL_sim = single_exp(t, tau, a, noise)
109114

110-
Resid= np.sqrt(np.sum(((PL_sim-TRPL)**2)/(np.sqrt(PL_sim)**2)))
115+
Resid= np.sum(((PL_sim-TRPL)**2)/(np.sqrt(TRPL)**2))
111116
return Resid #returns the difference between the PL data and simulated data
112117

113-
bounds = [tau_bounds, a_bounds]
118+
bounds = [tau_bounds, a_bounds, noise]
114119

115120
result = differential_evolution(residuals, bounds)
116121
return result.x
@@ -119,8 +124,9 @@ def residuals(params):#params are the parameters to be adjusted by differential
119124

120125
tau = p[0]
121126
a = p[1]
127+
noise = p[2]
122128

123-
PL_fit = single_exp(t, tau, a)
129+
PL_fit = single_exp(t, tau, a, noise)
124130

125-
return tau, a, PL_fit
131+
return tau, a, PL_fit, noise
126132

PythonGUI_apps/Lifetime_analysis/Lifetime_plot_fit.py

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
# local module imports
2626
try:
2727
from Lifetime_analysis.Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit
28-
from Lifetime_analysis.picoharp_phd import read_picoharp_phd
28+
from Lifetime_analysis.read_ph_phd import read_picoharp_phd
2929
from Lifetime_analysis.Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc
3030
except:
3131
from Fit_functions import stretch_exp_fit, double_exp_fit, single_exp_fit
3232
from Fit_functions_with_irf import fit_exp_stretch_diffev, fit_exp_stretch_fmin_tnc, fit_multi_exp_diffev, fit_multi_exp_fmin_tnc
33-
from picoharp_phd import read_picoharp_phd
33+
from read_ph_phd import read_picoharp_phd
3434

3535
"""Recylce params for plotting"""
3636
plt.rc('xtick', labelsize = 20)
@@ -95,10 +95,12 @@ def __init__(self):
9595
self.file = None
9696
self.out = None # output file after fitting
9797
self.data_list = []
98-
self.fit_lifetime_called = False
98+
self.fit_lifetime_called_w_irf = False
99+
self.fit_lifetime_called_wo_irf = False
99100
self.x_mem = [] # containers for adding x data to memory
100101
self.y_mem = [] # containers for adding y data to memory
101102
self.best_fit_mem = [] # containers for adding best fit data to memory
103+
self.best_fit_mem_x = [] # containers for adding best fit data to memory
102104
self.legend = [] # containers for adding legend to memory
103105

104106
#variables accounting for data received from FLIM analysis
@@ -127,6 +129,10 @@ def open_with_skip_rows_window(self):
127129
skip_rows = self.skip_rows_window.ui.skip_rows_spinBox.value()
128130
if ".txt" in self.filename[0]:
129131
self.file = np.loadtxt(self.filename[0], skiprows=skip_rows)
132+
133+
if self.file.ndim == 1: # if there is only one trace, reshape to 2D
134+
self.file = self.file.reshape(self.file.shape[0], 1)
135+
130136
elif ".csv" in self.filename[0]:
131137
self.file = np.genfromtxt(self.filename[0], skip_header=skip_rows, delimiter=",")
132138

@@ -147,6 +153,10 @@ def open_irf_with_skip_rows_window(self):
147153
irf_skip_rows = self.irf_skip_rows_window.ui.skip_rows_spinBox.value()
148154
if ".txt" in self.irf_filename[0]:
149155
self.irf_file = np.loadtxt(self.irf_filename[0], skiprows=irf_skip_rows)
156+
157+
if self.irf_file.ndim == 1: # if there is only one trace, reshape to 2d array
158+
self.irf_file = self.irf_file.reshape(self.irf_file.shape[0], 1)
159+
150160
elif ".csv" in self.irf_filename[0]:
151161
self.irf_file = np.genfrontxt(self.irf_filename[0], skip_header=irf_skip_rows, delimiter=",")
152162

@@ -258,7 +268,8 @@ def plot(self):
258268
x,y = self.acquire_settings() #get data
259269

260270
self.ui.plot.plot(x, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color))
261-
self.fit_lifetime_called = False
271+
self.fit_lifetime_called_w_irf = False
272+
self.fit_lifetime_called_wo_irf = False
262273

263274
try:
264275
self.ui.Result_textBrowser.setText("Integral Counts :\n" "{:.2E}".format(
@@ -303,7 +314,7 @@ def fit_and_plot(self):
303314
self.ui.plot.plot(t, y, clear=self.ui.clear_plot_checkBox.isChecked(), pen=pg.mkPen(self.plot_color))
304315

305316
if fit_func == "Stretched Exponential": #stretch exponential tab
306-
tc, beta, a, avg_tau, PL_fit = stretch_exp_fit(TRPL_interp, t)
317+
tc, beta, a, avg_tau, PL_fit, noise = stretch_exp_fit(TRPL_interp, t)
307318
self.out = np.empty((len(t), 3))
308319
self.out[:,0] = t #time
309320
self.out[:,1] = TRPL_interp #Raw PL
@@ -313,11 +324,12 @@ def fit_and_plot(self):
313324
"\nFit Method: " + "diff_ev" + #TODO : change when diff_ev and fmin_tnc implemented for non-irf
314325
"\nAverage Lifetime = " + str(avg_tau)+ " ns"
315326
"\nCharacteristic Tau = " + str(tc)+" ns"
316-
"\nBeta = "+str(beta))
327+
"\nBeta = "+str(beta)+
328+
"\nNoise = "+ str(noise))
317329
self.ui.average_lifetime_spinBox.setValue(avg_tau)
318330

319331
elif fit_func == "Double Exponential": #double exponential tab
320-
tau1, a1, tau2, a2, avg_tau, PL_fit = double_exp_fit(TRPL_interp, t)
332+
tau1, a1, tau2, a2, avg_tau, PL_fit, noise = double_exp_fit(TRPL_interp, t)
321333
self.out = np.empty((len(t), 3))
322334
self.out[:,0] = t #time
323335
self.out[:,1] = TRPL_interp #Raw PL
@@ -329,11 +341,12 @@ def fit_and_plot(self):
329341
"\nTau 1 = " + str(tau1)+" ns"
330342
"\nA 1 = " + str(a1)+
331343
"\nTau 2 = " + str(tau2)+" ns"
332-
"\nA 2 = " + str(a2))
344+
"\nA 2 = " + str(a2)+
345+
"\nNoise = "+ str(noise))
333346
#TODO - once tau_avg implemented, set average lifetime spinbox to tau_avg value
334347

335348
elif fit_func == "Single Exponential": #single exponential tab
336-
tau, a, PL_fit = single_exp_fit(TRPL_interp, t)
349+
tau, a, PL_fit, noise = single_exp_fit(TRPL_interp, t)
337350
self.out = np.empty((len(t), 3))
338351
self.out[:,0] = t #time
339352
self.out[:,1] = TRPL_interp #Raw PL
@@ -342,12 +355,14 @@ def fit_and_plot(self):
342355
self.ui.Result_textBrowser.setText("Fit Results:\n\nFit Function: Single Exponential"
343356
"\nFit Method: " + "diff_ev" +
344357
"\nLifetime = " + str(tau)+ " ns"
345-
"\nA = " + str(a))
358+
"\nA = " + str(a)+
359+
"\nNoise = "+ str(noise))
346360
self.ui.average_lifetime_spinBox.setValue(tau)
347361

348362
#add fit params to data_list
349363
self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText())
350-
self.fit_lifetime_called = True
364+
self.fit_lifetime_called_wo_irf = True
365+
self.fit_lifetime_called_w_irf = False
351366

352367
self.ui.plot.setLabel('left', 'Intensity', units='a.u.')
353368
self.ui.plot.setLabel('bottom', 'Time (ns)')
@@ -475,7 +490,8 @@ def fit_and_plot_with_irf(self):
475490

476491
#add fit params to data_list
477492
self.data_list.append("Data Channel: " + str(self.ui.Data_channel_spinBox.value()) + "\n" + self.ui.Result_textBrowser.toPlainText())
478-
self.fit_lifetime_called = True
493+
self.fit_lifetime_called_w_irf = True
494+
self.fit_lifetime_called_wo_irf = False
479495
except Exception as e:
480496
self.ui.Result_textBrowser.append(format(e))
481497

@@ -548,12 +564,19 @@ def clean_up_after_fig_export(self):
548564
self.y_mem = []
549565
self.legend = []
550566
self.best_fit_mem = []
567+
self.best_fit_mem_x = []
551568

552569
def add_trace_to_mem(self):
553570
try:
554-
if self.fit_lifetime_called == True:
571+
if self.fit_lifetime_called_w_irf == True:
555572
self.x_mem.append(self.out[:,0])
556573
self.y_mem.append(self.out[:,1])
574+
self.best_fit_mem_x.append(self.out[:,0])
575+
self.best_fit_mem.append(self.out[:,2])
576+
elif self.fit_lifetime_called_wo_irf == True:
577+
self.x_mem.append(self.acquire_settings()[0])
578+
self.y_mem.append(self.acquire_settings()[1])
579+
self.best_fit_mem_x.append(self.out[:,0])
557580
self.best_fit_mem.append(self.out[:,2])
558581
else:
559582
self.x_mem.append(self.acquire_settings()[0])
@@ -578,8 +601,8 @@ def pub_ready_plot_export(self):
578601
plt.tick_params(direction='out', length=8, width=3.5)
579602
for i in range(len(self.x_mem)):
580603
plt.plot(self.x_mem[i], self.y_mem[i], label=str(self.legend[i]))
581-
if self.fit_lifetime_called == True:
582-
plt.plot(self.x_mem[i], self.best_fit_mem[i],'k--')
604+
if self.fit_lifetime_called_w_irf == True or self.fit_lifetime_called_wo_irf == True:
605+
plt.plot(self.best_fit_mem_x[i], self.best_fit_mem[i],'k--')
583606

584607
plt.yscale('log')
585608
plt.xlabel("Time (ns)", fontsize=20, fontweight='bold')

0 commit comments

Comments
 (0)