DiadFit 0.0.54__py3-none-any.whl → 0.0.57__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.
- DiadFit/CO2_EOS.py +185 -18
- DiadFit/__init__.py +1 -2
- DiadFit/_version.py +1 -1
- DiadFit/diads.py +19 -8
- DiadFit/error_propagation.py +283 -165
- DiadFit/importing_data_files.py +160 -29
- DiadFit/ne_lines.py +117 -38
- {DiadFit-0.0.54.dist-info → DiadFit-0.0.57.dist-info}/METADATA +1 -1
- DiadFit-0.0.57.dist-info/RECORD +16 -0
- DiadFit/example_peak_params.py +0 -0
- DiadFit/microthermometry.py +0 -10
- DiadFit/ne_lines_BACKUP_966.py +0 -1431
- DiadFit/ne_lines_BASE_966.py +0 -1427
- DiadFit/ne_lines_LOCAL_966.py +0 -1427
- DiadFit/ne_lines_REMOTE_966.py +0 -1427
- DiadFit/skewness.py +0 -0
- DiadFit-0.0.54.dist-info/RECORD +0 -23
- {DiadFit-0.0.54.dist-info → DiadFit-0.0.57.dist-info}/WHEEL +0 -0
- {DiadFit-0.0.54.dist-info → DiadFit-0.0.57.dist-info}/top_level.txt +0 -0
DiadFit/ne_lines_BACKUP_966.py
DELETED
@@ -1,1431 +0,0 @@
|
|
1
|
-
import pandas as pd
|
2
|
-
import numpy as np
|
3
|
-
import matplotlib.pyplot as plt
|
4
|
-
from matplotlib import patches
|
5
|
-
import lmfit
|
6
|
-
from lmfit.models import GaussianModel, VoigtModel, LinearModel, ConstantModel, PseudoVoigtModel
|
7
|
-
from scipy.signal import find_peaks
|
8
|
-
import os
|
9
|
-
import re
|
10
|
-
from os import listdir
|
11
|
-
from os.path import isfile, join
|
12
|
-
from DiadFit.importing_data_files import *
|
13
|
-
from typing import Tuple, Optional
|
14
|
-
from dataclasses import dataclass
|
15
|
-
import matplotlib.patches as patches
|
16
|
-
from tqdm import tqdm
|
17
|
-
|
18
|
-
## Test this
|
19
|
-
|
20
|
-
|
21
|
-
encode="ISO-8859-1"
|
22
|
-
|
23
|
-
## Plotting Ne lines, returns peak position
|
24
|
-
def find_closest(df, line1_shift):
|
25
|
-
dist = (df['Raman_shift (cm-1)'] - line1_shift).abs()
|
26
|
-
return df.loc[dist.idxmin()]
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def calculate_Ne_splitting(wavelength=532.05, line1_shift=1117, line2_shift=1447, cut_off_intensity=2000):
|
31
|
-
"""
|
32
|
-
Calculates ideal splitting in air between lines closest to user-specified line shift
|
33
|
-
"""
|
34
|
-
|
35
|
-
df_Ne=calculate_Ne_line_positions(wavelength=wavelength, cut_off_intensity=cut_off_intensity)
|
36
|
-
|
37
|
-
closest1=find_closest(df_Ne, line1_shift).loc['Raman_shift (cm-1)']
|
38
|
-
closest2=find_closest(df_Ne, line2_shift).loc['Raman_shift (cm-1)']
|
39
|
-
|
40
|
-
diff=abs(closest1-closest2)
|
41
|
-
|
42
|
-
df=pd.DataFrame(data={'Ne_Split': diff,
|
43
|
-
'Line_1': closest1,
|
44
|
-
'Line_2': closest2,
|
45
|
-
'Entered Pos Line 1': line1_shift,
|
46
|
-
'Entered Pos Line 2': line2_shift}, index=[0])
|
47
|
-
|
48
|
-
|
49
|
-
return df
|
50
|
-
|
51
|
-
def calculate_Ne_line_positions(wavelength=532.05, cut_off_intensity=2000):
|
52
|
-
"""
|
53
|
-
Calculates Ne line positions using the theoretical lines from NIST for the user inputted wavelenth
|
54
|
-
"""
|
55
|
-
|
56
|
-
Ne_emission_line_air=np.array([
|
57
|
-
556.244160,
|
58
|
-
556.276620,
|
59
|
-
556.305310,
|
60
|
-
557.603940,
|
61
|
-
558.590500,
|
62
|
-
558.934720,
|
63
|
-
559.115000,
|
64
|
-
565.256640,
|
65
|
-
565.602580,
|
66
|
-
565.665880,
|
67
|
-
566.220000,
|
68
|
-
566.254890,
|
69
|
-
568.464700,
|
70
|
-
568.981630,
|
71
|
-
571.534090,
|
72
|
-
571.887980,
|
73
|
-
571.922480,
|
74
|
-
571.953000,
|
75
|
-
574.243700,
|
76
|
-
574.829850,
|
77
|
-
574.864460,
|
78
|
-
576.058850,
|
79
|
-
576.405250,
|
80
|
-
576.441880,
|
81
|
-
577.030670,
|
82
|
-
580.409000,
|
83
|
-
580.444960,
|
84
|
-
581.140660,
|
85
|
-
581.662190,
|
86
|
-
582.015580,
|
87
|
-
582.890630
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
])
|
92
|
-
|
93
|
-
Intensity=np.array([1500.00,
|
94
|
-
5000.00,
|
95
|
-
750.00,
|
96
|
-
350.00,
|
97
|
-
50.00,
|
98
|
-
500.00,
|
99
|
-
80.00,
|
100
|
-
750.00,
|
101
|
-
750.00,
|
102
|
-
5000.00,
|
103
|
-
40.00,
|
104
|
-
750.00,
|
105
|
-
250.00,
|
106
|
-
1500.00,
|
107
|
-
350.00,
|
108
|
-
1500.00,
|
109
|
-
5000.00,
|
110
|
-
750.00,
|
111
|
-
80.00,
|
112
|
-
5000.00,
|
113
|
-
700.00,
|
114
|
-
700.00,
|
115
|
-
30.00,
|
116
|
-
7000.00,
|
117
|
-
500.00,
|
118
|
-
750.00,
|
119
|
-
5000.00,
|
120
|
-
3000.00,
|
121
|
-
500.00,
|
122
|
-
5000.00,
|
123
|
-
750.00])
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
Raman_shift=(10**7/wavelength)-(10**7/Ne_emission_line_air)
|
128
|
-
|
129
|
-
df_Ne=pd.DataFrame(data={'Raman_shift (cm-1)': Raman_shift,
|
130
|
-
'Intensity': Intensity,
|
131
|
-
'Ne emission line in air': Ne_emission_line_air})
|
132
|
-
|
133
|
-
df_Ne_r=df_Ne.loc[df_Ne['Intensity']>cut_off_intensity]
|
134
|
-
return df_Ne_r
|
135
|
-
|
136
|
-
|
137
|
-
@dataclass
|
138
|
-
class Neon_id_config:
|
139
|
-
# Exclude a range, e.g. cosmic rays
|
140
|
-
exclude_range_1: Optional [Tuple[float, float]] = None
|
141
|
-
exclude_range_2: Optional [Tuple[float, float]] = None
|
142
|
-
|
143
|
-
# Things for Scipy find peaks
|
144
|
-
height: tuple = 10
|
145
|
-
distance: float= 1
|
146
|
-
prominence: float = 10
|
147
|
-
width: float = 1
|
148
|
-
threshold: float = 0.6
|
149
|
-
peak1_cent: float= 1117
|
150
|
-
peak2_cent: float=1447
|
151
|
-
|
152
|
-
# Number of peaks to look for
|
153
|
-
n_peaks: float = 6
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
def identify_Ne_lines(*, config: Neon_id_config=Neon_id_config(), path=None, filename=None, filetype=None, plot_figure=True, print_df=False,
|
161
|
-
Ne_array=None):
|
162
|
-
|
163
|
-
"""
|
164
|
-
Loads Ne line, uses scipy find peaks to identify peaks, overlays these,
|
165
|
-
and returns peak positions to feed into fitting algorithms
|
166
|
-
|
167
|
-
Parameters
|
168
|
-
-----------
|
169
|
-
|
170
|
-
path: str
|
171
|
-
Folder user wishes to read data from
|
172
|
-
|
173
|
-
filename: str
|
174
|
-
Specific file being read
|
175
|
-
|
176
|
-
filetype: str
|
177
|
-
Identifies type of file
|
178
|
-
Witec_ASCII: Datafile from WITEC with metadata for first few lines
|
179
|
-
headless_txt: Txt file with no headers, just data with wavenumber in 1st col, int 2nd
|
180
|
-
HORIBA_txt: Datafile from newer HORIBA machines with metadata in first rows
|
181
|
-
Renishaw_txt: Datafile from renishaw with column headings.
|
182
|
-
|
183
|
-
n_peaks: int
|
184
|
-
Number of peaks to return values for
|
185
|
-
|
186
|
-
peak1_cent: int or float, default 1118
|
187
|
-
Position to look for 1st peak in, finds peaks within +/- 5 of this
|
188
|
-
|
189
|
-
peak2_cent: int or float, default 1447
|
190
|
-
Position to look for 2nd peak in, finds peaks within +/- 5 of this
|
191
|
-
|
192
|
-
|
193
|
-
height, threshold, distance, prominence, width: int
|
194
|
-
parameters for scipy find peaks
|
195
|
-
|
196
|
-
exclude_range_1: None or list
|
197
|
-
users can enter a range (e.g [1100, 1112]) to exclude a part of their spectrum,
|
198
|
-
perhaps to remove cosmic rays
|
199
|
-
|
200
|
-
exclude_range_2: None or list
|
201
|
-
users can enter a range (e.g [1100, 1112]) to exclude a part of their spectrum,
|
202
|
-
perhaps to remove cosmic rays
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
"""
|
207
|
-
|
208
|
-
# This bit extracts the data, unless you already fed it in as an array
|
209
|
-
if filename is not None and path is not None and filetype is not None:
|
210
|
-
Ne_in=get_data(path=path, filename=filename, filetype=filetype)
|
211
|
-
if Ne_array is not None:
|
212
|
-
Ne_in=Ne_array
|
213
|
-
|
214
|
-
|
215
|
-
# This gets parameters from config file
|
216
|
-
exclude_range_1=config.exclude_range_1
|
217
|
-
exclude_range_2=config.exclude_range_2
|
218
|
-
height=config.height
|
219
|
-
distance=config.distance
|
220
|
-
prominence=config.prominence
|
221
|
-
width=config.width
|
222
|
-
threshold=config.threshold
|
223
|
-
peak1_cent=config.peak1_cent
|
224
|
-
peak2_cent=config.peak2_cent
|
225
|
-
n_peaks=config.n_peaks
|
226
|
-
|
227
|
-
|
228
|
-
# This bit filters the spectra if you want to exclude a range or 2
|
229
|
-
if exclude_range_1 is None and exclude_range_2 is None:
|
230
|
-
Ne=Ne_in
|
231
|
-
if exclude_range_1 is not None:
|
232
|
-
Ne=Ne_in[ (Ne_in[:, 0]<exclude_range_1[0]) | (Ne_in[:, 0]>exclude_range_1[1]) ]
|
233
|
-
|
234
|
-
if exclude_range_2 is not None:
|
235
|
-
Ne=Ne_in[ (Ne_in[:, 0]<exclude_range_2[0]) | (Ne_in[:, 0]>exclude_range_2[1]) ]
|
236
|
-
|
237
|
-
# Get X and Y coords.
|
238
|
-
y=Ne[:, 1]
|
239
|
-
x=Ne[:, 0]
|
240
|
-
spec_res=np.abs(x[1]-x[0])
|
241
|
-
|
242
|
-
|
243
|
-
# Apply Scipy Find peaks using the parameters in the config file.
|
244
|
-
peaks = find_peaks(y,height = height, threshold = threshold, distance = distance, prominence=prominence, width=width)
|
245
|
-
|
246
|
-
# This gets a list of peak heights
|
247
|
-
height = peaks[1]['peak_heights']
|
248
|
-
# This gets a list of peak positions
|
249
|
-
peak_pos = x[peaks[0]]
|
250
|
-
|
251
|
-
# Lets combine them in a dataframe
|
252
|
-
df=pd.DataFrame(data={'pos': peak_pos,
|
253
|
-
'height': height})
|
254
|
-
|
255
|
-
|
256
|
-
# Find bigest peaks, and take up to n peaks
|
257
|
-
df_sort_Ne=df.sort_values('height', axis=0, ascending=False)
|
258
|
-
df_sort_Ne_trim=df_sort_Ne[0:n_peaks]
|
259
|
-
|
260
|
-
if print_df is True:
|
261
|
-
print('Biggest 6 peaks:')
|
262
|
-
display(df_sort_Ne_trim)
|
263
|
-
|
264
|
-
# Get peak within +-5
|
265
|
-
df_pk1=df_sort_Ne.loc[df['pos'].between(peak1_cent-10*spec_res, peak1_cent+10*spec_res)]
|
266
|
-
df_pk2=df_sort_Ne.loc[df['pos'].between(peak2_cent-10*spec_res, peak2_cent+10*spec_res)]
|
267
|
-
|
268
|
-
df_pk1_trim=df_pk1[0:1]
|
269
|
-
df_pk2_trim=df_pk2[0:1]
|
270
|
-
|
271
|
-
# Lets extract spectra 10 spectral units either side of the asked for peak positions
|
272
|
-
Neon1_region=(x<(peak1_cent+10*spec_res)) & (x>(peak1_cent-10*spec_res))
|
273
|
-
Neon1_trim_y=y[Neon1_region]
|
274
|
-
Neon1_trim_x=x[Neon1_region]
|
275
|
-
Neon2_region=(x<(peak1_cent+10*spec_res)) & (x>(peak1_cent-10*spec_res))
|
276
|
-
Neon2_trim_y=y[Neon1_region]
|
277
|
-
Neon2_trim_x=x[Neon1_region]
|
278
|
-
|
279
|
-
# Take 25th quantile as representative of the background position
|
280
|
-
Baseline_Neon1=np.quantile(Neon1_trim_y, 0.1)
|
281
|
-
Baseline_Neon2=np.quantile(Neon2_trim_y, 0.1)
|
282
|
-
|
283
|
-
if len(df_pk1_trim)==1:
|
284
|
-
|
285
|
-
df_fit_params=pd.DataFrame(data={'Peak1_cent': df_pk1_trim['pos'],
|
286
|
-
'Peak1_height': df_pk1_trim['height']})
|
287
|
-
elif len(df_pk1_trim)>1:
|
288
|
-
df_pk1_max=df_pk1_trim.loc[df_pk1_trim['height']==np.max(df_pk1_trim['height'])]
|
289
|
-
df_fit_params=pd.DataFrame(data={'Peak1_cent': df_pk1_max['pos'],
|
290
|
-
'Peak1_height': df_pk1_max['height']})
|
291
|
-
elif len(df_pk1_trim)==0:
|
292
|
-
|
293
|
-
|
294
|
-
Max_y_Neon1=np.max(Neon1_trim_y)
|
295
|
-
x_Neon_1=x[y==Max_y_Neon1][0]
|
296
|
-
df_fit_params=pd.DataFrame(data={'Peak1_cent': x_Neon_1,
|
297
|
-
<<<<<<< HEAD
|
298
|
-
'Peak1_height': Max_y_Neon1}, index=[0])
|
299
|
-
=======
|
300
|
-
'Peak1_height': Max_y_Neon1},index=[0])
|
301
|
-
>>>>>>> 321e668c4492e7deb287a9d4e3f3b5173494efa8
|
302
|
-
|
303
|
-
|
304
|
-
if len(df_pk2_trim)==1:
|
305
|
-
df_fit_params['Peak2_cent']=df_pk2_trim['pos'].iloc[0]
|
306
|
-
df_fit_params['Peak2_height']=df_pk2_trim['height'].iloc[0]
|
307
|
-
elif len(df_pk2_trim)>1:
|
308
|
-
df_pk2_max=df_pk2_trim.loc[df_pk2_trim['height']==np.max(df_pk2['height'])]
|
309
|
-
|
310
|
-
df_fit_params['Peak2_cent']=df_pk2_max['pos'].iloc[0]
|
311
|
-
df_fit_params['Peak2_height']=df_pk2_max['height'].iloc[0]
|
312
|
-
|
313
|
-
elif len(df_pk2_trim)==0:
|
314
|
-
|
315
|
-
Max_y_Neon2=np.max(Neon2_trim_y)
|
316
|
-
x_Neon_2=x[y==Max_y_Neon2][0]
|
317
|
-
df_fit_params['Peak2_cent']= x_Neon_2
|
318
|
-
df_fit_params['Peak2_height']=Max_y_Neon2
|
319
|
-
|
320
|
-
|
321
|
-
if plot_figure is True:
|
322
|
-
fig, (ax0, ax1, ax2) = plt.subplots(1, 3, figsize=(11, 3.5))
|
323
|
-
ax0.plot(x, y, '-r')
|
324
|
-
miny=np.min(y)
|
325
|
-
maxy=np.max(y)
|
326
|
-
|
327
|
-
|
328
|
-
ax0.set_ylabel('Amplitude (counts)')
|
329
|
-
ax0.set_xlabel('Wavenumber (cm$^{-1}$)')
|
330
|
-
ax1.plot(Ne_in[:, 0], Ne_in[:, 1], '-c')
|
331
|
-
ax1.plot(Ne_in[:, 0], Ne_in[:, 1], '.c')
|
332
|
-
ax1.plot(Ne[:, 0], Ne[:, 1], '.r')
|
333
|
-
ax1.plot(x, y, '-r', label='filtered')
|
334
|
-
ax1.plot(df_sort_Ne_trim['pos'], df_sort_Ne_trim['height'], '*c', label='all pks IDed')
|
335
|
-
|
336
|
-
ax1.plot([peak1_cent-20, peak1_cent+20], [Baseline_Neon1, Baseline_Neon1], '-g', label='approx bck' )
|
337
|
-
#ax1.plot(peak2_cent, df_pk2_trim['height'], '*k')
|
338
|
-
|
339
|
-
pos_pk1=str(np.round(df_fit_params['Peak1_cent'].iloc[0], 2))
|
340
|
-
|
341
|
-
nearest_pk1=peak1_cent
|
342
|
-
|
343
|
-
|
344
|
-
ax1.annotate('peak=' + pos_pk1, xy=(df_fit_params['Peak1_cent'].iloc[0]+3,
|
345
|
-
Baseline_Neon1*1.5+700), xycoords="data", fontsize=10, rotation=90)
|
346
|
-
|
347
|
-
|
348
|
-
ax1.plot(df_fit_params['Peak1_cent'], df_fit_params['Peak1_height'], '*k', mfc='yellow', ms=8, label='selected peak')
|
349
|
-
|
350
|
-
ax1.legend(loc='upper center', ncol=2, fontsize=8)
|
351
|
-
|
352
|
-
|
353
|
-
pos_pk2=str(np.round(df_fit_params['Peak2_cent'].iloc[0], 2))
|
354
|
-
ax2.plot([peak2_cent-20, peak2_cent+20], [Baseline_Neon2, Baseline_Neon2], '-g')
|
355
|
-
|
356
|
-
ax2.annotate('peak=' + pos_pk2, xy=(df_fit_params['Peak2_cent'].iloc[0]-5,
|
357
|
-
Baseline_Neon1*2+700), xycoords="data", fontsize=10, rotation=90)
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
ax1.set_xlim([peak1_cent-15, peak1_cent+15])
|
362
|
-
|
363
|
-
ax1.set_xlim([peak1_cent-10, peak1_cent+10])
|
364
|
-
ax2.plot(Ne[:, 0], Ne[:, 1], '.r', label='input')
|
365
|
-
ax2.plot(x, y, '-r')
|
366
|
-
ax2.plot(df_sort_Ne_trim['pos'], df_sort_Ne_trim['height'], '*k', mfc='yellow', ms=8)
|
367
|
-
#print(df_pk1)
|
368
|
-
|
369
|
-
|
370
|
-
ax2.set_xlim([peak2_cent-15, peak2_cent+15])
|
371
|
-
|
372
|
-
ax1.set_xlabel('Wavenumber (cm$^{-1}$)')
|
373
|
-
ax2.set_xlabel('Wavenumber (cm$^{-1}$)')
|
374
|
-
|
375
|
-
ax1.set_ylim([0, 1.5*df_fit_params['Peak1_height'].iloc[0]+100])
|
376
|
-
ax2.set_ylim([0, 1.5*df_fit_params['Peak2_height'].iloc[0]+100])
|
377
|
-
fig.tight_layout()
|
378
|
-
|
379
|
-
df_fit_params['Peak1_prom']=df_fit_params['Peak1_height']-Baseline_Neon1
|
380
|
-
df_fit_params['Peak2_prom']=df_fit_params['Peak2_height']-Baseline_Neon2
|
381
|
-
|
382
|
-
|
383
|
-
return Ne, df_fit_params
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
## Ne baselines
|
388
|
-
def remove_Ne_baseline_pk1(Ne, N_poly_pk1_baseline=None, Ne_center_1=None,
|
389
|
-
lower_bck=None, upper_bck1=None, upper_bck2=None, sigma_baseline=None):
|
390
|
-
""" This function uses a defined range of values to fit a baseline of Nth degree polynomial to the baseline
|
391
|
-
around the 1117 peak
|
392
|
-
|
393
|
-
Parameters
|
394
|
-
-----------
|
395
|
-
|
396
|
-
Ne: np.array
|
397
|
-
np.array of x and y coordinates from the spectra
|
398
|
-
|
399
|
-
N_poly_pk1_baseline: int
|
400
|
-
Degree of polynomial used to fit the background
|
401
|
-
|
402
|
-
Ne_center_1: float
|
403
|
-
Center position for Ne line being fitted
|
404
|
-
|
405
|
-
lower_bck: list (length 2). default [-50, -20]
|
406
|
-
position used for lower background relative to peak, so =[-50, -20] takes a
|
407
|
-
background -50 and -20 from the peak center
|
408
|
-
|
409
|
-
upper_bck1: list (length 2). default [8, 15]
|
410
|
-
position used for 1st upper background relative to peak, so =[8, 15] takes a
|
411
|
-
background +8 and +15 from the peak center
|
412
|
-
|
413
|
-
upper_bck2: list (length 2). default [30, 50]
|
414
|
-
position used for 2nd upper background relative to peak, so =[30, 50] takes a
|
415
|
-
background +30 and +50 from the peak center
|
416
|
-
"""
|
417
|
-
|
418
|
-
lower_0baseline_pk1=Ne_center_1+lower_bck[0]
|
419
|
-
upper_0baseline_pk1=Ne_center_1+lower_bck[1]
|
420
|
-
lower_1baseline_pk1=Ne_center_1+upper_bck1[0]
|
421
|
-
upper_1baseline_pk1=Ne_center_1+upper_bck1[1]
|
422
|
-
lower_2baseline_pk1=Ne_center_1+upper_bck2[0]
|
423
|
-
upper_2baseline_pk1=Ne_center_1+upper_bck2[1]
|
424
|
-
|
425
|
-
# Trim for entire range
|
426
|
-
Ne_short=Ne[ (Ne[:,0]>lower_0baseline_pk1) & (Ne[:,0]<upper_2baseline_pk1) ]
|
427
|
-
|
428
|
-
# Get actual baseline
|
429
|
-
Baseline_with_outl=Ne_short[
|
430
|
-
((Ne_short[:, 0]<=upper_0baseline_pk1) &(Ne_short[:, 0]>=lower_0baseline_pk1))
|
431
|
-
|
|
432
|
-
((Ne_short[:, 0]<=upper_1baseline_pk1) &(Ne_short[:, 0]>=lower_1baseline_pk1))
|
433
|
-
|
|
434
|
-
((Ne_short[:, 0]<=upper_2baseline_pk1) &(Ne_short[:, 0]>=lower_2baseline_pk1))]
|
435
|
-
|
436
|
-
# Calculates the median for the baseline and the standard deviation
|
437
|
-
Median_Baseline=np.median(Baseline_with_outl[:, 1])
|
438
|
-
Std_Baseline=np.std(Baseline_with_outl[:, 1])
|
439
|
-
|
440
|
-
# Removes any points in the baseline outside of 2 sigma (helps remove cosmic rays etc).
|
441
|
-
Baseline=Baseline_with_outl[(Baseline_with_outl[:, 1]<Median_Baseline+sigma_baseline*Std_Baseline)
|
442
|
-
&
|
443
|
-
(Baseline_with_outl[:, 1]>Median_Baseline-sigma_baseline*Std_Baseline)
|
444
|
-
]
|
445
|
-
|
446
|
-
# Fits a polynomial to the baseline of degree
|
447
|
-
Pf_baseline = np.poly1d(np.polyfit(Baseline[:, 0], Baseline[:, 1], N_poly_pk1_baseline))
|
448
|
-
Py_base =Pf_baseline(Ne_short[:, 0])
|
449
|
-
Baseline_ysub=Pf_baseline(Baseline_with_outl[:, 0])
|
450
|
-
Baseline_y=Baseline[:, 1]
|
451
|
-
Baseline_x= Baseline[:, 0]#Baseline[:, 0]
|
452
|
-
y_corr= Ne_short[:, 1]- Py_base
|
453
|
-
x=Ne_short[:, 0]
|
454
|
-
|
455
|
-
|
456
|
-
return y_corr, Py_base, x, Ne_short, Py_base, Baseline_y, Baseline_x
|
457
|
-
|
458
|
-
def remove_Ne_baseline_pk2(Ne, N_poly_pk2_baseline=None, Ne_center_2=None, sigma_baseline=None,
|
459
|
-
lower_bck=None, upper_bck1=None, upper_bck2=None):
|
460
|
-
|
461
|
-
""" This function uses a defined range of values to fit a baseline of Nth degree polynomial to the baseline
|
462
|
-
around the 1447 peak
|
463
|
-
|
464
|
-
Parameters
|
465
|
-
-----------
|
466
|
-
|
467
|
-
Ne: np.array
|
468
|
-
np.array of x and y coordinates from the spectra
|
469
|
-
|
470
|
-
N_poly_pk1_baseline: int
|
471
|
-
Degree of polynomial used to fit the background
|
472
|
-
|
473
|
-
Ne_center_1: float
|
474
|
-
Center position for Ne line being fitted
|
475
|
-
|
476
|
-
lower_bck: list (length 2) Default [-44.2, -22]
|
477
|
-
position used for lower background relative to peak, so =[-50, -20] takes a
|
478
|
-
background -50 and -20 from the peak center
|
479
|
-
|
480
|
-
upper_bck1: list (length 2). Default [15, 50]
|
481
|
-
position used for 1st upper background relative to peak, so =[8, 15] takes a
|
482
|
-
background +8 and +15 from the peak center
|
483
|
-
|
484
|
-
upper_bck2: list (length 2) Default [50, 51]
|
485
|
-
position used for 2nd upper background relative to peak, so =[30, 50] takes a
|
486
|
-
background +30 and +50 from the peak center
|
487
|
-
"""
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
lower_0baseline_pk2=Ne_center_2+lower_bck[0]
|
492
|
-
upper_0baseline_pk2=Ne_center_2+lower_bck[1]
|
493
|
-
lower_1baseline_pk2=Ne_center_2+upper_bck1[0]
|
494
|
-
upper_1baseline_pk2=Ne_center_2+upper_bck1[1]
|
495
|
-
lower_2baseline_pk2=Ne_center_2+upper_bck2[0]
|
496
|
-
upper_2baseline_pk2=Ne_center_2+upper_bck2[1]
|
497
|
-
|
498
|
-
# Trim for entire range
|
499
|
-
Ne_short=Ne[ (Ne[:,0]>lower_0baseline_pk2) & (Ne[:,0]<upper_2baseline_pk2) ]
|
500
|
-
|
501
|
-
# Get actual baseline
|
502
|
-
Baseline_with_outl=Ne_short[
|
503
|
-
((Ne_short[:, 0]<upper_0baseline_pk2) &(Ne_short[:, 0]>lower_0baseline_pk2))
|
504
|
-
|
|
505
|
-
((Ne_short[:, 0]<upper_1baseline_pk2) &(Ne_short[:, 0]>lower_1baseline_pk2))
|
506
|
-
|
|
507
|
-
((Ne_short[:, 0]<upper_2baseline_pk2) &(Ne_short[:, 0]>lower_2baseline_pk2))]
|
508
|
-
|
509
|
-
# Calculates the median for the baseline and the standard deviation
|
510
|
-
Median_Baseline=np.median(Baseline_with_outl[:, 1])
|
511
|
-
Std_Baseline=np.std(Baseline_with_outl[:, 1])
|
512
|
-
|
513
|
-
# Removes any points in the baseline outside of 2 sigma (helps remove cosmic rays etc).
|
514
|
-
Baseline=Baseline_with_outl[(Baseline_with_outl[:, 1]<Median_Baseline+sigma_baseline*Std_Baseline)
|
515
|
-
&
|
516
|
-
(Baseline_with_outl[:, 1]>Median_Baseline-sigma_baseline*Std_Baseline)
|
517
|
-
]
|
518
|
-
|
519
|
-
# Fits a polynomial to the baseline of degree
|
520
|
-
Pf_baseline = np.poly1d(np.polyfit(Baseline[:, 0], Baseline[:, 1], N_poly_pk2_baseline))
|
521
|
-
Py_base =Pf_baseline(Ne_short[:, 0])
|
522
|
-
Baseline_ysub=Pf_baseline(Baseline[:, 0])
|
523
|
-
Baseline_x=Baseline[:, 0]
|
524
|
-
Baseline_y=Baseline[:, 1]
|
525
|
-
y_corr= Ne_short[:, 1]- Py_base
|
526
|
-
x=Ne_short[:, 0]
|
527
|
-
|
528
|
-
|
529
|
-
return y_corr, Py_base, x, Ne_short, Py_base, Baseline_y, Baseline_x
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
def fit_pk1(x, y_corr, x_span=[-10, 8], Ne_center=1117.1, amplitude=98, pk1_sigma=0.28,
|
536
|
-
LH_offset_mini=[1.5, 3], peaks_pk1=2, model_name='PseudoVoigtModel', block_print=True,
|
537
|
-
const_params=True, spec_res=0.4) :
|
538
|
-
""" This function fits the 1117 Ne line as 1 or two voigt peaks
|
539
|
-
|
540
|
-
Parameters
|
541
|
-
-----------
|
542
|
-
|
543
|
-
x: np.array
|
544
|
-
x coordinate (wavenumber)
|
545
|
-
|
546
|
-
y: np.array
|
547
|
-
Background corrected intensiy
|
548
|
-
|
549
|
-
x_span: list length 2. Default [-10, 8]
|
550
|
-
Span either side of peak center used for fitting,
|
551
|
-
e.g. by default, fits to 10 wavenumbers below peak, 8 above.
|
552
|
-
|
553
|
-
Ne_center: float (default=1117.1)
|
554
|
-
Center position for Ne line being fitted
|
555
|
-
|
556
|
-
amplitude: integer (default = 98)
|
557
|
-
peak amplitude
|
558
|
-
|
559
|
-
sigma: float (default =0.28)
|
560
|
-
sigma of the voigt peak
|
561
|
-
|
562
|
-
peaks_pk1: integer
|
563
|
-
number of peaks to fit, e.g. 1, single voigt, 2 to get shoulder peak
|
564
|
-
|
565
|
-
LH_offset_mini: list length 2
|
566
|
-
Forces second peak to be within -1.5 to -3 from the main peak position.
|
567
|
-
|
568
|
-
print_report: bool
|
569
|
-
if True, prints fit report.
|
570
|
-
|
571
|
-
|
572
|
-
"""
|
573
|
-
if const_params is True:
|
574
|
-
min_off=0.8
|
575
|
-
max_off=1.2
|
576
|
-
if const_params is False:
|
577
|
-
min_off=0
|
578
|
-
max_off=100
|
579
|
-
|
580
|
-
# Flatten x and y if needed
|
581
|
-
xdat=x.flatten()
|
582
|
-
ydat=y_corr.flatten()
|
583
|
-
|
584
|
-
# This defines the range you want to fit (e.g. how big the tails are)
|
585
|
-
lower_pk1=Ne_center+x_span[0]
|
586
|
-
upper_pk1=Ne_center+x_span[1]
|
587
|
-
|
588
|
-
# This segments into the x and y variable, and variables to plot, which are a bit bigger.
|
589
|
-
Ne_pk1_reg_x=x[(x>lower_pk1)&(x<upper_pk1)]
|
590
|
-
Ne_pk1_reg_y=y_corr[(x>lower_pk1)&(x<upper_pk1)]
|
591
|
-
Ne_pk1_reg_x_plot=x[(x>(lower_pk1-3))&(x<(upper_pk1+3))]
|
592
|
-
Ne_pk1_reg_y_plot=y_corr[(x>(lower_pk1-3))&(x<(upper_pk1+3))]
|
593
|
-
|
594
|
-
if peaks_pk1>1:
|
595
|
-
|
596
|
-
# Setting up lmfit
|
597
|
-
if model_name == 'PseudoVoigtModel':
|
598
|
-
model0 = PseudoVoigtModel(prefix='p0_')#+ ConstantModel(prefix='c0')
|
599
|
-
if model_name=="VoigtModel":
|
600
|
-
model0 = VoigtModel(prefix='p0_')#+ ConstantModel(prefix='c0')
|
601
|
-
pars0 = model0.make_params(p0_center=Ne_center, p0_amplitude=amplitude)
|
602
|
-
init0 = model0.eval(pars0, x=xdat)
|
603
|
-
result0 = model0.fit(ydat, pars0, x=xdat)
|
604
|
-
Center_p0=result0.best_values.get('p0_center')
|
605
|
-
if block_print is False:
|
606
|
-
print('first iteration, peak Center='+str(np.round(Center_p0, 4)))
|
607
|
-
|
608
|
-
Center_p0_error=result0.params.get('p0_center')
|
609
|
-
Amp_p0=result0.params.get('p0_amplitude')
|
610
|
-
if block_print is False:
|
611
|
-
print('first iteration, peak Amplitude='+str(np.round(Amp_p0, 4)))
|
612
|
-
fwhm_p0=result0.params.get('p0_fwhm')
|
613
|
-
Center_p0_errorval=float(str(Center_p0_error).split()[4].replace(",", ""))
|
614
|
-
|
615
|
-
#Ne_center=Ne_center
|
616
|
-
#rough_peak_positions=Ne_center-2
|
617
|
-
if model_name == 'PseudoVoigtModel':
|
618
|
-
model1 = PseudoVoigtModel(prefix='p1_')#+ ConstantModel(prefix='c0')
|
619
|
-
if model_name=="VoigtModel":
|
620
|
-
model1 = VoigtModel(prefix='p1_')#+ ConstantModel(prefix='c0')
|
621
|
-
pars1 = model1.make_params()
|
622
|
-
pars1['p1_'+ 'amplitude'].set(Amp_p0, min=min_off*Amp_p0, max=max_off*Amp_p0)
|
623
|
-
pars1['p1_'+ 'center'].set(Center_p0, min=Center_p0-0.2, max=Center_p0+0.2)
|
624
|
-
pars1['p1_'+ 'sigma'].set(pk1_sigma, min=pk1_sigma*min_off, max=pk1_sigma*max_off)
|
625
|
-
|
626
|
-
|
627
|
-
# Second wee peak
|
628
|
-
prefix='p2_'
|
629
|
-
if model_name == 'PseudoVoigtModel':
|
630
|
-
peak = PseudoVoigtModel(prefix='p2_')#+ ConstantModel(prefix='c0')
|
631
|
-
if model_name=="VoigtModel":
|
632
|
-
peak = VoigtModel(prefix='p2_')#+ ConstantModel(prefix='c0')
|
633
|
-
|
634
|
-
|
635
|
-
pars = peak.make_params()
|
636
|
-
minp2=Center_p0-LH_offset_mini[1]
|
637
|
-
maxp2=Center_p0-LH_offset_mini[0]
|
638
|
-
if block_print is False:
|
639
|
-
print('Trying to place second peak between '+str(np.round(minp2, 2))+'and'+ str(np.round(maxp2, 2)))
|
640
|
-
pars[prefix + 'center'].set(Center_p0, min=minp2,
|
641
|
-
max=maxp2)
|
642
|
-
|
643
|
-
pars['p2_'+ 'fwhm'].set(fwhm_p0/2, min=0.001, max=fwhm_p0*5)
|
644
|
-
|
645
|
-
|
646
|
-
pars[prefix + 'amplitude'].set(Amp_p0/5, min=0, max=Amp_p0/2)
|
647
|
-
pars[prefix + 'sigma'].set(0.2, min=0)
|
648
|
-
|
649
|
-
model_combo=model1+peak
|
650
|
-
pars1.update(pars)
|
651
|
-
|
652
|
-
|
653
|
-
if peaks_pk1==1:
|
654
|
-
|
655
|
-
if model_name == 'PseudoVoigtModel':
|
656
|
-
model_combo = PseudoVoigtModel(prefix='p1_')#+ ConstantModel(prefix='c0')
|
657
|
-
if model_name=="VoigtModel":
|
658
|
-
model_combo= VoigtModel(prefix='p1_')#+ ConstantModel(prefix='c0')
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
# create parameters with initial values
|
663
|
-
pars1 = model_combo.make_params(amplitude=amplitude)
|
664
|
-
pars1['p1_' + 'center'].set(Ne_center, min=Ne_center-2*spec_res,max=Ne_center+2*spec_res)
|
665
|
-
pars1['p1_'+ 'sigma'].set(pk1_sigma, min=pk1_sigma*min_off, max=pk1_sigma*max_off)
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
init = model_combo.eval(pars1, x=xdat)
|
674
|
-
result = model_combo.fit(ydat, pars1, x=xdat)
|
675
|
-
# Need to check errors output
|
676
|
-
Error_bars=result.errorbars
|
677
|
-
|
678
|
-
|
679
|
-
# Get center value
|
680
|
-
Center_p1=result.best_values.get('p1_center')
|
681
|
-
Center_p1_error=result.params.get('p1_center')
|
682
|
-
|
683
|
-
# Get mix of lorenz
|
684
|
-
Peak1_Prop_Lor=result.best_values.get('p1_fraction')
|
685
|
-
|
686
|
-
|
687
|
-
if peaks_pk1==1:
|
688
|
-
Center_pk1=Center_p1
|
689
|
-
if Error_bars is False:
|
690
|
-
if block_print is False:
|
691
|
-
print('Error bars not determined by function')
|
692
|
-
error_pk1=np.nan
|
693
|
-
else:
|
694
|
-
error_pk1 = float(str(Center_p1_error).split()[4].replace(",", ""))
|
695
|
-
|
696
|
-
|
697
|
-
if peaks_pk1>1:
|
698
|
-
Center_p2=result.best_values.get('p2_center')
|
699
|
-
Center_p2_error=result.params.get('p2_center')
|
700
|
-
|
701
|
-
|
702
|
-
if Error_bars is False:
|
703
|
-
if block_print is False:
|
704
|
-
print('Error bars not determined by function')
|
705
|
-
Center_p1_errorval=np.nan
|
706
|
-
if peaks_pk1>1:
|
707
|
-
Center_p2_errorval=np.nan
|
708
|
-
else:
|
709
|
-
Center_p1_errorval=float(str(Center_p1_error).split()[4].replace(",", ""))
|
710
|
-
if peaks_pk1>1:
|
711
|
-
Center_p2_errorval=float(str(Center_p2_error).split()[4].replace(",", ""))
|
712
|
-
|
713
|
-
# Check if nonsense, e.g. if center 2 miles away, just use center 0
|
714
|
-
if Center_p2 is not None:
|
715
|
-
if Center_p2>Center_p0 or Center_p2<1112:
|
716
|
-
Center_pk1=Center_p0
|
717
|
-
error_pk1=Center_p0_errorval
|
718
|
-
if block_print is False:
|
719
|
-
print('No meaningful second peak found')
|
720
|
-
|
721
|
-
elif Center_p1 is None and Center_p2 is None:
|
722
|
-
if block_print is False:
|
723
|
-
print('No peaks found')
|
724
|
-
elif Center_p1 is None and Center_p2>0:
|
725
|
-
Center_pk1=Center_p2
|
726
|
-
error_pk1=Center_p2_errorval
|
727
|
-
elif Center_p2 is None and Center_p1>0:
|
728
|
-
Center_pk1=Center_p1
|
729
|
-
error_pk1=Center_p1_errorval
|
730
|
-
elif Center_p1>Center_p2:
|
731
|
-
Center_pk1=Center_p1
|
732
|
-
error_pk1=Center_p1_errorval
|
733
|
-
elif Center_p1<Center_p2:
|
734
|
-
Center_pk1=Center_p2
|
735
|
-
error_pk1=Center_p2_errorval
|
736
|
-
|
737
|
-
Area_pk1=result.best_values.get('p1_amplitude')
|
738
|
-
sigma_pk1=result.best_values.get('p1_sigma')
|
739
|
-
gamma_pk1=result.best_values.get('p1_gamma')
|
740
|
-
|
741
|
-
|
742
|
-
# Evaluate the peak at 100 values for pretty plotting
|
743
|
-
xx_pk1=np.linspace(lower_pk1, upper_pk1, 2000)
|
744
|
-
|
745
|
-
result_pk1=result.eval(x=xx_pk1)
|
746
|
-
comps=result.eval_components(x=xx_pk1)
|
747
|
-
|
748
|
-
|
749
|
-
result_pk1_origx=result.eval(x=Ne_pk1_reg_x)
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
return Center_pk1, Area_pk1, sigma_pk1, gamma_pk1, Ne_pk1_reg_x_plot, Ne_pk1_reg_y_plot, Ne_pk1_reg_x, Ne_pk1_reg_y, xx_pk1, result_pk1, error_pk1, result_pk1_origx, comps, Peak1_Prop_Lor
|
754
|
-
|
755
|
-
|
756
|
-
def fit_pk2(x, y_corr, x_span=[-5, 5], Ne_center=1447.5, amplitude=1000, pk2_sigma=0.4,
|
757
|
-
model_name='PseudoVoigtModel', print_report=False, const_params=True) :
|
758
|
-
""" This function fits the 1447 Ne line as a single Voigt
|
759
|
-
|
760
|
-
Parameters
|
761
|
-
-----------
|
762
|
-
|
763
|
-
x: np.array
|
764
|
-
x coordinate (wavenumber)
|
765
|
-
|
766
|
-
y: np.array
|
767
|
-
Background corrected intensiy
|
768
|
-
|
769
|
-
x_span: list length 2. Default [-5, 5]
|
770
|
-
Span either side of peak center used for fitting,
|
771
|
-
e.g. by default, fits to 5 wavenumbers below peak, 5 above.
|
772
|
-
|
773
|
-
Ne_center: float (default=1447.5)
|
774
|
-
Center position for Ne line being fitted
|
775
|
-
|
776
|
-
amplitude: integer (default = 1000)
|
777
|
-
peak amplitude
|
778
|
-
|
779
|
-
sigma: float (default =0.28)
|
780
|
-
sigma of the voigt peak
|
781
|
-
|
782
|
-
|
783
|
-
print_report: bool
|
784
|
-
if True, prints fit report.
|
785
|
-
|
786
|
-
|
787
|
-
"""
|
788
|
-
if const_params is True:
|
789
|
-
min_off=0.8
|
790
|
-
max_off=1.2
|
791
|
-
if const_params is False:
|
792
|
-
min_off=0
|
793
|
-
max_off=100
|
794
|
-
|
795
|
-
|
796
|
-
# This defines the range you want to fit (e.g. how big the tails are)
|
797
|
-
lower_pk2=Ne_center+x_span[0]
|
798
|
-
upper_pk2=Ne_center+x_span[1]
|
799
|
-
|
800
|
-
# This segments into the x and y variable, and variables to plot, which are a bit bigger.
|
801
|
-
Ne_pk2_reg_x=x[(x>lower_pk2)&(x<upper_pk2)]
|
802
|
-
Ne_pk2_reg_y=y_corr[(x>lower_pk2)&(x<upper_pk2)]
|
803
|
-
Ne_pk2_reg_x_plot=x[(x>(lower_pk2-3))&(x<(upper_pk2+3))]
|
804
|
-
Ne_pk2_reg_y_plot=y_corr[(x>(lower_pk2-3))&(x<(upper_pk2+3))]
|
805
|
-
|
806
|
-
if model_name == 'PseudoVoigtModel':
|
807
|
-
model = PseudoVoigtModel()#+ ConstantModel(prefix='c0')
|
808
|
-
if model_name=="VoigtModel":
|
809
|
-
model = VoigtModel()#+ ConstantModel(prefix='c0')
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
# create parameters with initial values
|
814
|
-
params = model.make_params(center=Ne_center, amplitude=amplitude, sigma=pk2_sigma)
|
815
|
-
|
816
|
-
# Place bounds on center allowed
|
817
|
-
params['center'].min = Ne_center+x_span[0]
|
818
|
-
params['center'].max = Ne_center+x_span[1]
|
819
|
-
params['sigma'].max = pk2_sigma*max_off
|
820
|
-
params['sigma'].min = pk2_sigma*min_off
|
821
|
-
params['amplitude'].max = amplitude*max_off
|
822
|
-
params['amplitude'].min = amplitude*min_off
|
823
|
-
result = model.fit(Ne_pk2_reg_y.flatten(), params, x=Ne_pk2_reg_x.flatten())
|
824
|
-
|
825
|
-
# Get center value
|
826
|
-
Center_pk2=result.best_values.get('center')
|
827
|
-
Center_pk2_error=result.params.get('center')
|
828
|
-
|
829
|
-
Peak2_Prop_Lor=result.best_values.get('fraction')
|
830
|
-
|
831
|
-
#print(result.best_values)
|
832
|
-
|
833
|
-
Area_pk2=result.best_values.get('amplitude')
|
834
|
-
sigma_pk2=result.best_values.get('sigma')
|
835
|
-
gamma_pk2=result.best_values.get('gamma')
|
836
|
-
# Have to strip away the rest of the string, as center + error
|
837
|
-
# print('debug:')
|
838
|
-
# print(Center_pk2_error)
|
839
|
-
# Center_pk2_errorval=float(str(Center_pk2_error).split()[4].replace(",", ""))
|
840
|
-
# error_pk2=Center_pk2_errorval
|
841
|
-
error_pk2=1
|
842
|
-
|
843
|
-
# Evaluate the peak at 100 values for pretty plotting
|
844
|
-
xx_pk2=np.linspace(lower_pk2, upper_pk2, 2000)
|
845
|
-
|
846
|
-
result_pk2=result.eval(x=xx_pk2)
|
847
|
-
result_pk2_origx=result.eval(x=Ne_pk2_reg_x)
|
848
|
-
|
849
|
-
if print_report is True:
|
850
|
-
print(result.fit_report(min_correl=0.5))
|
851
|
-
|
852
|
-
return Center_pk2,Area_pk2, sigma_pk2, gamma_pk2, Ne_pk2_reg_x_plot, Ne_pk2_reg_y_plot, Ne_pk2_reg_x, Ne_pk2_reg_y, xx_pk2, result_pk2, error_pk2, result_pk2_origx, Peak2_Prop_Lor
|
853
|
-
|
854
|
-
## Setting default Ne fitting parameters
|
855
|
-
@dataclass
|
856
|
-
class Ne_peak_config:
|
857
|
-
|
858
|
-
model_name: str = 'PseudoVoigtModel'
|
859
|
-
# Things for the background positioning and fit
|
860
|
-
N_poly_pk1_baseline: float = 1 #Degree of polynomial to fit to the baseline
|
861
|
-
N_poly_pk2_baseline: float = 1 #Degree of polynomial to fit to the baseline
|
862
|
-
sigma_baseline=3 # Discard things outside of this sigma on the baseline
|
863
|
-
lower_bck_pk1: Tuple[float, float] = (-50, -25) # Background position Pk1
|
864
|
-
upper_bck1_pk1: Tuple[float, float] = (8, 15) # Background position Pk1
|
865
|
-
upper_bck2_pk1: Tuple[float, float] = (30, 50) # Background position Pk1
|
866
|
-
lower_bck_pk2: Tuple[float, float] = (-44.2, -22) # Background position Pk2
|
867
|
-
upper_bck1_pk2: Tuple[float, float] = (15, 50) # Background position Pk2
|
868
|
-
upper_bck2_pk2: Tuple[float, float] = (50, 51) # Background position Pk1
|
869
|
-
|
870
|
-
# Whether you want a secondary peak
|
871
|
-
peaks_1: float=2
|
872
|
-
|
873
|
-
# SPlitting
|
874
|
-
DeltaNe_ideal: float= 330.477634
|
875
|
-
|
876
|
-
# Things for plotting the baseline
|
877
|
-
x_range_baseline_pk1: float=20 # How many units outside your selected background it shows on the baseline plot
|
878
|
-
y_range_baseline_pk1: float= 200 # Where the y axis is cut off above the minimum baseline measurement
|
879
|
-
x_range_baseline_pk2: float=20 # How many units outside your selected background it shows on the baseline plot
|
880
|
-
y_range_baseline_pk2: float= 200 # Where the y axis is cut off above the minimum baseline measurement
|
881
|
-
|
882
|
-
|
883
|
-
# Sigma for peaks
|
884
|
-
pk1_sigma: float = 0.4
|
885
|
-
pk2_sigma: float = 0.4
|
886
|
-
|
887
|
-
# Things for plotting the primary peak
|
888
|
-
x_range_peak: float=15 # How many units to each side are shown when plotting the peak fits
|
889
|
-
|
890
|
-
# Things for plotting the residual
|
891
|
-
x_range_residual: float=7 # Shows how many x units to left and right is shown on residual plot
|
892
|
-
|
893
|
-
# Things for fitting a secondary peak on 1117
|
894
|
-
LH_offset_mini: Tuple[float, float] = (1.5, 3)
|
895
|
-
|
896
|
-
# Optional, by default, fits to the points inside the baseline. Can also specify as values to make a smaller peak fit.
|
897
|
-
x_span_pk1: Optional [Tuple[float, float]] = None # Tuple[float, float] = (-10, 8)
|
898
|
-
x_span_pk2: Optional [Tuple[float, float]] = None # Tuple[float, float] = (-5, 5)
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
def fit_Ne_lines(*, config: Ne_peak_config=Ne_peak_config(),
|
903
|
-
Ne_center_1=1117.1, Ne_center_2=1147, Ne_prom_1=100, Ne_prom_2=200,
|
904
|
-
Ne=None, filename=None, path=None, prefix=True,
|
905
|
-
plot_figure=True, loop=True,
|
906
|
-
save_clipboard=False,
|
907
|
-
close_figure=False, const_params=True):
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
""" This function reads in a user file, fits the Ne lines, and if required, saves an image
|
915
|
-
into a new sub folder
|
916
|
-
|
917
|
-
Parameters
|
918
|
-
-----------
|
919
|
-
|
920
|
-
Ne: np.array
|
921
|
-
x coordinate (wavenumber) and y coordinate (intensity)
|
922
|
-
|
923
|
-
filename and path: str
|
924
|
-
used to save filename in datatable, and to make a new folder.
|
925
|
-
|
926
|
-
filetype: str
|
927
|
-
Identifies type of file
|
928
|
-
Witec_ASCII: Datafile from WITEC with metadata for first few lines
|
929
|
-
headless_txt: Txt file with no headers, just data with wavenumber in 1st col, int 2nd
|
930
|
-
HORIBA_txt: Datafile from newer HORIBA machines with metadata in first rows
|
931
|
-
Renishaw_txt: Datafile from renishaw with column headings.
|
932
|
-
|
933
|
-
amplitude: int or float
|
934
|
-
first guess of peak amplitude
|
935
|
-
|
936
|
-
plot_figure: bool
|
937
|
-
if True, saves figure of fit in a new folder
|
938
|
-
|
939
|
-
Loop: bool
|
940
|
-
If True, only returns df.
|
941
|
-
|
942
|
-
x_range_baseline: flt, int
|
943
|
-
How much x range outside selected baseline the baseline selection plot shows.
|
944
|
-
|
945
|
-
y_range_baseline: flt, int
|
946
|
-
How much above the baseline position is shown on the y axis.
|
947
|
-
|
948
|
-
x_range_peak: flt, int, or None
|
949
|
-
How much to either side of the peak to show on the final peak fitting plot
|
950
|
-
|
951
|
-
|
952
|
-
DeltaNe_ideal: float
|
953
|
-
Theoretical distance between the two peaks you have selected. Default is 330.477634 for
|
954
|
-
the 1117 and 1447 Neon for the Cornell Raman. You can calculate this using the calculate_Ne_line_positions
|
955
|
-
|
956
|
-
|
957
|
-
Things for Neon 1 (~1117):
|
958
|
-
|
959
|
-
N_poly_pk1_baseline: int
|
960
|
-
Degree of polynomial used to fit the background
|
961
|
-
|
962
|
-
Ne_center_1: float
|
963
|
-
Center position for Ne line being fitted
|
964
|
-
|
965
|
-
lower_bck_1, upper_bck1, upper_bck1: 3 lists of length 2:
|
966
|
-
Positions used for background relative to peak.[-50, -20] takes a
|
967
|
-
background -50 and -20 from the peak center
|
968
|
-
|
969
|
-
x_span_pk1: list length 2. Default [-10, 8]
|
970
|
-
Span either side of peak center used for fitting,
|
971
|
-
e.g. by default, fits to 10 wavenumbers below peak, 8 above.
|
972
|
-
|
973
|
-
|
974
|
-
peaks_1: int
|
975
|
-
How many peaks to fit to the 1117 Neon, if 2, tries to put a shoulder peak
|
976
|
-
|
977
|
-
LH_offset_mini: list
|
978
|
-
If peaks>1, puts second peak within this range left of the main peak
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
Things for Neon 2 (~1447):
|
984
|
-
N_poly_pk2_baseline: int
|
985
|
-
Degree of polynomial used to fit the background
|
986
|
-
|
987
|
-
Ne_center_2: float
|
988
|
-
Center position for Ne line being fitted
|
989
|
-
|
990
|
-
lower_bck_2, upper_bck2, upper_bck2: 3 lists of length 2:
|
991
|
-
Positions used for background relative to peak.[-50, -20] takes a
|
992
|
-
background -50 and -20 from the peak center
|
993
|
-
|
994
|
-
x_span_pk2: list length 2. Default [-10, 8]
|
995
|
-
Span either side of peak center used for fitting,
|
996
|
-
e.g. by default, fits to 10 wavenumbers below peak, 8 above.
|
997
|
-
"""
|
998
|
-
|
999
|
-
x=Ne[:, 0]
|
1000
|
-
spec_res=np.abs(x[1]-x[0])
|
1001
|
-
# Getting things from config file
|
1002
|
-
peaks_1=config.peaks_1
|
1003
|
-
DeltaNe_ideal=config.DeltaNe_ideal
|
1004
|
-
|
1005
|
-
# Estimate amplitude from prominence and sigma you entered
|
1006
|
-
Pk1_Amp=((config.pk1_sigma)*(Ne_prom_1))/0.3939
|
1007
|
-
Pk2_Amp=((config.pk2_sigma)*(Ne_prom_2))/0.3939
|
1008
|
-
|
1009
|
-
|
1010
|
-
#Remove the baselines
|
1011
|
-
y_corr_pk1, Py_base_pk1, x_pk1, Ne_short_pk1, Py_base_pk1, Baseline_ysub_pk1, Baseline_x_pk1=remove_Ne_baseline_pk1(Ne,
|
1012
|
-
N_poly_pk1_baseline=config.N_poly_pk1_baseline, Ne_center_1=Ne_center_1, sigma_baseline=config.sigma_baseline,
|
1013
|
-
lower_bck=config.lower_bck_pk1, upper_bck1=config.upper_bck1_pk1, upper_bck2=config.upper_bck2_pk1)
|
1014
|
-
|
1015
|
-
y_corr_pk2, Py_base_pk2, x_pk2, Ne_short_pk2, Py_base_pk2, Baseline_ysub_pk2, Baseline_x_pk2=remove_Ne_baseline_pk2(Ne, Ne_center_2=Ne_center_2, N_poly_pk2_baseline=config.N_poly_pk2_baseline, sigma_baseline=config.sigma_baseline,
|
1016
|
-
lower_bck=config.lower_bck_pk2, upper_bck1=config.upper_bck1_pk2, upper_bck2=config.upper_bck2_pk2)
|
1017
|
-
|
1018
|
-
|
1019
|
-
# Have the option to override the xspan here from default. Else, trims
|
1020
|
-
if config.x_span_pk1 is None:
|
1021
|
-
|
1022
|
-
x_span_pk1=[config.lower_bck_pk1[1], config.upper_bck1_pk1[0]]
|
1023
|
-
x_span_pk1_dist=abs(config.lower_bck_pk1[1]-config.upper_bck1_pk1[0])
|
1024
|
-
else:
|
1025
|
-
x_span_pk1=config.x_span_pk1
|
1026
|
-
x_span_pk1_dist=abs(config.x_span_pk1[1]-config.x_span_pk1[0])
|
1027
|
-
|
1028
|
-
if config.x_span_pk2 is None:
|
1029
|
-
x_span_pk2=[config.lower_bck_pk2[1], config.upper_bck1_pk2[0]]
|
1030
|
-
x_span_pk2_dist=abs(config.lower_bck_pk2[1]-config.upper_bck1_pk2[0])
|
1031
|
-
else:
|
1032
|
-
x_span_pk2=config.x_span_pk2
|
1033
|
-
x_span_pk2_dist=abs(config.x_span_pk2[1]-config.x_span_pk2[0])
|
1034
|
-
|
1035
|
-
# Fit the 1117 peak
|
1036
|
-
cent_pk1, Area_pk1, sigma_pk1, gamma_pk1, Ne_pk1_reg_x_plot, Ne_pk1_reg_y_plot, Ne_pk1_reg_x, Ne_pk1_reg_y, xx_pk1, result_pk1, error_pk1, result_pk1_origx, comps, Peak1_Prop_Lor = fit_pk1(x_pk1, y_corr_pk1, x_span=x_span_pk1, Ne_center=Ne_center_1,model_name=config.model_name, LH_offset_mini=config.LH_offset_mini, peaks_pk1=peaks_1, amplitude=Pk1_Amp, pk1_sigma=config.pk1_sigma,
|
1037
|
-
const_params=const_params, spec_res=spec_res)
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
# Fit the 1447 peak
|
1042
|
-
cent_pk2,Area_pk2, sigma_pk2, gamma_pk2, Ne_pk2_reg_x_plot, Ne_pk2_reg_y_plot, Ne_pk2_reg_x, Ne_pk2_reg_y, xx_pk2, result_pk2, error_pk2, result_pk2_origx, Peak2_Prop_Lor = fit_pk2( x_pk2, y_corr_pk2, x_span=x_span_pk2, Ne_center=Ne_center_2, model_name=config.model_name, amplitude=Pk2_Amp, pk2_sigma=config.pk2_sigma, const_params=const_params)
|
1043
|
-
|
1044
|
-
|
1045
|
-
# Calculate difference between peak centers, and Delta Ne
|
1046
|
-
DeltaNe=cent_pk2-cent_pk1
|
1047
|
-
|
1048
|
-
Ne_Corr=DeltaNe_ideal/DeltaNe
|
1049
|
-
|
1050
|
-
# Calculate maximum splitting (+1 sigma)
|
1051
|
-
DeltaNe_max=(cent_pk2+error_pk2)-(cent_pk1-error_pk1)
|
1052
|
-
DeltaNe_min=(cent_pk2-error_pk2)-(cent_pk1+error_pk1)
|
1053
|
-
Ne_Corr_max=DeltaNe_ideal/DeltaNe_min
|
1054
|
-
Ne_Corr_min=DeltaNe_ideal/DeltaNe_max
|
1055
|
-
|
1056
|
-
# Calculating least square residual
|
1057
|
-
residual_pk1=np.sum(((Ne_pk1_reg_y-result_pk1_origx)**2)**0.5)/(len(Ne_pk1_reg_y))
|
1058
|
-
residual_pk2=np.sum(((Ne_pk2_reg_y-result_pk2_origx)**2)**0.5)/(len(Ne_pk2_reg_y))
|
1059
|
-
|
1060
|
-
if plot_figure is True:
|
1061
|
-
# Make a summary figure of the backgrounds and fits
|
1062
|
-
fig, ((ax3, ax2), (ax5, ax4), (ax1, ax0)) = plt.subplots(3,2, figsize = (12,15)) # adjust dimensions of figure here
|
1063
|
-
fig.suptitle(filename, fontsize=16)
|
1064
|
-
|
1065
|
-
# Setting y limits of axis
|
1066
|
-
ymin_ax1=min(Ne_short_pk1[:,1])-10
|
1067
|
-
ymax_ax1=min(Ne_short_pk1[:,1])+config.y_range_baseline_pk1
|
1068
|
-
ymin_ax0=min(Ne_short_pk2[:,1])-10
|
1069
|
-
ymax_ax0=min(Ne_short_pk2[:,1])+config.y_range_baseline_pk2
|
1070
|
-
ax1.set_ylim([ymin_ax1, ymax_ax1])
|
1071
|
-
ax0.set_ylim([ymin_ax0, ymax_ax0])
|
1072
|
-
|
1073
|
-
# Setting x limits of axis
|
1074
|
-
|
1075
|
-
ax1_xmin=min(Ne_short_pk1[:,0])-config.x_range_baseline_pk1
|
1076
|
-
ax1_xmax=max(Ne_short_pk1[:,0])+config.x_range_baseline_pk1
|
1077
|
-
ax0_xmin=min(Ne_short_pk2[:,0])-config.x_range_baseline_pk2
|
1078
|
-
ax0_xmax=max(Ne_short_pk2[:,0])+config.x_range_baseline_pk2
|
1079
|
-
ax0.set_xlim([ax0_xmin, ax0_xmax])
|
1080
|
-
ax1.set_xlim([ax1_xmin, ax1_xmax])
|
1081
|
-
|
1082
|
-
# Adding background positions as colored bars on pk1
|
1083
|
-
ax1cop=ax1.twiny()
|
1084
|
-
#ax1cop.set_zorder(ax1.get_zorder())
|
1085
|
-
ax1cop_xmax=ax1_xmax-Ne_center_1
|
1086
|
-
ax1cop_xmin=ax1_xmin-Ne_center_1
|
1087
|
-
ax1cop.set_xlim([ax1cop_xmin, ax1cop_xmax])
|
1088
|
-
rect_pk1_b1=patches.Rectangle((config.lower_bck_pk1[0],ymin_ax1),config.lower_bck_pk1[1]-config.lower_bck_pk1[0],ymax_ax1-ymin_ax1,
|
1089
|
-
linewidth=1,edgecolor='none',facecolor='cyan', label='bck_pk1', alpha=0.3, zorder=0)
|
1090
|
-
ax1cop.add_patch(rect_pk1_b1)
|
1091
|
-
rect_pk1_b2=patches.Rectangle((config.upper_bck1_pk1[0],ymin_ax1),config.upper_bck1_pk1[1]-config.upper_bck1_pk1[0],ymax_ax1-ymin_ax1,
|
1092
|
-
linewidth=1,edgecolor='none',facecolor='cyan', label='bck_pk2', alpha=0.3, zorder=0)
|
1093
|
-
ax1cop.add_patch(rect_pk1_b2)
|
1094
|
-
rect_pk1_b3=patches.Rectangle((config.upper_bck2_pk1[0],ymin_ax1),config.upper_bck2_pk1[1]-config.upper_bck2_pk1[0],ymax_ax1-ymin_ax1,
|
1095
|
-
linewidth=1,edgecolor='none',facecolor='cyan', label='bck_pk3', alpha=0.3, zorder=0)
|
1096
|
-
ax1cop.add_patch(rect_pk1_b3)
|
1097
|
-
|
1098
|
-
# Adding background positions as colored bars on pk2
|
1099
|
-
ax0cop=ax0.twiny()
|
1100
|
-
ax0cop_xmax=ax0_xmax-Ne_center_2
|
1101
|
-
ax0cop_xmin=ax0_xmin-Ne_center_2
|
1102
|
-
ax0cop.set_xlim([ax0cop_xmin, ax0cop_xmax])
|
1103
|
-
rect_pk2_b1=patches.Rectangle((config.lower_bck_pk2[0],ymin_ax0),config.lower_bck_pk2[1]-config.lower_bck_pk2[0],ymax_ax0-ymin_ax0,
|
1104
|
-
linewidth=1,edgecolor='none',facecolor='cyan', label='bck_pk2', alpha=0.3)
|
1105
|
-
ax0cop.add_patch(rect_pk2_b1)
|
1106
|
-
rect_pk2_b2=patches.Rectangle((config.upper_bck1_pk2[0],ymin_ax0),config.upper_bck1_pk2[1]-config.upper_bck1_pk2[0],ymax_ax0-ymin_ax0,
|
1107
|
-
linewidth=1,edgecolor='none',facecolor='cyan', label='bck_pk2', alpha=0.3)
|
1108
|
-
ax0cop.add_patch(rect_pk2_b2)
|
1109
|
-
rect_pk2_b3=patches.Rectangle((config.upper_bck2_pk2[0],ymin_ax0),config.upper_bck2_pk2[1]-config.upper_bck2_pk2[0],ymax_ax0-ymin_ax0,
|
1110
|
-
linewidth=1,edgecolor='none',facecolor='cyan', label='bck_pk3', alpha=0.3)
|
1111
|
-
ax0cop.add_patch(rect_pk2_b3)
|
1112
|
-
|
1113
|
-
# Plotting trimmed data and background
|
1114
|
-
ax0.plot(Ne_short_pk2[:,0], Py_base_pk2, '-k', label='Fit. Bck')
|
1115
|
-
ax0.plot(Ne_short_pk2[:,0], Ne_short_pk2[:,1], '-r')
|
1116
|
-
|
1117
|
-
ax1.plot(Ne_short_pk1[:,0], Py_base_pk1, '-k', label='Fit. Bck')
|
1118
|
-
ax1.plot(Ne_short_pk1[:,0], Ne_short_pk1[:,1], '-r')
|
1119
|
-
|
1120
|
-
# Plotting data actually used in the background, after sigma exclusion
|
1121
|
-
ax1.plot(Baseline_x_pk1, Baseline_ysub_pk1, '.b', ms=6, label='Bck')
|
1122
|
-
ax0.plot(Baseline_x_pk2, Baseline_ysub_pk2, '.b', ms=5, label='Bck')
|
1123
|
-
|
1124
|
-
|
1125
|
-
mean_baseline=np.mean(Py_base_pk2)
|
1126
|
-
std_baseline=np.std(Py_base_pk2)
|
1127
|
-
|
1128
|
-
std_baseline=np.std(Py_base_pk1)
|
1129
|
-
|
1130
|
-
|
1131
|
-
ax1.plot([Ne_center_1, Ne_center_1], [ymin_ax1, ymax_ax1], ':k', label='Peak')
|
1132
|
-
ax0.plot([Ne_center_2, Ne_center_2], [ymin_ax0, ymax_ax0], ':k', label='Peak')
|
1133
|
-
|
1134
|
-
ax1.set_title('%.0f' %Ne_center_1+': background fitting')
|
1135
|
-
ax1.set_xlabel('Wavenumber')
|
1136
|
-
ax1.set_ylabel('Intensity')
|
1137
|
-
ax0.set_title('%.0f' %Ne_center_2+ ': background fitting')
|
1138
|
-
ax0.set_xlabel('Wavenumber')
|
1139
|
-
ax0.set_ylabel('Intensity')
|
1140
|
-
ax1cop.set_xlabel('Offset from Pk estimate')
|
1141
|
-
ax0cop.set_xlabel('Offset from Pk estimate')
|
1142
|
-
|
1143
|
-
#Showing all data, not just stuff fit
|
1144
|
-
|
1145
|
-
|
1146
|
-
ax0.plot(Ne[:,0], Ne[:,1], '-', color='grey', zorder=0)
|
1147
|
-
ax1.plot(Ne[:,0], Ne[:,1], '-', color='grey', zorder=0)
|
1148
|
-
|
1149
|
-
|
1150
|
-
|
1151
|
-
# ax1.legend()
|
1152
|
-
# ax0.legend()
|
1153
|
-
ax0.legend(loc='lower right', bbox_to_anchor= (-0.08, 0.8), ncol=1,
|
1154
|
-
borderaxespad=0, frameon=True, facecolor='white')
|
1155
|
-
|
1156
|
-
# Actual peak fits.
|
1157
|
-
ax2.plot(Ne_pk2_reg_x_plot, Ne_pk2_reg_y_plot, 'xb', label='all data')
|
1158
|
-
ax2.plot(Ne_pk2_reg_x, Ne_pk2_reg_y, 'ok', label='data fitted')
|
1159
|
-
ax2.plot(xx_pk2, result_pk2, 'r-', label='interpolated fit')
|
1160
|
-
ax2.set_title('%.0f' %Ne_center_2+' peak fitting')
|
1161
|
-
ax2.set_xlabel('Wavenumber')
|
1162
|
-
ax2.set_ylabel('Intensity')
|
1163
|
-
if config.x_range_peak is None:
|
1164
|
-
ax2.set_xlim([cent_pk2-x_span_pk2_dist/2, cent_pk2+x_span_pk2_dist/2])
|
1165
|
-
else:
|
1166
|
-
ax2.set_xlim([cent_pk2-config.x_range_peak, cent_pk2+config.x_range_peak])
|
1167
|
-
|
1168
|
-
|
1169
|
-
ax3.plot(Ne_pk1_reg_x_plot, Ne_pk1_reg_y_plot, 'xb', label='all data')
|
1170
|
-
ax3.plot(Ne_pk1_reg_x, Ne_pk1_reg_y, 'ok', label='data fitted')
|
1171
|
-
|
1172
|
-
ax3.set_title('%.0f' %Ne_center_1+' peak fitting')
|
1173
|
-
ax3.set_xlabel('Wavenumber')
|
1174
|
-
ax3.set_ylabel('Intensity')
|
1175
|
-
ax3.plot(xx_pk1, comps.get('p1_'), '-r', label='p1')
|
1176
|
-
if peaks_1>1:
|
1177
|
-
ax3.plot(xx_pk1, comps.get('p2_'), '-c', label='p2')
|
1178
|
-
ax3.plot(xx_pk1, result_pk1, 'g-', label='best fit')
|
1179
|
-
ax3.legend()
|
1180
|
-
if config.x_range_peak is None:
|
1181
|
-
ax3.set_xlim([cent_pk1-x_span_pk1_dist/2, cent_pk1+x_span_pk1_dist/2])
|
1182
|
-
else:
|
1183
|
-
ax3.set_xlim([cent_pk1-config.x_range_peak, cent_pk1+config.x_range_peak ])
|
1184
|
-
|
1185
|
-
# Residuals for peak fits.
|
1186
|
-
ax4.plot(Ne_pk2_reg_x, Ne_pk2_reg_y-result_pk2_origx, '-r', label='residual')
|
1187
|
-
ax5.plot(Ne_pk1_reg_x, Ne_pk1_reg_y-result_pk1_origx, '-r', label='residual')
|
1188
|
-
ax4.plot(Ne_pk2_reg_x, Ne_pk2_reg_y-result_pk2_origx, 'ok', mfc='r', label='residual')
|
1189
|
-
ax5.plot(Ne_pk1_reg_x, Ne_pk1_reg_y-result_pk1_origx, 'ok', mfc='r', label='residual')
|
1190
|
-
ax4.set_ylabel('Residual (Intensity units)')
|
1191
|
-
ax4.set_xlabel('Wavenumber')
|
1192
|
-
ax5.set_ylabel('Residual (Intensity units)')
|
1193
|
-
ax5.set_xlabel('Wavenumber')
|
1194
|
-
Residual_pk2=Ne_pk2_reg_y-result_pk2_origx
|
1195
|
-
Residual_pk1=Ne_pk1_reg_y-result_pk1_origx
|
1196
|
-
|
1197
|
-
Local_Residual_pk2=Residual_pk2[(Ne_pk2_reg_x>cent_pk2-config.x_range_residual)&(Ne_pk2_reg_x<cent_pk2+config.x_range_residual)]
|
1198
|
-
Local_Residual_pk1=Residual_pk1[(Ne_pk1_reg_x>cent_pk1-config.x_range_residual)&(Ne_pk1_reg_x<cent_pk1+config.x_range_residual)]
|
1199
|
-
ax5.set_xlim([cent_pk1-config.x_range_residual, cent_pk1+config.x_range_residual])
|
1200
|
-
ax4.set_xlim([cent_pk2-config.x_range_residual, cent_pk2+config.x_range_residual])
|
1201
|
-
ax5.plot([cent_pk1, cent_pk1 ], [np.min(Local_Residual_pk1)-10, np.max(Local_Residual_pk1)+10], ':k')
|
1202
|
-
ax4.plot([cent_pk2, cent_pk2 ], [np.min(Local_Residual_pk2)-10, np.max(Local_Residual_pk2)+10], ':k')
|
1203
|
-
ax5.set_ylim([np.min(Local_Residual_pk1)-10, np.max(Local_Residual_pk1)+10])
|
1204
|
-
ax4.set_ylim([np.min(Local_Residual_pk2)-10, np.max(Local_Residual_pk2)+10])
|
1205
|
-
fig.tight_layout()
|
1206
|
-
|
1207
|
-
# Save figure
|
1208
|
-
path3=path+'/'+'Ne_fit_images'
|
1209
|
-
if os.path.exists(path3):
|
1210
|
-
out='path exists'
|
1211
|
-
else:
|
1212
|
-
os.makedirs(path+'/'+ 'Ne_fit_images', exist_ok=False)
|
1213
|
-
|
1214
|
-
figure_str=path+'/'+ 'Ne_fit_images'+ '/'+ filename+str('_Ne_Line_Fit')+str('.png')
|
1215
|
-
|
1216
|
-
fig.savefig(figure_str, dpi=200)
|
1217
|
-
if close_figure is True:
|
1218
|
-
plt.close(fig)
|
1219
|
-
|
1220
|
-
if prefix is True:
|
1221
|
-
|
1222
|
-
filename=filename.split(' ')[1:][0]
|
1223
|
-
df=pd.DataFrame(data={'filename': filename,
|
1224
|
-
'pk2_peak_cent':cent_pk2,
|
1225
|
-
'pk2_amplitude': Area_pk2,
|
1226
|
-
'pk2_sigma': sigma_pk2,
|
1227
|
-
'pk2_gamma': gamma_pk2,
|
1228
|
-
'error_pk2': error_pk2,
|
1229
|
-
'Peak2_Prop_Lor': Peak2_Prop_Lor,
|
1230
|
-
'pk1_peak_cent':cent_pk1,
|
1231
|
-
'pk1_amplitude': Area_pk1,
|
1232
|
-
'pk1_sigma': sigma_pk1,
|
1233
|
-
'pk1_gamma': gamma_pk1,
|
1234
|
-
'error_pk1': error_pk1,
|
1235
|
-
'Peak1_Prop_Lor': Peak1_Prop_Lor,
|
1236
|
-
|
1237
|
-
'deltaNe': DeltaNe,
|
1238
|
-
'Ne_Corr': Ne_Corr,
|
1239
|
-
'Ne_Corr_min':Ne_Corr_min,
|
1240
|
-
'Ne_Corr_max': Ne_Corr_max,
|
1241
|
-
'residual_pk2':residual_pk2,
|
1242
|
-
'residual_pk1': residual_pk1,
|
1243
|
-
'residual_pk1+pk2':residual_pk1+residual_pk2,
|
1244
|
-
}, index=[0])
|
1245
|
-
if save_clipboard is True:
|
1246
|
-
df.to_clipboard(excel=True, header=False, index=False)
|
1247
|
-
|
1248
|
-
if loop is False:
|
1249
|
-
return df, Ne_pk1_reg_x_plot, Ne_pk1_reg_y_plot
|
1250
|
-
if loop is True:
|
1251
|
-
return df
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
## Plot to help inspect which Ne lines to discard
|
1256
|
-
def plot_Ne_corrections(df=None, x_axis=None, x_label='index', marker='o', mec='k',
|
1257
|
-
mfc='r'):
|
1258
|
-
if x_axis is not None:
|
1259
|
-
x=x_axis
|
1260
|
-
else:
|
1261
|
-
x=df.index
|
1262
|
-
fig, ((ax5, ax6), (ax1, ax2), (ax3, ax4), ) = plt.subplots(3, 2, figsize=(10, 12))
|
1263
|
-
ax1.plot(x, df['Ne_Corr'], marker, mec='k', mfc='grey')
|
1264
|
-
ax1.set_ylabel('Ne Correction factor')
|
1265
|
-
ax1.set_xlabel(x_label)
|
1266
|
-
|
1267
|
-
ax5.plot(x, df['pk1_peak_cent'], marker, mec='k', mfc='b')
|
1268
|
-
ax6.plot(x, df['pk2_peak_cent'], marker, mec='k', mfc='r')
|
1269
|
-
ax5.set_xlabel(x_label)
|
1270
|
-
ax6.set_xlabel(x_label)
|
1271
|
-
ax5.set_ylabel('Peak 1 center')
|
1272
|
-
ax6.set_ylabel('Peak 2 center')
|
1273
|
-
|
1274
|
-
|
1275
|
-
ax2.plot( df['residual_pk2']+df['residual_pk1'], df['Ne_Corr'], marker, mec='k', mfc='r')
|
1276
|
-
ax2.set_xlabel('Sum of pk1 and pk2 residual')
|
1277
|
-
ax2.set_ylabel('Ne Correction factor')
|
1278
|
-
|
1279
|
-
ax3.plot(df['Ne_Corr'], df['pk2_peak_cent'],marker, mec='k', mfc='r')
|
1280
|
-
ax3.set_xlabel('Ne Correction factor')
|
1281
|
-
ax3.set_ylabel('Peak 2 center')
|
1282
|
-
|
1283
|
-
ax4.plot(df['Ne_Corr'], df['pk1_peak_cent'], marker, mec='k', mfc='b')
|
1284
|
-
ax4.set_xlabel('Ne Correction factor')
|
1285
|
-
ax4.set_ylabel('Peak 1 center')
|
1286
|
-
|
1287
|
-
plt.setp(ax3.get_xticklabels(), rotation=30, horizontalalignment='right')
|
1288
|
-
plt.setp(ax4.get_xticklabels(), rotation=30, horizontalalignment='right')
|
1289
|
-
ax1.ticklabel_format(useOffset=False)
|
1290
|
-
ax5.ticklabel_format(useOffset=False)
|
1291
|
-
ax6.ticklabel_format(useOffset=False)
|
1292
|
-
ax2.ticklabel_format(useOffset=False)
|
1293
|
-
ax3.ticklabel_format(useOffset=False)
|
1294
|
-
ax4.ticklabel_format(useOffset=False)
|
1295
|
-
fig.tight_layout()
|
1296
|
-
return fig
|
1297
|
-
|
1298
|
-
## Looping Ne lines
|
1299
|
-
def loop_Ne_lines(*, files, spectra_path, filetype,
|
1300
|
-
config, config_ID_peaks, df_fit_params=None, prefix=False, print_df=False,
|
1301
|
-
plot_figure=True, single_acq=False):
|
1302
|
-
|
1303
|
-
df = pd.DataFrame([])
|
1304
|
-
# This is for repeated acquisition of Ne lines
|
1305
|
-
if single_acq is True:
|
1306
|
-
|
1307
|
-
for i in tqdm(range(0, np.shape(files)[1]-2)):
|
1308
|
-
Ne=np.column_stack((files[:, 0], files[:, i+1]))
|
1309
|
-
filename=str(i)
|
1310
|
-
|
1311
|
-
Ne, df_fit_params=identify_Ne_lines(Ne_array=Ne,
|
1312
|
-
config=config_ID_peaks, print_df=False, plot_figure=False)
|
1313
|
-
|
1314
|
-
|
1315
|
-
data=fit_Ne_lines(Ne=Ne, path=spectra_path,
|
1316
|
-
config=config, prefix=prefix,
|
1317
|
-
Ne_center_1=df_fit_params['Peak1_cent'].iloc[0],
|
1318
|
-
Ne_center_2=df_fit_params['Peak2_cent'].iloc[0],
|
1319
|
-
Ne_prom_1=df_fit_params['Peak1_prom'].iloc[0],
|
1320
|
-
Ne_prom_2=df_fit_params['Peak2_prom'].iloc[0],
|
1321
|
-
plot_figure=plot_figure)
|
1322
|
-
df = pd.concat([df, data], axis=0)
|
1323
|
-
|
1324
|
-
else:
|
1325
|
-
for i in tqdm(range(0, len(files))):
|
1326
|
-
filename=files[i]
|
1327
|
-
|
1328
|
-
Ne, df_fit_params=identify_Ne_lines(path=spectra_path,
|
1329
|
-
filename=filename, filetype=filetype,
|
1330
|
-
config=config_ID_peaks, print_df=False, plot_figure=False)
|
1331
|
-
|
1332
|
-
data=fit_Ne_lines(Ne=Ne, filename=filename,
|
1333
|
-
path=spectra_path, prefix=prefix,
|
1334
|
-
config=config,
|
1335
|
-
Ne_center_1=df_fit_params['Peak1_cent'].iloc[0],
|
1336
|
-
Ne_center_2=df_fit_params['Peak2_cent'].iloc[0],
|
1337
|
-
Ne_prom_1=df_fit_params['Peak1_prom'].iloc[0],
|
1338
|
-
Ne_prom_2=df_fit_params['Peak2_prom'].iloc[0],
|
1339
|
-
plot_figure=plot_figure)
|
1340
|
-
df = pd.concat([df, data], axis=0)
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
#print('working on ' + str(files[i]))
|
1347
|
-
|
1348
|
-
|
1349
|
-
df2=df.reset_index(drop=True)
|
1350
|
-
|
1351
|
-
# Now lets reorder some columns
|
1352
|
-
|
1353
|
-
cols_to_move = ['filename', 'Ne_Corr', 'deltaNe', 'pk2_peak_cent', 'pk1_peak_cent', 'pk2_amplitude', 'pk1_amplitude', 'residual_pk2', 'residual_pk1']
|
1354
|
-
df2 = df2[cols_to_move + [
|
1355
|
-
col for col in df2.columns if col not in cols_to_move]]
|
1356
|
-
|
1357
|
-
|
1358
|
-
return df2
|
1359
|
-
|
1360
|
-
## Regressing Ne lines against time
|
1361
|
-
from scipy.interpolate import interp1d
|
1362
|
-
def reg_Ne_lines_time(df, fit='poly', N_poly=None, spline_fit=None):
|
1363
|
-
"""
|
1364
|
-
Parameters
|
1365
|
-
-----------
|
1366
|
-
df: pd.DataFrame
|
1367
|
-
dataframe of stitched Ne fits and metadata information from WITEC,
|
1368
|
-
must have columns 'sec since midnight' and 'Ne_Corr'
|
1369
|
-
|
1370
|
-
fit: float 'poly', or 'spline'
|
1371
|
-
If 'poly':
|
1372
|
-
N_poly: int, degree of polynomial to fit (1 if linear)
|
1373
|
-
if 'spline':
|
1374
|
-
spline_fit: The string has to be one of:
|
1375
|
-
‘linear’, ‘nearest’, ‘nearest-up’, ‘zero’, ‘slinear’,
|
1376
|
-
‘quadratic’, ‘cubic’, ‘previous’. Look up documentation for interpld
|
1377
|
-
|
1378
|
-
Returns
|
1379
|
-
-----------
|
1380
|
-
figure of fit and data used to make it
|
1381
|
-
Pf: fit model, can be used to evaluate unknown data (only within x range of df for spline fits).
|
1382
|
-
|
1383
|
-
|
1384
|
-
|
1385
|
-
|
1386
|
-
"""
|
1387
|
-
Px=np.linspace(np.min(df['sec since midnight']), np.max(df['sec since midnight']),
|
1388
|
-
101)
|
1389
|
-
if fit=='poly':
|
1390
|
-
Pf = np.poly1d(np.polyfit(df['sec since midnight'], df['Ne_Corr'],
|
1391
|
-
N_poly))
|
1392
|
-
|
1393
|
-
if fit == 'spline':
|
1394
|
-
Pf = interp1d(df['sec since midnight'], df['Ne_Corr'], kind=spline_fit)
|
1395
|
-
|
1396
|
-
Py=Pf(Px)
|
1397
|
-
|
1398
|
-
fig, (ax1) = plt.subplots(1, 1, figsize=(6, 3))
|
1399
|
-
ax1.plot(df['sec since midnight'], df['Ne_Corr'], 'xk')
|
1400
|
-
ax1.plot(Px, Py, '-r')
|
1401
|
-
ax1.set_xlabel('Seconds since midnight')
|
1402
|
-
ax1.set_ylabel('Ne Correction Factor')
|
1403
|
-
|
1404
|
-
ax1.ticklabel_format(useOffset=False)
|
1405
|
-
|
1406
|
-
|
1407
|
-
return Pf, fig
|
1408
|
-
|
1409
|
-
|
1410
|
-
def filter_Ne_Line_neighbours(Corr_factor, number_av=6, offset=0.00005):
|
1411
|
-
Corr_factor_Filt=np.empty(len(Corr_factor), dtype=float)
|
1412
|
-
median_loop=np.empty(len(Corr_factor), dtype=float)
|
1413
|
-
|
1414
|
-
for i in range(0, len(Corr_factor)):
|
1415
|
-
if i<len(Corr_factor)/2: # For first half, do 5 after
|
1416
|
-
median_loop[i]=np.nanmedian(Corr_factor[i:i+number_av])
|
1417
|
-
if i>=len(Corr_factor)/2: # For first half, do 5 after
|
1418
|
-
median_loop[i]=np.nanmedian(Corr_factor[i-number_av:i])
|
1419
|
-
if Corr_factor[i]>(median_loop[i]+offset) or Corr_factor[i]<(median_loop[i]-offset) :
|
1420
|
-
Corr_factor_Filt[i]=np.nan
|
1421
|
-
else:
|
1422
|
-
Corr_factor_Filt[i]=Corr_factor[i]
|
1423
|
-
ds=pd.Series(Corr_factor_Filt)
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
return ds
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
|