mmanalysis 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mmanalysis/__init__.py +12 -0
- mmanalysis/cli/__init__.py +0 -0
- mmanalysis/cli/mmanalysis_cli.py +25 -0
- mmanalysis/core/__init__.py +0 -0
- mmanalysis/core/fits.py +419 -0
- mmanalysis/core/settings.py +36 -0
- mmanalysis/gui/__init__.py +0 -0
- mmanalysis/gui/mma_gui.py +139 -0
- mmanalysis/io/__init__.py +0 -0
- mmanalysis/io/importing.py +245 -0
- mmanalysis/main_analysis.py +192 -0
- mmanalysis/mmanalysis.py +414 -0
- mmanalysis/visualization/__init__.py +0 -0
- mmanalysis/visualization/plots.py +486 -0
- mmanalysis-0.0.1.dist-info/METADATA +92 -0
- mmanalysis-0.0.1.dist-info/RECORD +19 -0
- mmanalysis-0.0.1.dist-info/WHEEL +5 -0
- mmanalysis-0.0.1.dist-info/entry_points.txt +2 -0
- mmanalysis-0.0.1.dist-info/top_level.txt +1 -0
mmanalysis/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Created on Fri Nov 29 17:52:31 2024
|
|
5
|
+
|
|
6
|
+
@author: roncofaber
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
|
|
11
|
+
import mmanalysis
|
|
12
|
+
import mmanalysis.main_analysis
|
|
13
|
+
|
|
14
|
+
#%%
|
|
15
|
+
|
|
16
|
+
def main():
|
|
17
|
+
parser = argparse.ArgumentParser(description="Run MMAnalysis with specified parameters.")
|
|
18
|
+
parser.add_argument('-f', '--folder', type=str, default=None, help="Path to the folder to analyze.")
|
|
19
|
+
|
|
20
|
+
args = parser.parse_args()
|
|
21
|
+
|
|
22
|
+
mmanalysis.main_analysis.main(folder=args.folder)
|
|
23
|
+
|
|
24
|
+
if __name__ == "__main__":
|
|
25
|
+
main()
|
|
File without changes
|
mmanalysis/core/fits.py
ADDED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Wed Dec 21 16:54:01 2022
|
|
4
|
+
|
|
5
|
+
@author: Tim Kodalle
|
|
6
|
+
"""
|
|
7
|
+
import numpy as np
|
|
8
|
+
import os
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
from matplotlib import ticker
|
|
12
|
+
from scipy import signal
|
|
13
|
+
from tqdm import tqdm
|
|
14
|
+
from lmfit.models import LinearModel, PseudoVoigtModel
|
|
15
|
+
from scipy.optimize import curve_fit
|
|
16
|
+
import scipy.integrate as integrate
|
|
17
|
+
import traceback
|
|
18
|
+
|
|
19
|
+
#%%
|
|
20
|
+
#GIWAXS-Fitting
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def fit_single_frame(lowQ, highQ, q, intensity, frame_index, frames_to_plot, sampleName, outputPath):
|
|
24
|
+
|
|
25
|
+
x = q[lowQ:highQ]
|
|
26
|
+
y = intensity[frame_index, lowQ:highQ]
|
|
27
|
+
|
|
28
|
+
init_params = { # initial guess parameters
|
|
29
|
+
'amplitude' : max(y)/40, # default: 2
|
|
30
|
+
'center' : x[np.argmax(y)], # 1 (in angstrom-1)
|
|
31
|
+
'sigma' : 0.01, # 0.01
|
|
32
|
+
'fraction' : 0.5, # 0.5
|
|
33
|
+
'slope' : y[-1] - y[0],
|
|
34
|
+
'intercept' : 0 # 700
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# init_params = { # initial guess parameters
|
|
38
|
+
# 'amplitude' : max(y)/2, # default: 2
|
|
39
|
+
# 'center' : x[np.argmax(y)], # 1 (in angstrom-1)
|
|
40
|
+
# 'sigma' : 0.3, # 0.01
|
|
41
|
+
# 'fraction' : 0.5, # 0.5
|
|
42
|
+
# 'slope' : (y[-1] - y[0])/(x[-1] - x[0]),
|
|
43
|
+
# 'intercept' : y[0] - (y[-1] - y[0])/(x[-1] - x[0])*x[0] # 700
|
|
44
|
+
# }
|
|
45
|
+
|
|
46
|
+
# define fitting models (so far, one peak and a background function)
|
|
47
|
+
peak = PseudoVoigtModel()
|
|
48
|
+
background = LinearModel()
|
|
49
|
+
mod = peak + background
|
|
50
|
+
# initial values
|
|
51
|
+
pars = mod.make_params(amplitude = init_params['amplitude'],
|
|
52
|
+
center = init_params['center'],
|
|
53
|
+
sigma = init_params['sigma'],
|
|
54
|
+
fraction = init_params['fraction'],
|
|
55
|
+
slope = init_params['slope'],
|
|
56
|
+
intercept = init_params['intercept'])
|
|
57
|
+
# bounds
|
|
58
|
+
pars.add('center', value=init_params['center'], min=q[lowQ], max=q[highQ])
|
|
59
|
+
pars.add('amplitude', value=init_params['amplitude'])
|
|
60
|
+
mod.set_param_hint('amplitude', min=0)
|
|
61
|
+
mod.set_param_hint('center', min=q[lowQ], max=q[highQ])
|
|
62
|
+
mod.set_param_hint('sigma', max=0.01)
|
|
63
|
+
|
|
64
|
+
# determine if peak in data, promninence of 190 is chosen by hand, doesn't
|
|
65
|
+
# need to be ideal for every sample
|
|
66
|
+
peak_in_frame = False #initially false
|
|
67
|
+
peaks = signal.find_peaks(y)[0]
|
|
68
|
+
if len(peaks) > 0:
|
|
69
|
+
|
|
70
|
+
peak_in_frame = True
|
|
71
|
+
|
|
72
|
+
# fitting call
|
|
73
|
+
result = mod.fit(y, pars, x=x)
|
|
74
|
+
|
|
75
|
+
redchi = result.redchi
|
|
76
|
+
dely = result.eval_uncertainty(sigma=3)
|
|
77
|
+
params = []
|
|
78
|
+
std_error = []
|
|
79
|
+
|
|
80
|
+
for name, param in result.params.items():
|
|
81
|
+
params.append(param.value)
|
|
82
|
+
std_error.append(param.stderr)
|
|
83
|
+
if frame_index in frames_to_plot:
|
|
84
|
+
plt.figure(figsize=(7, 5))
|
|
85
|
+
plt.plot(x, y, 'o', label='intensity')
|
|
86
|
+
plt.plot(x[peaks], y[peaks], 'r.', label='found peak')
|
|
87
|
+
plt.plot(x, result.init_fit, '--', label='initial guess')
|
|
88
|
+
plt.plot(x, result.best_fit, '-', label='best fit')
|
|
89
|
+
plt.fill_between(x, result.best_fit-dely, result.best_fit+dely,
|
|
90
|
+
color='#ABABAB', label='3$\sigma$ - uncertainty band')
|
|
91
|
+
|
|
92
|
+
plt.xlabel(r'q $(\AA)$')
|
|
93
|
+
plt.ylabel(r'Intensity (au)')
|
|
94
|
+
# result.plot(data_kws={'markersize': 1})
|
|
95
|
+
plt.legend()
|
|
96
|
+
plt.title('Frame: ' + str(frame_index))
|
|
97
|
+
plt.savefig(os.path.join(outputPath + '/fits/', str(sampleName) + '_GIWAXS-fit_Frame_' + str(frame_index) + '.png'), format = 'png')
|
|
98
|
+
plt.show(block=False)
|
|
99
|
+
plt.pause(1)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
elif len(peaks) == 0:
|
|
103
|
+
if frame_index in frames_to_plot:
|
|
104
|
+
plt.figure(figsize=(7, 5))
|
|
105
|
+
plt.plot(x, y, 'o', label='intensity')
|
|
106
|
+
plt.xlabel(r'q $(\AA)$')
|
|
107
|
+
plt.ylabel(r'Intensity (au)')
|
|
108
|
+
# result.plot(data_kws={'markersize': 1})
|
|
109
|
+
plt.legend()
|
|
110
|
+
plt.title('Frame: ' + str(frame_index))
|
|
111
|
+
#plt.show()
|
|
112
|
+
params = [None]*6
|
|
113
|
+
std_error = [None]*3
|
|
114
|
+
redchi = [None]
|
|
115
|
+
print("No Peak Found")
|
|
116
|
+
|
|
117
|
+
return (params, std_error, redchi, peak_in_frame)
|
|
118
|
+
|
|
119
|
+
def fit_several_frames(q, time, intensity, show_every, lowQ, highQ, sampleName, outputPath, hkl):
|
|
120
|
+
|
|
121
|
+
amplitude, unc_a = [], []
|
|
122
|
+
center, unc_c = [], []
|
|
123
|
+
sigma, unc_s = [], []
|
|
124
|
+
fraction = []
|
|
125
|
+
slope = []
|
|
126
|
+
|
|
127
|
+
intercept = []
|
|
128
|
+
red_chi = []
|
|
129
|
+
all_params = [amplitude, center, sigma, fraction, slope, intercept]
|
|
130
|
+
peak_unc = [unc_a, unc_c, unc_s]
|
|
131
|
+
frames = range(0, len(time))
|
|
132
|
+
frames_to_plot = [i for i in frames if i % show_every == 0]
|
|
133
|
+
for frame in tqdm(frames, desc='Fitting frames'):
|
|
134
|
+
params, std_error, redchi, peak_in_frame = fit_single_frame(lowQ, highQ, q, intensity,
|
|
135
|
+
frame, frames_to_plot, sampleName, outputPath)
|
|
136
|
+
|
|
137
|
+
red_chi.append(redchi)
|
|
138
|
+
|
|
139
|
+
for index, param in enumerate(all_params):
|
|
140
|
+
param.append(params[index])
|
|
141
|
+
for index, unc in enumerate(peak_unc):
|
|
142
|
+
unc.append(std_error[index])
|
|
143
|
+
# =============================================================================
|
|
144
|
+
# if peak_in_frame:
|
|
145
|
+
# if std_error[0] != None:
|
|
146
|
+
# if std_error[0] < 1:
|
|
147
|
+
# # for higher efficiency, the init_params are now changed to the
|
|
148
|
+
# # fit values for next scan. However, if the initial frame is
|
|
149
|
+
# # wrongly identified to contain a peak, this might lead to problems
|
|
150
|
+
# init_params['amplitude'] = params[0]
|
|
151
|
+
# init_params['center'] = params[1]
|
|
152
|
+
# init_params['sigma'] = params[2]
|
|
153
|
+
# init_params['fraction'] = params[3]
|
|
154
|
+
# init_params['slope'] = params[4]
|
|
155
|
+
# init_params['intercept'] = params[5]
|
|
156
|
+
# =============================================================================
|
|
157
|
+
|
|
158
|
+
fig, ax1 = plt.subplots(figsize=(7, 5))
|
|
159
|
+
plot1, = ax1.plot(frames, center, label='center')
|
|
160
|
+
ax2 = ax1.twinx()
|
|
161
|
+
plot2, = ax2.plot(frames, sigma, 'g', label='$\sigma$')
|
|
162
|
+
ax1.set_xlabel('Frame #')
|
|
163
|
+
ax1.set_ylabel(r'q ($\AA^{-1}$)')
|
|
164
|
+
ax2.set_ylabel(r' $\sigma$ ($\AA^{-1}$)')
|
|
165
|
+
# Create your ticker object with M ticks
|
|
166
|
+
yticks = ticker.MaxNLocator(5)
|
|
167
|
+
ax1.yaxis.set_major_locator(yticks)
|
|
168
|
+
fig.suptitle('Fit Results ' + sampleName, fontsize=14)
|
|
169
|
+
fig.legend()
|
|
170
|
+
plt.pause(1)
|
|
171
|
+
|
|
172
|
+
# saving peak fit params in separate csv files
|
|
173
|
+
params_to_save = {sampleName + '_' + hkl + '_time (s)' : time,
|
|
174
|
+
sampleName + '_' + hkl + '_amplitude (au)' : amplitude,
|
|
175
|
+
sampleName + '_' + hkl + '_center ($\AA$)' : center,
|
|
176
|
+
sampleName + '_' + hkl + '_sigma ($\AA$)' : sigma,
|
|
177
|
+
sampleName + '_' + hkl + '_std error amplitude (au)' : unc_a,
|
|
178
|
+
sampleName + '_' + hkl + '_std error center ($\AA$)' : unc_c,
|
|
179
|
+
sampleName + '_' + hkl + '_std error sigma ($\AA$)' : unc_s}
|
|
180
|
+
|
|
181
|
+
df = pd.DataFrame(params_to_save)
|
|
182
|
+
df = df.replace(np.nan, 'NaN')
|
|
183
|
+
|
|
184
|
+
df.to_csv(os.path.join(outputPath, str(hkl) + '_peak_fit_results_' + sampleName + '.csv'), index=None)
|
|
185
|
+
|
|
186
|
+
return
|
|
187
|
+
|
|
188
|
+
#%%
|
|
189
|
+
#PL-Fitting
|
|
190
|
+
|
|
191
|
+
def sum_of_Voigts(x, *params):
|
|
192
|
+
|
|
193
|
+
if isinstance(x, float):
|
|
194
|
+
x = np.array([x])
|
|
195
|
+
|
|
196
|
+
params = np.array(params)
|
|
197
|
+
n = (len(params)-2) // 4
|
|
198
|
+
|
|
199
|
+
# divide parameters
|
|
200
|
+
amps = params[:n]
|
|
201
|
+
mus = params[n:2*n]
|
|
202
|
+
sigmas = params[2*n:3*n]
|
|
203
|
+
alphas = params[3*n:4*n]
|
|
204
|
+
|
|
205
|
+
gaussians = amps*np.exp(-(x[:, np.newaxis] - mus)**2 / sigmas)
|
|
206
|
+
lorentian = np.log(2) * (2/np.pi)**0.5 * (amps*sigmas / ((x[:, np.newaxis] - mus)**2 + sigmas*np.log(2)))
|
|
207
|
+
background = params[-2]*x + params[-1]
|
|
208
|
+
|
|
209
|
+
return np.dot(gaussians, 1-alphas) + np.dot(lorentian, alphas) + background
|
|
210
|
+
|
|
211
|
+
def background(x, y0, y1):
|
|
212
|
+
return y0*x + y1
|
|
213
|
+
|
|
214
|
+
def fWHM_Voigt(x, center, maxValue, params):
|
|
215
|
+
|
|
216
|
+
x1 = np.linspace(x[0], center, 5001)
|
|
217
|
+
x2 = np.linspace(center, x[-1], 5001)
|
|
218
|
+
|
|
219
|
+
y1 = sum_of_Voigts(x1, *params)
|
|
220
|
+
y2 = sum_of_Voigts(x2, *params)
|
|
221
|
+
|
|
222
|
+
root1 = np.interp(maxValue/2,y1,x1)
|
|
223
|
+
root2 = np.interp(maxValue/2,y2[::-1],x2[::-1])
|
|
224
|
+
|
|
225
|
+
return root2 - root1
|
|
226
|
+
|
|
227
|
+
def plFitting(plParams, df_yCut, df_xCutFit, df_fit, show_every, numGauss, peakLowerTH, inputDict, peakUpperTH, estPeakWidth, minPeakWidth, maxPeakWidth, name_d, name):
|
|
228
|
+
|
|
229
|
+
estPositions = inputDict["PLFits_CenterGuesses"]
|
|
230
|
+
|
|
231
|
+
frames = range(0, len(df_xCutFit))
|
|
232
|
+
frames_to_plot = [i for i in frames if i % show_every == 0]
|
|
233
|
+
|
|
234
|
+
yVals = np.copy(df_fit)
|
|
235
|
+
popt = np.array([[np.nan, np.nan, np.nan, np.nan]*int(numGauss) + [np.nan, np.nan]] * np.shape(df_fit)[1])
|
|
236
|
+
peakFWHM = np.array([[np.nan]*int(numGauss)] * np.shape(df_fit)[1])
|
|
237
|
+
peakArea = np.array([[np.nan]*int(numGauss)] * np.shape(df_fit)[1])
|
|
238
|
+
|
|
239
|
+
# The next block is to convert the estimated peak positions and ranges into indexes
|
|
240
|
+
idxLowerTH = [0.0]*int(numGauss)
|
|
241
|
+
idxUpperTH = [0.0]*int(numGauss)
|
|
242
|
+
|
|
243
|
+
for i in range(0, int(numGauss)):
|
|
244
|
+
idxLowerTH[i] = next(xStart for xStart, valStart in enumerate(df_yCut) if valStart > peakLowerTH[i])
|
|
245
|
+
idxUpperTH[i] = next(xEnd for xEnd, valEnd in enumerate(df_yCut) if valEnd > peakUpperTH[i])
|
|
246
|
+
|
|
247
|
+
firstSpectrum = True
|
|
248
|
+
for i in range(0, np.shape(df_fit)[1]):
|
|
249
|
+
|
|
250
|
+
# get y values
|
|
251
|
+
yVals[:, i] = np.where(yVals[:, i] == float('inf'), 5, yVals[:, i])
|
|
252
|
+
|
|
253
|
+
idx = np.argmax(yVals[0:idxUpperTH[0], i])
|
|
254
|
+
yVals[idx, i] = yVals[idx - 1, i]
|
|
255
|
+
|
|
256
|
+
# find peaks
|
|
257
|
+
peaks = signal.find_peaks(yVals[:, i])[0]
|
|
258
|
+
|
|
259
|
+
# array initialization
|
|
260
|
+
estAmplitudes = [0.0]*int(numGauss)
|
|
261
|
+
minAmplitudes = [0.0]*int(numGauss)
|
|
262
|
+
maxAmplitudes = [0.0]*int(numGauss)
|
|
263
|
+
estAlphas = [0.24]*int(numGauss)
|
|
264
|
+
minAlphas = [0.0]*int(numGauss)
|
|
265
|
+
maxAlphas = [1.0]*int(numGauss)
|
|
266
|
+
minLinBkg = 0.0
|
|
267
|
+
estLinBkg = 0.0
|
|
268
|
+
maxLinBkg = 1000.0
|
|
269
|
+
minConstBkg = 0.0
|
|
270
|
+
estConstBkg = 0.0
|
|
271
|
+
maxConstBkg = 1000.0
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
# no peak, skip
|
|
275
|
+
if len(peaks) == 0:
|
|
276
|
+
print("Time:")
|
|
277
|
+
print(df_xCutFit[i])
|
|
278
|
+
print("No Peak Found")
|
|
279
|
+
continue
|
|
280
|
+
|
|
281
|
+
if firstSpectrum:
|
|
282
|
+
firstSpectrum = False
|
|
283
|
+
firstFitIdx = i
|
|
284
|
+
|
|
285
|
+
# find initial parameters and bounds for peak amplitudes, having free peaks start more prominent than propagating ones
|
|
286
|
+
for ii in range(0,int(numGauss)):
|
|
287
|
+
if float(inputDict["PLFits_Propagate?"][ii]):
|
|
288
|
+
estAmplitudes[ii] = max(yVals[idxLowerTH[ii]:idxUpperTH[ii], i]) / 5
|
|
289
|
+
minAmplitudes[ii] = 0
|
|
290
|
+
maxAmplitudes[ii] = max(yVals[idxLowerTH[ii]:idxUpperTH[ii], i]) / 1.5
|
|
291
|
+
else:
|
|
292
|
+
estAmplitudes[ii] = max(yVals[idxLowerTH[ii]:idxUpperTH[ii], i])
|
|
293
|
+
minAmplitudes[ii] = estAmplitudes[ii] / 10
|
|
294
|
+
maxAmplitudes[ii] = np.inf
|
|
295
|
+
|
|
296
|
+
# collecting fit parameters
|
|
297
|
+
estParams = estAmplitudes + estPositions + estPeakWidth + estAlphas + [estLinBkg, estConstBkg]
|
|
298
|
+
lowerBounds = minAmplitudes + peakLowerTH + minPeakWidth + minAlphas + [minLinBkg, minConstBkg]
|
|
299
|
+
upperBounds = maxAmplitudes + peakUpperTH + maxPeakWidth + maxAlphas + [maxLinBkg, maxConstBkg]
|
|
300
|
+
|
|
301
|
+
else:
|
|
302
|
+
# update initial parameters and bounds. Propagating peaks have their position and width linked to the first one
|
|
303
|
+
for ii in range(0,int(numGauss)):
|
|
304
|
+
# estAlphas[ii] = popt[firstFitIdx, 3*int(numGauss)+ii]
|
|
305
|
+
# minAlphas[ii] = estAlphas[ii] / 1.05
|
|
306
|
+
# maxAlphas[ii] = estAlphas[ii] * 1.05
|
|
307
|
+
|
|
308
|
+
if float(inputDict["PLFits_Propagate?"][ii]):
|
|
309
|
+
estAmplitudes[ii] = max(yVals[idxLowerTH[ii]:idxUpperTH[ii], i]) / 10
|
|
310
|
+
minAmplitudes[ii] = 0
|
|
311
|
+
maxAmplitudes[ii] = np.inf
|
|
312
|
+
estPositions[ii] = popt[firstFitIdx,int(numGauss)+ii]
|
|
313
|
+
peakLowerTH[ii] = estPositions[ii]
|
|
314
|
+
peakUpperTH[ii] = estPositions[ii] * 1.001
|
|
315
|
+
estPeakWidth[ii] = popt[firstFitIdx][2*int(numGauss)+ii]
|
|
316
|
+
minPeakWidth[ii] = estPeakWidth[ii] / 1.01
|
|
317
|
+
maxPeakWidth[ii] = estPeakWidth[ii] * 1.01
|
|
318
|
+
|
|
319
|
+
else:
|
|
320
|
+
estAmplitudes[ii] = max(yVals[idxLowerTH[ii]:idxUpperTH[ii], i])
|
|
321
|
+
minAmplitudes[ii] = 0
|
|
322
|
+
maxAmplitudes[ii] = np.inf
|
|
323
|
+
|
|
324
|
+
# # if previously converged, keep position from optimized (didn't improve fit much but makes it slower)
|
|
325
|
+
# if not np.isnan(popt[i-1, int(numGauss)+ii]):
|
|
326
|
+
# estPositions[ii] = popt[i-1,int(numGauss)+ii]
|
|
327
|
+
# peakLowerTH[ii] = estPositions[ii] - 0.1
|
|
328
|
+
# peakUpperTH[ii] = estPositions[ii] + 0.1
|
|
329
|
+
|
|
330
|
+
# collecting fit parameters
|
|
331
|
+
estParams = estAmplitudes + estPositions + estPeakWidth + estAlphas + [estConstBkg, estLinBkg]
|
|
332
|
+
lowerBounds = minAmplitudes + peakLowerTH + minPeakWidth + minAlphas + [0.0, 0.0]
|
|
333
|
+
upperBounds = maxAmplitudes + peakUpperTH + maxPeakWidth + maxAlphas + [1000.0, 1000.0]
|
|
334
|
+
|
|
335
|
+
# try fitting
|
|
336
|
+
try:
|
|
337
|
+
popt[i], pcov = curve_fit(sum_of_Voigts,
|
|
338
|
+
df_yCut,
|
|
339
|
+
yVals[:, i],
|
|
340
|
+
p0 = estParams,
|
|
341
|
+
bounds = (lowerBounds, upperBounds)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
except Exception:
|
|
346
|
+
print("Time:")
|
|
347
|
+
print(df_xCutFit[i])
|
|
348
|
+
traceback.print_exc()
|
|
349
|
+
pass
|
|
350
|
+
|
|
351
|
+
for ii in range(0,int(numGauss)):
|
|
352
|
+
parameters = [popt[i,ii], popt[i,int(numGauss)+ii], popt[i,2*int(numGauss)+ii], popt[i,3*int(numGauss)+ii], 0, 0]
|
|
353
|
+
peakFWHM[i,ii] = fWHM_Voigt(df_yCut, popt[i,int(numGauss)+ii], sum_of_Voigts(popt[i,int(numGauss)+ii], *parameters), parameters)
|
|
354
|
+
peakArea[i,ii] = integrate.quad(lambda x: sum_of_Voigts(x, *parameters), -np.inf,np.inf)[0]
|
|
355
|
+
|
|
356
|
+
# plotting fit results for pre-selected frames
|
|
357
|
+
if i in frames_to_plot:
|
|
358
|
+
|
|
359
|
+
plt.figure(figsize=(6, 5))
|
|
360
|
+
plt.plot(df_yCut, yVals[:, i], 'o', label='data')
|
|
361
|
+
plt.plot(df_yCut, sum_of_Voigts(df_yCut, *popt[i,:]), 'r-', label='fit')
|
|
362
|
+
|
|
363
|
+
for ii in range(0, int(numGauss)):
|
|
364
|
+
plt.plot(df_yCut, sum_of_Voigts(df_yCut, *[popt[i,ii], popt[i,int(numGauss)+ii], popt[i,2*int(numGauss)+ii], popt[i,3*int(numGauss)+ii], 0, 0]), '--', label='Peak ' + str(ii+1))
|
|
365
|
+
plt.plot(df_yCut, background(df_yCut, *[popt[i,-2], popt[i,-1]]), 'k--', label='Background')
|
|
366
|
+
plt.legend()
|
|
367
|
+
plt.xlabel('Energy (eV)')
|
|
368
|
+
plt.ylabel('Intensity (a.u.)')
|
|
369
|
+
plt.title('Time: ' + str(df_xCutFit[i]))
|
|
370
|
+
plt.savefig(os.path.join(name + '/fits/', str(name_d) + '_PL-fit_' + str(int(df_xCutFit[i])) + '_s.png'), format = 'png')
|
|
371
|
+
plt.show(block=False)
|
|
372
|
+
plt.pause(1)
|
|
373
|
+
|
|
374
|
+
if plParams['logplots']:
|
|
375
|
+
plt.figure(figsize=(6, 5))
|
|
376
|
+
plt.plot(df_yCut, np.log(yVals[:, i]), 'o', label='data')
|
|
377
|
+
plt.plot(df_yCut, np.log(sum_of_Voigts(df_yCut, *popt[i,:])), 'r-', label='fit')
|
|
378
|
+
plt.legend()
|
|
379
|
+
plt.xlabel('Energy (eV)')
|
|
380
|
+
plt.ylabel('Log-Intensity (a.u.)')
|
|
381
|
+
plt.title('Time: ' + str(df_xCutFit[i]))
|
|
382
|
+
plt.savefig(os.path.join(name + '/fits/', str(name_d) + '_PL-fit_Log_' + str(int(df_xCutFit[i])) + '_s.png'), format = 'png')
|
|
383
|
+
plt.show(block=False)
|
|
384
|
+
plt.pause(1)
|
|
385
|
+
|
|
386
|
+
# Plotting the time-evolution of the peak-positions and intensities
|
|
387
|
+
for i in range(0, int(numGauss)):
|
|
388
|
+
fig, ax1 = plt.subplots(figsize=(6, 5))
|
|
389
|
+
plot1, = ax1.plot(df_xCutFit, popt[:,int(numGauss)+i], label = 'Peak Position')
|
|
390
|
+
ax2 = ax1.twinx()
|
|
391
|
+
plot2, = ax2.plot(df_xCutFit, popt[:,i], 'g', label = 'Peak Intensity')
|
|
392
|
+
ax1.set_xlabel('Time (s)')
|
|
393
|
+
ax1.set_ylabel(r'PL Position (eV)')
|
|
394
|
+
ax2.set_ylabel(r'PL Intensity (a.u.)')
|
|
395
|
+
# Create your ticker object with M ticks
|
|
396
|
+
yticks = ticker.MaxNLocator(5)
|
|
397
|
+
ax1.yaxis.set_major_locator(yticks)
|
|
398
|
+
fig.suptitle('Fit Results Peak ' + str(i+1) + ' ' + name_d, fontsize=14)
|
|
399
|
+
fig.legend()
|
|
400
|
+
|
|
401
|
+
# collecting the fit results in a dataframe
|
|
402
|
+
dfPeaks = pd.DataFrame()
|
|
403
|
+
dfPeaks['Fit-Time_' + name_d] = df_xCutFit
|
|
404
|
+
for i in range(0,int(numGauss)):
|
|
405
|
+
colPos = 'Peak' + str(i+1) + 'Pos_' + name_d
|
|
406
|
+
colArea = 'Peak' + str(i+1) + 'Area_' + name_d
|
|
407
|
+
colFWHM = 'Peak' + str(i+1) + 'FWHM_' + name_d
|
|
408
|
+
colAlphas = 'Peak' + str(i+1) + 'Alpha_' + name_d
|
|
409
|
+
data = np.array([peakArea[:,i], popt[:,int(numGauss)+i], peakFWHM[:,i], popt[:,3*int(numGauss)+i]])
|
|
410
|
+
dfTemp = pd.DataFrame(
|
|
411
|
+
data.T,
|
|
412
|
+
columns=[colArea, colPos, colFWHM, colAlphas])
|
|
413
|
+
dfPeaks = pd.concat([dfPeaks, dfTemp], axis=1)
|
|
414
|
+
dfPeaks = dfPeaks.fillna('nan')
|
|
415
|
+
|
|
416
|
+
# saving the data:
|
|
417
|
+
dfPeaks.to_csv(str(name) + '/PL_FitResults.csv', index=False)
|
|
418
|
+
|
|
419
|
+
return
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Thu Dec 22 11:56:04 2022
|
|
4
|
+
|
|
5
|
+
@author: Tim Kodalle
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
#%%PL-Settings:
|
|
9
|
+
|
|
10
|
+
def generalParameters():
|
|
11
|
+
|
|
12
|
+
genParams = {
|
|
13
|
+
'GIWAXS' : True,
|
|
14
|
+
'PL' : True,
|
|
15
|
+
'Logging': True,
|
|
16
|
+
'TempOld' : False,
|
|
17
|
+
|
|
18
|
+
'LabviewPL' : True, # BL PL via Labview
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return genParams
|
|
22
|
+
|
|
23
|
+
def plParameters():
|
|
24
|
+
|
|
25
|
+
plParams = {
|
|
26
|
+
'Thorlabs' : False, # If Thorlabs software is used instead of OceanView
|
|
27
|
+
'smoothing' : False, # Smoothing of the data to reduce noise
|
|
28
|
+
'Labview' : True, # BL PL via Labview
|
|
29
|
+
'sFactor' : 3, # Parameter for smoothing with a SavGol-Filter
|
|
30
|
+
'bkgCorr' : False, # Enable linear background removal. If True, the program will ask for two ranges for the removal. I recommend setting one of them at higher and the other at lower energy compared to the peaks of interest.
|
|
31
|
+
'bkgCorrPoly' : 1, # This parameter determines the order of the polynomial fit used for background correction (0=const, 1=linear, etc.)
|
|
32
|
+
'binning' : 0, # 0: no binning, >0: Binning of n spectra into one, i.e. reducing the time resolution for increased signal to noise ratio
|
|
33
|
+
'logplots': 0,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return plParams
|
|
File without changes
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Mon Mar 6 11:03:33 2023
|
|
4
|
+
|
|
5
|
+
@author: Tim Kodalle
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import tkinter as tk
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def inputGUI(inputDict, DictEntry, numberOfInputs, Title, Labels, TextPrompt):
|
|
12
|
+
|
|
13
|
+
entries = []
|
|
14
|
+
|
|
15
|
+
# Create a function to update the variables and close the GUI window
|
|
16
|
+
def updateVariables():
|
|
17
|
+
allEntries = []
|
|
18
|
+
for entry in entries:
|
|
19
|
+
allEntries.append(entry.get())
|
|
20
|
+
|
|
21
|
+
root.quit()
|
|
22
|
+
root.destroy() # close the GUI window
|
|
23
|
+
|
|
24
|
+
# update class variable
|
|
25
|
+
inputDict[DictEntry] = allEntries
|
|
26
|
+
|
|
27
|
+
# Create the GUI window
|
|
28
|
+
root = tk.Tk()
|
|
29
|
+
root.title(Title)
|
|
30
|
+
|
|
31
|
+
label = tk.Label(root, text=TextPrompt)
|
|
32
|
+
label.grid(row=0, column=0, columnspan = 2)
|
|
33
|
+
|
|
34
|
+
# Create the input fields and labels
|
|
35
|
+
for i in range(numberOfInputs):
|
|
36
|
+
label = tk.Label(root, text=Labels[i])
|
|
37
|
+
label.grid(row=i+1, column=0, pady=10, padx=5)
|
|
38
|
+
entry = tk.Entry(root)
|
|
39
|
+
entry.grid(row=i+1, column=1, pady=10, padx=5)
|
|
40
|
+
entries.append(entry)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# Create a button to update the variables
|
|
44
|
+
update_button = tk.Button(root, text="Submit", command=updateVariables)
|
|
45
|
+
update_button.grid(row=numberOfInputs + 2, column=0, columnspan=2)
|
|
46
|
+
|
|
47
|
+
# Start the GUI event loop
|
|
48
|
+
root.mainloop()
|
|
49
|
+
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def selectionGUI(inputDict, DictEntry, title, options):
|
|
54
|
+
|
|
55
|
+
root = tk.Tk()
|
|
56
|
+
root.title(title)
|
|
57
|
+
|
|
58
|
+
v = tk.IntVar(root)
|
|
59
|
+
|
|
60
|
+
for i, option in enumerate(options):
|
|
61
|
+
radioButton = tk.Radiobutton(root, text=option, variable=v, value=i)
|
|
62
|
+
radioButton.grid(row=i, column=1)
|
|
63
|
+
|
|
64
|
+
def submitButton():
|
|
65
|
+
root.quit()
|
|
66
|
+
root.destroy()
|
|
67
|
+
|
|
68
|
+
submitButton = tk.Button(root, text="Submit", command=submitButton)
|
|
69
|
+
submitButton.grid(row=len(options) + 2, column=1)
|
|
70
|
+
|
|
71
|
+
root.mainloop()
|
|
72
|
+
|
|
73
|
+
inputDict[DictEntry] = options[v.get()]
|
|
74
|
+
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
def combinedGUI(inputDict, DictEntry, DictEntry2, DictEntry3, numberOfInputs, Title, Labels, TextPrompt, options, options2):
|
|
78
|
+
|
|
79
|
+
entries = []
|
|
80
|
+
boxes = []
|
|
81
|
+
boxes2 = []
|
|
82
|
+
|
|
83
|
+
# Create a function to update the variables and close the GUI window
|
|
84
|
+
def updateVariables():
|
|
85
|
+
allEntries = []
|
|
86
|
+
allBoxes = []
|
|
87
|
+
allBoxes2 = []
|
|
88
|
+
for entry in entries:
|
|
89
|
+
allEntries.append(float(entry.get()))
|
|
90
|
+
|
|
91
|
+
for box in boxes:
|
|
92
|
+
allBoxes.append(box.get())
|
|
93
|
+
|
|
94
|
+
for box in boxes2:
|
|
95
|
+
allBoxes2.append(box.get())
|
|
96
|
+
|
|
97
|
+
root.quit()
|
|
98
|
+
root.destroy() # close the GUI window
|
|
99
|
+
|
|
100
|
+
# update class variable
|
|
101
|
+
inputDict[DictEntry] = allEntries
|
|
102
|
+
inputDict[DictEntry2] = allBoxes
|
|
103
|
+
inputDict[DictEntry3] = allBoxes2
|
|
104
|
+
|
|
105
|
+
# Create the GUI window
|
|
106
|
+
root = tk.Tk()
|
|
107
|
+
root.title(Title)
|
|
108
|
+
|
|
109
|
+
label = tk.Label(root, text=TextPrompt)
|
|
110
|
+
label.grid(row=0, column=0, columnspan = 2)
|
|
111
|
+
|
|
112
|
+
# Create the input fields and labels
|
|
113
|
+
for i in range(numberOfInputs):
|
|
114
|
+
label = tk.Label(root, text=Labels[i])
|
|
115
|
+
label.grid(row=i+1, column=0, pady=10, padx=5)
|
|
116
|
+
entry = tk.Entry(root)
|
|
117
|
+
entry.grid(row=i+1, column=1, pady=10, padx=5)
|
|
118
|
+
entries.append(entry)
|
|
119
|
+
|
|
120
|
+
for i, option in enumerate(options):
|
|
121
|
+
v = tk.IntVar(root)
|
|
122
|
+
checkBox = tk.Checkbutton(root, text=option, variable=v, onvalue=1, offvalue=0, command=None)
|
|
123
|
+
checkBox.grid(row=i+1, column=3)
|
|
124
|
+
boxes.append(v)
|
|
125
|
+
|
|
126
|
+
for i, option in enumerate(options2):
|
|
127
|
+
v = tk.IntVar(root)
|
|
128
|
+
checkBox = tk.Checkbutton(root, text=option, variable=v, onvalue=1, offvalue=0, command=None)
|
|
129
|
+
checkBox.grid(row=i+1, column=4)
|
|
130
|
+
boxes2.append(v)
|
|
131
|
+
|
|
132
|
+
# Create a button to update the variables
|
|
133
|
+
update_button = tk.Button(root, text="Submit", command=updateVariables)
|
|
134
|
+
update_button.grid(row=numberOfInputs + 2, column=0, columnspan=2)
|
|
135
|
+
|
|
136
|
+
# Start the GUI event loop
|
|
137
|
+
root.mainloop()
|
|
138
|
+
|
|
139
|
+
return
|
|
File without changes
|