PEARL Procedures  rev-distro-2.0.3-0-g0fb0fd9
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 
68  string param = csr_int_linbg_reduction("")
69  svar /z global_params = root:packages:pearl_explorer:s_reduction_params
70  if (svar_exists(global_params))
71  global_params = param
72  endif
73  return param
74 end
75 
89 function /s csr_int_linbg_reduction(win)
90  string win
91 
92  // read all cursor positions
93  variable ic
94  string sc
95  variable nc = 10
96  make /n=(nc) /free positions
97  variable np = 0
98  wave /z image = $""
99  string imagename = ""
100  string tracename = ""
101  string info
102 
103  for (ic = 0; ic < nc; ic += 1)
104  sc = num2char(char2num("A") + ic)
105  wave /z wc = CsrWaveRef($sc, win)
106  info = CsrInfo($sc, win)
107  tracename = StringByKey("TNAME", info, ":", ";")
108  if (waveexists(wc) && (wavedims(wc) == 2))
109  if (!waveexists(image))
110  wave image = wc
111  imagename = tracename
112  endif
113  if (cmpstr(tracename, imagename) == 0)
114  positions[np] = pcsr($sc, win)
115  np += 1
116  endif
117  endif
118  endfor
119 
120  np = floor(np / 2) * 2 // ignore odd cursor
121  redimension /n=(np) positions
122  sort positions, positions
123  // shift upper positions by one so that the rightmost pixel becomes 1.0
124  positions = p >= np / 2 ? positions + 1 : positions
125  positions = positions / dimsize(image, 0)
126 
127  // map innermost cursor pair to peak center and size
128  variable ip2 = np / 2
129  variable ip1 = ip2 - 1
130  variable Cpos = (positions[ip1] + positions[ip2]) / 2
131  variable Csize = positions[ip2] - positions[ip1]
132  if (ip1 >= 0)
133  Cpos = (positions[ip1] + positions[ip2]) / 2
134  Csize = positions[ip2] - positions[ip1]
135  else
136  // default: a small region in the center
137  Cpos = 0.5
138  Csize = 0.2
139  endif
140 
141  // background region
142  ip1 -= 1
143  ip2 += 1
144  variable Lsize
145  variable Hsize
146  if (ip1 >= 0)
147  Lsize = positions[ip1]
148  Hsize = 1 - positions[ip2]
149  else
150  // default: everything outside the peak region
151  Lsize = Cpos - Csize / 2
152  Hsize = 1 - (Cpos + Csize / 2)
153  endif
154 
155  // crop region
156  ip1 -= 1
157  ip2 += 1
158  variable Lcrop
159  variable Hcrop
160  if (ip1 >= 0)
161  Lcrop = positions[ip1]
162  Hcrop = 1 - positions[ip2]
163  else
164  // default: dead corners of the EW4000 at PEARL
165  Lcrop = 0.11
166  Hcrop = 0.11
167  endif
168  Lsize = max(Lsize - Lcrop, 0)
169  Hsize = max(Hsize - Hcrop, 0)
170 
171  string param = ""
172  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
173  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
174  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
175  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
176  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
177  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
178 
179  return param
180 end
181 
214 threadsafe function /wave int_linbg_reduction(source, param)
215  wave source
216  string &param
217 
218  variable nx = dimsize(source, 0)
219  variable ny = dimsize(source, 1)
220 
221  // read parameters
222  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
223  variable lsize = NumberByKey("Lsize", param, "=", ";")
224  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
225  variable hsize = NumberByKey("Hsize", param, "=", ";")
226  variable cpos = NumberByKey("Cpos", param, "=", ";")
227  variable csize = NumberByKey("Csize", param, "=", ";")
228 
229  make /wave /free /n=2 result_waves
230  make /free /n=0 dest1, dest2
231  result_waves[0] = dest1
232  result_waves[1] = dest2
233  adh5_setup_profile(source, dest1, 1)
234  adh5_setup_profile(source, dest2, 1)
235 
236  // validate parameters
237  // background parameters are optional, center parameter is required.
238  if (numtype(lcrop) != 0)
239  lcrop = 0
240  endif
241  if (numtype(lsize) != 0)
242  lsize = 0
243  endif
244  if (numtype(hcrop) != 0)
245  hcrop = 0
246  endif
247  if (numtype(hsize) != 0)
248  hsize = 0
249  endif
250  if (numtype(Cpos) != 0)
251  redimension /n=0 result_waves
252  return result_waves // Cpos parameter missing
253  endif
254  if (numtype(Csize) != 0)
255  redimension /n=0 result_waves
256  return result_waves // Csize parameter missing
257  endif
258 
259  variable lpos = lcrop + lsize / 2
260  variable hpos = 1 - (hcrop + hsize / 2)
261 
262  variable p0
263  variable p1
264 
265  duplicate /free dest1, lbg, hbg
266  if (lsize > 0)
267  p0 = round(lcrop * nx)
268  p1 = round((lcrop + lsize) * nx)
269  ad_profile_y_w(source, p0, p1, lbg)
270  else
271  lbg = 0
272  endif
273  if (hsize > 0)
274  p0 = round((1 - hcrop - hsize) * nx)
275  p1 = round((1 - hcrop) * nx)
276  ad_profile_y_w(source, p0, p1, hbg)
277  else
278  hbg = 0
279  endif
280  if (csize > 0)
281  p0 = round((cpos - csize/2) * nx)
282  p1 = round((cpos + csize/2) * nx)
283  ad_profile_y_w(source, p0, p1, dest1)
284  else
285  dest1 = 0
286  endif
287 
288  variable scale = (cpos - lpos) / (hpos - lpos)
289  dest2 = dest1
290  dest1 -= scale * (hbg - lbg) + lbg
291  dest2 = sqrt(dest2 + scale^2 * (hbg + lbg))
292 
293  string s_note1
294  string s_note2
295  sprintf s_note1, "AxisLabelD=peak integral"
296  sprintf s_note2, "KineticEnergy=%.3f", cpos * nx * dimdelta(source, 0) + dimoffset(source, 0)
297  Note dest1, s_note1
298  Note dest1, s_note2
299  Note dest2, s_note1
300  Note dest2, s_note2
301 
302  return result_waves
303 end
304 
306  string &param
307 
308  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
309  variable Lsize = NumberByKey("Lsize", param, "=", ";")
310  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
311  variable Hsize = NumberByKey("Hsize", param, "=", ";")
312  variable Cpos = NumberByKey("Cpos", param, "=", ";")
313  variable Csize = NumberByKey("Csize", param, "=", ";")
314 
315  prompt Lcrop, "Lower cropping region"
316  prompt Hcrop, "Upper cropping region"
317  prompt Lsize, "Lower background region"
318  prompt Hsize, "Upper background region"
319  prompt Cpos, "Center position"
320  prompt Csize, "Center integration region"
321 
322  doprompt "int_quadbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
323  if (v_flag == 0)
324  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
325  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
326  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
327  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
328  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
329  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
330  endif
331 
332  return v_flag
333 end
334 
367 threadsafe function /wave int_quadbg_reduction(source, param)
368  wave source
369  string &param
370 
371  variable nx = dimsize(source, 0)
372  variable ny = dimsize(source, 1)
373 
374  // read parameters
375  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
376  variable lsize = NumberByKey("Lsize", param, "=", ";")
377  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
378  variable hsize = NumberByKey("Hsize", param, "=", ";")
379  variable cpos = NumberByKey("Cpos", param, "=", ";")
380  variable csize = NumberByKey("Csize", param, "=", ";")
381 
382  make /wave /free /n=2 result_waves
383  make /free /n=0 dest1, dest2
384  result_waves[0] = dest1
385  result_waves[1] = dest2
386  adh5_setup_profile(source, dest1, 1)
387  adh5_setup_profile(source, dest2, 1)
388 
389  // validate parameters
390  // background parameters are optional, center parameter is required.
391  if (numtype(lcrop) != 0)
392  lcrop = 0
393  endif
394  if (numtype(lsize) != 0)
395  lsize = 0
396  endif
397  if (numtype(hcrop) != 0)
398  hcrop = 0
399  endif
400  if (numtype(hsize) != 0)
401  hsize = 0
402  endif
403  if (numtype(Cpos) != 0)
404  redimension /n=0 result_waves
405  return result_waves // Cpos parameter missing
406  endif
407  if (numtype(Csize) != 0)
408  redimension /n=0 result_waves
409  return result_waves // Csize parameter missing
410  endif
411 
412  // crop boundaries
413  variable pcl = round(lcrop * nx)
414  variable pch = round((1 - hcrop) * nx)
415  // fit boundaries
416  variable pfl = round((lcrop + lsize) * nx)
417  variable pfh = round((1 - hcrop - hsize) * nx)
418  // integration boundaries
419  variable pil = round((cpos - csize/2) * nx)
420  variable pih = round((cpos + csize/2) * nx)
421 
422  // prepare intermediate data buffer
423  make /n=(nx) /d /free profile, mask, fit
424  setscale /p x dimoffset(source,0), dimdelta(source,0), waveunits(source,0), profile, mask, fit
425  mask = ((p >= pcl) && (p < pfl)) || ((p >= pfh) && (p < pch))
426 
427  variable qq
428  variable sp, sf
429  variable xil = x2pnt(profile, pil)
430  variable xih = x2pnt(profile, pih)
431 
432  make /n=3 /free /d w_coef
433  for (qq = 0; qq < ny; qq += 1)
434  profile = source[p][qq]
435  curvefit /Q /NTHR=1 /W=2 poly 3, kwCWave=w_coef, profile /M=mask
436  fit = poly(w_coef, x)
437  sp = sum(profile, xil, xih)
438  sf = sum(fit, xil, xih)
439  dest1[qq] = sp - sf
440  dest2[qq] = sqrt(sp)
441  endfor
442 
443  string s_note1
444  string s_note2
445  sprintf s_note1, "AxisLabelD=peak integral"
446  sprintf s_note2, "KineticEnergy=%.3f", cpos * nx * dimdelta(source, 0) + dimoffset(source, 0)
447  Note dest1, s_note1
448  Note dest1, s_note2
449  Note dest2, s_note1
450  Note dest2, s_note2
451 
452  return result_waves
453 end
454 
464  string &param
465 
466  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
467  variable Lsize = NumberByKey("Lsize", param, "=", ";")
468  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
469  variable Hsize = NumberByKey("Hsize", param, "=", ";")
470  variable Cpos = NumberByKey("Cpos", param, "=", ";")
471  variable Csize = NumberByKey("Csize", param, "=", ";")
472 
473  prompt Lcrop, "Lower cropping region"
474  prompt Hcrop, "Upper cropping region"
475  prompt Lsize, "Lower background region"
476  prompt Hsize, "Upper background region"
477  prompt Cpos, "Center position"
478  prompt Csize, "Center integration region"
479 
480  doprompt "redim_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
481  if (v_flag == 0)
482  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
483  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
484  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
485  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
486  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
487  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
488  endif
489 
490  return v_flag
491 end
492 
526 threadsafe function /wave redim_linbg_reduction(source, param)
527  wave source
528  string &param
529 
530  variable nx = dimsize(source, 0)
531  variable ny = dimsize(source, 1)
532 
533  duplicate /free source, source_redim
534  redimension /n=(nx * ny) source_redim
535  nx += 1
536  redimension /n=(nx, ny) source_redim
537 
538  return int_linbg_reduction(source_redim, param)
539 end
540 
546 function test_gauss4_reduction(image)
547  wave image
548 
549  string param = ""
550 
551  param = ReplaceNumberByKey("rngl", param, -inf, "=", ";")
552  param = ReplaceNumberByKey("rngh", param, inf, "=", ";")
553  param = ReplaceNumberByKey("npeaks", param, 4, "=", ";")
554  param = ReplaceNumberByKey("ybox", param, 1, "=", ";")
555  param = ReplaceNumberByKey("pos1", param, 11, "=", ";")
556  param = ReplaceNumberByKey("wid1", param, 0.1, "=", ";")
557  param = ReplaceNumberByKey("pos2", param, 12, "=", ";")
558  param = ReplaceNumberByKey("wid2", param, 0.2, "=", ";")
559  param = ReplaceNumberByKey("pos3", param, 13, "=", ";")
560  param = ReplaceNumberByKey("wid3", param, 0.3, "=", ";")
561  param = ReplaceNumberByKey("pos4", param, 14, "=", ";")
562  param = ReplaceNumberByKey("wid4", param, 0.4, "=", ";")
563 
564  wave /wave results = gauss4_reduction(image, param)
565 
566  variable npk = numpnts(results) / 2
567  variable ipk
568  string sw
569  for (ipk = 0; ipk < npk; ipk += 1)
570  sw = "test_int_" + num2str(ipk + 1)
571  duplicate /o results[ipk], $sw
572  sw = "test_sig_" + num2str(ipk + 1)
573  duplicate /o results[ipk + npk], $sw
574  endfor
575 end
576 
580 function prompt_gauss4_reduction(param)
581  string &param
582 
583  variable rngl = NumberByKey("rngl", param, "=", ";")
584  variable rngh = NumberByKey("rngh", param, "=", ";")
585  variable pos1 = NumberByKey("pos1", param, "=", ";")
586  variable wid1 = NumberByKey("wid1", param, "=", ";")
587  variable pos2 = NumberByKey("pos2", param, "=", ";")
588  variable wid2 = NumberByKey("wid2", param, "=", ";")
589  variable pos3 = NumberByKey("pos3", param, "=", ";")
590  variable wid3 = NumberByKey("wid3", param, "=", ";")
591  variable pos4 = NumberByKey("pos4", param, "=", ";")
592  variable wid4 = NumberByKey("wid4", param, "=", ";")
593  variable npeaks = NumberByKey("npeaks", param, "=", ";")
594  variable ybox = NumberByKey("ybox", param, "=", ";")
595 
596  prompt rngl, "range low"
597  prompt rngh, "range high"
598  prompt pos1, "position 1"
599  prompt wid1, "width 1"
600  prompt pos2, "position 2"
601  prompt wid2, "width 2"
602  prompt pos3, "position 3"
603  prompt wid3, "width 3"
604  prompt pos4, "position 4"
605  prompt wid4, "width 4"
606  prompt npeaks, "number of peaks"
607  prompt ybox, "ybox (1 or 3)"
608 
609  doprompt "gauss4_reduction reduction parameters (1/2)", rngl, rngh, npeaks, ybox
610  if (v_flag == 0)
611  param = ReplaceNumberByKey("rngl", param, rngl, "=", ";")
612  param = ReplaceNumberByKey("rngh", param, rngh, "=", ";")
613  param = ReplaceNumberByKey("npeaks", param, npeaks, "=", ";")
614  param = ReplaceNumberByKey("ybox", param, ybox, "=", ";")
615 
616  doprompt "gauss4_reduction reduction parameters (2/2)", pos1, wid1, pos2, wid2, pos3, wid3, pos4, wid4
617  if (v_flag == 0)
618  param = ReplaceNumberByKey("pos1", param, pos1, "=", ";")
619  param = ReplaceNumberByKey("wid1", param, wid1, "=", ";")
620  param = ReplaceNumberByKey("pos2", param, pos2, "=", ";")
621  param = ReplaceNumberByKey("wid2", param, wid2, "=", ";")
622  param = ReplaceNumberByKey("pos3", param, pos3, "=", ";")
623  param = ReplaceNumberByKey("wid3", param, wid3, "=", ";")
624  param = ReplaceNumberByKey("pos4", param, pos4, "=", ";")
625  param = ReplaceNumberByKey("wid4", param, wid4, "=", ";")
626  endif
627  endif
628 
629  return v_flag
630 end
631 
672 threadsafe function /wave gauss4_reduction(source, param)
673  wave source
674  string &param
675 
676  variable nx = dimsize(source, 0)
677  variable ny = dimsize(source, 1)
678 
679  // read parameters
680  variable rngl = NumberByKey("rngl", param, "=", ";")
681  variable rngh = NumberByKey("rngh", param, "=", ";")
682  variable pos1 = NumberByKey("pos1", param, "=", ";")
683  variable wid1 = NumberByKey("wid1", param, "=", ";")
684  variable pos2 = NumberByKey("pos2", param, "=", ";")
685  variable wid2 = NumberByKey("wid2", param, "=", ";")
686  variable pos3 = NumberByKey("pos3", param, "=", ";")
687  variable wid3 = NumberByKey("wid3", param, "=", ";")
688  variable pos4 = NumberByKey("pos4", param, "=", ";")
689  variable wid4 = NumberByKey("wid4", param, "=", ";")
690  variable npeaks = NumberByKey("npeaks", param, "=", ";")
691  variable ybox = NumberByKey("ybox", param, "=", ";")
692 
693  // prepare curve fit
694  variable ipk
695  make /free xprof
696  adh5_setup_profile(source, xprof, 0)
697  duplicate /free xprof, xprof_sig
698  variable pl = max(x2pnt(xprof, rngl), 0)
699  variable ph = min(x2pnt(xprof, rngh), numpnts(xprof) - 1)
700 
701  make /free /n=(npeaks) peak_coef
702  peak_coef = p * 3 + 2
703  variable n_coef = npeaks * 3 + 2
704  make /free /d /n=14 w_coef, W_sigma
705  w_coef[0] = {0, 0, 1, pos1, wid1, 1, pos2, wid2, 1, pos3, wid3, 1, pos4, wid4}
706  redimension /n=(n_coef) w_coef, w_sigma
707 
708  // text constraints cannot be used in threadsafe functions.
709  // the following matrix-vector forumlation is equivalent to:
710  // make /free /T /N=6 constraints
711  // constraints[0] = {"K2 >= 0", "K5 >= 0", "K8 >= 0", "K11 >= 0", "K1 <= 0", "K0 => 0"}
712  make /free /n=(npeaks + 2, numpnts(w_coef)) cmat
713  make /free /n=(npeaks + 2) cvec
714  cmat = 0
715  cmat[0][0] = -1
716  cmat[1][1] = 1
717  cvec = 0
718 
719  string hold = "00"
720  for (ipk=0; ipk < npeaks; ipk += 1)
721  hold += "011"
722  cmat[2 + ipk][2 + ipk*3] = -1
723  endfor
724 
725  // prepare output
726  make /free /n=(npeaks * 2) /wave result_waves
727  string s_note
728  for (ipk = 0; ipk < npeaks; ipk += 1)
729  make /free /n=0 pk_int
730  adh5_setup_profile(source, pk_int, 1)
731  pk_int = nan
732  sprintf s_note, "AxisLabelD=peak %u integral", ipk+1
733  Note pk_int, s_note
734  sprintf s_note, "KineticEnergy=%.3f", w_coef[3 + ipk * 3]
735  Note pk_int, s_note
736  result_waves[ipk] = pk_int
737 
738  make /free /n=0 pk_sig
739  adh5_setup_profile(source, pk_sig, 1)
740  pk_sig = nan
741  sprintf s_note, "AxisLabelD=peak %u sigma", ipk+1
742  Note pk_sig, s_note
743  sprintf s_note, "KineticEnergy=%.3f", w_coef[3 + ipk * 3]
744  Note pk_sig, s_note
745  result_waves[ipk + npeaks] = pk_sig
746 
747  waveclear pk_int, pk_sig
748  endfor
749 
750  // loop over angle scale
751  variable p0 = 0
752  variable p1 = dimsize(source, 1) - 1
753  variable pp
754  variable wmin
755  variable wmax
756  if (ybox > 1)
757  p0 += ceil((ybox - 1) / 2)
758  p1 -= ceil((ybox - 1) / 2)
759  endif
760  variable V_FitNumIters
761 
762  for (pp = p0; pp <= p1; pp += 1)
763  // box average
764  xprof = source[p][pp]
765  if (ybox > 1)
766  xprof += source[p][pp-1] + source[p][pp+1]
767  endif
768  xprof_sig = max(sqrt(xprof), 1)
769  xprof /= ybox
770  xprof_sig /= ybox
771 
772  // generate guess
773  wmin = wavemin(xprof)
774  wmax = wavemax(xprof)
775  w_coef[0] = wmin
776  w_coef[1] = 0
777 
778  for (ipk=0; ipk < npeaks; ipk += 1)
779  w_coef[2 + ipk*3] = wmax - wmin
780  endfor
781  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]
782  wave w_sigma
783 
784  // retrieve results, leave them at nan if the fit did not converge
785  if (V_FitNumIters < 40)
786  for (ipk = 0; ipk < npeaks; ipk += 1)
787  wave val = result_waves[ipk]
788  wave sig = result_waves[ipk + npeaks]
789  val[pp] = max(w_coef[peak_coef[ipk]], 0)
790  sig[pp] = max(w_sigma[peak_coef[ipk]], 0)
791  endfor
792  endif
793  endfor
794 
795  // calculate integral
796  for (ipk = 0; ipk < npeaks; ipk += 1)
797  wave val = result_waves[ipk]
798  wave sig = result_waves[ipk + npeaks]
799  val *= w_coef[peak_coef[ipk] + 2] * sqrt(pi)
800  sig *= w_coef[peak_coef[ipk] + 2] * sqrt(pi)
801  endfor
802 
803  return result_waves
804 end
805 
806 
838 function /s find_gauss4_reduction_params(spectrum, peakpos)
839  wave spectrum
840  wave peakpos
841  string param = ""
842 
843  variable wmin = wavemin(spectrum)
844  variable wmax = wavemax(spectrum)
845 
846  // read parameters
847  variable rngl = dimoffset(spectrum, 0)
848  variable rngh = dimoffset(spectrum, 0) + dimdelta(spectrum, 0) * (dimsize(spectrum, 0) - 1)
849  make /n=4 /free positions, widths
850  variable npeaks = numpnts(peakpos)
851  variable ybox = 1
852  positions = 0
853  positions[0, npeaks-1] = peakpos[p]
854  widths = 0.2
855 
856  variable n_coef = npeaks * 3 + 2
857  make /free /d /n=(n_coef) w_coef
858  w_coef = 0
859  w_coef[0] = wmin
860  w_coef[1] = 0
861 
862  make /free /n=(2+npeaks, numpnts(w_coef)) cmat
863  make /free /n=(2+npeaks) cvec
864  cmat = 0
865  cmat[0][0] = -1
866  cmat[1][1] = 1
867  cvec = 0
868 
869  variable ip
870  for (ip=0; ip < npeaks; ip += 1)
871  cmat[2 + ip][2 + ip*3] = -1
872  w_coef[2 + ip*3] = wmax - wmin
873  w_coef[3 + ip*3] = peakpos[ip]
874  w_coef[4 + ip*3] = widths[ip]
875  endfor
876 
877  variable V_FitNumIters
878  FuncFit /Q /NTHR=1 /N MultiGaussLinBG w_coef spectrum /C={cmat, cvec}
879 
880  for (ip=0; ip < npeaks; ip += 1)
881  positions[ip] = w_coef[3 + ip * 3]
882  widths[ip ] = abs(w_coef[4 + ip * 3])
883  endfor
884  for (ip=npeaks; ip < 4; ip += 1)
885  positions[ip] = 0
886  widths[ip] = 0.2
887  endfor
888 
889  param = ReplaceNumberByKey("rngl", param, rngl, "=", ";")
890  param = ReplaceNumberByKey("rngh", param, rngh, "=", ";")
891  param = ReplaceNumberByKey("npeaks", param, npeaks, "=", ";")
892  param = ReplaceNumberByKey("ybox", param, ybox, "=", ";")
893  param = ReplaceNumberByKey("pos1", param, positions[0], "=", ";")
894  param = ReplaceNumberByKey("wid1", param, widths[0], "=", ";")
895  param = ReplaceNumberByKey("pos2", param, positions[1], "=", ";")
896  param = ReplaceNumberByKey("wid2", param, widths[1], "=", ";")
897  param = ReplaceNumberByKey("pos3", param, positions[2], "=", ";")
898  param = ReplaceNumberByKey("wid3", param, widths[2], "=", ";")
899  param = ReplaceNumberByKey("pos4", param, positions[3], "=", ";")
900  param = ReplaceNumberByKey("wid4", param, widths[3], "=", ";")
901 
902  return param
903 end
904 
912 function test_shockley_anglefit(image, branch)
913  wave image
914  variable branch
915 
916  string param = ""
917  param = ReplaceStringByKey("branch", param, num2str(branch), "=", ";")
918 
919  string s_branch
920  if (branch >= 0)
921  s_branch = "p"
922  else
923  s_branch = "n"
924  endif
925  string pkpos_name = "saf_pkpos_" + s_branch
926  string pkwid_name = "saf_pkwid_" + s_branch
927 
928  wave /wave results = shockley_anglefit(image, param)
929  duplicate results[0], $pkpos_name
930  duplicate results[1], $pkwid_name
931 end
932 
933 function prompt_Shockley_anglefit(param)
934  string &param
935 
936  variable branch = NumberByKey("branch", param, "=", ";")
937 
938  prompt branch, "Branch (-1 or +1)"
939 
940  doprompt "Shockley_anglefit_reduction Parameters", branch
941  if (v_flag == 0)
942  param = ReplaceNumberByKey("branch", param, branch, "=", ";")
943  endif
944 
945  return v_flag
946 end
947 
970 threadsafe function /wave Shockley_anglefit(source, param)
971  wave source
972  string &param
973 
974  variable nx = dimsize(source, 0)
975  variable ny = dimsize(source, 1)
976 
977  // read parameters
978  variable branch = NumberByKey("branch", param, "=", ";")
979 
980  // validate parameters
981  if (numtype(branch) != 0)
982  branch = +1
983  endif
984 
985  // prepare output
986  make /wave /free /n=2 result_waves
987  make /free /n=0 dest1, dest2
988  result_waves[0] = dest1
989  result_waves[1] = dest2
990  adh5_setup_profile(source, dest1, 0)
991  adh5_setup_profile(source, dest2, 0)
992  dest1 = nan
993  dest2 = nan
994 
995  // select angle range
996  // hard-coded for a particular measurement series
997  variable y0
998  variable y1
999  if (branch < 0)
1000  y0 = -5
1001  y1 = 0
1002  else
1003  y0 = 0
1004  y1 = 5
1005  endif
1006 
1007  // select energy range
1008  // start at the point of highest intensity and go up 0.45 eV
1009  variable p0
1010  variable p1
1011  variable q0
1012  variable q1
1013  duplicate /free dest1, center
1014  q0 = round((y0 - dimoffset(source, 1)) / dimdelta(source, 1))
1015  q1 = round((y1 - dimoffset(source, 1)) / dimdelta(source, 1))
1016  ad_profile_x_w(source, q0, q1, center)
1017  wavestats /q/m=1 center
1018  p0 = round((v_maxloc - dimoffset(source, 0)) / dimdelta(source, 0))
1019  p1 = round((v_maxloc + 0.4 - dimoffset(source, 0)) / dimdelta(source, 0))
1020 
1021  // prepare intermediate data buffer
1022  make /n=(ny)/d/free profile
1023  setscale /p x dimoffset(source,1), dimdelta(source,1), waveunits(source,1), profile
1024 
1025  variable pp
1026  for (pp = p0; pp <= p1; pp += 1)
1027  profile = source[pp][p]
1028  curvefit /Q /NTHR=1 /W=2 gauss profile(y0,y1)
1029  wave w_coef
1030  dest1[pp] = w_coef[2]
1031  dest2[pp] = w_coef[3]
1032  endfor
1033 
1034  return result_waves
1035 end
1036 
1037 function scienta_norm(w, x): fitfunc
1038  wave w
1039  variable x
1040 
1041  return w[0] * (x^2 - w[1]^2)
1042 end
1043 
1044 function /wave fit_scienta_ang_transm(data, params)
1045  wave data // measured angular distribution (1D)
1046  wave /z params
1047 
1048  if (!waveexists(params))
1049  make /n=12 /o params
1050  endif
1051  redimension /n=12/d params
1052 
1053  variable h = wavemax(data) - wavemin(data)
1054  params[0] = h / 2
1055  params[1] = 0
1056  params[2] = 7
1057  params[3] = h / 4
1058  params[4] = -23
1059  params[5] = 4
1060  params[6] = h / 4
1061  params[7] = +23
1062  params[8] = 4
1063  params[9] = h / 2
1064  params[10] = 0
1065  params[11] = -0.001
1066  FuncFit /NTHR=0 /q scienta_ang_transm params data
1067 
1068  return params
1069 end
1070 
1071 threadsafe function scienta_ang_transm(w, x): fitfunc
1072  // parameterized angular transmission function of the analyser
1073  wave w // coefficients
1074  // w[0] = amplitude gauss 1
1075  // w[1] = position gauss 1
1076  // w[2] = width gauss 1
1077  // w[3] = amplitude gauss 2
1078  // w[4] = position gauss 2
1079  // w[5] = width gauss 2
1080  // w[6] = amplitude gauss 3
1081  // w[7] = position gauss 3
1082  // w[8] = width gauss 3
1083  // w[9] = constant background
1084  // w[10] = linear background
1085  // w[11] = quadratic background
1086  variable x
1087 
1088  make /free /n=4 /d w_int
1089  w_int[0] = 0
1090  w_int[1,] = w[p - 1]
1091  variable pk1 = gauss1d(w_int, x)
1092  w_int[1,] = w[p + 2]
1093  variable pk2 = gauss1d(w_int, x)
1094  w_int[1,] = w[p + 5]
1095  variable pk3 = gauss1d(w_int, x)
1096  w_int[0,2] = w[9 + p]
1097  w_int[3] = 0
1098  variable bg = poly(w_int, x)
1099 
1100  return bg + pk1 + pk2 + pk3
1101 end
1102 
1103 function /wave fit_scienta_poly_bg(data, params, bgterms)
1104  wave data // measured distribution (2D)
1105  wave /z params // wave, will be redimensioned for the correct size
1106  variable bgterms // number of terms in the polynomial background: 2, 3, or 4
1107 
1108  if (!waveexists(params))
1109  make /n=15 /o params
1110  endif
1111  redimension /n=15 /d params
1112 
1113  variable wmax = wavemax(data)
1114  variable wmin = wavemin(data)
1115  params[0] = 0
1116  params[1] = 7
1117  params[2] = 1 / 2
1118  params[3] = -23
1119  params[4] = 4
1120  params[5] = 1 / 2
1121  params[6] = +23
1122  params[7] = 4
1123  params[8] = 1
1124  params[9] = 0
1125  params[10] = -0.001
1126  params[11] = wmin
1127  params[12] = (wmax - wmin) / dimdelta(data,1) / dimsize(data,1)
1128  params[13] = 0
1129  params[14] = 0
1130 
1131  string h = "0000000000000"
1132  if (bgterms < 3)
1133  h = h + "1"
1134  else
1135  h = h + "0"
1136  endif
1137  if (bgterms < 4)
1138  h = h + "1"
1139  else
1140  h = h + "0"
1141  endif
1142  FuncFitMD /NTHR=1 /q /h=h scienta_poly_bg params data
1143 
1144  return params
1145 end
1146 
1147 function scienta_poly_bg(w, e, a): fitfunc
1148  // polynomial background with
1149  // parameterized angular transmission function of the analyser
1150  wave w // coefficients
1151  // angular transmission, varies with a
1152  // amplitude of gauss 1 = 1 constant
1153  // other peak amplitudes and linear terms are relative to gauss 1
1154  // w[0] = position gauss 1
1155  // w[1] = width gauss 1
1156  // w[2] = amplitude gauss 2, relative to gauss 1
1157  // w[3] = position gauss 2
1158  // w[4] = width gauss 2
1159  // w[5] = amplitude gauss 3, relative to gauss 1
1160  // w[6] = position gauss 3
1161  // w[7] = width gauss 3
1162  // w[8] = constant term
1163  // w[9] = linear term
1164  // w[10] = quadratic term
1165  // spectral background, varies with e
1166  // w[11] = constant term
1167  // w[12] = linear term
1168  // w[13] = quadratic term
1169  // w[14] = cubic term
1170  variable a // detection angle
1171  variable e // electron energy
1172 
1173  make /free /n=4 /d w_int
1174  variable p0 = 0
1175 
1176  w_int[0] = 0
1177  w_int[1] = 1
1178  w_int[2,] = w[p0 + p - 2]
1179  variable pk1 = gauss1d(w_int, a)
1180  p0 += 2
1181 
1182  w_int[1,] = w[p0 + p - 1]
1183  variable pk2 = gauss1d(w_int, a)
1184  p0 += 3
1185 
1186  w_int[1,] = w[p0 + p - 1]
1187  variable pk3 = gauss1d(w_int, a)
1188  p0 += 3
1189 
1190  w_int[0,2] = w[p0 + p]
1191  w_int[3] = 0
1192  variable base = poly(w_int, a)
1193  p0 += 3
1194 
1195  w_int[0,3] = w[p0 + p]
1196  variable bg = poly(w_int, e)
1197 
1198  return bg * (base + pk1 + pk2 + pk3)
1199 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)
set reduction parameters from cursors in a graph.
string capture_int_linbg_cursors()
this function is for testing only, until we implement a proper interface