PEARL Procedures  rev-distro-2.1.1-1-gf419e92-dirty
Igor procedures for the analysis of PEARL data
pearl-scienta-preprocess.ipf
Go to the documentation of this file.
1 #pragma rtGlobals=3 // Use modern global access method and strict wave access.
2 #pragma IgorVersion = 6.1
3 #pragma ModuleName = PearlScientaPreprocess
4 #include "pearl-fitfuncs"
5 
6 // Copyright (c) 2013-18 Paul Scherrer Institut
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
12 
27 
32 
36  string &param
37 
38  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
39  variable Lsize = NumberByKey("Lsize", param, "=", ";")
40  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
41  variable Hsize = NumberByKey("Hsize", param, "=", ";")
42  variable Cpos = NumberByKey("Cpos", param, "=", ";")
43  variable Csize = NumberByKey("Csize", param, "=", ";")
44 
45  prompt Lcrop, "Lower cropping region"
46  prompt Hcrop, "Upper cropping region"
47  prompt Lsize, "Lower background region"
48  prompt Hsize, "Upper background region"
49  prompt Cpos, "Center position"
50  prompt Csize, "Center integration region"
51 
52  doprompt "int_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
53  if (v_flag == 0)
54  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
55  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
56  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
57  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
58  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
59  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
60  endif
61 
62  return v_flag
63 end
64 
94  string param = csr_int_linbg_reduction("")
95  svar /z global_params = root:packages:pearl_explorer:s_reduction_params
96  if (svar_exists(global_params))
97  global_params = param
98  endif
99  return param
100 end
101 
133 function /s csr_int_linbg_reduction(win)
134  string win
135 
136  // read all cursor positions
137  variable ic
138  string sc
139  variable nc = 10
140  make /n=(nc) /free positions
141  variable np = 0
142  wave /z image = $""
143  string imagename = ""
144  string tracename = ""
145  string info
146 
147  for (ic = 0; ic < nc; ic += 1)
148  sc = num2char(char2num("A") + ic)
149  wave /z wc = CsrWaveRef($sc, win)
150  info = CsrInfo($sc, win)
151  tracename = StringByKey("TNAME", info, ":", ";")
152  if (waveexists(wc) && (wavedims(wc) == 2))
153  if (!waveexists(image))
154  wave image = wc
155  imagename = tracename
156  endif
157  if (cmpstr(tracename, imagename) == 0)
158  positions[np] = pcsr($sc, win)
159  np += 1
160  endif
161  endif
162  endfor
163 
164  np = floor(np / 2) * 2 // ignore odd cursor
165  redimension /n=(np) positions
166  sort positions, positions
167  // shift upper positions by one so that the rightmost pixel becomes 1.0
168  positions = p >= np / 2 ? positions + 1 : positions
169  positions = positions / dimsize(image, 0)
170 
171  // map innermost cursor pair to peak center and size
172  variable ip2 = np / 2
173  variable ip1 = ip2 - 1
174  variable Cpos
175  variable Csize
176  if (ip1 >= 0)
177  Cpos = (positions[ip1] + positions[ip2]) / 2
178  Csize = positions[ip2] - positions[ip1]
179  else
180  // default: a small region in the center
181  Cpos = 0.5
182  Csize = 0.2
183  endif
184 
185  // background region
186  ip1 -= 1
187  ip2 += 1
188  variable Lsize
189  variable Hsize
190  if (ip1 >= 0)
191  Lsize = positions[ip1]
192  Hsize = 1 - positions[ip2]
193  else
194  // default: everything outside the peak region
195  Lsize = Cpos - Csize / 2
196  Hsize = 1 - (Cpos + Csize / 2)
197  endif
198 
199  // crop region
200  ip1 -= 1
201  ip2 += 1
202  variable Lcrop = 0
203  variable Hcrop = 0
204  if (ip1 >= 0)
205  Lcrop = positions[ip1]
206  Hcrop = 1 - positions[ip2]
207  else
208  // default: in fixed mode: dark corners of the EW4000 at PEARL, 0 otherwise
209  if (dimsize(image, 0) >= 992)
210  Lcrop = 0.11
211  Hcrop = 0.11
212  endif
213  endif
214  Lsize = max(Lsize - Lcrop, 0)
215  Hsize = max(Hsize - Hcrop, 0)
216 
217  string param = ""
218  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
219  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
220  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
221  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
222  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
223  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
224 
225  return param
226 end
227 
260 threadsafe function /wave int_linbg_reduction(source, param)
261  wave source
262  string &param
263 
264  variable nx = dimsize(source, 0)
265  variable ny = dimsize(source, 1)
266 
267  // read parameters
268  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
269  variable lsize = NumberByKey("Lsize", param, "=", ";")
270  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
271  variable hsize = NumberByKey("Hsize", param, "=", ";")
272  variable cpos = NumberByKey("Cpos", param, "=", ";")
273  variable csize = NumberByKey("Csize", param, "=", ";")
274 
275  make /wave /free /n=2 result_waves
276  make /free /n=0 dest1, dest2
277  result_waves[0] = dest1
278  result_waves[1] = dest2
279  adh5_setup_profile(source, dest1, 1)
280  adh5_setup_profile(source, dest2, 1)
281 
282  // validate parameters
283  // background parameters are optional, center parameter is required.
284  if (numtype(lcrop) != 0)
285  lcrop = 0
286  endif
287  if (numtype(lsize) != 0)
288  lsize = 0
289  endif
290  if (numtype(hcrop) != 0)
291  hcrop = 0
292  endif
293  if (numtype(hsize) != 0)
294  hsize = 0
295  endif
296  if (numtype(Cpos) != 0)
297  redimension /n=0 result_waves
298  return result_waves // Cpos parameter missing
299  endif
300  if (numtype(Csize) != 0)
301  redimension /n=0 result_waves
302  return result_waves // Csize parameter missing
303  endif
304 
305  variable lpos = lcrop + lsize / 2
306  variable hpos = 1 - (hcrop + hsize / 2)
307 
308  variable p0
309  variable p1
310 
311  duplicate /free dest1, lbg, hbg
312  if (lsize > 0)
313  p0 = round(lcrop * nx)
314  p1 = round((lcrop + lsize) * nx)
315  ad_profile_y_w(source, p0, p1, lbg)
316  else
317  lbg = 0
318  endif
319  if (hsize > 0)
320  p0 = round((1 - hcrop - hsize) * nx)
321  p1 = round((1 - hcrop) * nx)
322  ad_profile_y_w(source, p0, p1, hbg)
323  else
324  hbg = 0
325  endif
326  if (csize > 0)
327  p0 = round((cpos - csize/2) * nx)
328  p1 = round((cpos + csize/2) * nx)
329  ad_profile_y_w(source, p0, p1, dest1)
330  else
331  dest1 = 0
332  endif
333 
334  variable scale = (cpos - lpos) / (hpos - lpos)
335  dest2 = dest1
336  dest1 -= scale * (hbg - lbg) + lbg
337  dest2 = sqrt(dest2 + scale^2 * (hbg + lbg))
338 
339  string s_note1
340  string s_note2
341  sprintf s_note1, "AxisLabelD=peak integral"
342  sprintf s_note2, "KineticEnergy=%.3f", cpos * nx * dimdelta(source, 0) + dimoffset(source, 0)
343  Note dest1, s_note1
344  Note dest1, s_note2
345  Note dest2, s_note1
346  Note dest2, s_note2
347 
348  return result_waves
349 end
350 
352  string &param
353 
354  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
355  variable Lsize = NumberByKey("Lsize", param, "=", ";")
356  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
357  variable Hsize = NumberByKey("Hsize", param, "=", ";")
358  variable Cpos = NumberByKey("Cpos", param, "=", ";")
359  variable Csize = NumberByKey("Csize", param, "=", ";")
360 
361  prompt Lcrop, "Lower cropping region"
362  prompt Hcrop, "Upper cropping region"
363  prompt Lsize, "Lower background region"
364  prompt Hsize, "Upper background region"
365  prompt Cpos, "Center position"
366  prompt Csize, "Center integration region"
367 
368  doprompt "int_quadbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
369  if (v_flag == 0)
370  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
371  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
372  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
373  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
374  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
375  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
376  endif
377 
378  return v_flag
379 end
380 
413 threadsafe function /wave int_quadbg_reduction(source, param)
414  wave source
415  string &param
416 
417  variable nx = dimsize(source, 0)
418  variable ny = dimsize(source, 1)
419 
420  // read parameters
421  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
422  variable lsize = NumberByKey("Lsize", param, "=", ";")
423  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
424  variable hsize = NumberByKey("Hsize", param, "=", ";")
425  variable cpos = NumberByKey("Cpos", param, "=", ";")
426  variable csize = NumberByKey("Csize", param, "=", ";")
427 
428  make /wave /free /n=2 result_waves
429  make /free /n=0 dest1, dest2
430  result_waves[0] = dest1
431  result_waves[1] = dest2
432  adh5_setup_profile(source, dest1, 1)
433  adh5_setup_profile(source, dest2, 1)
434 
435  // validate parameters
436  // background parameters are optional, center parameter is required.
437  if (numtype(lcrop) != 0)
438  lcrop = 0
439  endif
440  if (numtype(lsize) != 0)
441  lsize = 0
442  endif
443  if (numtype(hcrop) != 0)
444  hcrop = 0
445  endif
446  if (numtype(hsize) != 0)
447  hsize = 0
448  endif
449  if (numtype(Cpos) != 0)
450  redimension /n=0 result_waves
451  return result_waves // Cpos parameter missing
452  endif
453  if (numtype(Csize) != 0)
454  redimension /n=0 result_waves
455  return result_waves // Csize parameter missing
456  endif
457 
458  // crop boundaries
459  variable pcl = round(lcrop * nx)
460  variable pch = round((1 - hcrop) * nx)
461  // fit boundaries
462  variable pfl = round((lcrop + lsize) * nx)
463  variable pfh = round((1 - hcrop - hsize) * nx)
464  // integration boundaries
465  variable pil = round((cpos - csize/2) * nx)
466  variable pih = round((cpos + csize/2) * nx)
467 
468  // prepare intermediate data buffer
469  make /n=(nx) /d /free profile, mask, fit
470  setscale /p x dimoffset(source,0), dimdelta(source,0), waveunits(source,0), profile, mask, fit
471  mask = ((p >= pcl) && (p < pfl)) || ((p >= pfh) && (p < pch))
472 
473  variable qq
474  variable sp, sf
475  variable xil = x2pnt(profile, pil)
476  variable xih = x2pnt(profile, pih)
477 
478  make /n=3 /free /d w_coef
479  for (qq = 0; qq < ny; qq += 1)
480  profile = source[p][qq]
481  curvefit /Q /NTHR=1 /W=2 poly 3, kwCWave=w_coef, profile /M=mask
482  fit = poly(w_coef, x)
483  sp = sum(profile, xil, xih)
484  sf = sum(fit, xil, xih)
485  dest1[qq] = sp - sf
486  dest2[qq] = sqrt(sp)
487  endfor
488 
489  string s_note1
490  string s_note2
491  sprintf s_note1, "AxisLabelD=peak integral"
492  sprintf s_note2, "KineticEnergy=%.3f", cpos * nx * dimdelta(source, 0) + dimoffset(source, 0)
493  Note dest1, s_note1
494  Note dest1, s_note2
495  Note dest2, s_note1
496  Note dest2, s_note2
497 
498  return result_waves
499 end
500 
510  string &param
511 
512  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
513  variable Lsize = NumberByKey("Lsize", param, "=", ";")
514  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
515  variable Hsize = NumberByKey("Hsize", param, "=", ";")
516  variable Cpos = NumberByKey("Cpos", param, "=", ";")
517  variable Csize = NumberByKey("Csize", param, "=", ";")
518 
519  prompt Lcrop, "Lower cropping region"
520  prompt Hcrop, "Upper cropping region"
521  prompt Lsize, "Lower background region"
522  prompt Hsize, "Upper background region"
523  prompt Cpos, "Center position"
524  prompt Csize, "Center integration region"
525 
526  doprompt "redim_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
527  if (v_flag == 0)
528  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
529  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
530  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
531  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
532  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
533  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
534  endif
535 
536  return v_flag
537 end
538 
572 threadsafe function /wave redim_linbg_reduction(source, param)
573  wave source
574  string &param
575 
576  variable nx = dimsize(source, 0)
577  variable ny = dimsize(source, 1)
578 
579  duplicate /free source, source_redim
580  redimension /n=(nx * ny) source_redim
581  nx += 1
582  redimension /n=(nx, ny) source_redim
583 
584  return int_linbg_reduction(source_redim, param)
585 end
586 
592 function test_gauss4_reduction(image)
593  wave image
594 
595  string param = ""
596 
597  param = ReplaceNumberByKey("rngl", param, -inf, "=", ";")
598  param = ReplaceNumberByKey("rngh", param, inf, "=", ";")
599  param = ReplaceNumberByKey("npeaks", param, 4, "=", ";")
600  param = ReplaceNumberByKey("ybox", param, 1, "=", ";")
601  param = ReplaceNumberByKey("pos1", param, 11, "=", ";")
602  param = ReplaceNumberByKey("wid1", param, 0.1, "=", ";")
603  param = ReplaceNumberByKey("pos2", param, 12, "=", ";")
604  param = ReplaceNumberByKey("wid2", param, 0.2, "=", ";")
605  param = ReplaceNumberByKey("pos3", param, 13, "=", ";")
606  param = ReplaceNumberByKey("wid3", param, 0.3, "=", ";")
607  param = ReplaceNumberByKey("pos4", param, 14, "=", ";")
608  param = ReplaceNumberByKey("wid4", param, 0.4, "=", ";")
609 
610  wave /wave results = gauss4_reduction(image, param)
611 
612  variable npk = numpnts(results) / 2
613  variable ipk
614  string sw
615  for (ipk = 0; ipk < npk; ipk += 1)
616  sw = "test_int_" + num2str(ipk + 1)
617  duplicate /o results[ipk], $sw
618  sw = "test_sig_" + num2str(ipk + 1)
619  duplicate /o results[ipk + npk], $sw
620  endfor
621 end
622 
626 function prompt_gauss4_reduction(param)
627  string &param
628 
629  variable rngl = NumberByKey("rngl", param, "=", ";")
630  variable rngh = NumberByKey("rngh", param, "=", ";")
631  variable pos1 = NumberByKey("pos1", param, "=", ";")
632  variable wid1 = NumberByKey("wid1", param, "=", ";")
633  variable pos2 = NumberByKey("pos2", param, "=", ";")
634  variable wid2 = NumberByKey("wid2", param, "=", ";")
635  variable pos3 = NumberByKey("pos3", param, "=", ";")
636  variable wid3 = NumberByKey("wid3", param, "=", ";")
637  variable pos4 = NumberByKey("pos4", param, "=", ";")
638  variable wid4 = NumberByKey("wid4", param, "=", ";")
639  variable npeaks = NumberByKey("npeaks", param, "=", ";")
640  variable ybox = NumberByKey("ybox", param, "=", ";")
641 
642  prompt rngl, "range low"
643  prompt rngh, "range high"
644  prompt pos1, "position 1"
645  prompt wid1, "width 1"
646  prompt pos2, "position 2"
647  prompt wid2, "width 2"
648  prompt pos3, "position 3"
649  prompt wid3, "width 3"
650  prompt pos4, "position 4"
651  prompt wid4, "width 4"
652  prompt npeaks, "number of peaks"
653  prompt ybox, "ybox (1 or 3)"
654 
655  doprompt "gauss4_reduction reduction parameters (1/2)", rngl, rngh, npeaks, ybox
656  if (v_flag == 0)
657  param = ReplaceNumberByKey("rngl", param, rngl, "=", ";")
658  param = ReplaceNumberByKey("rngh", param, rngh, "=", ";")
659  param = ReplaceNumberByKey("npeaks", param, npeaks, "=", ";")
660  param = ReplaceNumberByKey("ybox", param, ybox, "=", ";")
661 
662  doprompt "gauss4_reduction reduction parameters (2/2)", pos1, wid1, pos2, wid2, pos3, wid3, pos4, wid4
663  if (v_flag == 0)
664  param = ReplaceNumberByKey("pos1", param, pos1, "=", ";")
665  param = ReplaceNumberByKey("wid1", param, wid1, "=", ";")
666  param = ReplaceNumberByKey("pos2", param, pos2, "=", ";")
667  param = ReplaceNumberByKey("wid2", param, wid2, "=", ";")
668  param = ReplaceNumberByKey("pos3", param, pos3, "=", ";")
669  param = ReplaceNumberByKey("wid3", param, wid3, "=", ";")
670  param = ReplaceNumberByKey("pos4", param, pos4, "=", ";")
671  param = ReplaceNumberByKey("wid4", param, wid4, "=", ";")
672  endif
673  endif
674 
675  return v_flag
676 end
677 
718 threadsafe function /wave gauss4_reduction(source, param)
719  wave source
720  string &param
721 
722  variable nx = dimsize(source, 0)
723  variable ny = dimsize(source, 1)
724 
725  // read parameters
726  variable rngl = NumberByKey("rngl", param, "=", ";")
727  variable rngh = NumberByKey("rngh", param, "=", ";")
728  variable pos1 = NumberByKey("pos1", param, "=", ";")
729  variable wid1 = NumberByKey("wid1", param, "=", ";")
730  variable pos2 = NumberByKey("pos2", param, "=", ";")
731  variable wid2 = NumberByKey("wid2", param, "=", ";")
732  variable pos3 = NumberByKey("pos3", param, "=", ";")
733  variable wid3 = NumberByKey("wid3", param, "=", ";")
734  variable pos4 = NumberByKey("pos4", param, "=", ";")
735  variable wid4 = NumberByKey("wid4", param, "=", ";")
736  variable npeaks = NumberByKey("npeaks", param, "=", ";")
737  variable ybox = NumberByKey("ybox", param, "=", ";")
738 
739  // prepare curve fit
740  variable ipk
741  make /free xprof
742  adh5_setup_profile(source, xprof, 0)
743  duplicate /free xprof, xprof_sig
744  variable pl = max(x2pnt(xprof, rngl), 0)
745  variable ph = min(x2pnt(xprof, rngh), numpnts(xprof) - 1)
746 
747  make /free /n=(npeaks) peak_coef
748  peak_coef = p * 3 + 2
749  variable n_coef = npeaks * 3 + 2
750  make /free /d /n=14 w_coef, W_sigma
751  w_coef[0] = {0, 0, 1, pos1, wid1, 1, pos2, wid2, 1, pos3, wid3, 1, pos4, wid4}
752  redimension /n=(n_coef) w_coef, w_sigma
753 
754  // text constraints cannot be used in threadsafe functions.
755  // the following matrix-vector forumlation is equivalent to:
756  // make /free /T /N=6 constraints
757  // constraints[0] = {"K2 >= 0", "K5 >= 0", "K8 >= 0", "K11 >= 0", "K1 <= 0", "K0 => 0"}
758  make /free /n=(npeaks + 2, numpnts(w_coef)) cmat
759  make /free /n=(npeaks + 2) cvec
760  cmat = 0
761  cmat[0][0] = -1
762  cmat[1][1] = 1
763  cvec = 0
764 
765  string hold = "00"
766  for (ipk=0; ipk < npeaks; ipk += 1)
767  hold += "011"
768  cmat[2 + ipk][2 + ipk*3] = -1
769  endfor
770 
771  // prepare output
772  make /free /n=(npeaks * 2) /wave result_waves
773  string s_note
774  for (ipk = 0; ipk < npeaks; ipk += 1)
775  make /free /n=0 pk_int
776  adh5_setup_profile(source, pk_int, 1)
777  pk_int = nan
778  sprintf s_note, "AxisLabelD=peak %u integral", ipk+1
779  Note pk_int, s_note
780  sprintf s_note, "KineticEnergy=%.3f", w_coef[3 + ipk * 3]
781  Note pk_int, s_note
782  result_waves[ipk] = pk_int
783 
784  make /free /n=0 pk_sig
785  adh5_setup_profile(source, pk_sig, 1)
786  pk_sig = nan
787  sprintf s_note, "AxisLabelD=peak %u sigma", ipk+1
788  Note pk_sig, s_note
789  sprintf s_note, "KineticEnergy=%.3f", w_coef[3 + ipk * 3]
790  Note pk_sig, s_note
791  result_waves[ipk + npeaks] = pk_sig
792 
793  waveclear pk_int, pk_sig
794  endfor
795 
796  // loop over angle scale
797  variable p0 = 0
798  variable p1 = dimsize(source, 1) - 1
799  variable pp
800  variable wmin
801  variable wmax
802  if (ybox > 1)
803  p0 += ceil((ybox - 1) / 2)
804  p1 -= ceil((ybox - 1) / 2)
805  endif
806  variable V_FitNumIters
807 
808  for (pp = p0; pp <= p1; pp += 1)
809  // box average
810  xprof = source[p][pp]
811  if (ybox > 1)
812  xprof += source[p][pp-1] + source[p][pp+1]
813  endif
814  xprof_sig = max(sqrt(xprof), 1)
815  xprof /= ybox
816  xprof_sig /= ybox
817 
818  // generate guess
819  wmin = wavemin(xprof)
820  wmax = wavemax(xprof)
821  w_coef[0] = wmin
822  w_coef[1] = 0
823 
824  for (ipk=0; ipk < npeaks; ipk += 1)
825  w_coef[2 + ipk*3] = wmax - wmin
826  endfor
827  FuncFit /H=hold /Q /NTHR=1 /N /W=2 MultiGaussLinBG_AO w_coef xprof[pl,ph] /C={cmat, cvec} /I=1 /W=xprof_sig[pl,ph]
828  wave w_sigma
829 
830  // retrieve results, leave them at nan if the fit did not converge
831  if (V_FitNumIters < 40)
832  for (ipk = 0; ipk < npeaks; ipk += 1)
833  wave val = result_waves[ipk]
834  wave sig = result_waves[ipk + npeaks]
835  val[pp] = max(w_coef[peak_coef[ipk]], 0)
836  sig[pp] = max(w_sigma[peak_coef[ipk]], 0)
837  endfor
838  endif
839  endfor
840 
841  // calculate integral
842  for (ipk = 0; ipk < npeaks; ipk += 1)
843  wave val = result_waves[ipk]
844  wave sig = result_waves[ipk + npeaks]
845  val *= w_coef[peak_coef[ipk] + 2] * sqrt(pi)
846  sig *= w_coef[peak_coef[ipk] + 2] * sqrt(pi)
847  endfor
848 
849  return result_waves
850 end
851 
852 
884 function /s find_gauss4_reduction_params(spectrum, peakpos)
885  wave spectrum
886  wave peakpos
887  string param = ""
888 
889  variable wmin = wavemin(spectrum)
890  variable wmax = wavemax(spectrum)
891 
892  // read parameters
893  variable rngl = dimoffset(spectrum, 0)
894  variable rngh = dimoffset(spectrum, 0) + dimdelta(spectrum, 0) * (dimsize(spectrum, 0) - 1)
895  make /n=4 /free positions, widths
896  variable npeaks = numpnts(peakpos)
897  variable ybox = 1
898  positions = 0
899  positions[0, npeaks-1] = peakpos[p]
900  widths = 0.2
901 
902  variable n_coef = npeaks * 3 + 2
903  make /free /d /n=(n_coef) w_coef
904  w_coef = 0
905  w_coef[0] = wmin
906  w_coef[1] = 0
907 
908  make /free /n=(2+npeaks, numpnts(w_coef)) cmat
909  make /free /n=(2+npeaks) cvec
910  cmat = 0
911  cmat[0][0] = -1
912  cmat[1][1] = 1
913  cvec = 0
914 
915  variable ip
916  for (ip=0; ip < npeaks; ip += 1)
917  cmat[2 + ip][2 + ip*3] = -1
918  w_coef[2 + ip*3] = wmax - wmin
919  w_coef[3 + ip*3] = peakpos[ip]
920  w_coef[4 + ip*3] = widths[ip]
921  endfor
922 
923  variable V_FitNumIters
924  FuncFit /Q /NTHR=1 /N MultiGaussLinBG w_coef spectrum /C={cmat, cvec}
925 
926  for (ip=0; ip < npeaks; ip += 1)
927  positions[ip] = w_coef[3 + ip * 3]
928  widths[ip ] = abs(w_coef[4 + ip * 3])
929  endfor
930  for (ip=npeaks; ip < 4; ip += 1)
931  positions[ip] = 0
932  widths[ip] = 0.2
933  endfor
934 
935  param = ReplaceNumberByKey("rngl", param, rngl, "=", ";")
936  param = ReplaceNumberByKey("rngh", param, rngh, "=", ";")
937  param = ReplaceNumberByKey("npeaks", param, npeaks, "=", ";")
938  param = ReplaceNumberByKey("ybox", param, ybox, "=", ";")
939  param = ReplaceNumberByKey("pos1", param, positions[0], "=", ";")
940  param = ReplaceNumberByKey("wid1", param, widths[0], "=", ";")
941  param = ReplaceNumberByKey("pos2", param, positions[1], "=", ";")
942  param = ReplaceNumberByKey("wid2", param, widths[1], "=", ";")
943  param = ReplaceNumberByKey("pos3", param, positions[2], "=", ";")
944  param = ReplaceNumberByKey("wid3", param, widths[2], "=", ";")
945  param = ReplaceNumberByKey("pos4", param, positions[3], "=", ";")
946  param = ReplaceNumberByKey("wid4", param, widths[3], "=", ";")
947 
948  return param
949 end
950 
958 function test_shockley_anglefit(image, branch)
959  wave image
960  variable branch
961 
962  string param = ""
963  param = ReplaceStringByKey("branch", param, num2str(branch), "=", ";")
964 
965  string s_branch
966  if (branch >= 0)
967  s_branch = "p"
968  else
969  s_branch = "n"
970  endif
971  string pkpos_name = "saf_pkpos_" + s_branch
972  string pkwid_name = "saf_pkwid_" + s_branch
973 
974  wave /wave results = shockley_anglefit(image, param)
975  duplicate results[0], $pkpos_name
976  duplicate results[1], $pkwid_name
977 end
978 
979 function prompt_Shockley_anglefit(param)
980  string &param
981 
982  variable branch = NumberByKey("branch", param, "=", ";")
983 
984  prompt branch, "Branch (-1 or +1)"
985 
986  doprompt "Shockley_anglefit_reduction Parameters", branch
987  if (v_flag == 0)
988  param = ReplaceNumberByKey("branch", param, branch, "=", ";")
989  endif
990 
991  return v_flag
992 end
993 
1016 threadsafe function /wave Shockley_anglefit(source, param)
1017  wave source
1018  string &param
1019 
1020  variable nx = dimsize(source, 0)
1021  variable ny = dimsize(source, 1)
1022 
1023  // read parameters
1024  variable branch = NumberByKey("branch", param, "=", ";")
1025 
1026  // validate parameters
1027  if (numtype(branch) != 0)
1028  branch = +1
1029  endif
1030 
1031  // prepare output
1032  make /wave /free /n=2 result_waves
1033  make /free /n=0 dest1, dest2
1034  result_waves[0] = dest1
1035  result_waves[1] = dest2
1036  adh5_setup_profile(source, dest1, 0)
1037  adh5_setup_profile(source, dest2, 0)
1038  dest1 = nan
1039  dest2 = nan
1040 
1041  // select angle range
1042  // hard-coded for a particular measurement series
1043  variable y0
1044  variable y1
1045  if (branch < 0)
1046  y0 = -5
1047  y1 = 0
1048  else
1049  y0 = 0
1050  y1 = 5
1051  endif
1052 
1053  // select energy range
1054  // start at the point of highest intensity and go up 0.45 eV
1055  variable p0
1056  variable p1
1057  variable q0
1058  variable q1
1059  duplicate /free dest1, center
1060  q0 = round((y0 - dimoffset(source, 1)) / dimdelta(source, 1))
1061  q1 = round((y1 - dimoffset(source, 1)) / dimdelta(source, 1))
1062  ad_profile_x_w(source, q0, q1, center)
1063  wavestats /q/m=1 center
1064  p0 = round((v_maxloc - dimoffset(source, 0)) / dimdelta(source, 0))
1065  p1 = round((v_maxloc + 0.4 - dimoffset(source, 0)) / dimdelta(source, 0))
1066 
1067  // prepare intermediate data buffer
1068  make /n=(ny)/d/free profile
1069  setscale /p x dimoffset(source,1), dimdelta(source,1), waveunits(source,1), profile
1070 
1071  variable pp
1072  for (pp = p0; pp <= p1; pp += 1)
1073  profile = source[pp][p]
1074  curvefit /Q /NTHR=1 /W=2 gauss profile(y0,y1)
1075  wave w_coef
1076  dest1[pp] = w_coef[2]
1077  dest2[pp] = w_coef[3]
1078  endfor
1079 
1080  return result_waves
1081 end
1082 
1083 function scienta_norm(w, x): fitfunc
1084  wave w
1085  variable x
1086 
1087  return w[0] * (x^2 - w[1]^2)
1088 end
1089 
1090 function /wave fit_scienta_ang_transm(data, params)
1091  wave data // measured angular distribution (1D)
1092  wave /z params
1093 
1094  if (!waveexists(params))
1095  make /n=12 /o params
1096  endif
1097  redimension /n=12/d params
1098 
1099  variable h = wavemax(data) - wavemin(data)
1100  params[0] = h / 2
1101  params[1] = 0
1102  params[2] = 7
1103  params[3] = h / 4
1104  params[4] = -23
1105  params[5] = 4
1106  params[6] = h / 4
1107  params[7] = +23
1108  params[8] = 4
1109  params[9] = h / 2
1110  params[10] = 0
1111  params[11] = -0.001
1112  FuncFit /NTHR=0 /q scienta_ang_transm params data
1113 
1114  return params
1115 end
1116 
1117 threadsafe function scienta_ang_transm(w, x): fitfunc
1118  // parameterized angular transmission function of the analyser
1119  wave w // coefficients
1120  // w[0] = amplitude gauss 1
1121  // w[1] = position gauss 1
1122  // w[2] = width gauss 1
1123  // w[3] = amplitude gauss 2
1124  // w[4] = position gauss 2
1125  // w[5] = width gauss 2
1126  // w[6] = amplitude gauss 3
1127  // w[7] = position gauss 3
1128  // w[8] = width gauss 3
1129  // w[9] = constant background
1130  // w[10] = linear background
1131  // w[11] = quadratic background
1132  variable x
1133 
1134  make /free /n=4 /d w_int
1135  w_int[0] = 0
1136  w_int[1,] = w[p - 1]
1137  variable pk1 = gauss1d(w_int, x)
1138  w_int[1,] = w[p + 2]
1139  variable pk2 = gauss1d(w_int, x)
1140  w_int[1,] = w[p + 5]
1141  variable pk3 = gauss1d(w_int, x)
1142  w_int[0,2] = w[9 + p]
1143  w_int[3] = 0
1144  variable bg = poly(w_int, x)
1145 
1146  return bg + pk1 + pk2 + pk3
1147 end
1148 
1149 function /wave fit_scienta_poly_bg(data, params, bgterms)
1150  wave data // measured distribution (2D)
1151  wave /z params // wave, will be redimensioned for the correct size
1152  variable bgterms // number of terms in the polynomial background: 2, 3, or 4
1153 
1154  if (!waveexists(params))
1155  make /n=15 /o params
1156  endif
1157  redimension /n=15 /d params
1158 
1159  variable wmax = wavemax(data)
1160  variable wmin = wavemin(data)
1161  params[0] = 0
1162  params[1] = 7
1163  params[2] = 1 / 2
1164  params[3] = -23
1165  params[4] = 4
1166  params[5] = 1 / 2
1167  params[6] = +23
1168  params[7] = 4
1169  params[8] = 1
1170  params[9] = 0
1171  params[10] = -0.001
1172  params[11] = wmin
1173  params[12] = (wmax - wmin) / dimdelta(data,1) / dimsize(data,1)
1174  params[13] = 0
1175  params[14] = 0
1176 
1177  string h = "0000000000000"
1178  if (bgterms < 3)
1179  h = h + "1"
1180  else
1181  h = h + "0"
1182  endif
1183  if (bgterms < 4)
1184  h = h + "1"
1185  else
1186  h = h + "0"
1187  endif
1188  FuncFitMD /NTHR=1 /q /h=h scienta_poly_bg params data
1189 
1190  return params
1191 end
1192 
1193 function scienta_poly_bg(w, e, a): fitfunc
1194  // polynomial background with
1195  // parameterized angular transmission function of the analyser
1196  wave w // coefficients
1197  // angular transmission, varies with a
1198  // amplitude of gauss 1 = 1 constant
1199  // other peak amplitudes and linear terms are relative to gauss 1
1200  // w[0] = position gauss 1
1201  // w[1] = width gauss 1
1202  // w[2] = amplitude gauss 2, relative to gauss 1
1203  // w[3] = position gauss 2
1204  // w[4] = width gauss 2
1205  // w[5] = amplitude gauss 3, relative to gauss 1
1206  // w[6] = position gauss 3
1207  // w[7] = width gauss 3
1208  // w[8] = constant term
1209  // w[9] = linear term
1210  // w[10] = quadratic term
1211  // spectral background, varies with e
1212  // w[11] = constant term
1213  // w[12] = linear term
1214  // w[13] = quadratic term
1215  // w[14] = cubic term
1216  variable a // detection angle
1217  variable e // electron energy
1218 
1219  make /free /n=4 /d w_int
1220  variable p0 = 0
1221 
1222  w_int[0] = 0
1223  w_int[1] = 1
1224  w_int[2,] = w[p0 + p - 2]
1225  variable pk1 = gauss1d(w_int, a)
1226  p0 += 2
1227 
1228  w_int[1,] = w[p0 + p - 1]
1229  variable pk2 = gauss1d(w_int, a)
1230  p0 += 3
1231 
1232  w_int[1,] = w[p0 + p - 1]
1233  variable pk3 = gauss1d(w_int, a)
1234  p0 += 3
1235 
1236  w_int[0,2] = w[p0 + p]
1237  w_int[3] = 0
1238  variable base = poly(w_int, a)
1239  p0 += 3
1240 
1241  w_int[0,3] = w[p0 + p]
1242  variable bg = poly(w_int, e)
1243 
1244  return bg * (base + pk1 + pk2 + pk3)
1245 end
threadsafe variable MultiGaussLinBG(wave w, variable x)
multiple gaussian peaks on a linear background fit function.
threadsafe variable MultiGaussLinBG_AO(wave pw, wave yw, wave xw)
multiple gaussian peaks on a linear background fit function (all at once).
variable prompt_gauss4_reduction(string *param)
prompt for the gauss4_reduction parameters
threadsafe wave redim_linbg_reduction(wave source, string *param)
linear background reduction function for incorrectly dimensioned scienta image
variable test_gauss4_reduction(wave image)
apply the gauss4_reduction function to a single image
threadsafe wave ad_profile_x_w(wave dataset, variable q1, variable q2, wave destwave, variable noavg=defaultValue)
1D cut through 2D dataset along X dimension, existing destination wave.
threadsafe variable adh5_setup_profile(wave image, wave profile, variable dim)
set up a one-dimensional wave for a line profile based on a 2D original wave.
variable prompt_int_quadbg_reduction(string *param)
threadsafe wave int_linbg_reduction(wave source, string *param)
linear-background subtracted integration reduction function.
threadsafe wave gauss4_reduction(wave source, string *param)
fit horizontal cuts of an image with up to four gaussian peaks on a linear background ...
variable prompt_redim_linbg_reduction(string *param)
parameter dialog for the redim_linbg_reduction() function
threadsafe wave ad_profile_y_w(wave dataset, variable p1, variable p2, wave destwave, variable noavg=defaultValue)
1D cut through 2D dataset along X dimension, existing destination wave.
threadsafe wave int_quadbg_reduction(wave source, string *param)
integrate peak area minus a quadratic background
variable prompt_int_linbg_reduction(string *param)
prompt the user for integrate on linear background reduction parameters.
string csr_int_linbg_reduction(string win)
calculate linear background reduction parameters from cursors in a graph.
string capture_int_linbg_cursors()
capture linear background reduction parameters from cursors in a graph.