-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgaussNpeaksbg.pro
667 lines (633 loc) · 27.5 KB
/
gaussNpeaksbg.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
; *******************************************************************
; Multfit efficient processing of 2D diffraction images
; Copyright (C) 2000-2014 S. Merkel, Universite Lille 1
; http://merkel.zoneo.net/Multifit/
;
; This program is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version 2
; of the License, or (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
;
; *******************************************************************
; *******************************************************************
; subroutine GAUSSNPEAKSBG
;
; Modified on 12/20/2001 by S. Merkel
; Try to zoom in when there are less than minScale+npeaks*minScale points.
; I just multiply the number of points in x by a number
; and interpolate y in between known values.
; This is done because the fit is unstable otherwise, and it
; tends to make it faster.
; Modified on 12/21/2001 by S. Merkel
; Added the possibility to change peak profile.
; If parameter peakmodel = 1 -> pseudo-voigt
; if parameter peakmodel = 2 -> lorentzian
; else gaussian.
; Modified 02/2005 by S. Merkel
; Added a common block with fit improvement parameters so they can
; be easily set in a GUI.
; Modified 03/2005 by S. Merkel
; Changed plots, they are now in degrees. All calculations are done
; in pixels but we calculate a 2theta scale for plotting. It makes
; it much easier to identify peaks...
;
;
; Fits N gaussians to a given x-y data set using the mpfit subroutine
; and a second degree poly for the background
; send x, y, npeaks, fit
; Fit parameters will be returned in the array fit as follow
; fit(i,0) = position for peak i
; fit(i,1) = intensity for peak i
; fit(i,2) = half width for peak i
; If called with keyword AUTO, it will use previous parameters
; given in the fit table to estimate peak positions, otherwise
; user will be asked to define the top and first peak and half
; width for each peak
;
; parameters:
; theta: 2 theta values
; x: index (pixel numbers) of the section of spectra to fit
; y: corresponding intensities
; npeaks: number of peaks
; fit: fit parameters (see above for format) of the previous fits or
; array of zeros
; hardbg: if equals to 1, background will be fitted by user using a
; polynomial function a begining of iterations
; sidebg: if equals to 1, background = line between the few points
; on the side of the domain to fit
; automatic: if set, program uses the coefficients of the previous
; fits (as sent in the fit array), otherwise, user defines
; the peaks by clicking on top and half-width
; peakmodel: = 1 -> pseudo-voigt peak profile
; = 2 -> lorentzian peak profile
; else gaussian peak profile
;
; parameters to be set in common block 'fitoptions'
; - basescale: sets the restriction of region to fit, (should be 5, by
; default)
; - smallDetection: detection of small peaks (should be 3, by
; default)
; - nloops: number of loops (20)
; - startSmall: 2
; - endSmall: 10
; - ignoreration: 0. Calculate (maxIntensity-medianIntensity)/medianIntensity. Do not run fit if below the threshold. Increase this value if you want to skip fit for peaks at orientations where there is no more intensity (texture effects). Only used in automatic fitting. This function was tested in 01/2016. It does not work well right now. Forced set to 0
; *******************************************************************
; REMEMEBER: ALL FITS ARE DONE IN PIXELS! THERE ARE CONVERSIONS TO
; 2THETA FOR EASY DISPLAY, BUT THE MATHS ARE IN PIXELS!
pro gaussNpeaksbg, theta, x, y, npeaks, fit, hardbg, sidebg, peakmodel, alpha, AUTO = automatic
common bginfo, bgdegree, bgCoefs
common fitoptions, basescale, smallDetection, nLoop, startSmall, endSmall, ignoreratio
if (keyword_set(automatic)) then auto = 1 else auto = 0
ignoreratio = 0.
; Parameters for the fit
fitBg = 10
;startSmall = 2
;endSmall = 12
;nLoop = 20
; peak profile setup
; default, gaussian peak profile
shiftNterms = 0
; restriction of region, number of terms to fit
; basescaling defines the region to include around the peak position
; in the fit (baseScaling*peakwidth). The rest of the spectrum is
; simply ignored.
; default, gaussian peak profile
baseScaling = 1.0*basescale
shiftNterms = 0
; if lorentzian peak profile
if (peakmodel eq 2) then begin
; lorentzians have no extra term, and
; they are pretty wide at the base, so we give them more space for the
; fit
shiftNterms = 0
baseScaling = 1.0*basescale
endif
; if pseudo-Voigt peak profile
if (peakmodel eq 1) then begin
; there is one more term with a pseudo-voigt function (weigth between
; Gauss and Lorentz)
; they are pretty wide at the base, so we give them more space for the
; fit
shiftNterms = 1
baseScaling = 1.0*basescale
endif
;
; x are integers than indicate the pixel numbers for the center of
; the imaging plate
;
; they are converted to whatever they mean in another subroutine
;
; y are floats that represent the intensity of diffraction at this
; pixel
;
ylength = N_ELEMENTS(y)
;
; added for scaling
;
minScale = 60
scaling = 1
if (ylength lt (minScale+npeaks*minScale)) then begin
scaling = fix((minScale+npeaks*minScale)/ylength)
endif
; scaling = 2 means for instance:
; x = 10 11 12 13
; y = 0.0 0.1 0.2 0.3
; scaledx = 10 11 12 13 14 15 16
; scaledy = 0.0 0.05 0.1 0.15 0.2 0.25 0.3
;print, 'x-scaling = ', scaling
scaledylength = ylength+(ylength-1)*(scaling-1)
scaledx = fltarr(scaledylength)
scaledy = fltarr(scaledylength)
scaledtheta = fltarr(scaledylength)
for i=0, scaledylength-2 do begin
indexInf = fix(i/scaling)
indexSup = fix(i/scaling)+1
scaledx(i) = min(x)+i
scaledy(i) = 1.0*(y(indexInf)+1.0*(1.0*i-scaling*indexInf)* $
(y(indexSup)-y(indexInf))/scaling)
scaledtheta(i) = 1.0*(theta(indexInf)+1.0*(1.0*i-scaling*indexInf)* $
(theta(indexSup)-theta(indexInf))/scaling)
endfor
scaledx(scaledylength-1) = min(x)+scaledylength-1
scaledy(scaledylength-1) = y(ylength-1)
scaledtheta(scaledylength-1) = theta(ylength-1)
oldx = x
oldy = y
y = scaledy
x = scaledx
ylength = scaledylength
;
; end scaling
;
minX = min(x)
maxX = max(x)
minY = min(y)
minYA = [replicate(miny,ylength)]
y = y - minYA
tofittmp = fltarr(maxX+1,2)
weighttmp = fltarr(maxX+1)
tofittmp(*,0) = findgen(maxX+1)
yfit = ptrarr(npeaks)
estimates = ptrarr(npeaks)
coeffs = ptrarr(npeaks)
xtmp = ptrarr(npeaks)
ytmp = ptrarr(npeaks)
thetatmp = ptrarr(npeaks)
if (auto eq 0) then begin
yplotmin = min(y)-0.05*(max(y)-min(y))
yplotmax = max(y)+0.05*(max(y)-min(y))
xplotmin = min(scaledtheta)
xplotmax = max(scaledtheta)
!X.STYLE = 1
!Y.STYLE = 1
!P.NOERASE = 0
plot, scaledtheta, y, background=255, color = 0, yrange=[yplotmin,yplotmax]
endif
; hard backgound?? THIS HAS TO BE CORRECTED, WAS WRITTEN AT A TIME
; WHERE THE PLOTS WERE IN PIXELS
if (hardbg eq 1) then begin
if (auto eq 0) then begin
print, 'n elements in x 1:', n_elements(x)
read, bgdegree, prompt = 'Degree of polynomial for the background:'
print, " Click points for the background, right click to end."
xCbg = fltarr(100)
yCbg = fltarr(100)
iBg = -1
!err=0
while (!err ne 4)do begin
cursor,xCurs,yCurs,/down
if !err ne 4 then begin
iBg = iBg + 1
print, iBg
xCbg(iBg) = xCurs
yCbg(iBg) = yCurs
endif
endwhile
fitBgX = xCbg (0:iBg)
fitBgY = yCbg (0:iBg)
bgCoefs = POLY_FIT(fitBgX,fitBgY,bgdegree)
bg = fltarr(n_elements(x))
for deg=0, bgdegree do begin
bg = bg + bgCoefs(deg)*x^deg
endfor
plot, x, y-bg, background=255, color = 0
endif else begin
bg = fltarr(n_elements(x))
for deg=0, bgdegree do begin
bg = bg + bgCoefs(deg)*x^deg
endfor
endelse
endif else begin
bgdegree = 1
bg = fltarr(n_elements(x))
if (sidebg eq 1) then begin
fitBgX = fltarr(20)
fitBgY = fltarr(20)
for j = 0, 9 do begin
fitBgX(j) = x(j)
fitbgX(10+j) = x(N_ELEMENTS(x)-1-j)
fitBgY(j) = y(j)
fitbgY(10+j) = y(N_ELEMENTS(x)-1-j)
endfor
bgCoefs = POLY_FIT(fitBgX,fitBgY,bgdegree)
for deg=0, bgdegree do begin
bg = bg + bgCoefs(deg)*x^deg
endfor
endif
endelse
; first loop to initialize all pointers, variables, and peak positions
; if we have to initialize it by hand, we ask the user to
; click on the peaks one by one, a we try t fit them
diff = fltarr(maxX+1)
if (auto eq 0) then begin
xleg = xplotmin+0.05*(xplotmax-xplotmin)
for peak = 0, npeaks-1 do begin
estimates[peak] = PTR_NEW(/ALLOCATE_HEAP)
xtmp[peak] = PTR_NEW(/ALLOCATE_HEAP)
ytmp[peak] = PTR_NEW(/ALLOCATE_HEAP)
thetatmp[peak] = PTR_NEW(/ALLOCATE_HEAP)
coeffs[peak] = PTR_NEW(/ALLOCATE_HEAP)
yfit[peak] = PTR_NEW(/ALLOCATE_HEAP)
; get position of this peak from the user
string = "Click on peak maximum " + string(peak + 1, /print)
yleg = yplotmax-0.04*(yplotmax-yplotmin)
xyouts, xleg,yleg, string, color = 0, charsize=1.5, charthick=2
cursor,xC,yC,/down
yleg = yleg-0.04*(yplotmax-yplotmin)
xyouts, xleg,yleg, "Click on peak's left or right side", color = 0, charsize=1.5, charthick=2
cursor,xH,yH,/down
xC = theta2pixels(scaledtheta, N_ELEMENTS(scaledtheta), xC)+minX
xH = theta2pixels(scaledtheta, N_ELEMENTS(scaledtheta), xH)+minX
*estimates[peak] = fltarr(5+shiftNterms)
(*estimates[peak])[1] = xC ; position
(*estimates[peak])[0] = yC ; intensity
(*estimates[peak])[2] = max([2,abs(xC-xH)]) ; half width
; we remove the peaks found before
tofittmp(*,1) = 0.0
tofittmp(x,1) = y-bg
for j = 0, peak-1 do begin
tofittmp((*xtmp(j)),1) = (tofittmp((*xtmp(j)),1)-(*yfit(j)))
endfor
; we limit the zone to fit the peak, so it doesn't
; fit everything
minZoneX = minmaxval(minX,maxX-1,(*estimates[peak])[1]-baseScaling*(*estimates[peak])[2])
maxZoneX = minmaxval(minX,maxX-1,(*estimates[peak])[1]+baseScaling*(*estimates[peak])[2])
; print, N_ELEMENTS(tofittmp), XC2, estimates2[2], minxx, maxxx
*xtmp[peak] = tofittmp(minZonex:maxZonex,0)
*ytmp[peak] = tofittmp(minZonex:maxZonex,1)
*thetatmp[peak] = scaledtheta(minZonex-x[0]:maxZonex-x[0])
; fit the gaussian or pseudovoigt with
; a linear background
; force the peaks width to be
; positive... Forcing peak height to
; be positive causes crashes... I
; can't understand why, and it's a
; real problem
parinfo = replicate({limited:[0,0], $
limits:[0,0]}, 3+shiftNterms)
parinfo[1].limited[0] = 1
parinfo[1].limits[0] = 0.0
if (peakmodel eq 1) then begin
*yfit[peak] = MPFITPEAK(*xtmp[peak],*ytmp[peak],(*coeffs[peak]), $
nterms=5+shiftNterms, estimates=(*estimates[peak]), /pseudoV, parinfo = parinfo)
endif else if (peakmodel eq 2) then begin
*yfit[peak] = MPFITPEAK(*xtmp[peak],*ytmp[peak],(*coeffs[peak]), $
nterms=5+shiftNterms, estimates=(*estimates[peak]), /LORENTZIAN, parinfo = parinfo)
endif else begin
*yfit[peak] = MPFITPEAK(*xtmp[peak],*ytmp[peak],(*coeffs[peak]), $
nterms=5+shiftNterms, estimates=(*estimates[peak]), parinfo = parinfo)
endelse
; show the result
diff(x) = y-bg
for j = 0, peak do begin
diff((*xtmp(j))) = (diff((*xtmp(j)))-(*yfit(j)))
endfor
diff((*xtmp[peak])) = (diff((*xtmp[peak]))+(*coeffs[peak])(3+shiftNterms)+(*xtmp[peak])*(*coeffs[peak])(4+shiftNterms))
yplotmin = min(y-bg) - 0.05* (max(y-bg)-min(y-bg))
yplotmax = max(y-bg) + 0.05* (max(y-bg)-min(y-bg))
!X.STYLE = 1
!Y.STYLE = 1
!P.NOERASE = 0
plot, scaledtheta, y-bg, background=255, color = 0, yrange=[yplotmin,yplotmax]
oplot, *thetatmp[peak], *yfit[peak], color = 100
oplot, scaledtheta, diff(x), color=200
; we remove the linear background from the fit
*yfit[peak] = *yfit[peak]-(*coeffs[peak])(3+shiftNterms)-(*xtmp[peak]) *(*coeffs[peak])(4+shiftNterms)
endfor
endif
; We show the result of the pre-fit with user input
if (auto eq 0) then begin
plot, scaledtheta, y, background=255, color = 0
for peak = 0, npeaks-1 do $
oplot, *thetatmp[peak], *yfit[peak], color = 100
oplot, scaledtheta, bg, color = 200
; plot, x, y, background=255, color = 0
; tofittmp(*,1) = 0.0
; tofittmp(x,1) = bg
; for j = 0, npeaks-1 do begin
; tofittmp((*xtmp(j)),1) = tofittmp((*xtmp(j)),1)+(*yfit(j))
; endfor
; newfit = tofittmp(minX:maxX,1)
; oplot, x, newfit, color = 200
endif
; We use the results from previous fits as starting model. So we have
; to regenerate the peak profiles from their position, half-width and intensity.
if (auto ne 0) then begin
for peak = 0, npeaks-1 do begin
estimates[peak] = PTR_NEW(/ALLOCATE_HEAP)
xtmp[peak] = PTR_NEW(/ALLOCATE_HEAP)
ytmp[peak] = PTR_NEW(/ALLOCATE_HEAP)
coeffs[peak] = PTR_NEW(/ALLOCATE_HEAP)
yfit[peak] = PTR_NEW(/ALLOCATE_HEAP)
thetatmp[peak] = PTR_NEW(/ALLOCATE_HEAP)
*estimates[peak] = fltarr(5+shiftNterms)
; guess for position and half width have to be scaled
position = minX+(fit(peak,0)-minX)*scaling
halfwidth = max([5,fit(peak,2)])*scaling
intensity = fit(peak,1)
(*estimates[peak])[1] = position ; position
(*estimates[peak])[0] = intensity ; intensity
(*estimates[peak])[2] = halfwidth ; half width
; we don't fit anything, just regenerate the peak profiles
; we remove the peaks found before
tofittmp(*,1) = 0.0
tofittmp(x,1) = y-bg
for j = 0, peak-1 do begin
tofittmp((*xtmp(j)),1) = (tofittmp((*xtmp(j)),1)-(*yfit(j)))
endfor
; we limit the zone where the peak resides
minZoneX = minmaxval(minX,maxX-1,(*estimates[peak])[1]-baseScaling*(*estimates[peak])[2])
maxZoneX = minmaxval(minX,maxX-1,(*estimates[peak])[1]+baseScaling*(*estimates[peak])[2])
*xtmp[peak] = tofittmp(minZonex:maxZonex,0)
*ytmp[peak] = tofittmp(minZonex:maxZonex,1)
*thetatmp[peak] = scaledtheta(minZonex-x[0]:maxZonex-x[0])
; generate the gaussian or pseudovoigt with no background
; since we lost the weigth between
; gaussian and lorentzian, we just use
; a gaussian model
; y = intensity * exp (-0.5 *((x-center)/half-width)^2)
*yfit[peak] = intensity*exp(-0.5*((*xtmp[peak]-position)/halfwidth)^2)
*coeffs[peak] = *estimates[peak]
endfor
endif
;print, "Optimization..."
; optimization loop
doSmall = 0
compteBg = 0
doPeak = intArr(npeaks)
for i = 0, nLoop do begin
; If there is a very small peak, we do n0t optimize it at the same time,
; we do
; - the big ones from 0 to startSmall
; - the small ones from startSmall to endSmall
; - the big ones later
;
; Also, we we are in doSmall mode, the peak width is automatically divided by 2 before refitting...
; In that case, we also fit a local background in order to avoid the effects of the surrounding peaks...
;
; Small peak is also ignored when fitting the rest...
; Detect wheter we should do anything about small peaks at all...
if (npeaks gt 1) then begin
maxIntensity = 0.0
minIntensity = 100000000000
for j = 0, npeaks-1 do begin
if ((*coeffs(j))[0] gt maxIntensity) then maxIntensity=(*coeffs(j))[0]
if ((*coeffs(j))[0] lt minIntensity) then minIntensity=(*coeffs(j))[0]
endfor
if (maxIntensity gt (smallDetection*minIntensity)) then begin
if ((i lt startSmall) or (i gt endSmall)) then begin
doSmall = 0
for j = 0, npeaks-1 do begin
if ((*coeffs(j))[0] lt (smallDetection*minIntensity)) then doPeak(j) = 0 else doPeak(j) = 1
endfor
endif else begin
doSmall = 1
for j = 0, npeaks-1 do begin
if ((*coeffs(j))[0] lt (smallDetection*minIntensity)) then doPeak(j) = 1 else doPeak(j) = 0
endfor
endelse
endif else begin
doSmall = 0
for j = 0, npeaks-1 do doPeak(j) = 1
endelse
endif else begin
doSmall = 0
doPeak[0] = 1
endelse
;
if ((compteBg eq fitBg) and (sidebg eq 0)) then begin
; we fit a quadratic background to the
; data minus the two previous fits
tofittmp[*,1] = 0.0
tofittmp[x,1] = y
for j = 0, npeaks-1 do begin
tofittmp[(*xtmp[j]),1] -= -(*yfit[j])
endfor
xbg = x
ybg = tofittmp[minX:maxX,1]
bgCoefs = POLY_FIT(xbg,ybg,bgdegree)
bg = fltarr(n_elements(x))
for deg=0, bgdegree do begin
bg = bg + bgCoefs(deg)*x^deg
endfor
endif
compteBg = compteBg + 1
;plot, xbg, ybg, background=255, color = 0
;oplot, x, bg, color = 100
;cursor,xH,yH,/down
; loop on peaks
for peak = 0, npeaks-1 do begin
if (doPeak[peak] eq 1) then begin
; we take the original data, minus the other peaks and the bg
tofittmp(*,1) = 0.0
tofittmp(x,1) = y-bg
; If there is a very small beak, we ignore it when fitting the others
; If we are fitting a small peak, we take care of everything
; Also, if we are working on a small peak, the background has to be lifted up because of the surrounding ones, otherwise the fit fucks up
; This is done later once, we have restricted the zone...
if (doSmall eq 1) then begin
for j = 0, npeaks-1 do begin
if (j ne peak)then $
tofittmp[(*xtmp(j)),1] = tofittmp[(*xtmp(j)),1]-(*yfit[j])
endfor
endif else begin
for j = 0, npeaks-1 do begin
if ((j ne peak) and (doPeak(j) eq 1))then $
tofittmp[(*xtmp(j)),1] = tofittmp[(*xtmp(j)),1]-(*yfit[j])
endfor
endelse
; we have to apply a weight, otherwise, it fucks, if the fit from other peaks is high, the weight is small, so the peaks don't shift towards each other
weighttmp(*) = 0.0
for j = 0, npeaks-1 do begin
if (j ne peak) then $
weighttmp[(*xtmp[j])] = weighttmp[(*xtmp[j])]+abs((*yfit[j]))
endfor
; We apply another weight to give more importance to the top of the peak..
; weighttmp((*xtmp[peak])) = weighttmp((*xtmp[peak]))-abs((*yfit[peak]))
; Removed it does not help at all...
; Normalization...
maxweigth = max(weighttmp)
if (maxweigth lt 1) then maxweigth = 1
; Coefficient to change to strength of the weighting...
coeffWeight = 3.
weighttmp[*] = (coeffWeight*weighttmp[*] + 0.1 * maxweigth)/coeffWeight
; results from previous fit on this peak becomes estimation, if they were not set no NaN
if (FINITE((*coeffs[peak])[0])) then *estimates[peak] = *coeffs[peak]
; avoid getting a fitting zone that is too small in X, forcing 5 pixels minimum
(*estimates[peak])[2] = max([5,(*estimates[peak])[2]])
; we limit the zone to fit the peak, so it doesn't fit everything
; This part is tricky...
; At first, I was restricting at baseScaling * peak width, but it works badly if one peak is much smaller that the other... So now, it is weighted by the peak intensity...
; find Max Intensity
if (npeaks gt 1) then begin
maxIntensity = 0.0
minIntensity = 100000000000
for j = 0, npeaks-1 do begin
if ((*coeffs[j])[0] gt maxIntensity) then maxIntensity=(*coeffs[j])[0]
if ((*coeffs[j])[0] lt minIntensity) then minIntensity=(*coeffs[j])[0]
endfor
; factor for zoneWidth is baseScaling for peak with maxIntensity, and
; 0.5*baseScaling for lowest peak
if (((maxIntensity-minIntensity)/maxIntensity) gt 0.1) then thisScaling = (0.5 + 0.5*((*coeffs[peak])[0]-minIntensity)/(maxIntensity-minIntensity)) * baseScaling else thisScaling = baseScaling
; We restrict the zone
endif else thisScaling = baseScaling
; If we are working on a small peak, we divide its width by 3 before refiting
if (doSmall eq 1) then (*estimates[peak])[2] = (*estimates[peak])[2]/2.
minZoneX = minmaxval(minX,maxX-1,(*estimates[peak])[1]-4.*thisScaling*(*estimates[peak])[2])
maxZoneX = minmaxval(minX,maxX-1,(*estimates[peak])[1]+4.*thisScaling*(*estimates[peak])[2])
if ((maxZoneX- minZoneX) lt 5) then minZoneX = minzoneX -10
minZoneX = minmaxval(0,maxX-1,minZoneX)
if ((maxZoneX- minZoneX) lt 5) then maxZoneX = maxZoneX + 10
*xtmp[peak] = tofittmp[minZonex:maxZonex,0]
*ytmp[peak] = tofittmp[minZonex:maxZonex,1]
*thetatmp[peak] = scaledtheta[minZonex-x[0]:maxZonex-x[0]]
; If it is a small peak, we take a straight line between left and right to remove it otherwise the peak is too high
if (doSmall eq 1) then begin
bg2 = fltarr(n_elements(*xtmp[peak]))
fitBgX2 = fltarr(4)
fitBgY2 = fltarr(4)
for j = 0, 1 do begin
fitBgX2[j] = (*xtmp[peak])[j]
fitbgX2[2+j] = (*xtmp[peak])(N_ELEMENTS(*xtmp[peak])-1-j)
fitBgY2[j] = (*ytmp[peak])[j]
fitbgY2[2+j] = (*ytmp[peak])(N_ELEMENTS(*xtmp[peak])-1-j)
endfor
bgCoefs2 = POLY_FIT(fitBgX2,fitBgY2,1)
for deg=0, 1 do begin
bg2 = bg2 + bgCoefs2[deg]*(*xtmp[peak])^deg
endfor
; Another weight... So the intensity of the not so small peaks are not reduced to much...
coeffBg = (minIntensity*smallDetection-(*estimates[peak])[1])/(smallDetection*minIntensity)
(*ytmp[peak]) = (*ytmp[peak]) - coeffBg * bg2
endif
weigthtmp2 = fltarr(maxZonex-minZonex+1)
weighttmp2 = weighttmp(minZonex:maxZonex)
; print, 'le poids ', weighttmp2
;print, minZoneX, maxZoneX
; fit the gaussian with no background
parinfo = replicate({limited:[0,0], $
limits:[0,0]}, 3+shiftNterms)
; force the peaks width to be positive... Forcing peak height to be positive causes crashes... I can't understand why, and it's a real problem
parinfo[1].limited[0] = 1
parinfo[1].limits[0] = 0.0
; Check if we should do anything at all. Calculate (maxIntensity-medianIntensity)/medianIntensity. Do not run fit if below the threshold.
medianY = median(*ytmp[peak])
maxY = max(*ytmp[peak])
if ((maxY-medianY)/abs(medianY) lt ignoreratio) then begin
(*coeffs[peak])[0] = !VALUES.F_NAN
(*coeffs[peak])[1] = !VALUES.F_NAN
(*coeffs[peak])[2] = !VALUES.F_NAN
(*yfit[peak])[*] = 0.
print, "Ignore peak ", peak, maxY, medianY
print, *ytmp[peak]
print, (*yfit[peak])
endif else begin
if (peakmodel eq 1) then begin
*yfit[peak] = MPFITPEAK(*xtmp[peak],*ytmp[peak],(*coeffs[peak]), $
nterms=3+shiftNterms, $
estimates=(*estimates[peak]), error = weighttmp2, $
parinfo = parinfo, /pseudoV)
endif else if (peakmodel eq 2) then begin
*yfit[peak] = MPFITPEAK(*xtmp[peak],*ytmp[peak],(*coeffs[peak]), $
nterms=3+shiftNterms, estimates=(*estimates[peak]), /LORENTZIAN)
endif else begin
*yfit[peak] = MPFITPEAK(*xtmp[peak],*ytmp[peak],(*coeffs[peak]), $
nterms=3+shiftNterms, $
estimates=(*estimates[peak]), error = weighttmp2)
endelse
endelse
; check the result... If we get
; negative height, we make it 0
; does not work, still need to find
; something better. Has been a problem
; for 3 years...
;if ((*coeffs[peak])[0]<0.0) then begin
; print, 'Warning: negative peak for number', peak, '... Canceling...'
; (*coeffs[peak])[0] = 0.0
; *yfit[peak] = *yfit[peak]-*yfit[peak]
;endif
; *yfit[peak] = *yfit[peak]-(*coeffs[peak])(3)
; plot, *xtmp[peak], *ytmp[peak], background=255, color = 0
; oplot, *xtmp[peak], *yfit[peak], color = 100
; cursor,xH,yH,/down
endif
endfor
endfor
; print, 'le poids ', weighttmp2
; preparing to plot the result...
; results of the fit = bg + all peaks
tofittmp[*,1] = 0.0
tofittmp[x,1] = bg
for j = 0, npeaks-1 do begin
tofittmp[(*xtmp[j]),1] = tofittmp[(*xtmp[j]),1]+(*yfit[j])
endfor
newfit = tofittmp[minX:maxX,1]
; plot the original curve
plotmin = min(y)-.3*(max(y)-min(y))
plotmax = max(y)+.1*(max(y)-min(y))
xmin = min(scaledtheta)
xmax = max(scaledtheta)
plot, scaledtheta, y, background=255, color = 0, xrange=[xmin,xmax], yrange = [plotmin,plotmax], ystyle=1, xstyle=1
xleg = xmax-0.5*(xmax-xmin)
yleg = plotmax-0.05*(plotmax-plotmin)
; print, xleg, yleg
xyouts, xleg,yleg, "az = "+STRING(alpha,format='(F6.1)'), color = 0, charsize=2, charthick=3
yleg = plotmax-0.10*(plotmax-plotmin)
xyouts, xleg,yleg, "scale fac. x = "+STRING(scaling,format='(I3)'), color = 0, charsize=1.5, charthick=2
; global fit
oplot, scaledtheta, newfit, color = 100
; and the gaussians
for peak = 0, npeaks-1 do begin
oplot, *thetatmp[peak], *yfit[peak], color = 200
endfor
; plot the residuals
diff[x] = y-bg-.1*(max(y)-min(y))
for j = 0, npeaks-1 do begin
diff[(*xtmp[j])] = diff[(*xtmp[j])]-(*yfit[j])
endfor
oplot, scaledtheta, diff[x], color=50
; prepare the results to send them back...
fit = fltarr(npeaks,3)
for peak = 0, npeaks-1 do begin
; position has to be corrected for scaling
scaledposition = (*coeffs[peak])[1]
position = minX + (scaledposition-minX)/scaling
; same for half width
scaledHWidth = (*coeffs[peak])[2]
hWidth = scaledHWidth/scaling
fit[peak,0] = position ; position
fit[peak,1] = (*coeffs[peak])[0] ; intensity
fit[peak,2] = hWidth ; half width
ptr_free, estimates[peak], xtmp[peak], ytmp[peak], coeffs[peak], yfit[peak]
endfor
wait, 0.3
end