2828from pathlib import Path
2929import matplotlib .pyplot as plt
3030import numpy as np
31+ from scipy .optimize import curve_fit
32+ from scipy import interpolate
3133
3234import pyDCONTINPALSSpecSimulator as specSimulator
3335import pyDCONTINPALSInput as userInput
3436
3537def __information__ ():
36- print ("#********************* pyDCONTINPALS 1.01 (20.01 .2021) *********************" )
38+ print ("#********************* pyDCONTINPALS 1.02 (16.03 .2021) *********************" )
3739 print ("#**" )
3840 print ("#** Copyright (C) 2020-2021 Danny Petschke" )
3941 print ("#**" )
@@ -63,6 +65,53 @@ def __licence__():
6365 print ("#**" )
6466 print ("#*************************************************************************************************" )
6567
68+ def gaussian (x = [],amplitude = 1. ,loc = 0. ,scale = 1. ):
69+ return amplitude * np .exp (- 0.5 * ((x - loc )/ scale )** 2 )
70+
71+ def detectPeaks (x = [],y = []):
72+ peak_list = []
73+ peak_list_y = []
74+
75+ der_1st = []
76+ for i in range (0 ,len (y )- 1 ):
77+ der_1st .append ((y [i + 1 ]- y [i ])/ (x [i + 1 ]- x [i ]))
78+
79+ #plt.plot(der_1st,'ro')
80+ #plt.show()
81+
82+ for i in range (0 ,len (der_1st )- 1 ):
83+ p1 = der_1st [i ]
84+ p2 = der_1st [i + 1 ]
85+
86+ if np .abs (p1 - p2 )<= 1e-5 :
87+ continue
88+
89+ if (p1 > 0 and p2 < 0 ) or (p2 > 0 and p1 < 0 ):
90+ peak_list .append (x [i + 1 ])
91+ peak_list_y .append (y [i + 1 ])
92+
93+ return peak_list ,peak_list_y
94+
95+ def multiPeakFit (x = [],y = []):
96+ peak_list_x ,peak_list_y = detectPeaks (x ,y )
97+
98+ results = []
99+ results_uncertainties = []
100+ results_curve = []
101+ results_area = []
102+
103+ for i in range (0 ,len (peak_list_x )):
104+ init_vals = [peak_list_y [i ],peak_list_x [i ],50. ]
105+
106+ best_vals ,covar = curve_fit (gaussian ,x ,y ,p0 = init_vals )
107+
108+ results .append (best_vals )
109+ results_uncertainties .append (np .sqrt (np .diag (covar )))
110+ results_curve .append (gaussian (x ,amplitude = best_vals [0 ],loc = best_vals [1 ],scale = best_vals [2 ]))
111+ results_area .append (sum (gaussian (x ,amplitude = best_vals [0 ],loc = best_vals [1 ],scale = best_vals [2 ])))
112+
113+ return results ,results_uncertainties ,results_curve ,results_area
114+
66115if __name__ == '__main__' :
67116 __information__ ()
68117
@@ -75,15 +124,16 @@ def __licence__():
75124
76125 monoDecayTau = userInput .__tau_monoDecaySpec_in_ps
77126 binWidth_in_ps = userInput .__channelResolutionInPs
78- tauGrid_in_ps = [userInput .__gridTau_start , userInput .__gridTau_stop ]
127+ tauGrid_in_ps = [userInput .__gridTau_start ,userInput .__gridTau_stop ]
79128 gridPoints = userInput .__gridPoints
129+ binFac = userInput .__binFactor
80130
81131 # running demo mode ?
82132 if userInput .__demoMode :
83133 numberOfBins = userInput .__bkgrd_startIndex + userInput .__bkgrd_count + 10 # set to the maximum for demonstration purposes
84134
85- charactLifetimes_in_ps = [160 .0 , 400.0 , 2000 .0 ]
86- contributionOfLifetimes = [0.90 , 0.095 , 0.005 ]
135+ charactLifetimes_in_ps = [180 .0 , 400.0 , 1600 .0 ]
136+ contributionOfLifetimes = [0.30 , 0.50 , 0.20 ]
87137
88138 specdata_sample = specSimulator .generateCompleteLTSpectrum (numberOfComponents = len (charactLifetimes_in_ps ),
89139 binWidth_in_ps = binWidth_in_ps ,
@@ -92,49 +142,110 @@ def __licence__():
92142 numberOfBins = numberOfBins ,
93143 charactLifetimes_in_ps = charactLifetimes_in_ps ,
94144 contributionOfLifetimes = contributionOfLifetimes ,
95- irf_tZero_in_ps = 3500.0 ,
145+ irf_tZero_in_ps = userInput . __t_zero * userInput . __channelResolutionInPs ,
96146 irf_fwhm_in_ps = 230.0 ,
97147 noise = True ,
98148 noiseLevel = 1.0 )
99149
100- specdata_ref = specSimulator .generateCompleteLTSpectrum (numberOfComponents = 1 ,
150+ specdata_ref = specSimulator .generateCompleteLTSpectrum (numberOfComponents = 3 ,
101151 binWidth_in_ps = binWidth_in_ps ,
102152 integralCounts = 5000000 ,
103153 constBkgrdCounts = 5 ,
104154 numberOfBins = numberOfBins ,
105- charactLifetimes_in_ps = [monoDecayTau ],
106- contributionOfLifetimes = [1.0 ],
107- irf_tZero_in_ps = 3500.0 ,
155+ charactLifetimes_in_ps = [userInput . __tau_monoDecaySpec_in_ps ],
156+ contributionOfLifetimes = [1. ],
157+ irf_tZero_in_ps = userInput . __t_zero * userInput . __channelResolutionInPs ,
108158 irf_fwhm_in_ps = 230.0 ,
109159 noise = True ,
110160 noiseLevel = 1.0 )
111161 else :
112- __ ,specdata_sample = np .loadtxt (userInput .__filePathSpec , delimiter = userInput .__specDataDelimiter , skiprows = userInput .__skipRows , unpack = True , dtype = 'float' );
113- __ ,specdata_ref = np .loadtxt (userInput .__filePathRefOrIRFSpec , delimiter = userInput .__refDataDelimiter , skiprows = userInput .__skipRows , unpack = True , dtype = 'float' );
114-
115- numberOfBins = len (specdata_sample )
162+ specdata_sample = np .loadtxt (userInput .__filePathSpec , delimiter = userInput .__specDataDelimiter , skiprows = userInput .__skipRows , unpack = True , dtype = 'float' )
163+
164+ if userInput .__usingRefSpectrum :
165+ specdata_ref = np .loadtxt (userInput .__filePathRefOrIRFSpec , delimiter = userInput .__refDataDelimiter , skiprows = userInput .__skipRows , unpack = True , dtype = 'float' )
166+ else :
167+ specdata_ref = np .zeros (len (specdata_sample ))
168+
169+ spec_rebinned = np .zeros (int (np .ceil (len (specdata_sample )/ binFac )))
170+
171+ i_bin = 0
172+ sum_bins = 0.
173+ for i in range (0 ,len (specdata_sample )):
174+ sum_bins += specdata_sample [i ]
175+ if not i % binFac :
176+ spec_rebinned [i_bin ] = sum_bins
177+ i_bin += 1
178+ sum_bins = 0.
179+
180+ specdata_sample = spec_rebinned
181+
182+ if not userInput .__usingRefSpectrum :
183+ for i in range (len (specdata_ref )):
184+ t = (i - userInput .__t_zero )* binWidth_in_ps
185+
186+ a = 0
187+ for ii in range (len (userInput .__irf_fwhm )):
188+ a += userInput .__irf_intensity [ii ]* np .exp (- 0.5 * ((t - userInput .__irf_t0 [ii ])/ (userInput .__irf_fwhm [ii ]/ 2.3548 ))** 2 )
189+
190+ specdata_ref [i ] = a
191+
192+ irf_rebinned = np .zeros (int (np .ceil (len (specdata_ref )/ binFac )))
193+
194+ i_bin = 0
195+ sum_bins = 0.
196+ for i in range (0 ,len (specdata_ref )):
197+ sum_bins += specdata_ref [i ]
198+ if not i % binFac :
199+ irf_rebinned [i_bin ] = sum_bins
200+ i_bin += 1
201+ sum_bins = 0.
202+
203+ specdata_ref = irf_rebinned
204+
205+ # adjust values to rebinned data ...
206+ binWidth_in_ps *= binFac
207+
208+ roi_start = int (np .ceil (userInput .__roi_start / binFac ))
209+ roi_end = int (np .ceil (userInput .__roi_end / binFac ))
210+
211+ bkgrd_startIndex = int (np .ceil (userInput .__bkgrd_startIndex / binFac ))
212+ bkgrd_count = int (np .ceil (userInput .__bkgrd_count / binFac ))
213+
214+ bkgrd_startIndex -= roi_start + 1
215+
216+ t_zero_chn = int (np .ceil (userInput .__t_zero / binFac ))
217+
218+ spec_data_roi = specdata_sample [roi_start :roi_end ]
219+ irf_data_roi = specdata_ref [roi_start :roi_end ]
220+
221+ numberOfBins = len (spec_data_roi )
116222
117223 # catch general limitations given by CONTIN-PALS
118224 assert numberOfBins <= 4000 and numberOfBins >= 10
119225 assert gridPoints >= 10 and gridPoints <= 100
120226 assert binWidth_in_ps >= 10.0
121227
122- if monoDecayTau == 0.0 :
228+ if not userInput . __usingRefSpectrum :
123229 monoDecayTau = 1E-6
124230
125231 # show the data
126232 fig , ax = plt .subplots ()
127- plt .semilogy (specdata_sample , 'bo' , specdata_ref , 'ro' )
128- ax .set_ylabel ('counts [a.u.]' )
129- ax .set_xlabel ('channel [a.u.]' )
233+
234+ if userInput .__usingRefSpectrum :
235+ plt .semilogy (spec_data_roi / sum (spec_data_roi ), 'bo' , irf_data_roi / sum (irf_data_roi ), 'r-' )
236+ else :
237+ plt .semilogy (spec_data_roi / sum (spec_data_roi ), 'bo' )
238+
239+ ax .set_ylabel ('area normalized counts [a.u.]' )
240+ ax .set_xlabel ('channels [{} ps]' .format (binWidth_in_ps ))
130241 plt .show ()
131242
132243 specSamp = (ctypes .c_int * numberOfBins )()
133244 specRef = (ctypes .c_int * numberOfBins )()
134245
135246 for i in range (numberOfBins ):
136- specSamp [i ] = int (specdata_sample [i ])
137- specRef [i ] = int (specdata_ref [i ])
247+ specSamp [i ] = int (spec_data_roi [i ])
248+ specRef [i ] = int (irf_data_roi [i ])
138249
139250 program = __dllPtr .analyseData
140251 program .restype = ctypes .c_int
@@ -148,8 +259,8 @@ def __licence__():
148259 ctypes .c_double (tauGrid_in_ps [0 ]),
149260 ctypes .c_double (tauGrid_in_ps [1 ]),
150261 ctypes .c_int (gridPoints ),
151- ctypes .c_int (userInput . __bkgrd_startIndex ),
152- ctypes .c_int (userInput . __bkgrd_count ))
262+ ctypes .c_int (bkgrd_startIndex ),
263+ ctypes .c_int (bkgrd_count ))
153264
154265 if not result == 1 :
155266 if result == 0 :
@@ -187,40 +298,89 @@ def __licence__():
187298 m_yerr .restype = ctypes .c_double
188299 m_res .restype = ctypes .c_double
189300
190- x = np .zeros (gridPoints )
191- y = np .zeros (gridPoints )
192- yerr = np .zeros (gridPoints )
301+ x = np .zeros (gridPoints )
302+ y = np .zeros (gridPoints )
303+ yerr = np .zeros (gridPoints )
193304
194- res = np .zeros (numberOfBins )
305+ res = np .zeros (numberOfBins )
195306
196307 # visualize results
197308 for i in range (0 , gridPoints ):
198309 x [i ] = m_x (ctypes .c_int (i ))
199310 y [i ] = m_y (ctypes .c_int (i ))
200311 yerr [i ] = m_yerr (ctypes .c_int (i ))
201312
313+ # fit results to retrieve information ...
314+ results ,uncertainties ,fitData ,intensities = multiPeakFit (x ,y )
315+
202316 for i in range (0 , numberOfBins ):
203317 res [i ] = m_res (ctypes .c_int (i ))
204318
205319 fig , ax = plt .subplots ()
206- plt .errorbar (x , y , yerr = yerr )
320+ plt .errorbar (x ,y ,yerr = yerr ,marker = 's' ,mfc = 'red' ,mec = 'blue' , ms = 2 , mew = 4 ,label = "CONTIN-PALS results" )
321+
322+ for i in range (0 ,len (fitData )):
323+ plt .plot (x ,fitData [i ],'r--' ,lw = 1 ,label = 'Gaussian fit at {} ps' .format (results [i ][1 ]))
324+
325+ x_v = [results [i ][1 ],results [i ][1 ]]
326+ y_v = [0 ,results [i ][0 ]]
327+
328+ plt .plot (x_v ,y_v ,'r-' ,lw = 2 )
207329
208330 # running demo mode ?
209331 if userInput .__demoMode :
210332 for xc in charactLifetimes_in_ps :
211333 plt .axvline (x = xc , color = 'k' , linestyle = '--' )
212334
213- ax .set_ylabel ('intensity [a.u.]' )
335+ ax .set_ylabel ('intensity pdf [a.u.]' )
214336 ax .set_xlabel ('characteristic lifetimes [ps]' )
337+ plt .legend (loc = 'best' )
215338 plt .show ()
216339
217340 fig , ax = plt .subplots ()
218- plt .plot (res , 'ro' )
341+ plt .plot (res ,'ro' ,label = "error normalized residuals" )
342+ plt .legend (loc = 'best' )
219343
220- hlines = [- 2 , 0 , 2 ]
344+ hlines = [- 4 , - 2 , 0 , 2 , 4 ]
221345 for yc in hlines :
222346 plt .axhline (y = yc , color = 'k' , linestyle = '--' )
223347
224348 ax .set_ylabel ('confidence level [sigma]' )
225- ax .set_xlabel ('channel [a.u.]' )
226- plt .show ()
349+ ax .set_xlabel ('channels [{} ps]' .format (binWidth_in_ps ))
350+ ax .set_ylim ([- 6 ,6 ])
351+ plt .show ()
352+
353+ print ('' )
354+ print ('channel-width: {} ps (= {} x {} ps)' .format (binWidth_in_ps ,binFac ,userInput .__channelResolutionInPs ))
355+ print ('' )
356+ print ('ROI: [{} : {}]' .format (roi_start ,roi_end ))
357+
358+ if not userInput .__usingRefSpectrum :
359+ print ('t-zero channel: {}' .format (t_zero_chn ))
360+
361+ print ('background: [{} : {}]' .format (bkgrd_startIndex ,bkgrd_startIndex + bkgrd_count ))
362+ print ('' )
363+
364+ if not userInput .__usingRefSpectrum :
365+ for i in range (len (userInput .__irf_fwhm )):
366+ print ('----- fixed Gaussian IRF components ({}/{}) -----' .format (i + 1 ,len (userInput .__irf_fwhm )))
367+ print ('' )
368+ print ('intensity: {} %' .format (100. * userInput .__irf_intensity [i ]))
369+ print ('t: {} ps' .format (userInput .__irf_t0 [i ]))
370+ print ('FWHM: {} ps' .format (userInput .__irf_fwhm [i ]))
371+
372+ print ('' )
373+
374+ for i in range (0 ,len (results )):
375+ print ('------------ found component ({}/{}) ------------' .format (i + 1 ,len (results )))
376+ print ('' )
377+ print ('tau-mean: ({} +/- {}) ps' .format (results [i ][1 ],uncertainties [i ][1 ]))
378+ print ('tau-sigma: ({} +/- {}) ps' .format (results [i ][2 ],uncertainties [i ][2 ]))
379+ print ('' )
380+ print ('intensity: {} %' .format (100. * intensities [i ]/ sum (intensities )))
381+ print ('' )
382+
383+
384+
385+
386+
0 commit comments