mmanalysis 0.0.1__tar.gz

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.
@@ -0,0 +1 @@
1
+ include requirements.txt
@@ -0,0 +1,92 @@
1
+ Metadata-Version: 2.1
2
+ Name: mmanalysis
3
+ Version: 0.0.1
4
+ Summary: MultiModalAnalysis is a package to easily postprocess GIWAXS data.
5
+ Home-page: https://github.com/sutterfellalab/MultiModalAnalysis
6
+ Author: attr:mmanalysis.__author__
7
+ Author-email: TimKodalle@lbl.gov
8
+ License: Apache-2.0
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Topic :: Software Development
13
+ Classifier: Topic :: Scientific/Engineering
14
+ Requires-Python: >=3.6
15
+ Description-Content-Type: text/markdown
16
+ Requires-Dist: numpy
17
+ Requires-Dist: scipy
18
+ Requires-Dist: pandas
19
+ Requires-Dist: dill
20
+ Requires-Dist: matplotlib
21
+ Requires-Dist: tk
22
+ Requires-Dist: lmfit
23
+ Requires-Dist: bokeh
24
+ Requires-Dist: tqdm
25
+
26
+ # Multi Modal Analysis
27
+
28
+ This repository contains a Python script designed for analysis tasks related to MMAnalysis. The script performs various data processing tasks including logging data selection, GIWAXS data selection, and PL data selection. It also allows for peak fitting and generates stacked plots.
29
+
30
+ ## Requirements
31
+
32
+ Check the file [requirements.txt](requirements.txt) to see which packages are needed. Installing the package using `pip` should already take care of all dependencies.
33
+
34
+ ## Installation instructions
35
+
36
+ ### Create a new virtual environment
37
+
38
+ Create a new Python environment. (You can also do it in a pre-existing environment, but make sure you don't break something):
39
+
40
+ ```bash
41
+ conda create -n mmanalysis python=3.11
42
+ conda activate mmanalysis
43
+ ```
44
+
45
+ Note that you may need to initialize your shell within conda, e.g., using conda init bash. You will know if the conda environment has been activated when you see that your shell prompt is modified with (`mmanalysis`).
46
+
47
+ After activating your new (or existing) environment, follow the next steps.
48
+
49
+ ### Install using `pip`
50
+
51
+ You can simply install the latest release of the package and all dependencies using:
52
+
53
+ ```bash
54
+ pip install mmanalysis
55
+ ```
56
+
57
+ ### Install directly the source code
58
+
59
+ Alternatively you can obtain `mmanalysis` directly from the repository by following those steps:
60
+
61
+ Clone the repository in the desired location:
62
+
63
+ ```bash
64
+ git clone https://github.com/sutterfellalab/MultiModalAnalysis.git
65
+ ```
66
+
67
+ Install the required packages:
68
+
69
+ ```bash
70
+ cd MultiModalAnalysis
71
+ conda install -c conda-forge --file requirements.txt
72
+ ```
73
+
74
+ Install the package with pip:
75
+
76
+ ```bash
77
+ pip install .
78
+ ```
79
+
80
+ ## Features
81
+
82
+ - **Logging Data Selection**: Automatically suggests start times and plots raw and post-processed log data.
83
+ - **GIWAXS Data Selection**: Automatically finds start times, plots raw and post-processed GIWAXS data, and performs peak fitting.
84
+ - **PL Data Selection**: Plots raw and post-processed PL data, optimizes data for plotting, and performs peak fitting.
85
+ - **Stacked Plots**: Generates stacked plots for combined GIWAXS, PL, and logging data.
86
+
87
+ ## Contact
88
+
89
+ Feel free to create Merge Requests and Issues on our GitHub page: [https://github.com/sutterfellalab/MultiModalAnalysis](https://github.com/sutterfellalab/MultiModalAnalysis).
90
+
91
+ If you want to contact the authors, please write to T. Kodalle at <TimKodalle@lbl.gov>.
92
+
@@ -0,0 +1,67 @@
1
+ # Multi Modal Analysis
2
+
3
+ This repository contains a Python script designed for analysis tasks related to MMAnalysis. The script performs various data processing tasks including logging data selection, GIWAXS data selection, and PL data selection. It also allows for peak fitting and generates stacked plots.
4
+
5
+ ## Requirements
6
+
7
+ Check the file [requirements.txt](requirements.txt) to see which packages are needed. Installing the package using `pip` should already take care of all dependencies.
8
+
9
+ ## Installation instructions
10
+
11
+ ### Create a new virtual environment
12
+
13
+ Create a new Python environment. (You can also do it in a pre-existing environment, but make sure you don't break something):
14
+
15
+ ```bash
16
+ conda create -n mmanalysis python=3.11
17
+ conda activate mmanalysis
18
+ ```
19
+
20
+ Note that you may need to initialize your shell within conda, e.g., using conda init bash. You will know if the conda environment has been activated when you see that your shell prompt is modified with (`mmanalysis`).
21
+
22
+ After activating your new (or existing) environment, follow the next steps.
23
+
24
+ ### Install using `pip`
25
+
26
+ You can simply install the latest release of the package and all dependencies using:
27
+
28
+ ```bash
29
+ pip install mmanalysis
30
+ ```
31
+
32
+ ### Install directly the source code
33
+
34
+ Alternatively you can obtain `mmanalysis` directly from the repository by following those steps:
35
+
36
+ Clone the repository in the desired location:
37
+
38
+ ```bash
39
+ git clone https://github.com/sutterfellalab/MultiModalAnalysis.git
40
+ ```
41
+
42
+ Install the required packages:
43
+
44
+ ```bash
45
+ cd MultiModalAnalysis
46
+ conda install -c conda-forge --file requirements.txt
47
+ ```
48
+
49
+ Install the package with pip:
50
+
51
+ ```bash
52
+ pip install .
53
+ ```
54
+
55
+ ## Features
56
+
57
+ - **Logging Data Selection**: Automatically suggests start times and plots raw and post-processed log data.
58
+ - **GIWAXS Data Selection**: Automatically finds start times, plots raw and post-processed GIWAXS data, and performs peak fitting.
59
+ - **PL Data Selection**: Plots raw and post-processed PL data, optimizes data for plotting, and performs peak fitting.
60
+ - **Stacked Plots**: Generates stacked plots for combined GIWAXS, PL, and logging data.
61
+
62
+ ## Contact
63
+
64
+ Feel free to create Merge Requests and Issues on our GitHub page: [https://github.com/sutterfellalab/MultiModalAnalysis](https://github.com/sutterfellalab/MultiModalAnalysis).
65
+
66
+ If you want to contact the authors, please write to T. Kodalle at <TimKodalle@lbl.gov>.
67
+
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env python3
2
+ # -- coding: utf-8 --
3
+ """
4
+ Created on Tue Dec 20 11:12:01 2022
5
+
6
+ @author: Tim Kodalle
7
+ """
8
+
9
+ # package info
10
+ __version__ = '0.0.1'
11
+ __date__ = "29 Nov. 2024"
12
+ __author__ = "sutterfellalab"
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
@@ -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