diff --git a/README.md b/README.md index ded38a5..690bbe0 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,10 @@ Copyright 2009-2016 by [Paul Scherrer Institut](http://www.psi.ch) Release Notes ============= +## rev-distro-2.0.0 + +- The interface of data reduction functions has changed to make data reduction more efficient in multi-peak fits. The supplied reduction functions and dialogs have been refactored. If you want to use your own reduction functions written for pre-2.0, you have to adapt them to the new interface. + ## rev-distro-1.1.1 - If you have upgraded PEARL Procedures from pre-1.1.1 and Igor breaks in pearl-elog.ipf while opening an experiment, please delete the ELOG preferences file `pearl-elog/preferences.pxp`. (Check the Igor Help to find the package preferences folder on your system.) diff --git a/doc/html/PageProjections.html b/doc/html/PageProjections.html index 6d103fe..d21ea6e 100644 --- a/doc/html/PageProjections.html +++ b/doc/html/PageProjections.html @@ -32,7 +32,7 @@
PEARL Procedures -  rev-distro-1.6.0-0-gcf1399e-dirty +  rev-distro-1.6.1-0-ge1f1aa9-dirty
Igor procedures for the analysis of PEARL data
@@ -126,7 +126,7 @@ $(document).ready(function(){initNavTree('PageProjections.html','');}); @@ -2515,7 +2611,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp -

Definition at line 1440 of file pearl-anglescan-process.ipf.

+

Definition at line 1523 of file pearl-anglescan-process.ipf.

@@ -2551,7 +2647,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp

save a hemispherical scan to an Igor text file

-

Definition at line 2607 of file pearl-anglescan-process.ipf.

+

Definition at line 2692 of file pearl-anglescan-process.ipf.

@@ -2605,7 +2701,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp -

Definition at line 2952 of file pearl-anglescan-process.ipf.

+

Definition at line 3037 of file pearl-anglescan-process.ipf.

@@ -2651,7 +2747,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 2218 of file pearl-anglescan-process.ipf.

+

Definition at line 2303 of file pearl-anglescan-process.ipf.

@@ -2747,7 +2843,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
Remarks
the function creates angle scan data under the nickname analyser.
-

Definition at line 765 of file pearl-anglescan-process.ipf.

+

Definition at line 848 of file pearl-anglescan-process.ipf.

@@ -2851,7 +2947,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp -

Definition at line 2738 of file pearl-anglescan-process.ipf.

+

Definition at line 2823 of file pearl-anglescan-process.ipf.

@@ -2887,7 +2983,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp -

Definition at line 2163 of file pearl-anglescan-process.ipf.

+

Definition at line 2248 of file pearl-anglescan-process.ipf.

@@ -2902,7 +2998,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 1995 of file pearl-anglescan-process.ipf.

+

Definition at line 2080 of file pearl-anglescan-process.ipf.

@@ -2916,7 +3012,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 1993 of file pearl-anglescan-process.ipf.

+

Definition at line 2078 of file pearl-anglescan-process.ipf.

@@ -2930,7 +3026,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 1996 of file pearl-anglescan-process.ipf.

+

Definition at line 2081 of file pearl-anglescan-process.ipf.

@@ -2944,7 +3040,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 1997 of file pearl-anglescan-process.ipf.

+

Definition at line 2082 of file pearl-anglescan-process.ipf.

@@ -2966,7 +3062,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 2001 of file pearl-anglescan-process.ipf.

+

Definition at line 2086 of file pearl-anglescan-process.ipf.

@@ -2988,7 +3084,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 1999 of file pearl-anglescan-process.ipf.

+

Definition at line 2084 of file pearl-anglescan-process.ipf.

@@ -3010,7 +3106,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 2003 of file pearl-anglescan-process.ipf.

+

Definition at line 2088 of file pearl-anglescan-process.ipf.

@@ -3032,7 +3128,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 2004 of file pearl-anglescan-process.ipf.

+

Definition at line 2089 of file pearl-anglescan-process.ipf.

@@ -3054,7 +3150,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 2000 of file pearl-anglescan-process.ipf.

+

Definition at line 2085 of file pearl-anglescan-process.ipf.

@@ -3068,7 +3164,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-

Definition at line 1994 of file pearl-anglescan-process.ipf.

+

Definition at line 2079 of file pearl-anglescan-process.ipf.

@@ -3078,7 +3174,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
-Go to the documentation of this file.
1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
2 #pragma version = 1.8
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlAnglescanProcess
5 #include "pearl-vector-operations"
6 #include "pearl-polar-coordinates"
7 #include <New Polar Graphs>
8 
9 // copyright (c) 2013-17 Paul Scherrer Institut
10 //
11 // Licensed under the Apache License, Version 2.0 (the "License");
12 // you may not use this file except in compliance with the License.
13 // You may obtain a copy of the License at
14 // http:///www.apache.org/licenses/LICENSE-2.0
15 //
16 // Please acknowledge the use of this code.
17 
76 
81 
82 
105 variable strip_delete_frames(wave strip, variable qlo, variable qhi, wave theta, wave tilt, wave phi){
106  wave strip// 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
107  variable qlo
108  variable qhi
109  wave theta
110  wave tilt
111  wave phi
112 
113  if (qlo > qhi)
114  return -1
115  endif
116 
117  // source indices
118  variable snx = dimsize(strip, 0)
119  variable sny = dimsize(strip, 1)
120  variable sq1lo = 0
121  variable sq1hi = max(qlo-1, 0)
122  variable sq2lo = min(qhi+1, sny - 1)
123  variable sq2hi = dimsize(strip, 1) - 1
124 
125  // dest indices
126  variable dnx = snx
127  variable dny = sny - (sq2lo - sq1hi + 1)
128  variable dq1lo = 0
129  variable dq1hi = sq1hi
130  variable dq2lo = dq1hi + 1
131  variable dq2hi = dny - 1
132  variable q1ofs = sq1lo - dq1lo
133  variable q2ofs = sq2lo - dq2lo
134 
135  duplicate /free strip, strip_copy
136  redimension /n=(dnx,dny) strip
137  strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs]
138  strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs]
139 
140  duplicate /free theta, theta_copy
141  redimension /n=(dny) theta
142  theta[dq1lo,dq1hi] = theta_copy[p + q1ofs]
143  theta[dq2lo,dq2hi] = theta_copy[p + q2ofs]
144 
145  duplicate /free tilt, tilt_copy
146  redimension /n=(dny) tilt
147  tilt[dq1lo,dq1hi] = tilt_copy[p + q1ofs]
148  tilt[dq2lo,dq2hi] = tilt_copy[p + q2ofs]
149 
150  duplicate /free phi, phi_copy
151  redimension /n=(dny) phi
152  phi[dq1lo,dq1hi] = phi_copy[p + q1ofs]
153  phi[dq2lo,dq2hi] = phi_copy[p + q2ofs]
154 
155  return 0
156 };
157 
185 variable normalize_strip_x(wave strip, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
186  wave strip
187  variable smooth_method
188  variable smooth_factor
189  variable check
190 
191  if (ParamIsDefault(smooth_method))
192  smooth_method = 1
193  endif
194  if (ParamIsDefault(smooth_factor))
195  switch(smooth_method)
196  case 4:
197  smooth_factor = 0.5
198  break
199  default:
200  smooth_factor = 2
201  endswitch
202  endif
203  if (ParamIsDefault(check))
204  check = 0
205  endif
206 
207  // average over all scan positions
208  wave dist = ad_profile_x(strip, -inf, inf, "")
209  variable div = mean(dist)
210  dist /= div
211 
212  if (check)
213  duplicate /o dist, check_dist
214  endif
215 
216  // smooth distribution function
217  switch(smooth_method)
218  case 1:
219  Smooth /B /E=3 smooth_factor, dist
220  break
221  case 2:
222  Smooth /E=3 smooth_factor, dist
223  break
224  case 3:
225  make /n=1 /d /free fit_params
226  fit_scienta_ang_transm(dist, fit_params)
227  dist = scienta_ang_transm(fit_params, x)
228  break
229  case 4:
230  loess /smth=(smooth_factor) srcWave=dist
231  break
232  endswitch
233 
234  if (check)
235  duplicate /o dist, check_smoo
236  endif
237 
238  // divide
239  if (check != 2)
240  strip /= dist[p]
241  endif
242 };
243 
270 variable normalize_strip_phi(wave strip, wave theta, wave phi, variable theta_offset = defaultValue, variable theta_range = defaultValue, variable check = defaultValue){
271  wave strip
272  wave theta
273  wave phi
274  variable theta_offset
275  variable theta_range
276  variable check
277 
278  if (ParamIsDefault(check))
279  check = 0
280  endif
281  if (ParamIsDefault(theta_offset))
282  theta_offset = 0
283  endif
284  if (ParamIsDefault(theta_range))
285  theta_offset = 10
286  endif
287 
288  // average over analyser angles
289  wave dist = ad_profile_y(strip, -inf, inf, "")
290 
291  // smooth distribution function
292  duplicate /free dist, dist_smoo
293  duplicate /free theta, theta_int
294  theta_int = theta - theta_offset
295  duplicate /free phi, phi_int
296  setscale /p x phi_int[0], phi_int[1] - phi_int[0], waveunits(phi, -1), dist, dist_smoo
297 
298  extract /free /indx dist, red_idx, theta_int < theta_range
299  duplicate /free red_idx, red_dist, red_phi
300  red_dist = dist[red_idx]
301  red_phi = phi_int[red_idx]
302 
303  variable wavg = mean(red_dist)
304  make /n=4 /d /free coef
305  coef[0] = {wavg, wavg/100, pi/180, 0}
306  CurveFit /q /h="0010" /g /w=2 sin, kwcWave=coef, red_dist /x=red_phi
307  dist_smoo = coef[0] + coef[1] * sin(coef[2] * phi_int[p] + coef[3])
308 
309  // divide
310  if (check != 2)
311  strip = strip / dist_smoo[q] * coef[0]
312  endif
313 
314  // check
315  if (check)
316  duplicate /o dist, check_dist
317  duplicate /o dist_smoo, check_smoo
318  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
319  endif
320 };
321 
353 variable normalize_strip_theta(wave strip, wave theta, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
354  wave strip
355  wave theta
356  variable theta_offset
357  variable smooth_method
358  variable smooth_factor
359  variable check
360 
361  if (ParamIsDefault(check))
362  check = 0
363  endif
364  if (ParamIsDefault(theta_offset))
365  theta_offset = 0
366  endif
367  if (ParamIsDefault(smooth_method))
368  smooth_method = 4
369  endif
370  if (ParamIsDefault(smooth_factor))
371  smooth_factor = 0.5
372  endif
373 
374  // average over analyser angles
375  wave dist = ad_profile_y(strip, -inf, inf, "")
376 
377  // smooth distribution function
378  duplicate /free dist, dist_smoo
379  duplicate /free theta, theta_int
380  theta_int = theta - theta_offset
381  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
382  variable nx = dimsize(strip, 0)
383  variable ix
384 
385  switch(smooth_method)
386  case 1:
387  Smooth /B /E=3 smooth_factor, dist_smoo
388  break
389  case 2:
390  Smooth /E=3 smooth_factor, dist_smoo
391  break
392  case 4:
393  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={theta_int}
394  break
395  case 3:
396  for (ix = 0; ix < nx; ix += 1)
397  dist = strip[ix][p]
398  if (smooth_factor > 1)
399  CurveFit /nthr=0 /q /w=2 poly smooth_factor+1, dist /x=theta_int /d=dist_smoo
400  else
401  CurveFit /nthr=0 /q /w=2 line, dist /x=theta_int /d=dist_smoo
402  endif
403  strip[ix,ix][] /= dist_smoo[q]
404  endfor
405  dist_smoo = 1
406  break
407  endswitch
408 
409  // divide
410  if (check != 2)
411  strip /= dist_smoo[q]
412  endif
413 
414  // check
415  if (check)
416  duplicate /o dist, check_dist
417  duplicate /o dist_smoo, check_smoo
418  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
419  endif
420 };
421 
435 variable normalize_strip_2d(wave strip, wave theta, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
436  wave strip
437  wave theta
438  variable theta_offset
439  variable smooth_method
440  variable smooth_factor
441  variable check
442 
443  if (ParamIsDefault(check))
444  check = 0
445  endif
446  if (ParamIsDefault(theta_offset))
447  theta_offset = 0
448  endif
449  if (ParamIsDefault(smooth_method))
450  smooth_method = 4
451  endif
452  if (ParamIsDefault(smooth_factor))
453  smooth_factor = 0.5
454  endif
455 
456  variable nx = dimsize(strip, 0)
457  variable ny = dimsize(strip, 1)
458 
459  duplicate /free strip, dist, alpha_int, theta_int
460  theta_int = theta[q] - theta_offset
461  alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
462  redimension /n=(nx * ny) dist, alpha_int, theta_int
463 
464  switch(smooth_method)
465  case 4:
466  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int}
467  redimension /n=(nx, ny) dist_smoo
468  break
469  default:
470  Abort "undefined smooth method"
471  break
472  endswitch
473 
474  // divide
475  if (check != 2)
476  strip /= dist_smoo
477  endif
478 
479  // check
480  if (check)
481  //duplicate /o dist, check_dist
482  duplicate /o dist_smoo, check_smoo
483  endif
484 };
485 
495 variable crop_strip(wave strip, variable xlo, variable xhi){
496  wave strip
497  variable xlo
498  variable xhi
499 
500  variable plo = round((xlo - dimoffset(strip, 0)) / dimdelta(strip, 0))
501  variable phi = round((xhi - dimoffset(strip, 0)) / dimdelta(strip, 0))
502  xlo = plo * dimdelta(strip, 0) + dimoffset(strip, 0)
503  xhi = phi * dimdelta(strip, 0) + dimoffset(strip, 0)
504  variable nx = phi - plo + 1
505  variable ny = dimsize(strip, 1)
506 
507  duplicate /free strip, strip_copy
508  redimension /n=(nx,ny) strip
509  strip = strip_copy[p + plo][q]
510  setscale /i x xlo, xhi, waveunits(strip, 0), strip
511 };
512 
555 variable pizza_service(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar = defaultValue, variable nograph = defaultValue, variable folding = defaultValue, variable xpdplot = defaultValue){
556  wave data
557  string nickname
558  variable theta_offset
559  variable tilt_offset
560  variable phi_offset
561  variable npolar
562  variable nograph
563  variable folding
564  variable xpdplot
565 
566  if (ParamIsDefault(npolar))
567  npolar = 91
568  endif
569  if (ParamIsDefault(nograph))
570  nograph = 0
571  endif
572  if (ParamIsDefault(folding))
573  folding = 1
574  endif
575  if (ParamIsDefault(xpdplot))
576  xpdplot = 0
577  endif
578 
579  // sort out data folder structure
580  dfref saveDF = GetDataFolderDFR()
581  dfref dataDF = GetWavesDataFolderDFR(data)
582  setdatafolder dataDF
583  if (DataFolderExists(":attr"))
584  setdatafolder :attr
585  endif
586  dfref attrDF = GetDataFolderDFR()
587 
588  wave /sdfr=attrDF ManipulatorTheta
589  wave /sdfr=attrDF ManipulatorTilt
590  wave /sdfr=attrDF ManipulatorPhi
591 
592  if ((dimsize(ManipulatorTheta, 0) != dimsize(data, 1)) || (dimsize(ManipulatorTilt, 0) != dimsize(data, 1)) || (dimsize(ManipulatorPhi, 0) != dimsize(data, 1)))
593  Abort "Warning: The dimension size of the manipulator waves does not match the Y dimension of the data wave!\rIf you restructured the data wave, please use pizza_service_2 with properly scaled manipulator waves."
594  endif
595 
596  duplicate /free ManipulatorTheta, m_theta
597  duplicate /free ManipulatorTilt, m_tilt
598  duplicate /free ManipulatorPhi, m_phi
599 
600  m_theta -= theta_offset
601  m_tilt -= tilt_offset
602  m_phi -= phi_offset
603 
604  pizza_service_2(data, nickname, m_theta, m_tilt, m_phi, npolar=npolar, nograph=nograph, folding=folding, xpdplot=xpdplot)
605 
606  setdatafolder saveDF
607 };
608 
648 variable pizza_service_2(wave data, string nickname, wave m_theta, wave m_tilt, wave m_phi, variable npolar = defaultValue, variable nograph = defaultValue, variable folding = defaultValue, variable xpdplot = defaultValue){
649  wave data
650  string nickname
651  wave m_theta
652  wave m_tilt
653  wave m_phi
654  variable npolar
655  variable nograph
656  variable folding
657  variable xpdplot
658 
659  if (ParamIsDefault(npolar))
660  npolar = 91
661  endif
662  if (ParamIsDefault(nograph))
663  nograph = 0
664  endif
665  if (ParamIsDefault(folding))
666  folding = 1
667  endif
668  if (ParamIsDefault(xpdplot))
669  xpdplot = 0
670  endif
671 
672  if ((dimsize(m_theta, 0) != dimsize(data, 1)) || (dimsize(m_tilt, 0) != dimsize(data, 1)) || (dimsize(m_phi, 0) != dimsize(data, 1)))
673  Abort "Warning: The dimension size of the manipulator waves does not match the Y dimension of the data wave!"
674  endif
675 
676  string graphname = "graph_" + nickname
677  string outprefix = nickname
678 
679  // sort out data folder structure
680  dfref saveDF = GetDataFolderDFR()
681  dfref dataDF = GetWavesDataFolderDFR(data)
682  setdatafolder dataDF
683 
684  if (xpdplot)
685  setdatafolder root:
686  outprefix = nickname
687  else
688  setdatafolder dataDF
689  newdatafolder /s/o $nickname
690  outprefix = ""
691  endif
692  dfref destDF = GetDataFolderDFR()
693 
694  // performance monitoring
695  variable timerRefNum
696  variable /g pol_perf_secs
697  timerRefNum = startMSTimer
698 
699  duplicate /free m_tilt, corr_tilt
700  duplicate /free m_phi, corr_phi
701  corr_tilt = -m_tilt// checked 140702
702  corr_phi = m_phi// checked 140702
703 
704  make /n=1/d/free d_polar, d_azi
705 
706  convert_angles_ttpd2polar(m_theta, corr_tilt, corr_phi, data, d_polar, d_azi)
707  d_azi += 180// changed 151030 (v1.6)
708  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
709  variable ifold
710  for (ifold = 0; ifold < folding; ifold += 1)
711  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
712  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
713  d_azi += 360 / folding
714  endfor
715 
716  // normalize folding
717  if (strlen(outprefix))
718  string s_prefix = outprefix + "_"
719  string s_int = s_prefix + "i"
720  else
721  s_prefix = ""
722  s_int = "values"
723  endif
724  if (folding > 1)
725  wave values = $s_int
726  values /= folding
727  endif
728 
729  if (!nograph)
730  display_hemi_scan(outprefix, graphname = graphname)
731  endif
732 
733  if (timerRefNum >= 0)
734  pol_perf_secs = stopMSTimer(timerRefNum) / 1e6
735  endif
736 
737  setdatafolder saveDF
738 };
739 
765 variable show_analyser_line(variable theta, variable tilt, variable phi, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar = defaultValue, variable nograph = defaultValue, variable xpdplot = defaultValue){
766  variable theta
767  variable tilt
768  variable phi
769  variable theta_offset
770  variable tilt_offset
771  variable phi_offset
772  variable npolar
773  variable nograph
774  variable xpdplot
775 
776  string nickname = "analyser"
777 
778  if (ParamIsDefault(npolar))
779  npolar = 91
780  endif
781  if (ParamIsDefault(nograph))
782  nograph = 0
783  endif
784  if (ParamIsDefault(xpdplot))
785  xpdplot = 0
786  endif
787  string graphname = "graph_" + nickname
788  string outprefix = nickname
789 
790  // sort out data folder structure
791  dfref saveDF = GetDataFolderDFR()
792  dfref dataDF = saveDF
793  if (xpdplot)
794  setdatafolder root:
795  outprefix = nickname
796  else
797  setdatafolder dataDF
798  newdatafolder /s/o $nickname
799  outprefix = ""
800  endif
801  dfref destDF = GetDataFolderDFR()
802 
803  make /n=1 /free m_theta
804  make /n=1 /free m_tilt
805  make /n=1 /free m_phi
806  m_theta = theta - theta_offset
807  m_tilt = tilt - tilt_offset
808  m_tilt *= -1// checked 140702
809  m_phi = phi - phi_offset
810  //m_phi *= -1 // checked 140702
811 
812  make /n=60 /free data
813  setscale /i x -30, 30, data
814  data = x
815  make /n=1/d/free d_polar, d_azi
816 
817  convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
818  d_azi += 180// changed 151030 (v1.6)
819  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
820  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
821  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
822 
823  if (!nograph)
824  display_hemi_scan(outprefix, graphname = graphname)
825  endif
826 
827  setdatafolder saveDF
828 };
829 
834 
835 variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi){
836  wave theta, tilt, phi// see convert_angles_ttpa2polar
837  wave data// in, 1D or 2D
838  // X-scale must be set to analyser angle scale
839  wave polar, azi// see convert_angles_ttpa2polar
840 
841  make /n=(dimsize(data, 0)) /d /free ana
842  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), ana
843  ana = x
844  convert_angles_ttpa2polar(theta, tilt, phi, ana, polar, azi)
845 };
846 
874 variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi){
875  wave theta
876  wave tilt
877  wave phi
878  wave analyser
879  wave polar, azi
880 
881  variable nn = numpnts(theta)
882  variable na = numpnts(analyser)
883  redimension /n=(na, nn) polar, azi
884 
885  variable radius = 1// don't need to specify - everything is scalable
886 
887  // step 1: calculate cartesian detection vectors at normal emission
888  // this is simply a polar-cartesian mapping, independent of the manipulator
889  // phi=0 is in the polar rotation plane
890  make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar
891  w_orig_polar[0][] = radius
892  w_orig_polar[1][] = analyser[q]
893  w_orig_polar[2][] = 0
894  polar2cart_wave(w_orig_polar, w_orig_cart)
895  // if the angle-dispersive axis was horizontal, we'd need to rotate the detector
896  //rotate_z_wave(w_orig_cart, 90)
897 
898  variable ii
899  for (ii = 0; ii < nn; ii += 1)
900  // step 2: rotate the detection vectors according to the manipulator angles
901  // the order of rotations is important because we rotate about fixed axes
902  // y-axis = tilt rotation axis
903  // x-axis = polar rotation axis
904  // z-axis = normal emission = azimuthal rotation axis
905  w_rot_cart = w_orig_cart
906  rotate_y_wave(w_rot_cart, -tilt[ii])
907  rotate_x_wave(w_rot_cart, -theta[ii])
908  rotate_z_wave(w_rot_cart, -phi[ii] - 90)
909  // map the vectors back to the sample coordinate system
910  cart2polar_wave(w_rot_cart, w_rot_polar)
911  // copy to output
912  polar[][ii] = w_rot_polar[1][p]
913  azi[][ii] = w_rot_polar[2][p]
914  endfor
915 };
916 
917 static variable line_average(wave source, wave dest){
918  // is this function used?
919  wave source
920  wave dest
921 
922  variable ii
923  variable nn = dimsize(source, 1)
924  make /n=(dimsize(source, 0))/d/free line
925  for (ii = 0; ii < nn; ii += 1)
926  line = source[p][ii]
927  wavestats /q line
928  dest[][ii] = line[p] / v_max
929  endfor
930 };
931 
935 static variable calc_nth(variable Theta_st, variable Theta_in, variable th, variable Phi_ran, variable Phi_ref, string Holomode){
936  Variable Theta_st, Theta_in, th, Phi_ran, Phi_ref
937  String Holomode
938  Variable The_step
939  Variable deg2rad=0.01745329
940 
941  if ( cmpstr(Holomode, "Stereographic") == 0)
942  The_step =trunc( Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st )
943  if(th==90)
944  The_step =trunc( Phi_ran*sin(th*pi/180)*Phi_ref/Theta_st )
945  endif
946  else
947  if (cmpstr(Holomode, "Parallel") == 0)
948  The_step=trunc( Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st )
949  else
950  if ( cmpstr(Holomode, "h") == 0)
951  The_step=trunc( th/Theta_in*Phi_ran/Theta_st )
952  else
953  //altro
954  endif
955  endif
956  endif
957 
958  return(The_step)
959 };
960 
964 static variable calc_phi_step(variable Theta_in, variable th, variable Theta_st, variable Phi_ran, variable Phi_ref, string Holomode){
965  Variable Theta_in, th, Theta_st, Phi_ran, Phi_ref
966  String Holomode
967 
968  Variable Phi_st
969  Variable deg2rad=0.01745329
970 
971  if ( cmpstr(Holomode, "Stereographic") == 0 )
972  if ((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
973  Phi_st=0.0
974  else
975  Phi_st=Phi_ran/(trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st))
976  endif
977  if(th==90)
978  Phi_st=2.0
979  endif
980  endif
981 
982  if ( cmpstr(Holomode, "Parallel") == 0 )
983  if((th < 0.5) || (trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st) == 0))
984  Phi_st=0.0
985  else
986  Phi_st=Phi_ran/(trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st))
987  endif
988  endif
989 
990  if ( cmpstr(Holomode, "h") == 0 )
991  if((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
992  Phi_st=0.0
993  else
994  Phi_st=Phi_ran/trunc(th/Theta_in*Phi_ran/Theta_st)
995  endif
996  endif
997 
998  if (Phi_st==0)
999  Phi_st=360
1000  endif
1001 
1002  return(Phi_st)
1003 };
1004 
1008 static variable Calc_The_step(variable th, variable Theta_st, string Holomode){
1009  String Holomode
1010  Variable th, Theta_st
1011 
1012  Variable deg2rad=0.01745329, dt_loc,The_step
1013 
1014  if ( (cmpstr(Holomode, "Stereographic")) ==0 )
1015  The_step=Theta_st
1016  endif
1017 
1018  if ( (cmpstr(Holomode, "h")) ==0 )
1019  The_step=Theta_st
1020  endif
1021 
1022  if ( cmpstr(Holomode, "Parallel") == 0 )
1023  if(th < 89.5)
1024  dt_loc = Theta_st/cos(th*deg2rad)
1025  if(dt_loc > 10)
1026  dt_loc=10
1027  endif
1028  The_step=dt_loc
1029  else
1030  The_step=10
1031  endif
1032  endif
1033  return(The_step)
1034 };
1035 
1039 static variable CalcN_Theta(string HoloMode, variable Theta_in, variable Theta_ran, variable Theta_st){
1040  String HoloMode
1041  Variable Theta_in,Theta_ran,Theta_st
1042  Variable n_theta, aux, aux1,ii
1043 
1044  aux = Theta_in
1045  aux1= Theta_in - Theta_ran
1046  ii = 0
1047  do
1048  aux = aux - Calc_The_step(aux, Theta_st, HoloMode)
1049  if(aux<=Theta_in-Theta_ran)
1050  aux=Theta_in-Theta_ran
1051  endif
1052  ii = ii+1
1053  while((aux>aux1)%&(Theta_in-aux<=Theta_ran))//
1054  n_theta=ii+1
1055  Return(n_theta)
1056 };
1057 
1077 variable make_hemi_grid(variable npol, string nickname, variable xpdplot = defaultValue){
1078  variable npol
1079  string nickname
1080  variable xpdplot
1081 
1082  if (ParamIsDefault(xpdplot))
1083  xpdplot = 0
1084  endif
1085 
1086  string HoloMode = "h"
1087  variable Theta_in = 90
1088  variable Theta_ran = 90
1089  variable Theta_st = 90 / (npol - 1)
1090  variable Phi_ran = 360
1091  variable Phi_ref = 1
1092  variable Phi_in = 0
1093 
1094  variable n_theta = CalcN_Theta(HoloMode, Theta_in, Theta_ran, Theta_st)
1095 
1096  // wave names
1097  if (strlen(nickname))
1098  string s_prefix = nickname + "_"
1099  string s_int = s_prefix + "i"// Intensity wave (counts/sec)
1100  else
1101  s_prefix = ""
1102  s_int = "values"// "i" is not a valid wave name
1103  endif
1104  string s_polar = s_prefix + "pol"// thetas for each int-point of the holo
1105  string s_azim = s_prefix + "az"// phis for each int-point of the holo
1106 
1107  string s_index = s_prefix + "index"// starting index for each theta
1108  string s_theta = s_prefix + "th"// theta values
1109  string s_dphi = s_prefix + "dphi"// delta phis at each theta
1110  string s_nphis = s_prefix + "nphis"// number of phis at each theta
1111 
1112  string s_HoloData = s_prefix + "data"// All holo exp.- parameter information
1113  string s_HoloInfo = s_prefix + "info"
1114 
1115  // the following two waves are used by the pearl-anglescan procedures but not by XPDplot
1116  string s_tot = s_prefix + "tot"// accumulated counts at each point
1117  string s_weight = s_prefix + "wt"// total accumulation time at each point (arb. units)
1118 
1119  make /O/D/n=(n_theta) $s_index /wave=index
1120  make /O/D/n=(n_theta) $s_theta /wave=theta
1121  make /O/D/n=(n_theta) $s_dphi /wave=dphi
1122  make /O/D/n=(n_theta) $s_nphis /wave=nphis
1123 
1124  //---------- calculate phi-step-size for this theta:
1125  variable aux = Calc_The_step(Theta_in, Theta_st, HoloMode)
1126  dphi[0] = calc_phi_step(Theta_in, Theta_in, aux, Phi_ran, Phi_ref, HoloMode)
1127  Theta[0] = Theta_in
1128  nphis[0] = calc_nth(aux, Theta_in, Theta_in, Phi_ran, Phi_ref, HoloMode)
1129  Index[0] = nphis[0]
1130 
1131  //---------- calculate number of phis, phi-step, and starting-index for each theta:
1132  variable ii = 1
1133  do
1134  Theta[ii] = Theta[ii-1] - aux
1135  if(Theta[ii] <= Theta_in-Theta_ran)
1136  Theta[ii] = Theta_in-Theta_ran
1137  endif
1138  aux = Calc_The_step(Theta[ii], Theta_st, HoloMode)
1139  dphi[ii] = calc_phi_step(Theta_in, Theta[ii], aux, Phi_ran, Phi_ref, HoloMode)
1140  nphis[ii] = calc_nth(aux, Theta_in, Theta[ii], Phi_ran, Phi_ref, HoloMode)
1141  Index[ii] = Index[ii-1] + nphis[ii]
1142  ii=ii+1
1143  while(ii < n_theta)
1144 
1145  if (Index[n_theta-1]==Index[n_theta-2])
1146  Index[n_theta-1]=Index[n_theta-2]+1
1147  nphis[n_theta-1]=1
1148  endif
1149 
1150  variable NumPoints = sum(nphis, 0, numpnts(nphis))
1151 
1152  //---------- calculate theta and phi for each data point:
1153  make /O/D/N=(NumPoints) $s_polar /wave=polar, $s_azim /wave=azim
1154  note azim, "version=1.6"
1155 
1156  ii = 0
1157  variable StartIndex = 0
1158  variable EndIndex
1159  do
1160  EndIndex=Index[ii]
1161  Polar[StartIndex, EndIndex-1]=Theta[ii]
1162  Azim[StartIndex, EndIndex-1]= mod(Phi_ran+(x-StartIndex)*dphi[ii]+Phi_in,Phi_ran)
1163  ii = ii + 1
1164  StartIndex = EndIndex
1165  while(ii < n_theta)
1166 
1167  duplicate /o azim, $s_int /wave=values
1168  duplicate /o azim, $s_tot /wave=totals
1169  duplicate /o azim, $s_weight /wave=weights
1170  values = nan
1171  totals = 0
1172  weights = 0
1173 
1174  // XPDplot metadata
1175  if (xpdplot)
1176  string s_FileName = ""
1177  string s_Comment = "created by pearl-anglescan-process.ipf"
1178  string s_HoloMode = "Stereographic"
1179  variable /g gb_SpectraFile = 0
1180 
1181  Make/O/D/n=22 $s_HoloData /wave=HoloData
1182  HoloData[0] = NaN// v_StartKE
1183  HoloData[1] = NaN// v_StoppKE
1184  HoloData[6] = NumPoints
1185  HoloData[7] = Theta_in
1186  HoloData[8] = Theta_ran
1187  HoloData[9] = Theta_st
1188  HoloData[11] = Phi_in
1189  HoloData[12] = Phi_ran
1190  HoloData[13] = Theta_st
1191  HoloData[15] = Phi_ref
1192  HoloData[16] = Phi_ran
1193  HoloData[17] = 0// v_HoloBit (stereographic)
1194 
1195  Make/O/T/n=22 $s_HoloInfo /wave=HoloInfo
1196  HoloInfo[0] = s_FileName
1197  HoloInfo[1] = s_Comment
1198  HoloInfo[10] = s_HoloMode
1199  HoloInfo[11] = ""// s_MeasuringMode
1200 
1201  // notebook for XPDplot
1202  if (WinType(NickName) == 5)
1203  Notebook $NickName selection={startOfFile, endOfFile}
1204  Notebook $NickName text=""
1205  else
1206  NewNotebook /F=0 /K=1 /N=$NickName /W=(5,40,341,260)
1207  Notebook $NickName defaultTab=140
1208  Notebook $NickName statusWidth=300
1209  Notebook $NickName backRGB=(56797,56797,56797)
1210  Notebook $NickName pageMargins={80,80,80,80}
1211  Notebook $NickName fSize=10
1212  Notebook $NickName fStyle=0,textRGB=(65535,0,26214)
1213  Notebook $NickName textRGB=(65535,0,26214)
1214  endif
1215  Notebook $NickName text = "File:\t" + s_FileName + "\r"
1216  Notebook $NickName text = "*** " + s_Comment + " ***\r\r"
1217  Notebook $NickName text = "Angle-Mode:\t" + s_HoloMode + "\r"
1218  Notebook $NickName text = "XPDplot Nickname:\t" + NickName + "\r"
1219  endif
1220 };
1221 
1228 string get_hemi_nickname(wave w){
1229  wave w
1230 
1231  string prefix = get_hemi_prefix(w)
1232  string wname = nameofwave(w)
1233  string nickname
1234 
1235  if (strlen(prefix))
1236  nickname = prefix
1237  else
1238  string s_wave_df = GetWavesDataFolder(w, 1)
1239  dfref parent_df = $(s_wave_df + "::")
1240  nickname = GetDataFolder(0, parent_df)
1241  endif
1242 
1243  return nickname
1244 };
1245 
1253 string get_hemi_prefix(wave w){
1254  wave w
1255 
1256  string wname = nameofwave(w)
1257  string prefix
1258  if (ItemsInList(wname, "_") >= 2)
1259  prefix = StringFromList(0, wname, "_")
1260  else
1261  prefix = ""
1262  endif
1263 
1264  return prefix
1265 };
1266 
1284 dfr find_hemi_data(string nickname, string* prefix, string* intwave){
1285  string nickname
1286  string &prefix
1287  string &intwave
1288 
1289  dfref datadf
1290  prefix = ""
1291  intwave = "values"
1292  if (strlen(nickname))
1293  if (DataFolderExists(nickname))
1294  datadf = $nickname
1295  else
1296  datadf = getdatafolderdfr()
1297  prefix = nickname + "_"
1298  intwave = prefix + "i"
1299  if (exists(intwave) != 1)
1300  datadf = root:
1301  endif
1302  endif
1303  else
1304  datadf = getdatafolderdfr()
1305  prefix = ""
1306  intwave = "values"
1307  endif
1308  return datadf
1309 };
1310 
1318 variable clear_hemi_grid(string nickname){
1319  string nickname
1320 
1321  dfref datadf
1322  string s_prefix
1323  string s_int
1324  datadf = find_hemi_data(nickname, s_prefix, s_int)
1325 
1326  string s_totals = s_prefix + "tot"
1327  string s_weights = s_prefix + "wt"
1328 
1329  wave /sdfr=datadf /z w_values = $s_int
1330  wave /sdfr=datadf /z w_totals = $s_totals
1331  wave /sdfr=datadf /z w_weights = $s_weights
1332 
1333  if (waveexists(w_totals))
1334  w_totals = 0
1335  endif
1336  if (waveexists(w_weights))
1337  w_weights = 0
1338  endif
1339  if (waveexists(w_values))
1340  w_values = nan
1341  endif
1342 };
1343 
1365 variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot = defaultValue){
1366  string source_nickname
1367  dfref dest_folder
1368  string dest_nickname
1369  variable xpdplot
1370 
1371  if (ParamIsDefault(xpdplot))
1372  xpdplot = 0
1373  endif
1374 
1375  dfref savedf = getdatafolderdfr()
1376 
1377  // source data
1378  string s_prefix = ""
1379  string s_int = "values"
1380  dfref source_df = find_hemi_data(source_nickname, s_prefix, s_int)
1381  string s_polar = s_prefix + "pol"
1382  string s_azim = s_prefix + "az"
1383  string s_theta = s_prefix + "th"
1384  string s_tot = s_prefix + "tot"
1385  string s_weight = s_prefix + "wt"
1386  string s_matrix = s_prefix + "matrix"
1387 
1388  wave /sdfr=source_df theta1 = $s_theta
1389  wave /sdfr=source_df polar1 = $s_polar
1390  wave /sdfr=source_df azim1 = $s_azim
1391  wave /sdfr=source_df tot1 = $s_tot
1392  wave /sdfr=source_df weight1 = $s_weight
1393  wave /sdfr=source_df values1 = $s_int
1394  wave /sdfr=source_df /z matrix1 = $s_matrix
1395 
1396  variable npol = numpnts(theta1)
1397 
1398  setdatafolder dest_folder
1399  make_hemi_grid(npol, dest_nickname, xpdplot=xpdplot)
1400 
1401  // dest data
1402  dfref dest_df = find_hemi_data(dest_nickname, s_prefix, s_int)
1403  s_polar = s_prefix + "pol"
1404  s_azim = s_prefix + "az"
1405  s_theta = s_prefix + "th"
1406  s_tot = s_prefix + "tot"
1407  s_weight = s_prefix + "wt"
1408  s_matrix = s_prefix + "matrix"
1409 
1410  wave /sdfr=dest_df theta2 = $s_theta
1411  wave /sdfr=dest_df polar2 = $s_polar
1412  wave /sdfr=dest_df azim2 = $s_azim
1413  wave /sdfr=dest_df tot2 = $s_tot
1414  wave /sdfr=dest_df weight2 = $s_weight
1415  wave /sdfr=dest_df values2 = $s_int
1416 
1417  tot2 = tot1
1418  weight2 = weight1
1419  values2 = values1
1420  if (waveexists(matrix1))
1421  setdatafolder dest_df
1422  duplicate /o matrix1, $s_matrix
1423  endif
1424 
1425  if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6))
1426  azim2 += 180// changed 151030 (v1.6)
1427  azim2 = azim2 >= 360 ? azim2 - 360 : azim2
1428  endif
1429 
1430  setdatafolder saveDF
1431 };
1432 
1440 variable rotate_hemi_scan(string nickname, variable angle){
1441  string nickname
1442  variable angle
1443 
1444  dfref savedf = getdatafolderdfr()
1445 
1446  string s_prefix = ""
1447  string s_int = "values"
1448  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1449 
1450  string s_polar = s_prefix + "pol"
1451  string s_azim = s_prefix + "az"
1452  string s_tot = s_prefix + "tot"
1453  string s_weight = s_prefix + "wt"
1454 
1455  wave /sdfr=df polar = $s_polar
1456  wave /sdfr=df azim = $s_azim
1457  wave /sdfr=df tot = $s_tot
1458  wave /sdfr=df weight = $s_weight
1459  wave /sdfr=df values = $s_int
1460 
1461  azim += angle
1462  azim = azim < 0 ? azim + 360 : azim
1463  azim = azim >= 360 ? azim - 360 : azim
1464 
1465  duplicate /free polar, neg_polar
1466  neg_polar = -polar
1467  sort {neg_polar, azim}, polar, azim, tot, weight, values
1468 
1469  setdatafolder saveDF
1470 };
1471 
1516 string display_hemi_scan(string nickname, variable projection = defaultValue, variable graphtype = defaultValue, variable do_ticks = defaultValue, variable do_grids = defaultValue, string graphname = defaultValue){
1517  string nickname
1518  variable projection
1519  variable graphtype
1520  variable do_ticks
1521  variable do_grids
1522  string graphname
1523 
1524  dfref savedf = getdatafolderdfr()
1525 
1526  if (ParamIsDefault(projection))
1527  projection = 1
1528  endif
1529  if (ParamIsDefault(graphtype))
1530  graphtype = 1
1531  endif
1532  if (ParamIsDefault(do_ticks))
1533  do_ticks = 3
1534  endif
1535  if (ParamIsDefault(do_grids))
1536  do_grids = 3
1537  endif
1538  if (ParamIsDefault(graphname))
1539  if (strlen(nickname) > 0)
1540  graphname = nickname
1541  else
1542  graphname = GetDataFolder(0)
1543  endif
1544  endif
1545 
1546  // hemi grid waves
1547  string s_prefix = ""
1548  string s_int = "values"
1549  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1550 
1551  string s_polar = s_prefix + "pol"
1552  string s_azim = s_prefix + "az"
1553  string s_matrix = s_prefix + "matrix"
1554 
1555  wave /sdfr=df /z values = $s_int
1556  wave /sdfr=df /z azim = $s_azim
1557  wave /sdfr=df /z polar = $s_polar
1558  wave /sdfr=df /z matrix = $s_matrix
1559 
1560  setdatafolder df
1561  string s_ster_rad = s_prefix + "ster_rad"
1562  duplicate /o polar, $s_ster_rad /wave=ster_rad
1563  ster_rad = calc_graph_radius(polar, projection=projection)
1564 
1565  string s_ster_x = s_prefix + "ster_x"
1566  string s_ster_y = s_prefix + "ster_y"
1567  duplicate /o azim, $s_ster_x /wave=ster_x, $s_ster_y /wave=ster_y
1568  ster_x = ster_rad * cos(azim * pi / 180)
1569  ster_y = ster_rad * sin(azim * pi / 180)
1570 
1571  variable azim_offset = 0
1572  if (!(NumberByKey("version", note(azim), "=", "\r") >= 1.6))
1573  DoAlert /T="display hemi scan" 0, "your dataset doesn't include the version 1.6 flag. if it was created with an earlier version that might be okay. please check that the orientation is correct!"
1574  azim_offset = 180// changed 151030 (v1.6)
1575  endif
1576 
1577  string s_trace
1578  switch(graphtype)
1579  case 1:
1580  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1581 
1582  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1583  ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2
1584  ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0}
1585 
1586  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 trace=polarY0
1587  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1588  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1589 
1590  SetWindow $graphname, userdata(projection)=num2str(projection)
1591  draw_hemi_axes(graphname, do_grids=do_grids)
1592  break
1593  case 3:
1594  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1595 
1596  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1597  ModifyGraph /W=$graphname mode($s_trace)=0, lsize($s_trace)=0
1598  AppendImage /L=VertCrossing /B=HorizCrossing matrix
1599 
1600  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 image=$s_matrix
1601  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1602  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1603 
1604  SetWindow $graphname, userdata(projection)=num2str(projection)
1605  draw_hemi_axes(graphname, do_grids=do_grids)
1606  break
1607  endswitch
1608 
1609  setdatafolder savedf
1610  return graphname
1611 };
1612 
1654 static string display_polar_graph(string graphname, variable angle_offset = defaultValue, variable do_ticks = defaultValue){
1655 
1656  string graphname
1657  variable angle_offset
1658  variable do_ticks
1659 
1660  dfref savedf = GetDataFolderDFR()
1661 
1662  if (ParamIsDefault(angle_offset))
1663  angle_offset = 0
1664  endif
1665  if (ParamIsDefault(do_ticks))
1666  do_ticks = 3
1667  endif
1668 
1669  if ((strlen(graphname) == 0) || (wintype(graphname) == 0))
1670  Display /k=1 /W=(10,45,360,345)
1671  DoWindow /C $graphname
1672  graphname = WMNewPolarGraph("", graphname)
1673  WMPolarGraphSetVar(graphname, "zeroAngleWhere", angle_offset)
1674 
1675  WMPolarGraphSetVar(graphname, "angleAxisThick", 0.5)
1676  WMPolarGraphSetStr(graphname, "doMajorAngleTicks", "manual")
1677  WMPolarGraphSetVar(graphname, "majorAngleInc", 30)// major ticks in 30 deg steps
1678  WMPolarGraphSetVar(graphname, "minorAngleTicks", 2)// minor ticks in 10 deg steps
1679  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1680  WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
1681  WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
1682  WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
1683  WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g")
1684 
1685  WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
1686  WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
1687  WMPolarGraphSetStr(graphname, "radiusAxesWhere", " Off")// note the leading spaces, cf. WMPolarAnglesForRadiusAxes
1688  WMPolarGraphSetStr(graphname, "radiusTicksLocation", "Off")
1689 
1690  WMPolarGraphSetVar(graphname, "majorTickLength", 2)
1691  WMPolarGraphSetVar(graphname, "majorTickThick", 0.5)
1692  WMPolarGraphSetVar(graphname, "minorTickLength", 1)
1693  WMPolarGraphSetVar(graphname, "minorTickThick", 0.5)
1694  WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0)
1695  WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7)
1696 
1697  // changes
1698  if (do_ticks & 1)
1699  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1700  else
1701  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Off")
1702  endif
1703  if (do_ticks & 2)
1704  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 1)
1705  else
1706  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 0)
1707  endif
1708 
1709  DoWindow /T $graphname, graphname
1710 
1711  // cursor info in angles
1712  string graphdf = "root:packages:WMPolarGraphs:" + graphname
1713  setdatafolder graphdf
1714  // current theta, phi coordinates are stored in global variables in the package folder of the graph
1715  variable /g csrA_theta
1716  variable /g csrA_phi
1717  variable /g csrB_theta
1718  variable /g csrB_phi
1719  // the text box is hidden initially. it shows up and hides with the cursor info box.
1720  string tb
1721  tb = "\\{"
1722  tb = tb + "\"A = (%.1f, %.1f)\","
1723  tb = tb + graphdf + ":csrA_theta,"
1724  tb = tb + graphdf + ":csrA_phi"
1725  tb = tb + "}"
1726  TextBox /W=$graphname /A=LT /B=1 /E=2 /F=0 /N=tb_angles /X=1 /Y=1 /V=0 tb
1727  tb = "\\{"
1728  tb = tb + "\"B = (%.1f, %.1f)\","
1729  tb = tb + graphdf + ":csrB_theta,"
1730  tb = tb + graphdf + ":csrB_phi"
1731  tb = tb + "}"
1732  AppendText /W=$graphname /N=tb_angles tb
1733  // updates are triggered by a window hook
1734  SetWindow $graphname, hook(polar_graph_hook)=PearlAnglescanProcess#polar_graph_hook
1735  else
1736  // graph window exists
1737  DoWindow /F $graphname
1738  endif
1739 
1740  setdatafolder savedf
1741  return graphname
1742 };
1743 
1769 static string draw_hemi_axes(string graphname, variable do_grids = defaultValue){
1770  string graphname
1771  variable do_grids
1772 
1773  if (ParamIsDefault(do_grids))
1774  do_grids = 3
1775  endif
1776 
1777  dfref savedf = GetDataFolderDFR()
1778 
1779  string sproj = GetUserData(graphname, "", "projection")
1780  variable projection = str2num("0" + sproj)
1781 
1782  SetDrawLayer /W=$graphname ProgFront
1783 
1784  // polar axis
1785  SetDrawEnv /W=$graphname xcoord=HorizCrossing, ycoord=VertCrossing
1786  SetDrawEnv /W=$graphname linethick= 0.5
1787  SetDrawEnv /W=$graphname dash=2
1788  SetDrawEnv /W=$graphname fillpat=0
1789  SetDrawEnv /W=$graphname fname="default", fsize=7
1790  SetDrawEnv /W=$graphname textxjust=1, textyjust=1
1791  //SetDrawEnv /W=$graphname linefgc=(65535,65535,65535)
1792  SetDrawEnv /W=$graphname save
1793 
1794  if (do_grids & 1)
1795  DrawLine /W=$graphname 0, -2, 0, 2
1796  DrawLine /W=$graphname -2, 0, 2, 0
1797  endif
1798 
1799  variable radi
1800  if (do_grids & 2)
1801  radi = calc_graph_radius(0.5, projection=projection)
1802  DrawOval /W=$graphname -radi, radi, radi, -radi
1803  radi = calc_graph_radius(30, projection=projection)
1804  DrawOval /W=$graphname -radi, radi, radi, -radi
1805  radi = calc_graph_radius(60, projection=projection)
1806  DrawOval /W=$graphname -radi, radi, radi, -radi
1807 
1808  SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
1809  SetDrawEnv /W=$graphname save
1810  radi = calc_graph_radius(30, projection=projection)
1811  DrawText /W=$graphname radi, -0.1, "30"
1812  radi = calc_graph_radius(60, projection=projection)
1813  DrawText /W=$graphname radi, -0.1, "60"
1814  endif
1815 
1816  setdatafolder savedf
1817 };
1818 
1841 variable draw_diffraction_cone(string graphname, string groupname, variable theta_axis, variable theta_inner, variable phi){
1842  string graphname
1843  string groupname
1844 
1845  variable theta_axis
1846  variable theta_inner
1847  variable phi
1848 
1849  variable r_axis = calc_graph_radius(theta_axis)
1850  variable r_inner = calc_graph_radius(theta_inner)
1851  variable r_outer = calc_graph_radius(2 * theta_axis - theta_inner)
1852 
1853  SetDrawEnv push
1854  SetDrawLayer UserFront
1855  DrawAction getgroup=$groupname, delete
1856  SetDrawEnv gstart, gname=$groupname
1857  variable xc, yc, xr, yr
1858 
1859  // cone periphery
1860  variable r_center = (r_outer + r_inner) / 2
1861  variable r_radius = (r_outer - r_inner) / 2
1862  xc = r_center * cos(phi * pi / 180)
1863  yc = r_center * sin(phi * pi / 180)
1864  xr = r_radius
1865  yr = r_radius
1866  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1867  SetDrawEnv dash=11, fillpat=0
1868  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1869 
1870  // cone axis
1871  xc = r_axis * cos(phi * pi / 180)
1872  yc = r_axis * sin(phi * pi / 180)
1873  r_radius = calc_graph_radius(2)
1874  xr = r_radius
1875  yr = r_radius
1876  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1877  SetDrawEnv fillfgc=(0,0,0)
1878  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1879 
1880  SetDrawEnv gstop
1881  SetDrawEnv pop
1882 };
1883 
1905 string display_scanlines(string nickname, variable alpha_lo, variable alpha_hi, wave m_theta, wave m_tilt, wave m_phi, variable folding = defaultValue, variable projection = defaultValue){
1906  string nickname
1907  variable alpha_lo
1908  variable alpha_hi
1909  wave m_theta
1910  wave m_tilt
1911  wave m_phi
1912  variable folding
1913  variable projection
1914 
1915  if (ParamIsDefault(folding))
1916  folding = 1
1917  endif
1918  if (ParamIsDefault(projection))
1919  projection = 1
1920  endif
1921 
1922  // sort out data folder structure
1923  dfref saveDF = GetDataFolderDFR()
1924  newdatafolder /s/o $nickname
1925  string graphname = "graph_" + nickname
1926 
1927  duplicate /free m_tilt, loc_m_tilt
1928  loc_m_tilt = -m_tilt
1929 
1930  make /n=1 /d /free d_polar, d_azi
1931  variable n_alpha = round(alpha_hi - alpha_lo) + 1
1932  make /n=(n_alpha) /d /free analyser
1933  setscale /i x alpha_lo, alpha_hi, "", analyser
1934  analyser = x
1935 
1936  convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
1937  duplicate /free d_polar, d_radius
1938  d_radius = calc_graph_radius(d_polar, projection=projection)
1939  d_azi += 180// changed 151030 (v1.6)
1940 
1941  graphname = display_polar_graph(graphname)
1942  SetWindow $graphname, userdata(projection)=num2str(projection)
1943 
1944  variable ifold
1945  variable iang
1946  variable nang = numpnts(m_theta)
1947  string s_rad
1948  string s_azi
1949  string s_trace
1950  for (ifold = 0; ifold < folding; ifold += 1)
1951  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
1952  for (iang = 0; iang < nang; iang += 1)
1953  sprintf s_rad, "rad_%d_%d", ifold, iang
1954  duplicate /o analyser, $s_rad
1955  wave w_rad = $s_rad
1956  w_rad = d_radius[p][iang]
1957 
1958  sprintf s_azi, "azi_%d_%d", ifold, iang
1959  duplicate /o analyser, $s_azi
1960  wave w_azi = $s_azi
1961  w_azi = d_azi[p][iang]
1962 
1963  if (numtype(sum(w_rad)) == 0)
1964  s_trace = WMPolarAppendTrace(graphname, w_rad, w_azi, 360)
1965  ModifyGraph /w=$graphname mode($s_trace)=0, lsize($s_trace)=0.5
1966  endif
1967  endfor
1968  d_azi += 360 / folding
1969  endfor
1970 
1971  draw_hemi_axes(graphname)
1972 
1973  setdatafolder saveDF
1974  return graphname
1975 };
1976 
1993 const variable kProjDist = 0;
1994 const variable kProjStereo = 1;
1995 const variable kProjArea = 2;
1996 const variable kProjGnom = 3;
1997 const variable kProjOrtho = 4;
1998 
1999 static const variable kProjScaleDist = 2;
2000 static const variable kProjScaleStereo = 2;
2001 static const variable kProjScaleArea = 2;
2002 // scaled so that radius(gnom) = radius(stereo) for polar = 88
2003 static const variable kProjScaleGnom = 0.06744519021;
2004 static const variable kProjScaleOrtho = 2;
2005 
2020 threadsafe variable calc_graph_radius(variable polar, variable projection = defaultValue){
2021  variable polar
2022  variable projection
2023 
2024  if (ParamIsDefault(projection))
2025  projection = 1
2026  endif
2027 
2028  variable radius
2029  switch(projection)
2030  case kProjStereo:// stereographic
2031  radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
2032  break
2033  case kProjArea:// equal area
2034  radius = kProjScaleArea * sin(polar / 2 * pi / 180)
2035  break
2036  case kProjGnom:// gnomonic
2037  radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
2038  break
2039  case kProjOrtho:// orthographic
2040  radius = kProjScaleOrtho * sin(polar * pi / 180)
2041  break
2042  default:// equidistant
2043  radius = kProjScaleDist * polar / 90
2044  endswitch
2045 
2046  return radius
2047 };
2048 
2065 threadsafe variable calc_graph_polar(variable x, variable y, variable projection = defaultValue){
2066  variable x
2067  variable y
2068  variable projection
2069 
2070  if (ParamIsDefault(projection))
2071  projection = 1
2072  endif
2073 
2074  variable radius
2075  variable polar
2076 
2077  radius = sqrt(x^2 + y^2)
2078  switch(projection)
2079  case kProjStereo:// stereographic
2080  polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
2081  break
2082  case kProjArea:// equal area
2083  polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
2084  break
2085  case kProjGnom:// gnomonic
2086  polar = atan(radius / kProjScaleGnom) * 180 / pi
2087  break
2088  case kProjOrtho:// orthographic
2089  polar = asin(radius / kProjScaleOrtho) * 180 / pi
2090  break
2091  default:// equidistant
2092  polar = 90 * radius / kProjScaleDist
2093  endswitch
2094 
2095  return polar
2096 };
2097 
2118 threadsafe variable calc_graph_azi(variable x, variable y, variable projection = defaultValue, variable zeroAngle = defaultValue){
2119  variable x
2120  variable y
2121  variable projection
2122  variable zeroAngle
2123 
2124  if (ParamIsDefault(projection))
2125  projection = 1
2126  endif
2127  if (ParamIsDefault(zeroAngle))
2128  zeroAngle = 0
2129  endif
2130 
2131  variable azi
2132  if (x > 0)
2133  azi = atan(y / x) * 180 / pi
2134  else
2135  azi = atan(y / x) * 180 / pi + 180
2136  endif
2137 
2138  azi += zeroAngle
2139  if (azi < 0)
2140  azi += 360
2141  endif
2142  if (azi >= 360)
2143  azi -= 360
2144  endif
2145  if (numtype(azi) != 0)
2146  azi = 0
2147  endif
2148 
2149  return azi
2150 };
2151 
2163 static variable update_polar_info(string graphname){
2164  string graphname
2165 
2166  dfref savedf = GetDataFolderDFR()
2167 
2168  string graphdf = "root:packages:WMPolarGraphs:" + graphname
2169  setdatafolder graphdf
2170 
2171  nvar csrA_theta
2172  nvar csrA_phi
2173  nvar csrB_theta
2174  nvar csrB_phi
2175 
2176  string sproj = GetUserData(graphname, "", "projection")
2177  variable projection = str2num("0" + sproj)
2178  nvar zeroAngleWhere
2179 
2180  variable x = hcsr(A, graphname)
2181  variable y = vcsr(A, graphname)
2182  csrA_theta = calc_graph_polar(x, y, projection=projection)
2183  csrA_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2184 
2185  x = hcsr(B, graphname)
2186  y = vcsr(B, graphname)
2187  csrB_theta = calc_graph_polar(x, y, projection=projection)
2188  csrB_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2189 
2190  setdatafolder savedf
2191 };
2192 
2198 static variable polar_graph_hook(WMWinHookStruct* s){
2199  STRUCT WMWinHookStruct &s
2200 
2201  Variable hookResult = 0
2202 
2203  switch(s.eventCode)
2204  case 7:// cursor moved
2205  update_polar_info(s.winname)
2206  break
2207  case 20:// show info
2208  TextBox /W=$s.winname /N=tb_angles /C /V=1
2209  break
2210  case 21:// hide info
2211  TextBox /W=$s.winname /N=tb_angles /C /V=0
2212  break
2213  endswitch
2214 
2215  return hookResult// 0 if nothing done, else 1
2216 };
2217 
2218 variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname = defaultValue){
2219  string nickname
2220  string cursorname
2221  variable polar_angle
2222  variable azim_angle
2223  string graphname
2224 
2225  if (ParamIsDefault(graphname))
2226  if (strlen(nickname) > 0)
2227  graphname = nickname
2228  else
2229  graphname = GetDataFolder(0)
2230  endif
2231  endif
2232 
2233  string s_prefix = ""
2234  string s_int = "values"
2235  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2236 
2237  string s_polar = s_prefix + "pol"
2238  string s_azim = s_prefix + "az"
2239  wave /sdfr=df /z azim = $s_azim
2240  wave /sdfr=df /z polar = $s_polar
2241 
2242  FindLevel /P /Q polar, polar_angle
2243  if (v_flag == 0)
2244  variable polar_level = floor(v_levelx)
2245  FindLevel /P /Q /R=[polar_level] azim, azim_angle
2246  if (v_flag == 0)
2247  variable azim_level = round(v_levelx)
2248  string tracename = "polarY0"
2249  Cursor /W=$graphname /P $cursorname $traceName azim_level
2250  endif
2251  endif
2252 };
2253 
2263 variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights = defaultValue){
2264  string nickname// name prefix of holo waves.
2265  // may be empty.
2266  wave values// intensity values
2267  // the wave can be one- or two-dimensional.
2268  // no specific order required, the function sorts the arrays internally
2269  wave polar// polar coordinates. allowed range 0 <= theta <= 90
2270  // dimensions corresponding to value.
2271  wave azi// azimuthal coordinates. allowed range -360 <= phi < +360
2272  // dimensions corresponding to value.
2273  wave weights// total accumulation time of each point of values. default = 1
2274 
2275  if (ParamIsDefault(weights))
2276  duplicate /free values, weights
2277  weights = 1
2278  endif
2279 
2280  // quick check whether hemi grid is existing
2281  string s_prefix = ""
2282  string s_int = "values"
2283  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2284 
2285  string s_polar = s_prefix + "pol"
2286  string s_azim = s_prefix + "az"
2287  string s_theta = s_prefix + "th"
2288 
2289  wave /sdfr=df /z w_values = $s_int
2290  wave /sdfr=df /z w_azim = $s_azim
2291  wave /sdfr=df /z w_polar = $s_polar
2292  wave /sdfr=df /z w_theta = $s_theta
2293  if (!waveexists(w_values) || !waveexists(w_azim) || !waveexists(w_polar))
2294  abort "Missing hemispherical scan grid. Please call make_hemi_grid() first."
2295  endif
2296 
2297  // make internal copies, one-dimensional, ordered in theta
2298  duplicate /free values, values_copy
2299  duplicate /free polar, polar_copy
2300  duplicate /free azi, azi_copy
2301  duplicate /free weights, weights_copy
2302  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2303  redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
2304  sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
2305 
2306  variable pol
2307  variable pol_st = abs(w_theta[1] - w_theta[0])
2308  variable pol1, pol2
2309 
2310  duplicate /free azi_copy, azi_slice
2311  duplicate /free values_copy, values_slice
2312  duplicate /free weights_copy, weights_slice
2313  for (pol = 90; pol >= 0; pol -= pol_st)
2314  pol1 = pol - pol_st / 2
2315  pol2 = pol + pol_st / 2
2316  extract /free /indx polar_copy, sel, (pol1 < polar_copy) && (polar_copy <= pol2)
2317  if (numpnts(sel) > 0)
2318  redimension /n=(numpnts(sel)) azi_slice, values_slice, weights_slice
2319  azi_slice = azi_copy[sel]
2320  values_slice = values_copy[sel]
2321  weights_slice = weights_copy[sel]
2322  hemi_add_aziscan(nickname, values_slice, pol, azi_slice, weights=weights_slice)
2323  endif
2324  endfor
2325 };
2326 
2333 variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights = defaultValue){
2334  string nickname// name prefix of holo waves.
2335  // may be empty.
2336  wave values// intensity values of the azimuthal scan at the positions given in the azi parameter
2337  variable polar// polar angle where to add the azi scan
2338  wave azi// angle positions of the azimuthal scan
2339  // acceptable range: >= -360 and < +360
2340  // no specific order required, the function sorts the array internally
2341  wave weights// total accumulation time of each point of values. default = 1
2342 
2343  if (ParamIsDefault(weights))
2344  duplicate /free values, weights
2345  weights = 1
2346  endif
2347 
2348  // hemi grid waves
2349  string s_prefix = ""
2350  string s_int = "values"
2351  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2352 
2353  string s_totals = s_prefix + "tot"
2354  string s_weights = s_prefix + "wt"
2355  string s_polar = s_prefix + "pol"
2356  string s_azim = s_prefix + "az"
2357  string s_index = s_prefix + "index"
2358  string s_theta = s_prefix + "th"
2359  string s_dphi = s_prefix + "dphi"
2360  string s_nphis = s_prefix + "nphis"
2361 
2362  wave /sdfr=df w_polar = $s_polar
2363  wave /sdfr=df w_azim = $s_azim
2364  wave /sdfr=df w_values = $s_int
2365  wave /sdfr=df w_totals = $s_totals
2366  wave /sdfr=df w_weights = $s_weights
2367  wave /sdfr=df w_index = $s_index
2368  wave /sdfr=df w_theta = $s_theta
2369  wave /sdfr=df w_dphi = $s_dphi
2370  wave /sdfr=df w_nphis = $s_nphis
2371 
2372  // destination slice coordinates
2373  //polar = round(polar)
2374  //variable ipol = 90 - polar
2375  variable ipol = BinarySearch(w_theta, polar)
2376  if (ipol < 0)
2377  abort "assertion failed in hemi_add_aziscan(): polar angle not found in grid."
2378  endif
2379 
2380  variable d1, d2
2381  if (ipol >= 1)
2382  d1 = w_index[ipol - 1]
2383  else
2384  d1 = 0
2385  endif
2386  d2 = w_index[ipol] - 1
2387  variable nd = d2 - d1 + 1
2388  variable dphi = w_dphi[ipol]
2389  variable az1, az2
2390 
2391  // source slice coordinates
2392  // order the slice from -dphi/2 to 360-dphi/2
2393  azi = azi < 0 ? azi + 360 : azi
2394  azi = azi >= 360 - dphi/2 ? azi - 360 : azi
2395  duplicate /free values, sel_values
2396  duplicate /free weights, sel_weights
2397 
2398  // loop over destination
2399  variable id
2400  variable v1, v2, w1, w2
2401  for (id = 0; id < nd; id += 1)
2402  az1 = (id - 0.5) * dphi
2403  az2 = (id + 0.5) * dphi
2404  extract /free /indx azi, sel, (az1 <= azi) && (azi < az2)
2405  if (numpnts(sel) > 0)
2406  redimension /n=(numpnts(sel)) sel_values, sel_weights
2407  sel_values = values[sel]
2408  sel_weights = weights[sel]
2409  v1 = w_totals[d1 + id]
2410  w1 = w_weights[d1 + id]
2411  if ((numtype(v1) == 2) || (w1 <= 0))
2412  v1 = 0
2413  w1 = 0
2414  endif
2415  v2 = sum(sel_values)
2416  w2 = sum(sel_weights)
2417  w_totals[d1 + id] = v1 + v2
2418  w_weights[d1 + id] = w1 + w2
2419  endif
2420  endfor
2421  w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
2422 };
2423 
2439 variable interpolate_hemi_scan(string nickname){
2440  string nickname
2441 
2442  dfref savedf = GetDataFolderDFR()
2443 
2444  string s_prefix = ""
2445  string s_int = "values"
2446  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2447 
2448  string s_polar = s_prefix + "pol"
2449  string s_azim = s_prefix + "az"
2450  string s_ster_x = s_prefix + "ster_x"
2451  string s_ster_y = s_prefix + "ster_y"
2452 
2453  wave /sdfr=df values = $s_int
2454  wave /sdfr=df azim = $s_azim
2455  wave /sdfr=df polar = $s_polar
2456  wave /sdfr=df ster_x = $s_ster_x
2457  wave /sdfr=df ster_y = $s_ster_y
2458 
2459  variable min_ster_x = wavemin(ster_x)
2460  variable max_ster_x = wavemax(ster_x)
2461  variable x0 = min_ster_x
2462  variable xn = 181
2463  variable dx = (max_ster_x - min_ster_x) / (xn - 1)
2464  make /n=(numpnts(ster_x), 3) /free triplet
2465  triplet[][0] = ster_x[p]
2466  triplet[][1] = ster_y[p]
2467  triplet[][2] = values[p]
2468 
2469  variable size = 181
2470  setdatafolder df
2471  make /n=(size, size) /d /o $(s_prefix + "matrix") /wave=matrix
2472  make /n=(size, size) /free mnorm
2473  ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm
2474  matrix /= mnorm
2475  matrixfilter NanZapMedian, matrix
2476  matrixfilter gauss, matrix
2477 
2478  duplicate /free values, ster_finite
2479  ster_finite = (numtype(values) == 0) * (ster_x^2 + ster_y^2)
2480  variable ster_max = wavemax(ster_finite)
2481  matrix = (x^2 + y^2) <= ster_max ? matrix : nan
2482 
2483  setdatafolder savedf
2484 };
2485 
2496 variable quick_pizza_image(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar = defaultValue, variable nograph = defaultValue, variable folding = defaultValue){
2497  wave data// 2D intensity wave, see requirements above
2498  string nickname// nick name for output data
2499  // in default mode, this will be the name of a child folder containing the output
2500  // in XPDplot mode, this will be a prefix of the generated data in the root folder
2501  variable theta_offset// manipulator theta angle corresponding to normal emission
2502  variable tilt_offset// manipulator tilt angle corresponding to normal emission
2503  variable phi_offset// manipulator phi angle corresponding to phi_result = 0
2504  variable npolar// number of polar angles, determines polar and azimuthal step size
2505  // default = 91 (1 degree steps)
2506  variable nograph// 0 (default) = display a new polar graph
2507  // 1 = don't display a new graph (if a graph is existing from a previous call, it will update)
2508  variable folding// rotational averaging, default = 1
2509 
2510  if (ParamIsDefault(npolar))
2511  npolar = 91
2512  endif
2513  if (ParamIsDefault(nograph))
2514  nograph = 0
2515  endif
2516  if (ParamIsDefault(folding))
2517  folding = 1
2518  endif
2519  string graphname = "graph_" + nickname
2520  string s_prefix = ""
2521 
2522  // sort out data folder structure
2523  dfref saveDF = GetDataFolderDFR()
2524  dfref dataDF = GetWavesDataFolderDFR(data)
2525  setdatafolder dataDF
2526  if (DataFolderExists(":attr"))
2527  setdatafolder :attr
2528  endif
2529  dfref attrDF = GetDataFolderDFR()
2530  setdatafolder dataDF
2531  newdatafolder /s/o $nickname
2532  dfref destDF = GetDataFolderDFR()
2533 
2534  // performance monitoring
2535  variable timerRefNum
2536  variable /g xyz_perf_secs
2537  timerRefNum = startMSTimer
2538 
2539  wave /sdfr=attrDF ManipulatorTheta
2540  wave /sdfr=attrDF ManipulatorTilt
2541  wave /sdfr=attrDF ManipulatorPhi
2542  duplicate /free ManipulatorTheta, m_theta
2543  duplicate /free ManipulatorTilt, m_tilt
2544  duplicate /free ManipulatorPhi, m_phi
2545  m_theta -= theta_offset
2546  m_tilt -= tilt_offset
2547  m_tilt *= -1// checked 140702
2548  m_phi -= phi_offset
2549  //m_phi *= -1 // checked 140702
2550 
2551  make /n=1/d/free d_polar, d_azi
2552  convert_angles_ttpd2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
2553  d_azi += 180// changed 151030 (v1.6)
2554  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
2555 
2556  duplicate /free data, values
2557  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2558  redimension /n=(nn) values, d_polar, d_azi
2559  duplicate /o d_polar, ster_rad, ster_x, ster_y
2560 
2561  variable projection = 1
2562  switch(projection)
2563  case 1:// stereographic
2564  ster_rad = 2 * tan(d_polar / 2 * pi / 180)
2565  break
2566  case 2:// azimuthal
2567  ster_rad = 2 * cos((180 - d_polar) / 2 * pi / 180)
2568  break
2569  endswitch
2570  string s_ster_x = s_prefix + "ster_x"
2571  string s_ster_y = s_prefix + "ster_y"
2572 
2573  nn = 401
2574  make /n=(nn, nn) /d /o matrix
2575  make /n=(nn, nn) /free mnorm
2576  setscale /i x -2, +2, matrix, mnorm
2577  setscale /i y -2, +2, matrix, mnorm
2578  matrix = 0
2579  mnorm = 0
2580 
2581  variable ifold
2582  for (ifold = 0; ifold < folding; ifold += 1)
2583  ster_x = ster_rad * cos(d_azi * pi / 180)
2584  ster_y = ster_rad * sin(d_azi * pi / 180)
2585  ImageFromXYZ {ster_x, ster_y, values}, matrix, mnorm
2586  d_azi = d_azi >= 180 ? d_azi + 360 / folding - 180 : d_azi + 360 / folding
2587  endfor
2588 
2589  matrix /= mnorm
2590  matrixfilter /n=5 NanZapMedian matrix
2591  matrixfilter /n=3 gauss matrix
2592 
2593  if (!nograph)
2594  display /k=1
2595  appendimage matrix
2596  modifygraph width={Plan,1,bottom,left}
2597  endif
2598 
2599  if (timerRefNum >= 0)
2600  xyz_perf_secs = stopMSTimer(timerRefNum) / 1e6
2601  endif
2602 
2603  setdatafolder saveDF
2604 };
2605 
2607 variable save_hemi_scan(string nickname, string pathname, string filename){
2608  string nickname
2609  string pathname
2610  string filename
2611 
2612  dfref savedf = getdatafolderdfr()
2613 
2614  // source data
2615  string s_prefix = ""
2616  string s_int = "values"
2617  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2618 
2619  string s_polar = s_prefix + "pol"
2620  string s_azim = s_prefix + "az"
2621  string s_theta = s_prefix + "th"
2622  string s_tot = s_prefix + "tot"
2623  string s_weight = s_prefix + "wt"
2624 
2625  wave /sdfr=df theta1 = $s_theta
2626  wave /sdfr=df polar1 = $s_polar
2627  wave /sdfr=df azim1 = $s_azim
2628  wave /sdfr=df tot1 = $s_tot
2629  wave /sdfr=df weight1 = $s_weight
2630  wave /sdfr=df values1 = $s_int
2631 
2632  save /m="\r\n" /o /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2633 
2634  setdatafolder saveDF
2635 };
2636 
2640 variable load_hemi_scan(string nickname, string pathname, string filename){
2641  string nickname
2642  string pathname
2643  string filename
2644 
2645  dfref savedf = getdatafolderdfr()
2646 
2647  //loadwave /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2648  //LoadWave /t/p=pearl_explorer_filepath/q filename
2649  //svar waves = s_wavenames
2650  //if (v_flag > 0)
2651  // string /g pearl_explorer_import = "load_itx_file"
2652  //endif
2653 
2654  setdatafolder saveDF
2655 };
2656 
2689 variable import_tpi_scan(string nickname, wave theta, wave phi, wave intensity, variable folding = defaultValue, variable npolar = defaultValue, variable nograph = defaultValue, variable xpdplot = defaultValue){
2690  string nickname
2691  wave theta
2692  wave phi
2693  wave intensity
2694 
2695  variable folding
2696  variable npolar
2697  variable nograph
2698  variable xpdplot
2699 
2700  if (ParamIsDefault(npolar))
2701  npolar = 91
2702  endif
2703  if (ParamIsDefault(nograph))
2704  nograph = 0
2705  endif
2706  if (ParamIsDefault(folding))
2707  folding = 1
2708  endif
2709  if (ParamIsDefault(xpdplot))
2710  xpdplot = 0
2711  endif
2712 
2713  make_hemi_grid(npolar, nickname, xpdplot=xpdplot)
2714 
2715  variable ifold
2716  duplicate /free phi, fold_phi
2717  for (ifold = 0; ifold < folding; ifold += 1)
2718  hemi_add_anglescan(nickname, intensity, theta, fold_phi)
2719  fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
2720  endfor
2721 
2722  if (nograph==0)
2723  display_hemi_scan(nickname)
2724  endif
2725 };
2726 
2738 variable trim_hemi_scan(string nickname, variable theta_max){
2739  string nickname
2740  variable theta_max
2741 
2742  string s_prefix = ""
2743  string s_int = "values"
2744  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2745 
2746  string s_totals = s_prefix + "tot"
2747  string s_weights = s_prefix + "wt"
2748  string s_polar = s_prefix + "pol"
2749 
2750  wave /sdfr=df w_polar = $s_polar
2751  wave /sdfr=df w_values = $s_int
2752  wave /sdfr=df w_totals = $s_totals
2753  wave /sdfr=df w_weights = $s_weights
2754 
2755  w_values = w_polar <= theta_max ? w_totals / w_weights : nan
2756 };
2757 
2777 wave hemi_polar_cut(string nickname, variable azim){
2778  string nickname
2779  variable azim
2780 
2781  dfref savedf = getdatafolderdfr()
2782  string s_prefix = ""
2783  string s_int = "values"
2784  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2785 
2786  string s_totals = s_prefix + "tot"
2787  string s_weights = s_prefix + "wt"
2788  string s_polar = s_prefix + "pol"
2789  string s_azim = s_prefix + "az"
2790  string s_index = s_prefix + "index"
2791  string s_theta = s_prefix + "th"
2792  string s_dphi = s_prefix + "dphi"
2793  string s_nphis = s_prefix + "nphis"
2794  string s_cut
2795  sprintf s_cut, "%s_azi%03u", s_int, round(azim)
2796 
2797  wave /sdfr=df w_polar = $s_polar
2798  wave /sdfr=df w_azim = $s_azim
2799  wave /sdfr=df w_values = $s_int
2800  wave /sdfr=df w_totals = $s_totals
2801  wave /sdfr=df w_weights = $s_weights
2802  wave /sdfr=df w_index = $s_index
2803  wave /sdfr=df w_theta = $s_theta
2804  wave /sdfr=df w_dphi = $s_dphi
2805  wave /sdfr=df w_nphis = $s_nphis
2806 
2807  variable npol = numpnts(w_theta)
2808  variable ipol
2809  variable pol_st = abs(w_theta[1] - w_theta[0])
2810  variable pol
2811  variable pol1, pol2
2812  variable nsel
2813 
2814  setdatafolder df
2815  make /n=(npol) /o $s_cut
2816  wave w_cut = $s_cut
2817  setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
2818  make /n=1 /free azi_slice
2819  make /n=1 /free values_slice
2820 
2821  for (ipol = 0; ipol < npol; ipol += 1)
2822  pol = w_theta[ipol]
2823  pol1 = pol - pol_st / 2
2824  pol2 = pol + pol_st / 2
2825  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2826  nsel = numpnts(sel)
2827  if (nsel > 0)
2828  redimension /n=(nsel+2) azi_slice, values_slice
2829  azi_slice[1, nsel] = w_azim[sel[p-1]]
2830  azi_slice[0] = azi_slice[nsel] - 360
2831  azi_slice[nsel+1] = azi_slice[1] + 360
2832  values_slice[1, nsel] = w_values[sel[p-1]]
2833  values_slice[0] = values_slice[nsel]
2834  values_slice[nsel+1] = values_slice[1]
2835  w_cut[ipol] = interp(azim, azi_slice, values_slice)
2836  else
2837  w_cut[ipol] = nan
2838  endif
2839  endfor
2840 
2841  setdatafolder savedf
2842  return w_cut
2843 };
2844 
2863 wave hemi_azi_cut(string nickname, variable pol){
2864  string nickname
2865  variable pol
2866 
2867  dfref savedf = getdatafolderdfr()
2868  string s_prefix = ""
2869  string s_int = "values"
2870  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2871 
2872  string s_totals = s_prefix + "tot"
2873  string s_weights = s_prefix + "wt"
2874  string s_polar = s_prefix + "pol"
2875  string s_azim = s_prefix + "az"
2876  string s_index = s_prefix + "index"
2877  string s_theta = s_prefix + "th"
2878  string s_dphi = s_prefix + "dphi"
2879  string s_nphis = s_prefix + "nphis"
2880  string s_cut
2881  sprintf s_cut, "%s_pol%03u", s_int, round(pol)
2882 
2883  wave /sdfr=df w_polar = $s_polar
2884  wave /sdfr=df w_azim = $s_azim
2885  wave /sdfr=df w_values = $s_int
2886  wave /sdfr=df w_totals = $s_totals
2887  wave /sdfr=df w_weights = $s_weights
2888  wave /sdfr=df w_index = $s_index
2889  wave /sdfr=df w_theta = $s_theta
2890  wave /sdfr=df w_dphi = $s_dphi
2891  wave /sdfr=df w_nphis = $s_nphis
2892 
2893  variable pol_st = abs(w_theta[1] - w_theta[0])
2894  variable pol1, pol2
2895  variable nsel
2896 
2897  pol1 = pol - pol_st / 2
2898  pol2 = pol + pol_st / 2
2899  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2900  nsel = numpnts(sel)
2901  if (nsel > 0)
2902  setdatafolder df
2903  make /n=(nsel) /o $s_cut
2904  wave w_cut = $s_cut
2905  w_cut = w_values[sel]
2906  setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "", w_cut
2907  setdatafolder savedf
2908  return w_cut
2909  else
2910  setdatafolder savedf
2911  return $""
2912  endif
2913  setdatafolder savedf
2914 };
2915 
2916 static variable check_contrast(wave values, variable pcmin, variable pcmax, variable* vmin, variable* vmax){
2917  wave values
2918  variable pcmin
2919  variable pcmax
2920  variable &vmin
2921  variable &vmax
2922 
2923  dfref save_df = GetDataFolderDFR()
2924  dfref dfr = NewFreeDataFolder()
2925  setdatafolder dfr
2926  StatsQuantiles /inan /iw /q /z values
2927  wave index = w_quantilesindex
2928  variable imin = round(numpnts(index) * pcmin / 100)
2929  variable imax = round(numpnts(index) * (100 - pcmax) / 100)
2930  vmin = values[index[imin]]
2931  vmax = values[index[imax]]
2932  KillDataFolder dfr
2933  setdatafolder save_df
2934 };
2935 
2952 variable set_contrast(variable pcmin, variable pcmax, string graphname = defaultValue, string colortable = defaultValue){
2953  variable pcmin
2954  variable pcmax
2955  string graphname
2956  string colortable
2957 
2958  if (ParamIsDefault(graphname))
2959  graphname = ""
2960  endif
2961  if (ParamIsDefault(colortable))
2962  colortable = ""
2963  endif
2964 
2965  dfref save_df = GetDataFolderDFR()
2966 
2967  string objname
2968  string info
2969  string wname
2970  string ctab
2971  variable rev
2972  variable n
2973  variable i
2974  variable vmin
2975  variable vmax
2976 
2977  string traces = TraceNameList(graphname, ";", 1+4)
2978  n = ItemsInList(traces, ";")
2979  for (i = 0; i < n; i += 1)
2980  objname = StringFromList(i, traces, ";")
2981  info = TraceInfo(graphname, objname, 0)
2982  if (strlen(info) > 0)
2983  info = StringByKey("RECREATION", info, ":", ";")
2984  info = StringByKey("zColor(x)", info, "=", ";")
2985  if (strlen(info) > 2)
2986  info = info[1,strlen(info)-2]
2987  wname = StringFromList(0, info, ",")
2988  wave w = $wname
2989  ctab = StringFromList(3, info, ",")
2990  rev = str2num("0" + StringFromList(4, info, ","))
2991  if (strlen(colortable) > 0)
2992  ctab = colortable
2993  endif
2994  check_contrast(w, pcmin, pcmax, vmin, vmax)
2995  ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
2996  endif
2997  endif
2998  endfor
2999 
3000  string images = ImageNameList(graphname, ";")
3001  n = ItemsInList(images, ";")
3002  for (i = 0; i < n; i += 1)
3003  objname = StringFromList(i, images, ";")
3004  wave w = ImageNameToWaveRef(graphname, objname)
3005  info = ImageInfo(graphname, objname, 0)
3006  if (strlen(info) > 0)
3007  info = StringByKey("RECREATION", info, ":", ";")
3008  info = StringByKey("ctab", info, "=", ";")
3009  if (strlen(info) > 2)
3010  info = info[1,strlen(info)-2]
3011  ctab = StringFromList(2, info, ",")
3012  rev = str2num("0" + StringFromList(3, info, ","))
3013  if (strlen(colortable) > 0)
3014  ctab = colortable
3015  endif
3016  check_contrast(w, pcmin, pcmax, vmin, vmax)
3017  ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
3018  endif
3019  endif
3020  endfor
3021 
3022  setdatafolder save_df
3023 };
3024 
wave fit_scienta_ang_transm(wave data, wave params)
-
wave hemi_polar_cut(string nickname, variable azim)
extract a polar cut from a hemispherical scan.
-
variable trim_hemi_scan(string nickname, variable theta_max)
trim a hemispherical scan at grazing angle
-
variable pizza_service_2(wave data, string nickname, wave m_theta, wave m_tilt, wave m_phi, variable npolar=defaultValue, variable nograph=defaultValue, variable folding=defaultValue, variable xpdplot=defaultValue)
create a pizza plot from a measured (energy-integrated) data strip
-
static const variable kProjScaleOrtho
+Go to the documentation of this file.
1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
2 #pragma version = 1.8
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlAnglescanProcess
5 #include "pearl-vector-operations"
6 #include "pearl-polar-coordinates"
7 #include <New Polar Graphs>
8 
9 // copyright (c) 2013-17 Paul Scherrer Institut
10 //
11 // Licensed under the Apache License, Version 2.0 (the "License");
12 // you may not use this file except in compliance with the License.
13 // You may obtain a copy of the License at
14 // http:///www.apache.org/licenses/LICENSE-2.0
15 //
16 // Please acknowledge the use of this code.
17 
76 
81 
82 
105 variable strip_delete_frames(wave strip, variable qlo, variable qhi, wave theta, wave tilt, wave phi){
106  wave strip// 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
107  variable qlo
108  variable qhi
109  wave theta
110  wave tilt
111  wave phi
112 
113  if (qlo > qhi)
114  return -1
115  endif
116 
117  // source indices
118  variable snx = dimsize(strip, 0)
119  variable sny = dimsize(strip, 1)
120  variable sq1lo = 0
121  variable sq1hi = max(qlo-1, 0)
122  variable sq2lo = min(qhi+1, sny - 1)
123  variable sq2hi = dimsize(strip, 1) - 1
124 
125  // dest indices
126  variable dnx = snx
127  variable dny = sny - (sq2lo - sq1hi + 1)
128  variable dq1lo = 0
129  variable dq1hi = sq1hi
130  variable dq2lo = dq1hi + 1
131  variable dq2hi = dny - 1
132  variable q1ofs = sq1lo - dq1lo
133  variable q2ofs = sq2lo - dq2lo
134 
135  duplicate /free strip, strip_copy
136  redimension /n=(dnx,dny) strip
137  strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs]
138  strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs]
139 
140  duplicate /free theta, theta_copy
141  redimension /n=(dny) theta
142  theta[dq1lo,dq1hi] = theta_copy[p + q1ofs]
143  theta[dq2lo,dq2hi] = theta_copy[p + q2ofs]
144 
145  duplicate /free tilt, tilt_copy
146  redimension /n=(dny) tilt
147  tilt[dq1lo,dq1hi] = tilt_copy[p + q1ofs]
148  tilt[dq2lo,dq2hi] = tilt_copy[p + q2ofs]
149 
150  duplicate /free phi, phi_copy
151  redimension /n=(dny) phi
152  phi[dq1lo,dq1hi] = phi_copy[p + q1ofs]
153  phi[dq2lo,dq2hi] = phi_copy[p + q2ofs]
154 
155  return 0
156 };
157 
185 variable normalize_strip_x(wave strip, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
186  wave strip
187  variable smooth_method
188  variable smooth_factor
189  variable check
190 
191  if (ParamIsDefault(smooth_method))
192  smooth_method = 4
193  endif
194  if (ParamIsDefault(smooth_factor))
195  switch(smooth_method)
196  case 4:
197  smooth_factor = 0.5
198  break
199  default:
200  smooth_factor = 2
201  endswitch
202  endif
203  if (ParamIsDefault(check))
204  check = 0
205  endif
206 
207  // average over all scan positions
208  wave dist = ad_profile_x(strip, -inf, inf, "")
209  variable div = mean(dist)
210  dist /= div
211 
212  if (check)
213  duplicate /o dist, check_dist
214  endif
215 
216  // smooth distribution function
217  switch(smooth_method)
218  case 1:
219  Smooth /B /E=3 smooth_factor, dist
220  break
221  case 2:
222  Smooth /E=3 smooth_factor, dist
223  break
224  case 3:
225  make /n=1 /d /free fit_params
226  fit_scienta_ang_transm(dist, fit_params)
227  dist = scienta_ang_transm(fit_params, x)
228  break
229  case 4:
230  loess /smth=(smooth_factor) srcWave=dist
231  break
232  endswitch
233 
234  if (check)
235  duplicate /o dist, check_smoo
236  endif
237 
238  // divide
239  if (check != 2)
240  strip /= dist[p]
241  endif
242 };
243 
270 variable normalize_strip_phi(wave strip, wave theta, wave phi, variable theta_offset = defaultValue, variable theta_range = defaultValue, variable check = defaultValue){
271  wave strip
272  wave theta
273  wave phi
274  variable theta_offset
275  variable theta_range
276  variable check
277 
278  if (ParamIsDefault(check))
279  check = 0
280  endif
281  if (ParamIsDefault(theta_offset))
282  theta_offset = 0
283  endif
284  if (ParamIsDefault(theta_range))
285  theta_offset = 10
286  endif
287 
288  // average over analyser angles
289  wave dist = ad_profile_y(strip, -inf, inf, "")
290 
291  // smooth distribution function
292  duplicate /free dist, dist_smoo
293  duplicate /free theta, theta_int
294  theta_int = theta - theta_offset
295  duplicate /free phi, phi_int
296  setscale /p x phi_int[0], phi_int[1] - phi_int[0], waveunits(phi, -1), dist, dist_smoo
297 
298  extract /free /indx dist, red_idx, theta_int < theta_range
299  duplicate /free red_idx, red_dist, red_phi
300  red_dist = dist[red_idx]
301  red_phi = phi_int[red_idx]
302 
303  variable wavg = mean(red_dist)
304  make /n=4 /d /free coef
305  coef[0] = {wavg, wavg/100, pi/180, 0}
306  CurveFit /q /h="0010" /g /w=2 sin, kwcWave=coef, red_dist /x=red_phi
307  dist_smoo = coef[0] + coef[1] * sin(coef[2] * phi_int[p] + coef[3])
308 
309  // divide
310  if (check != 2)
311  strip = strip / dist_smoo[q] * coef[0]
312  endif
313 
314  // check
315  if (check)
316  duplicate /o dist, check_dist
317  duplicate /o dist_smoo, check_smoo
318  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
319  endif
320 };
321 
353 variable normalize_strip_theta(wave strip, wave theta, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
354  wave strip
355  wave theta
356  variable theta_offset
357  variable smooth_method
358  variable smooth_factor
359  variable check
360 
361  if (ParamIsDefault(check))
362  check = 0
363  endif
364  if (ParamIsDefault(theta_offset))
365  theta_offset = 0
366  endif
367  if (ParamIsDefault(smooth_method))
368  smooth_method = 4
369  endif
370  if (ParamIsDefault(smooth_factor))
371  smooth_factor = 0.5
372  endif
373 
374  // average over analyser angles
375  wave dist = ad_profile_y(strip, -inf, inf, "")
376 
377  // smooth distribution function
378  duplicate /free dist, dist_smoo
379  duplicate /free theta, theta_int
380  theta_int = theta - theta_offset
381  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
382  variable nx = dimsize(strip, 0)
383  variable ix
384 
385  switch(smooth_method)
386  case 1:
387  Smooth /B /E=3 smooth_factor, dist_smoo
388  break
389  case 2:
390  Smooth /E=3 smooth_factor, dist_smoo
391  break
392  case 4:
393  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={theta_int}
394  break
395  case 3:
396  for (ix = 0; ix < nx; ix += 1)
397  dist = strip[ix][p]
398  if (smooth_factor > 1)
399  CurveFit /nthr=0 /q /w=2 poly smooth_factor+1, dist /x=theta_int /d=dist_smoo
400  else
401  CurveFit /nthr=0 /q /w=2 line, dist /x=theta_int /d=dist_smoo
402  endif
403  strip[ix,ix][] /= dist_smoo[q]
404  endfor
405  dist_smoo = 1
406  break
407  endswitch
408 
409  // divide
410  if (check != 2)
411  strip /= dist_smoo[q]
412  endif
413 
414  // check
415  if (check)
416  duplicate /o dist, check_dist
417  duplicate /o dist_smoo, check_smoo
418  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
419  endif
420 };
421 
451 variable normalize_strip_thetaphi(wave strip, wave theta, wave phi, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
452  wave strip
453  wave theta
454  wave phi
455  variable theta_offset
456  variable smooth_method
457  variable smooth_factor
458  variable check
459 
460  if (ParamIsDefault(check))
461  check = 0
462  endif
463  if (ParamIsDefault(theta_offset))
464  theta_offset = 0
465  endif
466  if (ParamIsDefault(smooth_method))
467  smooth_method = 4
468  endif
469  if (ParamIsDefault(smooth_factor))
470  smooth_factor = 0.5
471  endif
472 
473  // average over analyser angles
474  wave dist = ad_profile_y(strip, -inf, inf, "")
475 
476  // smooth distribution function
477  duplicate /free dist, dist_smoo
478  duplicate /free theta, theta_int
479  theta_int = theta - theta_offset
480  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
481  variable nx = dimsize(strip, 0)
482  variable ix
483 
484  switch(smooth_method)
485  case 4:
486  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={theta_int, phi}
487  break
488  default:
489  abort "smooth method not supported"
490  endswitch
491 
492  // divide
493  if (check != 2)
494  strip /= dist_smoo[q]
495  endif
496 
497  // check
498  if (check)
499  duplicate /o dist, check_dist
500  duplicate /o dist_smoo, check_smoo
501  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
502  endif
503 };
504 
518 variable normalize_strip_2d(wave strip, wave theta, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
519  wave strip
520  wave theta
521  variable theta_offset
522  variable smooth_method
523  variable smooth_factor
524  variable check
525 
526  if (ParamIsDefault(check))
527  check = 0
528  endif
529  if (ParamIsDefault(theta_offset))
530  theta_offset = 0
531  endif
532  if (ParamIsDefault(smooth_method))
533  smooth_method = 4
534  endif
535  if (ParamIsDefault(smooth_factor))
536  smooth_factor = 0.5
537  endif
538 
539  variable nx = dimsize(strip, 0)
540  variable ny = dimsize(strip, 1)
541 
542  duplicate /free strip, dist, alpha_int, theta_int
543  theta_int = theta[q] - theta_offset
544  alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
545  redimension /n=(nx * ny) dist, alpha_int, theta_int
546 
547  switch(smooth_method)
548  case 4:
549  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int}
550  redimension /n=(nx, ny) dist_smoo
551  break
552  default:
553  Abort "undefined smooth method"
554  break
555  endswitch
556 
557  // divide
558  if (check != 2)
559  strip /= dist_smoo
560  endif
561 
562  // check
563  if (check)
564  //duplicate /o dist, check_dist
565  duplicate /o dist_smoo, check_smoo
566  endif
567 };
568 
578 variable crop_strip(wave strip, variable xlo, variable xhi){
579  wave strip
580  variable xlo
581  variable xhi
582 
583  variable plo = round((xlo - dimoffset(strip, 0)) / dimdelta(strip, 0))
584  variable phi = round((xhi - dimoffset(strip, 0)) / dimdelta(strip, 0))
585  xlo = plo * dimdelta(strip, 0) + dimoffset(strip, 0)
586  xhi = phi * dimdelta(strip, 0) + dimoffset(strip, 0)
587  variable nx = phi - plo + 1
588  variable ny = dimsize(strip, 1)
589 
590  duplicate /free strip, strip_copy
591  redimension /n=(nx,ny) strip
592  strip = strip_copy[p + plo][q]
593  setscale /i x xlo, xhi, waveunits(strip, 0), strip
594 };
595 
638 variable pizza_service(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar = defaultValue, variable nograph = defaultValue, variable folding = defaultValue, variable xpdplot = defaultValue){
639  wave data
640  string nickname
641  variable theta_offset
642  variable tilt_offset
643  variable phi_offset
644  variable npolar
645  variable nograph
646  variable folding
647  variable xpdplot
648 
649  if (ParamIsDefault(npolar))
650  npolar = 91
651  endif
652  if (ParamIsDefault(nograph))
653  nograph = 0
654  endif
655  if (ParamIsDefault(folding))
656  folding = 1
657  endif
658  if (ParamIsDefault(xpdplot))
659  xpdplot = 0
660  endif
661 
662  // sort out data folder structure
663  dfref saveDF = GetDataFolderDFR()
664  dfref dataDF = GetWavesDataFolderDFR(data)
665  setdatafolder dataDF
666  if (DataFolderExists(":attr"))
667  setdatafolder :attr
668  endif
669  dfref attrDF = GetDataFolderDFR()
670 
671  wave /sdfr=attrDF ManipulatorTheta
672  wave /sdfr=attrDF ManipulatorTilt
673  wave /sdfr=attrDF ManipulatorPhi
674 
675  if ((dimsize(ManipulatorTheta, 0) != dimsize(data, 1)) || (dimsize(ManipulatorTilt, 0) != dimsize(data, 1)) || (dimsize(ManipulatorPhi, 0) != dimsize(data, 1)))
676  Abort "Warning: The dimension size of the manipulator waves does not match the Y dimension of the data wave!\rIf you restructured the data wave, please use pizza_service_2 with properly scaled manipulator waves."
677  endif
678 
679  duplicate /free ManipulatorTheta, m_theta
680  duplicate /free ManipulatorTilt, m_tilt
681  duplicate /free ManipulatorPhi, m_phi
682 
683  m_theta -= theta_offset
684  m_tilt -= tilt_offset
685  m_phi -= phi_offset
686 
687  pizza_service_2(data, nickname, m_theta, m_tilt, m_phi, npolar=npolar, nograph=nograph, folding=folding, xpdplot=xpdplot)
688 
689  setdatafolder saveDF
690 };
691 
731 variable pizza_service_2(wave data, string nickname, wave m_theta, wave m_tilt, wave m_phi, variable npolar = defaultValue, variable nograph = defaultValue, variable folding = defaultValue, variable xpdplot = defaultValue){
732  wave data
733  string nickname
734  wave m_theta
735  wave m_tilt
736  wave m_phi
737  variable npolar
738  variable nograph
739  variable folding
740  variable xpdplot
741 
742  if (ParamIsDefault(npolar))
743  npolar = 91
744  endif
745  if (ParamIsDefault(nograph))
746  nograph = 0
747  endif
748  if (ParamIsDefault(folding))
749  folding = 1
750  endif
751  if (ParamIsDefault(xpdplot))
752  xpdplot = 0
753  endif
754 
755  if ((dimsize(m_theta, 0) != dimsize(data, 1)) || (dimsize(m_tilt, 0) != dimsize(data, 1)) || (dimsize(m_phi, 0) != dimsize(data, 1)))
756  Abort "Warning: The dimension size of the manipulator waves does not match the Y dimension of the data wave!"
757  endif
758 
759  string graphname = "graph_" + nickname
760  string outprefix = nickname
761 
762  // sort out data folder structure
763  dfref saveDF = GetDataFolderDFR()
764  dfref dataDF = GetWavesDataFolderDFR(data)
765  setdatafolder dataDF
766 
767  if (xpdplot)
768  setdatafolder root:
769  outprefix = nickname
770  else
771  setdatafolder dataDF
772  newdatafolder /s/o $nickname
773  outprefix = ""
774  endif
775  dfref destDF = GetDataFolderDFR()
776 
777  // performance monitoring
778  variable timerRefNum
779  variable /g pol_perf_secs
780  timerRefNum = startMSTimer
781 
782  duplicate /free m_tilt, corr_tilt
783  duplicate /free m_phi, corr_phi
784  corr_tilt = -m_tilt// checked 140702
785  corr_phi = m_phi// checked 140702
786 
787  make /n=1/d/free d_polar, d_azi
788 
789  convert_angles_ttpd2polar(m_theta, corr_tilt, corr_phi, data, d_polar, d_azi)
790  d_azi += 180// changed 151030 (v1.6)
791  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
792  variable ifold
793  for (ifold = 0; ifold < folding; ifold += 1)
794  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
795  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
796  d_azi += 360 / folding
797  endfor
798 
799  // normalize folding
800  if (strlen(outprefix))
801  string s_prefix = outprefix + "_"
802  string s_int = s_prefix + "i"
803  else
804  s_prefix = ""
805  s_int = "values"
806  endif
807  if (folding > 1)
808  wave values = $s_int
809  values /= folding
810  endif
811 
812  if (!nograph)
813  display_hemi_scan(outprefix, graphname = graphname)
814  endif
815 
816  if (timerRefNum >= 0)
817  pol_perf_secs = stopMSTimer(timerRefNum) / 1e6
818  endif
819 
820  setdatafolder saveDF
821 };
822 
848 variable show_analyser_line(variable theta, variable tilt, variable phi, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar = defaultValue, variable nograph = defaultValue, variable xpdplot = defaultValue){
849  variable theta
850  variable tilt
851  variable phi
852  variable theta_offset
853  variable tilt_offset
854  variable phi_offset
855  variable npolar
856  variable nograph
857  variable xpdplot
858 
859  string nickname = "analyser"
860 
861  if (ParamIsDefault(npolar))
862  npolar = 91
863  endif
864  if (ParamIsDefault(nograph))
865  nograph = 0
866  endif
867  if (ParamIsDefault(xpdplot))
868  xpdplot = 0
869  endif
870  string graphname = "graph_" + nickname
871  string outprefix = nickname
872 
873  // sort out data folder structure
874  dfref saveDF = GetDataFolderDFR()
875  dfref dataDF = saveDF
876  if (xpdplot)
877  setdatafolder root:
878  outprefix = nickname
879  else
880  setdatafolder dataDF
881  newdatafolder /s/o $nickname
882  outprefix = ""
883  endif
884  dfref destDF = GetDataFolderDFR()
885 
886  make /n=1 /free m_theta
887  make /n=1 /free m_tilt
888  make /n=1 /free m_phi
889  m_theta = theta - theta_offset
890  m_tilt = tilt - tilt_offset
891  m_tilt *= -1// checked 140702
892  m_phi = phi - phi_offset
893  //m_phi *= -1 // checked 140702
894 
895  make /n=60 /free data
896  setscale /i x -30, 30, data
897  data = x
898  make /n=1/d/free d_polar, d_azi
899 
900  convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
901  d_azi += 180// changed 151030 (v1.6)
902  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
903  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
904  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
905 
906  if (!nograph)
907  display_hemi_scan(outprefix, graphname = graphname)
908  endif
909 
910  setdatafolder saveDF
911 };
912 
917 
918 variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi){
919  wave theta, tilt, phi// see convert_angles_ttpa2polar
920  wave data// in, 1D or 2D
921  // X-scale must be set to analyser angle scale
922  wave polar, azi// see convert_angles_ttpa2polar
923 
924  make /n=(dimsize(data, 0)) /d /free ana
925  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), ana
926  ana = x
927  convert_angles_ttpa2polar(theta, tilt, phi, ana, polar, azi)
928 };
929 
957 variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi){
958  wave theta
959  wave tilt
960  wave phi
961  wave analyser
962  wave polar, azi
963 
964  variable nn = numpnts(theta)
965  variable na = numpnts(analyser)
966  redimension /n=(na, nn) polar, azi
967 
968  variable radius = 1// don't need to specify - everything is scalable
969 
970  // step 1: calculate cartesian detection vectors at normal emission
971  // this is simply a polar-cartesian mapping, independent of the manipulator
972  // phi=0 is in the polar rotation plane
973  make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar
974  w_orig_polar[0][] = radius
975  w_orig_polar[1][] = analyser[q]
976  w_orig_polar[2][] = 0
977  polar2cart_wave(w_orig_polar, w_orig_cart)
978  // if the angle-dispersive axis was horizontal, we'd need to rotate the detector
979  //rotate_z_wave(w_orig_cart, 90)
980 
981  variable ii
982  for (ii = 0; ii < nn; ii += 1)
983  // step 2: rotate the detection vectors according to the manipulator angles
984  // the order of rotations is important because we rotate about fixed axes
985  // y-axis = tilt rotation axis
986  // x-axis = polar rotation axis
987  // z-axis = normal emission = azimuthal rotation axis
988  w_rot_cart = w_orig_cart
989  rotate_y_wave(w_rot_cart, -tilt[ii])
990  rotate_x_wave(w_rot_cart, -theta[ii])
991  rotate_z_wave(w_rot_cart, -phi[ii] - 90)
992  // map the vectors back to the sample coordinate system
993  cart2polar_wave(w_rot_cart, w_rot_polar)
994  // copy to output
995  polar[][ii] = w_rot_polar[1][p]
996  azi[][ii] = w_rot_polar[2][p]
997  endfor
998 };
999 
1000 static variable line_average(wave source, wave dest){
1001  // is this function used?
1002  wave source
1003  wave dest
1004 
1005  variable ii
1006  variable nn = dimsize(source, 1)
1007  make /n=(dimsize(source, 0))/d/free line
1008  for (ii = 0; ii < nn; ii += 1)
1009  line = source[p][ii]
1010  wavestats /q line
1011  dest[][ii] = line[p] / v_max
1012  endfor
1013 };
1014 
1018 static variable calc_nth(variable Theta_st, variable Theta_in, variable th, variable Phi_ran, variable Phi_ref, string Holomode){
1019  Variable Theta_st, Theta_in, th, Phi_ran, Phi_ref
1020  String Holomode
1021  Variable The_step
1022  Variable deg2rad=0.01745329
1023 
1024  if ( cmpstr(Holomode, "Stereographic") == 0)
1025  The_step =trunc( Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st )
1026  if(th==90)
1027  The_step =trunc( Phi_ran*sin(th*pi/180)*Phi_ref/Theta_st )
1028  endif
1029  else
1030  if (cmpstr(Holomode, "Parallel") == 0)
1031  The_step=trunc( Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st )
1032  else
1033  if ( cmpstr(Holomode, "h") == 0)
1034  The_step=trunc( th/Theta_in*Phi_ran/Theta_st )
1035  else
1036  //altro
1037  endif
1038  endif
1039  endif
1040 
1041  return(The_step)
1042 };
1043 
1047 static variable calc_phi_step(variable Theta_in, variable th, variable Theta_st, variable Phi_ran, variable Phi_ref, string Holomode){
1048  Variable Theta_in, th, Theta_st, Phi_ran, Phi_ref
1049  String Holomode
1050 
1051  Variable Phi_st
1052  Variable deg2rad=0.01745329
1053 
1054  if ( cmpstr(Holomode, "Stereographic") == 0 )
1055  if ((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
1056  Phi_st=0.0
1057  else
1058  Phi_st=Phi_ran/(trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st))
1059  endif
1060  if(th==90)
1061  Phi_st=2.0
1062  endif
1063  endif
1064 
1065  if ( cmpstr(Holomode, "Parallel") == 0 )
1066  if((th < 0.5) || (trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st) == 0))
1067  Phi_st=0.0
1068  else
1069  Phi_st=Phi_ran/(trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st))
1070  endif
1071  endif
1072 
1073  if ( cmpstr(Holomode, "h") == 0 )
1074  if((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
1075  Phi_st=0.0
1076  else
1077  Phi_st=Phi_ran/trunc(th/Theta_in*Phi_ran/Theta_st)
1078  endif
1079  endif
1080 
1081  if (Phi_st==0)
1082  Phi_st=360
1083  endif
1084 
1085  return(Phi_st)
1086 };
1087 
1091 static variable Calc_The_step(variable th, variable Theta_st, string Holomode){
1092  String Holomode
1093  Variable th, Theta_st
1094 
1095  Variable deg2rad=0.01745329, dt_loc,The_step
1096 
1097  if ( (cmpstr(Holomode, "Stereographic")) ==0 )
1098  The_step=Theta_st
1099  endif
1100 
1101  if ( (cmpstr(Holomode, "h")) ==0 )
1102  The_step=Theta_st
1103  endif
1104 
1105  if ( cmpstr(Holomode, "Parallel") == 0 )
1106  if(th < 89.5)
1107  dt_loc = Theta_st/cos(th*deg2rad)
1108  if(dt_loc > 10)
1109  dt_loc=10
1110  endif
1111  The_step=dt_loc
1112  else
1113  The_step=10
1114  endif
1115  endif
1116  return(The_step)
1117 };
1118 
1122 static variable CalcN_Theta(string HoloMode, variable Theta_in, variable Theta_ran, variable Theta_st){
1123  String HoloMode
1124  Variable Theta_in,Theta_ran,Theta_st
1125  Variable n_theta, aux, aux1,ii
1126 
1127  aux = Theta_in
1128  aux1= Theta_in - Theta_ran
1129  ii = 0
1130  do
1131  aux = aux - Calc_The_step(aux, Theta_st, HoloMode)
1132  if(aux<=Theta_in-Theta_ran)
1133  aux=Theta_in-Theta_ran
1134  endif
1135  ii = ii+1
1136  while((aux>aux1)%&(Theta_in-aux<=Theta_ran))//
1137  n_theta=ii+1
1138  Return(n_theta)
1139 };
1140 
1160 variable make_hemi_grid(variable npol, string nickname, variable xpdplot = defaultValue){
1161  variable npol
1162  string nickname
1163  variable xpdplot
1164 
1165  if (ParamIsDefault(xpdplot))
1166  xpdplot = 0
1167  endif
1168 
1169  string HoloMode = "h"
1170  variable Theta_in = 90
1171  variable Theta_ran = 90
1172  variable Theta_st = 90 / (npol - 1)
1173  variable Phi_ran = 360
1174  variable Phi_ref = 1
1175  variable Phi_in = 0
1176 
1177  variable n_theta = CalcN_Theta(HoloMode, Theta_in, Theta_ran, Theta_st)
1178 
1179  // wave names
1180  if (strlen(nickname))
1181  string s_prefix = nickname + "_"
1182  string s_int = s_prefix + "i"// Intensity wave (counts/sec)
1183  else
1184  s_prefix = ""
1185  s_int = "values"// "i" is not a valid wave name
1186  endif
1187  string s_polar = s_prefix + "pol"// thetas for each int-point of the holo
1188  string s_azim = s_prefix + "az"// phis for each int-point of the holo
1189 
1190  string s_index = s_prefix + "index"// starting index for each theta
1191  string s_theta = s_prefix + "th"// theta values
1192  string s_dphi = s_prefix + "dphi"// delta phis at each theta
1193  string s_nphis = s_prefix + "nphis"// number of phis at each theta
1194 
1195  string s_HoloData = s_prefix + "data"// All holo exp.- parameter information
1196  string s_HoloInfo = s_prefix + "info"
1197 
1198  // the following two waves are used by the pearl-anglescan procedures but not by XPDplot
1199  string s_tot = s_prefix + "tot"// accumulated counts at each point
1200  string s_weight = s_prefix + "wt"// total accumulation time at each point (arb. units)
1201 
1202  make /O/D/n=(n_theta) $s_index /wave=index
1203  make /O/D/n=(n_theta) $s_theta /wave=theta
1204  make /O/D/n=(n_theta) $s_dphi /wave=dphi
1205  make /O/D/n=(n_theta) $s_nphis /wave=nphis
1206 
1207  //---------- calculate phi-step-size for this theta:
1208  variable aux = Calc_The_step(Theta_in, Theta_st, HoloMode)
1209  dphi[0] = calc_phi_step(Theta_in, Theta_in, aux, Phi_ran, Phi_ref, HoloMode)
1210  Theta[0] = Theta_in
1211  nphis[0] = calc_nth(aux, Theta_in, Theta_in, Phi_ran, Phi_ref, HoloMode)
1212  Index[0] = nphis[0]
1213 
1214  //---------- calculate number of phis, phi-step, and starting-index for each theta:
1215  variable ii = 1
1216  do
1217  Theta[ii] = Theta[ii-1] - aux
1218  if(Theta[ii] <= Theta_in-Theta_ran)
1219  Theta[ii] = Theta_in-Theta_ran
1220  endif
1221  aux = Calc_The_step(Theta[ii], Theta_st, HoloMode)
1222  dphi[ii] = calc_phi_step(Theta_in, Theta[ii], aux, Phi_ran, Phi_ref, HoloMode)
1223  nphis[ii] = calc_nth(aux, Theta_in, Theta[ii], Phi_ran, Phi_ref, HoloMode)
1224  Index[ii] = Index[ii-1] + nphis[ii]
1225  ii=ii+1
1226  while(ii < n_theta)
1227 
1228  if (Index[n_theta-1]==Index[n_theta-2])
1229  Index[n_theta-1]=Index[n_theta-2]+1
1230  nphis[n_theta-1]=1
1231  endif
1232 
1233  variable NumPoints = sum(nphis, 0, numpnts(nphis))
1234 
1235  //---------- calculate theta and phi for each data point:
1236  make /O/D/N=(NumPoints) $s_polar /wave=polar, $s_azim /wave=azim
1237  note azim, "version=1.6"
1238 
1239  ii = 0
1240  variable StartIndex = 0
1241  variable EndIndex
1242  do
1243  EndIndex=Index[ii]
1244  Polar[StartIndex, EndIndex-1]=Theta[ii]
1245  Azim[StartIndex, EndIndex-1]= mod(Phi_ran+(x-StartIndex)*dphi[ii]+Phi_in,Phi_ran)
1246  ii = ii + 1
1247  StartIndex = EndIndex
1248  while(ii < n_theta)
1249 
1250  duplicate /o azim, $s_int /wave=values
1251  duplicate /o azim, $s_tot /wave=totals
1252  duplicate /o azim, $s_weight /wave=weights
1253  values = nan
1254  totals = 0
1255  weights = 0
1256 
1257  // XPDplot metadata
1258  if (xpdplot)
1259  string s_FileName = ""
1260  string s_Comment = "created by pearl-anglescan-process.ipf"
1261  string s_HoloMode = "Stereographic"
1262  variable /g gb_SpectraFile = 0
1263 
1264  Make/O/D/n=22 $s_HoloData /wave=HoloData
1265  HoloData[0] = NaN// v_StartKE
1266  HoloData[1] = NaN// v_StoppKE
1267  HoloData[6] = NumPoints
1268  HoloData[7] = Theta_in
1269  HoloData[8] = Theta_ran
1270  HoloData[9] = Theta_st
1271  HoloData[11] = Phi_in
1272  HoloData[12] = Phi_ran
1273  HoloData[13] = Theta_st
1274  HoloData[15] = Phi_ref
1275  HoloData[16] = Phi_ran
1276  HoloData[17] = 0// v_HoloBit (stereographic)
1277 
1278  Make/O/T/n=22 $s_HoloInfo /wave=HoloInfo
1279  HoloInfo[0] = s_FileName
1280  HoloInfo[1] = s_Comment
1281  HoloInfo[10] = s_HoloMode
1282  HoloInfo[11] = ""// s_MeasuringMode
1283 
1284  // notebook for XPDplot
1285  if (WinType(NickName) == 5)
1286  Notebook $NickName selection={startOfFile, endOfFile}
1287  Notebook $NickName text=""
1288  else
1289  NewNotebook /F=0 /K=1 /N=$NickName /W=(5,40,341,260)
1290  Notebook $NickName defaultTab=140
1291  Notebook $NickName statusWidth=300
1292  Notebook $NickName backRGB=(56797,56797,56797)
1293  Notebook $NickName pageMargins={80,80,80,80}
1294  Notebook $NickName fSize=10
1295  Notebook $NickName fStyle=0,textRGB=(65535,0,26214)
1296  Notebook $NickName textRGB=(65535,0,26214)
1297  endif
1298  Notebook $NickName text = "File:\t" + s_FileName + "\r"
1299  Notebook $NickName text = "*** " + s_Comment + " ***\r\r"
1300  Notebook $NickName text = "Angle-Mode:\t" + s_HoloMode + "\r"
1301  Notebook $NickName text = "XPDplot Nickname:\t" + NickName + "\r"
1302  endif
1303 };
1304 
1311 string get_hemi_nickname(wave w){
1312  wave w
1313 
1314  string prefix = get_hemi_prefix(w)
1315  string wname = nameofwave(w)
1316  string nickname
1317 
1318  if (strlen(prefix))
1319  nickname = prefix
1320  else
1321  string s_wave_df = GetWavesDataFolder(w, 1)
1322  dfref parent_df = $(s_wave_df + "::")
1323  nickname = GetDataFolder(0, parent_df)
1324  endif
1325 
1326  return nickname
1327 };
1328 
1336 string get_hemi_prefix(wave w){
1337  wave w
1338 
1339  string wname = nameofwave(w)
1340  string prefix
1341  if (ItemsInList(wname, "_") >= 2)
1342  prefix = StringFromList(0, wname, "_")
1343  else
1344  prefix = ""
1345  endif
1346 
1347  return prefix
1348 };
1349 
1367 dfr find_hemi_data(string nickname, string* prefix, string* intwave){
1368  string nickname
1369  string &prefix
1370  string &intwave
1371 
1372  dfref datadf
1373  prefix = ""
1374  intwave = "values"
1375  if (strlen(nickname))
1376  if (DataFolderExists(nickname))
1377  datadf = $nickname
1378  else
1379  datadf = getdatafolderdfr()
1380  prefix = nickname + "_"
1381  intwave = prefix + "i"
1382  if (exists(intwave) != 1)
1383  datadf = root:
1384  endif
1385  endif
1386  else
1387  datadf = getdatafolderdfr()
1388  prefix = ""
1389  intwave = "values"
1390  endif
1391  return datadf
1392 };
1393 
1401 variable clear_hemi_grid(string nickname){
1402  string nickname
1403 
1404  dfref datadf
1405  string s_prefix
1406  string s_int
1407  datadf = find_hemi_data(nickname, s_prefix, s_int)
1408 
1409  string s_totals = s_prefix + "tot"
1410  string s_weights = s_prefix + "wt"
1411 
1412  wave /sdfr=datadf /z w_values = $s_int
1413  wave /sdfr=datadf /z w_totals = $s_totals
1414  wave /sdfr=datadf /z w_weights = $s_weights
1415 
1416  if (waveexists(w_totals))
1417  w_totals = 0
1418  endif
1419  if (waveexists(w_weights))
1420  w_weights = 0
1421  endif
1422  if (waveexists(w_values))
1423  w_values = nan
1424  endif
1425 };
1426 
1448 variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot = defaultValue){
1449  string source_nickname
1450  dfref dest_folder
1451  string dest_nickname
1452  variable xpdplot
1453 
1454  if (ParamIsDefault(xpdplot))
1455  xpdplot = 0
1456  endif
1457 
1458  dfref savedf = getdatafolderdfr()
1459 
1460  // source data
1461  string s_prefix = ""
1462  string s_int = "values"
1463  dfref source_df = find_hemi_data(source_nickname, s_prefix, s_int)
1464  string s_polar = s_prefix + "pol"
1465  string s_azim = s_prefix + "az"
1466  string s_theta = s_prefix + "th"
1467  string s_tot = s_prefix + "tot"
1468  string s_weight = s_prefix + "wt"
1469  string s_matrix = s_prefix + "matrix"
1470 
1471  wave /sdfr=source_df theta1 = $s_theta
1472  wave /sdfr=source_df polar1 = $s_polar
1473  wave /sdfr=source_df azim1 = $s_azim
1474  wave /sdfr=source_df tot1 = $s_tot
1475  wave /sdfr=source_df weight1 = $s_weight
1476  wave /sdfr=source_df values1 = $s_int
1477  wave /sdfr=source_df /z matrix1 = $s_matrix
1478 
1479  variable npol = numpnts(theta1)
1480 
1481  setdatafolder dest_folder
1482  make_hemi_grid(npol, dest_nickname, xpdplot=xpdplot)
1483 
1484  // dest data
1485  dfref dest_df = find_hemi_data(dest_nickname, s_prefix, s_int)
1486  s_polar = s_prefix + "pol"
1487  s_azim = s_prefix + "az"
1488  s_theta = s_prefix + "th"
1489  s_tot = s_prefix + "tot"
1490  s_weight = s_prefix + "wt"
1491  s_matrix = s_prefix + "matrix"
1492 
1493  wave /sdfr=dest_df theta2 = $s_theta
1494  wave /sdfr=dest_df polar2 = $s_polar
1495  wave /sdfr=dest_df azim2 = $s_azim
1496  wave /sdfr=dest_df tot2 = $s_tot
1497  wave /sdfr=dest_df weight2 = $s_weight
1498  wave /sdfr=dest_df values2 = $s_int
1499 
1500  tot2 = tot1
1501  weight2 = weight1
1502  values2 = values1
1503  if (waveexists(matrix1))
1504  setdatafolder dest_df
1505  duplicate /o matrix1, $s_matrix
1506  endif
1507 
1508  if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6))
1509  azim2 += 180// changed 151030 (v1.6)
1510  azim2 = azim2 >= 360 ? azim2 - 360 : azim2
1511  endif
1512 
1513  setdatafolder saveDF
1514 };
1515 
1523 variable rotate_hemi_scan(string nickname, variable angle){
1524  string nickname
1525  variable angle
1526 
1527  dfref savedf = getdatafolderdfr()
1528 
1529  string s_prefix = ""
1530  string s_int = "values"
1531  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1532 
1533  string s_polar = s_prefix + "pol"
1534  string s_azim = s_prefix + "az"
1535  string s_tot = s_prefix + "tot"
1536  string s_weight = s_prefix + "wt"
1537 
1538  wave /sdfr=df polar = $s_polar
1539  wave /sdfr=df azim = $s_azim
1540  wave /sdfr=df tot = $s_tot
1541  wave /sdfr=df weight = $s_weight
1542  wave /sdfr=df values = $s_int
1543 
1544  azim += angle
1545  azim = azim < 0 ? azim + 360 : azim
1546  azim = azim >= 360 ? azim - 360 : azim
1547 
1548  duplicate /free polar, neg_polar
1549  neg_polar = -polar
1550  sort {neg_polar, azim}, polar, azim, tot, weight, values
1551 
1552  setdatafolder saveDF
1553 };
1554 
1601 string display_hemi_scan(string nickname, variable projection = defaultValue, variable graphtype = defaultValue, variable do_ticks = defaultValue, variable do_grids = defaultValue, string graphname = defaultValue){
1602  string nickname
1603  variable projection
1604  variable graphtype
1605  variable do_ticks
1606  variable do_grids
1607  string graphname
1608 
1609  dfref savedf = getdatafolderdfr()
1610 
1611  if (ParamIsDefault(projection))
1612  projection = 1
1613  endif
1614  if (ParamIsDefault(graphtype))
1615  graphtype = 1
1616  endif
1617  if (ParamIsDefault(do_ticks))
1618  do_ticks = 3
1619  endif
1620  if (ParamIsDefault(do_grids))
1621  do_grids = 3
1622  endif
1623  if (ParamIsDefault(graphname))
1624  if (strlen(nickname) > 0)
1625  graphname = nickname
1626  else
1627  graphname = GetDataFolder(0)
1628  endif
1629  endif
1630 
1631  // hemi grid waves
1632  string s_prefix = ""
1633  string s_int = "values"
1634  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1635 
1636  string s_polar = s_prefix + "pol"
1637  string s_azim = s_prefix + "az"
1638  string s_matrix = s_prefix + "matrix"
1639 
1640  wave /sdfr=df /z values = $s_int
1641  wave /sdfr=df /z azim = $s_azim
1642  wave /sdfr=df /z polar = $s_polar
1643  wave /sdfr=df /z matrix = $s_matrix
1644 
1645  setdatafolder df
1646  string s_ster_rad = s_prefix + "ster_rad"
1647  duplicate /o polar, $s_ster_rad /wave=ster_rad
1648  ster_rad = calc_graph_radius(polar, projection=projection)
1649 
1650  string s_ster_x = s_prefix + "ster_x"
1651  string s_ster_y = s_prefix + "ster_y"
1652  duplicate /o azim, $s_ster_x /wave=ster_x, $s_ster_y /wave=ster_y
1653  ster_x = ster_rad * cos(azim * pi / 180)
1654  ster_y = ster_rad * sin(azim * pi / 180)
1655 
1656  variable azim_offset = 0
1657  if (!(NumberByKey("version", note(azim), "=", "\r") >= 1.6))
1658  DoAlert /T="display hemi scan" 0, "your dataset doesn't include the version 1.6 flag. if it was created with an earlier version that might be okay. please check that the orientation is correct!"
1659  azim_offset = 180// changed 151030 (v1.6)
1660  endif
1661 
1662  string s_trace
1663  switch(graphtype)
1664  case 1:
1665  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1666 
1667  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1668  ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2
1669  ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0}
1670 
1671  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 trace=polarY0
1672  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1673  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1674 
1675  SetWindow $graphname, userdata(projection)=num2str(projection)
1676  draw_hemi_axes(graphname, do_grids=do_grids)
1677  break
1678  case 3:
1679  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1680 
1681  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1682  ModifyGraph /W=$graphname mode($s_trace)=0, lsize($s_trace)=0
1683  AppendImage /L=VertCrossing /B=HorizCrossing matrix
1684 
1685  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 image=$s_matrix
1686  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1687  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1688 
1689  SetWindow $graphname, userdata(projection)=num2str(projection)
1690  draw_hemi_axes(graphname, do_grids=do_grids)
1691  break
1692  endswitch
1693 
1694  setdatafolder savedf
1695  return graphname
1696 };
1697 
1739 static string display_polar_graph(string graphname, variable angle_offset = defaultValue, variable do_ticks = defaultValue){
1740 
1741  string graphname
1742  variable angle_offset
1743  variable do_ticks
1744 
1745  dfref savedf = GetDataFolderDFR()
1746 
1747  if (ParamIsDefault(angle_offset))
1748  angle_offset = 0
1749  endif
1750  if (ParamIsDefault(do_ticks))
1751  do_ticks = 3
1752  endif
1753 
1754  if ((strlen(graphname) == 0) || (wintype(graphname) == 0))
1755  Display /k=1 /W=(10,45,360,345)
1756  DoWindow /C $graphname
1757  graphname = WMNewPolarGraph("", graphname)
1758  WMPolarGraphSetVar(graphname, "zeroAngleWhere", angle_offset)
1759 
1760  WMPolarGraphSetVar(graphname, "angleAxisThick", 0.5)
1761  WMPolarGraphSetStr(graphname, "doMajorAngleTicks", "manual")
1762  WMPolarGraphSetVar(graphname, "majorAngleInc", 30)// major ticks in 30 deg steps
1763  WMPolarGraphSetVar(graphname, "minorAngleTicks", 2)// minor ticks in 10 deg steps
1764  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1765  WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
1766  WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
1767  WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
1768  WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g")
1769 
1770  WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
1771  WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
1772  WMPolarGraphSetStr(graphname, "radiusAxesWhere", " Off")// note the leading spaces, cf. WMPolarAnglesForRadiusAxes
1773  WMPolarGraphSetStr(graphname, "radiusTicksLocation", "Off")
1774 
1775  WMPolarGraphSetVar(graphname, "majorTickLength", 2)
1776  WMPolarGraphSetVar(graphname, "majorTickThick", 0.5)
1777  WMPolarGraphSetVar(graphname, "minorTickLength", 1)
1778  WMPolarGraphSetVar(graphname, "minorTickThick", 0.5)
1779  WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0)
1780  WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7)
1781 
1782  // changes
1783  if (do_ticks & 1)
1784  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1785  else
1786  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Off")
1787  endif
1788  if (do_ticks & 2)
1789  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 1)
1790  else
1791  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 0)
1792  endif
1793 
1794  DoWindow /T $graphname, graphname
1795 
1796  // cursor info in angles
1797  string graphdf = "root:packages:WMPolarGraphs:" + graphname
1798  setdatafolder graphdf
1799  // current theta, phi coordinates are stored in global variables in the package folder of the graph
1800  variable /g csrA_theta
1801  variable /g csrA_phi
1802  variable /g csrB_theta
1803  variable /g csrB_phi
1804  // the text box is hidden initially. it shows up and hides with the cursor info box.
1805  string tb
1806  tb = "\\{"
1807  tb = tb + "\"A = (%.1f, %.1f)\","
1808  tb = tb + graphdf + ":csrA_theta,"
1809  tb = tb + graphdf + ":csrA_phi"
1810  tb = tb + "}"
1811  TextBox /W=$graphname /A=LT /B=1 /E=2 /F=0 /N=tb_angles /X=1 /Y=1 /V=0 tb
1812  tb = "\\{"
1813  tb = tb + "\"B = (%.1f, %.1f)\","
1814  tb = tb + graphdf + ":csrB_theta,"
1815  tb = tb + graphdf + ":csrB_phi"
1816  tb = tb + "}"
1817  AppendText /W=$graphname /N=tb_angles tb
1818  // updates are triggered by a window hook
1819  SetWindow $graphname, hook(polar_graph_hook)=PearlAnglescanProcess#polar_graph_hook
1820  else
1821  // graph window exists
1822  DoWindow /F $graphname
1823  endif
1824 
1825  setdatafolder savedf
1826  return graphname
1827 };
1828 
1854 static string draw_hemi_axes(string graphname, variable do_grids = defaultValue){
1855  string graphname
1856  variable do_grids
1857 
1858  if (ParamIsDefault(do_grids))
1859  do_grids = 3
1860  endif
1861 
1862  dfref savedf = GetDataFolderDFR()
1863 
1864  string sproj = GetUserData(graphname, "", "projection")
1865  variable projection = str2num("0" + sproj)
1866 
1867  SetDrawLayer /W=$graphname ProgFront
1868 
1869  // polar axis
1870  SetDrawEnv /W=$graphname xcoord=HorizCrossing, ycoord=VertCrossing
1871  SetDrawEnv /W=$graphname linethick= 0.5
1872  SetDrawEnv /W=$graphname dash=2
1873  SetDrawEnv /W=$graphname fillpat=0
1874  SetDrawEnv /W=$graphname fname="default", fsize=7
1875  SetDrawEnv /W=$graphname textxjust=1, textyjust=1
1876  //SetDrawEnv /W=$graphname linefgc=(65535,65535,65535)
1877  SetDrawEnv /W=$graphname save
1878 
1879  if (do_grids & 1)
1880  DrawLine /W=$graphname 0, -2, 0, 2
1881  DrawLine /W=$graphname -2, 0, 2, 0
1882  endif
1883 
1884  variable radi
1885  if (do_grids & 2)
1886  radi = calc_graph_radius(0.5, projection=projection)
1887  DrawOval /W=$graphname -radi, radi, radi, -radi
1888  radi = calc_graph_radius(30, projection=projection)
1889  DrawOval /W=$graphname -radi, radi, radi, -radi
1890  radi = calc_graph_radius(60, projection=projection)
1891  DrawOval /W=$graphname -radi, radi, radi, -radi
1892 
1893  SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
1894  SetDrawEnv /W=$graphname save
1895  radi = calc_graph_radius(30, projection=projection)
1896  DrawText /W=$graphname radi, -0.1, "30"
1897  radi = calc_graph_radius(60, projection=projection)
1898  DrawText /W=$graphname radi, -0.1, "60"
1899  endif
1900 
1901  setdatafolder savedf
1902 };
1903 
1926 variable draw_diffraction_cone(string graphname, string groupname, variable theta_axis, variable theta_inner, variable phi){
1927  string graphname
1928  string groupname
1929 
1930  variable theta_axis
1931  variable theta_inner
1932  variable phi
1933 
1934  variable r_axis = calc_graph_radius(theta_axis)
1935  variable r_inner = calc_graph_radius(theta_inner)
1936  variable r_outer = calc_graph_radius(2 * theta_axis - theta_inner)
1937 
1938  SetDrawEnv push
1939  SetDrawLayer UserFront
1940  DrawAction getgroup=$groupname, delete
1941  SetDrawEnv gstart, gname=$groupname
1942  variable xc, yc, xr, yr
1943 
1944  // cone periphery
1945  variable r_center = (r_outer + r_inner) / 2
1946  variable r_radius = (r_outer - r_inner) / 2
1947  xc = r_center * cos(phi * pi / 180)
1948  yc = r_center * sin(phi * pi / 180)
1949  xr = r_radius
1950  yr = r_radius
1951  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1952  SetDrawEnv dash=11, fillpat=0
1953  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1954 
1955  // cone axis
1956  xc = r_axis * cos(phi * pi / 180)
1957  yc = r_axis * sin(phi * pi / 180)
1958  r_radius = calc_graph_radius(2)
1959  xr = r_radius
1960  yr = r_radius
1961  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1962  SetDrawEnv fillfgc=(0,0,0)
1963  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1964 
1965  SetDrawEnv gstop
1966  SetDrawEnv pop
1967 };
1968 
1990 string display_scanlines(string nickname, variable alpha_lo, variable alpha_hi, wave m_theta, wave m_tilt, wave m_phi, variable folding = defaultValue, variable projection = defaultValue){
1991  string nickname
1992  variable alpha_lo
1993  variable alpha_hi
1994  wave m_theta
1995  wave m_tilt
1996  wave m_phi
1997  variable folding
1998  variable projection
1999 
2000  if (ParamIsDefault(folding))
2001  folding = 1
2002  endif
2003  if (ParamIsDefault(projection))
2004  projection = 1
2005  endif
2006 
2007  // sort out data folder structure
2008  dfref saveDF = GetDataFolderDFR()
2009  newdatafolder /s/o $nickname
2010  string graphname = "graph_" + nickname
2011 
2012  duplicate /free m_tilt, loc_m_tilt
2013  loc_m_tilt = -m_tilt
2014 
2015  make /n=1 /d /free d_polar, d_azi
2016  variable n_alpha = round(alpha_hi - alpha_lo) + 1
2017  make /n=(n_alpha) /d /free analyser
2018  setscale /i x alpha_lo, alpha_hi, "", analyser
2019  analyser = x
2020 
2021  convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
2022  duplicate /free d_polar, d_radius
2023  d_radius = calc_graph_radius(d_polar, projection=projection)
2024  d_azi += 180// changed 151030 (v1.6)
2025 
2026  graphname = display_polar_graph(graphname)
2027  SetWindow $graphname, userdata(projection)=num2str(projection)
2028 
2029  variable ifold
2030  variable iang
2031  variable nang = numpnts(m_theta)
2032  string s_rad
2033  string s_azi
2034  string s_trace
2035  for (ifold = 0; ifold < folding; ifold += 1)
2036  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
2037  for (iang = 0; iang < nang; iang += 1)
2038  sprintf s_rad, "rad_%d_%d", ifold, iang
2039  duplicate /o analyser, $s_rad
2040  wave w_rad = $s_rad
2041  w_rad = d_radius[p][iang]
2042 
2043  sprintf s_azi, "azi_%d_%d", ifold, iang
2044  duplicate /o analyser, $s_azi
2045  wave w_azi = $s_azi
2046  w_azi = d_azi[p][iang]
2047 
2048  if (numtype(sum(w_rad)) == 0)
2049  s_trace = WMPolarAppendTrace(graphname, w_rad, w_azi, 360)
2050  ModifyGraph /w=$graphname mode($s_trace)=0, lsize($s_trace)=0.5
2051  endif
2052  endfor
2053  d_azi += 360 / folding
2054  endfor
2055 
2056  draw_hemi_axes(graphname)
2057 
2058  setdatafolder saveDF
2059  return graphname
2060 };
2061 
2078 const variable kProjDist = 0;
2079 const variable kProjStereo = 1;
2080 const variable kProjArea = 2;
2081 const variable kProjGnom = 3;
2082 const variable kProjOrtho = 4;
2083 
2084 static const variable kProjScaleDist = 2;
2085 static const variable kProjScaleStereo = 2;
2086 static const variable kProjScaleArea = 2;
2087 // scaled so that radius(gnom) = radius(stereo) for polar = 88
2088 static const variable kProjScaleGnom = 0.06744519021;
2089 static const variable kProjScaleOrtho = 2;
2090 
2105 threadsafe variable calc_graph_radius(variable polar, variable projection = defaultValue){
2106  variable polar
2107  variable projection
2108 
2109  if (ParamIsDefault(projection))
2110  projection = 1
2111  endif
2112 
2113  variable radius
2114  switch(projection)
2115  case kProjStereo:// stereographic
2116  radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
2117  break
2118  case kProjArea:// equal area
2119  radius = kProjScaleArea * sin(polar / 2 * pi / 180)
2120  break
2121  case kProjGnom:// gnomonic
2122  radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
2123  break
2124  case kProjOrtho:// orthographic
2125  radius = kProjScaleOrtho * sin(polar * pi / 180)
2126  break
2127  default:// equidistant
2128  radius = kProjScaleDist * polar / 90
2129  endswitch
2130 
2131  return radius
2132 };
2133 
2150 threadsafe variable calc_graph_polar(variable x, variable y, variable projection = defaultValue){
2151  variable x
2152  variable y
2153  variable projection
2154 
2155  if (ParamIsDefault(projection))
2156  projection = 1
2157  endif
2158 
2159  variable radius
2160  variable polar
2161 
2162  radius = sqrt(x^2 + y^2)
2163  switch(projection)
2164  case kProjStereo:// stereographic
2165  polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
2166  break
2167  case kProjArea:// equal area
2168  polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
2169  break
2170  case kProjGnom:// gnomonic
2171  polar = atan(radius / kProjScaleGnom) * 180 / pi
2172  break
2173  case kProjOrtho:// orthographic
2174  polar = asin(radius / kProjScaleOrtho) * 180 / pi
2175  break
2176  default:// equidistant
2177  polar = 90 * radius / kProjScaleDist
2178  endswitch
2179 
2180  return polar
2181 };
2182 
2203 threadsafe variable calc_graph_azi(variable x, variable y, variable projection = defaultValue, variable zeroAngle = defaultValue){
2204  variable x
2205  variable y
2206  variable projection
2207  variable zeroAngle
2208 
2209  if (ParamIsDefault(projection))
2210  projection = 1
2211  endif
2212  if (ParamIsDefault(zeroAngle))
2213  zeroAngle = 0
2214  endif
2215 
2216  variable azi
2217  if (x > 0)
2218  azi = atan(y / x) * 180 / pi
2219  else
2220  azi = atan(y / x) * 180 / pi + 180
2221  endif
2222 
2223  azi += zeroAngle
2224  if (azi < 0)
2225  azi += 360
2226  endif
2227  if (azi >= 360)
2228  azi -= 360
2229  endif
2230  if (numtype(azi) != 0)
2231  azi = 0
2232  endif
2233 
2234  return azi
2235 };
2236 
2248 static variable update_polar_info(string graphname){
2249  string graphname
2250 
2251  dfref savedf = GetDataFolderDFR()
2252 
2253  string graphdf = "root:packages:WMPolarGraphs:" + graphname
2254  setdatafolder graphdf
2255 
2256  nvar csrA_theta
2257  nvar csrA_phi
2258  nvar csrB_theta
2259  nvar csrB_phi
2260 
2261  string sproj = GetUserData(graphname, "", "projection")
2262  variable projection = str2num("0" + sproj)
2263  nvar zeroAngleWhere
2264 
2265  variable x = hcsr(A, graphname)
2266  variable y = vcsr(A, graphname)
2267  csrA_theta = calc_graph_polar(x, y, projection=projection)
2268  csrA_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2269 
2270  x = hcsr(B, graphname)
2271  y = vcsr(B, graphname)
2272  csrB_theta = calc_graph_polar(x, y, projection=projection)
2273  csrB_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2274 
2275  setdatafolder savedf
2276 };
2277 
2283 static variable polar_graph_hook(WMWinHookStruct* s){
2284  STRUCT WMWinHookStruct &s
2285 
2286  Variable hookResult = 0
2287 
2288  switch(s.eventCode)
2289  case 7:// cursor moved
2290  update_polar_info(s.winname)
2291  break
2292  case 20:// show info
2293  TextBox /W=$s.winname /N=tb_angles /C /V=1
2294  break
2295  case 21:// hide info
2296  TextBox /W=$s.winname /N=tb_angles /C /V=0
2297  break
2298  endswitch
2299 
2300  return hookResult// 0 if nothing done, else 1
2301 };
2302 
2303 variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname = defaultValue){
2304  string nickname
2305  string cursorname
2306  variable polar_angle
2307  variable azim_angle
2308  string graphname
2309 
2310  if (ParamIsDefault(graphname))
2311  if (strlen(nickname) > 0)
2312  graphname = nickname
2313  else
2314  graphname = GetDataFolder(0)
2315  endif
2316  endif
2317 
2318  string s_prefix = ""
2319  string s_int = "values"
2320  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2321 
2322  string s_polar = s_prefix + "pol"
2323  string s_azim = s_prefix + "az"
2324  wave /sdfr=df /z azim = $s_azim
2325  wave /sdfr=df /z polar = $s_polar
2326 
2327  FindLevel /P /Q polar, polar_angle
2328  if (v_flag == 0)
2329  variable polar_level = floor(v_levelx)
2330  FindLevel /P /Q /R=[polar_level] azim, azim_angle
2331  if (v_flag == 0)
2332  variable azim_level = round(v_levelx)
2333  string tracename = "polarY0"
2334  Cursor /W=$graphname /P $cursorname $traceName azim_level
2335  endif
2336  endif
2337 };
2338 
2348 variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights = defaultValue){
2349  string nickname// name prefix of holo waves.
2350  // may be empty.
2351  wave values// intensity values
2352  // the wave can be one- or two-dimensional.
2353  // no specific order required, the function sorts the arrays internally
2354  wave polar// polar coordinates. allowed range 0 <= theta <= 90
2355  // dimensions corresponding to value.
2356  wave azi// azimuthal coordinates. allowed range -360 <= phi < +360
2357  // dimensions corresponding to value.
2358  wave weights// total accumulation time of each point of values. default = 1
2359 
2360  if (ParamIsDefault(weights))
2361  duplicate /free values, weights
2362  weights = 1
2363  endif
2364 
2365  // quick check whether hemi grid is existing
2366  string s_prefix = ""
2367  string s_int = "values"
2368  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2369 
2370  string s_polar = s_prefix + "pol"
2371  string s_azim = s_prefix + "az"
2372  string s_theta = s_prefix + "th"
2373 
2374  wave /sdfr=df /z w_values = $s_int
2375  wave /sdfr=df /z w_azim = $s_azim
2376  wave /sdfr=df /z w_polar = $s_polar
2377  wave /sdfr=df /z w_theta = $s_theta
2378  if (!waveexists(w_values) || !waveexists(w_azim) || !waveexists(w_polar))
2379  abort "Missing hemispherical scan grid. Please call make_hemi_grid() first."
2380  endif
2381 
2382  // make internal copies, one-dimensional, ordered in theta
2383  duplicate /free values, values_copy
2384  duplicate /free polar, polar_copy
2385  duplicate /free azi, azi_copy
2386  duplicate /free weights, weights_copy
2387  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2388  redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
2389  sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
2390 
2391  variable pol
2392  variable pol_st = abs(w_theta[1] - w_theta[0])
2393  variable pol1, pol2
2394 
2395  duplicate /free azi_copy, azi_slice
2396  duplicate /free values_copy, values_slice
2397  duplicate /free weights_copy, weights_slice
2398  for (pol = 90; pol >= 0; pol -= pol_st)
2399  pol1 = pol - pol_st / 2
2400  pol2 = pol + pol_st / 2
2401  extract /free /indx polar_copy, sel, (pol1 < polar_copy) && (polar_copy <= pol2)
2402  if (numpnts(sel) > 0)
2403  redimension /n=(numpnts(sel)) azi_slice, values_slice, weights_slice
2404  azi_slice = azi_copy[sel]
2405  values_slice = values_copy[sel]
2406  weights_slice = weights_copy[sel]
2407  hemi_add_aziscan(nickname, values_slice, pol, azi_slice, weights=weights_slice)
2408  endif
2409  endfor
2410 };
2411 
2418 variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights = defaultValue){
2419  string nickname// name prefix of holo waves.
2420  // may be empty.
2421  wave values// intensity values of the azimuthal scan at the positions given in the azi parameter
2422  variable polar// polar angle where to add the azi scan
2423  wave azi// angle positions of the azimuthal scan
2424  // acceptable range: >= -360 and < +360
2425  // no specific order required, the function sorts the array internally
2426  wave weights// total accumulation time of each point of values. default = 1
2427 
2428  if (ParamIsDefault(weights))
2429  duplicate /free values, weights
2430  weights = 1
2431  endif
2432 
2433  // hemi grid waves
2434  string s_prefix = ""
2435  string s_int = "values"
2436  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2437 
2438  string s_totals = s_prefix + "tot"
2439  string s_weights = s_prefix + "wt"
2440  string s_polar = s_prefix + "pol"
2441  string s_azim = s_prefix + "az"
2442  string s_index = s_prefix + "index"
2443  string s_theta = s_prefix + "th"
2444  string s_dphi = s_prefix + "dphi"
2445  string s_nphis = s_prefix + "nphis"
2446 
2447  wave /sdfr=df w_polar = $s_polar
2448  wave /sdfr=df w_azim = $s_azim
2449  wave /sdfr=df w_values = $s_int
2450  wave /sdfr=df w_totals = $s_totals
2451  wave /sdfr=df w_weights = $s_weights
2452  wave /sdfr=df w_index = $s_index
2453  wave /sdfr=df w_theta = $s_theta
2454  wave /sdfr=df w_dphi = $s_dphi
2455  wave /sdfr=df w_nphis = $s_nphis
2456 
2457  // destination slice coordinates
2458  //polar = round(polar)
2459  //variable ipol = 90 - polar
2460  variable ipol = BinarySearch(w_theta, polar)
2461  if (ipol < 0)
2462  abort "assertion failed in hemi_add_aziscan(): polar angle not found in grid."
2463  endif
2464 
2465  variable d1, d2
2466  if (ipol >= 1)
2467  d1 = w_index[ipol - 1]
2468  else
2469  d1 = 0
2470  endif
2471  d2 = w_index[ipol] - 1
2472  variable nd = d2 - d1 + 1
2473  variable dphi = w_dphi[ipol]
2474  variable az1, az2
2475 
2476  // source slice coordinates
2477  // order the slice from -dphi/2 to 360-dphi/2
2478  azi = azi < 0 ? azi + 360 : azi
2479  azi = azi >= 360 - dphi/2 ? azi - 360 : azi
2480  duplicate /free values, sel_values
2481  duplicate /free weights, sel_weights
2482 
2483  // loop over destination
2484  variable id
2485  variable v1, v2, w1, w2
2486  for (id = 0; id < nd; id += 1)
2487  az1 = (id - 0.5) * dphi
2488  az2 = (id + 0.5) * dphi
2489  extract /free /indx azi, sel, (az1 <= azi) && (azi < az2)
2490  if (numpnts(sel) > 0)
2491  redimension /n=(numpnts(sel)) sel_values, sel_weights
2492  sel_values = values[sel]
2493  sel_weights = weights[sel]
2494  v1 = w_totals[d1 + id]
2495  w1 = w_weights[d1 + id]
2496  if ((numtype(v1) == 2) || (w1 <= 0))
2497  v1 = 0
2498  w1 = 0
2499  endif
2500  v2 = sum(sel_values)
2501  w2 = sum(sel_weights)
2502  w_totals[d1 + id] = v1 + v2
2503  w_weights[d1 + id] = w1 + w2
2504  endif
2505  endfor
2506  w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
2507 };
2508 
2524 variable interpolate_hemi_scan(string nickname){
2525  string nickname
2526 
2527  dfref savedf = GetDataFolderDFR()
2528 
2529  string s_prefix = ""
2530  string s_int = "values"
2531  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2532 
2533  string s_polar = s_prefix + "pol"
2534  string s_azim = s_prefix + "az"
2535  string s_ster_x = s_prefix + "ster_x"
2536  string s_ster_y = s_prefix + "ster_y"
2537 
2538  wave /sdfr=df values = $s_int
2539  wave /sdfr=df azim = $s_azim
2540  wave /sdfr=df polar = $s_polar
2541  wave /sdfr=df ster_x = $s_ster_x
2542  wave /sdfr=df ster_y = $s_ster_y
2543 
2544  variable min_ster_x = wavemin(ster_x)
2545  variable max_ster_x = wavemax(ster_x)
2546  variable x0 = min_ster_x
2547  variable xn = 181
2548  variable dx = (max_ster_x - min_ster_x) / (xn - 1)
2549  make /n=(numpnts(ster_x), 3) /free triplet
2550  triplet[][0] = ster_x[p]
2551  triplet[][1] = ster_y[p]
2552  triplet[][2] = values[p]
2553 
2554  variable size = 181
2555  setdatafolder df
2556  make /n=(size, size) /d /o $(s_prefix + "matrix") /wave=matrix
2557  make /n=(size, size) /free mnorm
2558  ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm
2559  matrix /= mnorm
2560  matrixfilter NanZapMedian, matrix
2561  matrixfilter gauss, matrix
2562 
2563  duplicate /free values, ster_finite
2564  ster_finite = (numtype(values) == 0) * (ster_x^2 + ster_y^2)
2565  variable ster_max = wavemax(ster_finite)
2566  matrix = (x^2 + y^2) <= ster_max ? matrix : nan
2567 
2568  setdatafolder savedf
2569 };
2570 
2581 variable quick_pizza_image(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar = defaultValue, variable nograph = defaultValue, variable folding = defaultValue){
2582  wave data// 2D intensity wave, see requirements above
2583  string nickname// nick name for output data
2584  // in default mode, this will be the name of a child folder containing the output
2585  // in XPDplot mode, this will be a prefix of the generated data in the root folder
2586  variable theta_offset// manipulator theta angle corresponding to normal emission
2587  variable tilt_offset// manipulator tilt angle corresponding to normal emission
2588  variable phi_offset// manipulator phi angle corresponding to phi_result = 0
2589  variable npolar// number of polar angles, determines polar and azimuthal step size
2590  // default = 91 (1 degree steps)
2591  variable nograph// 0 (default) = display a new polar graph
2592  // 1 = don't display a new graph (if a graph is existing from a previous call, it will update)
2593  variable folding// rotational averaging, default = 1
2594 
2595  if (ParamIsDefault(npolar))
2596  npolar = 91
2597  endif
2598  if (ParamIsDefault(nograph))
2599  nograph = 0
2600  endif
2601  if (ParamIsDefault(folding))
2602  folding = 1
2603  endif
2604  string graphname = "graph_" + nickname
2605  string s_prefix = ""
2606 
2607  // sort out data folder structure
2608  dfref saveDF = GetDataFolderDFR()
2609  dfref dataDF = GetWavesDataFolderDFR(data)
2610  setdatafolder dataDF
2611  if (DataFolderExists(":attr"))
2612  setdatafolder :attr
2613  endif
2614  dfref attrDF = GetDataFolderDFR()
2615  setdatafolder dataDF
2616  newdatafolder /s/o $nickname
2617  dfref destDF = GetDataFolderDFR()
2618 
2619  // performance monitoring
2620  variable timerRefNum
2621  variable /g xyz_perf_secs
2622  timerRefNum = startMSTimer
2623 
2624  wave /sdfr=attrDF ManipulatorTheta
2625  wave /sdfr=attrDF ManipulatorTilt
2626  wave /sdfr=attrDF ManipulatorPhi
2627  duplicate /free ManipulatorTheta, m_theta
2628  duplicate /free ManipulatorTilt, m_tilt
2629  duplicate /free ManipulatorPhi, m_phi
2630  m_theta -= theta_offset
2631  m_tilt -= tilt_offset
2632  m_tilt *= -1// checked 140702
2633  m_phi -= phi_offset
2634  //m_phi *= -1 // checked 140702
2635 
2636  make /n=1/d/free d_polar, d_azi
2637  convert_angles_ttpd2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
2638  d_azi += 180// changed 151030 (v1.6)
2639  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
2640 
2641  duplicate /free data, values
2642  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2643  redimension /n=(nn) values, d_polar, d_azi
2644  duplicate /o d_polar, ster_rad, ster_x, ster_y
2645 
2646  variable projection = 1
2647  switch(projection)
2648  case 1:// stereographic
2649  ster_rad = 2 * tan(d_polar / 2 * pi / 180)
2650  break
2651  case 2:// azimuthal
2652  ster_rad = 2 * cos((180 - d_polar) / 2 * pi / 180)
2653  break
2654  endswitch
2655  string s_ster_x = s_prefix + "ster_x"
2656  string s_ster_y = s_prefix + "ster_y"
2657 
2658  nn = 401
2659  make /n=(nn, nn) /d /o matrix
2660  make /n=(nn, nn) /free mnorm
2661  setscale /i x -2, +2, matrix, mnorm
2662  setscale /i y -2, +2, matrix, mnorm
2663  matrix = 0
2664  mnorm = 0
2665 
2666  variable ifold
2667  for (ifold = 0; ifold < folding; ifold += 1)
2668  ster_x = ster_rad * cos(d_azi * pi / 180)
2669  ster_y = ster_rad * sin(d_azi * pi / 180)
2670  ImageFromXYZ {ster_x, ster_y, values}, matrix, mnorm
2671  d_azi = d_azi >= 180 ? d_azi + 360 / folding - 180 : d_azi + 360 / folding
2672  endfor
2673 
2674  matrix /= mnorm
2675  matrixfilter /n=5 NanZapMedian matrix
2676  matrixfilter /n=3 gauss matrix
2677 
2678  if (!nograph)
2679  display /k=1
2680  appendimage matrix
2681  modifygraph width={Plan,1,bottom,left}
2682  endif
2683 
2684  if (timerRefNum >= 0)
2685  xyz_perf_secs = stopMSTimer(timerRefNum) / 1e6
2686  endif
2687 
2688  setdatafolder saveDF
2689 };
2690 
2692 variable save_hemi_scan(string nickname, string pathname, string filename){
2693  string nickname
2694  string pathname
2695  string filename
2696 
2697  dfref savedf = getdatafolderdfr()
2698 
2699  // source data
2700  string s_prefix = ""
2701  string s_int = "values"
2702  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2703 
2704  string s_polar = s_prefix + "pol"
2705  string s_azim = s_prefix + "az"
2706  string s_theta = s_prefix + "th"
2707  string s_tot = s_prefix + "tot"
2708  string s_weight = s_prefix + "wt"
2709 
2710  wave /sdfr=df theta1 = $s_theta
2711  wave /sdfr=df polar1 = $s_polar
2712  wave /sdfr=df azim1 = $s_azim
2713  wave /sdfr=df tot1 = $s_tot
2714  wave /sdfr=df weight1 = $s_weight
2715  wave /sdfr=df values1 = $s_int
2716 
2717  save /m="\r\n" /o /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2718 
2719  setdatafolder saveDF
2720 };
2721 
2725 variable load_hemi_scan(string nickname, string pathname, string filename){
2726  string nickname
2727  string pathname
2728  string filename
2729 
2730  dfref savedf = getdatafolderdfr()
2731 
2732  //loadwave /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2733  //LoadWave /t/p=pearl_explorer_filepath/q filename
2734  //svar waves = s_wavenames
2735  //if (v_flag > 0)
2736  // string /g pearl_explorer_import = "load_itx_file"
2737  //endif
2738 
2739  setdatafolder saveDF
2740 };
2741 
2774 variable import_tpi_scan(string nickname, wave theta, wave phi, wave intensity, variable folding = defaultValue, variable npolar = defaultValue, variable nograph = defaultValue, variable xpdplot = defaultValue){
2775  string nickname
2776  wave theta
2777  wave phi
2778  wave intensity
2779 
2780  variable folding
2781  variable npolar
2782  variable nograph
2783  variable xpdplot
2784 
2785  if (ParamIsDefault(npolar))
2786  npolar = 91
2787  endif
2788  if (ParamIsDefault(nograph))
2789  nograph = 0
2790  endif
2791  if (ParamIsDefault(folding))
2792  folding = 1
2793  endif
2794  if (ParamIsDefault(xpdplot))
2795  xpdplot = 0
2796  endif
2797 
2798  make_hemi_grid(npolar, nickname, xpdplot=xpdplot)
2799 
2800  variable ifold
2801  duplicate /free phi, fold_phi
2802  for (ifold = 0; ifold < folding; ifold += 1)
2803  hemi_add_anglescan(nickname, intensity, theta, fold_phi)
2804  fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
2805  endfor
2806 
2807  if (nograph==0)
2808  display_hemi_scan(nickname)
2809  endif
2810 };
2811 
2823 variable trim_hemi_scan(string nickname, variable theta_max){
2824  string nickname
2825  variable theta_max
2826 
2827  string s_prefix = ""
2828  string s_int = "values"
2829  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2830 
2831  string s_totals = s_prefix + "tot"
2832  string s_weights = s_prefix + "wt"
2833  string s_polar = s_prefix + "pol"
2834 
2835  wave /sdfr=df w_polar = $s_polar
2836  wave /sdfr=df w_values = $s_int
2837  wave /sdfr=df w_totals = $s_totals
2838  wave /sdfr=df w_weights = $s_weights
2839 
2840  w_values = w_polar <= theta_max ? w_totals / w_weights : nan
2841 };
2842 
2862 wave hemi_polar_cut(string nickname, variable azim){
2863  string nickname
2864  variable azim
2865 
2866  dfref savedf = getdatafolderdfr()
2867  string s_prefix = ""
2868  string s_int = "values"
2869  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2870 
2871  string s_totals = s_prefix + "tot"
2872  string s_weights = s_prefix + "wt"
2873  string s_polar = s_prefix + "pol"
2874  string s_azim = s_prefix + "az"
2875  string s_index = s_prefix + "index"
2876  string s_theta = s_prefix + "th"
2877  string s_dphi = s_prefix + "dphi"
2878  string s_nphis = s_prefix + "nphis"
2879  string s_cut
2880  sprintf s_cut, "%s_azi%03u", s_int, round(azim)
2881 
2882  wave /sdfr=df w_polar = $s_polar
2883  wave /sdfr=df w_azim = $s_azim
2884  wave /sdfr=df w_values = $s_int
2885  wave /sdfr=df w_totals = $s_totals
2886  wave /sdfr=df w_weights = $s_weights
2887  wave /sdfr=df w_index = $s_index
2888  wave /sdfr=df w_theta = $s_theta
2889  wave /sdfr=df w_dphi = $s_dphi
2890  wave /sdfr=df w_nphis = $s_nphis
2891 
2892  variable npol = numpnts(w_theta)
2893  variable ipol
2894  variable pol_st = abs(w_theta[1] - w_theta[0])
2895  variable pol
2896  variable pol1, pol2
2897  variable nsel
2898 
2899  setdatafolder df
2900  make /n=(npol) /o $s_cut
2901  wave w_cut = $s_cut
2902  setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
2903  make /n=1 /free azi_slice
2904  make /n=1 /free values_slice
2905 
2906  for (ipol = 0; ipol < npol; ipol += 1)
2907  pol = w_theta[ipol]
2908  pol1 = pol - pol_st / 2
2909  pol2 = pol + pol_st / 2
2910  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2911  nsel = numpnts(sel)
2912  if (nsel > 0)
2913  redimension /n=(nsel+2) azi_slice, values_slice
2914  azi_slice[1, nsel] = w_azim[sel[p-1]]
2915  azi_slice[0] = azi_slice[nsel] - 360
2916  azi_slice[nsel+1] = azi_slice[1] + 360
2917  values_slice[1, nsel] = w_values[sel[p-1]]
2918  values_slice[0] = values_slice[nsel]
2919  values_slice[nsel+1] = values_slice[1]
2920  w_cut[ipol] = interp(azim, azi_slice, values_slice)
2921  else
2922  w_cut[ipol] = nan
2923  endif
2924  endfor
2925 
2926  setdatafolder savedf
2927  return w_cut
2928 };
2929 
2948 wave hemi_azi_cut(string nickname, variable pol){
2949  string nickname
2950  variable pol
2951 
2952  dfref savedf = getdatafolderdfr()
2953  string s_prefix = ""
2954  string s_int = "values"
2955  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2956 
2957  string s_totals = s_prefix + "tot"
2958  string s_weights = s_prefix + "wt"
2959  string s_polar = s_prefix + "pol"
2960  string s_azim = s_prefix + "az"
2961  string s_index = s_prefix + "index"
2962  string s_theta = s_prefix + "th"
2963  string s_dphi = s_prefix + "dphi"
2964  string s_nphis = s_prefix + "nphis"
2965  string s_cut
2966  sprintf s_cut, "%s_pol%03u", s_int, round(pol)
2967 
2968  wave /sdfr=df w_polar = $s_polar
2969  wave /sdfr=df w_azim = $s_azim
2970  wave /sdfr=df w_values = $s_int
2971  wave /sdfr=df w_totals = $s_totals
2972  wave /sdfr=df w_weights = $s_weights
2973  wave /sdfr=df w_index = $s_index
2974  wave /sdfr=df w_theta = $s_theta
2975  wave /sdfr=df w_dphi = $s_dphi
2976  wave /sdfr=df w_nphis = $s_nphis
2977 
2978  variable pol_st = abs(w_theta[1] - w_theta[0])
2979  variable pol1, pol2
2980  variable nsel
2981 
2982  pol1 = pol - pol_st / 2
2983  pol2 = pol + pol_st / 2
2984  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2985  nsel = numpnts(sel)
2986  if (nsel > 0)
2987  setdatafolder df
2988  make /n=(nsel) /o $s_cut
2989  wave w_cut = $s_cut
2990  w_cut = w_values[sel]
2991  setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "", w_cut
2992  setdatafolder savedf
2993  return w_cut
2994  else
2995  setdatafolder savedf
2996  return $""
2997  endif
2998  setdatafolder savedf
2999 };
3000 
3001 static variable check_contrast(wave values, variable pcmin, variable pcmax, variable* vmin, variable* vmax){
3002  wave values
3003  variable pcmin
3004  variable pcmax
3005  variable &vmin
3006  variable &vmax
3007 
3008  dfref save_df = GetDataFolderDFR()
3009  dfref dfr = NewFreeDataFolder()
3010  setdatafolder dfr
3011  StatsQuantiles /inan /iw /q /z values
3012  wave index = w_quantilesindex
3013  variable imin = round(numpnts(index) * pcmin / 100)
3014  variable imax = round(numpnts(index) * (100 - pcmax) / 100)
3015  vmin = values[index[imin]]
3016  vmax = values[index[imax]]
3017  KillDataFolder dfr
3018  setdatafolder save_df
3019 };
3020 
3037 variable set_contrast(variable pcmin, variable pcmax, string graphname = defaultValue, string colortable = defaultValue){
3038  variable pcmin
3039  variable pcmax
3040  string graphname
3041  string colortable
3042 
3043  if (ParamIsDefault(graphname))
3044  graphname = ""
3045  endif
3046  if (ParamIsDefault(colortable))
3047  colortable = ""
3048  endif
3049 
3050  dfref save_df = GetDataFolderDFR()
3051 
3052  string objname
3053  string info
3054  string wname
3055  string ctab
3056  variable rev
3057  variable n
3058  variable i
3059  variable vmin
3060  variable vmax
3061 
3062  string traces = TraceNameList(graphname, ";", 1+4)
3063  n = ItemsInList(traces, ";")
3064  for (i = 0; i < n; i += 1)
3065  objname = StringFromList(i, traces, ";")
3066  info = TraceInfo(graphname, objname, 0)
3067  if (strlen(info) > 0)
3068  info = StringByKey("RECREATION", info, ":", ";")
3069  info = StringByKey("zColor(x)", info, "=", ";")
3070  if (strlen(info) > 2)
3071  info = info[1,strlen(info)-2]
3072  wname = StringFromList(0, info, ",")
3073  wave w = $wname
3074  ctab = StringFromList(3, info, ",")
3075  rev = str2num("0" + StringFromList(4, info, ","))
3076  if (strlen(colortable) > 0)
3077  ctab = colortable
3078  endif
3079  check_contrast(w, pcmin, pcmax, vmin, vmax)
3080  ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
3081  endif
3082  endif
3083  endfor
3084 
3085  string images = ImageNameList(graphname, ";")
3086  n = ItemsInList(images, ";")
3087  for (i = 0; i < n; i += 1)
3088  objname = StringFromList(i, images, ";")
3089  wave w = ImageNameToWaveRef(graphname, objname)
3090  info = ImageInfo(graphname, objname, 0)
3091  if (strlen(info) > 0)
3092  info = StringByKey("RECREATION", info, ":", ";")
3093  info = StringByKey("ctab", info, "=", ";")
3094  if (strlen(info) > 2)
3095  info = info[1,strlen(info)-2]
3096  ctab = StringFromList(2, info, ",")
3097  rev = str2num("0" + StringFromList(3, info, ","))
3098  if (strlen(colortable) > 0)
3099  ctab = colortable
3100  endif
3101  check_contrast(w, pcmin, pcmax, vmin, vmax)
3102  ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
3103  endif
3104  endif
3105  endfor
3106 
3107  setdatafolder save_df
3108 };
3109 
wave hemi_polar_cut(string nickname, variable azim)
extract a polar cut from a hemispherical scan.
+
variable trim_hemi_scan(string nickname, variable theta_max)
trim a hemispherical scan at grazing angle
+
variable pizza_service_2(wave data, string nickname, wave m_theta, wave m_tilt, wave m_phi, variable npolar=defaultValue, variable nograph=defaultValue, variable folding=defaultValue, variable xpdplot=defaultValue)
create a pizza plot from a measured (energy-integrated) data strip
+
static const variable kProjScaleOrtho
variable polar2cart_wave(wave in, wave out)
variable normalize_strip_theta(wave strip, wave theta, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by the average polar distribution.
-
variable normalize_strip_2d(wave strip, wave theta, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by a two-dimensional normalization function.
-
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
-
const variable kProjGnom
+
variable normalize_strip_2d(wave strip, wave theta, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by a two-dimensional normalization function.
+
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
+
const variable kProjGnom
threadsafe wave ad_profile_y(wave dataset, variable p1, variable p2, string destname, variable noavg=defaultValue)
1D cut through 2D dataset along Y dimension, new destination wave.
-
variable make_hemi_grid(variable npol, string nickname, variable xpdplot=defaultValue)
create a hemispherical, constant solid angle grid
-
variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights=defaultValue)
add an arbitrary angle scan to a hemispherical scan grid.
-
string get_hemi_nickname(wave w)
finds the nick name given any hemi wave
-
variable interpolate_hemi_scan(string nickname)
interpolate a hemispherical scan onto a rectangular grid
-
string get_hemi_prefix(wave w)
finds the prefix given any hemi wave
-
string display_hemi_scan(string nickname, variable projection=defaultValue, variable graphtype=defaultValue, variable do_ticks=defaultValue, variable do_grids=defaultValue, string graphname=defaultValue)
display a plot of a hemispherical angle scan.
-
static variable CalcN_Theta(string HoloMode, variable Theta_in, variable Theta_ran, variable Theta_st)
calculate the number of thetas for a pattern
-
dfr find_hemi_data(string nickname, string *prefix, string *intwave)
finds the folder, prefix and name of holo waves given their nick name
-
variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
-
variable clear_hemi_grid(string nickname)
clear a hemispherical scan grid
-
static const variable kProjScaleDist
-
threadsafe variable calc_graph_polar(variable x, variable y, variable projection=defaultValue)
calculate polar angle from Cartesian coordinate
-
static variable check_contrast(wave values, variable pcmin, variable pcmax, variable *vmin, variable *vmax)
-
static variable Calc_The_step(variable th, variable Theta_st, string Holomode)
calculate delta-theta for a given theta
-
const variable kProjArea
-
static variable line_average(wave source, wave dest)
-
threadsafe variable calc_graph_radius(variable polar, variable projection=defaultValue)
calculate the projected polar angle
-
threadsafe variable scienta_ang_transm(wave w, variable x)
-
variable pizza_service(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar=defaultValue, variable nograph=defaultValue, variable folding=defaultValue, variable xpdplot=defaultValue)
create a pizza plot from a measured (energy-integrated) data strip
+
variable make_hemi_grid(variable npol, string nickname, variable xpdplot=defaultValue)
create a hemispherical, constant solid angle grid
+
variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights=defaultValue)
add an arbitrary angle scan to a hemispherical scan grid.
+
string get_hemi_nickname(wave w)
finds the nick name given any hemi wave
+
variable interpolate_hemi_scan(string nickname)
interpolate a hemispherical scan onto a rectangular grid
+
string get_hemi_prefix(wave w)
finds the prefix given any hemi wave
+
string display_hemi_scan(string nickname, variable projection=defaultValue, variable graphtype=defaultValue, variable do_ticks=defaultValue, variable do_grids=defaultValue, string graphname=defaultValue)
display a plot of a hemispherical angle scan.
+
static variable CalcN_Theta(string HoloMode, variable Theta_in, variable Theta_ran, variable Theta_st)
calculate the number of thetas for a pattern
+
dfr find_hemi_data(string nickname, string *prefix, string *intwave)
finds the folder, prefix and name of holo waves given their nick name
+
variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
+
variable clear_hemi_grid(string nickname)
clear a hemispherical scan grid
+
static const variable kProjScaleDist
+
threadsafe variable calc_graph_polar(variable x, variable y, variable projection=defaultValue)
calculate polar angle from Cartesian coordinate
+
static variable check_contrast(wave values, variable pcmin, variable pcmax, variable *vmin, variable *vmax)
+
static variable Calc_The_step(variable th, variable Theta_st, string Holomode)
calculate delta-theta for a given theta
+
const variable kProjArea
+
static variable line_average(wave source, wave dest)
+
threadsafe variable calc_graph_radius(variable polar, variable projection=defaultValue)
calculate the projected polar angle
+
variable pizza_service(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar=defaultValue, variable nograph=defaultValue, variable folding=defaultValue, variable xpdplot=defaultValue)
create a pizza plot from a measured (energy-integrated) data strip
variable rotate_x_wave(wave inout, variable angle)
variable cart2polar_wave(wave in, wave out)
-
string display_scanlines(string nickname, variable alpha_lo, variable alpha_hi, wave m_theta, wave m_tilt, wave m_phi, variable folding=defaultValue, variable projection=defaultValue)
display a polar graph with lines indicating the angles covered by an angle scan.
-
wave hemi_azi_cut(string nickname, variable pol)
extract an azimuthal cut from a hemispherical scan
-
variable draw_diffraction_cone(string graphname, string groupname, variable theta_axis, variable theta_inner, variable phi)
draw the circle of a diffraction cone in a stereographic polar graph.
-
variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights=defaultValue)
add an azimuthal scan to a hemispherical scan grid.
-
static const variable kProjScaleGnom
+
string display_scanlines(string nickname, variable alpha_lo, variable alpha_hi, wave m_theta, wave m_tilt, wave m_phi, variable folding=defaultValue, variable projection=defaultValue)
display a polar graph with lines indicating the angles covered by an angle scan.
+
wave hemi_azi_cut(string nickname, variable pol)
extract an azimuthal cut from a hemispherical scan
+
variable draw_diffraction_cone(string graphname, string groupname, variable theta_axis, variable theta_inner, variable phi)
draw the circle of a diffraction cone in a stereographic polar graph.
+
variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights=defaultValue)
add an azimuthal scan to a hemispherical scan grid.
+
static const variable kProjScaleGnom
variable rotate_y_wave(wave inout, variable angle)
-
variable rotate_hemi_scan(string nickname, variable angle)
azimuthally rotate a hemispherical scan dataset.
-
static const variable kProjScaleStereo
+
variable rotate_hemi_scan(string nickname, variable angle)
azimuthally rotate a hemispherical scan dataset.
+
static const variable kProjScaleStereo
processing and holographic mapping of angle scanned XPD data.
-
static string display_polar_graph(string graphname, variable angle_offset=defaultValue, variable do_ticks=defaultValue)
displays an empty polar graph
-
const variable kProjOrtho
-
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
+
static string display_polar_graph(string graphname, variable angle_offset=defaultValue, variable do_ticks=defaultValue)
displays an empty polar graph
+
const variable kProjOrtho
+
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
variable normalize_strip_phi(wave strip, wave theta, wave phi, variable theta_offset=defaultValue, variable theta_range=defaultValue, variable check=defaultValue)
divide the strip by a sine function in phi (wobble correction).
-
const variable kProjStereo
-
variable quick_pizza_image(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar=defaultValue, variable nograph=defaultValue, variable folding=defaultValue)
map angle scan data onto a rectangular grid in stereographic projection
-
static variable polar_graph_hook(WMWinHookStruct *s)
polar graph window hook
-
const variable kProjDist
-
threadsafe variable calc_graph_azi(variable x, variable y, variable projection=defaultValue, variable zeroAngle=defaultValue)
calculate azimuthal angle from Cartesian coordinate
-
variable set_contrast(variable pcmin, variable pcmax, string graphname=defaultValue, string colortable=defaultValue)
set the pseudocolor contrast by percentile.
+
variable normalize_strip_thetaphi(wave strip, wave theta, wave phi, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by a smooth polar-azimuthal distribution.
+
const variable kProjStereo
+
variable quick_pizza_image(wave data, string nickname, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar=defaultValue, variable nograph=defaultValue, variable folding=defaultValue)
map angle scan data onto a rectangular grid in stereographic projection
+
static variable polar_graph_hook(WMWinHookStruct *s)
polar graph window hook
+
const variable kProjDist
+
threadsafe variable calc_graph_azi(variable x, variable y, variable projection=defaultValue, variable zeroAngle=defaultValue)
calculate azimuthal angle from Cartesian coordinate
+
variable set_contrast(variable pcmin, variable pcmax, string graphname=defaultValue, string colortable=defaultValue)
set the pseudocolor contrast by percentile.
variable strip_delete_frames(wave strip, variable qlo, variable qhi, wave theta, wave tilt, wave phi)
delete a contiguous range of frames from a strip.
variable rotate_z_wave(wave inout, variable angle)
-
static variable calc_nth(variable Theta_st, variable Theta_in, variable th, variable Phi_ran, variable Phi_ref, string Holomode)
calculate the number of phis for a given theta
-
static const variable kProjScaleArea
-
variable show_analyser_line(variable theta, variable tilt, variable phi, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar=defaultValue, variable nograph=defaultValue, variable xpdplot=defaultValue)
calculate and display the line seen by the analyser for a specific emission angle ...
-
variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
-
static string draw_hemi_axes(string graphname, variable do_grids=defaultValue)
draw polar and azimuthal grids in an existing polar graph.
-
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
-
variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname=defaultValue)
-
static variable update_polar_info(string graphname)
update the angles info based on cursors A and B of a given polar graph window
-
variable import_tpi_scan(string nickname, wave theta, wave phi, wave intensity, variable folding=defaultValue, variable npolar=defaultValue, variable nograph=defaultValue, variable xpdplot=defaultValue)
import a hemispherical scan from theta-phi-intensity waves and display it
-
variable load_hemi_scan(string nickname, string pathname, string filename)
load a hemispherical scan from an Igor text file
+
static variable calc_nth(variable Theta_st, variable Theta_in, variable th, variable Phi_ran, variable Phi_ref, string Holomode)
calculate the number of phis for a given theta
+
static const variable kProjScaleArea
+
variable show_analyser_line(variable theta, variable tilt, variable phi, variable theta_offset, variable tilt_offset, variable phi_offset, variable npolar=defaultValue, variable nograph=defaultValue, variable xpdplot=defaultValue)
calculate and display the line seen by the analyser for a specific emission angle ...
+
variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
+
static string draw_hemi_axes(string graphname, variable do_grids=defaultValue)
draw polar and azimuthal grids in an existing polar graph.
+
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
+
variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname=defaultValue)
+
static variable update_polar_info(string graphname)
update the angles info based on cursors A and B of a given polar graph window
+
variable import_tpi_scan(string nickname, wave theta, wave phi, wave intensity, variable folding=defaultValue, variable npolar=defaultValue, variable nograph=defaultValue, variable xpdplot=defaultValue)
import a hemispherical scan from theta-phi-intensity waves and display it
+
variable load_hemi_scan(string nickname, string pathname, string filename)
load a hemispherical scan from an Igor text file
threadsafe wave ad_profile_x(wave dataset, variable q1, variable q2, string destname, variable noavg=defaultValue)
1D cut through 2D dataset along X dimension, new destination wave.
-
static variable calc_phi_step(variable Theta_in, variable th, variable Theta_st, variable Phi_ran, variable Phi_ref, string Holomode)
calculate delta-phi for a given theta
+
static variable calc_phi_step(variable Theta_in, variable th, variable Theta_st, variable Phi_ran, variable Phi_ref, string Holomode)
calculate delta-phi for a given theta
variable normalize_strip_x(wave strip, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by the average X distribution.
@@ -182,7 +181,7 @@ $(document).ready(function(){initNavTree('pearl-anglescan-process_8ipf_source.ht @@ -422,7 +422,7 @@ Variables

callback function for new detector state from EPICS.

save the manipulator position at the beginning of image acquisition. it is used by ast_callback_data().

-

Definition at line 951 of file pearl-anglescan-tracker.ipf.

+

Definition at line 956 of file pearl-anglescan-tracker.ipf.

@@ -442,7 +442,7 @@ Variables

callback function for new manipulator position from EPICS.

-

Definition at line 980 of file pearl-anglescan-tracker.ipf.

+

Definition at line 985 of file pearl-anglescan-tracker.ipf.

@@ -613,7 +613,7 @@ Variables

the parameters will be effective for subsequent measurements only. previously acquired data is not affected. the processing parameters are saved with the preferences.

Parameters
- +
reduction_funcname of custom reduction function, e.g. "int_linbg_reduction". any user-defined function with the same signature as adh5_default_reduction() is allowed.
reduction_funcname of custom reduction function, e.g. "int_linbg_reduction". any user-defined function with the same signature as adh5_default_reduction() is allowed.
reduction_paramsparameter string for the reduction function. the format depends on the actual function. for int_linbg_reduction, e.g., "Lcrop=0.1;Hcrop=0.1;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.4".
@@ -719,7 +719,7 @@ Variables

window hook

disconnects from EPICS when the window is closed.

-

Definition at line 831 of file pearl-anglescan-tracker.ipf.

+

Definition at line 836 of file pearl-anglescan-tracker.ipf.

@@ -745,7 +745,7 @@ Variables
-

Definition at line 1013 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1018 of file pearl-anglescan-tracker.ipf.

@@ -770,7 +770,7 @@ Variables
-

Definition at line 1234 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1239 of file pearl-anglescan-tracker.ipf.

@@ -795,7 +795,7 @@ Variables
-

Definition at line 1218 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1223 of file pearl-anglescan-tracker.ipf.

@@ -826,7 +826,7 @@ Variables
Returns
zero if successful, non-zero if an error occurred
Todo:
the X03DA channel names are hard-coded.
-

Definition at line 675 of file pearl-anglescan-tracker.ipf.

+

Definition at line 680 of file pearl-anglescan-tracker.ipf.

@@ -851,7 +851,7 @@ Variables
-

Definition at line 801 of file pearl-anglescan-tracker.ipf.

+

Definition at line 806 of file pearl-anglescan-tracker.ipf.

@@ -877,7 +877,7 @@ Variables
-

Definition at line 787 of file pearl-anglescan-tracker.ipf.

+

Definition at line 792 of file pearl-anglescan-tracker.ipf.

@@ -904,7 +904,7 @@ Variables

export tracker data (with prompt)

-

Definition at line 1095 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1100 of file pearl-anglescan-tracker.ipf.

@@ -994,7 +994,7 @@ Variables

import tracker data (with prompt)

-

Definition at line 1125 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1130 of file pearl-anglescan-tracker.ipf.

@@ -1075,7 +1075,7 @@ Variables

import tracker data from file (with prompt)

-

Definition at line 1165 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1170 of file pearl-anglescan-tracker.ipf.

@@ -1101,7 +1101,7 @@ Variables
-

Definition at line 1061 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1066 of file pearl-anglescan-tracker.ipf.

@@ -1127,7 +1127,7 @@ Variables
-

Definition at line 1075 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1080 of file pearl-anglescan-tracker.ipf.

@@ -1153,7 +1153,7 @@ Variables
-

Definition at line 1184 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1189 of file pearl-anglescan-tracker.ipf.

@@ -1179,7 +1179,7 @@ Variables
-

Definition at line 1198 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1203 of file pearl-anglescan-tracker.ipf.

@@ -1206,7 +1206,7 @@ Variables

process the data buffer to generate the tracker dataset.

-

Definition at line 502 of file pearl-anglescan-tracker.ipf.

+

Definition at line 507 of file pearl-anglescan-tracker.ipf.

@@ -1261,7 +1261,7 @@ Variables

save tracker data to file (with prompt)

-

Definition at line 1154 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1159 of file pearl-anglescan-tracker.ipf.

@@ -1338,7 +1338,7 @@ Variables

create the graph window.

-

Definition at line 589 of file pearl-anglescan-tracker.ipf.

+

Definition at line 594 of file pearl-anglescan-tracker.ipf.

@@ -1363,7 +1363,7 @@ Variables
-

Definition at line 1027 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1032 of file pearl-anglescan-tracker.ipf.

@@ -1388,7 +1388,7 @@ Variables
-

Definition at line 1045 of file pearl-anglescan-tracker.ipf.

+

Definition at line 1050 of file pearl-anglescan-tracker.ipf.

@@ -1413,7 +1413,7 @@ Variables
-

Definition at line 640 of file pearl-anglescan-tracker.ipf.

+

Definition at line 645 of file pearl-anglescan-tracker.ipf.

@@ -1473,7 +1473,7 @@ Variables

the manipulator angles are corrected by the preset offsets internally.

-

Definition at line 554 of file pearl-anglescan-tracker.ipf.

+

Definition at line 559 of file pearl-anglescan-tracker.ipf.

@@ -1498,7 +1498,7 @@ Variables
-

Definition at line 652 of file pearl-anglescan-tracker.ipf.

+

Definition at line 657 of file pearl-anglescan-tracker.ipf.

@@ -1560,7 +1560,7 @@ Variables
-Initial value:
= 1.6
static const string package_name = "pearl_anglescan_tracker"
static const string package_name
+Initial value:
= 1.6
static const string package_name = "pearl_anglescan_tracker"
static const string package_name
package name is used as data folder name

Definition at line 5 of file pearl-anglescan-tracker.ipf.

@@ -1572,7 +1572,7 @@ Variables
-Go to the documentation of this file.
1 #pragma rtGlobals=3
2 #pragma version = 1.4
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlAnglescanTracker
5 #include "pearl-area-profiles", version > 1.04
6 #include "pearl-area-import", version > 1.05
7 #include "pearl-scienta-preprocess", version > 1.00
8 #include "pearl-anglescan-process", version >= 1.6
9 #include <New Polar Graphs>
10 
11 // $Id$
12 //
13 // author: matthias.muntwiler@psi.ch
14 // Copyright (c) 2014-15 Paul Scherrer Institut
15 //
16 // Licensed under the Apache License, Version 2.0 (the "License");
17 // you may not use this file except in compliance with the License.
18 // You may obtain a copy of the License at
19 // http://www.apache.org/licenses/LICENSE-2.0
20 
58 
64 
66 static const string package_name = "pearl_anglescan_tracker";
68 static const string package_path = "root:packages:pearl_anglescan_tracker:";
70 static const string prefs_objects = "projection;theta_offset;tilt_offset;phi_offset;reduction_func;reduction_params";
71 
73 static variable AfterCompiledHook(){
74 
75  dfref savedf = GetDataFolderDFR()
76  variable do_init = 1
77  if (DataFolderExists(package_path))
78  setdatafolder $(package_path)
79  nvar /z init_done
80  if (nvar_exists(init_done))
81  if (init_done)
82  do_init = 0
83  endif
84  endif
85  endif
86 
87  if (do_init)
88  init_package()
89  load_prefs()
90  setdatafolder $(package_path)
91  variable /g init_done = 1
92  endif
93 
94  setdatafolder savedf
95  return 0
96 };
97 
98 static variable init_package(){
99  dfref savedf = getdatafolderdfr()
100  setdatafolder root:
101  newdatafolder /o/s packages
102  newdatafolder /o/s $package_name
103 
104  // configuration (persistent)
105  string /g graphname = "graph_anglescan_tracker"
106  string /g dataname = "tracker"
107  string /g projection = "stereographic"
108 
109  // recently used (persistent)
110  variable /g theta_offset = 0
111  variable /g tilt_offset = 0
112  variable /g phi_offset = 0
113  string /g reduction_func = "int_linbg_reduction"
114  string /g reduction_params = "Lcrop=0.1;Hcrop=0.1;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.4"
115 
116  // recently used (volatile)
117  string /g export_folderpath = "root:"
118  variable /g export_format = 1
119 
120  // run-time variables (volatile)
121  string /g detector_tracename
122  variable /g capturing = 0
123  variable /g buf_size = 0// number of measurements that fit into the data buffer
124  variable /g buf_count = 0// number of measurements contained in the data buffer
125  variable /g buf_width = 0// number of slices that fit into the data buffer
126 
127  // load icon of sample holder
128  string path = FunctionPath("")
129  path = ParseFilePath(1, path, ":", 1, 0) + "tracker-sample-picture.png"
130  LoadPict /O/Q path, pict_tracker_sample
131 
132  setdatafolder savedf
133 };
134 
139 static variable save_prefs(){
140  dfref saveDF = GetDataFolderDFR()
141 
142  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
143  fullPath += package_name
144  NewPath/O/C/Q tempPackagePrefsPath, fullPath
145  fullPath += ":preferences.pxp"
146 
147  SetDataFolder root:packages
148  SetDataFolder $package_name
149  SaveData /O /Q /J=prefs_objects fullPath
150 
151  KillPath/Z tempPackagePrefsPath
152 
153  SetDataFolder saveDF
154 };
155 
163 static variable load_prefs(){
164  dfref saveDF = GetDataFolderDFR()
165 
166  variable result = -1
167  setdatafolder root:
168  NewDataFolder /O/S packages
169  NewDataFolder /O/S $package_name
170  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
171  fullPath += package_name
172 
173  GetFileFolderInfo /Q /Z fullPath
174  if (V_Flag == 0)// Disk directory exists?
175  fullPath += ":preferences.pxp"
176  GetFileFolderInfo /Q /Z fullPath
177  if (V_Flag == 0)// Preference file exist?
178  LoadData /O /R /Q fullPath
179  result = 0
180  endif
181  endif
182 
183  SetDataFolder saveDF
184  return result
185 };
186 
188 static variable IgorQuitHook(string app){
189  string app
191 };
192 
194 variable ast_setup(){
195  setup_data()
197  setup_graph()
198  epics_connect()
199 };
200 
211 variable ast_prepare(variable theta_offset = defaultValue, variable tilt_offset = defaultValue, variable phi_offset = defaultValue){
212  variable theta_offset
213  variable tilt_offset
214  variable phi_offset
215 
216  dfref savedf = getdatafolderdfr()
217  setdatafolder $(package_path)
218 
219  if (!ParamIsDefault(theta_offset))
220  nvar v_theta_offset = theta_offset
221  v_theta_offset = theta_offset
222  endif
223  if (!ParamIsDefault(tilt_offset))
224  nvar v_tilt_offset = tilt_offset
225  v_tilt_offset = tilt_offset
226  endif
227  if (!ParamIsDefault(phi_offset))
228  nvar v_phi_offset = phi_offset
229  v_phi_offset = phi_offset
230  endif
231 
232  nvar buf_count
233  nvar buf_size
234  nvar buf_width
235  buf_count = 0
236  buf_size = 0
237  buf_width = 0
238 
239  svar dataname
240  clear_hemi_grid(dataname)
241  // work-around: set one point to a real number to make the rest of the trace in the graph transparent
242  wave values = $(dataname + "_i")
243  values[numpnts(values) - 1] = 0
244 
246 
247  setdatafolder saveDF
248 };
249 
261 variable ast_set_processing(string reduction_func, string reduction_params){
262  string reduction_func
263  string reduction_params
264 
265  dfref savedf = getdatafolderdfr()
266  setdatafolder $(package_path)
267 
268  svar red_func = reduction_func
269  svar red_params = reduction_params
270 
271  red_func = reduction_func
272  red_params = reduction_params
273 
274  setdatafolder saveDF
275 };
276 
285 variable ast_add_image(wave image, variable theta, variable tilt, variable phi){
286  wave image
287  variable theta
288  variable tilt
289  variable phi
290 
291  add_image_data(image, theta, tilt, phi)
294 };
295 
307 variable ast_export(dfref folder, string nickname, variable xpdplot = defaultValue){
308  dfref folder
309  string nickname
310  variable xpdplot
311 
312  if (ParamIsDefault(xpdplot))
313  xpdplot = 0
314  endif
315 
316  dfref savedf = getdatafolderdfr()
317  setdatafolder $(package_path)
318 
319  svar dataname
320  duplicate_hemi_scan(dataname, folder, nickname, xpdplot=xpdplot)
321 
322  setdatafolder saveDF
323 };
324 
329 variable ast_import(string nickname){
330  string nickname
331 
332  dfref savedf = getdatafolderdfr()
333 
334  svar /sdfr=$(package_path) dataname
335  duplicate_hemi_scan(nickname, $(package_path), dataname)
336 
337  setdatafolder saveDF
338 };
339 
349 variable ast_update_detector(variable theta, variable tilt, variable phi, variable range){
350  variable theta
351  variable tilt
352  variable phi
353  variable range
354 
355  update_detector(theta, tilt, phi, range)
357 };
358 
360 variable ast_close(){
361  dfref savedf = getdatafolderdfr()
362  setdatafolder $(package_path)
363 
365 
366  svar graphname
367  KillWindow $graphname
368 
369  setdatafolder saveDF
370 };
371 
372 static variable setup_data(){
373  dfref savedf = getdatafolderdfr()
374  setdatafolder $(package_path)
375 
376  nvar buf_size
377  nvar buf_count
378  nvar buf_width
379  buf_size = 0
380  buf_count = 0
381  buf_width = 0
382  make /n=(1,1) /o buf_i
383  make /n=(1) /o buf_th, buf_ph, buf_ti
384 
385  svar dataname
386  variable npolar = 91
387  make_hemi_grid(npolar, dataname)
388 
389  // work-around: set one point to a real number to make the rest of the trace in the graph transparent
390  wave values = $(dataname + "_i")
391  values[numpnts(values) - 1] = 0
392 
393  setdatafolder saveDF
394 };
395 
402 static variable extend_data(variable num_slices){
403  variable num_slices
404 
405  dfref savedf = getdatafolderdfr()
406  setdatafolder $(package_path)
407 
408  nvar buf_size
409  nvar buf_count
410  nvar buf_width
411 
412  variable new_size = buf_size + 91
413  buf_width = num_slices
414 
415  wave buf_i
416  wave buf_th
417  wave buf_ti
418  wave buf_ph
419 
420  redimension /n=(buf_width,new_size) buf_i
421  redimension /n=(new_size) buf_th, buf_ph, buf_ti
422 
423  buf_i[][buf_size, new_size-1] = nan
424  buf_th[buf_size, new_size-1] = nan
425  buf_ph[buf_size, new_size-1] = nan
426  buf_ti[buf_size, new_size-1] = nan
427 
428  buf_size = new_size
429 
430  setdatafolder saveDF
431  return buf_count
432 };
433 
434 static variable setup_detector(){
435  dfref savedf = getdatafolderdfr()
436  setdatafolder $(package_path)
437 
438  make /n=31 /o detector_angle, detector_pol, detector_az, detector_rad
439  setscale /i x -30, 30, "°", detector_angle, detector_pol, detector_az, detector_rad
440  detector_angle = x
441 
442  setdatafolder saveDF
443 };
444 
453 static variable add_image_data(wave image, variable theta, variable tilt, variable phi){
454  wave image
455  variable theta
456  variable tilt
457  variable phi
458 
459  dfref savedf = getdatafolderdfr()
460  setdatafolder $(package_path)
461  svar dataname
462  nvar theta_offset
463  nvar tilt_offset
464  nvar phi_offset
465 
466  // extract angle distribution from image using reduction function mechanism from area-import
467  svar red_func_name = reduction_func
468  svar red_params = reduction_params
469  funcref adh5_default_reduction red_func = $red_func_name
470  variable nx = dimsize(image, 0)
471  make /n=(nx) /free profile1, profile2
472  string loc_params = red_params
473  red_func(image, profile1, profile2, loc_params)
474  nx = numpnts(profile1)
475 
476  // write the result to the buffer
477  nvar buf_count
478  nvar buf_size
479  nvar buf_width
480  wave buf_i
481  wave buf_th
482  wave buf_ph
483  wave buf_ti
484 
485  if ((buf_count >= buf_size) || (nx > buf_width))
486  extend_data(nx)
487  setscale /p x dimoffset(profile1,0), dimdelta(profile1,0), waveunits(profile1,0), buf_i
488  endif
489 
490  buf_i[][buf_count] = profile1[p]
491  buf_th[buf_count] = theta - theta_offset
492  buf_ti[buf_count] = -(tilt - tilt_offset)
493  buf_ph[buf_count] = phi - phi_offset
494 
495  buf_count += 1
496 
497  setdatafolder saveDF
498 };
499 
502 static variable process_image_data(){
503  wave image
504  variable theta
505  variable tilt
506  variable phi
507 
508  dfref savedf = getdatafolderdfr()
509  setdatafolder $(package_path)
510  svar dataname
511 
512  nvar buf_count
513  nvar buf_size
514  nvar buf_width
515 
516  wave buf_i
517  wave buf_th
518  wave buf_ph
519  wave buf_ti
520 
521  duplicate /free /R=[0,buf_width-1][0,buf_count-1] buf_i, buf_n
522  duplicate /free /R=[0,buf_count-1] buf_th, w_th
523  duplicate /free /R=[0,buf_count-1] buf_ti, w_ti
524  duplicate /free /R=[0,buf_count-1] buf_ph, w_ph
525 
526  normalize_strip_x(buf_n, smooth_method=4)
527  if (buf_count >= 10)
528  normalize_strip_theta(buf_n, w_th, smooth_method=4)
529  endif
530  if (dimoffset(buf_i,0) < -20)
531  crop_strip(buf_n, -25, 25)
532  else
533  crop_strip(buf_n, -15, 15)
534  endif
535 
536  make /n=1 /free d_polar, d_azi
537  convert_angles_ttpd2polar(w_th, w_ti, w_ph, buf_n, d_polar, d_azi)
538  d_azi += 180// changed 151030 (v1.4)
539  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
540  hemi_add_anglescan(dataname, buf_n, d_polar, d_azi)
541 
542  setdatafolder saveDF
543 };
544 
554 static variable update_detector(variable theta, variable tilt, variable phi, variable range){
555  variable theta
556  variable tilt
557  variable phi
558  variable range
559 
560  dfref savedf = getdatafolderdfr()
561  setdatafolder $(package_path)
562  nvar theta_offset
563  nvar tilt_offset
564  nvar phi_offset
565 
566  make /n=1 /free m_theta
567  make /n=1 /free m_tilt
568  make /n=1 /free m_phi
569  m_theta = theta - theta_offset
570  m_tilt = tilt - tilt_offset
571  m_tilt *= -1// checked 140702
572  m_phi = phi - phi_offset
573  //m_phi *= -1 // checked 140702
574 
575  wave detector_angle, detector_pol, detector_az, detector_rad
576  setscale /i x -range/2, +range/2, "°", detector_angle
577  detector_angle = x
578 
579  convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, detector_angle, detector_pol, detector_az)
580  redimension /n=(numpnts(detector_pol)) detector_rad
581  detector_rad = 2 * tan(detector_pol / 2 * pi / 180)
582  detector_az += 180// changed 151030 (v1.4)
583  detector_az = detector_az >= 360 ? detector_az - 360 : detector_az
584 
585  setdatafolder saveDF
586 };
587 
589 static variable setup_graph(){
590  dfref savedf = getdatafolderdfr()
591  setdatafolder $(package_path)
592 
593  svar dataname
594  svar graphname
595  wave detector_az
596  wave detector_rad
597  wave detector_angle
598  svar tracename = detector_tracename
599 
600  graphname = display_hemi_scan(dataname, graphname=graphname)
601  tracename = WMPolarAppendTrace(graphname, detector_rad, detector_az, 360)
602  ModifyGraph /w=$graphname lstyle($tracename)=0
603  ModifyGraph /w=$graphname lsize($tracename)=1.5
604  ModifyGraph /w=$graphname zColor($tracename)={detector_angle,*,*,RedWhiteBlue,0}
605  ColorScale /w=$graphname /C /N=text1 trace=$tracename
606  ColorScale /w=$graphname /C /N=text1 /F=0 /B=1 /A=LB /X=0.00 /Y=0.00
607  ColorScale /w=$graphname /C /N=text1 width=1.5, heightPct=20, frame=0.00
608  ColorScale /w=$graphname /C /N=text1 lblMargin=0
609  ColorScale /w=$graphname /C /N=text1 nticks=2, tickLen=2.00, tickThick=0.50
610 
611  TextBox /w=$graphname /C /N=tb_manip /F=0 /B=1 /X=0.00 /Y=0.00 /E=2 "\\{\"manip = (%.1f, %.1f, %.1f)\", "
612  AppendText /w=$graphname /N=tb_manip /NOCR "root:packages:pearl_anglescan_tracker:curTheta, "
613  AppendText /w=$graphname /N=tb_manip /NOCR "root:packages:pearl_anglescan_tracker:curTilt, "
614  AppendText /w=$graphname /N=tb_manip /NOCR "root:packages:pearl_anglescan_tracker:curPhi}"
615 
616  // the window hook releases the EPICS variables when the window is killed
617  DoWindow /T $graphname, "Angle Scan Tracker"
618  SetWindow $graphname, hook(ast_hook) = ast_window_hook
619 
620  ControlBar /w=$graphname 21
621  Button b_capture win=$graphname, title="start", pos={0,0}, size={40,21}, proc=PearlAnglescanTracker#bp_capture
622  Button b_capture win=$graphname, fColor=(65535,65535,65535), fSize=10
623  Button b_capture win=$graphname, help={"Start/stop capturing."}
624  PopupMenu pm_params win=$graphname, mode=0, value="load preferences;save preferences;reduction parameters;manipulator offsets", title="parameters"
625  PopupMenu pm_params win=$graphname, pos={70,0}, bodyWidth=80, proc=PearlAnglescanTracker#pmp_parameters
626  PopupMenu pm_params win=$graphname, help={"Load/save/edit data processing parameters"}
627  PopupMenu pm_data win=$graphname, mode=0, value="import;export;load file;save file", title="data"
628  PopupMenu pm_data win=$graphname, pos={120,0}, proc=PearlAnglescanTracker#pmp_data
629  PopupMenu pm_data win=$graphname, help={"Load/save data from/to independent dataset or file"}
630 
631  SetDrawLayer /w=$graphname ProgFront
632  SetDrawEnv /w=$graphname xcoord=rel, ycoord=rel
633  DrawPict /w=$graphname 0, 0, 1, 1, pict_tracker_sample
634 
636 
637  setdatafolder saveDF
638 };
639 
640 static variable update_data_graph(){
641  dfref savedf = getdatafolderdfr()
642  setdatafolder $(package_path)
643 
644  svar dataname
645  svar graphname
646 
647  // nothing to do - trace is updated automatically
648 
649  setdatafolder saveDF
650 };
651 
652 static variable update_detector_graph(){
653  dfref savedf = getdatafolderdfr()
654  setdatafolder $(package_path)
655 
656  svar dataname
657  svar graphname
658 
659  // nothing to do - trace is updated automatically
660 
661  setdatafolder saveDF
662 };
663 
675 static variable epics_connect(){
676  dfref savedf = getdatafolderdfr()
677  setdatafolder $(package_path)
678 
679  // close PVs which may be open from a previous call
681 
682  // create variables and waves
683  make /n=(1)/o arraydata, xscale, yscale
684  make /n=(1,1)/o image
685  variable /g ndimensions
686  variable /g arraysize0, arraysize1
687  variable /g datatype
688  variable /g colormode
689  string /g controls, monitors
690  string /g xunits, yunits
691 
692  // channel ID variables
693  variable /g chidDetectorState = 0
694  variable /g chidArrayData = 0
695  variable /g chidXScale = 0
696  variable /g chidYScale = 0
697  variable /g chidNDimensions = 0
698  variable /g chidArraySize0 = 0
699  variable /g chidArraySize1 = 0
700  variable /g chidDataType = 0
701  variable /g chidColorMode = 0
702  variable /g chidLensMode = 0
703  variable /g chidTheta = 0
704  variable /g chidTilt = 0
705  variable /g chidPhi = 0
706  variable /g curDetectorState = 0
707  variable /g curLensMode = 0
708  variable /g curTheta = 0
709  variable /g curTilt = 0
710  variable /g curPhi = 0
711  variable /g acqTheta = 0
712  variable /g acqTilt = 0
713  variable /g acqPhi = 0
714  variable /g connected = 0
715 
716  string epicsname = "X03DA-SCIENTA:"
717  string imagename = epicsname + "image1:"
718  string camname = epicsname + "cam1:"
719  string manipname = "X03DA-ES2-MA:"
720  variable timeout = 5// seconds
721 
722  #if exists("pvWait")
723  // EPICS.XOP version 0.3.0 or later
724  pvOpen /Q chidDetectorState, camname + "DetectorState_RBV"// 0 = idle
725  pvOpen /Q chidLensMode, camname + "LENS_MODE_RBV"
726  pvOpen /Q chidXScale, camname + "CHANNEL_SCALE_RBV"
727  pvOpen /Q chidYScale, camname + "SLICE_SCALE_RBV"
728  pvOpen /Q chidArrayData, imagename + "ArrayData"
729  pvOpen /Q chidNDimensions, imagename + "NDimensions_RBV"
730  pvOpen /Q chidArraySize0, imagename + "ArraySize0_RBV"
731  pvOpen /Q chidArraySize1, imagename + "ArraySize1_RBV"
732  pvOpen /Q chidDataType, imagename + "DataType_RBV"
733  pvOpen /Q chidColorMode, imagename + "ColorMode_RBV"
734 
735  pvOpen /Q chidTheta, manipname + "THT.RBV"
736  pvOpen /Q chidTilt, manipname + "TLT.RBV"
737  pvOpen /Q chidPhi, manipname + "PHI.RBV"
738 
739  pvWait timeout
740 
741  if (!GetRTError(1))
742  connected = 1
743  endif
744  #elif exists("pvOpen")
745  // EPICS.XOP version < 0.3.0
746  pvOpen /T=(timeout) chidDetectorState, camname + "DetectorState_RBV"// 0 = idle
747  pvOpen /T=(timeout) chidLensMode, camname + "LENS_MODE_RBV"
748  pvOpen /T=(timeout) chidXScale, camname + "CHANNEL_SCALE_RBV"
749  pvOpen /T=(timeout) chidYScale, camname + "SLICE_SCALE_RBV"
750  pvOpen /T=(timeout) chidArrayData, imagename + "ArrayData"
751  pvOpen /T=(timeout) chidNDimensions, imagename + "NDimensions_RBV"
752  pvOpen /T=(timeout) chidArraySize0, imagename + "ArraySize0_RBV"
753  pvOpen /T=(timeout) chidArraySize1, imagename + "ArraySize1_RBV"
754  pvOpen /T=(timeout) chidDataType, imagename + "DataType_RBV"
755  pvOpen /T=(timeout) chidColorMode, imagename + "ColorMode_RBV"
756 
757  pvOpen /T=(timeout) chidTheta, manipname + "THT.RBV"
758  pvOpen /T=(timeout) chidTilt, manipname + "TLT.RBV"
759  pvOpen /T=(timeout) chidPhi, manipname + "PHI.RBV"
760 
761  if (!GetRTError(1))
762  connected = 1
763  endif
764  #endif
765 
766  #if exists("pvMonitor")
767  if (connected)
768  pvMonitor /F=ast_callback_detector chidDetectorState, curDetectorState
769  pvMonitor /F=ast_callback_manip chidTheta, curTheta
770  pvMonitor /F=ast_callback_manip chidTilt, curTilt
771  pvMonitor /F=ast_callback_manip chidPhi, curPhi
772  pvMonitor /F=ast_callback_manip chidLensMode, curLensMode
773  pvMonitor /F=ast_callback_data chidArrayData
774  endif
775  #endif
776 
777  if (connected)
778  print "angle scan tracker: online"
779  else
780  print "angle scan tracker: offline"
781  endif
782 
783  setdatafolder saveDF
784  return !connected
785 };
786 
787 static variable epics_disconnect_chid(string chid_var_name){
788  string chid_var_name
789 
790  #if exists("pvClose")
791  nvar /z chid = $chid_var_name
792  if (nvar_exists(chid))
793  if (chid != 0)
794  pvClose chid
795  endif
796  chid = 0
797  endif
798  #endif
799 };
800 
801 static variable epics_disconnect(){
802  dfref savedf = GetDataFolderDFR()
803  setdatafolder $(package_path)
804 
805  nvar connected
806  if (connected)
807  connected = 0
808  epics_disconnect_chid("chidDetectorState")
809  epics_disconnect_chid("chidArrayData")
810  epics_disconnect_chid("chidXScale")
811  epics_disconnect_chid("chidYScale")
812  epics_disconnect_chid("chidNDimensions")
813  epics_disconnect_chid("chidArraySize0")
814  epics_disconnect_chid("chidArraySize1")
815  epics_disconnect_chid("chidDataType")
816  epics_disconnect_chid("chidColorMode")
817  epics_disconnect_chid("chidLensMode")
818  epics_disconnect_chid("chidTheta")
819  epics_disconnect_chid("chidTilt")
820  epics_disconnect_chid("chidPhi")
821  print "angle scan tracker: offline"
822  endif
823 
824  setdatafolder savedf
825 };
826 
831 static variable ast_window_hook(WMWinHookStruct* s){
832  STRUCT WMWinHookStruct &s
833 
834  Variable hookResult = 0
835 
836  switch(s.eventCode)
837  case 2:// kill
839  break
840  endswitch
841 
842  return hookResult
843 };
844 
846 variable ast_callback_data(variable chan){
847  variable chan
848 
849  nvar capturing = $(package_path + "capturing")
850  if (!capturing)
851  return 0
852  endif
853 
854  dfref savedf = GetDataFolderDFR()
855  setdatafolder $(package_path)
856  #if exists("pvGetWave")
857 
858  // retrieve data
859  nvar chidArrayData
860  nvar chidXScale
861  nvar chidYScale
862  nvar chidNDimensions
863  nvar chidArraySize0
864  nvar chidArraySize1
865  nvar chidDataType
866  nvar chidColorMode
867  nvar chidTheta
868  nvar chidTilt
869  nvar chidPhi
870  nvar acqTheta
871  nvar acqTilt
872  nvar acqPhi
873 
874  wave arraydata
875  wave image
876  wave xscale
877  wave yscale
878  variable ndimensions
879  variable arraysize0
880  variable arraysize1
881  variable datatype
882  variable colormode
883 
884  //printf "array callback: acqtheta = %.1f, acqtilt = %.1f, acqphi = %.1f\r", acqTheta, acqTilt, acqPhi
885 
886  pvGet chidNDimensions, ndimensions
887  pvGet chidArraySize0, arraysize0
888  pvGet chidArraySize1, arraysize1
889  pvGet chidDataType, datatype
890  pvGet chidColorMode, colormode
891 
892  // sanity checks
893  if (ndimensions != 2)
894  return -2
895  endif
896  if (colormode != 0)
897  return -3
898  endif
899 
900  redimension /n=(arraysize0 * arraysize1) arraydata
901  redimension /n=(arraysize0, arraysize1) image
902  redimension /n=(arraysize0) xscale
903  redimension /n=(arraysize1) yscale
904 
905  switch(datatype)
906  case 0:// int8
907  redimension /b arraydata, image
908  break
909  case 1:// uint8
910  redimension /b/u arraydata, image
911  break
912  case 2:// int16
913  redimension /w arraydata, image
914  break
915  case 3:// uint16
916  redimension /w/u arraydata, image
917  break
918  case 4:// int32
919  redimension /i arraydata, image
920  break
921  case 5:// uint32
922  redimension /i/u arraydata, image
923  break
924  case 6:// float32
925  redimension /s arraydata, image
926  break
927  case 7:// float64
928  redimension /d arraydata, image
929  break
930  endswitch
931 
932  pvGetWave chidArrayData, arraydata
933  pvGetWave chidXScale, xscale
934  pvGetWave chidYScale, yscale
935 
936  image = arraydata[p + q * arraysize0]
937  setscale /i x xscale[0], xscale[numpnts(xscale)-1], image
938  setscale /i y yscale[0], yscale[numpnts(yscale)-1], image
939 
940  ast_add_image(image, acqTheta, acqTilt, acqPhi)
941 
942  #endif
943  setdatafolder savedf
944  return 0
945 };
946 
951 variable ast_callback_detector(variable chan){
952  variable chan
953 
954  dfref savedf = GetDataFolderDFR()
955  setdatafolder $(package_path)
956 
957  // retrieve data
958  nvar curDetectorState
959  nvar curTheta
960  nvar curTilt
961  nvar curPhi
962 
963  nvar acqTheta
964  nvar acqTilt
965  nvar acqPhi
966 
967  if (curDetectorState == 1)
968  acqTheta = curTheta
969  acqTilt = curTilt
970  acqPhi = curPhi
971  endif
972 
973  //printf "detector callback: acqtheta = %.1f, acqtilt = %.1f, acqphi = %.1f, detstate = %d\r", acqTheta, acqTilt, acqPhi, curDetectorState
974 
975  setdatafolder savedf
976  return 0
977 };
978 
980 variable ast_callback_manip(variable chan){
981  variable chan
982 
983  dfref savedf = GetDataFolderDFR()
984  setdatafolder $(package_path)
985 
986  // retrieve data
987  nvar lensmode = curLensMode
988  nvar theta = curTheta
989  nvar tilt = curTilt
990  nvar phi = curPhi
991 
992  //printf "manipulator callback: curtheta = %.1f, curtilt = %.1f, curphi = %.1f, lensmode = %d\r", theta, tilt, phi, lensmode
993 
994  variable range
995  switch(lensmode)
996  case 1:
997  range = 45// angular 45
998  break
999  case 2:
1000  range = 60// angular 60
1001  break
1002  default:
1003  range = 2// transmission or error
1004  endswitch
1005  ast_update_detector(theta, tilt, phi, range)
1006 
1007  setdatafolder savedf
1008  return 0
1009 };
1010 
1011 // GUI functions
1012 
1013 static variable bp_capture(WMButtonAction* ba){
1014  STRUCT WMButtonAction &ba
1015 
1016  switch( ba.eventCode )
1017  case 2:// mouse up
1018  toggle_capture()
1019  break
1020  case -1:// control being killed
1021  break
1022  endswitch
1023 
1024  return 0
1025 };
1026 
1027 static variable toggle_capture(){
1028  dfref savedf = getdatafolderdfr()
1029  setdatafolder $(package_path)
1030 
1031  nvar capturing
1032  svar graphname
1033 
1034  capturing = !capturing
1035  if (capturing)
1036  ast_prepare()
1037  Button b_capture win=$graphname, title="stop"
1038  else
1039  Button b_capture win=$graphname, title="start"
1040  endif
1041 
1042  setdatafolder saveDF
1043 };
1044 
1045 static variable update_capture(){
1046  dfref savedf = getdatafolderdfr()
1047  setdatafolder $(package_path)
1048 
1049  nvar capturing
1050  svar graphname
1051 
1052  if (capturing)
1053  Button b_capture win=$graphname, title="stop"
1054  else
1055  Button b_capture win=$graphname, title="start"
1056  endif
1057 
1058  setdatafolder saveDF
1059 };
1060 
1061 static variable pmp_data(WMPopupAction* pa){
1062  STRUCT WMPopupAction &pa
1063 
1064  switch( pa.eventCode )
1065  case 2:// mouse up
1066  pmp_data_mouseup(pa)
1067  break
1068  case -1:// control being killed
1069  break
1070  endswitch
1071 
1072  return 0
1073 };
1074 
1075 static variable pmp_data_mouseup(WMPopupAction* pa){
1076  STRUCT WMPopupAction &pa
1077 
1078  switch(pa.popNum)
1079  case 1:
1081  break
1082  case 2:
1084  break
1085  case 3:
1087  break
1088  case 4:
1090  break
1091  endswitch
1092 };
1093 
1095 static variable export_tracker_data(){
1096  dfref savedf = getdatafolderdfr()
1097  setdatafolder $(package_path)
1098 
1099  svar export_folderpath
1100  nvar export_format
1101 
1102  string folderpath = export_folderpath
1103  string nickname = ""
1104  variable format = export_format
1105 
1106  prompt folderpath, "Folder Path"
1107  prompt nickname, "Nick Name"
1108  prompt format, "Format", popup, "PEARL;XPDplot"
1109 
1110  doprompt "Export Parameters", folderpath, nickname, format
1111 
1112  if (v_flag == 0)
1113  export_folderpath = folderpath
1114  export_format = format
1115  // note: if a full or partial path is used, all data folders except for the last in the path must already exist.
1116  newdatafolder /o $folderpath
1117  variable xpdplot = format == 2
1118  ast_export($folderpath, nickname, xpdplot=xpdplot)
1119  endif
1120 
1121  setdatafolder saveDF
1122 };
1123 
1125 static variable import_tracker_data(){
1126  dfref savedf = getdatafolderdfr()
1127  setdatafolder $(package_path)
1128 
1129  svar export_folderpath
1130  string folderpath = export_folderpath
1131  string nickname = ""
1132 
1133  dfref dfBefore = GetDataFolderDFR()
1134  Execute /q/z "CreateBrowser prompt=\"Select wave from dataset\", showWaves=1, showVars=0, showStrs=0"
1135  dfref dfAfter = GetDataFolderDFR()
1136  SetDataFolder dfBefore
1137 
1138  SVAR list = S_BrowserList
1139  NVAR flag = V_Flag
1140 
1141  if ((flag != 0) && (ItemsInList(list) >= 1))
1142  string wname = StringFromList(0, list)
1143  wave w = $wname
1144  string prefix = get_hemi_prefix(w)
1145  dfref df = GetWavesDataFolderDFR(w)
1146  setdatafolder df
1147  ast_import(prefix)
1148  endif
1149 
1150  setdatafolder saveDF
1151 };
1152 
1154 static variable save_tracker_data(){
1155  dfref savedf = getdatafolderdfr()
1156  setdatafolder $(package_path)
1157 
1158  svar dataname
1159  save_hemi_scan(dataname, "", "")
1160 
1161  setdatafolder saveDF
1162 };
1163 
1165 static variable load_tracker_data(){
1166  dfref savedf = getdatafolderdfr()
1167  setdatafolder $(package_path)
1168 
1169  NewDataFolder /O/S load_data
1170  LoadWave /t /q
1171  if (v_flag > 0)
1172  string wname = StringFromList(0, s_wavenames, ";")
1173  wave w = $wname
1174  string prefix = get_hemi_prefix(w)
1175  ast_import(prefix)
1176  endif
1177 
1178  setdatafolder $(package_path)
1179  KillDataFolder /Z load_data
1180 
1181  setdatafolder saveDF
1182 };
1183 
1184 static variable pmp_parameters(WMPopupAction* pa){
1185  STRUCT WMPopupAction &pa
1186 
1187  switch( pa.eventCode )
1188  case 2:// mouse up
1190  break
1191  case -1:// control being killed
1192  break
1193  endswitch
1194 
1195  return 0
1196 };
1197 
1198 static variable pmp_parameters_mouseup(WMPopupAction* pa){
1199  STRUCT WMPopupAction &pa
1200 
1201  switch(pa.popNum)
1202  case 1:
1203  load_prefs()
1204  break
1205  case 2:
1206  save_prefs()
1207  break
1208  case 3:
1210  break
1211  case 4:
1212  edit_offsets()
1213  break
1214  endswitch
1215 
1216 };
1217 
1218 static variable edit_reduction_params(){
1219  dfref savedf = getdatafolderdfr()
1220  setdatafolder $(package_path)
1221 
1222  svar pref_func = reduction_func
1223  svar pref_params = reduction_params
1224 
1225  string loc_func = pref_func
1226  string loc_params = pref_params
1227  if (prompt_func_params(loc_func, loc_params) == 0)
1228  ast_set_processing(loc_func, loc_params)
1229  endif
1230 
1231  setdatafolder saveDF
1232 };
1233 
1234 static variable edit_offsets(){
1235  dfref savedf = getdatafolderdfr()
1236  setdatafolder $(package_path)
1237 
1238  nvar theta_offset
1239  nvar tilt_offset
1240  nvar phi_offset
1241 
1242  variable loc_theta = theta_offset
1243  variable loc_tilt = tilt_offset
1244  variable loc_phi = phi_offset
1245 
1246  prompt loc_theta, "theta offset"
1247  prompt loc_tilt, "tilt offset"
1248  prompt loc_phi, "phi offset"
1249 
1250  doprompt "manipulator offsets", loc_theta, loc_tilt, loc_phi
1251  if (v_flag == 0)
1252  theta_offset = loc_theta
1253  tilt_offset = loc_tilt
1254  phi_offset = loc_phi
1255  endif
1256 
1257  setdatafolder saveDF
1258 };
1259 
variable ast_set_processing(string reduction_func, string reduction_params)
set the data processing parameters
+Go to the documentation of this file.
1 #pragma rtGlobals=3
2 #pragma version = 1.4
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlAnglescanTracker
5 #include "pearl-area-profiles", version > 1.04
6 #include "pearl-area-import", version > 1.05
7 #include "pearl-scienta-preprocess", version > 1.00
8 #include "pearl-anglescan-process", version >= 1.6
9 #include <New Polar Graphs>
10 
11 // $Id$
12 //
13 // author: matthias.muntwiler@psi.ch
14 // Copyright (c) 2014-15 Paul Scherrer Institut
15 //
16 // Licensed under the Apache License, Version 2.0 (the "License");
17 // you may not use this file except in compliance with the License.
18 // You may obtain a copy of the License at
19 // http://www.apache.org/licenses/LICENSE-2.0
20 
58 
64 
66 static const string package_name = "pearl_anglescan_tracker";
68 static const string package_path = "root:packages:pearl_anglescan_tracker:";
70 static const string prefs_objects = "projection;theta_offset;tilt_offset;phi_offset;reduction_func;reduction_params";
71 
73 static variable AfterCompiledHook(){
74 
75  dfref savedf = GetDataFolderDFR()
76  variable do_init = 1
77  if (DataFolderExists(package_path))
78  setdatafolder $(package_path)
79  nvar /z init_done
80  if (nvar_exists(init_done))
81  if (init_done)
82  do_init = 0
83  endif
84  endif
85  endif
86 
87  if (do_init)
88  init_package()
89  load_prefs()
90  setdatafolder $(package_path)
91  variable /g init_done = 1
92  endif
93 
94  setdatafolder savedf
95  return 0
96 };
97 
98 static variable init_package(){
99  dfref savedf = getdatafolderdfr()
100  setdatafolder root:
101  newdatafolder /o/s packages
102  newdatafolder /o/s $package_name
103 
104  // configuration (persistent)
105  string /g graphname = "graph_anglescan_tracker"
106  string /g dataname = "tracker"
107  string /g projection = "stereographic"
108 
109  // recently used (persistent)
110  variable /g theta_offset = 0
111  variable /g tilt_offset = 0
112  variable /g phi_offset = 0
113  string /g reduction_func = "int_linbg_reduction"
114  string /g reduction_params = "Lcrop=0.1;Hcrop=0.1;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.4"
115 
116  // recently used (volatile)
117  string /g export_folderpath = "root:"
118  variable /g export_format = 1
119 
120  // run-time variables (volatile)
121  string /g detector_tracename
122  variable /g capturing = 0
123  variable /g buf_size = 0// number of measurements that fit into the data buffer
124  variable /g buf_count = 0// number of measurements contained in the data buffer
125  variable /g buf_width = 0// number of slices that fit into the data buffer
126 
127  // load icon of sample holder
128  string path = FunctionPath("")
129  path = ParseFilePath(1, path, ":", 1, 0) + "tracker-sample-picture.png"
130  LoadPict /O/Q path, pict_tracker_sample
131 
132  setdatafolder savedf
133 };
134 
139 static variable save_prefs(){
140  dfref saveDF = GetDataFolderDFR()
141 
142  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
143  fullPath += package_name
144  NewPath/O/C/Q tempPackagePrefsPath, fullPath
145  fullPath += ":preferences.pxp"
146 
147  SetDataFolder root:packages
148  SetDataFolder $package_name
149  SaveData /O /Q /J=prefs_objects fullPath
150 
151  KillPath/Z tempPackagePrefsPath
152 
153  SetDataFolder saveDF
154 };
155 
163 static variable load_prefs(){
164  dfref saveDF = GetDataFolderDFR()
165 
166  variable result = -1
167  setdatafolder root:
168  NewDataFolder /O/S packages
169  NewDataFolder /O/S $package_name
170  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
171  fullPath += package_name
172 
173  GetFileFolderInfo /Q /Z fullPath
174  if (V_Flag == 0)// Disk directory exists?
175  fullPath += ":preferences.pxp"
176  GetFileFolderInfo /Q /Z fullPath
177  if (V_Flag == 0)// Preference file exist?
178  LoadData /O /R /Q fullPath
179  result = 0
180  endif
181  endif
182 
183  SetDataFolder saveDF
184  return result
185 };
186 
188 static variable IgorQuitHook(string app){
189  string app
191 };
192 
194 variable ast_setup(){
195  setup_data()
197  setup_graph()
198  epics_connect()
199 };
200 
211 variable ast_prepare(variable theta_offset = defaultValue, variable tilt_offset = defaultValue, variable phi_offset = defaultValue){
212  variable theta_offset
213  variable tilt_offset
214  variable phi_offset
215 
216  dfref savedf = getdatafolderdfr()
217  setdatafolder $(package_path)
218 
219  if (!ParamIsDefault(theta_offset))
220  nvar v_theta_offset = theta_offset
221  v_theta_offset = theta_offset
222  endif
223  if (!ParamIsDefault(tilt_offset))
224  nvar v_tilt_offset = tilt_offset
225  v_tilt_offset = tilt_offset
226  endif
227  if (!ParamIsDefault(phi_offset))
228  nvar v_phi_offset = phi_offset
229  v_phi_offset = phi_offset
230  endif
231 
232  nvar buf_count
233  nvar buf_size
234  nvar buf_width
235  buf_count = 0
236  buf_size = 0
237  buf_width = 0
238 
239  svar dataname
240  clear_hemi_grid(dataname)
241  // work-around: set one point to a real number to make the rest of the trace in the graph transparent
242  wave values = $(dataname + "_i")
243  values[numpnts(values) - 1] = 0
244 
246 
247  setdatafolder saveDF
248 };
249 
261 variable ast_set_processing(string reduction_func, string reduction_params){
262  string reduction_func
263  string reduction_params
264 
265  dfref savedf = getdatafolderdfr()
266  setdatafolder $(package_path)
267 
268  svar red_func = reduction_func
269  svar red_params = reduction_params
270 
271  red_func = reduction_func
272  red_params = reduction_params
273 
274  setdatafolder saveDF
275 };
276 
285 variable ast_add_image(wave image, variable theta, variable tilt, variable phi){
286  wave image
287  variable theta
288  variable tilt
289  variable phi
290 
291  add_image_data(image, theta, tilt, phi)
294 };
295 
307 variable ast_export(dfref folder, string nickname, variable xpdplot = defaultValue){
308  dfref folder
309  string nickname
310  variable xpdplot
311 
312  if (ParamIsDefault(xpdplot))
313  xpdplot = 0
314  endif
315 
316  dfref savedf = getdatafolderdfr()
317  setdatafolder $(package_path)
318 
319  svar dataname
320  duplicate_hemi_scan(dataname, folder, nickname, xpdplot=xpdplot)
321 
322  setdatafolder saveDF
323 };
324 
329 variable ast_import(string nickname){
330  string nickname
331 
332  dfref savedf = getdatafolderdfr()
333 
334  svar /sdfr=$(package_path) dataname
335  duplicate_hemi_scan(nickname, $(package_path), dataname)
336 
337  setdatafolder saveDF
338 };
339 
349 variable ast_update_detector(variable theta, variable tilt, variable phi, variable range){
350  variable theta
351  variable tilt
352  variable phi
353  variable range
354 
355  update_detector(theta, tilt, phi, range)
357 };
358 
360 variable ast_close(){
361  dfref savedf = getdatafolderdfr()
362  setdatafolder $(package_path)
363 
365 
366  svar graphname
367  KillWindow $graphname
368 
369  setdatafolder saveDF
370 };
371 
372 static variable setup_data(){
373  dfref savedf = getdatafolderdfr()
374  setdatafolder $(package_path)
375 
376  nvar buf_size
377  nvar buf_count
378  nvar buf_width
379  buf_size = 0
380  buf_count = 0
381  buf_width = 0
382  make /n=(1,1) /o buf_i
383  make /n=(1) /o buf_th, buf_ph, buf_ti
384 
385  svar dataname
386  variable npolar = 91
387  make_hemi_grid(npolar, dataname)
388 
389  // work-around: set one point to a real number to make the rest of the trace in the graph transparent
390  wave values = $(dataname + "_i")
391  values[numpnts(values) - 1] = 0
392 
393  setdatafolder saveDF
394 };
395 
402 static variable extend_data(variable num_slices){
403  variable num_slices
404 
405  dfref savedf = getdatafolderdfr()
406  setdatafolder $(package_path)
407 
408  nvar buf_size
409  nvar buf_count
410  nvar buf_width
411 
412  variable new_size = buf_size + 91
413  buf_width = num_slices
414 
415  wave buf_i
416  wave buf_th
417  wave buf_ti
418  wave buf_ph
419 
420  redimension /n=(buf_width,new_size) buf_i
421  redimension /n=(new_size) buf_th, buf_ph, buf_ti
422 
423  buf_i[][buf_size, new_size-1] = nan
424  buf_th[buf_size, new_size-1] = nan
425  buf_ph[buf_size, new_size-1] = nan
426  buf_ti[buf_size, new_size-1] = nan
427 
428  buf_size = new_size
429 
430  setdatafolder saveDF
431  return buf_count
432 };
433 
434 static variable setup_detector(){
435  dfref savedf = getdatafolderdfr()
436  setdatafolder $(package_path)
437 
438  make /n=31 /o detector_angle, detector_pol, detector_az, detector_rad
439  setscale /i x -30, 30, "", detector_angle, detector_pol, detector_az, detector_rad
440  detector_angle = x
441 
442  setdatafolder saveDF
443 };
444 
453 static variable add_image_data(wave image, variable theta, variable tilt, variable phi){
454  wave image
455  variable theta
456  variable tilt
457  variable phi
458 
459  dfref savedf = getdatafolderdfr()
460  setdatafolder $(package_path)
461  svar dataname
462  nvar theta_offset
463  nvar tilt_offset
464  nvar phi_offset
465 
466  // extract angle distribution from image using reduction function mechanism from area-import
467  svar red_func_name = reduction_func
468  svar red_params = reduction_params
469  funcref adh5_default_reduction red_func = $red_func_name
470  variable nx = dimsize(image, 0)
471  string loc_params = red_params
472  wave /wave red_results = red_func(image, loc_params)
473  if (numpnts(red_results) < 1)
474  setdatafolder saveDF
475  return 0
476  endif
477 
478  wave profile1 = red_results[0]
479  nx = numpnts(profile1)
480 
481  // write the result to the buffer
482  nvar buf_count
483  nvar buf_size
484  nvar buf_width
485  wave buf_i
486  wave buf_th
487  wave buf_ph
488  wave buf_ti
489 
490  if ((buf_count >= buf_size) || (nx > buf_width))
491  extend_data(nx)
492  setscale /p x dimoffset(profile1,0), dimdelta(profile1,0), waveunits(profile1,0), buf_i
493  endif
494 
495  buf_i[][buf_count] = profile1[p]
496  buf_th[buf_count] = theta - theta_offset
497  buf_ti[buf_count] = -(tilt - tilt_offset)
498  buf_ph[buf_count] = phi - phi_offset
499 
500  buf_count += 1
501 
502  setdatafolder saveDF
503 };
504 
507 static variable process_image_data(){
508  wave image
509  variable theta
510  variable tilt
511  variable phi
512 
513  dfref savedf = getdatafolderdfr()
514  setdatafolder $(package_path)
515  svar dataname
516 
517  nvar buf_count
518  nvar buf_size
519  nvar buf_width
520 
521  wave buf_i
522  wave buf_th
523  wave buf_ph
524  wave buf_ti
525 
526  duplicate /free /R=[0,buf_width-1][0,buf_count-1] buf_i, buf_n
527  duplicate /free /R=[0,buf_count-1] buf_th, w_th
528  duplicate /free /R=[0,buf_count-1] buf_ti, w_ti
529  duplicate /free /R=[0,buf_count-1] buf_ph, w_ph
530 
531  normalize_strip_x(buf_n, smooth_method=4)
532  if (buf_count >= 10)
533  normalize_strip_theta(buf_n, w_th, smooth_method=4)
534  endif
535  if (dimoffset(buf_i,0) < -20)
536  crop_strip(buf_n, -25, 25)
537  else
538  crop_strip(buf_n, -15, 15)
539  endif
540 
541  make /n=1 /free d_polar, d_azi
542  convert_angles_ttpd2polar(w_th, w_ti, w_ph, buf_n, d_polar, d_azi)
543  d_azi += 180// changed 151030 (v1.4)
544  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
545  hemi_add_anglescan(dataname, buf_n, d_polar, d_azi)
546 
547  setdatafolder saveDF
548 };
549 
559 static variable update_detector(variable theta, variable tilt, variable phi, variable range){
560  variable theta
561  variable tilt
562  variable phi
563  variable range
564 
565  dfref savedf = getdatafolderdfr()
566  setdatafolder $(package_path)
567  nvar theta_offset
568  nvar tilt_offset
569  nvar phi_offset
570 
571  make /n=1 /free m_theta
572  make /n=1 /free m_tilt
573  make /n=1 /free m_phi
574  m_theta = theta - theta_offset
575  m_tilt = tilt - tilt_offset
576  m_tilt *= -1// checked 140702
577  m_phi = phi - phi_offset
578  //m_phi *= -1 // checked 140702
579 
580  wave detector_angle, detector_pol, detector_az, detector_rad
581  setscale /i x -range/2, +range/2, "", detector_angle
582  detector_angle = x
583 
584  convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, detector_angle, detector_pol, detector_az)
585  redimension /n=(numpnts(detector_pol)) detector_rad
586  detector_rad = 2 * tan(detector_pol / 2 * pi / 180)
587  detector_az += 180// changed 151030 (v1.4)
588  detector_az = detector_az >= 360 ? detector_az - 360 : detector_az
589 
590  setdatafolder saveDF
591 };
592 
594 static variable setup_graph(){
595  dfref savedf = getdatafolderdfr()
596  setdatafolder $(package_path)
597 
598  svar dataname
599  svar graphname
600  wave detector_az
601  wave detector_rad
602  wave detector_angle
603  svar tracename = detector_tracename
604 
605  graphname = display_hemi_scan(dataname, graphname=graphname)
606  tracename = WMPolarAppendTrace(graphname, detector_rad, detector_az, 360)
607  ModifyGraph /w=$graphname lstyle($tracename)=0
608  ModifyGraph /w=$graphname lsize($tracename)=1.5
609  ModifyGraph /w=$graphname zColor($tracename)={detector_angle,*,*,RedWhiteBlue,0}
610  ColorScale /w=$graphname /C /N=text1 trace=$tracename
611  ColorScale /w=$graphname /C /N=text1 /F=0 /B=1 /A=LB /X=0.00 /Y=0.00
612  ColorScale /w=$graphname /C /N=text1 width=1.5, heightPct=20, frame=0.00
613  ColorScale /w=$graphname /C /N=text1 lblMargin=0
614  ColorScale /w=$graphname /C /N=text1 nticks=2, tickLen=2.00, tickThick=0.50
615 
616  TextBox /w=$graphname /C /N=tb_manip /F=0 /B=1 /X=0.00 /Y=0.00 /E=2 "\\{\"manip = (%.1f, %.1f, %.1f)\", "
617  AppendText /w=$graphname /N=tb_manip /NOCR "root:packages:pearl_anglescan_tracker:curTheta, "
618  AppendText /w=$graphname /N=tb_manip /NOCR "root:packages:pearl_anglescan_tracker:curTilt, "
619  AppendText /w=$graphname /N=tb_manip /NOCR "root:packages:pearl_anglescan_tracker:curPhi}"
620 
621  // the window hook releases the EPICS variables when the window is killed
622  DoWindow /T $graphname, "Angle Scan Tracker"
623  SetWindow $graphname, hook(ast_hook) = ast_window_hook
624 
625  ControlBar /w=$graphname 21
626  Button b_capture win=$graphname, title="start", pos={0,0}, size={40,21}, proc=PearlAnglescanTracker#bp_capture
627  Button b_capture win=$graphname, fColor=(65535,65535,65535), fSize=10
628  Button b_capture win=$graphname, help={"Start/stop capturing."}
629  PopupMenu pm_params win=$graphname, mode=0, value="load preferences;save preferences;reduction parameters;manipulator offsets", title="parameters"
630  PopupMenu pm_params win=$graphname, pos={70,0}, bodyWidth=80, proc=PearlAnglescanTracker#pmp_parameters
631  PopupMenu pm_params win=$graphname, help={"Load/save/edit data processing parameters"}
632  PopupMenu pm_data win=$graphname, mode=0, value="import;export;load file;save file", title="data"
633  PopupMenu pm_data win=$graphname, pos={120,0}, proc=PearlAnglescanTracker#pmp_data
634  PopupMenu pm_data win=$graphname, help={"Load/save data from/to independent dataset or file"}
635 
636  SetDrawLayer /w=$graphname ProgFront
637  SetDrawEnv /w=$graphname xcoord=rel, ycoord=rel
638  DrawPict /w=$graphname 0, 0, 1, 1, pict_tracker_sample
639 
641 
642  setdatafolder saveDF
643 };
644 
645 static variable update_data_graph(){
646  dfref savedf = getdatafolderdfr()
647  setdatafolder $(package_path)
648 
649  svar dataname
650  svar graphname
651 
652  // nothing to do - trace is updated automatically
653 
654  setdatafolder saveDF
655 };
656 
657 static variable update_detector_graph(){
658  dfref savedf = getdatafolderdfr()
659  setdatafolder $(package_path)
660 
661  svar dataname
662  svar graphname
663 
664  // nothing to do - trace is updated automatically
665 
666  setdatafolder saveDF
667 };
668 
680 static variable epics_connect(){
681  dfref savedf = getdatafolderdfr()
682  setdatafolder $(package_path)
683 
684  // close PVs which may be open from a previous call
686 
687  // create variables and waves
688  make /n=(1)/o arraydata, xscale, yscale
689  make /n=(1,1)/o image
690  variable /g ndimensions
691  variable /g arraysize0, arraysize1
692  variable /g datatype
693  variable /g colormode
694  string /g controls, monitors
695  string /g xunits, yunits
696 
697  // channel ID variables
698  variable /g chidDetectorState = 0
699  variable /g chidArrayData = 0
700  variable /g chidXScale = 0
701  variable /g chidYScale = 0
702  variable /g chidNDimensions = 0
703  variable /g chidArraySize0 = 0
704  variable /g chidArraySize1 = 0
705  variable /g chidDataType = 0
706  variable /g chidColorMode = 0
707  variable /g chidLensMode = 0
708  variable /g chidTheta = 0
709  variable /g chidTilt = 0
710  variable /g chidPhi = 0
711  variable /g curDetectorState = 0
712  variable /g curLensMode = 0
713  variable /g curTheta = 0
714  variable /g curTilt = 0
715  variable /g curPhi = 0
716  variable /g acqTheta = 0
717  variable /g acqTilt = 0
718  variable /g acqPhi = 0
719  variable /g connected = 0
720 
721  string epicsname = "X03DA-SCIENTA:"
722  string imagename = epicsname + "image1:"
723  string camname = epicsname + "cam1:"
724  string manipname = "X03DA-ES2-MA:"
725  variable timeout = 5// seconds
726 
727  #if exists("pvWait")
728  // EPICS.XOP version 0.3.0 or later
729  pvOpen /Q chidDetectorState, camname + "DetectorState_RBV"// 0 = idle
730  pvOpen /Q chidLensMode, camname + "LENS_MODE_RBV"
731  pvOpen /Q chidXScale, camname + "CHANNEL_SCALE_RBV"
732  pvOpen /Q chidYScale, camname + "SLICE_SCALE_RBV"
733  pvOpen /Q chidArrayData, imagename + "ArrayData"
734  pvOpen /Q chidNDimensions, imagename + "NDimensions_RBV"
735  pvOpen /Q chidArraySize0, imagename + "ArraySize0_RBV"
736  pvOpen /Q chidArraySize1, imagename + "ArraySize1_RBV"
737  pvOpen /Q chidDataType, imagename + "DataType_RBV"
738  pvOpen /Q chidColorMode, imagename + "ColorMode_RBV"
739 
740  pvOpen /Q chidTheta, manipname + "THT.RBV"
741  pvOpen /Q chidTilt, manipname + "TLT.RBV"
742  pvOpen /Q chidPhi, manipname + "PHI.RBV"
743 
744  pvWait timeout
745 
746  if (!GetRTError(1))
747  connected = 1
748  endif
749  #elif exists("pvOpen")
750  // EPICS.XOP version < 0.3.0
751  pvOpen /T=(timeout) chidDetectorState, camname + "DetectorState_RBV"// 0 = idle
752  pvOpen /T=(timeout) chidLensMode, camname + "LENS_MODE_RBV"
753  pvOpen /T=(timeout) chidXScale, camname + "CHANNEL_SCALE_RBV"
754  pvOpen /T=(timeout) chidYScale, camname + "SLICE_SCALE_RBV"
755  pvOpen /T=(timeout) chidArrayData, imagename + "ArrayData"
756  pvOpen /T=(timeout) chidNDimensions, imagename + "NDimensions_RBV"
757  pvOpen /T=(timeout) chidArraySize0, imagename + "ArraySize0_RBV"
758  pvOpen /T=(timeout) chidArraySize1, imagename + "ArraySize1_RBV"
759  pvOpen /T=(timeout) chidDataType, imagename + "DataType_RBV"
760  pvOpen /T=(timeout) chidColorMode, imagename + "ColorMode_RBV"
761 
762  pvOpen /T=(timeout) chidTheta, manipname + "THT.RBV"
763  pvOpen /T=(timeout) chidTilt, manipname + "TLT.RBV"
764  pvOpen /T=(timeout) chidPhi, manipname + "PHI.RBV"
765 
766  if (!GetRTError(1))
767  connected = 1
768  endif
769  #endif
770 
771  #if exists("pvMonitor")
772  if (connected)
773  pvMonitor /F=ast_callback_detector chidDetectorState, curDetectorState
774  pvMonitor /F=ast_callback_manip chidTheta, curTheta
775  pvMonitor /F=ast_callback_manip chidTilt, curTilt
776  pvMonitor /F=ast_callback_manip chidPhi, curPhi
777  pvMonitor /F=ast_callback_manip chidLensMode, curLensMode
778  pvMonitor /F=ast_callback_data chidArrayData
779  endif
780  #endif
781 
782  if (connected)
783  print "angle scan tracker: online"
784  else
785  print "angle scan tracker: offline"
786  endif
787 
788  setdatafolder saveDF
789  return !connected
790 };
791 
792 static variable epics_disconnect_chid(string chid_var_name){
793  string chid_var_name
794 
795  #if exists("pvClose")
796  nvar /z chid = $chid_var_name
797  if (nvar_exists(chid))
798  if (chid != 0)
799  pvClose chid
800  endif
801  chid = 0
802  endif
803  #endif
804 };
805 
806 static variable epics_disconnect(){
807  dfref savedf = GetDataFolderDFR()
808  setdatafolder $(package_path)
809 
810  nvar connected
811  if (connected)
812  connected = 0
813  epics_disconnect_chid("chidDetectorState")
814  epics_disconnect_chid("chidArrayData")
815  epics_disconnect_chid("chidXScale")
816  epics_disconnect_chid("chidYScale")
817  epics_disconnect_chid("chidNDimensions")
818  epics_disconnect_chid("chidArraySize0")
819  epics_disconnect_chid("chidArraySize1")
820  epics_disconnect_chid("chidDataType")
821  epics_disconnect_chid("chidColorMode")
822  epics_disconnect_chid("chidLensMode")
823  epics_disconnect_chid("chidTheta")
824  epics_disconnect_chid("chidTilt")
825  epics_disconnect_chid("chidPhi")
826  print "angle scan tracker: offline"
827  endif
828 
829  setdatafolder savedf
830 };
831 
836 static variable ast_window_hook(WMWinHookStruct* s){
837  STRUCT WMWinHookStruct &s
838 
839  Variable hookResult = 0
840 
841  switch(s.eventCode)
842  case 2:// kill
844  break
845  endswitch
846 
847  return hookResult
848 };
849 
851 variable ast_callback_data(variable chan){
852  variable chan
853 
854  nvar capturing = $(package_path + "capturing")
855  if (!capturing)
856  return 0
857  endif
858 
859  dfref savedf = GetDataFolderDFR()
860  setdatafolder $(package_path)
861  #if exists("pvGetWave")
862 
863  // retrieve data
864  nvar chidArrayData
865  nvar chidXScale
866  nvar chidYScale
867  nvar chidNDimensions
868  nvar chidArraySize0
869  nvar chidArraySize1
870  nvar chidDataType
871  nvar chidColorMode
872  nvar chidTheta
873  nvar chidTilt
874  nvar chidPhi
875  nvar acqTheta
876  nvar acqTilt
877  nvar acqPhi
878 
879  wave arraydata
880  wave image
881  wave xscale
882  wave yscale
883  variable ndimensions
884  variable arraysize0
885  variable arraysize1
886  variable datatype
887  variable colormode
888 
889  //printf "array callback: acqtheta = %.1f, acqtilt = %.1f, acqphi = %.1f\r", acqTheta, acqTilt, acqPhi
890 
891  pvGet chidNDimensions, ndimensions
892  pvGet chidArraySize0, arraysize0
893  pvGet chidArraySize1, arraysize1
894  pvGet chidDataType, datatype
895  pvGet chidColorMode, colormode
896 
897  // sanity checks
898  if (ndimensions != 2)
899  return -2
900  endif
901  if (colormode != 0)
902  return -3
903  endif
904 
905  redimension /n=(arraysize0 * arraysize1) arraydata
906  redimension /n=(arraysize0, arraysize1) image
907  redimension /n=(arraysize0) xscale
908  redimension /n=(arraysize1) yscale
909 
910  switch(datatype)
911  case 0:// int8
912  redimension /b arraydata, image
913  break
914  case 1:// uint8
915  redimension /b/u arraydata, image
916  break
917  case 2:// int16
918  redimension /w arraydata, image
919  break
920  case 3:// uint16
921  redimension /w/u arraydata, image
922  break
923  case 4:// int32
924  redimension /i arraydata, image
925  break
926  case 5:// uint32
927  redimension /i/u arraydata, image
928  break
929  case 6:// float32
930  redimension /s arraydata, image
931  break
932  case 7:// float64
933  redimension /d arraydata, image
934  break
935  endswitch
936 
937  pvGetWave chidArrayData, arraydata
938  pvGetWave chidXScale, xscale
939  pvGetWave chidYScale, yscale
940 
941  image = arraydata[p + q * arraysize0]
942  setscale /i x xscale[0], xscale[numpnts(xscale)-1], image
943  setscale /i y yscale[0], yscale[numpnts(yscale)-1], image
944 
945  ast_add_image(image, acqTheta, acqTilt, acqPhi)
946 
947  #endif
948  setdatafolder savedf
949  return 0
950 };
951 
956 variable ast_callback_detector(variable chan){
957  variable chan
958 
959  dfref savedf = GetDataFolderDFR()
960  setdatafolder $(package_path)
961 
962  // retrieve data
963  nvar curDetectorState
964  nvar curTheta
965  nvar curTilt
966  nvar curPhi
967 
968  nvar acqTheta
969  nvar acqTilt
970  nvar acqPhi
971 
972  if (curDetectorState == 1)
973  acqTheta = curTheta
974  acqTilt = curTilt
975  acqPhi = curPhi
976  endif
977 
978  //printf "detector callback: acqtheta = %.1f, acqtilt = %.1f, acqphi = %.1f, detstate = %d\r", acqTheta, acqTilt, acqPhi, curDetectorState
979 
980  setdatafolder savedf
981  return 0
982 };
983 
985 variable ast_callback_manip(variable chan){
986  variable chan
987 
988  dfref savedf = GetDataFolderDFR()
989  setdatafolder $(package_path)
990 
991  // retrieve data
992  nvar lensmode = curLensMode
993  nvar theta = curTheta
994  nvar tilt = curTilt
995  nvar phi = curPhi
996 
997  //printf "manipulator callback: curtheta = %.1f, curtilt = %.1f, curphi = %.1f, lensmode = %d\r", theta, tilt, phi, lensmode
998 
999  variable range
1000  switch(lensmode)
1001  case 1:
1002  range = 45// angular 45
1003  break
1004  case 2:
1005  range = 60// angular 60
1006  break
1007  default:
1008  range = 2// transmission or error
1009  endswitch
1010  ast_update_detector(theta, tilt, phi, range)
1011 
1012  setdatafolder savedf
1013  return 0
1014 };
1015 
1016 // GUI functions
1017 
1018 static variable bp_capture(WMButtonAction* ba){
1019  STRUCT WMButtonAction &ba
1020 
1021  switch( ba.eventCode )
1022  case 2:// mouse up
1023  toggle_capture()
1024  break
1025  case -1:// control being killed
1026  break
1027  endswitch
1028 
1029  return 0
1030 };
1031 
1032 static variable toggle_capture(){
1033  dfref savedf = getdatafolderdfr()
1034  setdatafolder $(package_path)
1035 
1036  nvar capturing
1037  svar graphname
1038 
1039  capturing = !capturing
1040  if (capturing)
1041  ast_prepare()
1042  Button b_capture win=$graphname, title="stop"
1043  else
1044  Button b_capture win=$graphname, title="start"
1045  endif
1046 
1047  setdatafolder saveDF
1048 };
1049 
1050 static variable update_capture(){
1051  dfref savedf = getdatafolderdfr()
1052  setdatafolder $(package_path)
1053 
1054  nvar capturing
1055  svar graphname
1056 
1057  if (capturing)
1058  Button b_capture win=$graphname, title="stop"
1059  else
1060  Button b_capture win=$graphname, title="start"
1061  endif
1062 
1063  setdatafolder saveDF
1064 };
1065 
1066 static variable pmp_data(WMPopupAction* pa){
1067  STRUCT WMPopupAction &pa
1068 
1069  switch( pa.eventCode )
1070  case 2:// mouse up
1071  pmp_data_mouseup(pa)
1072  break
1073  case -1:// control being killed
1074  break
1075  endswitch
1076 
1077  return 0
1078 };
1079 
1080 static variable pmp_data_mouseup(WMPopupAction* pa){
1081  STRUCT WMPopupAction &pa
1082 
1083  switch(pa.popNum)
1084  case 1:
1086  break
1087  case 2:
1089  break
1090  case 3:
1092  break
1093  case 4:
1095  break
1096  endswitch
1097 };
1098 
1100 static variable export_tracker_data(){
1101  dfref savedf = getdatafolderdfr()
1102  setdatafolder $(package_path)
1103 
1104  svar export_folderpath
1105  nvar export_format
1106 
1107  string folderpath = export_folderpath
1108  string nickname = ""
1109  variable format = export_format
1110 
1111  prompt folderpath, "Folder Path"
1112  prompt nickname, "Nick Name"
1113  prompt format, "Format", popup, "PEARL;XPDplot"
1114 
1115  doprompt "Export Parameters", folderpath, nickname, format
1116 
1117  if (v_flag == 0)
1118  export_folderpath = folderpath
1119  export_format = format
1120  // note: if a full or partial path is used, all data folders except for the last in the path must already exist.
1121  newdatafolder /o $folderpath
1122  variable xpdplot = format == 2
1123  ast_export($folderpath, nickname, xpdplot=xpdplot)
1124  endif
1125 
1126  setdatafolder saveDF
1127 };
1128 
1130 static variable import_tracker_data(){
1131  dfref savedf = getdatafolderdfr()
1132  setdatafolder $(package_path)
1133 
1134  svar export_folderpath
1135  string folderpath = export_folderpath
1136  string nickname = ""
1137 
1138  dfref dfBefore = GetDataFolderDFR()
1139  Execute /q/z "CreateBrowser prompt=\"Select wave from dataset\", showWaves=1, showVars=0, showStrs=0"
1140  dfref dfAfter = GetDataFolderDFR()
1141  SetDataFolder dfBefore
1142 
1143  SVAR list = S_BrowserList
1144  NVAR flag = V_Flag
1145 
1146  if ((flag != 0) && (ItemsInList(list) >= 1))
1147  string wname = StringFromList(0, list)
1148  wave w = $wname
1149  string prefix = get_hemi_prefix(w)
1150  dfref df = GetWavesDataFolderDFR(w)
1151  setdatafolder df
1152  ast_import(prefix)
1153  endif
1154 
1155  setdatafolder saveDF
1156 };
1157 
1159 static variable save_tracker_data(){
1160  dfref savedf = getdatafolderdfr()
1161  setdatafolder $(package_path)
1162 
1163  svar dataname
1164  save_hemi_scan(dataname, "", "")
1165 
1166  setdatafolder saveDF
1167 };
1168 
1170 static variable load_tracker_data(){
1171  dfref savedf = getdatafolderdfr()
1172  setdatafolder $(package_path)
1173 
1174  NewDataFolder /O/S load_data
1175  LoadWave /t /q
1176  if (v_flag > 0)
1177  string wname = StringFromList(0, s_wavenames, ";")
1178  wave w = $wname
1179  string prefix = get_hemi_prefix(w)
1180  ast_import(prefix)
1181  endif
1182 
1183  setdatafolder $(package_path)
1184  KillDataFolder /Z load_data
1185 
1186  setdatafolder saveDF
1187 };
1188 
1189 static variable pmp_parameters(WMPopupAction* pa){
1190  STRUCT WMPopupAction &pa
1191 
1192  switch( pa.eventCode )
1193  case 2:// mouse up
1195  break
1196  case -1:// control being killed
1197  break
1198  endswitch
1199 
1200  return 0
1201 };
1202 
1203 static variable pmp_parameters_mouseup(WMPopupAction* pa){
1204  STRUCT WMPopupAction &pa
1205 
1206  switch(pa.popNum)
1207  case 1:
1208  load_prefs()
1209  break
1210  case 2:
1211  save_prefs()
1212  break
1213  case 3:
1215  break
1216  case 4:
1217  edit_offsets()
1218  break
1219  endswitch
1220 
1221 };
1222 
1223 static variable edit_reduction_params(){
1224  dfref savedf = getdatafolderdfr()
1225  setdatafolder $(package_path)
1226 
1227  svar pref_func = reduction_func
1228  svar pref_params = reduction_params
1229 
1230  string loc_func = pref_func
1231  string loc_params = pref_params
1232  if (prompt_func_params(loc_func, loc_params) == 0)
1233  ast_set_processing(loc_func, loc_params)
1234  endif
1235 
1236  setdatafolder saveDF
1237 };
1238 
1239 static variable edit_offsets(){
1240  dfref savedf = getdatafolderdfr()
1241  setdatafolder $(package_path)
1242 
1243  nvar theta_offset
1244  nvar tilt_offset
1245  nvar phi_offset
1246 
1247  variable loc_theta = theta_offset
1248  variable loc_tilt = tilt_offset
1249  variable loc_phi = phi_offset
1250 
1251  prompt loc_theta, "theta offset"
1252  prompt loc_tilt, "tilt offset"
1253  prompt loc_phi, "phi offset"
1254 
1255  doprompt "manipulator offsets", loc_theta, loc_tilt, loc_phi
1256  if (v_flag == 0)
1257  theta_offset = loc_theta
1258  tilt_offset = loc_tilt
1259  phi_offset = loc_phi
1260  endif
1261 
1262  setdatafolder saveDF
1263 };
1264 
variable ast_set_processing(string reduction_func, string reduction_params)
set the data processing parameters
variable ast_close()
stop tracker, close graph, release data structures.
variable normalize_strip_theta(wave strip, wave theta, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by the average polar distribution.
-
static variable epics_connect()
connect the angle scan tracker to EPICS
-
static variable update_detector_graph()
-
static variable bp_capture(WMButtonAction *ba)
-
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
-
variable make_hemi_grid(variable npol, string nickname, variable xpdplot=defaultValue)
create a hemispherical, constant solid angle grid
-
variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights=defaultValue)
add an arbitrary angle scan to a hemispherical scan grid.
+
static variable epics_connect()
connect the angle scan tracker to EPICS
+
static variable update_detector_graph()
+
static variable bp_capture(WMButtonAction *ba)
+
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
+
variable make_hemi_grid(variable npol, string nickname, variable xpdplot=defaultValue)
create a hemispherical, constant solid angle grid
+
variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights=defaultValue)
add an arbitrary angle scan to a hemispherical scan grid.
static variable setup_detector()
-
static variable pmp_parameters(WMPopupAction *pa)
-
string get_hemi_prefix(wave w)
finds the prefix given any hemi wave
-
string display_hemi_scan(string nickname, variable projection=defaultValue, variable graphtype=defaultValue, variable do_ticks=defaultValue, variable do_grids=defaultValue, string graphname=defaultValue)
display a plot of a hemispherical angle scan.
-
static variable epics_disconnect()
-
static variable update_data_graph()
+
static variable pmp_parameters(WMPopupAction *pa)
+
string get_hemi_prefix(wave w)
finds the prefix given any hemi wave
+
string display_hemi_scan(string nickname, variable projection=defaultValue, variable graphtype=defaultValue, variable do_ticks=defaultValue, variable do_grids=defaultValue, string graphname=defaultValue)
display a plot of a hemispherical angle scan.
+
static variable epics_disconnect()
+
static variable update_data_graph()
variable ast_setup()
set up data structures, display graph, and try to connect to analyser.
-
variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
+
variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
static const string prefs_objects
semicolon-separated list of persistent variable, string, and wave names
-
static variable setup_graph()
create the graph window.
-
static variable import_tracker_data()
import tracker data (with prompt)
-
variable clear_hemi_grid(string nickname)
clear a hemispherical scan grid
+
static variable setup_graph()
create the graph window.
+
static variable import_tracker_data()
import tracker data (with prompt)
+
variable clear_hemi_grid(string nickname)
clear a hemispherical scan grid
static variable extend_data(variable num_slices)
extend the data buffer for the next polar scan
-
static variable pmp_data_mouseup(WMPopupAction *pa)
+
static variable pmp_data_mouseup(WMPopupAction *pa)
variable ast_prepare(variable theta_offset=defaultValue, variable tilt_offset=defaultValue, variable phi_offset=defaultValue)
prepare for new measurement and clear the data buffer.
-
variable PearlAnglescanTracker(string epicsname, string wbRGB)
Definition: pearl-menu.ipf:182
+
variable PearlAnglescanTracker(string epicsname, string wbRGB)
Definition: pearl-menu.ipf:187
static variable setup_data()
-
static variable epics_disconnect_chid(string chid_var_name)
+
static variable epics_disconnect_chid(string chid_var_name)
static variable AfterCompiledHook()
initialize package data once when the procedure is first loaded
static variable save_prefs()
save persistent package data to the preferences file.
-
static const string package_name
-
static variable edit_offsets()
+
static variable edit_offsets()
static variable add_image_data(wave image, variable theta, variable tilt, variable phi)
reduce a detector image and add the result to the data buffer.
static const string package_path
data folder path
-
static variable load_tracker_data()
import tracker data from file (with prompt)
-
static variable save_tracker_data()
save tracker data to file (with prompt)
-
static variable update_capture()
+
static variable load_tracker_data()
import tracker data from file (with prompt)
+
static variable save_tracker_data()
save tracker data to file (with prompt)
+
static variable update_capture()
variable ast_export(dfref folder, string nickname, variable xpdplot=defaultValue)
export tracker data to a separate, independent data set.
variable ast_update_detector(variable theta, variable tilt, variable phi, variable range)
update the current position indicator.
-
threadsafe variable adh5_default_reduction(wave source, wave dest1, wave dest2, string *param)
function prototype for adh5_load_reduced_detector
-
static variable process_image_data()
process the data buffer to generate the tracker dataset.
-
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
+
static variable process_image_data()
process the data buffer to generate the tracker dataset.
+
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
static variable IgorQuitHook(string app)
disconnect EPICS channels before Igor quits.
-
variable ast_callback_manip(variable chan)
callback function for new manipulator position from EPICS.
-
variable ast_callback_detector(variable chan)
callback function for new detector state from EPICS.
-
static variable pmp_parameters_mouseup(WMPopupAction *pa)
+
threadsafe wave adh5_default_reduction(wave source, string *param)
function prototype for adh5_load_reduced_detector
+
variable ast_callback_manip(variable chan)
callback function for new manipulator position from EPICS.
+
variable ast_callback_detector(variable chan)
callback function for new detector state from EPICS.
+
static variable pmp_parameters_mouseup(WMPopupAction *pa)
variable prompt_func_params(string func_name, string *func_param)
-
variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
+
variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi)
convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.
variable ast_add_image(wave image, variable theta, variable tilt, variable phi)
process and add a detector image to the tracker scan.
-
static variable pmp_data(WMPopupAction *pa)
-
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
+
static variable pmp_data(WMPopupAction *pa)
+
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
static variable init_package()
-
static variable ast_window_hook(WMWinHookStruct *s)
window hook
-
static variable edit_reduction_params()
-
static variable toggle_capture()
-
variable ast_callback_data(variable chan)
callback function for new analyser data from EPICS.
+
static variable ast_window_hook(WMWinHookStruct *s)
window hook
+
static variable edit_reduction_params()
+
static variable toggle_capture()
+
variable ast_callback_data(variable chan)
callback function for new analyser data from EPICS.
variable ast_import(string nickname)
import tracker data from an existing angle scan dataset.
+
static const string package_name
package name is used as data folder name
static variable load_prefs()
load persistent package data from the preferences file.
variable normalize_strip_x(wave strip, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by the average X distribution.
-
static variable update_detector(variable theta, variable tilt, variable phi, variable range)
update the current position indicator.
-
static variable export_tracker_data()
export tracker data (with prompt)
+
static variable update_detector(variable theta, variable tilt, variable phi, variable range)
update the current position indicator.
+
static variable export_tracker_data()
export tracker data (with prompt)
- +
- + - - - - - - - - - - - - @@ -323,19 +319,65 @@ Functions

function prototype for adh5_load_reduced_detector

-

derived functions reduce a two-dimensional dataset to a one-dimensional dataset, e.g. by ROI-integration, curve fitting, etc. each destination wave is a one-dimensional intensity distribution. the function must redimension each of these waves to one of the image dimensions by calling the adh5_setup_profile() function. this function will also copy the scale information and dimension labels, which is important for the proper scaling of the result.

-

the meaning of the data in dest1 and dest2 is up to the particular function, e.g. dest1 could hold the mean value and dest2 the one-sigma error, or dest1 could hold the X-profile, and dest2 the Y-profile.

+

this is a prototype of custom functions that convert (reduce) a two-dimensional detector image into one or more one-dimensional waves. data processing can be tuned with a set of parameters.

+

reduction functions have a fixed signature (function arguments) so that the file import functions can call them efficiently on a series of detector images. pearl procedures comes with a number of pre-defined reduction functions but you may as well implement your own functions. if you write your own function, you must use the same declaration and arguments as this function except for the function name. you can do many things in a reduction function, e.g. integration over a region of interest, curve fitting, etc.

+

each destination wave is a one-dimensional intensity distribution. the function must redimension each of these waves to one of the image dimensions by calling the adh5_setup_profile() function. this function will also copy the scale information and dimension labels, which is important for the proper scaling of the result.

+

the meaning of the data in the result waves is up to the particular function, e.g. dest1 could hold the mean value and dest2 the one-sigma error, or dest1 could hold the X-profile, and dest2 the Y-profile.

Parameters
threadsafe variable adh5_default_reduction threadsafe wave adh5_default_reduction ( wave  source,
wave dest1,
wave dest2,
- - - + +
sourcesource wave two-dimensional intensity distribution (image)
dest1,dest2destination waves
paramstring with optional parameters, shared between calls. this is a pass-by-reference argument, the function may modify the string
sourcesource wave. two-dimensional intensity distribution (image). the scales are carried over to the result waves.
paramstring with optional parameters, shared between calls. this is a pass-by-reference argument, the function may modify the string.
-
Returns
zero if successful, non-zero if an error occurs.
+
Returns
a free wave containing references of the result waves. the result waves should as well be free waves. if an error occurred, the reference wave is empty.
-

Definition at line 1093 of file pearl-area-import.ipf.

+

Definition at line 1110 of file pearl-area-import.ipf.

+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
threadsafe variable adh5_get_result_waves (wave results,
string result_prefix,
variable start_index 
)
+
+ +

copy waves from wave reference wave into current data folder

+

this function copies waves that are referenced in a wave reference wave into the current data folder. the destination waves get new names consisting of a prefix and a numeric index. the index is the array index of the wave in results plus a chosen offset.

+
Parameters
+ + + + +
resultsa wave reference wave pointing to result waves from data reduction. the waves can be free or regular waves. results can be a free or regular wave.
result_prefixname prefix of the copied waves.
start_indexstart index (offset) of the copied waves.
+
+
+ +

Definition at line 1192 of file pearl-area-import.ipf.

@@ -355,7 +397,7 @@ Functions

get a list of functions which can be used as reduction functions.

the function evaluates only the function arguments, it may thus include functions which are not suitable as reduction functions.

-

Definition at line 1033 of file pearl-area-import.ipf.

+

Definition at line 1040 of file pearl-area-import.ipf.

@@ -414,7 +456,7 @@ Functions -

Definition at line 199 of file pearl-area-import.ipf.

+

Definition at line 206 of file pearl-area-import.ipf.

@@ -452,7 +494,7 @@ Functions -

Definition at line 573 of file pearl-area-import.ipf.

+

Definition at line 580 of file pearl-area-import.ipf.

@@ -518,7 +560,7 @@ Functions -

Definition at line 937 of file pearl-area-import.ipf.

+

Definition at line 944 of file pearl-area-import.ipf.

@@ -564,7 +606,7 @@ Functions
Returns
0 if successful, non-zero if an error occurred.
-

Definition at line 772 of file pearl-area-import.ipf.

+

Definition at line 779 of file pearl-area-import.ipf.

@@ -603,7 +645,7 @@ Functions -

Definition at line 489 of file pearl-area-import.ipf.

+

Definition at line 496 of file pearl-area-import.ipf.

@@ -663,7 +705,7 @@ Functions -

Definition at line 379 of file pearl-area-import.ipf.

+

Definition at line 386 of file pearl-area-import.ipf.

@@ -736,7 +778,7 @@ Functions ANickNamedestination folder name (top level under root) APathNameigor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed AFileNameif empty a dialog box shows up - reduction_funccustom reduction function (any user-defined function which has the same parameters as adh5_default_reduction()) + reduction_funccustom reduction function (any user-defined function which has the same parameters as adh5_default_reduction()) reduction_paramparameter string for the reduction function load_data1 (default): load data; 0: do not load data load_attr1 (default): load attributes; 0: do not load attributes for proper wave scaling, the attributes must be loaded @@ -745,7 +787,7 @@ Functions -

Definition at line 294 of file pearl-area-import.ipf.

+

Definition at line 301 of file pearl-area-import.ipf.

@@ -804,7 +846,7 @@ Functions - + @@ -812,7 +854,7 @@ Functions -

Definition at line 1162 of file pearl-area-import.ipf.

+

Definition at line 1228 of file pearl-area-import.ipf.

@@ -850,7 +892,7 @@ Functions -

Definition at line 1479 of file pearl-area-import.ipf.

+

Definition at line 1552 of file pearl-area-import.ipf.

@@ -878,7 +920,7 @@ Functions -

Definition at line 618 of file pearl-area-import.ipf.

+

Definition at line 625 of file pearl-area-import.ipf.

@@ -909,7 +951,7 @@ Functions

set the dimension scales of an area detector dataset.

the intrinsic dimensions 0 and 1 are scaled according to the data source (currently supported: Prosilica cameras, Scienta electron analyser). the extra dimensions are scaled according to the scan. the latter requires that the positioner names and position values are available.

-

Definition at line 718 of file pearl-area-import.ipf.

+

Definition at line 725 of file pearl-area-import.ipf.

@@ -931,7 +973,7 @@ Functions

the scan positioner name and its values must be available

Todo:
incomplete
-

Definition at line 1719 of file pearl-area-import.ipf.

+

Definition at line 1792 of file pearl-area-import.ipf.

@@ -952,7 +994,7 @@ Functions

set the energy and angle scales of an area detector dataset from the Scienta analyser.

the dimension labels of the energy and angle scales must be set correctly: AD_Dim0 = energy dimension; AD_Dim1 = angle dimension. these dimensions must be the first two dimensions of a multi-dimensional dataset. normally, AD_Dim0 is the X dimension, and AD_Dim1 the Y dimension.

-

Definition at line 1614 of file pearl-area-import.ipf.

+

Definition at line 1687 of file pearl-area-import.ipf.

@@ -989,11 +1031,11 @@ Functions

set up a one-dimensional wave for a line profile based on a 2D original wave.

redimensions the profile wave to the given dimension. copies the scale and dimension label of the given dimension.

-

Definition at line 1113 of file pearl-area-import.ipf.

+

Definition at line 1133 of file pearl-area-import.ipf.

- +
fileIDID of open HDF5 file from HDF5OpenFile
detectorpathpath to detector group in the HDF5 file
reduction_funccustom reduction function (any user-defined function which has the same parameters as adh5_default_reduction())
reduction_funccustom reduction function (any user-defined function which has the same parameters as adh5_default_reduction())
reduction_paramparameter string for the reduction function
progress1 (default): show progress window; 0: do not show progress window
nthreads-1 (default): use as many threads as there are processor cores (in addition to main thread) 0: use main thread only (e.g. for debugging the reduction function) >= 1: use a fixed number of (additional) threads
@@ -1003,18 +1045,6 @@ Functions - - - - - - - - - - - - @@ -1025,7 +1055,13 @@ Functions - + + + + + + + @@ -1036,9 +1072,19 @@ Functions

wrapper function for testing reduction functions from the command line.

-

Igor does not allow global variables as pass-by-reference parameter for reduction_param.

+

reduction functions cannot be used on the command line because they require a pass-by-reference argument and return free waves. this function expects the reduction parameters in a normal string and copies the results into the current data folder. the prefix of the result names can be specified.

+
Parameters
+
wave  source,
wave dest1,
wave dest2,
string reduction_param reduction_param,
string result_prefix 
+ + + + +
sourcesource wave. two-dimensional intensity distribution (image). the scales are carried over to the result waves.
reduction_funcname of the reduction function to apply to the source data.
reduction_paramstring with reduction parameters as required by the specific reduction function.
result_prefixname prefix of result waves. a numeric index is appended to distinguish the results. the index starts at 1. existing waves are overwritten.
+ + +
Returns
a copy of the reduction_param string, possibly modified by the reduction function.
-

Definition at line 1128 of file pearl-area-import.ipf.

+

Definition at line 1166 of file pearl-area-import.ipf.

@@ -1100,7 +1146,7 @@ Functions

callback function for drag&drop of HDF5 files into Igor.

-

Definition at line 34 of file pearl-area-import.ipf.

+

Definition at line 41 of file pearl-area-import.ipf.

@@ -1136,7 +1182,7 @@ Functions
Returns
data folder reference of the attributes folder. the reference may be invalid (and default to root) if the folder cannot be found, cf. built-in DataFolderRefStatus function.
-

Definition at line 699 of file pearl-area-import.ipf.

+

Definition at line 706 of file pearl-area-import.ipf.

@@ -1189,11 +1235,11 @@ Functions -

Definition at line 1561 of file pearl-area-import.ipf.

+

Definition at line 1634 of file pearl-area-import.ipf.

- +
@@ -1201,7 +1247,7 @@ Functions
- + @@ -1212,18 +1258,6 @@ Functions - - - - - - - - - - - - @@ -1249,7 +1283,7 @@ Functions
static threadsafe variable reduce_slab_image static threadsafe wave reduce_slab_image ( wave  slabdata,
wave  image,
wave profile1,
wave profile2,
-

Definition at line 1444 of file pearl-area-import.ipf.

+

Definition at line 1519 of file pearl-area-import.ipf.

@@ -1275,7 +1309,7 @@ Functions
-

Definition at line 1405 of file pearl-area-import.ipf.

+

Definition at line 1480 of file pearl-area-import.ipf.

@@ -1285,7 +1319,7 @@ Functions
-Go to the documentation of this file.
1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
2 #pragma IgorVersion = 6.2
3 #pragma ModuleName = PearlAreaImport
4 #pragma version = 1.06
5 #include <HDF5 Browser>
6 #include "pearl-gui-tools"
7 
8 // copyright (c) 2013-16 Paul Scherrer Institut
9 //
10 // Licensed under the Apache License, Version 2.0 (the "License");
11 // you may not use this file except in compliance with the License.
12 // You may obtain a copy of the License at
13 // http:///www.apache.org/licenses/LICENSE-2.0
14 
26 
31 
34 static variable BeforeFileOpenHook(variable refNum, string fileName, string path, string type, string creator, variable kind){
35  variable refNum, kind
36  string fileName, path, type, creator
37 
38  variable handledOpen = 0
39 
40  //PathInfo $path
41  //string FilePath = s_path + filename
42  string NickName = CleanupName(ParseFilePath(3, FileName, ":", 0, 0), 0)
43  string FileExt = LowerStr(ParseFilePath(4, FileName, ":", 0, 0))
44  string result = ""
45 
46  // override nickname with custom setting
47  svar /z cnn = gsCustomNickName
48  if (svar_exists(cnn))
49  if (exists("gvNickNameIndex") != 2)
50  variable/g gvNickNameIndex = 1
51  endif
52  nvar nni = gvNickNameIndex
53  NickName = cnn + num2str(nni)
54  nni += 1
55  endif
56 
57  if (stringmatch(FileExt, "h5") == 1)
58  result = adh5_load_complete(NickName, path, FileName)
59  endif
60 
61  string/g s_latest_datafile = result
62  string/g s_latest_nickname = nickname
63 
64  handledOpen = strlen(result) > 0
65  if (handledOpen)
66  close refnum
67  endif
68 
69  return handledOpen// 1 tells Igor not to open the file
70 };
71 
98 string ad_suggest_foldername(string filename, variable ignoredate = defaultValue, string sourcename = defaultValue, variable unique = defaultValue){
99  string filename
100  variable ignoredate
101  string sourcename
102  variable unique
103 
104  if (ParamIsDefault(ignoredate))
105  ignoredate = 0
106  endif
107  if (ParamIsDefault(unique))
108  unique = 0
109  endif
110 
111  string basename = ParseFilePath(3, filename, ":", 0, 0)
112  string extension = ParseFilePath(4, filename, ":", 0, 0)
113  string nickname
114 
115  string autosource
116  if (strsearch(basename, "scienta", 0, 2) >= 0)
117  autosource = "sci"
118  else if (strsearch(basename, "pshell", 0, 2) >= 0)
119  autosource = "psh"
120  else if (strsearch(basename, "OP-SL", 0, 2) >= 0)
121  autosource = "sl"
122  else if (strsearch(basename, "ES-PS", 0, 2) >= 0)
123  autosource = "es"
124  else
125  autosource = "xy"
126  endif
127  if (ParamIsDefault(sourcename))
128  sourcename = autosource
129  endif
130 
131  variable nparts = ItemsInList(basename, "-")
132  if (nparts >= 3)
133  string datepart = StringFromList(1, basename, "-")
134  variable l_datepart = strlen(datepart)
135  if (l_datepart == 8)
136  datepart = datepart[l_datepart-6, l_datepart-1]
137  endif
138  string indexpart = StringFromList(2, basename, "-")
139  if (ignoredate)
140  sprintf nickname, "%s_%s", sourcename, indexpart
141  else
142  sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart
143  endif
144  else
145  nickname = CleanupName(basename, 0)
146  endif
147 
148  if (unique && CheckName(nickname, 11))
149  nickname = UniqueName(nickname + "_", 11, 0)
150  endif
151 
152  return nickname
153 };
154 
159 variable ad_load_dialog(string APathName){
160  string APathName
161 
162  variable refNum
163  string message = "Select data files"
164  string filepaths
165  string filefilters = "Area Detector HDF5 Files (*.h5):.h5;"
166  filefilters += "All Files:.*;"
167 
168  PathInfo /S $APathName
169  Open /D /R /F=filefilters /M=message /MULT=1 refNum
170  filepaths = S_fileName
171 
172  dfref saveDF = GetDataFolderDFR()
173  setdatafolder root:
174 
175  if (strlen(filepaths) > 0)
176  variable nfiles = ItemsInList(filepaths, "\r")
177  variable ifile
178  for(ifile = 0; ifile < nfiles; ifile += 1)
179  String path = StringFromList(ifile, filepaths, "\r")
180  string nickname = ad_suggest_foldername(path)
181  adh5_load_complete(nickname, "", path)
182  endfor
183  endif
184 
185  setdatafolder saveDF
186 };
187 
199 string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
200  string ANickName
201  string APathName
202  string AFileName
203  variable load_data
204  variable load_attr
205 
206  if (ParamIsDefault(load_data))
207  load_data = 1
208  endif
209  if (ParamIsDefault(load_attr))
210  load_attr = 1
211  endif
212 
213  dfref saveDF = GetDataFolderDFR()
214  setdatafolder root:
215  newdatafolder /s/o $("root:" + ANickName)
216 
217  // open file
218  variable fileID
219  string instrumentpath = "/entry/instrument/"
220  string detectorpath = instrumentpath + "detector/"
221  string attributespath = instrumentpath + "NDAttributes/"
222  string datasetname
223  string datawavename
224 
225  // performance monitoring
226  variable timerRefNum
227  variable /g adh5_perf_secs
228  timerRefNum = startMSTimer
229 
230  // avoid compilation error if HDF5 XOP has not been loaded
231  #if Exists("HDF5OpenFile")
232  HDF5OpenFile /P=$APathName/R fileID as AFileName
233  if (v_flag == 0)
234  AFileName = s_path + s_filename
235  print "loading " + s_filename + "\r"
236 
237  if (load_data)
238  adh5_load_detector_slabs(fileID, detectorpath)
239  endif
240  if (load_attr)
241  newdatafolder /o/s attr
242  adh5_loadattr_all(fileID, attributespath)
243  setdatafolder ::
244  endif
245 
246  wave /z data
247  if (waveexists(data))
248  //adh5_redim(data) // not to be used with adh5_load_detector_slabs
249  adh5_scale(data)
250  endif
251 
252  HDF5CloseFile fileID
253  else
254  AFileName = ""
255  endif
256  #else
257  Abort "HDF5 XOP not loaded."
258  #endif
259 
260  if (timerRefNum >= 0)
261  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
262  endif
263 
264  setdatafolder saveDF
265  return AFileName
266 };
267 
294 string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data = defaultValue, variable load_attr = defaultValue, variable progress = defaultValue){
295  string ANickName
296  string APathName
297  string AFileName
298 
299  funcref adh5_default_reduction reduction_func
300  string reduction_param
301 
302  variable load_data
303  variable load_attr
304  variable progress
305 
306  if (ParamIsDefault(load_data))
307  load_data = 1
308  endif
309  if (ParamIsDefault(load_attr))
310  load_attr = 1
311  endif
312  if (ParamIsDefault(progress))
313  progress = 1
314  endif
315 
316  dfref saveDF = GetDataFolderDFR()
317  setdatafolder root:
318  newdatafolder /s/o $("root:" + ANickName)
319 
320  // open file
321  variable fileID
322  string instrumentpath = "/entry/instrument/"
323  string detectorpath = instrumentpath + "detector/"
324  string attributespath = instrumentpath + "NDAttributes/"
325  string datasetname
326  string datawavename
327 
328  // performance monitoring
329  variable timerRefNum
330  variable /g adh5_perf_secs
331  timerRefNum = startMSTimer
332 
333  // avoid compilation error if HDF5 XOP has not been loaded
334  #if Exists("HDF5OpenFile")
335  HDF5OpenFile /P=$APathName/R fileID as AFileName
336  if (v_flag == 0)
337  AFileName = s_path + s_filename
338  print "loading " + s_filename + "\r"
339 
340  if (load_attr)
341  newdatafolder /o/s attr
342  adh5_loadattr_all(fileID, attributespath)
343  setdatafolder ::
344  endif
345  if (load_data)
346  adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduction_param, progress=progress)
347  endif
348 
349  HDF5CloseFile fileID
350  else
351  AFileName = ""
352  endif
353  #else
354  Abort "HDF5 XOP not loaded."
355  #endif
356 
357  if (timerRefNum >= 0)
358  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
359  endif
360 
361  setdatafolder saveDF
362  return AFileName
363 };
364 
379 string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
380  string ANickName
381  string APathName
382  string AFileName
383  variable load_data
384  variable load_attr
385 
386  if (ParamIsDefault(load_data))
387  load_data = 1
388  endif
389  if (ParamIsDefault(load_attr))
390  load_attr = 1
391  endif
392 
393  dfref saveDF = GetDataFolderDFR()
394  setdatafolder root:
395  newdatafolder /o/s pearl_area
396  newdatafolder /o/s preview
397 
398  // open file
399  variable fileID
400  string instrumentpath = "/entry/instrument/"
401  string detectorpath = instrumentpath + "detector/"
402  string attributespath = instrumentpath + "NDAttributes/"
403  string datasetname
404  string datawavename
405 
406  // performance monitoring
407  variable timerRefNum
408  variable /g adh5_perf_secs
409  timerRefNum = startMSTimer
410 
411  // avoid compilation error if HDF5 XOP has not been loaded
412  #if Exists("HDF5OpenFile")
413  HDF5OpenFile /P=$APathName/R/Z fileID as AFileName
414  if (v_flag == 0)
415  AFileName = s_path + s_filename
416 
417  // detector data
418  datasetname = detectorpath + "data"
419  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
420  InitHDF5DataInfo(di)
421  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
422  if (err != 0)
423  print "error accessing detector/data"
424  return ""
425  endif
426  if (di.ndims < 2)
427  print "error: rank of dataset < 2"
428  return ""
429  endif
430 
431  variable dim2start = 0, dim2count = 1, dim3start = 0, dim3count = 1
432  if (di.ndims >= 3)
433  dim2start = floor(di.dims[di.ndims - 3] / 2)
434  dim2count = 1
435  endif
436  if (di.ndims >= 4)
437  dim3start = floor(di.dims[di.ndims - 4] / 2)
438  dim3count = 1
439  endif
440 
441  if (load_data)
442  adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, dim3start, dim3count)
443  wave /z data
444  string destpath = GetDataFolder(1, saveDF) + ANickName
445  if (waveexists(data))
446  duplicate /o data, $destpath
447  wave /z data = $destpath
448  endif
449  endif
450 
451  if (load_attr)
452  setdatafolder saveDF
453  newdatafolder /o/s attr
454  killwaves /a/z
455  adh5_loadattr_all(fileID, attributespath)
456  setdatafolder ::
457  if (waveexists(data))
458  adh5_scale(data)
459  endif
460  endif
461 
462  HDF5CloseFile fileID
463  else
464  print "error opening file " + AFileName
465  AFileName = ""
466  endif
467  #else
468  Abort "HDF5 XOP not loaded."
469  #endif
470 
471  if (timerRefNum >= 0)
472  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
473  endif
474 
475  setdatafolder saveDF
476  return AFileName
477 };
478 
489 string adh5_load_info(string APathName, string AFileName){
490  string APathName
491  string AFileName
492 
493  dfref saveDF = GetDataFolderDFR()
494 
495  // open file
496  variable fileID
497  string instrumentpath = "/entry/instrument/"
498  string detectorpath = instrumentpath + "detector/"
499  string attributespath = instrumentpath + "NDAttributes/"
500  string datasetname
501  string datawavename
502 
503  string s_info = ""
504  string s
505 
506  variable idim
507 
508  // avoid compilation error if HDF5 XOP has not been loaded
509  #if Exists("HDF5OpenFile")
510  HDF5OpenFile /P=$APathName/R/Z fileID as AFileName
511  if (v_flag == 0)
512  AFileName = s_path + s_filename
513 
514  // detector data
515  datasetname = detectorpath + "data"
516  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
517  InitHDF5DataInfo(di)
518  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
519  if (err != 0)
520  print "error accessing detector/data"
521  return ""
522  endif
523 
524  for (idim = 0; idim < di.ndims; idim += 1)
525  sprintf s, "dim %u: %u points", idim, di.dims[idim]
526  if (strlen(s_info) > 0)
527  s_info = s_info + "\r" + s
528  else
529  s_info = s
530  endif
531  endfor
532 
533  dfref df = NewFreeDataFolder()
534  setdatafolder df
535  adh5_loadattr_all(fileID, attributespath)
536 
537  for (idim = 1; idim < 5; idim += 1)
538  sprintf s, "Scan%uActive", idim
539  wave /z w = $s
540  if (waveexists(w) && (numpnts(w) > 0) && (w[0] > 0))
541  sprintf s, "Scan%uPositioner1", idim
542  wave /t wt = $s
543  sprintf s, "scan %u: %s", idim, wt[0]
544  if (strlen(s_info) > 0)
545  s_info = s_info + "\r" + s
546  else
547  s_info = s
548  endif
549  endif
550  endfor
551 
552  HDF5CloseFile fileID
553  else
554  print "error opening file " + AFileName
555  AFileName = ""
556  endif
557  #else
558  Abort "HDF5 XOP not loaded."
559  #endif
560 
561  setdatafolder saveDF
562  return s_info
563 };
564 
573 variable adh5_load_detector(variable fileID, string detectorpath){
574  variable fileID
575  string detectorpath
576 
577  // avoid compilation error if HDF5 XOP has not been loaded
578  #if Exists("HDF5LoadData")
579  string datasetname
580  string datawavename
581 
582  // detector data
583  datasetname = detectorpath + "data"
584  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
585  InitHDF5DataInfo(di)
586  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
587  if (err != 0)
588  print "error accessing detector/data"
589  return -1
590  endif
591  if (di.ndims < 2)
592  print "error: rank of dataset < 2"
593  return -2
594  endif
595 
596  HDF5LoadData /O /Q /Z fileID, datasetname
597  wave data
598 
599  #else
600  Abort "HDF5 XOP not loaded."
601  #endif
602 };
603 
618 variable adh5_redim(wave data){
619  wave data
620 
621  duplicate /free data, tempdata
622  variable nd = wavedims(tempdata)
623  variable nx = dimsize(tempdata, nd - 1)
624  variable ny = dimsize(tempdata, nd - 2)
625  variable nz = dimsize(tempdata, nd - 3)
626  variable nt = dimsize(tempdata, nd - 4)
627 
628  switch (nd)
629  case 2:
630  if (nx <= 1)
631  redimension /n=(ny) data
632  setdimlabel 0, -1, AD_Dim1, data
633  data = tempdata[p][0]
634  else if (ny <= 1)
635  redimension /n=(nx) data
636  setdimlabel 0, -1, AD_Dim0, data
637  data = tempdata[0][p]
638  else
639  redimension /n=(nx,ny) data
640  setdimlabel 0, -1, AD_Dim0, data
641  setdimlabel 1, -1, AD_Dim1, data
642  data = tempdata[q][p]
643  endif
644  break
645  case 3:
646  if (nx <= 1)
647  redimension /n=(ny,nz) data
648  setdimlabel 0, -1, AD_Dim1, data
649  setdimlabel 1, -1, AD_DimN, data
650  multithread data = tempdata[q][p][0]
651  else if (ny <= 1)
652  redimension /n=(nx,nz) data
653  setdimlabel 0, -1, AD_Dim0, data
654  setdimlabel 1, -1, AD_DimN, data
655  multithread data = tempdata[q][0][p]
656  else if (nz <= 1)
657  redimension /n=(nx,ny) data
658  setdimlabel 0, -1, AD_Dim0, data
659  setdimlabel 1, -1, AD_Dim1, data
660  multithread data = tempdata[0][q][p]
661  else
662  redimension /n=(nx,ny,nz) data
663  setdimlabel 0, -1, AD_Dim0, data
664  setdimlabel 1, -1, AD_Dim1, data
665  setdimlabel 2, -1, AD_DimN, data
666  multithread data = tempdata[r][q][p]
667  endif
668  break
669  case 4:
670  if (nz <= 1)
671  // singleton "frame number" dimension
672  redimension /n=(nx,ny,nt) data
673  setdimlabel 0, -1, AD_Dim0, data
674  setdimlabel 1, -1, AD_Dim1, data
675  setdimlabel 2, -1, AD_DimX, data
676  multithread data = tempdata[r][0][q][p]
677  else
678  redimension /n=(nx,ny,nz,nt) data
679  setdimlabel 0, -1, AD_Dim0, data
680  setdimlabel 1, -1, AD_Dim1, data
681  setdimlabel 2, -1, AD_DimN, data
682  setdimlabel 3, -1, AD_DimX, data
683  multithread data = tempdata[s][r][q][p]
684  endif
685  break
686  endswitch
687 };
688 
699 static dfr GetAttrDataFolderDFR(wave data){
700  wave data
701 
702  dfref dataDF = GetWavesDataFolderDFR(data)
703  dfref attrDF = dataDF:attr
704  if (DataFolderRefStatus(attrDF) == 0)
705  attrDF = dataDF
706  endif
707 
708  return attrDF
709 };
710 
718 variable adh5_scale(wave data, string source = defaultValue){
719  wave data
720  string source
721 
722  dfref saveDF = GetDataFolderDFR()
723  dfref dataDF = GetWavesDataFolderDFR(data)
724  dfref attrDF = GetAttrDataFolderDFR(data)
725 
726  if (ParamIsDefault(source))
727  // is the source a Scienta analyser?
728  wave /SDFR=attrDF /Z AcquisitionMode
729  wave /SDFR=attrDF /T /Z Manufacturer
730  source = "unknown"
731  if (waveexists(Manufacturer) && (numpnts(Manufacturer) >= 1))
732  strswitch(Manufacturer[0])
733  case "VG Scienta":
734  source = "scienta"
735  break
736  case "Prosilica":
737  source = "prosilica"
738  break
739  endswitch
740  else if (waveexists(AcquisitionMode) && (numpnts(AcquisitionMode) >= 1))
741  if (stringmatch(note(AcquisitionMode), "*SCIENTA*"))
742  source = "scienta"
743  endif
744  endif
745  endif
746 
747  strswitch(source)
748  case "prosilica":
749  // pixel scale - nothing to do
750  break
751  case "scienta":
752  adh5_scale_scienta(data)
753  break
754  endswitch
755 
756  setdatafolder saveDF
757 };
758 
772 variable adh5_load_detector_slabs(variable fileID, string detectorpath, variable progress = defaultValue){
773  variable fileID
774  string detectorpath
775  variable progress
776 
777  if (ParamIsDefault(progress))
778  progress = 1
779  endif
780  variable result = 0
781 
782  // avoid compilation error if HDF5 XOP has not been loaded
783  #if Exists("HDF5LoadData")
784  string datasetname
785  string datawavename
786 
787  // detector data
788  datasetname = detectorpath + "data"
789  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
790  InitHDF5DataInfo(di)
791  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
792  if (err != 0)
793  print "error accessing detector/data"
794  return -1
795  endif
796  if (di.ndims < 2)
797  print "error: rank of dataset < 2"
798  return -2
799  endif
800 
801  // nx and nz are the image dimensions
802  variable idx, idy, idz, idt, izt
803  idx = di.ndims - 1
804  idy = di.ndims - 2
805  idz = -1
806  idt = -1
807 
808  variable nx, ny, nz, nt, nzt
809  nx = di.dims[idx]
810  ny = di.dims[idy]
811  nz = 1
812  nt = 1
813 
814  make /n=(nx,ny,nz,nt) /o data
815  string dim_labels = "AD_Dim0;AD_Dim1;AD_DimN;AD_DimX;AD_DimY"
816  string dim_label
817  dim_label = StringFromList(0, dim_labels, ";")
818  setdimlabel 0, -1, $dim_label, data
819  dim_labels = RemoveFromList(dim_label, dim_labels, ";")
820  dim_label = StringFromList(0, dim_labels, ";")
821  setdimlabel 1, -1, $dim_label, data
822  dim_labels = RemoveFromList(dim_label, dim_labels, ";")
823 
824  // find additional dimensions, ignore singletons
825  variable id
826  for (id = idy - 1; (id >= 0) && (nz == 1); id -= 1)
827  if (di.dims[id] > 1)
828  idz = id
829  nz = di.dims[id]
830  dim_label = StringFromList(0, dim_labels, ";")
831  setdimlabel 2, -1, $dim_label, data
832  endif
833  dim_labels = RemoveListItem(0, dim_labels, ";")
834  endfor
835  for (id = idz - 1; (id >= 0) && (nt == 1); id -= 1)
836  if (di.dims[id] > 1)
837  idt = id
838  nt = di.dims[id]
839  dim_label = StringFromList(0, dim_labels, ";")
840  setdimlabel 3, -1, $dim_label, data
841  endif
842  dim_labels = RemoveListItem(0, dim_labels, ";")
843  endfor
844  redimension /n=(nx,ny,nz,nt) data
845 
846  // default values if dimensions are not present in dataset
847  if (idz < 0)
848  idz = idx + 1
849  idt = idz + 1
850  else if (idt < 0)
851  idt = idx + 1
852  endif
853 
854  nzt = nz * nt
855  izt = 0
856  if (progress)
857  display_progress_panel("HDF5 Import", "Loading data...", nzt)
858  endif
859 
860  // load data image by image
861  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
862  wave slab
863  slab[][%Start] = 0
864  slab[][%Stride] = 1
865  slab[][%Count] = 1
866  slab[][%Block] = 1
867  slab[idx][%Block] = nx
868  slab[idy][%Block] = ny
869 
870  variable iz, it
871  for (iz = 0; iz < nz; iz += 1)
872  for (it = 0; it < nt; it += 1)
873  slab[idz][%Start] = iz
874  slab[idt][%Start] = it
875  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
876  wave slabdata// 2D, 3D, or 4D with singletons
877  switch (WaveDims(slabdata))
878  case 2:
879  data[][][iz][it] = slabdata[q][p]
880  break
881  case 3:
882  data[][][iz][it] = slabdata[0][q][p]
883  break
884  case 4:
885  data[][][iz][it] = slabdata[0][0][q][p]
886  break
887  endswitch
888  // progress window
889  izt += 1
890  if (progress)
891  if (update_progress_panel(izt))
892  result = -4// user abort
893  break
894  endif
895  endif
896  endfor
897  if (result < 0)
898  break
899  endif
900  endfor
901 
902  if (nz == 1)
903  redimension /n=(nx,ny) data
904  else if (nt == 1)
905  redimension /n=(nx,ny,nz) data
906  endif
907 
908  if (progress)
910  endif
911  #else
912  Abort "HDF5 XOP not loaded."
913  #endif
914 
915  return result
916 };
917 
937 variable adh5_load_detector_image(variable fileID, string detectorpath, variable dim2start, variable dim2count, variable dim3start, variable dim3count){
938  variable fileID
939  string detectorpath
940  variable dim2start
941  variable dim2count
942  variable dim3start
943  variable dim3count
944 
945  // avoid compilation error if HDF5 XOP has not been loaded
946  #if Exists("HDF5LoadData")
947  string datasetname
948  string datawavename
949 
950  // detector data
951  datasetname = detectorpath + "data"
952  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
953  InitHDF5DataInfo(di)
954  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
955  if (err != 0)
956  print "error accessing detector/data"
957  return -1
958  endif
959  if (di.ndims < 1)
960  print "error: rank of dataset < 1"
961  return -2
962  endif
963 
964  // nx and nz are the image dimensions
965  variable idx, idy, idz, idt
966  idx = di.ndims - 1
967  idy = di.ndims >= 2 ? di.ndims - 2 : 1
968  idz = di.ndims >= 3 ? di.ndims - 3 : 2
969  idt = di.ndims >= 4 ? di.ndims - 4 : 3
970 
971  variable nx, ny
972  nx = di.dims[idx]
973  ny = di.ndims >= 2 ? di.dims[idy] : 1
974 
975  variable dim2end = dim2start + dim2count - 1
976  variable dim3end = dim3start + dim3count - 1
977 
978  // the slab wave is at least 4-dimensional
979  // it will also load lower-dimensional datasets
980  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
981  wave slab
982  slab[][%Start] = 0
983  slab[][%Stride] = 1
984  slab[][%Count] = 1
985  slab[][%Block] = 1
986  slab[idx][%Block] = nx
987  slab[idy][%Block] = ny
988 
989  make /n=(nx,ny)/o/d data
990  data = 0
991  variable iz, it
992  variable navg = 0
993  for (iz = dim2start; iz <= dim2end; iz += 1)
994  for (it = dim3start; it <= dim3end; it += 1)
995  slab[idz][%Start] = iz
996  slab[idt][%Start] = it
997  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
998  wave slabdata// 2D, 3D, or 4D with singletons
999  switch (WaveDims(slabdata))
1000  case 1:
1001  data += slabdata[p]
1002  navg += 1
1003  break
1004  case 2:
1005  data += slabdata[q][p]
1006  navg += 1
1007  break
1008  case 3:
1009  data += slabdata[0][q][p]
1010  navg += 1
1011  break
1012  case 4:
1013  data += slabdata[0][0][q][p]
1014  navg += 1
1015  break
1016  endswitch
1017  endfor
1018  endfor
1019  data /= navg
1020  setdimlabel 0, -1, AD_Dim0, data
1021  setdimlabel 1, -1, AD_Dim1, data
1022 
1023  #else
1024  Abort "HDF5 XOP not loaded."
1025  #endif
1026 };
1027 
1034  string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:4,VALTYPE:1")
1035  string result = ""
1036 
1037  variable ii
1038  variable nn = ItemsInList(all_funcs, ";")
1039 
1040  string funcname
1041  string info
1042  variable nparams
1043  variable accept
1044 
1045  for (ii = 0; ii < nn; ii += 1)
1046  funcname = StringFromList(ii, all_funcs, ";")
1047  info = FunctionInfo(funcname)
1048  accept = (NumberByKey("RETURNTYPE", info, ":", ";") == 0x0004)
1049  accept = accept && (cmpstr(StringByKey("THREADSAFE", info, ":", ";"), "yes") == 0)
1050  accept = accept && (NumberByKey("N_PARAMS", info, ":", ";") == 4)
1051  accept = accept && (NumberByKey("N_OPT_PARAMS", info, ":", ";") == 0)
1052  if (accept)
1053  // 3 numeric waves and one pass-by-reference string
1054  accept = accept && (NumberByKey("PARAM_0_TYPE", info, ":", ";") == 0x4002)
1055  accept = accept && (NumberByKey("PARAM_1_TYPE", info, ":", ";") == 0x4002)
1056  accept = accept && (NumberByKey("PARAM_2_TYPE", info, ":", ";") == 0x4002)
1057  accept = accept && (NumberByKey("PARAM_3_TYPE", info, ":", ";") == 0x3000)
1058  endif
1059  if (accept)
1060  result = AddListItem(funcname, result, ";")
1061  endif
1062  endfor
1063 
1064  result = SortList(result, ";", 4)
1065  return result
1066 };
1067 
1072 // the resulting wave must have the same size as either dimension of the source image.
1093 threadsafe variable adh5_default_reduction(wave source, wave dest1, wave dest2, string* param){
1094  wave source
1095  wave dest1, dest2
1096  string &param
1097 
1098  // demo code
1099  // integrate along the dimensions
1100  adh5_setup_profile(source, dest1, 0)
1101  ad_profile_x_w(source, 0, -1, dest1)
1102  adh5_setup_profile(source, dest2, 1)
1103  ad_profile_y_w(source, 0, -1, dest2)
1104 
1105  return 0
1106 };
1107 
1113 threadsafe variable adh5_setup_profile(wave image, wave profile, variable dim){
1114  wave image// prototype
1115  wave profile// destination wave
1116  variable dim// which dimension to keep: 0 = X, 1 = Y
1117 
1118  redimension /n=(dimsize(image, dim)) profile
1119  setscale /p x dimoffset(image, dim), dimdelta(image, dim), waveunits(image, dim), profile
1120  setscale d 0, 0, waveunits(image, -1), profile
1121  setdimlabel 0, -1, $getdimlabel(image, dim, -1), profile
1122 };
1123 
1128 string adh5_test_reduction_func(wave source, wave dest1, wave dest2, funcref reduction_func, string reduction_param){
1129  wave source
1130  wave dest1
1131  wave dest2
1132  funcref adh5_default_reduction reduction_func
1133  string reduction_param
1134 
1135  reduction_func(source, dest1, dest2, reduction_param)
1136 
1137  return reduction_param
1138 };
1139 
1162 variable adh5_load_reduced_detector(variable fileID, string detectorpath, funcref reduction_func, string reduction_param, variable progress = defaultValue, variable nthreads = defaultValue){
1163  variable fileID
1164  string detectorpath
1165  funcref adh5_default_reduction reduction_func
1166  string reduction_param
1167  variable progress
1168  variable nthreads
1169 
1170  if (ParamIsDefault(progress))
1171  progress = 1
1172  endif
1173  if (ParamIsDefault(nthreads))
1174  nthreads = -1
1175  endif
1176  variable result = 0
1177 
1178  // avoid compilation error if HDF5 XOP has not been loaded
1179  #if Exists("HDF5LoadData")
1180  string datasetname
1181  string datawavename
1182 
1183  // detector data
1184  datasetname = detectorpath + "data"
1185  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
1186  InitHDF5DataInfo(di)
1187  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
1188  if (err != 0)
1189  print "error accessing detector/data"
1190  return -1
1191  endif
1192  if (di.ndims < 2)
1193  print "error: rank of dataset < 2"
1194  return -2
1195  endif
1196 
1197  // nx and nz are the image dimensions
1198  variable idx, idy, idz, idt
1199  idx = di.ndims - 1
1200  idy = di.ndims - 2
1201  idz = -1
1202  idt = -1
1203 
1204  variable nx, ny, nz, nt
1205  nx = di.dims[idx]
1206  ny = di.dims[idy]
1207  nz = 1
1208  nt = 1
1209 
1210  // find additional dimensions, ignore singletons
1211  variable id
1212  for (id = idy - 1; (id >= 0) && (nz == 1); id -= 1)
1213  if (di.dims[id] > 1)
1214  idz = id
1215  nz = di.dims[id]
1216  endif
1217  endfor
1218  for (id = idz - 1; (id >= 0) && (nt == 1); id -= 1)
1219  if (di.dims[id] > 1)
1220  idt = id
1221  nt = di.dims[id]
1222  endif
1223  endfor
1224  // default values if dimensions are not present in dataset
1225  if (idz < 0)
1226  idz = idx + 1
1227  idt = idz + 1
1228  else if (idt < 0)
1229  idt = idx + 1
1230  endif
1231  variable nzt = nz * nt
1232  variable izt
1233 
1234  // load data image by image
1235  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
1236  wave slab
1237  slab[][%Start] = 0
1238  slab[][%Stride] = 1
1239  slab[][%Count] = 1
1240  slab[][%Block] = 1
1241  slab[idx][%Block] = nx
1242  slab[idy][%Block] = ny
1243 
1244  // set up multi threading
1245  if (nthreads < 0)
1246  nthreads = ThreadProcessorCount
1247  endif
1248  if (nthreads > 0)
1249  variable threadGroupID = ThreadGroupCreate(nthreads)
1250  variable ithread
1251  for (ithread = 0; ithread < nthreads; ithread += 1)
1252  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
1253  endfor
1254  else
1255  make /n=(nzt) /df /free processing_folders
1256  endif
1257 
1258  if (progress)
1259  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
1260  endif
1261 
1262  make /n=(nx,ny)/d image_template
1263  setdimlabel 0, -1, AD_Dim0, image_template
1264  setdimlabel 1, -1, AD_Dim1, image_template
1265  adh5_scale(image_template)
1266 
1267  variable iz, it
1268  string dfname
1269  izt = 0
1270  for (iz = 0; iz < nz; iz += 1)
1271  for (it = 0; it < nt; it += 1)
1272  // load hyperslab
1273  slab[idz][%Start] = iz
1274  slab[idt][%Start] = it
1275  dfname = "processing_" + num2str(izt)
1276  newdatafolder /s $dfname
1277  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
1278 
1279  // send to processing queue
1280  duplicate image_template, image
1281  variable /g r_index = iz
1282  variable /g s_index = it
1283  string /g func_param = reduction_param
1284 
1285  if (nthreads > 0)
1286  WaveClear image
1287  ThreadGroupPutDF threadGroupID, :
1288  else
1289  processing_folders[izt] = GetDataFolderDFR()
1290  make /n=1/d profile1, profile2
1291  wave slabdata
1292  variable /g func_result
1293  func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
1294  WaveClear slabdata, image, profile1, profile2
1295  setdatafolder ::
1296  endif
1297 
1298  izt += 1
1299  // progress window
1300  if (progress)
1301  if (update_progress_panel(izt))
1302  result = -4// user abort
1303  break
1304  endif
1305  endif
1306  endfor
1307  endfor
1308 
1309  killwaves /z slab, image_template
1310  if (progress)
1311  update_progress_panel(0, message="Processing data (step 2 of 2)...")
1312  endif
1313 
1314  dfref dfr
1315  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
1316  if (nthreads > 0)
1317  do
1318  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
1319  if (DatafolderRefStatus(dfr) != 0)
1320  break
1321  endif
1322  if (progress)
1323  if (update_progress_panel(izt))
1324  result = -4// user abort
1325  break
1326  endif
1327  endif
1328  while (1)
1329  else
1330  dfr = processing_folders[izt]
1331  if (progress)
1332  if (update_progress_panel(izt))
1333  result = -4// user abort
1334  break
1335  endif
1336  endif
1337  endif
1338 
1339  if (result != 0)
1340  break
1341  endif
1342 
1343  nvar rr = dfr:r_index
1344  nvar ss = dfr:s_index
1345  nvar func_result = dfr:func_result
1346  wave profile1 = dfr:profile1
1347  wave profile2 = dfr:profile2
1348 
1349  if (func_result == 0)
1350  if (izt == 0)
1351  make /n=(dimsize(profile1, 0), nz, nt)/d/o data1
1352  make /n=(dimsize(profile2, 0), nz, nt)/d/o data2
1353  setdimlabel 0, -1, $getdimlabel(profile1, 0, -1), data1
1354  setdimlabel 0, -1, $getdimlabel(profile2, 0, -1), data2
1355  setscale /p x dimoffset(profile1, 0), dimdelta(profile1, 0), waveunits(profile1, 0), data1
1356  setscale /p x dimoffset(profile2, 0), dimdelta(profile2, 0), waveunits(profile2, 0), data2
1357  setscale d 0, 0, waveunits(profile1, -1), data1
1358  setscale d 0, 0, waveunits(profile2, -1), data2
1359  endif
1360  data1[][rr][ss] = profile1[p]
1361  data2[][rr][ss] = profile2[p]
1362  else
1363  result = -3// dimension reduction error
1364  break
1365  endif
1366  endfor
1367 
1368  if (nthreads > 0)
1369  variable tstatus = ThreadGroupRelease(threadGroupID)
1370  if (tstatus == -2)
1371  result = -5// thread did not terminate properly
1372  endif
1373  else
1374  for (izt = 0; izt < nzt; izt += 1)
1375  KillDataFolder /Z processing_folders[izt]
1376  endfor
1377  endif
1378 
1379  if (result == 0)
1380  if (nz == 1)
1381  redimension /n=(dimsize(data1,0)) data1
1382  redimension /n=(dimsize(data2,0)) data2
1383  else if (nt == 1)
1384  redimension /n=(dimsize(data1,0),nz) data1
1385  redimension /n=(dimsize(data2,0),nz) data2
1386  setdimlabel 1, -1, AD_DimN, data1
1387  setdimlabel 1, -1, AD_DimN, data2
1388  else
1389  setdimlabel 1, -1, AD_DimN, data1
1390  setdimlabel 1, -1, AD_DimN, data2
1391  setdimlabel 2, -1, AD_DimX, data1
1392  setdimlabel 2, -1, AD_DimX, data2
1393  endif
1394  endif
1395  if (progress)
1397  endif
1398 
1399  #else
1400  Abort "HDF5 XOP not loaded."
1401  #endif
1402  return result
1403 };
1404 
1405 threadsafe static variable reduce_slab_worker(funcref reduction_func){
1406  funcref adh5_default_reduction reduction_func
1407  do
1408  // wait for job from main thread
1409  do
1410  dfref dfr = ThreadGroupGetDFR(0, 1000)
1411  if (DataFolderRefStatus(dfr) == 0)
1412  if (GetRTError(2))
1413  return 0// no more jobs
1414  endif
1415  else
1416  break
1417  endif
1418  while (1)
1419 
1420  // get input data
1421  wave slabdata = dfr:slabdata
1422  wave image = dfr:image
1423  svar func_param = dfr:func_param
1424  nvar rr = dfr:r_index
1425  nvar ss = dfr:s_index
1426 
1427  // do the work
1428  newdatafolder /s outDF
1429  make /n=1/d profile1, profile2
1430  variable /g r_index = rr
1431  variable /g s_index = ss
1432  variable /g func_result
1433  func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
1434 
1435  // send output to queue and clean up
1436  WaveClear slabdata, image, profile1, profile2
1437  ThreadGroupPutDF 0, :
1438  KillDataFolder dfr
1439  while (1)
1440 
1441  return 0
1442 };
1443 
1444 threadsafe static variable reduce_slab_image(wave slabdata, wave image, wave profile1, wave profile2, funcref reduction_func, string reduction_param){
1445  wave slabdata
1446  wave image
1447  wave profile1
1448  wave profile2
1449  funcref adh5_default_reduction reduction_func
1450  string reduction_param
1451 
1452  switch (WaveDims(slabdata))
1453  case 2:
1454  image = slabdata[q][p]
1455  break
1456  case 3:
1457  image = slabdata[0][q][p]
1458  break
1459  case 4:
1460  image = slabdata[0][0][q][p]
1461  break
1462  endswitch
1463 
1464  return reduction_func(image, profile1, profile2, reduction_param)
1465 };
1466 
1479 variable adh5_loadattr_all(variable fileID, string attributespath){
1480  variable fileID
1481  string attributespath
1482 
1483  string datasetname
1484  string datawavename
1485 
1486  // avoid compilation error if HDF5 XOP has not been loaded
1487  #if Exists("HDF5LoadData")
1488 
1489  // datasets in NDAttributes group
1490  HDF5ListGroup /F /TYPE=2 fileID, attributespath
1491  string h5datasets = S_HDF5ListGroup
1492  HDF5ListAttributes /TYPE=1 /Z fileID, attributespath
1493  string h5attributes = S_HDF5ListAttributes
1494 
1495  variable nds = ItemsInList(h5datasets, ";")
1496  variable na = ItemsInList(h5attributes, ";")
1497  variable ids
1498  variable idest = 0
1499  variable n_attr
1500  string s_attr
1501  string s_source
1502 
1503  make /n=(nds+na) /t /o IN, ID, IV, IU
1504 
1505  for (ids = 0; ids < nds; ids += 1)
1506  datasetname = StringFromList(ids, h5datasets, ";")
1507  HDF5LoadData /O/Q fileID, datasetname
1508  if (v_flag == 0)
1509  datawavename = StringFromList(0, s_wavenames)
1510  else
1511  datawavename = ""
1512  endif
1513  HDF5LoadData /A="source"/O/Q/TYPE=2 fileID, datasetname
1514  if (v_flag == 0)
1515  wave /t source
1516  s_source = source[0]
1517  else
1518  s_source = ""
1519  endif
1520  read_attribute_info(datawavename, s_source, idest)
1521  endfor
1522 
1523  // attributes of NDAttributes group
1524  if (v_flag == 0)
1525  nds = ItemsInList(h5attributes, ";")
1526  else
1527  nds = 0
1528  endif
1529  for (ids = 0; ids < nds; ids += 1)
1530  datasetname = StringFromList(ids, h5attributes, ";")
1531  HDF5LoadData /A=datasetname/O/Q/TYPE=1 fileID, attributespath
1532  if (v_flag == 0)
1533  datawavename = StringFromList(0, s_wavenames)
1534  read_attribute_info(datawavename, "", idest)// we don't get the source of these attributes
1535  endif
1536  endfor
1537 
1538  redimension /n=(idest) IN, ID, IV, IU
1539  sort {IN, ID}, IN, ID, IV, IU
1540 
1541  killwaves /z source
1542  #else
1543  Abort "HDF5 XOP not loaded."
1544  #endif
1545 
1546 };
1547 
1561 static variable read_attribute_info(string datawavename, string source, variable* idest){
1562  string datawavename// name of the attribute wave in the current folder.
1563  // can be text or numeric.
1564  string source
1565  // source identifier (EPICS name) of the attribute.
1566  variable &idest
1567  // destination index in IN, ID, IV, IU where the results are written.
1568  // the variable is incremented if data was written, otherwise it is left unchanged.
1569  // make sure IN, ID, IV, IU have at least idest + 1 elements.
1570 
1571  wave /t IN
1572  wave /t ID
1573  wave /t IV
1574  wave /t IU
1575 
1576  variable n_attr
1577  string s_attr
1578 
1579  if (exists(datawavename) == 1)
1580  if (strlen(source) > 0)
1581  Note $datawavename, "PV=" + source
1582  endif
1583  switch(WaveType($datawavename, 1))
1584  case 1:// numeric
1585  wave w_attr = $datawavename
1586  n_attr = numpnts(w_attr)
1587  sprintf s_attr, "%.12g", w_attr[0]
1588  break
1589  case 2:// text
1590  wave /t wt_attr = $datawavename
1591  n_attr = numpnts(wt_attr)
1592  s_attr = wt_attr[0]
1593  break
1594  default:// unknown
1595  n_attr = 0
1596  endswitch
1597  if (n_attr == 1)
1598  IN[idest] = source
1599  ID[idest] = datawavename
1600  IV[idest] = s_attr
1601  IU[idest] = ""// we don't get the units
1602  idest += 1
1603  endif
1604  endif
1605 };
1606 
1614 variable adh5_scale_scienta(wave data){
1615  wave data
1616 
1617  dfref saveDF = GetDataFolderDFR()
1618 
1619  dfref dataDF = GetWavesDataFolderDFR(data)
1620  dfref attrDF = GetAttrDataFolderDFR(data)
1621 
1622  wave /SDFR=attrDF LensMode
1623  wave /SDFR=attrDF /Z ChannelBegin, ChannelEnd
1624  wave /SDFR=attrDF /Z SliceBegin, SliceEnd
1625 
1626  variable EDim, ADim
1627  variable ELow, EHigh, ALow, AHigh
1628  string EUnit, AUnit
1629 
1630  // which dimension is angle and which one is energy?
1631  strswitch(GetDimLabel(data, 0, -1))
1632  case "AD_Dim0":
1633  EDim = 0
1634  break
1635  case "AD_Dim1":
1636  EDim = 1
1637  break
1638  default:
1639  EDim = -1
1640  endswitch
1641  strswitch(GetDimLabel(data, 1, -1))
1642  case "AD_Dim0":
1643  ADim = 0
1644  break
1645  case "AD_Dim1":
1646  ADim = 1
1647  break
1648  default:
1649  ADim = -1
1650  endswitch
1651 
1652  // defaults (point scaling)
1653  if (EDim >= 0)
1654  ELow = dimoffset(data, EDim)
1655  EHigh = dimoffset(data, EDim) + dimdelta(data, EDim) * (dimsize(data, EDim) - 1)
1656  EUnit = "eV"
1657  endif
1658  if (ADim >= 0)
1659  ALow = dimoffset(data, ADim)
1660  AHigh = dimoffset(data, ADim) + dimdelta(data, ADim) * (dimsize(data, ADim) - 1)
1661  AUnit = "arb."
1662  endif
1663 
1664  // lens mode can give more detail
1665  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
1666  switch(LensMode[0])
1667  case 1:// Angular45
1668  ALow = -45/2
1669  AHigh = +45/2
1670  AUnit = "°"
1671  break
1672  case 2:// Angular60
1673  ALow = -60/2
1674  AHigh = +60/2
1675  AUnit = "°"
1676  break
1677  endswitch
1678  endif
1679 
1680  // best option if scales are explicit in separate waves
1681  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
1682  ELow = ChannelBegin[0]
1683  EHigh = ChannelEnd[0]
1684  endif
1685  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
1686  ALow = SliceBegin[0]
1687  AHigh = SliceEnd[0]
1688  endif
1689 
1690  // apply new scales
1691  switch(EDim)
1692  case 0:
1693  setscale /i x ELow, EHigh, EUnit, data
1694  break
1695  case 1:
1696  setscale /i y ELow, EHigh, EUnit, data
1697  break
1698  endswitch
1699  switch(ADim)
1700  case 0:
1701  setscale /i x ALow, AHigh, AUnit, data
1702  break
1703  case 1:
1704  setscale /i y ALow, AHigh, AUnit, data
1705  break
1706  endswitch
1707 
1708  setscale d 0, 0, "arb.", data
1709 
1710  setdatafolder saveDF
1711 };
1712 
1719 variable adh5_scale_scan(wave data){
1720  wave data
1721 
1722  dfref saveDF = GetDataFolderDFR()
1723 
1724  dfref dataDF = GetWavesDataFolderDFR(data)
1725  wave /SDFR=dataDF AcquisitionMode, DetectorMode, EnergyMode
1726 
1727  wave /SDFR=dataDF /z Scan1Active, Scan2Active
1728  wave /SDFR=dataDF /t /z Scan1Positioner1, Scan1Readback1
1729  wave /SDFR=dataDF /t /z Scan1Positioner2, Scan1Readback2
1730  wave /SDFR=dataDF /t /z Scan2Positioner1, Scan2Readback1
1731  wave /SDFR=dataDF /t /z Scan2Positioner2, Scan2Readback2
1732 
1733  // TODO : search the data folder for positioner waves,
1734  // i.e. waves with the PV name corresponding to Scan1Positioner1 in their wave note.
1735  wave /z zscale
1736 
1737  strswitch(GetDimLabel(data, 0, -1))
1738  case "AD_DimN":
1739  setscale /i x zscale[0], zscale[numpnts(zscale)-1], "", data
1740  break
1741  endswitch
1742  strswitch(GetDimLabel(data, 1, -1))
1743  case "AD_DimN":
1744  setscale /i y zscale[0], zscale[numpnts(zscale)-1], "", data
1745  break
1746  endswitch
1747  strswitch(GetDimLabel(data, 2, -1))
1748  case "AD_DimN":
1749  setscale /i z zscale[0], zscale[numpnts(zscale)-1], "", data
1750  break
1751  endswitch
1752 
1753  setdatafolder saveDF
1754 };
1755 
string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load a single image from a HDF5 file created by the Area Detector software.
+Go to the documentation of this file.
1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
2 #pragma IgorVersion = 6.2
3 #pragma ModuleName = PearlAreaImport
4 #include <HDF5 Browser>
5 #include "pearl-gui-tools"
6 
7 // copyright (c) 2013-18 Paul Scherrer Institut
8 //
9 // Licensed under the Apache License, Version 2.0 (the "License");
10 // you may not use this file except in compliance with the License.
11 // You may obtain a copy of the License at
12 // http:///www.apache.org/licenses/LICENSE-2.0
13 
33 
38 
41 static variable BeforeFileOpenHook(variable refNum, string fileName, string path, string type, string creator, variable kind){
42  variable refNum, kind
43  string fileName, path, type, creator
44 
45  variable handledOpen = 0
46 
47  //PathInfo $path
48  //string FilePath = s_path + filename
49  string NickName = CleanupName(ParseFilePath(3, FileName, ":", 0, 0), 0)
50  string FileExt = LowerStr(ParseFilePath(4, FileName, ":", 0, 0))
51  string result = ""
52 
53  // override nickname with custom setting
54  svar /z cnn = gsCustomNickName
55  if (svar_exists(cnn))
56  if (exists("gvNickNameIndex") != 2)
57  variable/g gvNickNameIndex = 1
58  endif
59  nvar nni = gvNickNameIndex
60  NickName = cnn + num2str(nni)
61  nni += 1
62  endif
63 
64  if (stringmatch(FileExt, "h5") == 1)
65  result = adh5_load_complete(NickName, path, FileName)
66  endif
67 
68  string/g s_latest_datafile = result
69  string/g s_latest_nickname = nickname
70 
71  handledOpen = strlen(result) > 0
72  if (handledOpen)
73  close refnum
74  endif
75 
76  return handledOpen// 1 tells Igor not to open the file
77 };
78 
105 string ad_suggest_foldername(string filename, variable ignoredate = defaultValue, string sourcename = defaultValue, variable unique = defaultValue){
106  string filename
107  variable ignoredate
108  string sourcename
109  variable unique
110 
111  if (ParamIsDefault(ignoredate))
112  ignoredate = 0
113  endif
114  if (ParamIsDefault(unique))
115  unique = 0
116  endif
117 
118  string basename = ParseFilePath(3, filename, ":", 0, 0)
119  string extension = ParseFilePath(4, filename, ":", 0, 0)
120  string nickname
121 
122  string autosource
123  if (strsearch(basename, "scienta", 0, 2) >= 0)
124  autosource = "sci"
125  else if (strsearch(basename, "pshell", 0, 2) >= 0)
126  autosource = "psh"
127  else if (strsearch(basename, "OP-SL", 0, 2) >= 0)
128  autosource = "sl"
129  else if (strsearch(basename, "ES-PS", 0, 2) >= 0)
130  autosource = "es"
131  else
132  autosource = "xy"
133  endif
134  if (ParamIsDefault(sourcename))
135  sourcename = autosource
136  endif
137 
138  variable nparts = ItemsInList(basename, "-")
139  if (nparts >= 3)
140  string datepart = StringFromList(1, basename, "-")
141  variable l_datepart = strlen(datepart)
142  if (l_datepart == 8)
143  datepart = datepart[l_datepart-6, l_datepart-1]
144  endif
145  string indexpart = StringFromList(2, basename, "-")
146  if (ignoredate)
147  sprintf nickname, "%s_%s", sourcename, indexpart
148  else
149  sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart
150  endif
151  else
152  nickname = CleanupName(basename, 0)
153  endif
154 
155  if (unique && CheckName(nickname, 11))
156  nickname = UniqueName(nickname + "_", 11, 0)
157  endif
158 
159  return nickname
160 };
161 
166 variable ad_load_dialog(string APathName){
167  string APathName
168 
169  variable refNum
170  string message = "Select data files"
171  string filepaths
172  string filefilters = "Area Detector HDF5 Files (*.h5):.h5;"
173  filefilters += "All Files:.*;"
174 
175  PathInfo /S $APathName
176  Open /D /R /F=filefilters /M=message /MULT=1 refNum
177  filepaths = S_fileName
178 
179  dfref saveDF = GetDataFolderDFR()
180  setdatafolder root:
181 
182  if (strlen(filepaths) > 0)
183  variable nfiles = ItemsInList(filepaths, "\r")
184  variable ifile
185  for(ifile = 0; ifile < nfiles; ifile += 1)
186  String path = StringFromList(ifile, filepaths, "\r")
187  string nickname = ad_suggest_foldername(path)
188  adh5_load_complete(nickname, "", path)
189  endfor
190  endif
191 
192  setdatafolder saveDF
193 };
194 
206 string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
207  string ANickName
208  string APathName
209  string AFileName
210  variable load_data
211  variable load_attr
212 
213  if (ParamIsDefault(load_data))
214  load_data = 1
215  endif
216  if (ParamIsDefault(load_attr))
217  load_attr = 1
218  endif
219 
220  dfref saveDF = GetDataFolderDFR()
221  setdatafolder root:
222  newdatafolder /s/o $("root:" + ANickName)
223 
224  // open file
225  variable fileID
226  string instrumentpath = "/entry/instrument/"
227  string detectorpath = instrumentpath + "detector/"
228  string attributespath = instrumentpath + "NDAttributes/"
229  string datasetname
230  string datawavename
231 
232  // performance monitoring
233  variable timerRefNum
234  variable /g adh5_perf_secs
235  timerRefNum = startMSTimer
236 
237  // avoid compilation error if HDF5 XOP has not been loaded
238  #if Exists("HDF5OpenFile")
239  HDF5OpenFile /P=$APathName/R fileID as AFileName
240  if (v_flag == 0)
241  AFileName = s_path + s_filename
242  print "loading " + s_filename + "\r"
243 
244  if (load_data)
245  adh5_load_detector_slabs(fileID, detectorpath)
246  endif
247  if (load_attr)
248  newdatafolder /o/s attr
249  adh5_loadattr_all(fileID, attributespath)
250  setdatafolder ::
251  endif
252 
253  wave /z data
254  if (waveexists(data))
255  //adh5_redim(data) // not to be used with adh5_load_detector_slabs
256  adh5_scale(data)
257  endif
258 
259  HDF5CloseFile fileID
260  else
261  AFileName = ""
262  endif
263  #else
264  Abort "HDF5 XOP not loaded."
265  #endif
266 
267  if (timerRefNum >= 0)
268  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
269  endif
270 
271  setdatafolder saveDF
272  return AFileName
273 };
274 
301 string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data = defaultValue, variable load_attr = defaultValue, variable progress = defaultValue){
302  string ANickName
303  string APathName
304  string AFileName
305 
306  funcref adh5_default_reduction reduction_func
307  string reduction_param
308 
309  variable load_data
310  variable load_attr
311  variable progress
312 
313  if (ParamIsDefault(load_data))
314  load_data = 1
315  endif
316  if (ParamIsDefault(load_attr))
317  load_attr = 1
318  endif
319  if (ParamIsDefault(progress))
320  progress = 1
321  endif
322 
323  dfref saveDF = GetDataFolderDFR()
324  setdatafolder root:
325  newdatafolder /s/o $("root:" + ANickName)
326 
327  // open file
328  variable fileID
329  string instrumentpath = "/entry/instrument/"
330  string detectorpath = instrumentpath + "detector/"
331  string attributespath = instrumentpath + "NDAttributes/"
332  string datasetname
333  string datawavename
334 
335  // performance monitoring
336  variable timerRefNum
337  variable /g adh5_perf_secs
338  timerRefNum = startMSTimer
339 
340  // avoid compilation error if HDF5 XOP has not been loaded
341  #if Exists("HDF5OpenFile")
342  HDF5OpenFile /P=$APathName/R fileID as AFileName
343  if (v_flag == 0)
344  AFileName = s_path + s_filename
345  print "loading " + s_filename + "\r"
346 
347  if (load_attr)
348  newdatafolder /o/s attr
349  adh5_loadattr_all(fileID, attributespath)
350  setdatafolder ::
351  endif
352  if (load_data)
353  adh5_load_reduced_detector(fileID, detectorpath, reduction_func, reduction_param, progress=progress)
354  endif
355 
356  HDF5CloseFile fileID
357  else
358  AFileName = ""
359  endif
360  #else
361  Abort "HDF5 XOP not loaded."
362  #endif
363 
364  if (timerRefNum >= 0)
365  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
366  endif
367 
368  setdatafolder saveDF
369  return AFileName
370 };
371 
386 string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
387  string ANickName
388  string APathName
389  string AFileName
390  variable load_data
391  variable load_attr
392 
393  if (ParamIsDefault(load_data))
394  load_data = 1
395  endif
396  if (ParamIsDefault(load_attr))
397  load_attr = 1
398  endif
399 
400  dfref saveDF = GetDataFolderDFR()
401  setdatafolder root:
402  newdatafolder /o/s pearl_area
403  newdatafolder /o/s preview
404 
405  // open file
406  variable fileID
407  string instrumentpath = "/entry/instrument/"
408  string detectorpath = instrumentpath + "detector/"
409  string attributespath = instrumentpath + "NDAttributes/"
410  string datasetname
411  string datawavename
412 
413  // performance monitoring
414  variable timerRefNum
415  variable /g adh5_perf_secs
416  timerRefNum = startMSTimer
417 
418  // avoid compilation error if HDF5 XOP has not been loaded
419  #if Exists("HDF5OpenFile")
420  HDF5OpenFile /P=$APathName/R/Z fileID as AFileName
421  if (v_flag == 0)
422  AFileName = s_path + s_filename
423 
424  // detector data
425  datasetname = detectorpath + "data"
426  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
427  InitHDF5DataInfo(di)
428  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
429  if (err != 0)
430  print "error accessing detector/data"
431  return ""
432  endif
433  if (di.ndims < 2)
434  print "error: rank of dataset < 2"
435  return ""
436  endif
437 
438  variable dim2start = 0, dim2count = 1, dim3start = 0, dim3count = 1
439  if (di.ndims >= 3)
440  dim2start = floor(di.dims[di.ndims - 3] / 2)
441  dim2count = 1
442  endif
443  if (di.ndims >= 4)
444  dim3start = floor(di.dims[di.ndims - 4] / 2)
445  dim3count = 1
446  endif
447 
448  if (load_data)
449  adh5_load_detector_image(fileID, detectorpath, dim2start, dim2count, dim3start, dim3count)
450  wave /z data
451  string destpath = GetDataFolder(1, saveDF) + ANickName
452  if (waveexists(data))
453  duplicate /o data, $destpath
454  wave /z data = $destpath
455  endif
456  endif
457 
458  if (load_attr)
459  setdatafolder saveDF
460  newdatafolder /o/s attr
461  killwaves /a/z
462  adh5_loadattr_all(fileID, attributespath)
463  setdatafolder ::
464  if (waveexists(data))
465  adh5_scale(data)
466  endif
467  endif
468 
469  HDF5CloseFile fileID
470  else
471  print "error opening file " + AFileName
472  AFileName = ""
473  endif
474  #else
475  Abort "HDF5 XOP not loaded."
476  #endif
477 
478  if (timerRefNum >= 0)
479  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
480  endif
481 
482  setdatafolder saveDF
483  return AFileName
484 };
485 
496 string adh5_load_info(string APathName, string AFileName){
497  string APathName
498  string AFileName
499 
500  dfref saveDF = GetDataFolderDFR()
501 
502  // open file
503  variable fileID
504  string instrumentpath = "/entry/instrument/"
505  string detectorpath = instrumentpath + "detector/"
506  string attributespath = instrumentpath + "NDAttributes/"
507  string datasetname
508  string datawavename
509 
510  string s_info = ""
511  string s
512 
513  variable idim
514 
515  // avoid compilation error if HDF5 XOP has not been loaded
516  #if Exists("HDF5OpenFile")
517  HDF5OpenFile /P=$APathName/R/Z fileID as AFileName
518  if (v_flag == 0)
519  AFileName = s_path + s_filename
520 
521  // detector data
522  datasetname = detectorpath + "data"
523  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
524  InitHDF5DataInfo(di)
525  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
526  if (err != 0)
527  print "error accessing detector/data"
528  return ""
529  endif
530 
531  for (idim = 0; idim < di.ndims; idim += 1)
532  sprintf s, "dim %u: %u points", idim, di.dims[idim]
533  if (strlen(s_info) > 0)
534  s_info = s_info + "\r" + s
535  else
536  s_info = s
537  endif
538  endfor
539 
540  dfref df = NewFreeDataFolder()
541  setdatafolder df
542  adh5_loadattr_all(fileID, attributespath)
543 
544  for (idim = 1; idim < 5; idim += 1)
545  sprintf s, "Scan%uActive", idim
546  wave /z w = $s
547  if (waveexists(w) && (numpnts(w) > 0) && (w[0] > 0))
548  sprintf s, "Scan%uPositioner1", idim
549  wave /t wt = $s
550  sprintf s, "scan %u: %s", idim, wt[0]
551  if (strlen(s_info) > 0)
552  s_info = s_info + "\r" + s
553  else
554  s_info = s
555  endif
556  endif
557  endfor
558 
559  HDF5CloseFile fileID
560  else
561  print "error opening file " + AFileName
562  AFileName = ""
563  endif
564  #else
565  Abort "HDF5 XOP not loaded."
566  #endif
567 
568  setdatafolder saveDF
569  return s_info
570 };
571 
580 variable adh5_load_detector(variable fileID, string detectorpath){
581  variable fileID
582  string detectorpath
583 
584  // avoid compilation error if HDF5 XOP has not been loaded
585  #if Exists("HDF5LoadData")
586  string datasetname
587  string datawavename
588 
589  // detector data
590  datasetname = detectorpath + "data"
591  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
592  InitHDF5DataInfo(di)
593  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
594  if (err != 0)
595  print "error accessing detector/data"
596  return -1
597  endif
598  if (di.ndims < 2)
599  print "error: rank of dataset < 2"
600  return -2
601  endif
602 
603  HDF5LoadData /O /Q /Z fileID, datasetname
604  wave data
605 
606  #else
607  Abort "HDF5 XOP not loaded."
608  #endif
609 };
610 
625 variable adh5_redim(wave data){
626  wave data
627 
628  duplicate /free data, tempdata
629  variable nd = wavedims(tempdata)
630  variable nx = dimsize(tempdata, nd - 1)
631  variable ny = dimsize(tempdata, nd - 2)
632  variable nz = dimsize(tempdata, nd - 3)
633  variable nt = dimsize(tempdata, nd - 4)
634 
635  switch (nd)
636  case 2:
637  if (nx <= 1)
638  redimension /n=(ny) data
639  setdimlabel 0, -1, AD_Dim1, data
640  data = tempdata[p][0]
641  else if (ny <= 1)
642  redimension /n=(nx) data
643  setdimlabel 0, -1, AD_Dim0, data
644  data = tempdata[0][p]
645  else
646  redimension /n=(nx,ny) data
647  setdimlabel 0, -1, AD_Dim0, data
648  setdimlabel 1, -1, AD_Dim1, data
649  data = tempdata[q][p]
650  endif
651  break
652  case 3:
653  if (nx <= 1)
654  redimension /n=(ny,nz) data
655  setdimlabel 0, -1, AD_Dim1, data
656  setdimlabel 1, -1, AD_DimN, data
657  multithread data = tempdata[q][p][0]
658  else if (ny <= 1)
659  redimension /n=(nx,nz) data
660  setdimlabel 0, -1, AD_Dim0, data
661  setdimlabel 1, -1, AD_DimN, data
662  multithread data = tempdata[q][0][p]
663  else if (nz <= 1)
664  redimension /n=(nx,ny) data
665  setdimlabel 0, -1, AD_Dim0, data
666  setdimlabel 1, -1, AD_Dim1, data
667  multithread data = tempdata[0][q][p]
668  else
669  redimension /n=(nx,ny,nz) data
670  setdimlabel 0, -1, AD_Dim0, data
671  setdimlabel 1, -1, AD_Dim1, data
672  setdimlabel 2, -1, AD_DimN, data
673  multithread data = tempdata[r][q][p]
674  endif
675  break
676  case 4:
677  if (nz <= 1)
678  // singleton "frame number" dimension
679  redimension /n=(nx,ny,nt) data
680  setdimlabel 0, -1, AD_Dim0, data
681  setdimlabel 1, -1, AD_Dim1, data
682  setdimlabel 2, -1, AD_DimX, data
683  multithread data = tempdata[r][0][q][p]
684  else
685  redimension /n=(nx,ny,nz,nt) data
686  setdimlabel 0, -1, AD_Dim0, data
687  setdimlabel 1, -1, AD_Dim1, data
688  setdimlabel 2, -1, AD_DimN, data
689  setdimlabel 3, -1, AD_DimX, data
690  multithread data = tempdata[s][r][q][p]
691  endif
692  break
693  endswitch
694 };
695 
706 static dfr GetAttrDataFolderDFR(wave data){
707  wave data
708 
709  dfref dataDF = GetWavesDataFolderDFR(data)
710  dfref attrDF = dataDF:attr
711  if (DataFolderRefStatus(attrDF) == 0)
712  attrDF = dataDF
713  endif
714 
715  return attrDF
716 };
717 
725 variable adh5_scale(wave data, string source = defaultValue){
726  wave data
727  string source
728 
729  dfref saveDF = GetDataFolderDFR()
730  dfref dataDF = GetWavesDataFolderDFR(data)
731  dfref attrDF = GetAttrDataFolderDFR(data)
732 
733  if (ParamIsDefault(source))
734  // is the source a Scienta analyser?
735  wave /SDFR=attrDF /Z AcquisitionMode
736  wave /SDFR=attrDF /T /Z Manufacturer
737  source = "unknown"
738  if (waveexists(Manufacturer) && (numpnts(Manufacturer) >= 1))
739  strswitch(Manufacturer[0])
740  case "VG Scienta":
741  source = "scienta"
742  break
743  case "Prosilica":
744  source = "prosilica"
745  break
746  endswitch
747  else if (waveexists(AcquisitionMode) && (numpnts(AcquisitionMode) >= 1))
748  if (stringmatch(note(AcquisitionMode), "*SCIENTA*"))
749  source = "scienta"
750  endif
751  endif
752  endif
753 
754  strswitch(source)
755  case "prosilica":
756  // pixel scale - nothing to do
757  break
758  case "scienta":
759  adh5_scale_scienta(data)
760  break
761  endswitch
762 
763  setdatafolder saveDF
764 };
765 
779 variable adh5_load_detector_slabs(variable fileID, string detectorpath, variable progress = defaultValue){
780  variable fileID
781  string detectorpath
782  variable progress
783 
784  if (ParamIsDefault(progress))
785  progress = 1
786  endif
787  variable result = 0
788 
789  // avoid compilation error if HDF5 XOP has not been loaded
790  #if Exists("HDF5LoadData")
791  string datasetname
792  string datawavename
793 
794  // detector data
795  datasetname = detectorpath + "data"
796  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
797  InitHDF5DataInfo(di)
798  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
799  if (err != 0)
800  print "error accessing detector/data"
801  return -1
802  endif
803  if (di.ndims < 2)
804  print "error: rank of dataset < 2"
805  return -2
806  endif
807 
808  // nx and nz are the image dimensions
809  variable idx, idy, idz, idt, izt
810  idx = di.ndims - 1
811  idy = di.ndims - 2
812  idz = -1
813  idt = -1
814 
815  variable nx, ny, nz, nt, nzt
816  nx = di.dims[idx]
817  ny = di.dims[idy]
818  nz = 1
819  nt = 1
820 
821  make /n=(nx,ny,nz,nt) /o data
822  string dim_labels = "AD_Dim0;AD_Dim1;AD_DimN;AD_DimX;AD_DimY"
823  string dim_label
824  dim_label = StringFromList(0, dim_labels, ";")
825  setdimlabel 0, -1, $dim_label, data
826  dim_labels = RemoveFromList(dim_label, dim_labels, ";")
827  dim_label = StringFromList(0, dim_labels, ";")
828  setdimlabel 1, -1, $dim_label, data
829  dim_labels = RemoveFromList(dim_label, dim_labels, ";")
830 
831  // find additional dimensions, ignore singletons
832  variable id
833  for (id = idy - 1; (id >= 0) && (nz == 1); id -= 1)
834  if (di.dims[id] > 1)
835  idz = id
836  nz = di.dims[id]
837  dim_label = StringFromList(0, dim_labels, ";")
838  setdimlabel 2, -1, $dim_label, data
839  endif
840  dim_labels = RemoveListItem(0, dim_labels, ";")
841  endfor
842  for (id = idz - 1; (id >= 0) && (nt == 1); id -= 1)
843  if (di.dims[id] > 1)
844  idt = id
845  nt = di.dims[id]
846  dim_label = StringFromList(0, dim_labels, ";")
847  setdimlabel 3, -1, $dim_label, data
848  endif
849  dim_labels = RemoveListItem(0, dim_labels, ";")
850  endfor
851  redimension /n=(nx,ny,nz,nt) data
852 
853  // default values if dimensions are not present in dataset
854  if (idz < 0)
855  idz = idx + 1
856  idt = idz + 1
857  else if (idt < 0)
858  idt = idx + 1
859  endif
860 
861  nzt = nz * nt
862  izt = 0
863  if (progress)
864  display_progress_panel("HDF5 Import", "Loading data...", nzt)
865  endif
866 
867  // load data image by image
868  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
869  wave slab
870  slab[][%Start] = 0
871  slab[][%Stride] = 1
872  slab[][%Count] = 1
873  slab[][%Block] = 1
874  slab[idx][%Block] = nx
875  slab[idy][%Block] = ny
876 
877  variable iz, it
878  for (iz = 0; iz < nz; iz += 1)
879  for (it = 0; it < nt; it += 1)
880  slab[idz][%Start] = iz
881  slab[idt][%Start] = it
882  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
883  wave slabdata// 2D, 3D, or 4D with singletons
884  switch (WaveDims(slabdata))
885  case 2:
886  data[][][iz][it] = slabdata[q][p]
887  break
888  case 3:
889  data[][][iz][it] = slabdata[0][q][p]
890  break
891  case 4:
892  data[][][iz][it] = slabdata[0][0][q][p]
893  break
894  endswitch
895  // progress window
896  izt += 1
897  if (progress)
898  if (update_progress_panel(izt))
899  result = -4// user abort
900  break
901  endif
902  endif
903  endfor
904  if (result < 0)
905  break
906  endif
907  endfor
908 
909  if (nz == 1)
910  redimension /n=(nx,ny) data
911  else if (nt == 1)
912  redimension /n=(nx,ny,nz) data
913  endif
914 
915  if (progress)
917  endif
918  #else
919  Abort "HDF5 XOP not loaded."
920  #endif
921 
922  return result
923 };
924 
944 variable adh5_load_detector_image(variable fileID, string detectorpath, variable dim2start, variable dim2count, variable dim3start, variable dim3count){
945  variable fileID
946  string detectorpath
947  variable dim2start
948  variable dim2count
949  variable dim3start
950  variable dim3count
951 
952  // avoid compilation error if HDF5 XOP has not been loaded
953  #if Exists("HDF5LoadData")
954  string datasetname
955  string datawavename
956 
957  // detector data
958  datasetname = detectorpath + "data"
959  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
960  InitHDF5DataInfo(di)
961  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
962  if (err != 0)
963  print "error accessing detector/data"
964  return -1
965  endif
966  if (di.ndims < 1)
967  print "error: rank of dataset < 1"
968  return -2
969  endif
970 
971  // nx and nz are the image dimensions
972  variable idx, idy, idz, idt
973  idx = di.ndims - 1
974  idy = di.ndims >= 2 ? di.ndims - 2 : 1
975  idz = di.ndims >= 3 ? di.ndims - 3 : 2
976  idt = di.ndims >= 4 ? di.ndims - 4 : 3
977 
978  variable nx, ny
979  nx = di.dims[idx]
980  ny = di.ndims >= 2 ? di.dims[idy] : 1
981 
982  variable dim2end = dim2start + dim2count - 1
983  variable dim3end = dim3start + dim3count - 1
984 
985  // the slab wave is at least 4-dimensional
986  // it will also load lower-dimensional datasets
987  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
988  wave slab
989  slab[][%Start] = 0
990  slab[][%Stride] = 1
991  slab[][%Count] = 1
992  slab[][%Block] = 1
993  slab[idx][%Block] = nx
994  slab[idy][%Block] = ny
995 
996  make /n=(nx,ny)/o/d data
997  data = 0
998  variable iz, it
999  variable navg = 0
1000  for (iz = dim2start; iz <= dim2end; iz += 1)
1001  for (it = dim3start; it <= dim3end; it += 1)
1002  slab[idz][%Start] = iz
1003  slab[idt][%Start] = it
1004  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
1005  wave slabdata// 2D, 3D, or 4D with singletons
1006  switch (WaveDims(slabdata))
1007  case 1:
1008  data += slabdata[p]
1009  navg += 1
1010  break
1011  case 2:
1012  data += slabdata[q][p]
1013  navg += 1
1014  break
1015  case 3:
1016  data += slabdata[0][q][p]
1017  navg += 1
1018  break
1019  case 4:
1020  data += slabdata[0][0][q][p]
1021  navg += 1
1022  break
1023  endswitch
1024  endfor
1025  endfor
1026  data /= navg
1027  setdimlabel 0, -1, AD_Dim0, data
1028  setdimlabel 1, -1, AD_Dim1, data
1029 
1030  #else
1031  Abort "HDF5 XOP not loaded."
1032  #endif
1033 };
1034 
1041  string all_funcs = FunctionList("*", ";", "KIND:6,NPARAMS:2,VALTYPE:8")
1042  string result = ""
1043 
1044  variable ii
1045  variable nn = ItemsInList(all_funcs, ";")
1046 
1047  string funcname
1048  string info
1049  variable nparams
1050  variable accept
1051 
1052  for (ii = 0; ii < nn; ii += 1)
1053  funcname = StringFromList(ii, all_funcs, ";")
1054  info = FunctionInfo(funcname)
1055  accept = (NumberByKey("RETURNTYPE", info, ":", ";") == 0x4000)
1056  accept = accept && (cmpstr(StringByKey("THREADSAFE", info, ":", ";"), "yes") == 0)
1057  accept = accept && (NumberByKey("N_PARAMS", info, ":", ";") == 2)
1058  accept = accept && (NumberByKey("N_OPT_PARAMS", info, ":", ";") == 0)
1059  if (accept)
1060  // one numeric wave and one pass-by-reference string
1061  accept = accept && (NumberByKey("PARAM_0_TYPE", info, ":", ";") == 0x4002)
1062  accept = accept && (NumberByKey("PARAM_1_TYPE", info, ":", ";") == 0x3000)
1063  endif
1064  if (accept)
1065  result = AddListItem(funcname, result, ";")
1066  endif
1067  endfor
1068 
1069  result = SortList(result, ";", 4)
1070  return result
1071 };
1072 
1110 threadsafe wave adh5_default_reduction(wave source, string* param){
1111  wave source
1112  string &param
1113 
1114  // demo code
1115  // integrate along the dimensions
1116  make /n=0 /free dest1, dest2
1117  adh5_setup_profile(source, dest1, 0)
1118  ad_profile_x_w(source, 0, -1, dest1)
1119  adh5_setup_profile(source, dest2, 1)
1120  ad_profile_y_w(source, 0, -1, dest2)
1121 
1122  make /n=2 /free /wave results
1123  results[0] = dest1
1124  results[1] = dest2
1125  return results
1126 };
1127 
1133 threadsafe variable adh5_setup_profile(wave image, wave profile, variable dim){
1134  wave image// prototype
1135  wave profile// destination wave
1136  variable dim// which dimension to keep: 0 = X, 1 = Y
1137 
1138  redimension /n=(dimsize(image, dim)) profile
1139  setscale /p x dimoffset(image, dim), dimdelta(image, dim), waveunits(image, dim), profile
1140  setscale d 0, 0, waveunits(image, -1), profile
1141  setdimlabel 0, -1, $getdimlabel(image, dim, -1), profile
1142 };
1143 
1166 string adh5_test_reduction_func(wave source, funcref reduction_func, string reduction_param, string result_prefix){
1167  wave source
1168  funcref adh5_default_reduction reduction_func
1169  string reduction_param
1170  string result_prefix
1171 
1172  wave /wave results = reduction_func(source, reduction_param)
1173  adh5_get_result_waves(results, result_prefix, 1)
1174 
1175  return reduction_param
1176 };
1177 
1192 threadsafe variable adh5_get_result_waves(wave results, string result_prefix, variable start_index){
1193  wave /wave results
1194  string result_prefix
1195  variable start_index
1196 
1197  variable nw = numpnts(results)
1198  variable iw
1199  string sw
1200  for (iw = 0; iw < nw; iw += 1)
1201  sw = result_prefix + num2str(iw + start_index)
1202  duplicate /o results[iw], $sw
1203  endfor
1204 };
1205 
1228 variable adh5_load_reduced_detector(variable fileID, string detectorpath, funcref reduction_func, string reduction_param, variable progress = defaultValue, variable nthreads = defaultValue){
1229  variable fileID
1230  string detectorpath
1231  funcref adh5_default_reduction reduction_func
1232  string reduction_param
1233  variable progress
1234  variable nthreads
1235 
1236  if (ParamIsDefault(progress))
1237  progress = 1
1238  endif
1239  if (ParamIsDefault(nthreads))
1240  nthreads = -1
1241  endif
1242  variable result = 0
1243 
1244  // avoid compilation error if HDF5 XOP has not been loaded
1245  #if Exists("HDF5LoadData")
1246  string datasetname
1247  string datawavename
1248 
1249  // detector data
1250  datasetname = detectorpath + "data"
1251  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
1252  InitHDF5DataInfo(di)
1253  variable err = HDF5DatasetInfo(fileID, datasetname, 0, di)
1254  if (err != 0)
1255  print "error accessing detector/data"
1256  return -1
1257  endif
1258  if (di.ndims < 2)
1259  print "error: rank of dataset < 2"
1260  return -2
1261  endif
1262 
1263  // nx and nz are the image dimensions
1264  variable idx, idy, idz, idt
1265  idx = di.ndims - 1
1266  idy = di.ndims - 2
1267  idz = -1
1268  idt = -1
1269 
1270  variable nx, ny, nz, nt
1271  nx = di.dims[idx]
1272  ny = di.dims[idy]
1273  nz = 1
1274  nt = 1
1275 
1276  // find additional dimensions, ignore singletons
1277  variable id
1278  for (id = idy - 1; (id >= 0) && (nz == 1); id -= 1)
1279  if (di.dims[id] > 1)
1280  idz = id
1281  nz = di.dims[id]
1282  endif
1283  endfor
1284  for (id = idz - 1; (id >= 0) && (nt == 1); id -= 1)
1285  if (di.dims[id] > 1)
1286  idt = id
1287  nt = di.dims[id]
1288  endif
1289  endfor
1290  // default values if dimensions are not present in dataset
1291  if (idz < 0)
1292  idz = idx + 1
1293  idt = idz + 1
1294  else if (idt < 0)
1295  idt = idx + 1
1296  endif
1297  variable nzt = nz * nt
1298  variable izt
1299 
1300  // load data image by image
1301  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
1302  wave slab
1303  slab[][%Start] = 0
1304  slab[][%Stride] = 1
1305  slab[][%Count] = 1
1306  slab[][%Block] = 1
1307  slab[idx][%Block] = nx
1308  slab[idy][%Block] = ny
1309 
1310  // set up multi threading
1311  if (nthreads < 0)
1312  nthreads = ThreadProcessorCount
1313  endif
1314  if (nthreads > 0)
1315  variable threadGroupID = ThreadGroupCreate(nthreads)
1316  variable ithread
1317  for (ithread = 0; ithread < nthreads; ithread += 1)
1318  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
1319  endfor
1320  else
1321  make /n=(nzt) /df /free processing_folders
1322  endif
1323 
1324  if (progress)
1325  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
1326  endif
1327 
1328  make /n=(nx,ny)/d image_template
1329  setdimlabel 0, -1, AD_Dim0, image_template
1330  setdimlabel 1, -1, AD_Dim1, image_template
1331  adh5_scale(image_template)
1332 
1333  variable iz, it
1334  string dfname
1335  variable iw, nw
1336  string sw
1337  make /n=0 /free /wave result_waves
1338 
1339  izt = 0
1340  for (iz = 0; iz < nz; iz += 1)
1341  for (it = 0; it < nt; it += 1)
1342  // load hyperslab
1343  slab[idz][%Start] = iz
1344  slab[idt][%Start] = it
1345  dfname = "processing_" + num2str(izt)
1346  newdatafolder /s $dfname
1347  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetname
1348 
1349  // send to processing queue
1350  duplicate image_template, image
1351  variable /g r_index = iz
1352  variable /g s_index = it
1353  string /g func_param = reduction_param
1354 
1355  if (nthreads > 0)
1356  WaveClear image
1357  ThreadGroupPutDF threadGroupID, :
1358  else
1359  processing_folders[izt] = GetDataFolderDFR()
1360  wave slabdata
1361  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
1362  variable /g func_result = numpnts(reduced_waves)
1363  adh5_get_result_waves(reduced_waves, "redw_", 0)
1364  WaveClear slabdata, image, reduced_waves
1365  setdatafolder ::
1366  endif
1367 
1368  izt += 1
1369  // progress window
1370  if (progress)
1371  if (update_progress_panel(izt))
1372  result = -4// user abort
1373  break
1374  endif
1375  endif
1376  endfor
1377  endfor
1378 
1379  killwaves /z slab, image_template
1380  if (progress)
1381  update_progress_panel(0, message="Processing data (step 2 of 2)...")
1382  endif
1383 
1384  dfref dfr
1385  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
1386  if (nthreads > 0)
1387  do
1388  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
1389  if (DatafolderRefStatus(dfr) != 0)
1390  break
1391  endif
1392  if (progress)
1393  if (update_progress_panel(izt))
1394  result = -4// user abort
1395  break
1396  endif
1397  endif
1398  while (1)
1399  else
1400  dfr = processing_folders[izt]
1401  if (progress)
1402  if (update_progress_panel(izt))
1403  result = -4// user abort
1404  break
1405  endif
1406  endif
1407  endif
1408 
1409  if (result != 0)
1410  break
1411  endif
1412 
1413  nvar rr = dfr:r_index
1414  nvar ss = dfr:s_index
1415  nvar func_result = dfr:func_result
1416 
1417  if (func_result < 1)
1418  result = -3// dimension reduction error
1419  break
1420  endif
1421 
1422  if (numpnts(result_waves) == 0)
1423  redimension /n=(func_result) result_waves
1424  for (iw = 0; iw < func_result; iw += 1)
1425  sw = "redw_" + num2str(iw)
1426  wave profile = dfr:$sw
1427  sw = "ReducedData" + num2str(iw+1)
1428  make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
1429  wave data = $sw
1430  setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
1431  setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
1432  setscale d 0, 0, waveunits(profile, -1), data
1433  result_waves[iw] = data
1434  endfor
1435  endif
1436  for (iw = 0; iw < func_result; iw += 1)
1437  sw = "redw_" + num2str(iw)
1438  wave profile = dfr:$sw
1439  wave data = result_waves[iw]
1440  data[][rr][ss] = profile[p]
1441  endfor
1442  endfor
1443 
1444  if (nthreads > 0)
1445  variable tstatus = ThreadGroupRelease(threadGroupID)
1446  if (tstatus == -2)
1447  result = -5// thread did not terminate properly
1448  endif
1449  else
1450  for (izt = 0; izt < nzt; izt += 1)
1451  KillDataFolder /Z processing_folders[izt]
1452  endfor
1453  endif
1454 
1455  if (result == 0)
1456  nw = numpnts(result_waves)
1457  for (iw = 0; iw < nw; iw += 1)
1458  wave data = result_waves[iw]
1459  if (nz == 1)
1460  redimension /n=(dimsize(data, 0)) data
1461  else if (nt == 1)
1462  redimension /n=(dimsize(data, 0),nz) data
1463  setdimlabel 1, -1, AD_DimN, data
1464  else
1465  setdimlabel 1, -1, AD_DimN, data
1466  setdimlabel 2, -1, AD_DimX, data
1467  endif
1468  endfor
1469  endif
1470  if (progress)
1472  endif
1473 
1474  #else
1475  Abort "HDF5 XOP not loaded."
1476  #endif
1477  return result
1478 };
1479 
1480 threadsafe static variable reduce_slab_worker(funcref reduction_func){
1481  funcref adh5_default_reduction reduction_func
1482  do
1483  // wait for job from main thread
1484  do
1485  dfref dfr = ThreadGroupGetDFR(0, 1000)
1486  if (DataFolderRefStatus(dfr) == 0)
1487  if (GetRTError(2))
1488  return 0// no more jobs
1489  endif
1490  else
1491  break
1492  endif
1493  while (1)
1494 
1495  // get input data
1496  wave slabdata = dfr:slabdata
1497  wave image = dfr:image
1498  svar func_param = dfr:func_param
1499  nvar rr = dfr:r_index
1500  nvar ss = dfr:s_index
1501 
1502  // do the work
1503  newdatafolder /s outDF
1504  variable /g r_index = rr
1505  variable /g s_index = ss
1506  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
1507  variable /g func_result = numpnts(reduced_waves)
1508 
1509  // send output to queue and clean up
1510  adh5_get_result_waves(reduced_waves, "redw_", 0)
1511  WaveClear slabdata, image, reduced_waves
1512  ThreadGroupPutDF 0, :
1513  KillDataFolder dfr
1514  while (1)
1515 
1516  return 0
1517 };
1518 
1519 threadsafe static wave reduce_slab_image(wave slabdata, wave image, funcref reduction_func, string reduction_param){
1520  wave slabdata
1521  wave image
1522  funcref adh5_default_reduction reduction_func
1523  string reduction_param
1524 
1525  switch (WaveDims(slabdata))
1526  case 2:
1527  image = slabdata[q][p]
1528  break
1529  case 3:
1530  image = slabdata[0][q][p]
1531  break
1532  case 4:
1533  image = slabdata[0][0][q][p]
1534  break
1535  endswitch
1536 
1537  return reduction_func(image, reduction_param)
1538 };
1539 
1552 variable adh5_loadattr_all(variable fileID, string attributespath){
1553  variable fileID
1554  string attributespath
1555 
1556  string datasetname
1557  string datawavename
1558 
1559  // avoid compilation error if HDF5 XOP has not been loaded
1560  #if Exists("HDF5LoadData")
1561 
1562  // datasets in NDAttributes group
1563  HDF5ListGroup /F /TYPE=2 fileID, attributespath
1564  string h5datasets = S_HDF5ListGroup
1565  HDF5ListAttributes /TYPE=1 /Z fileID, attributespath
1566  string h5attributes = S_HDF5ListAttributes
1567 
1568  variable nds = ItemsInList(h5datasets, ";")
1569  variable na = ItemsInList(h5attributes, ";")
1570  variable ids
1571  variable idest = 0
1572  variable n_attr
1573  string s_attr
1574  string s_source
1575 
1576  make /n=(nds+na) /t /o IN, ID, IV, IU
1577 
1578  for (ids = 0; ids < nds; ids += 1)
1579  datasetname = StringFromList(ids, h5datasets, ";")
1580  HDF5LoadData /O/Q fileID, datasetname
1581  if (v_flag == 0)
1582  datawavename = StringFromList(0, s_wavenames)
1583  else
1584  datawavename = ""
1585  endif
1586  HDF5LoadData /A="source"/O/Q/TYPE=2 fileID, datasetname
1587  if (v_flag == 0)
1588  wave /t source
1589  s_source = source[0]
1590  else
1591  s_source = ""
1592  endif
1593  read_attribute_info(datawavename, s_source, idest)
1594  endfor
1595 
1596  // attributes of NDAttributes group
1597  if (v_flag == 0)
1598  nds = ItemsInList(h5attributes, ";")
1599  else
1600  nds = 0
1601  endif
1602  for (ids = 0; ids < nds; ids += 1)
1603  datasetname = StringFromList(ids, h5attributes, ";")
1604  HDF5LoadData /A=datasetname/O/Q/TYPE=1 fileID, attributespath
1605  if (v_flag == 0)
1606  datawavename = StringFromList(0, s_wavenames)
1607  read_attribute_info(datawavename, "", idest)// we don't get the source of these attributes
1608  endif
1609  endfor
1610 
1611  redimension /n=(idest) IN, ID, IV, IU
1612  sort {IN, ID}, IN, ID, IV, IU
1613 
1614  killwaves /z source
1615  #else
1616  Abort "HDF5 XOP not loaded."
1617  #endif
1618 
1619 };
1620 
1634 static variable read_attribute_info(string datawavename, string source, variable* idest){
1635  string datawavename// name of the attribute wave in the current folder.
1636  // can be text or numeric.
1637  string source
1638  // source identifier (EPICS name) of the attribute.
1639  variable &idest
1640  // destination index in IN, ID, IV, IU where the results are written.
1641  // the variable is incremented if data was written, otherwise it is left unchanged.
1642  // make sure IN, ID, IV, IU have at least idest + 1 elements.
1643 
1644  wave /t IN
1645  wave /t ID
1646  wave /t IV
1647  wave /t IU
1648 
1649  variable n_attr
1650  string s_attr
1651 
1652  if (exists(datawavename) == 1)
1653  if (strlen(source) > 0)
1654  Note $datawavename, "PV=" + source
1655  endif
1656  switch(WaveType($datawavename, 1))
1657  case 1:// numeric
1658  wave w_attr = $datawavename
1659  n_attr = numpnts(w_attr)
1660  sprintf s_attr, "%.12g", w_attr[0]
1661  break
1662  case 2:// text
1663  wave /t wt_attr = $datawavename
1664  n_attr = numpnts(wt_attr)
1665  s_attr = wt_attr[0]
1666  break
1667  default:// unknown
1668  n_attr = 0
1669  endswitch
1670  if (n_attr == 1)
1671  IN[idest] = source
1672  ID[idest] = datawavename
1673  IV[idest] = s_attr
1674  IU[idest] = ""// we don't get the units
1675  idest += 1
1676  endif
1677  endif
1678 };
1679 
1687 variable adh5_scale_scienta(wave data){
1688  wave data
1689 
1690  dfref saveDF = GetDataFolderDFR()
1691 
1692  dfref dataDF = GetWavesDataFolderDFR(data)
1693  dfref attrDF = GetAttrDataFolderDFR(data)
1694 
1695  wave /SDFR=attrDF LensMode
1696  wave /SDFR=attrDF /Z ChannelBegin, ChannelEnd
1697  wave /SDFR=attrDF /Z SliceBegin, SliceEnd
1698 
1699  variable EDim, ADim
1700  variable ELow, EHigh, ALow, AHigh
1701  string EUnit, AUnit
1702 
1703  // which dimension is angle and which one is energy?
1704  strswitch(GetDimLabel(data, 0, -1))
1705  case "AD_Dim0":
1706  EDim = 0
1707  break
1708  case "AD_Dim1":
1709  EDim = 1
1710  break
1711  default:
1712  EDim = -1
1713  endswitch
1714  strswitch(GetDimLabel(data, 1, -1))
1715  case "AD_Dim0":
1716  ADim = 0
1717  break
1718  case "AD_Dim1":
1719  ADim = 1
1720  break
1721  default:
1722  ADim = -1
1723  endswitch
1724 
1725  // defaults (point scaling)
1726  if (EDim >= 0)
1727  ELow = dimoffset(data, EDim)
1728  EHigh = dimoffset(data, EDim) + dimdelta(data, EDim) * (dimsize(data, EDim) - 1)
1729  EUnit = "eV"
1730  endif
1731  if (ADim >= 0)
1732  ALow = dimoffset(data, ADim)
1733  AHigh = dimoffset(data, ADim) + dimdelta(data, ADim) * (dimsize(data, ADim) - 1)
1734  AUnit = "arb."
1735  endif
1736 
1737  // lens mode can give more detail
1738  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
1739  switch(LensMode[0])
1740  case 1:// Angular45
1741  ALow = -45/2
1742  AHigh = +45/2
1743  AUnit = ""
1744  break
1745  case 2:// Angular60
1746  ALow = -60/2
1747  AHigh = +60/2
1748  AUnit = ""
1749  break
1750  endswitch
1751  endif
1752 
1753  // best option if scales are explicit in separate waves
1754  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
1755  ELow = ChannelBegin[0]
1756  EHigh = ChannelEnd[0]
1757  endif
1758  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
1759  ALow = SliceBegin[0]
1760  AHigh = SliceEnd[0]
1761  endif
1762 
1763  // apply new scales
1764  switch(EDim)
1765  case 0:
1766  setscale /i x ELow, EHigh, EUnit, data
1767  break
1768  case 1:
1769  setscale /i y ELow, EHigh, EUnit, data
1770  break
1771  endswitch
1772  switch(ADim)
1773  case 0:
1774  setscale /i x ALow, AHigh, AUnit, data
1775  break
1776  case 1:
1777  setscale /i y ALow, AHigh, AUnit, data
1778  break
1779  endswitch
1780 
1781  setscale d 0, 0, "arb.", data
1782 
1783  setdatafolder saveDF
1784 };
1785 
1792 variable adh5_scale_scan(wave data){
1793  wave data
1794 
1795  dfref saveDF = GetDataFolderDFR()
1796 
1797  dfref dataDF = GetWavesDataFolderDFR(data)
1798  wave /SDFR=dataDF AcquisitionMode, DetectorMode, EnergyMode
1799 
1800  wave /SDFR=dataDF /z Scan1Active, Scan2Active
1801  wave /SDFR=dataDF /t /z Scan1Positioner1, Scan1Readback1
1802  wave /SDFR=dataDF /t /z Scan1Positioner2, Scan1Readback2
1803  wave /SDFR=dataDF /t /z Scan2Positioner1, Scan2Readback1
1804  wave /SDFR=dataDF /t /z Scan2Positioner2, Scan2Readback2
1805 
1806  // TODO : search the data folder for positioner waves,
1807  // i.e. waves with the PV name corresponding to Scan1Positioner1 in their wave note.
1808  wave /z zscale
1809 
1810  strswitch(GetDimLabel(data, 0, -1))
1811  case "AD_DimN":
1812  setscale /i x zscale[0], zscale[numpnts(zscale)-1], "", data
1813  break
1814  endswitch
1815  strswitch(GetDimLabel(data, 1, -1))
1816  case "AD_DimN":
1817  setscale /i y zscale[0], zscale[numpnts(zscale)-1], "", data
1818  break
1819  endswitch
1820  strswitch(GetDimLabel(data, 2, -1))
1821  case "AD_DimN":
1822  setscale /i z zscale[0], zscale[numpnts(zscale)-1], "", data
1823  break
1824  endswitch
1825 
1826  setdatafolder saveDF
1827 };
1828 
string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load a single image from a HDF5 file created by the Area Detector software.
variable kill_progress_panel()
variable display_progress_panel(string title, string message, variable progress_max)
-
string adh5_load_info(string APathName, string AFileName)
load descriptive info from a HDF5 file created by the Area Detector software.
-
variable ad_load_dialog(string APathName)
load area detector data files selected in a file dialog window
+
string adh5_load_info(string APathName, string AFileName)
load descriptive info from a HDF5 file created by the Area Detector software.
+
variable ad_load_dialog(string APathName)
load area detector data files selected in a file dialog window
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.
-
static variable read_attribute_info(string datawavename, string source, variable *idest)
sub-function of adh5_loadattr_all.
-
static dfr GetAttrDataFolderDFR(wave data)
find the attributes data folder of an area detector dataset.
-
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.
-
static threadsafe variable reduce_slab_image(wave slabdata, wave image, wave profile1, wave profile2, funcref reduction_func, string reduction_param)
-
variable adh5_scale_scienta(wave data)
set the energy and angle scales of an area detector dataset from the Scienta analyser.
-
string adh5_test_reduction_func(wave source, wave dest1, wave dest2, funcref reduction_func, string reduction_param)
wrapper function for testing reduction functions from the command line.
-
variable adh5_loadattr_all(variable fileID, string attributespath)
load an NDAttributes group from an open HDF5 file into the current data folder.
-
variable adh5_scale_scan(wave data)
scales the extra dimensions of an area detector dataset according to the EPICS scan ...
-
threadsafe variable adh5_default_reduction(wave source, wave dest1, wave dest2, string *param)
function prototype for adh5_load_reduced_detector
-
string ad_suggest_foldername(string filename, variable ignoredate=defaultValue, string sourcename=defaultValue, variable unique=defaultValue)
generate the name of a data folder based on a file name.
+
static variable read_attribute_info(string datawavename, string source, variable *idest)
sub-function of adh5_loadattr_all.
+
static dfr GetAttrDataFolderDFR(wave data)
find the attributes data folder of an area detector dataset.
+
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.
+
threadsafe variable adh5_get_result_waves(wave results, string result_prefix, variable start_index)
copy waves from wave reference wave into current data folder
+
variable adh5_scale_scienta(wave data)
set the energy and angle scales of an area detector dataset from the Scienta analyser.
+
string adh5_test_reduction_func(wave source, funcref reduction_func, string reduction_param, string result_prefix)
wrapper function for testing reduction functions from the command line.
+
variable adh5_loadattr_all(variable fileID, string attributespath)
load an NDAttributes group from an open HDF5 file into the current data folder.
+
variable adh5_scale_scan(wave data)
scales the extra dimensions of an area detector dataset according to the EPICS scan ...
+
string ad_suggest_foldername(string filename, variable ignoredate=defaultValue, string sourcename=defaultValue, variable unique=defaultValue)
generate the name of a data folder based on a file name.
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.
-
string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
import everything from a HDF5 file created by the Area Detector software.
-
variable adh5_load_reduced_detector(variable fileID, string detectorpath, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
load a reduced detector dataset from the open HDF5 file.
-
string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data=defaultValue, variable load_attr=defaultValue, variable progress=defaultValue)
load and reduce a dataset from a HDF5 file created by the Area Detector software. ...
-
variable adh5_redim(wave data)
redimension a multi-dimensional area detector array loaded from HDF5.
-
variable adh5_load_detector_slabs(variable fileID, string detectorpath, variable progress=defaultValue)
load the detector dataset from the open HDF5 file.
-
variable adh5_scale(wave data, string source=defaultValue)
set the dimension scales of an area detector dataset.
+
string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
import everything from a HDF5 file created by the Area Detector software.
+
variable adh5_load_reduced_detector(variable fileID, string detectorpath, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
load a reduced detector dataset from the open HDF5 file.
+
string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data=defaultValue, variable load_attr=defaultValue, variable progress=defaultValue)
load and reduce a dataset from a HDF5 file created by the Area Detector software. ...
+
variable adh5_redim(wave data)
redimension a multi-dimensional area detector array loaded from HDF5.
+
threadsafe wave adh5_default_reduction(wave source, string *param)
function prototype for adh5_load_reduced_detector
+
variable adh5_load_detector_slabs(variable fileID, string detectorpath, variable progress=defaultValue)
load the detector dataset from the open HDF5 file.
+
variable adh5_scale(wave data, string source=defaultValue)
set the dimension scales of an area detector dataset.
variable update_progress_panel(variable progress, string message=defaultValue, variable progress_max=defaultValue)
-
variable adh5_load_detector(variable fileID, string detectorpath)
load the detector dataset from the open HDF5 file.
-
static variable BeforeFileOpenHook(variable refNum, string fileName, string path, string type, string creator, variable kind)
callback function for drag&drop of HDF5 files into Igor.
-
string adh5_list_reduction_funcs()
get a list of functions which can be used as reduction functions.
-
variable adh5_load_detector_image(variable fileID, string detectorpath, variable dim2start, variable dim2count, variable dim3start, variable dim3count)
load a single image from the detector dataset of the open HDF5 file
-
static threadsafe variable reduce_slab_worker(funcref reduction_func)
+
variable adh5_load_detector(variable fileID, string detectorpath)
load the detector dataset from the open HDF5 file.
+
static threadsafe wave reduce_slab_image(wave slabdata, wave image, funcref reduction_func, string reduction_param)
+
static variable BeforeFileOpenHook(variable refNum, string fileName, string path, string type, string creator, variable kind)
callback function for drag&drop of HDF5 files into Igor.
+
string adh5_list_reduction_funcs()
get a list of functions which can be used as reduction functions.
+
variable adh5_load_detector_image(variable fileID, string detectorpath, variable dim2start, variable dim2count, variable dim3start, variable dim3count)
load a single image from the detector dataset of the open HDF5 file
+
static threadsafe variable reduce_slab_worker(funcref reduction_func)
-

Definition at line 88 of file pearl-arpes.ipf.

+

Definition at line 90 of file pearl-arpes.ipf.

@@ -208,7 +209,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
-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 = PearlArpes
4 #pragma version = 1.04
5 #include "pearl-area-display"// 2D and 3D data visualization
6 #include "pearl-area-profiles"// data processing for multi-dimensional datasets
7 #include "pearl-area-import"// import data files generated by area detector software
8 #include "pearl-pshell-import"
9 #include "pearl-data-explorer"// preview and import panel for PEARL data
10 #include "pearl-anglescan-process"
11 #include "pearl-anglescan-tracker"// live preview of hemispherical angle scan
12 #include "pearl-scienta-preprocess"// pre-processing functions for Scienta detector images
13 #include "pearl-elog"
14 #if exists("pvOpen")
15 #include "pearl-area-live"// live view of area detector
16 #include "pearl-epics"// EPICS access under Igor
17 #include "pearl-arpes-scans"// run ARPES scans under Igor
18 #endif
19 
20 // $Id$
21 //
22 // author: matthias.muntwiler@psi.ch
23 // Copyright (c) 2012-15 Paul Scherrer Institut
24 //
25 // Licensed under the Apache License, Version 2.0 (the "License");
26 // you may not use this file except in compliance with the License.
27 // You may obtain a copy of the License at
28 // http://www.apache.org/licenses/LICENSE-2.0
29 
48 
54 
79 
81 static variable AfterCompiledHook(){
82 
83  dfref savefolder = GetDataFolderDFR()
84 
85  return 0
86 };
87 
89  execute /p/q/z "DELETEINCLUDE \"pearl-arpes\""
90  execute /p/q/z "COMPILEPROCEDURES "
91 };
92 
variable UnloadPearlArpesPackage()
Definition: pearl-arpes.ipf:88
-
static variable AfterCompiledHook()
initializes package data once when the procedure is first loaded
Definition: pearl-arpes.ipf:81
+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 = PearlArpes
4 #pragma version = 1.05
5 #include "pearl-area-display"// 2D and 3D data visualization
6 #include "pearl-area-profiles"// data processing for multi-dimensional datasets
7 #include "pearl-area-import"// import data files generated by area detector software
8 #include "pearl-pshell-import"
9 #include "pearl-data-explorer"// preview and import panel for PEARL data
10 #include "pearl-anglescan-process"// angle scan (XPD) processing functions
11 #include "pearl-anglescan-panel"// panel interface to angle scan processing
12 #include "pearl-anglescan-tracker"// live preview of hemispherical angle scan
13 #include "pearl-scienta-preprocess"// pre-processing functions for Scienta detector images
14 #include "pearl-elog"
15 #if exists("pvOpen")
16 #include "pearl-area-live"// live view of area detector
17 #include "pearl-epics"// EPICS access under Igor
18 #include "pearl-arpes-scans"// run ARPES scans under Igor
19 #endif
20 
21 // $Id$
22 //
23 // author: matthias.muntwiler@psi.ch
24 // Copyright (c) 2012-15 Paul Scherrer Institut
25 //
26 // Licensed under the Apache License, Version 2.0 (the "License");
27 // you may not use this file except in compliance with the License.
28 // You may obtain a copy of the License at
29 // http://www.apache.org/licenses/LICENSE-2.0
30 
49 
55 
81 
83 static variable AfterCompiledHook(){
84 
85  dfref savefolder = GetDataFolderDFR()
86 
87  return 0
88 };
89 
91  execute /p/q/z "DELETEINCLUDE \"pearl-arpes\""
92  execute /p/q/z "COMPILEPROCEDURES "
93 };
94 
variable UnloadPearlArpesPackage()
Definition: pearl-arpes.ipf:90
+
static variable AfterCompiledHook()
initializes package data once when the procedure is first loaded
Definition: pearl-arpes.ipf:83
-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 = PearlDataExplorer
4 #pragma version = 1.50
5 #include "pearl-area-import"
6 #include "pearl-area-profiles"
7 #include "pearl-area-display"
8 #include "pearl-pshell-import"
9 #if exists("MFR_OpenResultFile")
10 #include "pearl-matrix-import"
11 #endif
12 
13 // copyright (c) 2013-16 Paul Scherrer Institut
14 //
15 // Licensed under the Apache License, Version 2.0 (the "License");
16 // you may not use this file except in compliance with the License.
17 // You may obtain a copy of the License at
18 // http:///www.apache.org/licenses/LICENSE-2.0
19 
30 
35 
36 static const string package_name = "pearl_explorer";
37 static const string package_path = "root:packages:pearl_explorer:";
38 
39 static const string ks_filematch_adh5 = "*.h5";
40 static const string ks_filematch_pshell = "psh*.h5";
41 static const string ks_filematch_itx = "*.itx";
42 static const string ks_filematch_mtrx = "*_mtrx";
43 
45  init_package()
46  load_prefs()
47  execute /q/z "PearlDataExplorer()"
48 };
49 
55 static variable init_package(){
56 
57  dfref savefolder = GetDataFolderDFR()
58  SetDataFolder root:
59  newdatafolder /o/s packages
60  newdatafolder /o/s $package_name
61  if (exists("v_InitPanelDone") == 2)
62  SetDataFolder savefolder
63  return 0
64  endif
65 
66  make /o/n=0/t wtFiles
67  make /o/n=0/i wSelectedFiles,wSelectedDatasets
68  make /o/n=0/t wtDatasets
69  make /o/n=0/t wtPositioners,wtDetectors
70  make /o/n=0/i wSelectedPositioners,wSelectedDetectors
71 
72  make /o/n=(1,1) preview_image// preview 2D data
73  make /o/n=0 preview_trace// preview 1D data
74  make /o/n=0/t attr_names, attr_values, attr_filter, attr_filter_summary
75 
76  // persistent strings and variables. persistent = saved in preferences
77  string /g s_filepath = ""// directory path to be listed
78  string /g s_hdf_options = ""// recently used HDF5 load options
79  string /g s_reduction_params = ""// recently used reduction parameters
80  string /g s_preview_pvs = ""// semicolon-separated list of EPICS PVs to display in preview.
81  // the list items can contain wildcards for StringMatch
82  s_preview_pvs = "*OP:CURRENT*;*Stats*Total*;*CADC*"
83 
84  // non-persistent strings and variables
85  string /g s_preview_file = ""// file or folder name of the current preview
86  string /g s_preview_source = ""// data source, e.g. EPICS channel name, of the current preview
87  string /g s_profiles_graph = ""// window name of the current preview if the data is two-dimensional
88  string /g s_preview_trace_graph = ""// window name of the current preview if the data is one-dimensional
89  string /g s_file_info = ""// description of selected file
90 
91  variable/g v_InitPanelDone = 1
92 
93  SetDataFolder savefolder
94 };
95 
96 static variable save_prefs(){
97  // saves persistent package data to the preferences file
98  // the data saved in the file are: data file path, attributes filter
99  dfref saveDF = GetDataFolderDFR()
100 
101  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
102  fullPath += package_name
103  NewPath/O/C/Q tempPackagePrefsPath, fullPath
104  fullPath += ":preferences.pxp"
105 
106  SetDataFolder root:packages
107  SetDataFolder $package_name
108  string objects = "attr_filter;attr_filter_summary;s_filepath;s_hdf_options;s_reduction_params;s_preview_pvs"
109  SaveData /O /Q /J=objects fullPath
110 
111  KillPath/Z tempPackagePrefsPath
112 
113  SetDataFolder saveDF
114 };
115 
116 static variable load_prefs(){
117  // loads persistent package data from the preferences file
118  // the preferences file is an Igor packed experiment file in a special preferences folder
119  dfref saveDF = GetDataFolderDFR()
120 
121  variable result = -1
122  setdatafolder root:
123  NewDataFolder /O/S packages
124  NewDataFolder /O/S $package_name
125  dfref packageDF = GetDataFolderDFR()
126  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
127  fullPath += package_name
128 
129  GetFileFolderInfo /Q /Z fullPath
130  if (V_Flag == 0)// Disk directory exists?
131  fullPath += ":preferences.pxp"
132  GetFileFolderInfo /Q /Z fullPath
133  if (V_Flag == 0)// Preference file exist?
134  LoadData /O /R /Q fullPath
135  result = 0
136  endif
137  endif
138 
139  if (result == 0)
140  svar /sdfr=packageDF filepath = s_filepath
141  NewPath /O/Z pearl_explorer_filepath, filepath
144  endif
145 
146  SetDataFolder saveDF
147  return result
148 };
149 
161 static variable pearl_file_type(string filename){
162  string filename
163 
164  if (StringMatch(filename, ks_filematch_pshell))
165  return 1
166  else if (StringMatch(filename, ks_filematch_adh5))
167  return 2
168  else if (StringMatch(filename, ks_filematch_itx))
169  return 3
170 #if exists("MFR_OpenResultFile")
171  else if (StringMatch(filename, ks_filematch_mtrx))
172  return 4
173 #endif
174  else
175  return 0
176  endif
177 };
178 
184 static variable update_filelist(){
185  dfref saveDF = GetDataFolderDFR()
186 
187  string all_files
188  wave /t wtFiles = $(package_path + "wtFiles")
189  wave wSelectedFiles = $(package_path + "wSelectedFiles")
190  variable nn
191 
192  PathInfo pearl_explorer_filepath
193  if (v_flag == 1)
194  all_files = IndexedFile(pearl_explorer_filepath, -1, "????")
195  nn = ItemsInList(all_files)
196  else
197  all_files = ""
198  nn = 0
199  endif
200 
201  make /n=(nn) /t /free wtAllFiles
202  wtAllFiles = StringFromList(p, all_files)
203  Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p])
204  Sort /A /R wtFiles, wtFiles
205 
206  redimension /n=(numpnts(wtFiles)) wSelectedFiles
207  wSelectedFiles = 0
208 
209  setdatafolder saveDF
210 };
211 
212 static variable update_datasets(){
213  // updates the list of imported datasets.
214  // a dataset means any top-level data folder
215  // which includes a string variable named pearl_explorer_import.
216  dfref saveDF = GetDataFolderDFR()
217 
218  setdatafolder root:
219  dfref rootdf = GetDataFolderDFR()
220  setdatafolder $package_path
221  dfref privatedf = GetDataFolderDFR()
222 
223  wave /t wtDatasets
224  wave wSelectedDatasets
225  variable maxdf = CountObjectsDFR(rootdf, 4)
226  redimension /n=(maxdf) wtDatasets
227 
228  variable idf = 0
229  variable ndf = 0
230  string sdf
231 
232  do
233  sdf = GetIndexedObjNameDFR(rootdf, 4, idf)
234  if (strlen(sdf) >= 1)
235  setdatafolder rootdf
236  setdatafolder $sdf
237  svar /z importer = pearl_explorer_import
238  if (svar_exists(importer))
239  wtDatasets[ndf] = sdf
240  ndf += 1
241  endif
242  else
243  break
244  endif
245  idf += 1
246  while(1)
247 
248  redimension /n=(ndf) wtDatasets, wSelectedDatasets
249  wSelectedDatasets = 0
250  sort wtDatasets, wtDatasets
251 
252  setdatafolder saveDF
253 };
254 
255 static variable preview_file(string filename){
256  string filename
257 
258  dfref saveDF = GetDataFolderDFR()
259 
260  variable ft = pearl_file_type(filename)
261  switch(ft)
262  case 1:
263  wave /z image = preview_pshell_file(filename)
264  break
265  case 2:
266  wave /z image = preview_hdf_file(filename)
267  break
268  case 3:
269  wave /z image = preview_itx_file(filename)
270  break
271  case 4:
272  wave /z image = preview_mtrx_file(filename)
273  break
274  default:
275  wave /z image = $""
276  endswitch
277 
278  if (WaveExists(image))
279  string graphname = show_preview_graph(image)
280  // preset ELOG panel - if available
281  if (exists("PearlElog#set_panel_attributes") == 6)
282  string cmd
283  sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"File=%s\")", ParseFilePath(0, filename, ":", 1, 0)
284  execute /Q/Z cmd
285  if (strlen(graphname) > 0)
286  sprintf cmd, "PearlElog#set_panel_graphs(\"\", \"%s\")", graphname
287  execute /Q/Z cmd
288  endif
289  endif
290  endif
291 
292  setdatafolder saveDF
293  return 0
294 };
295 
307 static wave preview_pshell_file(string filename){
308  string filename
309 
310  dfref saveDF = GetDataFolderDFR()
311 
312  setdatafolder $package_path
313  dfref previewDF = GetDataFolderDFR()
314  svar s_preview_file
315  svar s_preview_source
316  svar /z s_file_info
317  if (! svar_exists(s_file_info))
318  string /g s_file_info
319  endif
320 
321  dfref tempDF = NewFreeDataFolder()
322  setdatafolder tempDF
323  string dataname
324  dataname = psh5_load_preview("pearl_explorer_filepath", filename)
325 
326  s_preview_file = filename
327  s_preview_source = ""
328 
329  wave /z data = $dataname
330  if (waveexists(data))
331  duplicate /o data, previewDF:preview_image
332  else
333  print "no data found in file " + filename
334  endif
335 
336  if (strlen(s_preview_file) > 0)
337  s_file_info = psh5_load_info("pearl_explorer_filepath", filename)
338  else
339  s_file_info = ""
340  endif
341 
342  dfref attrDF = tempDF:attr
343  if (DataFolderRefStatus(attrDF))
344  preview_attributes(attrDF)
345  endif
346 
347  setdatafolder saveDF
348  wave /z /sdfr=previewDF preview_image
349  return preview_image
350 };
351 
363 static wave preview_hdf_file(string filename){
364  string filename
365 
366  dfref saveDF = GetDataFolderDFR()
367  setdatafolder $package_path
368  svar s_preview_file
369  svar s_preview_source
370  adh5_load_preview("preview_image", "pearl_explorer_filepath", filename)
371  s_preview_file = filename
372  s_preview_source = ""
373  wave /z preview_image
374 
375  svar /z s_file_info
376  if (! svar_exists(s_file_info))
377  string /g s_file_info
378  endif
379  if (strlen(s_preview_file) > 0)
380  s_file_info = adh5_load_info("pearl_explorer_filepath", filename)
381  else
382  s_file_info = ""
383  endif
384 
385  if (DataFolderExists("attr"))
386  setdatafolder attr
387  preview_attributes(GetDataFolderDFR())
388  setdatafolder ::
389  endif
390 
391  setdatafolder saveDF
392  return preview_image
393 };
394 
395 static wave preview_itx_file(string filename){
396  string filename
397 
398  dfref saveDF = GetDataFolderDFR()
399  setdatafolder $package_path
400  svar s_preview_file
401  svar s_preview_source
402  wave preview_image
403 
404  // note: some versions of PEARL data files save data to a new data folder,
405  // and leave the newly created folder as the current folder.
406  // the free data folder is used by those files which don't create their own data folder.
407  // this is the new recommended behaviour
408  dfref dataDF = newfreedatafolder()
409  setdatafolder dataDF
410  LoadWave /t/p=pearl_explorer_filepath/q filename
411  s_preview_file = s_filename
412  s_preview_source = ""
413 
415  preview_attributes(dataDF, include_datawaves=0)
416 
417  setdatafolder saveDF
418  return preview_image
419 };
420 
435 static wave preview_mtrx_file(string filename){
436  string filename
437 
438 #if exists("MFR_OpenResultFile")
439  dfref saveDF = GetDataFolderDFR()
440  setdatafolder $package_path
441  variable /g V_MatrixFileReaderOverwrite = 1
442  variable /g V_MatrixFileReaderFolder = 0
443  variable /g V_MatrixFileReaderDouble = 0
444  svar s_preview_file
445  svar s_preview_source
446  string datanames
447  string dataname
448  datanames = mtrx_load_preview("preview", "pearl_explorer_filepath", filename)
449  if (strlen(datanames) > 0)
450  s_preview_file = filename
451 
452  dataname = StringFromList(0, datanames)
453  wave data = $dataname
454  duplicate /o $dataname, preview_image
455  s_preview_source = StringByKey("Dataset", note(data), "=", "\r")
456 
457  svar /z s_file_info
458  if (svar_exists(s_file_info))
459  s_file_info = ""
460  endif
461 
462  variable i
463  variable n = ItemsInList(datanames)
464  string s
465  for (i = 0; i < n; i += 1)
466  s = StringFromList(i, datanames)
467  killwaves /z $s
468  endfor
469  endif
470  wave /z preview_image
471  setdatafolder saveDF
472 #else
473  wave /z preview_image = $""
474 #endif
475  return preview_image
476 };
477 
478 static variable extract_preview_image(wave data, wave preview){
479  // extracts a preview image from a wave of arbitrary dimension
480  wave data
481  wave preview
482 
483  variable z1, z2
484 
485  // extract image
486  switch (WaveDims(data))
487  case 1:
488  redimension /n=(numpnts(data)) preview
489  preview = data[p]
490  break
491  case 2:
492  redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview
493  preview = data
494  break
495  case 3:
496  redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview
497  z1 = floor(DimSize(data, 2) / 2)
498  z2 = z1
499  wave slab = ad_extract_slab(data, nan, nan, nan, nan, z1, z2, "", pscale=1)
500  preview = slab
501  break
502  case 4:
503  // not implemented
504  endswitch
505 
506  switch (WaveDims(data))
507  case 4:
508  case 3:
509  case 2:
510  setscale /p y dimoffset(data, 1), dimdelta(data, 1), waveunits(data, 1), preview
511  case 1:
512  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), preview
513  setscale d 0, 0, waveunits(data, -1), preview
514  endswitch
515 };
516 
517 static variable preview_dataset(string datasetname){
518  string datasetname// name of a data folder under root
519 
520  dfref saveDF = GetDataFolderDFR()
521 
522  if (!DataFolderExists("root:" + datasetname))
523  return -1
524  endif
525  setdatafolder root:
526  setdatafolder $datasetname
527  dfref datadf = GetDataFolderDFR()
528  wave /z data
529 
530  setdatafolder $package_path
531  svar s_preview_file
532  svar s_preview_source
533  wave preview_image
534  if (WaveExists(data))
535  s_preview_file = datasetname
536  s_preview_source = ""
537  extract_preview_image(data, preview_image)
538  show_preview_graph(preview_image)
539  else
540  preview_image = nan
541  s_preview_file = datasetname
542  setdatafolder datadf
544  show_preview_graph(preview_image)
545  endif
546 
547  // attributes
548  setdatafolder datadf
549  if (DataFolderExists("attr"))
550  setdatafolder attr
551  preview_attributes(GetDataFolderDFR())
552  else
553  preview_attributes(GetDataFolderDFR(), include_datawaves=0)
554  endif
555 
556  setdatafolder saveDF
557  return 0
558 };
559 
560 static variable preview_datafolder(){
561  // preview data in the current data folder
562  dfref saveDF = GetDataFolderDFR()
563 
564  setdatafolder $package_path
565  svar s_preview_file
566  svar s_preview_source
567  svar s_preview_pvs
568  wave preview_image
569 
570  setdatafolder saveDF
571 
572  // select a wave to display
573  // consider only double-precision waves, i.e. ignore text and other special waves
574  // filter by matching PV name to s_preview_pvs
575  string d_names = WaveList("*", ";", "DP:1")
576  variable nw = ItemsInList(d_names, ";")
577  variable npv = ItemsInList(s_preview_pvs, ";")
578  variable iw, ipv
579  string wname, wnote, pv_name, pv_match
580  for (iw = 0; iw < nw; iw += 1)
581  wname = StringFromList(iw, d_names, ";")
582  wnote = note($wname)
583  pv_name = StringByKey("PV", wnote, "=", "\r")
584  // find matching data wave by PV name
585  for (ipv = 0; ipv < npv; ipv += 1)
586  pv_match = StringFromList(ipv, s_preview_pvs)
587  if (StringMatch(pv_name, pv_match))
588  wave data = $wname
589  s_preview_source = pv_name
590  extract_preview_image(data, preview_image)
591  preview_setscale_x(data, preview_image)
592  npv = 0
593  nw = 0
594  endif
595  endfor
596  endfor
597 
598  setdatafolder saveDF
599 };
600 
601 static variable preview_setscale_x(wave data, wave preview){
602  // sets the approximate x scale of OTF data.
603  // requires an Axis1 tag with name of x wave in the wave note.
604  // if any of these conditions is true, the function does not change the scaling:
605  // 1) Axis1 tag or referenced wave is missing.
606  // 2) preview wave is not set to point scaling.
607  // 3) x wave is not monotonic (90% of the steps in the same direction).
608  wave data
609  wave preview
610 
611  if ((DimOffset(preview, 0) == 0) && (DimDelta(preview, 0) == 1))
612  string xname = StringByKey("Axis1", note(data), "=", "\r")
613  wave /z xwave = $xname
614  if (WaveExists(xwave))
615  // check for monotonicity
616  variable monotonic = 0
617  duplicate /free xwave, xdiff
618  differentiate /p xwave /D=xdiff
619  duplicate /free xdiff, xflag
620  xflag = xdiff > 0
621  monotonic = sum(xflag) > numpnts(xwave) * 0.9
622  xflag = xdiff < 0
623  monotonic = monotonic || (sum(xflag) > numpnts(xwave) * 0.9)
624  if (monotonic)
625  setscale /i x xwave[0], xwave[numpnts(xwave)-1], waveunits(xwave, -1), preview
626  endif
627  endif
628  endif
629 };
630 
631 static variable preview_attributes(dfref attr_folder, dfref dest_folder = defaultValue, wave attr_filter = defaultValue, variable include_datawaves = defaultValue, variable include_infowaves = defaultValue){
632  // copies the first elements of attributes in the specified folder to the preview waves
633  // by default, all existing attributes are copied
634  // if a text wave attr_filter exists in the pear_explorer folder, only the attributes referenced therein are copied
635  // to set up a filter, duplicate the attr_names wave of a template dataset, and remove unwanted items
636  dfref attr_folder// data folder which contains the attribute waves
637  dfref dest_folder// destination folder. the output is written to the attr_names and attr_values waves
638  // default = package folder
639  wave /t attr_filter// list of attributes allowed in the output
640  // default = use attr_filter of package folder
641  variable include_datawaves// 1 (default) = include data waves (any numeric wave which has a PV=name note)
642  // 0 = don't include attributes from data waves
643  variable include_infowaves// 1 (default) = include attributes from info waves (IN, ID, IV, IU)
644  // 0 = don't include attributes from info waves
645 
646  dfref saveDF = GetDataFolderDFR()
647  setdatafolder $package_path
648 
649  if (ParamIsDefault(dest_folder))
650  dest_folder = GetDataFolderDFR()// package folder
651  endif
652  if (ParamIsDefault(attr_filter))
653  wave /t /z attr_filter
654  endif
655  if (ParamIsDefault(include_datawaves))
656  include_datawaves = 1
657  endif
658  if (ParamIsDefault(include_infowaves))
659  include_infowaves = 1
660  endif
661 
662  setdatafolder dest_folder
663  wave /t /z attr_names, attr_values
664  if (!WaveExists(attr_names) || !WaveExists(attr_values))
665  make /n=(1) /o /t attr_names, attr_values
666  endif
667  attr_names = ""
668  attr_values = ""
669 
670  setdatafolder attr_folder
671  wave /t /z IN
672  wave /t /z ID
673  wave /t /z IV
674  wave /t /z IU
675 
676  // compile list of attributes
677  variable nattr// destination attributes
678  variable iattr
679  variable ninfo// info wave elements
680  variable iinfo
681  variable nw// attribute waves
682  variable iw
683  string sw
684  string ss
685 
686  if (WaveExists(IN) && include_infowaves)
687  ninfo = numpnts(IN)
688  else
689  ninfo = 0
690  endif
691  if (include_datawaves)
692  string waves = WaveList("*", ";", "")
693  string exceptions = "ID;IN;IU;IV"
694  waves = RemoveFromList(exceptions, waves)
695  nw = ItemsInList(waves, ";")
696  else
697  nw = 0
698  endif
699 
700  if (WaveExists(attr_filter) && (numpnts(attr_filter) >= 1))
701  nattr = numpnts(attr_filter)
702  redimension /n=(nattr) attr_names
703  attr_names = attr_filter
704  else
705  if(ninfo > 0)
706  redimension /n=(ninfo) attr_names
707  attr_names = SelectString(strlen(ID[p]) >= 0, IN[p], ID[p])// use ID unless empty
708  endif
709 
710  nattr = ninfo + nw
711  iattr = ninfo
712  redimension /n=(nattr) attr_names
713  for (iw = 0; iw < nw; iw +=1 )
714  sw = StringFromList(iw, waves, ";")
715  ss = StringByKey("PV", note($sw), "=", "\r")
716  FindValue /text=sw attr_names
717  if ((v_value < 0) && (strlen(ss) >= 0))
718  attr_names[iattr] = sw
719  iattr += 1
720  endif
721  endfor
722  nattr = iattr
723  endif
724  redimension /n=(nattr) attr_names, attr_values
725  sort attr_names, attr_names
726 
727  // look up attribute values
728  for (iattr = 0; iattr < nattr; iattr += 1)
729  sw = attr_names[iattr]
730  // try info waves
731  if (ninfo > 0)
732  FindValue /text=sw ID
733  if (v_value >= 0)
734  attr_values[iattr] = IV[v_value]
735  endif
736  FindValue /text=sw IN
737  if (v_value >= 0)
738  attr_values[iattr] = IV[v_value]
739  endif
740  endif
741 
742  // override from attribute wave if existent
743  if (nw > 0)
744  switch (WaveType($sw, 1))
745  case 1:// numeric
746  wave /z w = $sw
747  if (WaveExists(w) && (numpnts(w) >= 1))
748  sprintf ss, "%g", w[0]
749  attr_values[iattr] = ss
750  endif
751  break
752  case 2:// text
753  wave /t/z wt = $sw
754  if (WaveExists(wt) && (numpnts(wt) >= 1))
755  attr_values[iattr] = wt[0]
756  endif
757  break
758  endswitch
759  endif
760  endfor
761 
762  setdatafolder saveDF
763 };
764 
765 static variable display_dataset(string datasetname){
766  // displays the graph of a loaded dataset in its own window
767  string datasetname// name of a data folder under root
768 
769  dfref saveDF = GetDataFolderDFR()
770 
771  if (!DataFolderExists("root:" + datasetname))
772  return -1
773  endif
774  setdatafolder root:
775  setdatafolder $datasetname
776  dfref datadf = GetDataFolderDFR()
777  wave /z data
778  if (!WaveExists(data))
779  wave /z data = data1
780  endif
781 
782  if (WaveExists(data))
783  switch(WaveDims(data))
784  case 2:
785  ad_display_profiles(data)
786  break
787  case 3:
788  ad_display_slice(data)
789  ad_brick_slicer(data)
790  break
791  endswitch
792  endif
793 
794  setdatafolder saveDF
795  return 0
796 };
797 
799  dfref df = GetDataFolderDFR()
800  wave /t /sdfr=df attr_names
801  wave /t /sdfr=df attr_values
802  attributes_notebook(attr_names, attr_values, GetDataFolder(0))
803 };
804 
805 static variable attributes_notebook(wave attr_names, wave attr_values, string title){
806  wave /t attr_names
807  wave /t attr_values
808  string title
809 
810  dfref saveDF = GetDataFolderDFR()
811  setdatafolder $package_path
812  wave /t/z attr_filter, attr_filter_summary
813 
814  string name = CleanupName("nb_" + title[0,28], 0)
815  if (WinType(name) == 5)
816  Notebook $name selection={startOfFile, endOfFile}
817  Notebook $name text=""
818  else
819  NewNotebook /F=1 /K=1 /N=$name as title
820  GetWindow $name wsize
821  v_right = v_left + 260
822  v_bottom = v_top + 360
823  MoveWindow /W=$name v_left, v_top, v_right, v_bottom
824  Notebook $name tabs={2*72}
825  endif
826 
827  // summary
828  if (WaveExists(attr_filter_summary) && (numpnts(attr_filter_summary) >= 1))
829  notebook $name fStyle=1, text="Summary\r\r"
830  notebook $name fStyle=0
831  notebook_add_attributes(name, attr_filter_summary, attr_names, attr_values)
832  notebook $name text="\r"
833  endif
834 
835  // all attributes
836  notebook $name fStyle=1, text="All Attributes\r\r"
837  notebook $name fStyle=0
838  notebook_add_attributes(name, $"", attr_names, attr_values)
839  notebook $name selection={startOfFile,startOfFile}, findText={"",1}
840 
841  setdatafolder saveDF
842 };
843 
844 static variable notebook_add_attributes(string notebook_name, wave attr_filter, wave attr_names, wave attr_values){
845  string notebook_name
846  wave /t /z attr_filter
847  wave /t attr_names
848  wave /t attr_values
849 
850  variable nw = numpnts(attr_names)
851  variable iw
852  string sw
853  string ss
854 
855  variable do_filter = WaveExists(attr_filter)
856 
857  for (iw = 0; iw < nw; iw += 1)
858  if (do_filter)
859  sw = attr_names[iw]
860  FindValue /text=sw attr_filter
861  else
862  v_value = 0
863  endif
864  if (v_value >= 0)
865  sprintf ss, "%s\t%s\r", attr_names[iw], attr_values[iw]
866  notebook $notebook_name text=ss
867  endif
868  endfor
869 };
870 
871 static string show_preview_graph(wave data, wave xdata = defaultValue){
872  // displays a preview of one- or two-dimensional data
873  wave data// data to be displayed. must either one-dimensional or two-dimensional
874  wave xdata// positions on x axis
875 
876  dfref saveDF = GetDataFolderDFR()
877  setdatafolder $package_path
878 
879  svar s_profiles_graph
880  svar s_preview_file
881  svar s_preview_source
882  svar s_preview_trace_graph
883 
884  if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1))
885  KillWindow $s_profiles_graph
886  endif
887  if ((strlen(s_preview_trace_graph) > 0) && (WinType(s_preview_trace_graph) == 1))
888  KillWindow $s_preview_trace_graph
889  endif
890 
891  string graphname
892  if (wavedims(data) == 2)
893  s_profiles_graph = ad_display_profiles(data)
894  ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
895  graphname = s_profiles_graph
896  else if (wavedims(data) == 1)
897  duplicate /o data, preview_trace
898  if (!ParamIsDefault(xdata))
899  duplicate /o xdata, preview_trace_x
900  else
901  duplicate /o data, preview_trace_x
902  preview_trace_x = x
903  setscale d 0, 0, WaveUnits(data, 0), preview_trace_x
904  endif
905  s_preview_trace_graph = display_preview_trace(preview_trace_x, preview_trace)
906  ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
907  graphname = s_preview_trace_graph
908  else
909  return ""
910  endif
911 
912  string title = "Preview " + s_preview_file
913  if (strlen(s_preview_source) > 0)
914  title = title + " (" + s_preview_source[0,31] + ")"
915  endif
916  dowindow /f/t $graphname, title
917 
918  setdatafolder saveDF
919  return graphname
920 };
921 
922 static string display_preview_trace(wave xtrace, wave ytrace){
923  wave xtrace
924  wave ytrace
925 
926  display /n=pearl_explorer_1d /k=1 ytrace vs xtrace as "Preview"
927  string graphname = s_name
928  ModifyGraph /w=$graphname rgb[0]=(0,0,0)
929  ModifyGraph /w=$graphname grid=2
930  ModifyGraph /w=$graphname mirror=1
931  ModifyGraph /w=$graphname minor=1
932  ModifyGraph /w=$graphname axThick=0.5
933  ModifyGraph /w=$graphname gridRGB=(52224,52224,52224)
934  ModifyGraph /w=$graphname gridHair=0
935  ModifyGraph /w=$graphname tick=0
936  ModifyGraph /w=$graphname btLen=4
937 
938  // axis labels
939  string labels = note(ytrace)
940  string lab
941  lab = StringByKey("AxisLabelX", labels, "=", "\r")
942  if (!strlen(lab))
943  lab = "X"
944  endif
945  Label /w=$graphname bottom lab + " (\\U)"
946  lab = StringByKey("AxisLabelD", labels, "=", "\r")
947  if (!strlen(lab))
948  lab = "value"
949  endif
950  Label /w=$graphname left lab + " (\\U)"
951 
952  return s_name
953 };
954 
955 static variable load_selected_files(string options = defaultValue){
956  string options
957 
958  dfref saveDF = GetDataFolderDFR()
959  setdatafolder $package_path
960 
961  wave wSelectedFiles
962  wave/t wtFiles
963  variable nn = numpnts(wSelectedFiles)
964  variable ii
965  for (ii = 0; ii < nn; ii += 1)
966  if (wSelectedFiles[ii])
967  if (ParamIsDefault(options))
968  load_file(wtFiles[ii])
969  else
970  load_file(wtFiles[ii], options=options)
971  endif
972  endif
973  endfor
974 
976  setdatafolder saveDF
977 };
978 
979 static variable load_file(string filename, string options = defaultValue){
980  string filename
981  string options
982 
983  dfref saveDF = GetDataFolderDFR()
984 
985  variable ft = pearl_file_type(filename)
986  switch(ft)
987  case 1:
988  if (ParamIsDefault(options))
989  load_pshell_file(filename)
990  else
991  load_pshell_file(filename, options=options)
992  endif
993  break
994  case 2:
995  if (ParamIsDefault(options))
996  load_hdf_file(filename)
997  else
998  load_hdf_file(filename, options=options)
999  endif
1000  break
1001  case 3:
1002  load_itx_file(filename)
1003  break
1004  case 4:
1005  load_mtrx_file(filename)
1006  break
1007  default:
1008  break
1009  endswitch
1010 
1011  setdatafolder saveDF
1012 };
1013 
1014 static variable prompt_hdf_options(string* options){
1015  string &options
1016 
1017  string mode = StringByKey("mode", options, ":", ";")
1018  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1019 
1020  string modes = "load_reduced"
1021  string reduction_functions = adh5_list_reduction_funcs()
1022 
1023  if (strlen(mode) == 0)
1024  mode = StringFromList(0, modes, ";")
1025  endif
1026  if (strlen(reduction_func) == 0)
1027  reduction_func = StringFromList(0, reduction_functions, ";")
1028  endif
1029 
1030  prompt mode, "Mode", popup, modes
1031  prompt reduction_func, "Reduction Function", popup, reduction_functions
1032  doprompt "HDF5 Loading Options", mode, reduction_func
1033 
1034  if (v_flag == 0)
1035  options = ReplaceStringByKey("mode", options, mode, ":", ";")
1036  options = ReplaceStringByKey("reduction_func", options, reduction_func, ":", ";")
1037  endif
1038  return v_flag// 0 = OK, 1 = cancel
1039 };
1040 
1053 variable prompt_default_process(string* param){
1054  string &param
1055 
1056  return 0
1057 };
1058 
1059 variable prompt_func_params(string func_name, string* func_param){
1060  string func_name
1061  string &func_param
1062 
1063  string prompt_name = "prompt_" + func_name
1064  if (exists(prompt_name) == 6)
1065  funcref prompt_default_process prompt_func = $prompt_name
1066  return prompt_func(func_param)
1067  else
1068  // ignore missing prompt function
1069  return 0
1070  endif
1071 };
1072 
1073 static dfr load_pshell_file(string filename, string options = defaultValue){
1074  string filename
1075  string options
1076 
1077  dfref saveDF = GetDataFolderDFR()
1078  string nickname = ad_suggest_foldername(filename)
1079  string loaded_filename = ""
1080 
1081  if (ParamIsDefault(options))
1082  loaded_filename = psh5_load_complete(nickname, "pearl_explorer_filepath", filename)
1083  else
1084  if (strlen(options) == 0)
1085  svar pref_options = $(package_path + "s_hdf_options")
1086  options = pref_options
1087  if (prompt_hdf_options(options) == 0)
1088  // OK
1089  pref_options = options
1090  else
1091  // cancel
1092  options = ""
1093  endif
1094  endif
1095 
1096  string mode = StringByKey("mode", options, ":", ";")
1097 
1098  strswitch(mode)
1099  case "load_reduced":
1100  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1101  svar pref_params = $(package_path + "s_reduction_params")
1102  string reduction_params = pref_params
1103  if (prompt_func_params(reduction_func, reduction_params) == 0)
1104  pref_params = reduction_params
1105  print reduction_func, reduction_params
1106  psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
1107  svar s_filepath
1108  loaded_filename = s_filepath
1109  endif
1110  break
1111  endswitch
1112  endif
1113 
1114  dfref dataDF
1115  if (strlen(loaded_filename) > 0)
1116  setdatafolder $("root:" + nickname)
1117  dataDF = GetDataFolderDFR()
1118  string /g pearl_explorer_import = "load_pshell_file"
1119  endif
1120 
1121  setdatafolder saveDF
1122  return dataDF
1123 };
1124 
1125 static dfr load_hdf_file(string filename, string options = defaultValue){
1126  string filename
1127  string options
1128 
1129  dfref saveDF = GetDataFolderDFR()
1130  string nickname = ad_suggest_foldername(filename)
1131  string loaded_filename = ""
1132 
1133  if (ParamIsDefault(options))
1134  loaded_filename = adh5_load_complete(nickname, "pearl_explorer_filepath", filename)
1135  else
1136  if (strlen(options) == 0)
1137  svar pref_options = $(package_path + "s_hdf_options")
1138  options = pref_options
1139  if (prompt_hdf_options(options) == 0)
1140  // OK
1141  pref_options = options
1142  else
1143  // cancel
1144  options = ""
1145  endif
1146  endif
1147 
1148  string mode = StringByKey("mode", options, ":", ";")
1149 
1150  strswitch(mode)
1151  case "load_reduced":
1152  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1153  svar pref_params = $(package_path + "s_reduction_params")
1154  string reduction_params = pref_params
1155  if (prompt_func_params(reduction_func, reduction_params) == 0)
1156  pref_params = reduction_params
1157  print reduction_func, reduction_params
1158  loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
1159  endif
1160  break
1161  endswitch
1162  endif
1163 
1164  dfref dataDF
1165  if (strlen(loaded_filename) > 0)
1166  setdatafolder $("root:" + nickname)
1167  dataDF = GetDataFolderDFR()
1168  string /g pearl_explorer_import = "load_hdf_file"
1169  endif
1170 
1171  setdatafolder saveDF
1172  return dataDF
1173 };
1174 
1175 static dfr load_itx_file(string filename, string options = defaultValue){
1176  string filename
1177  string options
1178 
1179  dfref saveDF = GetDataFolderDFR()
1180  string nickname = itx_suggest_foldername(filename)
1181 
1182  if (ParamIsDefault(options))
1183  options = ""
1184  endif
1185 
1186  setdatafolder root:
1187  newdatafolder /s/o $("root:" + nickname)
1188  dfref dataDF = GetDataFolderDFR()
1189 
1190  // note: some versions of PEARL data files save data to a new data folder,
1191  // and leave the newly created folder as the current folder.
1192  // the free data folder is used by those files which don't create their own data folder.
1193  // this is the new recommended behaviour
1194 
1195  LoadWave /t/p=pearl_explorer_filepath/q filename
1196  svar waves = s_wavenames
1197  dfref actDF = GetDataFolderDFR()
1198  if (v_flag > 0)
1199  string /g pearl_explorer_import = "load_itx_file"
1200  endif
1201 
1202  if (!DataFolderRefsEqual(actDF, dataDF))
1203  // the file created its own data folder.
1204  // let's kill the pre-allocated folder
1205  setdatafolder dataDF
1206  if (ItemsInList(WaveList("*", ";", ""), ";") == 0)
1207  killdatafolder /z dataDF
1208  endif
1209  endif
1210 
1211  setdatafolder saveDF
1212  return actDF
1213 };
1214 
1218 static dfr load_mtrx_file(string filename, string options = defaultValue){
1219  string filename
1220  string options
1221 
1222  dfref saveDF = GetDataFolderDFR()
1223  dfref dataDF = $""
1224 
1225 #if exists("MFR_OpenResultFile")
1226  setdatafolder root:
1227  string datasets = ""
1228  datasets = mtrx_load_file("pearl_explorer_filepath", filename)
1229  if (strlen(datasets) > 0)
1230  string /g pearl_explorer_import = "load_mtrx_file"
1231  string s1 = StringFromList(0, datasets)
1232  wave w1 = $s1
1233  dataDF = GetWavesDataFolderDFR(w1)
1234  endif
1235 #endif
1236 
1237  setdatafolder saveDF
1238  return dataDF
1239 };
1240 
1241 string itx_suggest_foldername(string filename, variable ignoredate = defaultValue, string sourcename = defaultValue, variable unique = defaultValue){
1242  // suggests the name of a data folder based on a file name
1243  // if the file name follows the naming convention source-date-index.extension,
1244  // the function tries to generate the nick name as source_date_index.
1245  // otherwise it's just a cleaned up version of the file name.
1246  string filename// file name, including extension. can also include a folder path (which is ignored)
1247  // the extension is currently ignored, but may be used later to select the parent folder
1248  variable ignoredate// if non-zero, the nick name will not include the date part
1249  // defaults to zero
1250  string sourcename// nick name of the data source
1251  // the function tries to detect the source from the file name
1252  // this option can be used to override auto-detection
1253  // allowed values: sscan, otf
1254  variable unique// if non-zero, the resulting name is made a unique data folder name in the current data folder
1255  // defaults to zero
1256 
1257  if (ParamIsDefault(ignoredate))
1258  ignoredate = 0
1259  endif
1260  if (ParamIsDefault(unique))
1261  unique = 0
1262  endif
1263 
1264  string basename = ParseFilePath(3, filename, ":", 0, 0)
1265  string extension = ParseFilePath(4, filename, ":", 0, 0)
1266  string nickname
1267 
1268  string autosource
1269  if (strsearch(basename, "X03DA_PC", 0, 2) >= 0)
1270  autosource = "sscan"
1271  basename = ReplaceString("_", basename, "-")
1272  ignoredate = 1
1273  else if (strsearch(basename, "otf", 0, 2) >= 0)
1274  autosource = "otf"
1275  endif
1276  if (ParamIsDefault(sourcename))
1277  sourcename = autosource
1278  endif
1279 
1280  variable nparts = ItemsInList(basename, "-")
1281  if (nparts >= 3)
1282  string datepart = StringFromList(nparts - 2, basename, "-")
1283  string indexpart = StringFromList(nparts - 1, basename, "-")
1284  if (ignoredate)
1285  sprintf nickname, "%s_%s", sourcename, indexpart
1286  else
1287  sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart
1288  endif
1289  else
1290  nickname = CleanupName(basename, 0)
1291  endif
1292 
1293  if (unique && CheckName(nickname, 11))
1294  nickname = UniqueName(nickname + "_", 11, 0)
1295  endif
1296 
1297  return nickname
1298 };
1299 
1301  PauseUpdate; Silent 1// building window...
1302  NewPanel /K=1 /W=(800,0,1530,444) as "PEARL Data Explorer"
1303  ModifyPanel cbRGB=(48640,56832,60160)
1304 
1305  GroupBox gb_filepath,pos={8,4},size={224,52},title="file system folder"
1306  TitleBox tb_filepath,pos={20,24},size={174,20},frame=2
1307  TitleBox tb_filepath,variable=root:packages:pearl_explorer:s_filepath,fixedSize=1
1308  Button b_browse_filepath,pos={200,24},size={20,20},proc=PearlDataExplorer#bp_browse_filepath,title="..."
1309  Button b_browse_filepath,fColor=(65280,48896,32768)
1310 
1311  GroupBox gb_prefs,pos={240,4},size={58,52},title="prefs",help={"explorer package preferences"}
1312  Button b_save_prefs,pos={252,20},size={32,17},proc=PearlDataExplorer#bp_save_prefs,title="save"
1313  Button b_save_prefs,help={"save preferences of the data explorer package (data file path, attributes filter)"}
1314  Button b_save_prefs,fColor=(65280,48896,32768)
1315  Button b_load_prefs,pos={252,36},size={32,17},proc=PearlDataExplorer#bp_load_prefs,title="load"
1316  Button b_load_prefs,help={"load preferences of the data explorer package"}
1317  Button b_load_prefs,fColor=(65280,48896,32768)
1318 
1319  GroupBox gb_filelist,pos={8,64},size={224,372},title="data files"
1320  ListBox lb_files,pos={20,84},size={200,212},proc=PearlDataExplorer#lbp_filelist
1321  ListBox lb_files,listWave=root:packages:pearl_explorer:wtFiles
1322  ListBox lb_files,selWave=root:packages:pearl_explorer:wSelectedFiles,row= 11,mode= 4
1323  TitleBox tb_file_info,pos={20,300},size={198,78},frame=2,fixedSize=1
1324  TitleBox tb_file_info,variable= root:packages:pearl_explorer:s_file_info
1325 
1326  Button b_update_filelist,pos={20,386},size={60,20},proc=PearlDataExplorer#bp_update_filelist,title="update list"
1327  Button b_update_filelist,fColor=(65280,48896,32768)
1328  CheckBox cb_file_preview,pos={84,390},size={60,20},title="preview"
1329  CheckBox cb_file_preview,help={"enable/disable automatic preview window when selecting a data file"}
1330  CheckBox cb_file_preview,value=1
1331  Button b_file_prev,pos={176,386},size={20,20},proc=PearlDataExplorer#bp_file_prev,title="\\W646"
1332  Button b_file_prev,help={"previous file"}
1333  Button b_file_prev,fColor=(65280,48896,32768)
1334  Button b_file_next,pos={200,386},size={20,20},proc=PearlDataExplorer#bp_file_next,title="\\W649"
1335  Button b_file_next,help={"next file"}
1336  Button b_file_next,fColor=(65280,48896,32768)
1337 
1338  Button b_load_files,pos={20,410},size={76,20},proc=PearlDataExplorer#bp_load_files,title="load complete"
1339  Button b_load_files,help={"load the complete contents from the selected files"}
1340  Button b_load_files,fColor=(65280,48896,32768)
1341  Button b_load_files_opt,pos={100,410},size={76,20},proc=PearlDataExplorer#bp_load_files_opt,title="load reduced"
1342  Button b_load_files_opt,help={"load data from the selected files with options (reduced dimensions)"}
1343  Button b_load_files_opt,fColor=(65280,48896,32768)
1344 
1345  // datasets group
1346  GroupBox gb_datasets,pos={240,64},size={224,372},title="datasets"
1347  ListBox lb_datasets,pos={252,84},size={200,300},proc=PearlDataExplorer#lbp_datasets,help={"list of loaded datasets"}
1348  ListBox lb_datasets,listWave=root:packages:pearl_explorer:wtDatasets
1349  ListBox lb_datasets,selWave=root:packages:pearl_explorer:wSelectedDatasets,mode= 1
1350  ListBox lb_datasets,selRow= -1
1351 
1352  Button b_update_datasets,pos={252,386},size={60,20},proc=PearlDataExplorer#bp_update_datasets,title="update list"
1353  Button b_update_datasets,help={"update the list of datasets"}
1354  Button b_update_datasets,fColor=(65280,48896,32768)
1355  CheckBox cb_dataset_preview,pos={316,390},size={60,20},title="preview"
1356  CheckBox cb_dataset_preview,help={"enable/disable automatic preview window when selecting a dataset"}
1357  CheckBox cb_dataset_preview,value=0
1358  Button b_dataset_prev,pos={408,386},size={20,20},proc=PearlDataExplorer#bp_dataset_prev,title="\\W646"
1359  Button b_dataset_prev,help={"goto previous dataset"}
1360  Button b_dataset_prev,fColor=(65280,48896,32768)
1361  Button b_dataset_next,pos={432,386},size={20,20},proc=PearlDataExplorer#bp_dataset_next,title="\\W649"
1362  Button b_dataset_next,help={"goto next dataset"}
1363  Button b_dataset_next,fColor=(65280,48896,32768)
1364 
1365  Button b_dataset_folder,pos={252,410},size={50,20},proc=PearlDataExplorer#bp_dataset_folder,title="goto DF"
1366  Button b_dataset_folder,help={"set the current data folder of the selected dataset"}
1367  Button b_dataset_folder,fColor=(65280,48896,32768)
1368  Button b_dataset_display,pos={306,410},size={50,20},proc=PearlDataExplorer#bp_dataset_display,title="display"
1369  Button b_dataset_display,help={"display the selected dataset in its own window"}
1370  Button b_dataset_display,fColor=(65280,48896,32768)
1371 
1372  GroupBox gb_preview,pos={472,4},size={250,52},title="preview"
1373  TitleBox tb_preview_file,pos={484,24},size={226,20},frame=2
1374  TitleBox tb_preview_file,variable=root:packages:pearl_explorer:s_preview_file,fixedSize=1
1375 
1376  GroupBox gb_attributes,pos={472,64},size={250,372},title="attributes"
1377  Button b_attr_notebook,pos={484,386},size={60,20},proc=PearlDataExplorer#bp_attr_notebook,title="notebook"
1378  Button b_attr_notebook,help={"show attribute list in a notebook"}
1379  Button b_attr_notebook,fColor=(65280,48896,32768)
1380 
1381  String fldrSav0= GetDataFolder(1)
1382  SetDataFolder root:packages:pearl_explorer:
1383  Edit/W=(484,84,710,384)/HOST=# attr_names,attr_values
1384  ModifyTable format(Point)=1,width(Point)=0,width(attr_names)=103,width(attr_values)=103
1385  ModifyTable statsArea=85
1386  SetDataFolder fldrSav0
1387  RenameWindow #,T0
1388  SetActiveSubwindow ##
1389 };
1390 
1391 static variable bp_load_prefs(WMButtonAction* ba){
1392  STRUCT WMButtonAction &ba
1393 
1394  switch( ba.eventCode )
1395  case 2:// mouse up
1396  load_prefs()
1397  break
1398  case -1:// control being killed
1399  break
1400  endswitch
1401 
1402  return 0
1403 };
1404 
1405 static variable bp_save_prefs(WMButtonAction* ba){
1406  STRUCT WMButtonAction &ba
1407 
1408  switch( ba.eventCode )
1409  case 2:// mouse up
1410  save_prefs()
1411  break
1412  case -1:// control being killed
1413  break
1414  endswitch
1415 
1416  return 0
1417 };
1418 
1419 static variable bp_browse_filepath(WMButtonAction* ba){
1420  STRUCT WMButtonAction &ba
1421 
1422  dfref saveDF = GetDataFolderDFR()
1423 
1424  switch( ba.eventCode )
1425  case 2:// mouse up
1426  PathInfo /S pearl_explorer_filepath
1427  NewPath /M="select data file folder" /O/Z pearl_explorer_filepath
1428  if (v_flag == 0)
1429  PathInfo /S pearl_explorer_filepath
1430  svar filepath = $(package_path + "s_filepath")
1431  filepath = s_path
1432  update_filelist()
1433  endif
1434  break
1435  case -1:// control being killed
1436  break
1437  endswitch
1438 
1439  setdatafolder saveDF
1440  return 0
1441 };
1442 
1443 static variable bp_update_filelist(WMButtonAction* ba){
1444  STRUCT WMButtonAction &ba
1445 
1446  switch( ba.eventCode )
1447  case 2:// mouse up
1448  update_filelist()
1449  break
1450  case -1:// control being killed
1451  break
1452  endswitch
1453 
1454  return 0
1455 };
1456 
1457 static variable bp_load_files(WMButtonAction* ba){
1458  STRUCT WMButtonAction &ba
1459 
1460  switch( ba.eventCode )
1461  case 2:// mouse up
1463  break
1464  case -1:// control being killed
1465  break
1466  endswitch
1467 
1468  return 0
1469 };
1470 
1471 static variable bp_load_files_opt(WMButtonAction* ba){
1472  STRUCT WMButtonAction &ba
1473 
1474  switch( ba.eventCode )
1475  case 2:// mouse up
1476  load_selected_files(options="")
1477  break
1478  case -1:// control being killed
1479  break
1480  endswitch
1481 
1482  return 0
1483 };
1484 
1485 static variable bp_file_next(WMButtonAction* ba){
1486  STRUCT WMButtonAction &ba
1487 
1488  dfref saveDF = GetDataFolderDFR()
1489 
1490  switch( ba.eventCode )
1491  case 2:// mouse up
1492  setdatafolder $package_path
1493  wave /t wtFiles
1494  wave wSelectedFiles
1495  FindValue /i=1 wSelectedFiles
1496  v_value += 1
1497  if (v_value >= numpnts(wtFiles))
1498  v_value = min(numpnts(wtFiles) - 1, 0)
1499  endif
1500  wSelectedFiles = p == v_value
1501  if (v_value >= 0)
1502  variable ifile = v_value
1503  ControlInfo /W=PearlDataExplorer cb_file_preview
1504  if (v_value)
1505  preview_file(wtFiles[ifile])
1506  endif
1507  endif
1508  break
1509  case -1:// control being killed
1510  break
1511  endswitch
1512 
1513  setdatafolder saveDF
1514  return 0
1515 };
1516 
1517 static variable bp_file_prev(WMButtonAction* ba){
1518  STRUCT WMButtonAction &ba
1519 
1520  dfref saveDF = GetDataFolderDFR()
1521 
1522  switch( ba.eventCode )
1523  case 2:// mouse up
1524  setdatafolder $package_path
1525  wave /t wtFiles
1526  wave wSelectedFiles
1527  FindValue /i=1 wSelectedFiles
1528  v_value -= 1
1529  if (v_value < 0)
1530  v_value = numpnts(wtFiles) - 1
1531  endif
1532  wSelectedFiles = p == v_value
1533  if (v_value >= 0)
1534  variable ifile = v_value
1535  ControlInfo /W=PearlDataExplorer cb_file_preview
1536  if (v_value)
1537  preview_file(wtFiles[ifile])
1538  endif
1539  endif
1540  break
1541  case -1:// control being killed
1542  break
1543  endswitch
1544 
1545  setdatafolder saveDF
1546  return 0
1547 };
1548 
1549 static variable lbp_filelist(WMListboxAction* lba){
1550  STRUCT WMListboxAction &lba
1551 
1552  Variable row = lba.row
1553  Variable col = lba.col
1554  WAVE/T/Z listWave = lba.listWave
1555  WAVE/Z selWave = lba.selWave
1556 
1557  switch( lba.eventCode )
1558  case -1:// control being killed
1559  break
1560  case 1:// mouse down
1561  if (selWave[row])
1562  ControlInfo /W=PearlDataExplorer cb_file_preview
1563  if (v_value)
1564  preview_file(listWave[row])
1565  endif
1566  endif
1567  break
1568  case 3:// double click
1569  break
1570  case 4:// cell selection
1571  case 5:// cell selection plus shift key
1572  break
1573  case 6:// begin edit
1574  break
1575  case 7:// finish edit
1576  break
1577  case 13:// checkbox clicked (Igor 6.2 or later)
1578  break
1579  endswitch
1580 
1581  return 0
1582 };
1583 
1584 static variable bp_update_datasets(WMButtonAction* ba){
1585  STRUCT WMButtonAction &ba
1586 
1587  switch( ba.eventCode )
1588  case 2:// mouse up
1589  update_datasets()
1590  break
1591  case -1:// control being killed
1592  break
1593  endswitch
1594 
1595  return 0
1596 };
1597 
1598 static variable bp_dataset_folder(WMButtonAction* ba){
1599  STRUCT WMButtonAction &ba
1600 
1601  switch( ba.eventCode )
1602  case 2:// mouse up
1603  ControlInfo /W=PearlDataExplorer lb_datasets
1604  if (v_value >= 0)
1605  setdatafolder $package_path
1606  wave /t wtDatasets
1607  string dataset = wtDatasets[v_value]
1608  string cmd
1609  sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset)
1610  execute /q /z cmd
1611  cmd = "setdatafolder :scan1"
1612  execute /q /z cmd
1613  sprintf cmd, "setdatafolder %s", GetDataFolder(1)
1614  print cmd
1615  endif
1616  break
1617  case -1:// control being killed
1618  break
1619  endswitch
1620 
1621  return 0
1622 };
1623 
1624 static variable bp_dataset_display(WMButtonAction* ba){
1625  STRUCT WMButtonAction &ba
1626 
1627  switch( ba.eventCode )
1628  case 2:// mouse up
1629  ControlInfo /W=PearlDataExplorer lb_datasets
1630  if (v_value >= 0)
1631  setdatafolder $package_path
1632  wave /t wtDatasets
1633  string dataset = wtDatasets[v_value]
1634  display_dataset(dataset)
1635  endif
1636  break
1637  case -1:// control being killed
1638  break
1639  endswitch
1640 
1641  return 0
1642 };
1643 
1644 static variable bp_dataset_next(WMButtonAction* ba){
1645  STRUCT WMButtonAction &ba
1646 
1647  switch( ba.eventCode )
1648  case 2:// mouse up
1649  ControlInfo /W=PearlDataExplorer lb_datasets
1650  wave /t wtDatasets = $(s_datafolder + s_value)
1651  v_value += 1
1652  if (v_value >= numpnts(wtDatasets))
1653  v_value = min(0, numpnts(wtDatasets) - 1)
1654  endif
1655  ListBox lb_datasets win=PearlDataExplorer, selRow=v_value
1656  if (v_value >= 0)
1657  variable ids = v_value
1658  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1659  if (v_value)
1660  preview_dataset(wtDatasets[ids])
1661  endif
1662  endif
1663  break
1664  case -1:// control being killed
1665  break
1666  endswitch
1667 
1668  return 0
1669 };
1670 
1671 static variable bp_dataset_prev(WMButtonAction* ba){
1672  STRUCT WMButtonAction &ba
1673 
1674  switch( ba.eventCode )
1675  case 2:// mouse up
1676  ControlInfo /W=PearlDataExplorer lb_datasets
1677  wave /t wtDatasets = $(s_datafolder + s_value)
1678  v_value -= 1
1679  if (v_value < 0)
1680  v_value = max(-1, numpnts(wtDatasets) - 1)
1681  endif
1682  ListBox lb_datasets win=PearlDataExplorer, selRow=v_value
1683  if (v_value >= 0)
1684  variable ids = v_value
1685  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1686  if (v_value)
1687  preview_dataset(wtDatasets[ids])
1688  endif
1689  endif
1690  break
1691  case -1:// control being killed
1692  break
1693  endswitch
1694 
1695  return 0
1696 };
1697 
1698 static variable lbp_datasets(WMListboxAction* lba){
1699  STRUCT WMListboxAction &lba
1700 
1701  Variable row = lba.row
1702  Variable col = lba.col
1703  WAVE/T/Z listWave = lba.listWave
1704  WAVE/Z selWave = lba.selWave
1705 
1706  switch( lba.eventCode )
1707  case -1:// control being killed
1708  break
1709  case 1:// mouse down
1710  if (row >= 0)
1711  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1712  if (v_value)
1713  preview_dataset(listWave[row])
1714  endif
1715  endif
1716  break
1717  case 3:// double click
1718  break
1719  case 4:// cell selection
1720  case 5:// cell selection plus shift key
1721  break
1722  case 6:// begin edit
1723  break
1724  case 7:// finish edit
1725  break
1726  case 13:// checkbox clicked (Igor 6.2 or later)
1727  break
1728  endswitch
1729 
1730  return 0
1731 };
1732 
1733 static variable bp_attr_notebook(WMButtonAction* ba){
1734  STRUCT WMButtonAction &ba
1735 
1736  dfref saveDF = GetDataFolderDFR()
1737 
1738  switch( ba.eventCode )
1739  case 2:// mouse up
1740  setdatafolder $package_path
1741  svar s_preview_file
1742  wave /t /z attr_names
1743  wave /t /z attr_values
1744  if (WaveExists(attr_names))
1745  attributes_notebook(attr_names, attr_values, s_preview_file)
1746  endif
1747  break
1748  case -1:// control being killed
1749  break
1750  endswitch
1751 
1752  setdatafolder saveDF
1753  return 0
1754 };
1755 
static dfr load_mtrx_file(string filename, string options=defaultValue)
load a matrix (STM) data file
+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 = PearlDataExplorer
4 #pragma version = 1.50
5 #include "pearl-area-import"
6 #include "pearl-area-profiles"
7 #include "pearl-area-display"
8 #include "pearl-pshell-import"
9 #if exists("MFR_OpenResultFile")
10 #include "pearl-matrix-import"
11 #endif
12 
13 // copyright (c) 2013-16 Paul Scherrer Institut
14 //
15 // Licensed under the Apache License, Version 2.0 (the "License");
16 // you may not use this file except in compliance with the License.
17 // You may obtain a copy of the License at
18 // http:///www.apache.org/licenses/LICENSE-2.0
19 
30 
35 
36 static const string package_name = "pearl_explorer";
37 static const string package_path = "root:packages:pearl_explorer:";
38 
39 static const string ks_filematch_adh5 = "*.h5";
40 static const string ks_filematch_pshell = "psh*.h5";
41 static const string ks_filematch_itx = "*.itx";
42 static const string ks_filematch_mtrx = "*_mtrx";
43 
45  init_package()
46  load_prefs()
47  execute /q/z "PearlDataExplorer()"
48 };
49 
55 static variable init_package(){
56 
57  dfref savefolder = GetDataFolderDFR()
58  SetDataFolder root:
59  newdatafolder /o/s packages
60  newdatafolder /o/s $package_name
61  if (exists("v_InitPanelDone") == 2)
62  SetDataFolder savefolder
63  return 0
64  endif
65 
66  make /o/n=0/t wtFiles
67  make /o/n=0/i wSelectedFiles,wSelectedDatasets
68  make /o/n=0/t wtDatasets
69  make /o/n=0/t wtPositioners,wtDetectors
70  make /o/n=0/i wSelectedPositioners,wSelectedDetectors
71 
72  make /o/n=(1,1) preview_image// preview 2D data
73  make /o/n=0 preview_trace// preview 1D data
74  make /o/n=0/t attr_names, attr_values, attr_filter, attr_filter_summary
75 
76  // persistent strings and variables. persistent = saved in preferences
77  string /g s_filepath = ""// directory path to be listed
78  string /g s_hdf_options = ""// recently used HDF5 load options
79  string /g s_reduction_params = ""// recently used reduction parameters
80  string /g s_preview_pvs = ""// semicolon-separated list of EPICS PVs to display in preview.
81  // the list items can contain wildcards for StringMatch
82  s_preview_pvs = "*OP:CURRENT*;*Stats*Total*;*CADC*"
83 
84  // non-persistent strings and variables
85  string /g s_preview_file = ""// file or folder name of the current preview
86  string /g s_preview_source = ""// data source, e.g. EPICS channel name, of the current preview
87  string /g s_profiles_graph = ""// window name of the current preview if the data is two-dimensional
88  string /g s_preview_trace_graph = ""// window name of the current preview if the data is one-dimensional
89  string /g s_file_info = ""// description of selected file
90 
91  variable/g v_InitPanelDone = 1
92 
93  SetDataFolder savefolder
94 };
95 
96 static variable save_prefs(){
97  // saves persistent package data to the preferences file
98  // the data saved in the file are: data file path, attributes filter
99  dfref saveDF = GetDataFolderDFR()
100 
101  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
102  fullPath += package_name
103  NewPath/O/C/Q tempPackagePrefsPath, fullPath
104  fullPath += ":preferences.pxp"
105 
106  SetDataFolder root:packages
107  SetDataFolder $package_name
108  string objects = "attr_filter;attr_filter_summary;s_filepath;s_hdf_options;s_reduction_params;s_preview_pvs"
109  SaveData /O /Q /J=objects fullPath
110 
111  KillPath/Z tempPackagePrefsPath
112 
113  SetDataFolder saveDF
114 };
115 
116 static variable load_prefs(){
117  // loads persistent package data from the preferences file
118  // the preferences file is an Igor packed experiment file in a special preferences folder
119  dfref saveDF = GetDataFolderDFR()
120 
121  variable result = -1
122  setdatafolder root:
123  NewDataFolder /O/S packages
124  NewDataFolder /O/S $package_name
125  dfref packageDF = GetDataFolderDFR()
126  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
127  fullPath += package_name
128 
129  GetFileFolderInfo /Q /Z fullPath
130  if (V_Flag == 0)// Disk directory exists?
131  fullPath += ":preferences.pxp"
132  GetFileFolderInfo /Q /Z fullPath
133  if (V_Flag == 0)// Preference file exist?
134  LoadData /O /R /Q fullPath
135  result = 0
136  endif
137  endif
138 
139  if (result == 0)
140  svar /sdfr=packageDF filepath = s_filepath
141  NewPath /O/Z pearl_explorer_filepath, filepath
144  endif
145 
146  SetDataFolder saveDF
147  return result
148 };
149 
161 static variable pearl_file_type(string filename){
162  string filename
163 
164  if (StringMatch(filename, ks_filematch_pshell))
165  return 1
166  else if (StringMatch(filename, ks_filematch_adh5))
167  return 2
168  else if (StringMatch(filename, ks_filematch_itx))
169  return 3
170 #if exists("MFR_OpenResultFile")
171  else if (StringMatch(filename, ks_filematch_mtrx))
172  return 4
173 #endif
174  else
175  return 0
176  endif
177 };
178 
184 static variable update_filelist(){
185  dfref saveDF = GetDataFolderDFR()
186 
187  string all_files
188  wave /t wtFiles = $(package_path + "wtFiles")
189  wave wSelectedFiles = $(package_path + "wSelectedFiles")
190  variable nn
191 
192  PathInfo pearl_explorer_filepath
193  if (v_flag == 1)
194  all_files = IndexedFile(pearl_explorer_filepath, -1, "????")
195  nn = ItemsInList(all_files)
196  else
197  all_files = ""
198  nn = 0
199  endif
200 
201  make /n=(nn) /t /free wtAllFiles
202  wtAllFiles = StringFromList(p, all_files)
203  Extract /o /t wtAllFiles, wtFiles, pearl_file_type(wtAllFiles[p])
204  Sort /A /R wtFiles, wtFiles
205 
206  redimension /n=(numpnts(wtFiles)) wSelectedFiles
207  wSelectedFiles = 0
208 
209  setdatafolder saveDF
210 };
211 
212 static variable update_datasets(){
213  // updates the list of imported datasets.
214  // a dataset means any top-level data folder
215  // which includes a string variable named pearl_explorer_import.
216  dfref saveDF = GetDataFolderDFR()
217 
218  setdatafolder root:
219  dfref rootdf = GetDataFolderDFR()
220  setdatafolder $package_path
221  dfref privatedf = GetDataFolderDFR()
222 
223  wave /t wtDatasets
224  wave wSelectedDatasets
225  variable maxdf = CountObjectsDFR(rootdf, 4)
226  redimension /n=(maxdf) wtDatasets
227 
228  variable idf = 0
229  variable ndf = 0
230  string sdf
231 
232  do
233  sdf = GetIndexedObjNameDFR(rootdf, 4, idf)
234  if (strlen(sdf) >= 1)
235  setdatafolder rootdf
236  setdatafolder $sdf
237  svar /z importer = pearl_explorer_import
238  if (svar_exists(importer))
239  wtDatasets[ndf] = sdf
240  ndf += 1
241  endif
242  else
243  break
244  endif
245  idf += 1
246  while(1)
247 
248  redimension /n=(ndf) wtDatasets, wSelectedDatasets
249  wSelectedDatasets = 0
250  sort wtDatasets, wtDatasets
251 
252  setdatafolder saveDF
253 };
254 
255 static variable preview_file(string filename){
256  string filename
257 
258  dfref saveDF = GetDataFolderDFR()
259 
260  variable ft = pearl_file_type(filename)
261  switch(ft)
262  case 1:
263  wave /z image = preview_pshell_file(filename)
264  break
265  case 2:
266  wave /z image = preview_hdf_file(filename)
267  break
268  case 3:
269  wave /z image = preview_itx_file(filename)
270  break
271  case 4:
272  wave /z image = preview_mtrx_file(filename)
273  break
274  default:
275  wave /z image = $""
276  endswitch
277 
278  if (WaveExists(image))
279  string graphname = show_preview_graph(image)
280  // preset ELOG panel - if available
281  if (exists("PearlElog#set_panel_attributes") == 6)
282  string cmd
283  sprintf cmd, "PearlElog#set_panel_attributes(\"\", \"File=%s\")", ParseFilePath(0, filename, ":", 1, 0)
284  execute /Q/Z cmd
285  if (strlen(graphname) > 0)
286  sprintf cmd, "PearlElog#set_panel_graphs(\"\", \"%s\")", graphname
287  execute /Q/Z cmd
288  endif
289  endif
290  endif
291 
292  setdatafolder saveDF
293  return 0
294 };
295 
307 static wave preview_pshell_file(string filename){
308  string filename
309 
310  dfref saveDF = GetDataFolderDFR()
311 
312  setdatafolder $package_path
313  dfref previewDF = GetDataFolderDFR()
314  svar s_preview_file
315  svar s_preview_source
316  svar /z s_file_info
317  if (! svar_exists(s_file_info))
318  string /g s_file_info
319  endif
320 
321  dfref tempDF = NewFreeDataFolder()
322  setdatafolder tempDF
323  string dataname
324  dataname = psh5_load_preview("pearl_explorer_filepath", filename)
325 
326  s_preview_file = filename
327  s_preview_source = ""
328 
329  wave /z data = $dataname
330  if (waveexists(data))
331  duplicate /o data, previewDF:preview_image
332  else
333  print "no data found in file " + filename
334  endif
335 
336  if (strlen(s_preview_file) > 0)
337  s_file_info = psh5_load_info("pearl_explorer_filepath", filename)
338  else
339  s_file_info = ""
340  endif
341 
342  dfref attrDF = tempDF:attr
343  if (DataFolderRefStatus(attrDF))
344  preview_attributes(attrDF)
345  endif
346 
347  setdatafolder saveDF
348  wave /z /sdfr=previewDF preview_image
349  return preview_image
350 };
351 
363 static wave preview_hdf_file(string filename){
364  string filename
365 
366  dfref saveDF = GetDataFolderDFR()
367  setdatafolder $package_path
368  svar s_preview_file
369  svar s_preview_source
370  adh5_load_preview("preview_image", "pearl_explorer_filepath", filename)
371  s_preview_file = filename
372  s_preview_source = ""
373  wave /z preview_image
374 
375  svar /z s_file_info
376  if (! svar_exists(s_file_info))
377  string /g s_file_info
378  endif
379  if (strlen(s_preview_file) > 0)
380  s_file_info = adh5_load_info("pearl_explorer_filepath", filename)
381  else
382  s_file_info = ""
383  endif
384 
385  if (DataFolderExists("attr"))
386  setdatafolder attr
387  preview_attributes(GetDataFolderDFR())
388  setdatafolder ::
389  endif
390 
391  setdatafolder saveDF
392  return preview_image
393 };
394 
395 static wave preview_itx_file(string filename){
396  string filename
397 
398  dfref saveDF = GetDataFolderDFR()
399  setdatafolder $package_path
400  svar s_preview_file
401  svar s_preview_source
402  wave preview_image
403 
404  // note: some versions of PEARL data files save data to a new data folder,
405  // and leave the newly created folder as the current folder.
406  // the free data folder is used by those files which don't create their own data folder.
407  // this is the new recommended behaviour
408  dfref dataDF = newfreedatafolder()
409  setdatafolder dataDF
410  LoadWave /t/p=pearl_explorer_filepath/q filename
411  s_preview_file = s_filename
412  s_preview_source = ""
413 
415  preview_attributes(dataDF, include_datawaves=0)
416 
417  setdatafolder saveDF
418  return preview_image
419 };
420 
435 static wave preview_mtrx_file(string filename){
436  string filename
437 
438 #if exists("MFR_OpenResultFile")
439  dfref saveDF = GetDataFolderDFR()
440  setdatafolder $package_path
441  variable /g V_MatrixFileReaderOverwrite = 1
442  variable /g V_MatrixFileReaderFolder = 0
443  variable /g V_MatrixFileReaderDouble = 0
444  svar s_preview_file
445  svar s_preview_source
446  string datanames
447  string dataname
448  datanames = mtrx_load_preview("preview", "pearl_explorer_filepath", filename)
449  if (strlen(datanames) > 0)
450  s_preview_file = filename
451 
452  dataname = StringFromList(0, datanames)
453  wave data = $dataname
454  duplicate /o $dataname, preview_image
455  s_preview_source = StringByKey("Dataset", note(data), "=", "\r")
456 
457  svar /z s_file_info
458  if (svar_exists(s_file_info))
459  s_file_info = ""
460  endif
461 
462  variable i
463  variable n = ItemsInList(datanames)
464  string s
465  for (i = 0; i < n; i += 1)
466  s = StringFromList(i, datanames)
467  killwaves /z $s
468  endfor
469  endif
470  wave /z preview_image
471  setdatafolder saveDF
472 #else
473  wave /z preview_image = $""
474 #endif
475  return preview_image
476 };
477 
478 static variable extract_preview_image(wave data, wave preview){
479  // extracts a preview image from a wave of arbitrary dimension
480  wave data
481  wave preview
482 
483  variable z1, z2
484 
485  // extract image
486  switch (WaveDims(data))
487  case 1:
488  redimension /n=(numpnts(data)) preview
489  preview = data[p]
490  break
491  case 2:
492  redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview
493  preview = data
494  break
495  case 3:
496  redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview
497  z1 = floor(DimSize(data, 2) / 2)
498  z2 = z1
499  wave slab = ad_extract_slab(data, nan, nan, nan, nan, z1, z2, "", pscale=1)
500  preview = slab
501  break
502  case 4:
503  // not implemented
504  endswitch
505 
506  switch (WaveDims(data))
507  case 4:
508  case 3:
509  case 2:
510  setscale /p y dimoffset(data, 1), dimdelta(data, 1), waveunits(data, 1), preview
511  case 1:
512  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), preview
513  setscale d 0, 0, waveunits(data, -1), preview
514  endswitch
515 };
516 
517 static variable preview_dataset(string datasetname){
518  string datasetname// name of a data folder under root
519 
520  dfref saveDF = GetDataFolderDFR()
521 
522  if (!DataFolderExists("root:" + datasetname))
523  return -1
524  endif
525  setdatafolder root:
526  setdatafolder $datasetname
527  dfref datadf = GetDataFolderDFR()
528  wave /z data
529 
530  setdatafolder $package_path
531  svar s_preview_file
532  svar s_preview_source
533  wave preview_image
534  if (WaveExists(data))
535  s_preview_file = datasetname
536  s_preview_source = ""
537  extract_preview_image(data, preview_image)
538  show_preview_graph(preview_image)
539  else
540  preview_image = nan
541  s_preview_file = datasetname
542  setdatafolder datadf
544  show_preview_graph(preview_image)
545  endif
546 
547  // attributes
548  setdatafolder datadf
549  if (DataFolderExists("attr"))
550  setdatafolder attr
551  preview_attributes(GetDataFolderDFR())
552  else
553  preview_attributes(GetDataFolderDFR(), include_datawaves=0)
554  endif
555 
556  setdatafolder saveDF
557  return 0
558 };
559 
560 static variable preview_datafolder(){
561  // preview data in the current data folder
562  dfref saveDF = GetDataFolderDFR()
563 
564  setdatafolder $package_path
565  svar s_preview_file
566  svar s_preview_source
567  svar s_preview_pvs
568  wave preview_image
569 
570  setdatafolder saveDF
571 
572  // select a wave to display
573  // consider only double-precision waves, i.e. ignore text and other special waves
574  // filter by matching PV name to s_preview_pvs
575  string d_names = WaveList("*", ";", "DP:1")
576  variable nw = ItemsInList(d_names, ";")
577  variable npv = ItemsInList(s_preview_pvs, ";")
578  variable iw, ipv
579  string wname, wnote, pv_name, pv_match
580  for (iw = 0; iw < nw; iw += 1)
581  wname = StringFromList(iw, d_names, ";")
582  wnote = note($wname)
583  pv_name = StringByKey("PV", wnote, "=", "\r")
584  // find matching data wave by PV name
585  for (ipv = 0; ipv < npv; ipv += 1)
586  pv_match = StringFromList(ipv, s_preview_pvs)
587  if (StringMatch(pv_name, pv_match))
588  wave data = $wname
589  s_preview_source = pv_name
590  extract_preview_image(data, preview_image)
591  preview_setscale_x(data, preview_image)
592  npv = 0
593  nw = 0
594  endif
595  endfor
596  endfor
597 
598  setdatafolder saveDF
599 };
600 
601 static variable preview_setscale_x(wave data, wave preview){
602  // sets the approximate x scale of OTF data.
603  // requires an Axis1 tag with name of x wave in the wave note.
604  // if any of these conditions is true, the function does not change the scaling:
605  // 1) Axis1 tag or referenced wave is missing.
606  // 2) preview wave is not set to point scaling.
607  // 3) x wave is not monotonic (90% of the steps in the same direction).
608  wave data
609  wave preview
610 
611  if ((DimOffset(preview, 0) == 0) && (DimDelta(preview, 0) == 1))
612  string xname = StringByKey("Axis1", note(data), "=", "\r")
613  wave /z xwave = $xname
614  if (WaveExists(xwave))
615  // check for monotonicity
616  variable monotonic = 0
617  duplicate /free xwave, xdiff
618  differentiate /p xwave /D=xdiff
619  duplicate /free xdiff, xflag
620  xflag = xdiff > 0
621  monotonic = sum(xflag) > numpnts(xwave) * 0.9
622  xflag = xdiff < 0
623  monotonic = monotonic || (sum(xflag) > numpnts(xwave) * 0.9)
624  if (monotonic)
625  setscale /i x xwave[0], xwave[numpnts(xwave)-1], waveunits(xwave, -1), preview
626  endif
627  endif
628  endif
629 };
630 
631 static variable preview_attributes(dfref attr_folder, dfref dest_folder = defaultValue, wave attr_filter = defaultValue, variable include_datawaves = defaultValue, variable include_infowaves = defaultValue){
632  // copies the first elements of attributes in the specified folder to the preview waves
633  // by default, all existing attributes are copied
634  // if a text wave attr_filter exists in the pear_explorer folder, only the attributes referenced therein are copied
635  // to set up a filter, duplicate the attr_names wave of a template dataset, and remove unwanted items
636  dfref attr_folder// data folder which contains the attribute waves
637  dfref dest_folder// destination folder. the output is written to the attr_names and attr_values waves
638  // default = package folder
639  wave /t attr_filter// list of attributes allowed in the output
640  // default = use attr_filter of package folder
641  variable include_datawaves// 1 (default) = include data waves (any numeric wave which has a PV=name note)
642  // 0 = don't include attributes from data waves
643  variable include_infowaves// 1 (default) = include attributes from info waves (IN, ID, IV, IU)
644  // 0 = don't include attributes from info waves
645 
646  dfref saveDF = GetDataFolderDFR()
647  setdatafolder $package_path
648 
649  if (ParamIsDefault(dest_folder))
650  dest_folder = GetDataFolderDFR()// package folder
651  endif
652  if (ParamIsDefault(attr_filter))
653  wave /t /z attr_filter
654  endif
655  if (ParamIsDefault(include_datawaves))
656  include_datawaves = 1
657  endif
658  if (ParamIsDefault(include_infowaves))
659  include_infowaves = 1
660  endif
661 
662  setdatafolder dest_folder
663  wave /t /z attr_names, attr_values
664  if (!WaveExists(attr_names) || !WaveExists(attr_values))
665  make /n=(1) /o /t attr_names, attr_values
666  endif
667  attr_names = ""
668  attr_values = ""
669 
670  setdatafolder attr_folder
671  wave /t /z IN
672  wave /t /z ID
673  wave /t /z IV
674  wave /t /z IU
675 
676  // compile list of attributes
677  variable nattr// destination attributes
678  variable iattr
679  variable ninfo// info wave elements
680  variable iinfo
681  variable nw// attribute waves
682  variable iw
683  string sw
684  string ss
685 
686  if (WaveExists(IN) && include_infowaves)
687  ninfo = numpnts(IN)
688  else
689  ninfo = 0
690  endif
691  if (include_datawaves)
692  string waves = WaveList("*", ";", "")
693  string exceptions = "ID;IN;IU;IV"
694  waves = RemoveFromList(exceptions, waves)
695  nw = ItemsInList(waves, ";")
696  else
697  nw = 0
698  endif
699 
700  if (WaveExists(attr_filter) && (numpnts(attr_filter) >= 1))
701  nattr = numpnts(attr_filter)
702  redimension /n=(nattr) attr_names
703  attr_names = attr_filter
704  else
705  if(ninfo > 0)
706  redimension /n=(ninfo) attr_names
707  attr_names = SelectString(strlen(ID[p]) >= 0, IN[p], ID[p])// use ID unless empty
708  endif
709 
710  nattr = ninfo + nw
711  iattr = ninfo
712  redimension /n=(nattr) attr_names
713  for (iw = 0; iw < nw; iw +=1 )
714  sw = StringFromList(iw, waves, ";")
715  ss = StringByKey("PV", note($sw), "=", "\r")
716  FindValue /text=sw attr_names
717  if ((v_value < 0) && (strlen(ss) >= 0))
718  attr_names[iattr] = sw
719  iattr += 1
720  endif
721  endfor
722  nattr = iattr
723  endif
724  redimension /n=(nattr) attr_names, attr_values
725  sort attr_names, attr_names
726 
727  // look up attribute values
728  for (iattr = 0; iattr < nattr; iattr += 1)
729  sw = attr_names[iattr]
730  // try info waves
731  if (ninfo > 0)
732  FindValue /text=sw ID
733  if (v_value >= 0)
734  attr_values[iattr] = IV[v_value]
735  endif
736  FindValue /text=sw IN
737  if (v_value >= 0)
738  attr_values[iattr] = IV[v_value]
739  endif
740  endif
741 
742  // override from attribute wave if existent
743  if (nw > 0)
744  switch (WaveType($sw, 1))
745  case 1:// numeric
746  wave /z w = $sw
747  if (WaveExists(w) && (numpnts(w) >= 1))
748  sprintf ss, "%g", w[0]
749  attr_values[iattr] = ss
750  endif
751  break
752  case 2:// text
753  wave /t/z wt = $sw
754  if (WaveExists(wt) && (numpnts(wt) >= 1))
755  attr_values[iattr] = wt[0]
756  endif
757  break
758  endswitch
759  endif
760  endfor
761 
762  setdatafolder saveDF
763 };
764 
765 static variable display_dataset(string datasetname){
766  // displays the graph of a loaded dataset in its own window
767  string datasetname// name of a data folder under root
768 
769  dfref saveDF = GetDataFolderDFR()
770 
771  if (!DataFolderExists("root:" + datasetname))
772  return -1
773  endif
774  setdatafolder root:
775  setdatafolder $datasetname
776  dfref datadf = GetDataFolderDFR()
777  wave /z data
778  if (!WaveExists(data))
779  wave /z data = data1
780  endif
781 
782  if (WaveExists(data))
783  switch(WaveDims(data))
784  case 2:
785  ad_display_profiles(data)
786  break
787  case 3:
788  ad_display_slice(data)
789  ad_brick_slicer(data)
790  break
791  endswitch
792  endif
793 
794  setdatafolder saveDF
795  return 0
796 };
797 
799  dfref df = GetDataFolderDFR()
800  wave /t /sdfr=df attr_names
801  wave /t /sdfr=df attr_values
802  attributes_notebook(attr_names, attr_values, GetDataFolder(0))
803 };
804 
805 static variable attributes_notebook(wave attr_names, wave attr_values, string title){
806  wave /t attr_names
807  wave /t attr_values
808  string title
809 
810  dfref saveDF = GetDataFolderDFR()
811  setdatafolder $package_path
812  wave /t/z attr_filter, attr_filter_summary
813 
814  string name = CleanupName("nb_" + title[0,28], 0)
815  if (WinType(name) == 5)
816  Notebook $name selection={startOfFile, endOfFile}
817  Notebook $name text=""
818  else
819  NewNotebook /F=1 /K=1 /N=$name as title
820  GetWindow $name wsize
821  v_right = v_left + 260
822  v_bottom = v_top + 360
823  MoveWindow /W=$name v_left, v_top, v_right, v_bottom
824  Notebook $name tabs={2*72}
825  endif
826 
827  // summary
828  if (WaveExists(attr_filter_summary) && (numpnts(attr_filter_summary) >= 1))
829  notebook $name fStyle=1, text="Summary\r\r"
830  notebook $name fStyle=0
831  notebook_add_attributes(name, attr_filter_summary, attr_names, attr_values)
832  notebook $name text="\r"
833  endif
834 
835  // all attributes
836  notebook $name fStyle=1, text="All Attributes\r\r"
837  notebook $name fStyle=0
838  notebook_add_attributes(name, $"", attr_names, attr_values)
839  notebook $name selection={startOfFile,startOfFile}, findText={"",1}
840 
841  setdatafolder saveDF
842 };
843 
844 static variable notebook_add_attributes(string notebook_name, wave attr_filter, wave attr_names, wave attr_values){
845  string notebook_name
846  wave /t /z attr_filter
847  wave /t attr_names
848  wave /t attr_values
849 
850  variable nw = numpnts(attr_names)
851  variable iw
852  string sw
853  string ss
854 
855  variable do_filter = WaveExists(attr_filter)
856 
857  for (iw = 0; iw < nw; iw += 1)
858  if (do_filter)
859  sw = attr_names[iw]
860  FindValue /text=sw attr_filter
861  else
862  v_value = 0
863  endif
864  if (v_value >= 0)
865  sprintf ss, "%s\t%s\r", attr_names[iw], attr_values[iw]
866  notebook $notebook_name text=ss
867  endif
868  endfor
869 };
870 
871 static string show_preview_graph(wave data, wave xdata = defaultValue){
872  // displays a preview of one- or two-dimensional data
873  wave data// data to be displayed. must either one-dimensional or two-dimensional
874  wave xdata// positions on x axis
875 
876  dfref saveDF = GetDataFolderDFR()
877  setdatafolder $package_path
878 
879  svar s_profiles_graph
880  svar s_preview_file
881  svar s_preview_source
882  svar s_preview_trace_graph
883 
884  if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1))
885  KillWindow $s_profiles_graph
886  endif
887  if ((strlen(s_preview_trace_graph) > 0) && (WinType(s_preview_trace_graph) == 1))
888  KillWindow $s_preview_trace_graph
889  endif
890 
891  string graphname
892  if (wavedims(data) == 2)
893  s_profiles_graph = ad_display_profiles(data)
894  ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
895  graphname = s_profiles_graph
896  else if (wavedims(data) == 1)
897  duplicate /o data, preview_trace
898  if (!ParamIsDefault(xdata))
899  duplicate /o xdata, preview_trace_x
900  else
901  duplicate /o data, preview_trace_x
902  preview_trace_x = x
903  setscale d 0, 0, WaveUnits(data, 0), preview_trace_x
904  endif
905  s_preview_trace_graph = display_preview_trace(preview_trace_x, preview_trace)
906  ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
907  graphname = s_preview_trace_graph
908  else
909  return ""
910  endif
911 
912  string title = "Preview " + s_preview_file
913  if (strlen(s_preview_source) > 0)
914  title = title + " (" + s_preview_source[0,31] + ")"
915  endif
916  dowindow /f/t $graphname, title
917 
918  setdatafolder saveDF
919  return graphname
920 };
921 
922 static string display_preview_trace(wave xtrace, wave ytrace){
923  wave xtrace
924  wave ytrace
925 
926  display /n=pearl_explorer_1d /k=1 ytrace vs xtrace as "Preview"
927  string graphname = s_name
928  ModifyGraph /w=$graphname rgb[0]=(0,0,0)
929  ModifyGraph /w=$graphname grid=2
930  ModifyGraph /w=$graphname mirror=1
931  ModifyGraph /w=$graphname minor=1
932  ModifyGraph /w=$graphname axThick=0.5
933  ModifyGraph /w=$graphname gridRGB=(52224,52224,52224)
934  ModifyGraph /w=$graphname gridHair=0
935  ModifyGraph /w=$graphname tick=0
936  ModifyGraph /w=$graphname btLen=4
937 
938  // axis labels
939  string labels = note(ytrace)
940  string lab
941  lab = StringByKey("AxisLabelX", labels, "=", "\r")
942  if (!strlen(lab))
943  lab = "X"
944  endif
945  Label /w=$graphname bottom lab + " (\\U)"
946  lab = StringByKey("AxisLabelD", labels, "=", "\r")
947  if (!strlen(lab))
948  lab = "value"
949  endif
950  Label /w=$graphname left lab + " (\\U)"
951 
952  return s_name
953 };
954 
955 static variable load_selected_files(string options = defaultValue){
956  string options
957 
958  dfref saveDF = GetDataFolderDFR()
959  setdatafolder $package_path
960 
961  wave wSelectedFiles
962  wave/t wtFiles
963  variable nn = numpnts(wSelectedFiles)
964  variable ii
965  for (ii = 0; ii < nn; ii += 1)
966  if (wSelectedFiles[ii])
967  if (ParamIsDefault(options))
968  load_file(wtFiles[ii])
969  else
970  load_file(wtFiles[ii], options=options)
971  endif
972  endif
973  endfor
974 
976  setdatafolder saveDF
977 };
978 
979 static variable load_file(string filename, string options = defaultValue){
980  string filename
981  string options
982 
983  dfref saveDF = GetDataFolderDFR()
984 
985  variable ft = pearl_file_type(filename)
986  switch(ft)
987  case 1:
988  if (ParamIsDefault(options))
989  load_pshell_file(filename)
990  else
991  load_pshell_file(filename, options=options)
992  endif
993  break
994  case 2:
995  if (ParamIsDefault(options))
996  load_hdf_file(filename)
997  else
998  load_hdf_file(filename, options=options)
999  endif
1000  break
1001  case 3:
1002  load_itx_file(filename)
1003  break
1004  case 4:
1005  load_mtrx_file(filename)
1006  break
1007  default:
1008  break
1009  endswitch
1010 
1011  setdatafolder saveDF
1012 };
1013 
1014 static variable prompt_hdf_options(string* options){
1015  string &options
1016 
1017  string mode = StringByKey("mode", options, ":", ";")
1018  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1019 
1020  string modes = "load_reduced"
1021  string reduction_functions = adh5_list_reduction_funcs()
1022 
1023  if (strlen(mode) == 0)
1024  mode = StringFromList(0, modes, ";")
1025  endif
1026  if (strlen(reduction_func) == 0)
1027  reduction_func = StringFromList(0, reduction_functions, ";")
1028  endif
1029 
1030  prompt mode, "Mode", popup, modes
1031  prompt reduction_func, "Reduction Function", popup, reduction_functions
1032  doprompt "HDF5 Loading Options", mode, reduction_func
1033 
1034  if (v_flag == 0)
1035  options = ReplaceStringByKey("mode", options, mode, ":", ";")
1036  options = ReplaceStringByKey("reduction_func", options, reduction_func, ":", ";")
1037  endif
1038  return v_flag// 0 = OK, 1 = cancel
1039 };
1040 
1053 variable prompt_default_process(string* param){
1054  string &param
1055 
1056  return 0
1057 };
1058 
1059 variable prompt_func_params(string func_name, string* func_param){
1060  string func_name
1061  string &func_param
1062 
1063  string prompt_name = "prompt_" + func_name
1064  if (exists(prompt_name) == 6)
1065  funcref prompt_default_process prompt_func = $prompt_name
1066  return prompt_func(func_param)
1067  else
1068  // ignore missing prompt function
1069  return 0
1070  endif
1071 };
1072 
1073 static dfr load_pshell_file(string filename, string options = defaultValue){
1074  string filename
1075  string options
1076 
1077  dfref saveDF = GetDataFolderDFR()
1078  string nickname = ad_suggest_foldername(filename)
1079  string loaded_filename = ""
1080 
1081  if (ParamIsDefault(options))
1082  loaded_filename = psh5_load_complete(nickname, "pearl_explorer_filepath", filename)
1083  else
1084  if (strlen(options) == 0)
1085  svar pref_options = $(package_path + "s_hdf_options")
1086  options = pref_options
1087  if (prompt_hdf_options(options) == 0)
1088  // OK
1089  pref_options = options
1090  else
1091  // cancel
1092  options = ""
1093  endif
1094  endif
1095 
1096  string mode = StringByKey("mode", options, ":", ";")
1097 
1098  strswitch(mode)
1099  case "load_reduced":
1100  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1101  svar pref_params = $(package_path + "s_reduction_params")
1102  string reduction_params = pref_params
1103  if (prompt_func_params(reduction_func, reduction_params) == 0)
1104  pref_params = reduction_params
1105  print reduction_func, reduction_params
1106  psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
1107  svar s_filepath
1108  loaded_filename = s_filepath
1109  endif
1110  break
1111  endswitch
1112  endif
1113 
1114  dfref dataDF
1115  if (strlen(loaded_filename) > 0)
1116  setdatafolder $("root:" + nickname)
1117  dataDF = GetDataFolderDFR()
1118  string /g pearl_explorer_import = "load_pshell_file"
1119  endif
1120 
1121  setdatafolder saveDF
1122  return dataDF
1123 };
1124 
1125 static dfr load_hdf_file(string filename, string options = defaultValue){
1126  string filename
1127  string options
1128 
1129  dfref saveDF = GetDataFolderDFR()
1130  string nickname = ad_suggest_foldername(filename)
1131  string loaded_filename = ""
1132 
1133  if (ParamIsDefault(options))
1134  loaded_filename = adh5_load_complete(nickname, "pearl_explorer_filepath", filename)
1135  else
1136  if (strlen(options) == 0)
1137  svar pref_options = $(package_path + "s_hdf_options")
1138  options = pref_options
1139  if (prompt_hdf_options(options) == 0)
1140  // OK
1141  pref_options = options
1142  else
1143  // cancel
1144  options = ""
1145  endif
1146  endif
1147 
1148  string mode = StringByKey("mode", options, ":", ";")
1149 
1150  strswitch(mode)
1151  case "load_reduced":
1152  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1153  svar pref_params = $(package_path + "s_reduction_params")
1154  string reduction_params = pref_params
1155  if (prompt_func_params(reduction_func, reduction_params) == 0)
1156  pref_params = reduction_params
1157  print reduction_func, reduction_params
1158  loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
1159  endif
1160  break
1161  endswitch
1162  endif
1163 
1164  dfref dataDF
1165  if (strlen(loaded_filename) > 0)
1166  setdatafolder $("root:" + nickname)
1167  dataDF = GetDataFolderDFR()
1168  string /g pearl_explorer_import = "load_hdf_file"
1169  endif
1170 
1171  setdatafolder saveDF
1172  return dataDF
1173 };
1174 
1175 static dfr load_itx_file(string filename, string options = defaultValue){
1176  string filename
1177  string options
1178 
1179  dfref saveDF = GetDataFolderDFR()
1180  string nickname = itx_suggest_foldername(filename)
1181 
1182  if (ParamIsDefault(options))
1183  options = ""
1184  endif
1185 
1186  setdatafolder root:
1187  newdatafolder /s/o $("root:" + nickname)
1188  dfref dataDF = GetDataFolderDFR()
1189 
1190  // note: some versions of PEARL data files save data to a new data folder,
1191  // and leave the newly created folder as the current folder.
1192  // the free data folder is used by those files which don't create their own data folder.
1193  // this is the new recommended behaviour
1194 
1195  LoadWave /t/p=pearl_explorer_filepath/q filename
1196  svar waves = s_wavenames
1197  dfref actDF = GetDataFolderDFR()
1198  if (v_flag > 0)
1199  string /g pearl_explorer_import = "load_itx_file"
1200  endif
1201 
1202  if (!DataFolderRefsEqual(actDF, dataDF))
1203  // the file created its own data folder.
1204  // let's kill the pre-allocated folder
1205  setdatafolder dataDF
1206  if (ItemsInList(WaveList("*", ";", ""), ";") == 0)
1207  killdatafolder /z dataDF
1208  endif
1209  endif
1210 
1211  setdatafolder saveDF
1212  return actDF
1213 };
1214 
1218 static dfr load_mtrx_file(string filename, string options = defaultValue){
1219  string filename
1220  string options
1221 
1222  dfref saveDF = GetDataFolderDFR()
1223  dfref dataDF = $""
1224 
1225 #if exists("MFR_OpenResultFile")
1226  setdatafolder root:
1227  string datasets = ""
1228  datasets = mtrx_load_file("pearl_explorer_filepath", filename)
1229  if (strlen(datasets) > 0)
1230  string /g pearl_explorer_import = "load_mtrx_file"
1231  string s1 = StringFromList(0, datasets)
1232  wave w1 = $s1
1233  dataDF = GetWavesDataFolderDFR(w1)
1234  endif
1235 #endif
1236 
1237  setdatafolder saveDF
1238  return dataDF
1239 };
1240 
1241 string itx_suggest_foldername(string filename, variable ignoredate = defaultValue, string sourcename = defaultValue, variable unique = defaultValue){
1242  // suggests the name of a data folder based on a file name
1243  // if the file name follows the naming convention source-date-index.extension,
1244  // the function tries to generate the nick name as source_date_index.
1245  // otherwise it's just a cleaned up version of the file name.
1246  string filename// file name, including extension. can also include a folder path (which is ignored)
1247  // the extension is currently ignored, but may be used later to select the parent folder
1248  variable ignoredate// if non-zero, the nick name will not include the date part
1249  // defaults to zero
1250  string sourcename// nick name of the data source
1251  // the function tries to detect the source from the file name
1252  // this option can be used to override auto-detection
1253  // allowed values: sscan, otf
1254  variable unique// if non-zero, the resulting name is made a unique data folder name in the current data folder
1255  // defaults to zero
1256 
1257  if (ParamIsDefault(ignoredate))
1258  ignoredate = 0
1259  endif
1260  if (ParamIsDefault(unique))
1261  unique = 0
1262  endif
1263 
1264  string basename = ParseFilePath(3, filename, ":", 0, 0)
1265  string extension = ParseFilePath(4, filename, ":", 0, 0)
1266  string nickname
1267 
1268  string autosource
1269  if (strsearch(basename, "X03DA_PC", 0, 2) >= 0)
1270  autosource = "sscan"
1271  basename = ReplaceString("_", basename, "-")
1272  ignoredate = 1
1273  else if (strsearch(basename, "otf", 0, 2) >= 0)
1274  autosource = "otf"
1275  endif
1276  if (ParamIsDefault(sourcename))
1277  sourcename = autosource
1278  endif
1279 
1280  variable nparts = ItemsInList(basename, "-")
1281  if (nparts >= 3)
1282  string datepart = StringFromList(nparts - 2, basename, "-")
1283  string indexpart = StringFromList(nparts - 1, basename, "-")
1284  if (ignoredate)
1285  sprintf nickname, "%s_%s", sourcename, indexpart
1286  else
1287  sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart
1288  endif
1289  else
1290  nickname = CleanupName(basename, 0)
1291  endif
1292 
1293  if (unique && CheckName(nickname, 11))
1294  nickname = UniqueName(nickname + "_", 11, 0)
1295  endif
1296 
1297  return nickname
1298 };
1299 
1301  PauseUpdate; Silent 1// building window...
1302  NewPanel /K=1 /W=(800,0,1530,444) as "PEARL Data Explorer"
1303  ModifyPanel cbRGB=(48640,56832,60160)
1304 
1305  GroupBox gb_filepath,pos={8,4},size={224,52},title="file system folder"
1306  TitleBox tb_filepath,pos={20,24},size={174,20},frame=2
1307  TitleBox tb_filepath,variable=root:packages:pearl_explorer:s_filepath,fixedSize=1
1308  Button b_browse_filepath,pos={200,24},size={20,20},proc=PearlDataExplorer#bp_browse_filepath,title="..."
1309  Button b_browse_filepath,fColor=(65280,48896,32768)
1310 
1311  GroupBox gb_prefs,pos={240,4},size={58,52},title="prefs",help={"explorer package preferences"}
1312  Button b_save_prefs,pos={252,20},size={32,17},proc=PearlDataExplorer#bp_save_prefs,title="save"
1313  Button b_save_prefs,help={"save preferences of the data explorer package (data file path, attributes filter)"}
1314  Button b_save_prefs,fColor=(65280,48896,32768)
1315  Button b_load_prefs,pos={252,36},size={32,17},proc=PearlDataExplorer#bp_load_prefs,title="load"
1316  Button b_load_prefs,help={"load preferences of the data explorer package"}
1317  Button b_load_prefs,fColor=(65280,48896,32768)
1318 
1319  GroupBox gb_filelist,pos={8,64},size={224,372},title="data files"
1320  ListBox lb_files,pos={20,84},size={200,212},proc=PearlDataExplorer#lbp_filelist
1321  ListBox lb_files,listWave=root:packages:pearl_explorer:wtFiles
1322  ListBox lb_files,selWave=root:packages:pearl_explorer:wSelectedFiles,row= 11,mode= 4
1323  TitleBox tb_file_info,pos={20,300},size={198,78},frame=2,fixedSize=1
1324  TitleBox tb_file_info,variable= root:packages:pearl_explorer:s_file_info
1325 
1326  Button b_update_filelist,pos={20,386},size={60,20},proc=PearlDataExplorer#bp_update_filelist,title="update list"
1327  Button b_update_filelist,fColor=(65280,48896,32768)
1328  CheckBox cb_file_preview,pos={84,390},size={60,20},title="preview"
1329  CheckBox cb_file_preview,help={"enable/disable automatic preview window when selecting a data file"}
1330  CheckBox cb_file_preview,value=1
1331  Button b_file_prev,pos={176,386},size={20,20},proc=PearlDataExplorer#bp_file_prev,title="\\W646"
1332  Button b_file_prev,help={"previous file"}
1333  Button b_file_prev,fColor=(65280,48896,32768)
1334  Button b_file_next,pos={200,386},size={20,20},proc=PearlDataExplorer#bp_file_next,title="\\W649"
1335  Button b_file_next,help={"next file"}
1336  Button b_file_next,fColor=(65280,48896,32768)
1337 
1338  Button b_load_files,pos={20,410},size={76,20},proc=PearlDataExplorer#bp_load_files,title="load complete"
1339  Button b_load_files,help={"load the complete contents from the selected files"}
1340  Button b_load_files,fColor=(65280,48896,32768)
1341  Button b_load_files_opt,pos={100,410},size={76,20},proc=PearlDataExplorer#bp_load_files_opt,title="load reduced"
1342  Button b_load_files_opt,help={"load data from the selected files with options (reduced dimensions)"}
1343  Button b_load_files_opt,fColor=(65280,48896,32768)
1344 
1345  // datasets group
1346  GroupBox gb_datasets,pos={240,64},size={224,372},title="datasets"
1347  ListBox lb_datasets,pos={252,84},size={200,300},proc=PearlDataExplorer#lbp_datasets,help={"list of loaded datasets"}
1348  ListBox lb_datasets,listWave=root:packages:pearl_explorer:wtDatasets
1349  ListBox lb_datasets,selWave=root:packages:pearl_explorer:wSelectedDatasets,mode= 1
1350  ListBox lb_datasets,selRow= -1
1351 
1352  Button b_update_datasets,pos={252,386},size={60,20},proc=PearlDataExplorer#bp_update_datasets,title="update list"
1353  Button b_update_datasets,help={"update the list of datasets"}
1354  Button b_update_datasets,fColor=(65280,48896,32768)
1355  CheckBox cb_dataset_preview,pos={316,390},size={60,20},title="preview"
1356  CheckBox cb_dataset_preview,help={"enable/disable automatic preview window when selecting a dataset"}
1357  CheckBox cb_dataset_preview,value=0
1358  Button b_dataset_prev,pos={408,386},size={20,20},proc=PearlDataExplorer#bp_dataset_prev,title="\\W646"
1359  Button b_dataset_prev,help={"goto previous dataset"}
1360  Button b_dataset_prev,fColor=(65280,48896,32768)
1361  Button b_dataset_next,pos={432,386},size={20,20},proc=PearlDataExplorer#bp_dataset_next,title="\\W649"
1362  Button b_dataset_next,help={"goto next dataset"}
1363  Button b_dataset_next,fColor=(65280,48896,32768)
1364 
1365  Button b_dataset_folder,pos={252,410},size={50,20},proc=PearlDataExplorer#bp_dataset_folder,title="goto DF"
1366  Button b_dataset_folder,help={"set the current data folder of the selected dataset"}
1367  Button b_dataset_folder,fColor=(65280,48896,32768)
1368  Button b_dataset_display,pos={306,410},size={50,20},proc=PearlDataExplorer#bp_dataset_display,title="display"
1369  Button b_dataset_display,help={"display the selected dataset in its own window"}
1370  Button b_dataset_display,fColor=(65280,48896,32768)
1371 
1372  GroupBox gb_preview,pos={472,4},size={250,52},title="preview"
1373  TitleBox tb_preview_file,pos={484,24},size={226,20},frame=2
1374  TitleBox tb_preview_file,variable=root:packages:pearl_explorer:s_preview_file,fixedSize=1
1375 
1376  GroupBox gb_attributes,pos={472,64},size={250,372},title="attributes"
1377  Button b_attr_notebook,pos={484,386},size={60,20},proc=PearlDataExplorer#bp_attr_notebook,title="notebook"
1378  Button b_attr_notebook,help={"show attribute list in a notebook"}
1379  Button b_attr_notebook,fColor=(65280,48896,32768)
1380 
1381  String fldrSav0= GetDataFolder(1)
1382  SetDataFolder root:packages:pearl_explorer:
1383  Edit/W=(484,84,710,384)/HOST=# attr_names,attr_values
1384  ModifyTable format(Point)=1,width(Point)=0,width(attr_names)=103,width(attr_values)=103
1385  ModifyTable statsArea=85
1386  SetDataFolder fldrSav0
1387  RenameWindow #,T0
1388  SetActiveSubwindow ##
1389 };
1390 
1391 static variable bp_load_prefs(WMButtonAction* ba){
1392  STRUCT WMButtonAction &ba
1393 
1394  switch( ba.eventCode )
1395  case 2:// mouse up
1396  load_prefs()
1397  break
1398  case -1:// control being killed
1399  break
1400  endswitch
1401 
1402  return 0
1403 };
1404 
1405 static variable bp_save_prefs(WMButtonAction* ba){
1406  STRUCT WMButtonAction &ba
1407 
1408  switch( ba.eventCode )
1409  case 2:// mouse up
1410  save_prefs()
1411  break
1412  case -1:// control being killed
1413  break
1414  endswitch
1415 
1416  return 0
1417 };
1418 
1419 static variable bp_browse_filepath(WMButtonAction* ba){
1420  STRUCT WMButtonAction &ba
1421 
1422  dfref saveDF = GetDataFolderDFR()
1423 
1424  switch( ba.eventCode )
1425  case 2:// mouse up
1426  PathInfo /S pearl_explorer_filepath
1427  NewPath /M="select data file folder" /O/Z pearl_explorer_filepath
1428  if (v_flag == 0)
1429  PathInfo /S pearl_explorer_filepath
1430  svar filepath = $(package_path + "s_filepath")
1431  filepath = s_path
1432  update_filelist()
1433  endif
1434  break
1435  case -1:// control being killed
1436  break
1437  endswitch
1438 
1439  setdatafolder saveDF
1440  return 0
1441 };
1442 
1443 static variable bp_update_filelist(WMButtonAction* ba){
1444  STRUCT WMButtonAction &ba
1445 
1446  switch( ba.eventCode )
1447  case 2:// mouse up
1448  update_filelist()
1449  break
1450  case -1:// control being killed
1451  break
1452  endswitch
1453 
1454  return 0
1455 };
1456 
1457 static variable bp_load_files(WMButtonAction* ba){
1458  STRUCT WMButtonAction &ba
1459 
1460  switch( ba.eventCode )
1461  case 2:// mouse up
1463  break
1464  case -1:// control being killed
1465  break
1466  endswitch
1467 
1468  return 0
1469 };
1470 
1471 static variable bp_load_files_opt(WMButtonAction* ba){
1472  STRUCT WMButtonAction &ba
1473 
1474  switch( ba.eventCode )
1475  case 2:// mouse up
1476  load_selected_files(options="")
1477  break
1478  case -1:// control being killed
1479  break
1480  endswitch
1481 
1482  return 0
1483 };
1484 
1485 static variable bp_file_next(WMButtonAction* ba){
1486  STRUCT WMButtonAction &ba
1487 
1488  dfref saveDF = GetDataFolderDFR()
1489 
1490  switch( ba.eventCode )
1491  case 2:// mouse up
1492  setdatafolder $package_path
1493  wave /t wtFiles
1494  wave wSelectedFiles
1495  FindValue /i=1 wSelectedFiles
1496  v_value += 1
1497  if (v_value >= numpnts(wtFiles))
1498  v_value = min(numpnts(wtFiles) - 1, 0)
1499  endif
1500  wSelectedFiles = p == v_value
1501  if (v_value >= 0)
1502  variable ifile = v_value
1503  ControlInfo /W=PearlDataExplorer cb_file_preview
1504  if (v_value)
1505  preview_file(wtFiles[ifile])
1506  endif
1507  endif
1508  break
1509  case -1:// control being killed
1510  break
1511  endswitch
1512 
1513  setdatafolder saveDF
1514  return 0
1515 };
1516 
1517 static variable bp_file_prev(WMButtonAction* ba){
1518  STRUCT WMButtonAction &ba
1519 
1520  dfref saveDF = GetDataFolderDFR()
1521 
1522  switch( ba.eventCode )
1523  case 2:// mouse up
1524  setdatafolder $package_path
1525  wave /t wtFiles
1526  wave wSelectedFiles
1527  FindValue /i=1 wSelectedFiles
1528  v_value -= 1
1529  if (v_value < 0)
1530  v_value = numpnts(wtFiles) - 1
1531  endif
1532  wSelectedFiles = p == v_value
1533  if (v_value >= 0)
1534  variable ifile = v_value
1535  ControlInfo /W=PearlDataExplorer cb_file_preview
1536  if (v_value)
1537  preview_file(wtFiles[ifile])
1538  endif
1539  endif
1540  break
1541  case -1:// control being killed
1542  break
1543  endswitch
1544 
1545  setdatafolder saveDF
1546  return 0
1547 };
1548 
1549 static variable lbp_filelist(WMListboxAction* lba){
1550  STRUCT WMListboxAction &lba
1551 
1552  Variable row = lba.row
1553  Variable col = lba.col
1554  WAVE/T/Z listWave = lba.listWave
1555  WAVE/Z selWave = lba.selWave
1556 
1557  switch( lba.eventCode )
1558  case -1:// control being killed
1559  break
1560  case 1:// mouse down
1561  if (selWave[row])
1562  ControlInfo /W=PearlDataExplorer cb_file_preview
1563  if (v_value)
1564  preview_file(listWave[row])
1565  endif
1566  endif
1567  break
1568  case 3:// double click
1569  break
1570  case 4:// cell selection
1571  case 5:// cell selection plus shift key
1572  break
1573  case 6:// begin edit
1574  break
1575  case 7:// finish edit
1576  break
1577  case 13:// checkbox clicked (Igor 6.2 or later)
1578  break
1579  endswitch
1580 
1581  return 0
1582 };
1583 
1584 static variable bp_update_datasets(WMButtonAction* ba){
1585  STRUCT WMButtonAction &ba
1586 
1587  switch( ba.eventCode )
1588  case 2:// mouse up
1589  update_datasets()
1590  break
1591  case -1:// control being killed
1592  break
1593  endswitch
1594 
1595  return 0
1596 };
1597 
1598 static variable bp_dataset_folder(WMButtonAction* ba){
1599  STRUCT WMButtonAction &ba
1600 
1601  switch( ba.eventCode )
1602  case 2:// mouse up
1603  ControlInfo /W=PearlDataExplorer lb_datasets
1604  if (v_value >= 0)
1605  setdatafolder $package_path
1606  wave /t wtDatasets
1607  string dataset = wtDatasets[v_value]
1608  string cmd
1609  sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset)
1610  execute /q /z cmd
1611  cmd = "setdatafolder :scan1"
1612  execute /q /z cmd
1613  sprintf cmd, "setdatafolder %s", GetDataFolder(1)
1614  print cmd
1615  endif
1616  break
1617  case -1:// control being killed
1618  break
1619  endswitch
1620 
1621  return 0
1622 };
1623 
1624 static variable bp_dataset_display(WMButtonAction* ba){
1625  STRUCT WMButtonAction &ba
1626 
1627  switch( ba.eventCode )
1628  case 2:// mouse up
1629  ControlInfo /W=PearlDataExplorer lb_datasets
1630  if (v_value >= 0)
1631  setdatafolder $package_path
1632  wave /t wtDatasets
1633  string dataset = wtDatasets[v_value]
1634  display_dataset(dataset)
1635  endif
1636  break
1637  case -1:// control being killed
1638  break
1639  endswitch
1640 
1641  return 0
1642 };
1643 
1644 static variable bp_dataset_next(WMButtonAction* ba){
1645  STRUCT WMButtonAction &ba
1646 
1647  switch( ba.eventCode )
1648  case 2:// mouse up
1649  ControlInfo /W=PearlDataExplorer lb_datasets
1650  wave /t wtDatasets = $(s_datafolder + s_value)
1651  v_value += 1
1652  if (v_value >= numpnts(wtDatasets))
1653  v_value = min(0, numpnts(wtDatasets) - 1)
1654  endif
1655  ListBox lb_datasets win=PearlDataExplorer, selRow=v_value
1656  if (v_value >= 0)
1657  variable ids = v_value
1658  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1659  if (v_value)
1660  preview_dataset(wtDatasets[ids])
1661  endif
1662  endif
1663  break
1664  case -1:// control being killed
1665  break
1666  endswitch
1667 
1668  return 0
1669 };
1670 
1671 static variable bp_dataset_prev(WMButtonAction* ba){
1672  STRUCT WMButtonAction &ba
1673 
1674  switch( ba.eventCode )
1675  case 2:// mouse up
1676  ControlInfo /W=PearlDataExplorer lb_datasets
1677  wave /t wtDatasets = $(s_datafolder + s_value)
1678  v_value -= 1
1679  if (v_value < 0)
1680  v_value = max(-1, numpnts(wtDatasets) - 1)
1681  endif
1682  ListBox lb_datasets win=PearlDataExplorer, selRow=v_value
1683  if (v_value >= 0)
1684  variable ids = v_value
1685  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1686  if (v_value)
1687  preview_dataset(wtDatasets[ids])
1688  endif
1689  endif
1690  break
1691  case -1:// control being killed
1692  break
1693  endswitch
1694 
1695  return 0
1696 };
1697 
1698 static variable lbp_datasets(WMListboxAction* lba){
1699  STRUCT WMListboxAction &lba
1700 
1701  Variable row = lba.row
1702  Variable col = lba.col
1703  WAVE/T/Z listWave = lba.listWave
1704  WAVE/Z selWave = lba.selWave
1705 
1706  switch( lba.eventCode )
1707  case -1:// control being killed
1708  break
1709  case 1:// mouse down
1710  if (row >= 0)
1711  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1712  if (v_value)
1713  preview_dataset(listWave[row])
1714  endif
1715  endif
1716  break
1717  case 3:// double click
1718  break
1719  case 4:// cell selection
1720  case 5:// cell selection plus shift key
1721  break
1722  case 6:// begin edit
1723  break
1724  case 7:// finish edit
1725  break
1726  case 13:// checkbox clicked (Igor 6.2 or later)
1727  break
1728  endswitch
1729 
1730  return 0
1731 };
1732 
1733 static variable bp_attr_notebook(WMButtonAction* ba){
1734  STRUCT WMButtonAction &ba
1735 
1736  dfref saveDF = GetDataFolderDFR()
1737 
1738  switch( ba.eventCode )
1739  case 2:// mouse up
1740  setdatafolder $package_path
1741  svar s_preview_file
1742  wave /t /z attr_names
1743  wave /t /z attr_values
1744  if (WaveExists(attr_names))
1745  attributes_notebook(attr_names, attr_values, s_preview_file)
1746  endif
1747  break
1748  case -1:// control being killed
1749  break
1750  endswitch
1751 
1752  setdatafolder saveDF
1753  return 0
1754 };
1755 
static dfr load_mtrx_file(string filename, string options=defaultValue)
load a matrix (STM) data file
static const string package_path
-
string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress=defaultValue)
load and reduce the ScientaImage dataset of the first scan of a PShell data file. ...
-
string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load a single image from a HDF5 file created by the Area Detector software.
+
string adh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load a single image from a HDF5 file created by the Area Detector software.
static variable update_datasets()
+
string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
load and reduce the ScientaImage dataset of the first scan of a PShell data file. ...
static variable bp_browse_filepath(WMButtonAction *ba)
static variable preview_file(string filename)
variable prompt_default_process(string *param)
prototype for prompting for processing function parameters.
-
string adh5_load_info(string APathName, string AFileName)
load descriptive info from a HDF5 file created by the Area Detector software.
+
string adh5_load_info(string APathName, string AFileName)
load descriptive info from a HDF5 file created by the Area Detector software.
static variable bp_dataset_prev(WMButtonAction *ba)
static string display_preview_trace(wave xtrace, wave ytrace)
static variable bp_file_prev(WMButtonAction *ba)
@@ -143,7 +143,7 @@ $(document).ready(function(){initNavTree('pearl-data-explorer_8ipf_source.html',
static const string package_name
static variable update_filelist()
read a list of PEARL files from the file system
static dfr load_itx_file(string filename, string options=defaultValue)
-
string psh5_load_preview(string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue, string pref_scans=defaultValue, string pref_datasets=defaultValue)
load a preview image from a PShell data file.
+
string psh5_load_preview(string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue, string pref_scans=defaultValue, string pref_datasets=defaultValue)
load a preview image from a PShell data file.
static variable bp_attr_notebook(WMButtonAction *ba)
static variable load_file(string filename, string options=defaultValue)
preview and import panel for PEARL data
@@ -151,21 +151,21 @@ $(document).ready(function(){initNavTree('pearl-data-explorer_8ipf_source.html',
static variable preview_setscale_x(wave data, wave preview)
static variable bp_save_prefs(WMButtonAction *ba)
static dfr load_hdf_file(string filename, string options=defaultValue)
-
string ad_suggest_foldername(string filename, variable ignoredate=defaultValue, string sourcename=defaultValue, variable unique=defaultValue)
generate the name of a data folder based on a file name.
+
string ad_suggest_foldername(string filename, variable ignoredate=defaultValue, string sourcename=defaultValue, variable unique=defaultValue)
generate the name of a data folder based on a file name.
static wave preview_hdf_file(string filename)
load the preview of a PEARL HDF5 file.
static variable pearl_file_type(string filename)
check whether a file can be imported by this module.
static variable bp_dataset_display(WMButtonAction *ba)
static const string ks_filematch_itx
-
string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
import everything from a HDF5 file created by the Area Detector software.
+
string adh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
import everything from a HDF5 file created by the Area Detector software.
static variable bp_dataset_next(WMButtonAction *ba)
static variable extract_preview_image(wave data, wave preview)
-
string psh5_load_info(string APathName, string AFileName)
load descriptive info from a PShell data file.
-
string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data=defaultValue, variable load_attr=defaultValue, variable progress=defaultValue)
load and reduce a dataset from a HDF5 file created by the Area Detector software. ...
+
string psh5_load_info(string APathName, string AFileName)
load descriptive info from a PShell data file.
+
string adh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable load_data=defaultValue, variable load_attr=defaultValue, variable progress=defaultValue)
load and reduce a dataset from a HDF5 file created by the Area Detector software. ...
string ad_display_profiles(wave image, string filter=defaultValue)
open a new profiles graph window.
static variable bp_update_filelist(WMButtonAction *ba)
variable pearl_data_explorer()
string itx_suggest_foldername(string filename, variable ignoredate=defaultValue, string sourcename=defaultValue, variable unique=defaultValue)
-
string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load everything from a PShell data file.
+
string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
load everything from a PShell data file.
static variable load_prefs()
variable prompt_func_params(string func_name, string *func_param)
static wave preview_itx_file(string filename)
@@ -180,7 +180,7 @@ $(document).ready(function(){initNavTree('pearl-data-explorer_8ipf_source.html',
static variable attributes_notebook(wave attr_names, wave attr_values, string title)
string mtrx_load_file(string pathName, string fileName, string traces=defaultValue)
load all data from a Matrix data file.
static variable preview_attributes(dfref attr_folder, dfref dest_folder=defaultValue, wave attr_filter=defaultValue, variable include_datawaves=defaultValue, variable include_infowaves=defaultValue)
-
string adh5_list_reduction_funcs()
get a list of functions which can be used as reduction functions.
+
string adh5_list_reduction_funcs()
get a list of functions which can be used as reduction functions.
static variable notebook_add_attributes(string notebook_name, wave attr_filter, wave attr_names, wave attr_values)
threadsafe wave ad_extract_slab(wave dataset, variable x1, variable x2, variable y1, variable y2, variable z1, variable z2, string destname, variable noavg=defaultValue, variable pscale=defaultValue)
2D cut through 3D dataset, integrate in normal dimension
@@ -189,7 +189,7 @@ $(document).ready(function(){initNavTree('pearl-data-explorer_8ipf_source.html', @@ -241,7 +270,7 @@ Variables
-

Definition at line 549 of file pearl-fitfuncs.ipf.

+

Definition at line 694 of file pearl-fitfuncs.ipf.

@@ -269,7 +298,66 @@ Variables
-

Definition at line 362 of file pearl-fitfuncs.ipf.

+

Definition at line 507 of file pearl-fitfuncs.ipf.

+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
threadsafe variable DoniachSunjic (variable x,
variable amp,
variable pos,
variable sing,
variable fwhm 
)
+
+ +

Doniach-Sunjic line shape.

+

[S. Doniach, M. Sunjic, J. Phys. C 3 (1970) 285]

+
Parameters
+ + + + + + +
xindependent variable
ampamplitude
posposition
singsingularity index (0 <= sing < 1)
fwhmfull width at half maximum
+
+
+ +

Definition at line 140 of file pearl-fitfuncs.ipf.

@@ -303,7 +391,7 @@ Variables
-

Definition at line 301 of file pearl-fitfuncs.ipf.

+

Definition at line 446 of file pearl-fitfuncs.ipf.

@@ -321,7 +409,7 @@ Variables
-

Definition at line 212 of file pearl-fitfuncs.ipf.

+

Definition at line 357 of file pearl-fitfuncs.ipf.

@@ -349,7 +437,7 @@ Variables
-

Definition at line 38 of file pearl-fitfuncs.ipf.

+

Definition at line 183 of file pearl-fitfuncs.ipf.

@@ -377,7 +465,7 @@ Variables
-

Definition at line 61 of file pearl-fitfuncs.ipf.

+

Definition at line 206 of file pearl-fitfuncs.ipf.

@@ -405,7 +493,7 @@ Variables
-

Definition at line 89 of file pearl-fitfuncs.ipf.

+

Definition at line 234 of file pearl-fitfuncs.ipf.

@@ -433,7 +521,7 @@ Variables
-

Definition at line 130 of file pearl-fitfuncs.ipf.

+

Definition at line 275 of file pearl-fitfuncs.ipf.

@@ -477,7 +565,7 @@ Variables
  • pw[5] = gaussian width = FWHM / 1.66511
  • -

    Definition at line 672 of file pearl-fitfuncs.ipf.

    +

    Definition at line 817 of file pearl-fitfuncs.ipf.

    @@ -517,7 +605,195 @@ Variables
    -

    Definition at line 383 of file pearl-fitfuncs.ipf.

    +

    Definition at line 528 of file pearl-fitfuncs.ipf.

    + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + +
    variable MultiDoniachSunjicLinBG (wave w,
    variable x 
    )
    +
    + +

    multiple doniach-sunjic peaks on a linear background fit function.

    +
    Parameters
    + + + +
    wshape parameters. the length of the wave defines the number of peaks.
      +
    • w[0] = constant coefficient of background
    • +
    • w[1] = linear coefficient of background
    • +
    • w[2 + (i-1) * 4] = amplitude of peak i
    • +
    • w[3 + (i-1) * 4] = position of peak i
    • +
    • w[4 + (i-1) * 4] = width (fwhm) of peak i
    • +
    • w[5 + (i-1) * 4] = singularity index (0...1) of peak i
    • +
    +
    xindependent variable
    +
    +
    + +

    Definition at line 167 of file pearl-fitfuncs.ipf.

    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    threadsafe variable MultiGaussLinBG (wave w,
    variable x 
    )
    +
    + +

    multiple gaussian peaks on a linear background fit function.

    +
    Note
    FWHM = width * 2 * sqrt(ln(2)) = width * 1.665
    +
    Parameters
    + + + +
    wshape parameters. the length of the wave defines the number of peaks.
      +
    • w[0] = constant coefficient of background
    • +
    • w[1] = linear coefficient of background
    • +
    • w[2 + (i-1) * 3] = amplitude of peak i
    • +
    • w[3 + (i-1) * 3] = position of peak i
    • +
    • w[4 + (i-1) * 3] = width of peak i (see note)
    • +
    +
    xindependent variable
    +
    +
    + +

    Definition at line 44 of file pearl-fitfuncs.ipf.

    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    threadsafe variable MultiGaussLinBG_AO (wave pw,
    wave yw,
    wave xw 
    )
    +
    + +

    multiple gaussian peaks on a linear background fit function (all at once).

    +

    this is the all-at-once version of MultiGaussLinBG. it runs about 15% faster compared to the point-by-point function (measured on a 200 point spectrum with 3 peaks).

    +
    Note
    FWHM = width * 2 * sqrt(ln(2)) = width * 1.665
    +
    Parameters
    + + + + +
    pwshape parameters. the length of the wave defines the number of peaks.
      +
    • pw[0] = constant coefficient of background
    • +
    • pw[1] = linear coefficient of background
    • +
    • pw[2 + (i-1) * 3] = amplitude of peak i
    • +
    • pw[3 + (i-1) * 3] = position of peak i
    • +
    • pw[4 + (i-1) * 3] = width of peak i (see note)
    • +
    +
    ywy (dependent) values.
    xwx (independent) independent values.
    +
    +
    + +

    Definition at line 79 of file pearl-fitfuncs.ipf.

    + +
    +
    + +
    +
    + + + + + + + + + + + + + + + + + + +
    variable MultiVoigtLinBG (wave w,
    variable x 
    )
    +
    + +

    multiple voigt peaks on a linear background fit function.

    +
    Parameters
    + + + +
    wshape parameters. the length of the wave defines the number of peaks.
      +
    • w[0] = constant coefficient of background
    • +
    • w[1] = linear coefficient of background
    • +
    • w[2 + (i-1) * 4] = amplitude of peak i
    • +
    • w[3 + (i-1) * 4] = position of peak i
    • +
    • w[4 + (i-1) * 4] = width of peak i
    • +
    • w[5 + (i-1) * 4] = shape of peak i
    • +
    +
    xindependent variable
    +
    +
    + +

    Definition at line 110 of file pearl-fitfuncs.ipf.

    @@ -545,7 +821,7 @@ Variables
    -

    Definition at line 518 of file pearl-fitfuncs.ipf.

    +

    Definition at line 663 of file pearl-fitfuncs.ipf.

    @@ -573,22 +849,7 @@ Variables
    -

    Definition at line 617 of file pearl-fitfuncs.ipf.

    - -
    - -

    Variable Documentation

    - -
    -
    - - - - -
    version
    -
    - -

    Definition at line 5 of file pearl-fitfuncs.ipf.

    +

    Definition at line 762 of file pearl-fitfuncs.ipf.

    @@ -598,7 +859,7 @@ Variables
    -Go to the documentation of this file.
    1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
    2 #pragma IgorVersion = 6.2
    3 #pragma ModuleName = PearlFitFuncs
    4 #pragma version = 1.01
    5 #include "mm-physconst", version >= 1.05
    6 
    7 // various fit functions for photoelectron spectroscopy
    8 
    9 // $Id$
    10 // author: matthias.muntwiler@psi.ch
    11 // Copyright (c) 2013-14 Paul Scherrer Institut
    12 
    13 // Licensed under the Apache License, Version 2.0 (the "License");
    14 // you may not use this file except in compliance with the License.
    15 // You may obtain a copy of the License at
    16 // http://www.apache.org/licenses/LICENSE-2.0
    17 
    18 //------------------------------------------------------------------------------
    19 // Doniach-Sunjic fit functions
    20 //------------------------------------------------------------------------------
    21 
    22 threadsafe variable DoniachSunjic(variable x, variable amp, variable pos, variable sing, variable fwhm){
    23  // Doniach-Sunjic line shape
    24  // [S. Doniach, M. Sunjic, J. Phys. C 3 (1970) 285]
    25  variable x// independent variable
    26  variable amp// amplitude
    27  variable pos// position
    28  variable sing// singularity index (0 <= sing < 1)
    29  variable fwhm// width
    30 
    31  variable nom, denom
    32  nom = cos(pi * sing / 2 + (1 - sing) * atan((x - pos) / fwhm * 2))
    33  denom = ((x - pos)^2 + fwhm^2 / 4)^((1 - sing) / 2)
    34 
    35  return amp * nom / denom * fwhm / 2
    36 };
    37 
    38 threadsafe variable ds1_bg(wave w, variable x){
    39  // Doniach-Sunjic fit function
    40  // 0 <= sing < 1
    41  wave w// coefficients - see below
    42  variable x// independent variable
    43 
    44  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    45  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    46  //CurveFitDialog/ Equation:
    47  //CurveFitDialog/ f(x) = DoniachSunjic(x, amp, pos, sing, fwhm) + bg
    48  //CurveFitDialog/ End of Equation
    49  //CurveFitDialog/ Independent Variables 1
    50  //CurveFitDialog/ x
    51  //CurveFitDialog/ Coefficients 5
    52  //CurveFitDialog/ w[0] = bg
    53  //CurveFitDialog/ w[1] = amp
    54  //CurveFitDialog/ w[2] = pos
    55  //CurveFitDialog/ w[3] = sing
    56  //CurveFitDialog/ w[4] = FWHM
    57 
    58  return DoniachSunjic(x, w[1], w[2], w[3], w[4]) + w[0]
    59 };
    60 
    61 threadsafe variable ds2_bg(wave w, variable x){
    62  Wave w
    63  Variable x
    64 
    65  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    66  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    67  //CurveFitDialog/ Equation:
    68  //CurveFitDialog/ f(x) = w_0+( w_1*cos(pi*w_3/2+(1-w_3)*atan((x-w_2)/w_4)))/(((x-w_2)^2+w_4^2)^((1-w_3)/2)) +(w_5*cos(pi*w_7/2+(1-w_7)*atan((x-(w_6))/w_8)))/(((x-w_6)^2+w_8^2)^((1-w_7)/2))
    69  //CurveFitDialog/ End of Equation
    70  //CurveFitDialog/ Independent Variables 1
    71  //CurveFitDialog/ x
    72  //CurveFitDialog/ Coefficients 9
    73  //CurveFitDialog/ w[0] = bg
    74  //CurveFitDialog/ w[1] = amp1
    75  //CurveFitDialog/ w[2] = pos1
    76  //CurveFitDialog/ w[3] = sing1
    77  //CurveFitDialog/ w[4] = wid1
    78  //CurveFitDialog/ w[5] = amp2
    79  //CurveFitDialog/ w[6] = pos2
    80  //CurveFitDialog/ w[7] = sing2
    81  //CurveFitDialog/ w[8] = wid2
    82 
    83  variable ds1 = DoniachSunjic(x, w[1], w[2], w[3], w[4])
    84  variable ds2 = DoniachSunjic(x, w[5], w[6], w[7], w[8])
    85 
    86  return w[0] + ds1 + ds2
    87 };
    88 
    89 variable ds4_bg(wave w, variable x){
    90  Wave w
    91  Variable x
    92 
    93  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    94  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    95  //CurveFitDialog/ Equation:
    96  //CurveFitDialog/ f(x) = w_0+( w_1*cos(pi*w_3/2+(1-w_3)*atan((x-w_2)/w_4)))/(((x-w_2)^2+w_4^2)^((1-w_3)/2)) +(w_5*cos(pi*w_7/2+(1-w_7)*atan((x-(w_6))/w_8)))/(((x-w_6)^2+w_8^2)^((1-w_7)/2)) +( w_9*cos(pi*w_11/2+(1-w_11)*atan((x-w_10)/w_12)))/(((x-w_10)^2+w_12^2)^((1-w_11)/2)) +( w_13*cos(pi*w_15/2+(1-w_15)*atan((x-w_14)/w_16)))/(((x-w_14)^2+w_16^2)^((1-w_15)/2))
    97  //CurveFitDialog/ End of Equation
    98  //CurveFitDialog/ Independent Variables 1
    99  //CurveFitDialog/ x
    100  //CurveFitDialog/ Coefficients 17
    101  //CurveFitDialog/ w[0] = w_0
    102  //CurveFitDialog/ w[1] = w_11
    103  //CurveFitDialog/ w[2] = w_12
    104  //CurveFitDialog/ w[3] = w_13
    105  //CurveFitDialog/ w[4] = w_14
    106  //CurveFitDialog/ w[5] = w_21
    107  //CurveFitDialog/ w[6] = w_22
    108  //CurveFitDialog/ w[7] = w_23
    109  //CurveFitDialog/ w[8] = w_24
    110  //CurveFitDialog/ w[9] = w_31
    111  //CurveFitDialog/ w[10] = w_32
    112  //CurveFitDialog/ w[11] = w_33
    113  //CurveFitDialog/ w[12] = w_34
    114  //CurveFitDialog/ w[13] = w_41
    115  //CurveFitDialog/ w[14] = w_42
    116  //CurveFitDialog/ w[15] = w_43
    117  //CurveFitDialog/ w[16] = w_44
    118  Variable ds1, ds2, ds3, ds4
    119  ds1=( w[1]*cos(pi*w[3]/2+(1-w[3])*atan((x-w[2])/w[4])))/(((x-w[2])^2+w[4]^2)^((1-w[3])/2))
    120  ds2=( w[5]*cos(pi*w[7]/2+(1-w[7])*atan((x-w[6])/w[8])))/(((x-w[6])^2+w[8]^2)^((1-w[7])/2))
    121  ds3=( w[9]*cos(pi*w[11]/2+(1-w[11])*atan((x-w[10])/w[12])))/(((x-w[10])^2+w[12]^2)^((1-w[11])/2))
    122  ds4=( w[13]*cos(pi*w[15]/2+(1-w[15])*atan((x-w[14])/w[16])))/(((x-w[14])^2+w[16]^2)^((1-w[15])/2))
    123 
    124 
    125  return w[0]+ds1+ds2+ds3+ds4
    126 
    127 
    128 };
    129 
    130 variable ds6_bg(wave w, variable x){
    131  Wave w
    132  Variable x
    133 
    134  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    135  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    136  //CurveFitDialog/ Equation:
    137  //CurveFitDialog/
    138  //CurveFitDialog/ Variable g, ds1, ds2, ds3, ds4, ds5, ds6
    139  //CurveFitDialog/ ds1=( w_11*cos(pi*w_13/2+(1-w_13)*atan((x-w_12)/w_14)))/(((x-w_12)^2+w_14^2)^((1-w_13)/2))
    140  //CurveFitDialog/ ds2=( w_21*cos(pi*w_23/2+(1-w_23)*atan((x-w_22)/w_24)))/(((x-w_22)^2+w_24^2)^((1-w_23)/2))
    141  //CurveFitDialog/ ds3=( w_31*cos(pi*w_33/2+(1-w_33)*atan((x-w_32)/w_34)))/(((x-w_32)^2+w_34^2)^((1-w_33)/2))
    142  //CurveFitDialog/ ds4=( w_41*cos(pi*w_43/2+(1-w_43)*atan((x-w_42)/w_44)))/(((x-w_42)^2+w_44^2)^((1-w_43)/2))
    143  //CurveFitDialog/ ds5=( w_51*cos(pi*w_53/2+(1-w_53)*atan((x-w_52)/w_54)))/(((x-w_52)^2+w_54^2)^((1-w_53)/2))
    144  //CurveFitDialog/ ds6=( w_61*cos(pi*w_63/2+(1-w_63)*atan((x-w_62)/w_64)))/(((x-w_62)^2+w_64^2)^((1-w_63)/2))
    145  //CurveFitDialog/
    146  //CurveFitDialog/ f(x) =w_0+ds1+ds2+ds3+ds4+ds5+ds6
    147  //CurveFitDialog/
    148  //CurveFitDialog/ End of Equation
    149  //CurveFitDialog/ Independent Variables 1
    150  //CurveFitDialog/ x
    151  //CurveFitDialog/ Coefficients 25
    152  //CurveFitDialog/ w[0] = w_0
    153  //CurveFitDialog/ w[1] = w_11
    154  //CurveFitDialog/ w[2] = w_12
    155  //CurveFitDialog/ w[3] = w_13
    156  //CurveFitDialog/ w[4] = w_14
    157  //CurveFitDialog/ w[5] = w_21
    158  //CurveFitDialog/ w[6] = w_22
    159  //CurveFitDialog/ w[7] = w_23
    160  //CurveFitDialog/ w[8] = w_24
    161  //CurveFitDialog/ w[9] = w_31
    162  //CurveFitDialog/ w[10] = w_32
    163  //CurveFitDialog/ w[11] = w_33
    164  //CurveFitDialog/ w[12] = w_34
    165  //CurveFitDialog/ w[13] = w_41
    166  //CurveFitDialog/ w[14] = w_42
    167  //CurveFitDialog/ w[15] = w_43
    168  //CurveFitDialog/ w[16] = w_44
    169  //CurveFitDialog/ w[17] = w_51
    170  //CurveFitDialog/ w[18] = w_52
    171  //CurveFitDialog/ w[19] = w_53
    172  //CurveFitDialog/ w[20] = w_54
    173  //CurveFitDialog/ w[21] = w_61
    174  //CurveFitDialog/ w[22] = w_62
    175  //CurveFitDialog/ w[23] = w_63
    176  //CurveFitDialog/ w[24] = w_64
    177 
    178 
    179  Variable ds1, ds2, ds3, ds4, ds5, ds6
    180  ds1=( w[1]*cos(pi*w[3]/2+(1-w[3])*atan((x-w[2])/w[4])))/(((x-w[2])^2+w[4]^2)^((1-w[3])/2))
    181  ds2=( w[5]*cos(pi*w[7]/2+(1-w[7])*atan((x-w[6])/w[8])))/(((x-w[6])^2+w[8]^2)^((1-w[7])/2))
    182  ds3=( w[9]*cos(pi*w[11]/2+(1-w[11])*atan((x-w[10])/w[12])))/(((x-w[10])^2+w[12]^2)^((1-w[11])/2))
    183  ds4=( w[13]*cos(pi*w[15]/2+(1-w[15])*atan((x-w[14])/w[16])))/(((x-w[14])^2+w[16]^2)^((1-w[15])/2))
    184  ds5=( w[17]*cos(pi*w[19]/2+(1-w[19])*atan((x-w[18])/w[20])))/(((x-w[18])^2+w[20]^2)^((1-w[19])/2))
    185  ds6=( w[21]*cos(pi*w[23]/2+(1-w[23])*atan((x-w[22])/w[24])))/(((x-w[22])^2+w[24]^2)^((1-w[23])/2))
    186 
    187  return w[0]+ds1+ds2+ds3+ds4+ds5+ds6
    188 
    189 };
    190 
    192  // data structure for DoniachSunjicBroadS structural function fit
    193 
    194  // waves populated by the FuncFit operation
    195  wave pw;
    196  wave yw;
    197  wave xw;
    198 
    199  // convolution parameters to be set upon creation of the structure
    200  variable precision;
    201  variable oversampling;
    202 
    203  // auxiliary fields used internally by DoniachSunjicBroadS
    204  // do not touch these
    205  wave xdw;
    206  wave model;
    209 };
    210 
    211 //------------------------------------------------------------------------------
    212 threadsafe variable DoniachSunjicBroadS(DoniachSunjicStruct* s){
    213 //------------------------------------------------------------------------------
    214  // Two-peak (bulk + surface) Doniach-Sunjic line shape with Gaussian broadening (convolution).
    215  // Hold parameter 5 at 0 to fit just one peak.
    216 
    217  // Structural fit function for efficient fitting in procedures.
    218  // Calculating the convolution requires auxiliary waves and additional, non-fitting parameters.
    219  // To eliminate the time-consuming overhead of creating and killing the auxiliary waves,
    220  // these waves are held in the fitting structure.
    221 
    222  // Caution: The function on its own is thread-safe.
    223  // However, since FuncFit uses the same structure in all threads, the fitting cannot run in parallel.
    224  // Set /NTHR=1.
    225 
    226  // See also Fit_DoniachSunjicBroad (example), DoniachSunjicBroad (conventional fit function)
    227  Struct DoniachSunjicStruct &s
    228 
    229  // pw[0] = bulk amplitude
    230  // pw[1] = bulk position
    231  // pw[2] = Lorentzian FWHM
    232  // pw[3] = Donjach-Sunjic singularity index (0..1)
    233  // pw[4] = surface shift
    234  // pw[5] = surface/bulk ratio
    235  // pw[6] = Gaussian FWHM
    236  // pw[7] = constant background
    237  // pw[8] = linear background
    238 
    239  wave xw = s.xw
    240  wave yw = s.yw
    241  wave pw = s.pw
    242 
    243  variable precision = s.precision
    244  variable oversampling = s.oversampling
    245 
    246  if (WaveExists(s.xdw))
    247  wave xdw = s.xdw
    248  wave model = s.model
    249  wave broadening = s.broadening
    250  wave convolution = s.convolution
    251  else
    252  make /n=0 /free xdw, model, broadening, convolution
    253  redimension /d xdw, model, broadening, convolution
    254  wave fs.xdw = xdw
    255  wave fs.model = model
    256  wave fs.broadening = broadening
    257  wave fs.convolution = convolution
    258  endif
    259 
    260  // calculate wave spacing based on minimum spacing of desired x points
    261  differentiate /p xw /d=xdw
    262  xdw = abs(xdw)
    263  variable xd = wavemin(xdw) / oversampling
    264 
    265  // calculate broadening wave size based on width and precision variable
    266  variable x0b = pw[6] * precision
    267  variable nb = 2 * floor(x0b / xd) + 1
    268 
    269  // calculate model size based on desired range for yw
    270  variable x0m = max(abs(wavemax(xw) - pw[1]), abs(wavemin(xw) - pw[1])) + x0b
    271  variable nm = 2 * floor(x0m / xd) + 1
    272  nb = min(nb, nm * 10)// limit wave size to avoid runtime errors for unphysically large parameter
    273 
    274  // create and calculate initial waves, normalize exponential
    275  redimension /n=(nb) broadening
    276  redimension /n=(nm) model
    277  setscale/i x -x0b, x0b, "", broadening
    278  setscale/i x -x0m, x0m, "", model
    279 
    280  broadening = exp( - (x / pw[6])^2 * 4 * ln(2))
    281  variable nrm = area(broadening)
    282  broadening /= nrm
    283  model = DoniachSunjic(x, 1, 0, pw[3], pw[2])// bulk
    284  model += DoniachSunjic(x, pw[5], pw[4], pw[3], pw[2])// surface
    285 
    286  // calculate the convolution
    287  Convolve /a broadening, model
    288  variable scale = pw[0] / wavemax(model)
    289  model *= scale
    290 
    291  // prepare output
    292  nm = numpnts(model)
    293  x0m = xd * (nm - 1) / 2
    294  setscale/i x -x0m, x0m, "", model
    295 
    296  yw = model(xw[p] - pw[1]) + pw[7] + pw[8] * xw[p]
    297  yw = numtype(yw) ? 0 : yw
    298 };
    299 
    300 //------------------------------------------------------------------------------
    301 variable DoniachSunjicBroad(wave pw, wave yw, wave xw){
    302 //------------------------------------------------------------------------------
    303  // Two-peak (bulk + surface) Doniach-Sunjic line shape with Gaussian broadening (convolution).
    304  // Hold parameter 5 at 0 to fit just one peak.
    305  // Conventional fit function for use with the curve-fitting dialog.
    306  // Compared to DoniachSunjicBroadS this function incurs extra overhead
    307  // because auxiliary waves are created and killed between function calls.
    308  // See also DoniachSunjicBroadS (optimized structural fit function)
    309  Wave pw
    310  Wave yw
    311  Wave xw
    312 
    313  // pw[0] = bulk amplitude
    314  // pw[1] = bulk position
    315  // pw[2] = Lorentzian FWHM
    316  // pw[3] = Donjach-Sunjic singularity index (0..1)
    317  // pw[4] = surface shift
    318  // pw[5] = surface/bulk ratio
    319  // pw[6] = Gaussian FWHM
    320  // pw[7] = constant background
    321  // pw[8] = linear background
    322 
    323  // set up data structure
    324  struct DoniachSunjicStruct fs
    325  fs.precision = 5
    326  fs.oversampling = 4
    327 
    328  wave fs.pw = pw
    329  wave fs.xw = xw
    330  wave fs.yw = yw
    331 
    332  // create temporary calculation waves in a global folder
    333  dfref df = root:packages:pearl_fitfuncs:doniach_sunjic
    334  if (DataFolderRefStatus(df) == 0)
    335  newdatafolder root:packages:pearl_fitfuncs:doniach_sunjic
    336  dfref df = root:packages:pearl_fitfuncs:doniach_sunjic
    337  endif
    338 
    339  wave /z /sdfr=df fs.xdw = xdw
    340  wave /z /sdfr=df fs.model = model
    341  wave /z /sdfr=df fs.broadening = broadening
    342  wave /z /sdfr=df fs.convolution = convolution
    343 
    344  if (WaveExists(fs.xdw) == 0)
    345  dfref savedf = GetDataFolderDFR()
    346  setdatafolder df
    347  make /n=0 /d xdw, model, broadening, convolution
    348  wave fs.xdw = xdw
    349  wave fs.model = model
    350  wave fs.broadening = broadening
    351  wave fs.convolution = convolution
    352  setdatafolder savedf
    353  endif
    354 
    355  // calculate
    357 
    358  yw = fs.yw
    359 };
    360 
    361 //------------------------------------------------------------------------------
    362 variable Calc_DoniachSunjicBroad(wave pw, wave yw){
    363 //------------------------------------------------------------------------------
    364  // Calculate the DoniachSunjicBroadS line shape
    365  Wave pw// coefficient wave
    366  Wave yw// output wave, correct x-scaling required on input
    367 
    368  struct DoniachSunjicStruct fs
    369  fs.precision = 5
    370  fs.oversampling = 4
    371 
    372  duplicate /free pw, fs.pw
    373  duplicate /free yw, fs.xw
    374  fs.xw = x
    375  duplicate /free yw, fs.yw
    376 
    378 
    379  yw = fs.yw
    380 };
    381 
    382 //------------------------------------------------------------------------------
    383 variable Fit_DoniachSunjicBroad(wave pw, wave yw, wave xw, wave ww){
    384 //------------------------------------------------------------------------------
    385  // Fit the DoniachSunjicBroadS line shape.
    386  // The function applies constraints which assume that the energy scale is in eV.
    387  // Returns chi^2.
    388  wave pw// coefficient wave- pre-load it with initial guess
    389  wave yw
    390  wave /z xw
    391  wave /z ww// weights (standard deviation)
    392 
    393  struct DoniachSunjicStruct fs
    394  fs.precision = 5
    395  fs.oversampling = 4
    396 
    397  duplicate /free pw, fs.pw
    398  if (WaveExists(xw))
    399  duplicate /free xw, fs.xw
    400  else
    401  duplicate /free yw, fs.xw
    402  fs.xw = x
    403  endif
    404  duplicate /free yw, fs.yw
    405 
    406  variable v_chisq = nan
    407  variable V_FitMaxIters = 100
    408  make /n=1 /t /free constraints = {"K0 >= 0", "K2 > 0", "K2 < 10", "K3 >= 0", "K3 < 1", "K4 >= -10", "K4 <= 10", "K5 >= 0", "K5 <= 1", "K6 >= 0", "K6 < 10"}
    409  // note: only single thread allowed
    410  FuncFit /NTHR=1 DoniachSunjicBroadS, pw, yw /X=xw /D /STRC=fs /C=constraints /NWOK /I=1 /W=ww
    411 
    412  return v_chisq
    413 };
    414 
    415 //------------------------------------------------------------------------------
    416 // peak-specific fit functions
    417 //------------------------------------------------------------------------------
    418 
    419 variable Au4f(wave w, variable x){
    420  // fit function for a nitrogen 1s-pi* absorption spectrum
    421  // modelled as multiple Voigt shapes on a constant background
    422  // similar to the Igor VoigtFit function
    423  // but with a constant gaussian width (instrumental broadening) for all peaks
    424  // gaussian and lorentzian widths are specified as FWHM
    425  wave w// parameters
    426  // w[0] constant background
    427  // w[1] linear background
    428  // w[2] global gaussian FWHM
    429  // w[3 + 0 + (n-1) * 3] peak n area
    430  // w[3 + 1 + (n-1) * 3] peak n position
    431  // w[3 + 2 + (n-1) * 3] peak n lorentzian FWHM
    432  // length of wave defines number of peaks
    433 
    434  // for compatibility with older code the linear background term can be omitted.
    435  // if the number of parameters divides by 3, the linear background term is added,
    436  // otherwise only the constant background.
    437  variable x
    438 
    439  variable np = 15
    440  variable ip, ip0
    441 
    442  variable bg = w[0]
    443  variable v = bg
    444  if (mod(np, 3) == 0)
    445  v += w[1] * x
    446  ip0 = 3
    447  else
    448  ip0 = 2
    449  endif
    450 
    451  variable vc1, vc2, vc3, vc4
    452  vc2 = 2 * sqrt(ln(2)) / w[ip0-1]
    453  for (ip = ip0; ip < np; ip += 3)
    454  vc1 = w[ip] / sqrt(pi) * vc2
    455  vc3 = w[ip+1]
    456  vc4 = vc2 * w[ip+2] / 2
    457  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    458  endfor
    459 
    460  return v
    461 
    462 };
    463 
    464 variable Au4f_2p2(wave w, variable x){
    465  // Au 4f 5/2 and 7/2 2-component Voigt fit with a common gaussian width
    466  // gaussian and lorentzian widths are specified as FWHM
    467  wave w// parameters
    468  // w[0] constant background
    469  // w[1] linear background
    470  // w[2] global gaussian FWHM
    471  // w[3] 5/2 bulk area
    472  // w[4] 5/2 bulk position
    473  // w[5] 5/2 lorentzian FWHM
    474  // w[6] 7/2 bulk area
    475  // w[7] 7/2 bulk position
    476  // w[8] 7/2 lorentzian FWHM
    477  // w[9] surface/bulk area ratio
    478  // w[10] surface core level shift
    479  variable x
    480 
    481  variable bg = w[0] + w[1] * x
    482  variable v = bg
    483 
    484  variable vc1// amplitude
    485  variable vc2// width
    486  variable vc3// position
    487  variable vc4// shape
    488  vc2 = 2 * sqrt(ln(2)) / w[2]
    489 
    490  // 5/2 bulk
    491  vc1 = w[3] / sqrt(pi) * vc2
    492  vc3 = w[4]
    493  vc4 = vc2 * w[5] / 2
    494  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    495 
    496  // 5/2 surface
    497  vc1 = w[3] / sqrt(pi) * vc2 * w[9]
    498  vc3 = w[4] + w[10]
    499  vc4 = vc2 * w[5] / 2
    500  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    501 
    502  // 7/2 bulk
    503  vc1 = w[6] / sqrt(pi) * vc2
    504  vc3 = w[7]
    505  vc4 = vc2 * w[8] / 2
    506  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    507 
    508  // 7/2 surface
    509  vc1 = w[6] / sqrt(pi) * vc2 * w[9]
    510  vc3 = w[7] + w[10]
    511  vc4 = vc2 * w[8] / 2
    512  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    513 
    514  return v
    515 
    516 };
    517 
    518 variable ShowComponents_Au4f_2p2(wave coef_wave, wave fit_wave){
    519  wave coef_wave
    520  wave fit_wave
    521 
    522  duplicate /free coef_wave, coef1, coef2
    523  coef1[9] = 0
    524  coef2[3] *= coef_wave[9]
    525  coef2[4] += coef_wave[10]
    526  coef2[6] *= coef_wave[9]
    527  coef2[7] += coef_wave[10]
    528  coef2[9] = 0
    529 
    530  string s_fit_wave = NameOfWave(fit_wave)
    531  string s_fit_p1 = s_fit_wave + "_p1"
    532  string s_fit_p2 = s_fit_wave + "_p2"
    533  duplicate /o fit_wave, $(s_fit_p1) /wave=fit_p1
    534  duplicate /o fit_wave, $(s_fit_p2) /wave=fit_p2
    535 
    536  fit_p1 = Au4f_2p2(coef1, x)
    537  fit_p2 = Au4f_2p2(coef2, x)
    538 
    539  string traces = TraceNameList("", ";", 1)
    540  if ((WhichListItem(s_fit_wave, traces, ";") >= 0) && (WhichListItem(s_fit_p1, traces, ";") < 0))
    541  appendtograph fit_p1, fit_p2
    542  ModifyGraph lstyle($s_fit_p1)=2
    543  ModifyGraph lstyle($s_fit_p2)=2
    544  ModifyGraph rgb($s_fit_p1)=(0,0,65280)
    545  ModifyGraph rgb($s_fit_p2)=(0,0,65280)
    546  endif
    547 };
    548 
    549 variable Au4f_2p3(wave w, variable x){
    550  // Au 4f 5/2 and 7/2 3-component Voigt fit with a common gaussian width
    551  // gaussian and lorentzian widths are specified as FWHM
    552  wave w// parameters
    553  // w[0] constant background
    554  // w[1] linear background
    555  // w[2] global gaussian FWHM
    556  // w[3] 5/2 bulk area
    557  // w[4] 5/2 bulk position
    558  // w[5] 5/2 lorentzian FWHM
    559  // w[6] 7/2 bulk area
    560  // w[7] 7/2 bulk position
    561  // w[8] 7/2 lorentzian FWHM
    562  // w[9] surface/bulk area ratio
    563  // w[10] surface core level shift
    564  // w[11] 2nd layer/bulk area ratio
    565  // w[12] 2nd layer core level shift
    566  variable x
    567 
    568  variable bg = w[0] + w[1] * x
    569  variable v = bg
    570 
    571  variable vc1// amplitude
    572  variable vc2// width
    573  variable vc3// position
    574  variable vc4// shape
    575  vc2 = 2 * sqrt(ln(2)) / w[2]
    576 
    577  // 5/2 bulk
    578  vc1 = w[3] / sqrt(pi) * vc2
    579  vc3 = w[4]
    580  vc4 = vc2 * w[5] / 2
    581  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    582 
    583  // 5/2 surface
    584  vc1 = w[3] / sqrt(pi) * vc2 * w[9]
    585  vc3 = w[4] + w[10]
    586  vc4 = vc2 * w[5] / 2
    587  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    588 
    589  // 5/2 2nd layer
    590  vc1 = w[3] / sqrt(pi) * vc2 * w[11]
    591  vc3 = w[4] + w[12]
    592  vc4 = vc2 * w[5] / 2
    593  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    594 
    595  // 7/2 bulk
    596  vc1 = w[6] / sqrt(pi) * vc2
    597  vc3 = w[7]
    598  vc4 = vc2 * w[8] / 2
    599  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    600 
    601  // 7/2 surface
    602  vc1 = w[6] / sqrt(pi) * vc2 * w[9]
    603  vc3 = w[7] + w[10]
    604  vc4 = vc2 * w[8] / 2
    605  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    606 
    607  // 7/2 2nd layer
    608  vc1 = w[6] / sqrt(pi) * vc2 * w[11]
    609  vc3 = w[7] + w[12]
    610  vc4 = vc2 * w[8] / 2
    611  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    612 
    613  return v
    614 
    615 };
    616 
    617 variable ShowComponents_Au4f_2p3(wave coef_wave, wave fit_wave){
    618  wave coef_wave
    619  wave fit_wave
    620 
    621  duplicate /free coef_wave, coef1, coef2, coef3
    622  coef1[9] = 0
    623  coef1[11] = 0
    624 
    625  coef2[3] *= coef_wave[9]
    626  coef2[4] += coef_wave[10]
    627  coef2[6] *= coef_wave[9]
    628  coef2[7] += coef_wave[10]
    629  coef2[9] = 0
    630  coef2[11] = 0
    631 
    632  coef3[3] *= coef_wave[11]
    633  coef3[4] += coef_wave[12]
    634  coef3[6] *= coef_wave[11]
    635  coef3[7] += coef_wave[12]
    636  coef3[9] = 0
    637  coef3[11] = 0
    638 
    639  string s_fit_wave = NameOfWave(fit_wave)
    640  string s_fit_p1 = s_fit_wave + "_p1"
    641  string s_fit_p2 = s_fit_wave + "_p2"
    642  string s_fit_p3 = s_fit_wave + "_p3"
    643  duplicate /o fit_wave, $(s_fit_p1) /wave=fit_p1
    644  duplicate /o fit_wave, $(s_fit_p2) /wave=fit_p2
    645  duplicate /o fit_wave, $(s_fit_p3) /wave=fit_p3
    646 
    647  fit_p1 = Au4f_2p2(coef1, x)
    648  fit_p2 = Au4f_2p2(coef2, x)
    649  fit_p3 = Au4f_2p2(coef3, x)
    650 
    651  string traces = TraceNameList("", ";", 1)
    652  if ((WhichListItem(s_fit_wave, traces, ";") >= 0) && (WhichListItem(s_fit_p1, traces, ";") < 0))
    653  appendtograph fit_p1, fit_p2, fit_p3
    654  ModifyGraph lstyle($s_fit_p1)=2
    655  ModifyGraph lstyle($s_fit_p2)=2
    656  ModifyGraph lstyle($s_fit_p3)=2
    657  ModifyGraph rgb($s_fit_p1)=(0,0,65280)
    658  ModifyGraph rgb($s_fit_p2)=(0,0,65280)
    659  ModifyGraph rgb($s_fit_p3)=(0,0,65280)
    660  endif
    661 };
    662 
    672 variable FermiGaussConv(wave pw, wave yw, wave xw){
    673  WAVE pw, yw, xw
    674 
    675  // half width of temporary gaussian wave is pw[5] multiplied by this factor (may be fractional)
    676  variable precision_g = 5
    677  variable oversampling = 4
    678 
    679  // calculate wave spacing based on minimum spacing of desired x points
    680  duplicate /free xw, xdw
    681  differentiate /p xw /d=xdw
    682  xdw = abs(xdw)
    683  variable xd = wavemin(xdw) / oversampling
    684 
    685  // calculate gausswave size based on pw[5] and precision variable
    686  variable x0g = abs(pw[5]) * precision_g
    687  variable ng = 2 * floor(x0g / xd) + 1
    688 
    689  // calculate fermiwave size based on desired range for yw
    690  variable emax = wavemax(xw)
    691  variable emin = wavemin(xw)
    692  variable x0f = max(abs(emax - pw[3]), abs(emin - pw[3])) + x0g
    693  variable ne = 2 * floor(x0f / xd) + 1
    694 
    695  // create and calculate initial waves, normalize exponential
    696  make /d /n=(ng) /free gausswave
    697  make /d /n=(ne) /free fermiwave
    698  setscale/i x -x0g, x0g, "", gausswave
    699  setscale/i x -x0f, x0f, "", fermiwave
    700 
    701  gausswave = exp( - (x / pw[5] )^2 )
    702  fermiwave = 1 / (exp( x / (kBoltzmann * pw[4])) + 1.0 )
    703 
    704  // calculate the convolution
    705  duplicate /free fermiwave, resultwave
    706  Convolve /a gausswave, resultwave
    707  variable rmax = wavemax(resultwave)
    708  resultwave /= rmax
    709 
    710  // prepare output
    711  ng = numpnts(resultwave)
    712  x0g = xd * (ng - 1) / 2
    713  setscale/i x -x0g, x0g, "", resultwave
    714 
    715  yw = pw[2] * resultwave(xw[p] - pw[3]) + pw[0] + pw[1] * xw[p]
    716 };
    717 
    variable DoniachSunjicBroad(wave pw, wave yw, wave xw)
    - -
    variable ds4_bg(wave w, variable x)
    - -
    variable FermiGaussConv(wave pw, wave yw, wave xw)
    convolution of Fermi-Dirac distribution and a Gaussian.
    -
    threadsafe variable DoniachSunjicBroadS(DoniachSunjicStruct *s)
    - -
    variable Au4f(wave w, variable x)
    -
    variable Au4f_2p3(wave w, variable x)
    -
    variable Au4f_2p2(wave w, variable x)
    -
    variable ShowComponents_Au4f_2p2(wave coef_wave, wave fit_wave)
    -
    variable Calc_DoniachSunjicBroad(wave pw, wave yw)
    -
    variable ShowComponents_Au4f_2p3(wave coef_wave, wave fit_wave)
    -
    variable Fit_DoniachSunjicBroad(wave pw, wave yw, wave xw, wave ww)
    - - - -
    threadsafe variable ds2_bg(wave w, variable x)
    - -
    version
    - -
    variable ds6_bg(wave w, variable x)
    - -
    threadsafe variable ds1_bg(wave w, variable x)
    - +Go to the documentation of this file.
    1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
    2 #pragma IgorVersion = 6.2
    3 #pragma ModuleName = PearlFitFuncs
    4 #pragma version = 1.02
    5 #include "mm-physconst"
    6 
    20 
    25 
    26 
    27 //------------------------------------------------------------------------------
    28 // Gaussian shapes
    29 //------------------------------------------------------------------------------
    30 
    44 threadsafe variable MultiGaussLinBG(wave w, variable x){
    45  wave w
    46  variable x
    47 
    48  variable np = numpnts(w)
    49  variable ip
    50 
    51  variable v = w[0] + x * w[1]
    52  for (ip = 2; ip < np; ip += 3)
    53  v += w[ip] * exp( -( (x - w[ip+1]) / w[ip+2] )^2 )
    54  endfor
    55 
    56  return v
    57 };
    58 
    79 threadsafe variable MultiGaussLinBG_AO(wave pw, wave yw, wave xw){
    80  wave pw
    81  wave yw
    82  wave xw
    83 
    84  variable np = numpnts(pw)
    85  variable ip
    86 
    87  yw = pw[0] + xw[p] * pw[1]
    88  for (ip = 2; ip < np; ip += 3)
    89  yw += pw[ip] * exp( -( (xw[p] - pw[ip+1]) / pw[ip+2] )^2 )
    90  endfor
    91 };
    92 
    93 //------------------------------------------------------------------------------
    94 // Voigt shapes
    95 //------------------------------------------------------------------------------
    96 
    110 variable MultiVoigtLinBG(wave w, variable x){
    111  wave w
    112  variable x
    113 
    114  variable np = numpnts(w)
    115  variable ip
    116 
    117  variable v = w[0] + x * w[1]
    118  for (ip = 2; ip < np; ip += 4)
    119  v += w[ip] * VoigtFunc((x - w[ip+1]) / w[ip+2], w[ip+3])
    120  endfor
    121 
    122  return v
    123 };
    124 
    125 
    126 //------------------------------------------------------------------------------
    127 // Doniach-Sunjic shapes
    128 //------------------------------------------------------------------------------
    129 
    140 threadsafe variable DoniachSunjic(variable x, variable amp, variable pos, variable sing, variable fwhm){
    141  variable x
    142  variable amp
    143  variable pos
    144  variable sing
    145  variable fwhm
    146 
    147  variable nom, denom
    148  nom = cos(pi * sing / 2 + (1 - sing) * atan((x - pos) / fwhm * 2))
    149  denom = ((x - pos)^2 + fwhm^2 / 4)^((1 - sing) / 2)
    150 
    151  return amp * nom / denom * fwhm / 2
    152 };
    153 
    167 variable MultiDoniachSunjicLinBG(wave w, variable x){
    168  wave w
    169  variable x
    170 
    171  variable np = numpnts(w)
    172  variable ip
    173 
    174  variable v = w[0] + x * w[1]
    175  for (ip = 2; ip < np; ip += 4)
    176  v += DoniachSunjic(x, w[ip], w[ip+1], w[ip+3], w[ip+2])
    177  endfor
    178 
    179  return v
    180 };
    181 
    182 
    183 threadsafe variable ds1_bg(wave w, variable x){
    184  // Doniach-Sunjic fit function
    185  // 0 <= sing < 1
    186  wave w// coefficients - see below
    187  variable x// independent variable
    188 
    189  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    190  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    191  //CurveFitDialog/ Equation:
    192  //CurveFitDialog/ f(x) = DoniachSunjic(x, amp, pos, sing, fwhm) + bg
    193  //CurveFitDialog/ End of Equation
    194  //CurveFitDialog/ Independent Variables 1
    195  //CurveFitDialog/ x
    196  //CurveFitDialog/ Coefficients 5
    197  //CurveFitDialog/ w[0] = bg
    198  //CurveFitDialog/ w[1] = amp
    199  //CurveFitDialog/ w[2] = pos
    200  //CurveFitDialog/ w[3] = sing
    201  //CurveFitDialog/ w[4] = FWHM
    202 
    203  return DoniachSunjic(x, w[1], w[2], w[3], w[4]) + w[0]
    204 };
    205 
    206 threadsafe variable ds2_bg(wave w, variable x){
    207  Wave w
    208  Variable x
    209 
    210  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    211  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    212  //CurveFitDialog/ Equation:
    213  //CurveFitDialog/ f(x) = w_0+( w_1*cos(pi*w_3/2+(1-w_3)*atan((x-w_2)/w_4)))/(((x-w_2)^2+w_4^2)^((1-w_3)/2)) +(w_5*cos(pi*w_7/2+(1-w_7)*atan((x-(w_6))/w_8)))/(((x-w_6)^2+w_8^2)^((1-w_7)/2))
    214  //CurveFitDialog/ End of Equation
    215  //CurveFitDialog/ Independent Variables 1
    216  //CurveFitDialog/ x
    217  //CurveFitDialog/ Coefficients 9
    218  //CurveFitDialog/ w[0] = bg
    219  //CurveFitDialog/ w[1] = amp1
    220  //CurveFitDialog/ w[2] = pos1
    221  //CurveFitDialog/ w[3] = sing1
    222  //CurveFitDialog/ w[4] = wid1
    223  //CurveFitDialog/ w[5] = amp2
    224  //CurveFitDialog/ w[6] = pos2
    225  //CurveFitDialog/ w[7] = sing2
    226  //CurveFitDialog/ w[8] = wid2
    227 
    228  variable ds1 = DoniachSunjic(x, w[1], w[2], w[3], w[4])
    229  variable ds2 = DoniachSunjic(x, w[5], w[6], w[7], w[8])
    230 
    231  return w[0] + ds1 + ds2
    232 };
    233 
    234 variable ds4_bg(wave w, variable x){
    235  Wave w
    236  Variable x
    237 
    238  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    239  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    240  //CurveFitDialog/ Equation:
    241  //CurveFitDialog/ f(x) = w_0+( w_1*cos(pi*w_3/2+(1-w_3)*atan((x-w_2)/w_4)))/(((x-w_2)^2+w_4^2)^((1-w_3)/2)) +(w_5*cos(pi*w_7/2+(1-w_7)*atan((x-(w_6))/w_8)))/(((x-w_6)^2+w_8^2)^((1-w_7)/2)) +( w_9*cos(pi*w_11/2+(1-w_11)*atan((x-w_10)/w_12)))/(((x-w_10)^2+w_12^2)^((1-w_11)/2)) +( w_13*cos(pi*w_15/2+(1-w_15)*atan((x-w_14)/w_16)))/(((x-w_14)^2+w_16^2)^((1-w_15)/2))
    242  //CurveFitDialog/ End of Equation
    243  //CurveFitDialog/ Independent Variables 1
    244  //CurveFitDialog/ x
    245  //CurveFitDialog/ Coefficients 17
    246  //CurveFitDialog/ w[0] = w_0
    247  //CurveFitDialog/ w[1] = w_11
    248  //CurveFitDialog/ w[2] = w_12
    249  //CurveFitDialog/ w[3] = w_13
    250  //CurveFitDialog/ w[4] = w_14
    251  //CurveFitDialog/ w[5] = w_21
    252  //CurveFitDialog/ w[6] = w_22
    253  //CurveFitDialog/ w[7] = w_23
    254  //CurveFitDialog/ w[8] = w_24
    255  //CurveFitDialog/ w[9] = w_31
    256  //CurveFitDialog/ w[10] = w_32
    257  //CurveFitDialog/ w[11] = w_33
    258  //CurveFitDialog/ w[12] = w_34
    259  //CurveFitDialog/ w[13] = w_41
    260  //CurveFitDialog/ w[14] = w_42
    261  //CurveFitDialog/ w[15] = w_43
    262  //CurveFitDialog/ w[16] = w_44
    263  Variable ds1, ds2, ds3, ds4
    264  ds1=( w[1]*cos(pi*w[3]/2+(1-w[3])*atan((x-w[2])/w[4])))/(((x-w[2])^2+w[4]^2)^((1-w[3])/2))
    265  ds2=( w[5]*cos(pi*w[7]/2+(1-w[7])*atan((x-w[6])/w[8])))/(((x-w[6])^2+w[8]^2)^((1-w[7])/2))
    266  ds3=( w[9]*cos(pi*w[11]/2+(1-w[11])*atan((x-w[10])/w[12])))/(((x-w[10])^2+w[12]^2)^((1-w[11])/2))
    267  ds4=( w[13]*cos(pi*w[15]/2+(1-w[15])*atan((x-w[14])/w[16])))/(((x-w[14])^2+w[16]^2)^((1-w[15])/2))
    268 
    269 
    270  return w[0]+ds1+ds2+ds3+ds4
    271 
    272 
    273 };
    274 
    275 variable ds6_bg(wave w, variable x){
    276  Wave w
    277  Variable x
    278 
    279  //CurveFitDialog/ These comments were created by the Curve Fitting dialog. Altering them will
    280  //CurveFitDialog/ make the function less convenient to work with in the Curve Fitting dialog.
    281  //CurveFitDialog/ Equation:
    282  //CurveFitDialog/
    283  //CurveFitDialog/ Variable g, ds1, ds2, ds3, ds4, ds5, ds6
    284  //CurveFitDialog/ ds1=( w_11*cos(pi*w_13/2+(1-w_13)*atan((x-w_12)/w_14)))/(((x-w_12)^2+w_14^2)^((1-w_13)/2))
    285  //CurveFitDialog/ ds2=( w_21*cos(pi*w_23/2+(1-w_23)*atan((x-w_22)/w_24)))/(((x-w_22)^2+w_24^2)^((1-w_23)/2))
    286  //CurveFitDialog/ ds3=( w_31*cos(pi*w_33/2+(1-w_33)*atan((x-w_32)/w_34)))/(((x-w_32)^2+w_34^2)^((1-w_33)/2))
    287  //CurveFitDialog/ ds4=( w_41*cos(pi*w_43/2+(1-w_43)*atan((x-w_42)/w_44)))/(((x-w_42)^2+w_44^2)^((1-w_43)/2))
    288  //CurveFitDialog/ ds5=( w_51*cos(pi*w_53/2+(1-w_53)*atan((x-w_52)/w_54)))/(((x-w_52)^2+w_54^2)^((1-w_53)/2))
    289  //CurveFitDialog/ ds6=( w_61*cos(pi*w_63/2+(1-w_63)*atan((x-w_62)/w_64)))/(((x-w_62)^2+w_64^2)^((1-w_63)/2))
    290  //CurveFitDialog/
    291  //CurveFitDialog/ f(x) =w_0+ds1+ds2+ds3+ds4+ds5+ds6
    292  //CurveFitDialog/
    293  //CurveFitDialog/ End of Equation
    294  //CurveFitDialog/ Independent Variables 1
    295  //CurveFitDialog/ x
    296  //CurveFitDialog/ Coefficients 25
    297  //CurveFitDialog/ w[0] = w_0
    298  //CurveFitDialog/ w[1] = w_11
    299  //CurveFitDialog/ w[2] = w_12
    300  //CurveFitDialog/ w[3] = w_13
    301  //CurveFitDialog/ w[4] = w_14
    302  //CurveFitDialog/ w[5] = w_21
    303  //CurveFitDialog/ w[6] = w_22
    304  //CurveFitDialog/ w[7] = w_23
    305  //CurveFitDialog/ w[8] = w_24
    306  //CurveFitDialog/ w[9] = w_31
    307  //CurveFitDialog/ w[10] = w_32
    308  //CurveFitDialog/ w[11] = w_33
    309  //CurveFitDialog/ w[12] = w_34
    310  //CurveFitDialog/ w[13] = w_41
    311  //CurveFitDialog/ w[14] = w_42
    312  //CurveFitDialog/ w[15] = w_43
    313  //CurveFitDialog/ w[16] = w_44
    314  //CurveFitDialog/ w[17] = w_51
    315  //CurveFitDialog/ w[18] = w_52
    316  //CurveFitDialog/ w[19] = w_53
    317  //CurveFitDialog/ w[20] = w_54
    318  //CurveFitDialog/ w[21] = w_61
    319  //CurveFitDialog/ w[22] = w_62
    320  //CurveFitDialog/ w[23] = w_63
    321  //CurveFitDialog/ w[24] = w_64
    322 
    323 
    324  Variable ds1, ds2, ds3, ds4, ds5, ds6
    325  ds1=( w[1]*cos(pi*w[3]/2+(1-w[3])*atan((x-w[2])/w[4])))/(((x-w[2])^2+w[4]^2)^((1-w[3])/2))
    326  ds2=( w[5]*cos(pi*w[7]/2+(1-w[7])*atan((x-w[6])/w[8])))/(((x-w[6])^2+w[8]^2)^((1-w[7])/2))
    327  ds3=( w[9]*cos(pi*w[11]/2+(1-w[11])*atan((x-w[10])/w[12])))/(((x-w[10])^2+w[12]^2)^((1-w[11])/2))
    328  ds4=( w[13]*cos(pi*w[15]/2+(1-w[15])*atan((x-w[14])/w[16])))/(((x-w[14])^2+w[16]^2)^((1-w[15])/2))
    329  ds5=( w[17]*cos(pi*w[19]/2+(1-w[19])*atan((x-w[18])/w[20])))/(((x-w[18])^2+w[20]^2)^((1-w[19])/2))
    330  ds6=( w[21]*cos(pi*w[23]/2+(1-w[23])*atan((x-w[22])/w[24])))/(((x-w[22])^2+w[24]^2)^((1-w[23])/2))
    331 
    332  return w[0]+ds1+ds2+ds3+ds4+ds5+ds6
    333 
    334 };
    335 
    337  // data structure for DoniachSunjicBroadS structural function fit
    338 
    339  // waves populated by the FuncFit operation
    340  wave pw;
    341  wave yw;
    342  wave xw;
    343 
    344  // convolution parameters to be set upon creation of the structure
    345  variable precision;
    346  variable oversampling;
    347 
    348  // auxiliary fields used internally by DoniachSunjicBroadS
    349  // do not touch these
    350  wave xdw;
    351  wave model;
    354 };
    355 
    356 //------------------------------------------------------------------------------
    357 threadsafe variable DoniachSunjicBroadS(DoniachSunjicStruct* s){
    358 //------------------------------------------------------------------------------
    359  // Two-peak (bulk + surface) Doniach-Sunjic line shape with Gaussian broadening (convolution).
    360  // Hold parameter 5 at 0 to fit just one peak.
    361 
    362  // Structural fit function for efficient fitting in procedures.
    363  // Calculating the convolution requires auxiliary waves and additional, non-fitting parameters.
    364  // To eliminate the time-consuming overhead of creating and killing the auxiliary waves,
    365  // these waves are held in the fitting structure.
    366 
    367  // Caution: The function on its own is thread-safe.
    368  // However, since FuncFit uses the same structure in all threads, the fitting cannot run in parallel.
    369  // Set /NTHR=1.
    370 
    371  // See also Fit_DoniachSunjicBroad (example), DoniachSunjicBroad (conventional fit function)
    372  Struct DoniachSunjicStruct &s
    373 
    374  // pw[0] = bulk amplitude
    375  // pw[1] = bulk position
    376  // pw[2] = Lorentzian FWHM
    377  // pw[3] = Donjach-Sunjic singularity index (0..1)
    378  // pw[4] = surface shift
    379  // pw[5] = surface/bulk ratio
    380  // pw[6] = Gaussian FWHM
    381  // pw[7] = constant background
    382  // pw[8] = linear background
    383 
    384  wave xw = s.xw
    385  wave yw = s.yw
    386  wave pw = s.pw
    387 
    388  variable precision = s.precision
    389  variable oversampling = s.oversampling
    390 
    391  if (WaveExists(s.xdw))
    392  wave xdw = s.xdw
    393  wave model = s.model
    394  wave broadening = s.broadening
    395  wave convolution = s.convolution
    396  else
    397  make /n=0 /free xdw, model, broadening, convolution
    398  redimension /d xdw, model, broadening, convolution
    399  wave fs.xdw = xdw
    400  wave fs.model = model
    401  wave fs.broadening = broadening
    402  wave fs.convolution = convolution
    403  endif
    404 
    405  // calculate wave spacing based on minimum spacing of desired x points
    406  differentiate /p xw /d=xdw
    407  xdw = abs(xdw)
    408  variable xd = wavemin(xdw) / oversampling
    409 
    410  // calculate broadening wave size based on width and precision variable
    411  variable x0b = pw[6] * precision
    412  variable nb = 2 * floor(x0b / xd) + 1
    413 
    414  // calculate model size based on desired range for yw
    415  variable x0m = max(abs(wavemax(xw) - pw[1]), abs(wavemin(xw) - pw[1])) + x0b
    416  variable nm = 2 * floor(x0m / xd) + 1
    417  nb = min(nb, nm * 10)// limit wave size to avoid runtime errors for unphysically large parameter
    418 
    419  // create and calculate initial waves, normalize exponential
    420  redimension /n=(nb) broadening
    421  redimension /n=(nm) model
    422  setscale/i x -x0b, x0b, "", broadening
    423  setscale/i x -x0m, x0m, "", model
    424 
    425  broadening = exp( - (x / pw[6])^2 * 4 * ln(2))
    426  variable nrm = area(broadening)
    427  broadening /= nrm
    428  model = DoniachSunjic(x, 1, 0, pw[3], pw[2])// bulk
    429  model += DoniachSunjic(x, pw[5], pw[4], pw[3], pw[2])// surface
    430 
    431  // calculate the convolution
    432  Convolve /a broadening, model
    433  variable scale = pw[0] / wavemax(model)
    434  model *= scale
    435 
    436  // prepare output
    437  nm = numpnts(model)
    438  x0m = xd * (nm - 1) / 2
    439  setscale/i x -x0m, x0m, "", model
    440 
    441  yw = model(xw[p] - pw[1]) + pw[7] + pw[8] * xw[p]
    442  yw = numtype(yw) ? 0 : yw
    443 };
    444 
    445 //------------------------------------------------------------------------------
    446 variable DoniachSunjicBroad(wave pw, wave yw, wave xw){
    447 //------------------------------------------------------------------------------
    448  // Two-peak (bulk + surface) Doniach-Sunjic line shape with Gaussian broadening (convolution).
    449  // Hold parameter 5 at 0 to fit just one peak.
    450  // Conventional fit function for use with the curve-fitting dialog.
    451  // Compared to DoniachSunjicBroadS this function incurs extra overhead
    452  // because auxiliary waves are created and killed between function calls.
    453  // See also DoniachSunjicBroadS (optimized structural fit function)
    454  Wave pw
    455  Wave yw
    456  Wave xw
    457 
    458  // pw[0] = bulk amplitude
    459  // pw[1] = bulk position
    460  // pw[2] = Lorentzian FWHM
    461  // pw[3] = Donjach-Sunjic singularity index (0..1)
    462  // pw[4] = surface shift
    463  // pw[5] = surface/bulk ratio
    464  // pw[6] = Gaussian FWHM
    465  // pw[7] = constant background
    466  // pw[8] = linear background
    467 
    468  // set up data structure
    469  struct DoniachSunjicStruct fs
    470  fs.precision = 5
    471  fs.oversampling = 4
    472 
    473  wave fs.pw = pw
    474  wave fs.xw = xw
    475  wave fs.yw = yw
    476 
    477  // create temporary calculation waves in a global folder
    478  dfref df = root:packages:pearl_fitfuncs:doniach_sunjic
    479  if (DataFolderRefStatus(df) == 0)
    480  newdatafolder root:packages:pearl_fitfuncs:doniach_sunjic
    481  dfref df = root:packages:pearl_fitfuncs:doniach_sunjic
    482  endif
    483 
    484  wave /z /sdfr=df fs.xdw = xdw
    485  wave /z /sdfr=df fs.model = model
    486  wave /z /sdfr=df fs.broadening = broadening
    487  wave /z /sdfr=df fs.convolution = convolution
    488 
    489  if (WaveExists(fs.xdw) == 0)
    490  dfref savedf = GetDataFolderDFR()
    491  setdatafolder df
    492  make /n=0 /d xdw, model, broadening, convolution
    493  wave fs.xdw = xdw
    494  wave fs.model = model
    495  wave fs.broadening = broadening
    496  wave fs.convolution = convolution
    497  setdatafolder savedf
    498  endif
    499 
    500  // calculate
    502 
    503  yw = fs.yw
    504 };
    505 
    506 //------------------------------------------------------------------------------
    507 variable Calc_DoniachSunjicBroad(wave pw, wave yw){
    508 //------------------------------------------------------------------------------
    509  // Calculate the DoniachSunjicBroadS line shape
    510  Wave pw// coefficient wave
    511  Wave yw// output wave, correct x-scaling required on input
    512 
    513  struct DoniachSunjicStruct fs
    514  fs.precision = 5
    515  fs.oversampling = 4
    516 
    517  duplicate /free pw, fs.pw
    518  duplicate /free yw, fs.xw
    519  fs.xw = x
    520  duplicate /free yw, fs.yw
    521 
    523 
    524  yw = fs.yw
    525 };
    526 
    527 //------------------------------------------------------------------------------
    528 variable Fit_DoniachSunjicBroad(wave pw, wave yw, wave xw, wave ww){
    529 //------------------------------------------------------------------------------
    530  // Fit the DoniachSunjicBroadS line shape.
    531  // The function applies constraints which assume that the energy scale is in eV.
    532  // Returns chi^2.
    533  wave pw// coefficient wave- pre-load it with initial guess
    534  wave yw
    535  wave /z xw
    536  wave /z ww// weights (standard deviation)
    537 
    538  struct DoniachSunjicStruct fs
    539  fs.precision = 5
    540  fs.oversampling = 4
    541 
    542  duplicate /free pw, fs.pw
    543  if (WaveExists(xw))
    544  duplicate /free xw, fs.xw
    545  else
    546  duplicate /free yw, fs.xw
    547  fs.xw = x
    548  endif
    549  duplicate /free yw, fs.yw
    550 
    551  variable v_chisq = nan
    552  variable V_FitMaxIters = 100
    553  make /n=1 /t /free constraints = {"K0 >= 0", "K2 > 0", "K2 < 10", "K3 >= 0", "K3 < 1", "K4 >= -10", "K4 <= 10", "K5 >= 0", "K5 <= 1", "K6 >= 0", "K6 < 10"}
    554  // note: only single thread allowed
    555  FuncFit /NTHR=1 DoniachSunjicBroadS, pw, yw /X=xw /D /STRC=fs /C=constraints /NWOK /I=1 /W=ww
    556 
    557  return v_chisq
    558 };
    559 
    560 //------------------------------------------------------------------------------
    561 // peak-specific fit functions
    562 //------------------------------------------------------------------------------
    563 
    564 variable Au4f(wave w, variable x){
    565  // fit function for a nitrogen 1s-pi* absorption spectrum
    566  // modelled as multiple Voigt shapes on a constant background
    567  // similar to the Igor VoigtFit function
    568  // but with a constant gaussian width (instrumental broadening) for all peaks
    569  // gaussian and lorentzian widths are specified as FWHM
    570  wave w// parameters
    571  // w[0] constant background
    572  // w[1] linear background
    573  // w[2] global gaussian FWHM
    574  // w[3 + 0 + (n-1) * 3] peak n area
    575  // w[3 + 1 + (n-1) * 3] peak n position
    576  // w[3 + 2 + (n-1) * 3] peak n lorentzian FWHM
    577  // length of wave defines number of peaks
    578 
    579  // for compatibility with older code the linear background term can be omitted.
    580  // if the number of parameters divides by 3, the linear background term is added,
    581  // otherwise only the constant background.
    582  variable x
    583 
    584  variable np = 15
    585  variable ip, ip0
    586 
    587  variable bg = w[0]
    588  variable v = bg
    589  if (mod(np, 3) == 0)
    590  v += w[1] * x
    591  ip0 = 3
    592  else
    593  ip0 = 2
    594  endif
    595 
    596  variable vc1, vc2, vc3, vc4
    597  vc2 = 2 * sqrt(ln(2)) / w[ip0-1]
    598  for (ip = ip0; ip < np; ip += 3)
    599  vc1 = w[ip] / sqrt(pi) * vc2
    600  vc3 = w[ip+1]
    601  vc4 = vc2 * w[ip+2] / 2
    602  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    603  endfor
    604 
    605  return v
    606 
    607 };
    608 
    609 variable Au4f_2p2(wave w, variable x){
    610  // Au 4f 5/2 and 7/2 2-component Voigt fit with a common gaussian width
    611  // gaussian and lorentzian widths are specified as FWHM
    612  wave w// parameters
    613  // w[0] constant background
    614  // w[1] linear background
    615  // w[2] global gaussian FWHM
    616  // w[3] 5/2 bulk area
    617  // w[4] 5/2 bulk position
    618  // w[5] 5/2 lorentzian FWHM
    619  // w[6] 7/2 bulk area
    620  // w[7] 7/2 bulk position
    621  // w[8] 7/2 lorentzian FWHM
    622  // w[9] surface/bulk area ratio
    623  // w[10] surface core level shift
    624  variable x
    625 
    626  variable bg = w[0] + w[1] * x
    627  variable v = bg
    628 
    629  variable vc1// amplitude
    630  variable vc2// width
    631  variable vc3// position
    632  variable vc4// shape
    633  vc2 = 2 * sqrt(ln(2)) / w[2]
    634 
    635  // 5/2 bulk
    636  vc1 = w[3] / sqrt(pi) * vc2
    637  vc3 = w[4]
    638  vc4 = vc2 * w[5] / 2
    639  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    640 
    641  // 5/2 surface
    642  vc1 = w[3] / sqrt(pi) * vc2 * w[9]
    643  vc3 = w[4] + w[10]
    644  vc4 = vc2 * w[5] / 2
    645  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    646 
    647  // 7/2 bulk
    648  vc1 = w[6] / sqrt(pi) * vc2
    649  vc3 = w[7]
    650  vc4 = vc2 * w[8] / 2
    651  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    652 
    653  // 7/2 surface
    654  vc1 = w[6] / sqrt(pi) * vc2 * w[9]
    655  vc3 = w[7] + w[10]
    656  vc4 = vc2 * w[8] / 2
    657  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    658 
    659  return v
    660 
    661 };
    662 
    663 variable ShowComponents_Au4f_2p2(wave coef_wave, wave fit_wave){
    664  wave coef_wave
    665  wave fit_wave
    666 
    667  duplicate /free coef_wave, coef1, coef2
    668  coef1[9] = 0
    669  coef2[3] *= coef_wave[9]
    670  coef2[4] += coef_wave[10]
    671  coef2[6] *= coef_wave[9]
    672  coef2[7] += coef_wave[10]
    673  coef2[9] = 0
    674 
    675  string s_fit_wave = NameOfWave(fit_wave)
    676  string s_fit_p1 = s_fit_wave + "_p1"
    677  string s_fit_p2 = s_fit_wave + "_p2"
    678  duplicate /o fit_wave, $(s_fit_p1) /wave=fit_p1
    679  duplicate /o fit_wave, $(s_fit_p2) /wave=fit_p2
    680 
    681  fit_p1 = Au4f_2p2(coef1, x)
    682  fit_p2 = Au4f_2p2(coef2, x)
    683 
    684  string traces = TraceNameList("", ";", 1)
    685  if ((WhichListItem(s_fit_wave, traces, ";") >= 0) && (WhichListItem(s_fit_p1, traces, ";") < 0))
    686  appendtograph fit_p1, fit_p2
    687  ModifyGraph lstyle($s_fit_p1)=2
    688  ModifyGraph lstyle($s_fit_p2)=2
    689  ModifyGraph rgb($s_fit_p1)=(0,0,65280)
    690  ModifyGraph rgb($s_fit_p2)=(0,0,65280)
    691  endif
    692 };
    693 
    694 variable Au4f_2p3(wave w, variable x){
    695  // Au 4f 5/2 and 7/2 3-component Voigt fit with a common gaussian width
    696  // gaussian and lorentzian widths are specified as FWHM
    697  wave w// parameters
    698  // w[0] constant background
    699  // w[1] linear background
    700  // w[2] global gaussian FWHM
    701  // w[3] 5/2 bulk area
    702  // w[4] 5/2 bulk position
    703  // w[5] 5/2 lorentzian FWHM
    704  // w[6] 7/2 bulk area
    705  // w[7] 7/2 bulk position
    706  // w[8] 7/2 lorentzian FWHM
    707  // w[9] surface/bulk area ratio
    708  // w[10] surface core level shift
    709  // w[11] 2nd layer/bulk area ratio
    710  // w[12] 2nd layer core level shift
    711  variable x
    712 
    713  variable bg = w[0] + w[1] * x
    714  variable v = bg
    715 
    716  variable vc1// amplitude
    717  variable vc2// width
    718  variable vc3// position
    719  variable vc4// shape
    720  vc2 = 2 * sqrt(ln(2)) / w[2]
    721 
    722  // 5/2 bulk
    723  vc1 = w[3] / sqrt(pi) * vc2
    724  vc3 = w[4]
    725  vc4 = vc2 * w[5] / 2
    726  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    727 
    728  // 5/2 surface
    729  vc1 = w[3] / sqrt(pi) * vc2 * w[9]
    730  vc3 = w[4] + w[10]
    731  vc4 = vc2 * w[5] / 2
    732  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    733 
    734  // 5/2 2nd layer
    735  vc1 = w[3] / sqrt(pi) * vc2 * w[11]
    736  vc3 = w[4] + w[12]
    737  vc4 = vc2 * w[5] / 2
    738  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    739 
    740  // 7/2 bulk
    741  vc1 = w[6] / sqrt(pi) * vc2
    742  vc3 = w[7]
    743  vc4 = vc2 * w[8] / 2
    744  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    745 
    746  // 7/2 surface
    747  vc1 = w[6] / sqrt(pi) * vc2 * w[9]
    748  vc3 = w[7] + w[10]
    749  vc4 = vc2 * w[8] / 2
    750  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    751 
    752  // 7/2 2nd layer
    753  vc1 = w[6] / sqrt(pi) * vc2 * w[11]
    754  vc3 = w[7] + w[12]
    755  vc4 = vc2 * w[8] / 2
    756  v += vc1 * VoigtFunc(vc2 * (x - vc3), vc4)
    757 
    758  return v
    759 
    760 };
    761 
    762 variable ShowComponents_Au4f_2p3(wave coef_wave, wave fit_wave){
    763  wave coef_wave
    764  wave fit_wave
    765 
    766  duplicate /free coef_wave, coef1, coef2, coef3
    767  coef1[9] = 0
    768  coef1[11] = 0
    769 
    770  coef2[3] *= coef_wave[9]
    771  coef2[4] += coef_wave[10]
    772  coef2[6] *= coef_wave[9]
    773  coef2[7] += coef_wave[10]
    774  coef2[9] = 0
    775  coef2[11] = 0
    776 
    777  coef3[3] *= coef_wave[11]
    778  coef3[4] += coef_wave[12]
    779  coef3[6] *= coef_wave[11]
    780  coef3[7] += coef_wave[12]
    781  coef3[9] = 0
    782  coef3[11] = 0
    783 
    784  string s_fit_wave = NameOfWave(fit_wave)
    785  string s_fit_p1 = s_fit_wave + "_p1"
    786  string s_fit_p2 = s_fit_wave + "_p2"
    787  string s_fit_p3 = s_fit_wave + "_p3"
    788  duplicate /o fit_wave, $(s_fit_p1) /wave=fit_p1
    789  duplicate /o fit_wave, $(s_fit_p2) /wave=fit_p2
    790  duplicate /o fit_wave, $(s_fit_p3) /wave=fit_p3
    791 
    792  fit_p1 = Au4f_2p2(coef1, x)
    793  fit_p2 = Au4f_2p2(coef2, x)
    794  fit_p3 = Au4f_2p2(coef3, x)
    795 
    796  string traces = TraceNameList("", ";", 1)
    797  if ((WhichListItem(s_fit_wave, traces, ";") >= 0) && (WhichListItem(s_fit_p1, traces, ";") < 0))
    798  appendtograph fit_p1, fit_p2, fit_p3
    799  ModifyGraph lstyle($s_fit_p1)=2
    800  ModifyGraph lstyle($s_fit_p2)=2
    801  ModifyGraph lstyle($s_fit_p3)=2
    802  ModifyGraph rgb($s_fit_p1)=(0,0,65280)
    803  ModifyGraph rgb($s_fit_p2)=(0,0,65280)
    804  ModifyGraph rgb($s_fit_p3)=(0,0,65280)
    805  endif
    806 };
    807 
    817 variable FermiGaussConv(wave pw, wave yw, wave xw){
    818  WAVE pw, yw, xw
    819 
    820  // half width of temporary gaussian wave is pw[5] multiplied by this factor (may be fractional)
    821  variable precision_g = 5
    822  variable oversampling = 4
    823 
    824  // calculate wave spacing based on minimum spacing of desired x points
    825  duplicate /free xw, xdw
    826  differentiate /p xw /d=xdw
    827  xdw = abs(xdw)
    828  variable xd = wavemin(xdw) / oversampling
    829 
    830  // calculate gausswave size based on pw[5] and precision variable
    831  variable x0g = abs(pw[5]) * precision_g
    832  variable ng = 2 * floor(x0g / xd) + 1
    833 
    834  // calculate fermiwave size based on desired range for yw
    835  variable emax = wavemax(xw)
    836  variable emin = wavemin(xw)
    837  variable x0f = max(abs(emax - pw[3]), abs(emin - pw[3])) + x0g
    838  variable ne = 2 * floor(x0f / xd) + 1
    839 
    840  // create and calculate initial waves, normalize exponential
    841  make /d /n=(ng) /free gausswave
    842  make /d /n=(ne) /free fermiwave
    843  setscale/i x -x0g, x0g, "", gausswave
    844  setscale/i x -x0f, x0f, "", fermiwave
    845 
    846  gausswave = exp( - (x / pw[5] )^2 )
    847  fermiwave = 1 / (exp( x / (kBoltzmann * pw[4])) + 1.0 )
    848 
    849  // calculate the convolution
    850  duplicate /free fermiwave, resultwave
    851  Convolve /a gausswave, resultwave
    852  variable rmax = wavemax(resultwave)
    853  resultwave /= rmax
    854 
    855  // prepare output
    856  ng = numpnts(resultwave)
    857  x0g = xd * (ng - 1) / 2
    858  setscale/i x -x0g, x0g, "", resultwave
    859 
    860  yw = pw[2] * resultwave(xw[p] - pw[3]) + pw[0] + pw[1] * xw[p]
    861 };
    862 
    threadsafe variable MultiGaussLinBG(wave w, variable x)
    multiple gaussian peaks on a linear background fit function.
    +
    variable DoniachSunjicBroad(wave pw, wave yw, wave xw)
    +
    threadsafe variable MultiGaussLinBG_AO(wave pw, wave yw, wave xw)
    multiple gaussian peaks on a linear background fit function (all at once).
    + +
    variable ds4_bg(wave w, variable x)
    + +
    variable FermiGaussConv(wave pw, wave yw, wave xw)
    convolution of Fermi-Dirac distribution and a Gaussian.
    +
    threadsafe variable DoniachSunjicBroadS(DoniachSunjicStruct *s)
    + +
    threadsafe variable DoniachSunjic(variable x, variable amp, variable pos, variable sing, variable fwhm)
    Doniach-Sunjic line shape.
    +
    variable Au4f(wave w, variable x)
    +
    variable Au4f_2p3(wave w, variable x)
    +
    variable Au4f_2p2(wave w, variable x)
    +
    variable ShowComponents_Au4f_2p2(wave coef_wave, wave fit_wave)
    +
    variable Calc_DoniachSunjicBroad(wave pw, wave yw)
    +
    variable ShowComponents_Au4f_2p3(wave coef_wave, wave fit_wave)
    +
    variable Fit_DoniachSunjicBroad(wave pw, wave yw, wave xw, wave ww)
    + + + +
    threadsafe variable ds2_bg(wave w, variable x)
    + + +
    variable ds6_bg(wave w, variable x)
    + +
    variable MultiDoniachSunjicLinBG(wave w, variable x)
    multiple doniach-sunjic peaks on a linear background fit function.
    +
    threadsafe variable ds1_bg(wave w, variable x)
    + +
    variable MultiVoigtLinBG(wave w, variable x)
    multiple voigt peaks on a linear background fit function.
    -

    Definition at line 144 of file pearl-menu.ipf.

    +

    Definition at line 149 of file pearl-menu.ipf.

    @@ -201,7 +201,7 @@ Functions
    -

    Definition at line 96 of file pearl-menu.ipf.

    +

    Definition at line 101 of file pearl-menu.ipf.

    @@ -218,7 +218,7 @@ Functions
    -

    Definition at line 89 of file pearl-menu.ipf.

    +

    Definition at line 94 of file pearl-menu.ipf.

    @@ -235,7 +235,7 @@ Functions
    -

    Definition at line 102 of file pearl-menu.ipf.

    +

    Definition at line 107 of file pearl-menu.ipf.

    @@ -263,7 +263,7 @@ Functions
    -

    Definition at line 182 of file pearl-menu.ipf.

    +

    Definition at line 187 of file pearl-menu.ipf.

    @@ -297,7 +297,7 @@ Functions
    -

    Definition at line 163 of file pearl-menu.ipf.

    +

    Definition at line 168 of file pearl-menu.ipf.

    @@ -315,7 +315,7 @@ Functions
    -

    Definition at line 77 of file pearl-menu.ipf.

    +

    Definition at line 82 of file pearl-menu.ipf.

    @@ -325,7 +325,7 @@ Functions
    -Go to the documentation of this file.
    1 #pragma rtGlobals=1// Use modern global access method.
    2 #pragma ModuleName = PearlMenu
    3 #pragma version = 1.01
    4 
    5 // main menu for PEARL data acquisition and analysis packages
    6 
    7 // $Id$
    8 // author: matthias.muntwiler@psi.ch
    9 // Copyright (c) 2013-14 Paul Scherrer Institut
    10 
    11 // Licensed under the Apache License, Version 2.0 (the "License");
    12 // you may not use this file except in compliance with the License.
    13 // You may obtain a copy of the License at
    14 // http://www.apache.org/licenses/LICENSE-2.0
    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 string PearlMenuEnableFunc(string funcname){
    78  // checks whether a function name exists
    79  // and conditionally returns a prefix which disables the menu item
    80  // if the function does not exist
    81  string funcname
    82  if (exists(funcname) >= 3)
    83  return ""
    84  else
    85  return "("
    86  endif
    87 };
    88 
    89 variable LoadPearlOptics(){
    90  execute /p/q/z "INSERTINCLUDE \"pearl-optics\""
    91  execute /p/q/z "COMPILEPROCEDURES "
    92  execute /p/q/z "PearlOpticsPanel#po_InitPanel()"
    93  execute /p/q/z "BuildMenu \"PEARL\""
    94 };
    95 
    96 variable LoadPearlArpes(){
    97  execute /p/q/z "INSERTINCLUDE \"pearl-arpes\""
    98  execute /p/q/z "COMPILEPROCEDURES "
    99  execute /p/q/z "BuildMenu \"PEARL\""
    100 };
    101 
    103  execute /p/q/z "INSERTINCLUDE \"pearl-preparation\""
    104  execute /p/q/z "COMPILEPROCEDURES "
    105  execute /p/q/z "BuildMenu \"PEARL\""
    106 };
    107 
    108 variable Display2dProfiles(){
    109  dfref dfBefore = GetDataFolderDFR()
    110  Execute /q/z "CreateBrowser prompt=\"Select 2D wave\", showWaves=1, showVars=0, showStrs=0"
    111  dfref dfAfter = GetDataFolderDFR()
    112  SetDataFolder dfBefore
    113 
    114  SVAR list = S_BrowserList
    115  NVAR flag = V_Flag
    116 
    117  if ((flag != 0) && (ItemsInList(list) >= 1))
    118  string brickname = StringFromList(0, list)
    119  string cmd
    120  sprintf cmd, "ad_display_profiles(%s)", brickname
    121  execute /q/z cmd
    122  endif
    123 };
    124 
    125 variable Display3dSlicer(){
    126  dfref dfBefore = GetDataFolderDFR()
    127  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
    128  dfref dfAfter = GetDataFolderDFR()
    129  SetDataFolder dfBefore
    130 
    131  SVAR list = S_BrowserList
    132  NVAR flag = V_Flag
    133 
    134  if ((flag != 0) && (ItemsInList(list) >= 1))
    135  string brickname = StringFromList(0, list)
    136  string cmd
    137  sprintf cmd, "ad_display_slice(%s)", brickname
    138  execute /q/z cmd
    139  sprintf cmd, "ad_brick_slicer(%s)", brickname
    140  execute /q/z cmd
    141  endif
    142 };
    143 
    145  dfref dfBefore = GetDataFolderDFR()
    146  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
    147  dfref dfAfter = GetDataFolderDFR()
    148  SetDataFolder dfBefore
    149 
    150  SVAR list = S_BrowserList
    151  NVAR flag = V_Flag
    152 
    153  if ((flag != 0) && (ItemsInList(list) >= 1))
    154  string brickname = StringFromList(0, list)
    155  string cmd
    156  sprintf cmd, "ad_display_brick(%s)", brickname
    157  execute /q/z cmd
    158  sprintf cmd, "ad_brick_slicer(%s)", brickname
    159  execute /q/z cmd
    160  endif
    161 };
    162 
    163 variable PearlLiveDisplay(string epicsname, string nickname, string wbRGB){
    164  string epicsname// base name of the detector, e.g. X03DA-SCIENTA:
    165  // image1: and cam1: are appended by the function
    166  // see ad_connect
    167  string nickname// nick name under which this detector is referred to in Igor
    168  // must be a valid data folder name
    169  // see ad_connect
    170  string wbRGB// window background color, e.g. "(32768,49152,55296)"
    171  string cmd
    172  sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
    173  execute /q/z cmd
    174  sprintf cmd, "ad_display_profiles(root:pearl_epics:%s:image)", nickname
    175  execute /q/z cmd
    176  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
    177  execute /q/z cmd
    178  sprintf cmd, "add_roi_controls()"
    179  execute /q/z cmd
    180 };
    181 
    182 variable PearlAnglescanTracker(string epicsname, string wbRGB){
    183  string epicsname// base name of the detector, e.g. X03DA-SCIENTA:
    184  // image1: and cam1: are appended by the function
    185  // see ast_setup
    186  string wbRGB// window background color, e.g. "(32768,49152,55296)"
    187  string cmd
    188  sprintf cmd, "ast_setup()"
    189  execute /q/z cmd
    190  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
    191  execute /q/z cmd
    192 };
    193 
    variable PearlLiveDisplay(string epicsname, string nickname, string wbRGB)
    Definition: pearl-menu.ipf:163
    -
    variable DisplayGizmoSlicer()
    Definition: pearl-menu.ipf:144
    -
    variable LoadPearlPreparation()
    Definition: pearl-menu.ipf:102
    -
    variable PearlAnglescanTracker(string epicsname, string wbRGB)
    Definition: pearl-menu.ipf:182
    -
    variable LoadPearlArpes()
    Definition: pearl-menu.ipf:96
    -
    variable LoadPearlOptics()
    Definition: pearl-menu.ipf:89
    -
    variable Display3dSlicer()
    Definition: pearl-menu.ipf:125
    -
    string PearlMenuEnableFunc(string funcname)
    Definition: pearl-menu.ipf:77
    -
    variable Display2dProfiles()
    Definition: pearl-menu.ipf:108
    +Go to the documentation of this file.
    1 #pragma rtGlobals=1// Use modern global access method.
    2 #pragma ModuleName = PearlMenu
    3 #pragma version = 1.02
    4 
    5 // main menu for PEARL data acquisition and analysis packages
    6 
    7 // $Id$
    8 // author: matthias.muntwiler@psi.ch
    9 // Copyright (c) 2013-14 Paul Scherrer Institut
    10 
    11 // Licensed under the Apache License, Version 2.0 (the "License");
    12 // you may not use this file except in compliance with the License.
    13 // You may obtain a copy of the License at
    14 // http://www.apache.org/licenses/LICENSE-2.0
    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 string PearlMenuEnableFunc(string funcname){
    83  // checks whether a function name exists
    84  // and conditionally returns a prefix which disables the menu item
    85  // if the function does not exist
    86  string funcname
    87  if (exists(funcname) >= 3)
    88  return ""
    89  else
    90  return "("
    91  endif
    92 };
    93 
    94 variable LoadPearlOptics(){
    95  execute /p/q/z "INSERTINCLUDE \"pearl-optics\""
    96  execute /p/q/z "COMPILEPROCEDURES "
    97  execute /p/q/z "PearlOpticsPanel#po_InitPanel()"
    98  execute /p/q/z "BuildMenu \"PEARL\""
    99 };
    100 
    101 variable LoadPearlArpes(){
    102  execute /p/q/z "INSERTINCLUDE \"pearl-arpes\""
    103  execute /p/q/z "COMPILEPROCEDURES "
    104  execute /p/q/z "BuildMenu \"PEARL\""
    105 };
    106 
    108  execute /p/q/z "INSERTINCLUDE \"pearl-preparation\""
    109  execute /p/q/z "COMPILEPROCEDURES "
    110  execute /p/q/z "BuildMenu \"PEARL\""
    111 };
    112 
    113 variable Display2dProfiles(){
    114  dfref dfBefore = GetDataFolderDFR()
    115  Execute /q/z "CreateBrowser prompt=\"Select 2D wave\", showWaves=1, showVars=0, showStrs=0"
    116  dfref dfAfter = GetDataFolderDFR()
    117  SetDataFolder dfBefore
    118 
    119  SVAR list = S_BrowserList
    120  NVAR flag = V_Flag
    121 
    122  if ((flag != 0) && (ItemsInList(list) >= 1))
    123  string brickname = StringFromList(0, list)
    124  string cmd
    125  sprintf cmd, "ad_display_profiles(%s)", brickname
    126  execute /q/z cmd
    127  endif
    128 };
    129 
    130 variable Display3dSlicer(){
    131  dfref dfBefore = GetDataFolderDFR()
    132  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
    133  dfref dfAfter = GetDataFolderDFR()
    134  SetDataFolder dfBefore
    135 
    136  SVAR list = S_BrowserList
    137  NVAR flag = V_Flag
    138 
    139  if ((flag != 0) && (ItemsInList(list) >= 1))
    140  string brickname = StringFromList(0, list)
    141  string cmd
    142  sprintf cmd, "ad_display_slice(%s)", brickname
    143  execute /q/z cmd
    144  sprintf cmd, "ad_brick_slicer(%s)", brickname
    145  execute /q/z cmd
    146  endif
    147 };
    148 
    150  dfref dfBefore = GetDataFolderDFR()
    151  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
    152  dfref dfAfter = GetDataFolderDFR()
    153  SetDataFolder dfBefore
    154 
    155  SVAR list = S_BrowserList
    156  NVAR flag = V_Flag
    157 
    158  if ((flag != 0) && (ItemsInList(list) >= 1))
    159  string brickname = StringFromList(0, list)
    160  string cmd
    161  sprintf cmd, "ad_display_brick(%s)", brickname
    162  execute /q/z cmd
    163  sprintf cmd, "ad_brick_slicer(%s)", brickname
    164  execute /q/z cmd
    165  endif
    166 };
    167 
    168 variable PearlLiveDisplay(string epicsname, string nickname, string wbRGB){
    169  string epicsname// base name of the detector, e.g. X03DA-SCIENTA:
    170  // image1: and cam1: are appended by the function
    171  // see ad_connect
    172  string nickname// nick name under which this detector is referred to in Igor
    173  // must be a valid data folder name
    174  // see ad_connect
    175  string wbRGB// window background color, e.g. "(32768,49152,55296)"
    176  string cmd
    177  sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
    178  execute /q/z cmd
    179  sprintf cmd, "ad_display_profiles(root:pearl_epics:%s:image)", nickname
    180  execute /q/z cmd
    181  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
    182  execute /q/z cmd
    183  sprintf cmd, "add_roi_controls()"
    184  execute /q/z cmd
    185 };
    186 
    187 variable PearlAnglescanTracker(string epicsname, string wbRGB){
    188  string epicsname// base name of the detector, e.g. X03DA-SCIENTA:
    189  // image1: and cam1: are appended by the function
    190  // see ast_setup
    191  string wbRGB// window background color, e.g. "(32768,49152,55296)"
    192  string cmd
    193  sprintf cmd, "ast_setup()"
    194  execute /q/z cmd
    195  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
    196  execute /q/z cmd
    197 };
    198 
    variable PearlLiveDisplay(string epicsname, string nickname, string wbRGB)
    Definition: pearl-menu.ipf:168
    +
    variable DisplayGizmoSlicer()
    Definition: pearl-menu.ipf:149
    +
    variable LoadPearlPreparation()
    Definition: pearl-menu.ipf:107
    +
    variable PearlAnglescanTracker(string epicsname, string wbRGB)
    Definition: pearl-menu.ipf:187
    +
    variable LoadPearlArpes()
    Definition: pearl-menu.ipf:101
    +
    variable LoadPearlOptics()
    Definition: pearl-menu.ipf:94
    +
    variable Display3dSlicer()
    Definition: pearl-menu.ipf:130
    +
    string PearlMenuEnableFunc(string funcname)
    Definition: pearl-menu.ipf:82
    +
    variable Display2dProfiles()
    Definition: pearl-menu.ipf:113
    @@ -386,7 +391,7 @@ Variables

    find the scan folder

    the scan folder is the one that contains the :attr folder the data and scan folders may refer to the same folder.

    -

    Definition at line 1434 of file pearl-pshell-import.ipf.

    +

    Definition at line 1441 of file pearl-pshell-import.ipf.

    @@ -456,7 +461,7 @@ Variables
    Returns
    the function results are written to the lo, hi, un, and ax waves.
    Version
    this function supports regions from version 1.03. check that you're in the correct data folder!
    -

    Definition at line 1596 of file pearl-pshell-import.ipf.

    +

    Definition at line 1603 of file pearl-pshell-import.ipf.

    @@ -486,7 +491,7 @@ Variables
    Version
    this function supports regions from version 1.03.
    -

    Definition at line 1525 of file pearl-pshell-import.ipf.

    +

    Definition at line 1532 of file pearl-pshell-import.ipf.

    @@ -540,6 +545,7 @@ Variables
  • lo[%scan] scan dimension.
  • lo[%data] data dimension.
  • +

    if the data dimension labels and units are at their defaults ("value" and "arb.", respectively), the function tries to read them from the existing wave note ("AxisLabelD" and "AxisUnitD"), or based on the wave name if the name is one of the known measurement variables: "ScientaImage", "ImageAngleDistribution", "ScientaAngleDistribution", "ScientaSpectrum", "ImageEnergyDistribution", "ScientaEnergyDistribution", "SampleCurrent", "RefCurrent", "AuxCurrent", "MachineCurrent".

    Parameters
    @@ -552,7 +558,7 @@ Variables
    Version
    this function supports regions from version 1.03.
    -

    Definition at line 1750 of file pearl-pshell-import.ipf.

    +

    Definition at line 1763 of file pearl-pshell-import.ipf.

    @@ -575,7 +581,7 @@ Variables

    the dimension labels of the dataset waves must have been set correctly, e.g. by ps_set_dimlabels(). this is implicitly done by the high-level load functions.

    Version
    this function supports regions from version 1.03. check that you're in the correct data folder!
    -

    Definition at line 1479 of file pearl-pshell-import.ipf.

    +

    Definition at line 1486 of file pearl-pshell-import.ipf.

    @@ -609,7 +615,7 @@ Variables -

    Definition at line 1358 of file pearl-pshell-import.ipf.

    +

    Definition at line 1365 of file pearl-pshell-import.ipf.

    @@ -653,7 +659,7 @@ Variables -

    Definition at line 1377 of file pearl-pshell-import.ipf.

    +

    Definition at line 1384 of file pearl-pshell-import.ipf.

    @@ -680,7 +686,7 @@ Variables -

    Definition at line 132 of file pearl-pshell-import.ipf.

    +

    Definition at line 139 of file pearl-pshell-import.ipf.

    @@ -727,7 +733,7 @@ Variables
    Returns
    semicolon-separated list of dataset paths.
    Version
    since version 1.03 this function returns paths relative to scanpath.
    -

    Definition at line 432 of file pearl-pshell-import.ipf.

    +

    Definition at line 439 of file pearl-pshell-import.ipf.

    @@ -766,7 +772,7 @@ Variables
    Returns
    semicolon-separated list of datagroup paths.
    -

    Definition at line 473 of file pearl-pshell-import.ipf.

    +

    Definition at line 480 of file pearl-pshell-import.ipf.

    @@ -794,7 +800,7 @@ Variables
    Returns
    semicolon-separated list of group paths.
    -

    Definition at line 397 of file pearl-pshell-import.ipf.

    +

    Definition at line 404 of file pearl-pshell-import.ipf.

    @@ -865,7 +871,7 @@ global string s_filepath in new data folder contains the full file path on disk.
    global string s_scanpaths in new data folder contains a list of scan groups inside the file.
    -

    Definition at line 162 of file pearl-pshell-import.ipf.

    +

    Definition at line 169 of file pearl-pshell-import.ipf.

    @@ -929,7 +935,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded wave if successful. empty string otherwise.
    Version
    this function supports regions as of version 1.03.
    -

    Definition at line 681 of file pearl-pshell-import.ipf.

    +

    Definition at line 688 of file pearl-pshell-import.ipf.

    @@ -983,7 +989,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    0 if successful, non-zero if an error occurred.
    -

    Definition at line 1066 of file pearl-pshell-import.ipf.

    +

    Definition at line 1073 of file pearl-pshell-import.ipf.

    @@ -1042,7 +1048,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    load a reduced dataset from the open PShell HDF5 file.

    -

    the function loads the dataset image by image using the hyperslab option and applies a custom reduction function to each image. the results from the reduction function are written to the ReducedData1 and ReducedData2 waves. the raw data are discarded.

    +

    the function loads the dataset image by image using the hyperslab option and applies a custom reduction function to each image. the results from the reduction function are written to the ReducedData1, ReducedData2, etc. waves. the raw data are discarded.

    by default, the reduction function is called in separate threads to reduce the total loading time. (see the global variable psh5_perf_secs which reports the total run time of the function.) the effect varies depending on the balance between file loading (image size) and data processing (complexity of the reduction function). for debugging the reduction function, multi-threading can be disabled.

    if the reduction function requires the image waves to be scaled properly, the attributes must have been loaded by psh5_load_scan_attrs() before. in this case, the scales of the result waves are also set by the function. otherwise, the results can also be scaled by ps_scale_dataset() later.

    Parameters
    @@ -1050,7 +1056,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    - +
    datadata wave to be scaled. dimension labels (index -1) must be set to match the limit waves.
    fileIDID of open HDF5 file from psh5_open_file().
    scanpathpath to scan group in the HDF5 file.
    datasetnamename of the dataset. this must currently be "ScientaImage", other data is not supported. the name of the loaded wave is a cleaned up version of the dataset name. the name can include the region name as a relative path, e.g. "region1/ScientaImage". in this case, the dataset is loaded into a sub-folder named "region1".
    reduction_funccustom reduction function (any user-defined function which has the same parameters as adh5_default_reduction()).
    reduction_funccustom data reduction function. this can be any user-defined function which has the same parameters as adh5_default_reduction. some reduction functions are predefined in the PearlScientaPreprocess module.
    reduction_paramparameter string for the reduction function.
    progressprogress window.
    • 1 (default) show progress window
    • @@ -1059,17 +1065,17 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    nthreads
    • -1 (default) use as many threads as there are processor cores (in addition to main thread).
    • -
    • 0 use main thread only (e.g. for debugging the reduction function).
    • +
    • 0 use main thread only (for debugging and profiling).
    • >= 1 use a fixed number of (additional) threads.
    -
    Returns
    semicolon-separated list of the loaded waves, ReducedData1 and ReducedData2 if successful. empty string if an error occurred. error messages are printed to the history.
    +
    Returns
    semicolon-separated list of the loaded dataset ReducedData1, ReducedData2, etc. if successful. auxiliary waves, scan positions, attributes are loaded but not listed in the string. empty string if an error occurred. error messages are printed to the history.
    Version
    this function supports regions as of version 1.03.
    -

    Definition at line 1970 of file pearl-pshell-import.ipf.

    +

    Definition at line 2022 of file pearl-pshell-import.ipf.

    @@ -1143,7 +1149,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded wave if successful. empty string otherwise.
    -

    Definition at line 1259 of file pearl-pshell-import.ipf.

    +

    Definition at line 1266 of file pearl-pshell-import.ipf.

    @@ -1200,7 +1206,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded wave if successful. empty string otherwise.
    -

    Definition at line 1123 of file pearl-pshell-import.ipf.

    +

    Definition at line 1130 of file pearl-pshell-import.ipf.

    @@ -1244,7 +1250,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    newline terminated string.
    -

    Definition at line 2286 of file pearl-pshell-import.ipf.

    +

    Definition at line 2349 of file pearl-pshell-import.ipf.

    @@ -1311,11 +1317,11 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded preview wave.
    -

    Definition at line 243 of file pearl-pshell-import.ipf.

    +

    Definition at line 250 of file pearl-pshell-import.ipf.

    - +
    @@ -1353,7 +1359,13 @@ global string s_scanpaths in new data folder contains a list of scan groups insi - + + + + + + + @@ -1364,32 +1376,38 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    load and reduce the ScientaImage dataset of the first scan of a PShell data file.

    -

    the resulting dataset is reduced in one image dimension by a user-defined reduction function, e.g. by region-of-interest integration, curve fitting, etc.

    +

    the resulting dataset is reduced in one image dimension by a user-defined reduction function, e.g. by region-of-interest integration, curve fitting, etc. cf. adh5_default_reduction for further details.

    the function loads the dataset image by image using the hyperslab option and applies a custom reduction function to each image. the results from the reduction function are composed into one result wave. the raw data are discarded.

    if the data is from the electron analyser driver and some special attributes are included, the function will set the scales of the image dimensions.

    +

    by default, the reduction function is called in separate threads to reduce the total loading time. (see the global variable psh5_perf_secs which reports the total run time of the function.) the effect varies depending on the balance between file loading (image size) and data processing (complexity of the reduction function). for debugging the reduction function, multi-threading can be disabled.

    Parameters
    variable progress = defaultValue progress = defaultValue,
    variable nthreads = defaultValue 
    - + +
    ANickNamedestination folder name (top level under root).
    APathNameigor symbolic path name. can be empty if the path is specified in FileName or a dialog box should be displayed.
    AFileNameif empty a dialog box shows up.
    reduction_funccustom reduction function (any user-defined function which has the same parameters as adh5_default_reduction())
    reduction_funccustom data reduction function. this can be any user-defined function which has the same parameters as adh5_default_reduction. some reduction functions are predefined in the PearlScientaPreprocess module.
    reduction_paramparameter string for the reduction function.
    progressprogress window.
    • 1 (default) show progress window
    • 0 do not show progress window
    +
    nthreads
      +
    • -1 (default) use as many threads as there are processor cores (in addition to main thread).
    • +
    • 0 use main thread only (for debugging and profiling).
    • +
    • >= 1 use a fixed number of (additional) threads.
    • +
    -
    Returns
    semicolon-separated list of the loaded waves, ReducedData1 and ReducedData2 if successful. empty string if an error occurred. error messages are printed to the history.
    +
    Returns
    semicolon-separated list of the loaded dataset ReducedData1, ReducedData2, etc. if successful. auxiliary waves, scan positions, attributes are loaded but not listed in the string. empty string if an error occurred. error messages are printed to the history.
    global string s_filepath in new data folder contains the full file path on disk.
    -global string s_scanpaths in new data folder contains a list of scan groups inside the file.
    -
    Todo:
    load scan positions.
    +global string s_scanpaths in new data folder contains a list of scan groups inside the file.
    -

    Definition at line 1846 of file pearl-pshell-import.ipf.

    +

    Definition at line 1893 of file pearl-pshell-import.ipf.

    @@ -1440,7 +1458,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    semicolon-separated list of the loaded waves.
    -

    Definition at line 546 of file pearl-pshell-import.ipf.

    +

    Definition at line 553 of file pearl-pshell-import.ipf.

    @@ -1501,7 +1519,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    semicolon-separated list of the loaded data waves (excluding attributes).
    -

    Definition at line 353 of file pearl-pshell-import.ipf.

    +

    Definition at line 360 of file pearl-pshell-import.ipf.

    @@ -1541,7 +1559,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    semicolon-separated list of the loaded waves.
    -

    Definition at line 506 of file pearl-pshell-import.ipf.

    +

    Definition at line 513 of file pearl-pshell-import.ipf.

    @@ -1585,7 +1603,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    newline terminated string.
    -

    Definition at line 2333 of file pearl-pshell-import.ipf.

    +

    Definition at line 2396 of file pearl-pshell-import.ipf.

    @@ -1632,7 +1650,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    semicolon-separated list of the loaded waves.
    -

    Definition at line 614 of file pearl-pshell-import.ipf.

    +

    Definition at line 621 of file pearl-pshell-import.ipf.

    @@ -1689,7 +1707,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded wave if successful. empty string otherwise.
    -

    Definition at line 815 of file pearl-pshell-import.ipf.

    +

    Definition at line 822 of file pearl-pshell-import.ipf.

    @@ -1754,7 +1772,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded wave if successful. empty string otherwise.
    Warning
    EXPERIMENTAL: this function is under development.
    -

    Definition at line 928 of file pearl-pshell-import.ipf.

    +

    Definition at line 935 of file pearl-pshell-import.ipf.

    @@ -1805,11 +1823,11 @@ global string s_filepath in new data folder contains the full file path on disk.
    global string s_scanpaths in new data folder contains a list of scan groups inside the file.
    -

    Definition at line 102 of file pearl-pshell-import.ipf.

    +

    Definition at line 109 of file pearl-pshell-import.ipf.

    - +
    @@ -1817,7 +1835,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    - + @@ -1828,18 +1846,6 @@ global string s_scanpaths in new data folder contains a list of scan groups insi - - - - - - - - - - - - @@ -1865,7 +1871,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    static threadsafe variable reduce_slab_image static threadsafe wave reduce_slab_image ( wave  slabdata, wave  image,
    wave profile1,
    wave profile2,
    -

    Definition at line 2258 of file pearl-pshell-import.ipf.

    +

    Definition at line 2323 of file pearl-pshell-import.ipf.

    @@ -1891,7 +1897,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    -

    Definition at line 2219 of file pearl-pshell-import.ipf.

    +

    Definition at line 2284 of file pearl-pshell-import.ipf.

    @@ -1937,7 +1943,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    selected dataset.
    -

    Definition at line 753 of file pearl-pshell-import.ipf.

    +

    Definition at line 760 of file pearl-pshell-import.ipf.

    @@ -1975,7 +1981,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    convert text wave to list.

    -

    Definition at line 2392 of file pearl-pshell-import.ipf.

    +

    Definition at line 2455 of file pearl-pshell-import.ipf.

    @@ -2019,7 +2025,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    convert numeric wave to list.

    -

    Definition at line 2409 of file pearl-pshell-import.ipf.

    +

    Definition at line 2472 of file pearl-pshell-import.ipf.

    @@ -2036,7 +2042,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    Dimension label for the angle dispersive dimension of multi-dimensional datasets.

    -

    Definition at line 60 of file pearl-pshell-import.ipf.

    +

    Definition at line 67 of file pearl-pshell-import.ipf.

    @@ -2053,7 +2059,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    Dimension label for the data dimension.

    This label may be used to store the parameters for the setscale d operation.

    -

    Definition at line 67 of file pearl-pshell-import.ipf.

    +

    Definition at line 74 of file pearl-pshell-import.ipf.

    @@ -2069,7 +2075,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    multiply scienta detector intensity by this value to get actual counts.

    -

    Definition at line 79 of file pearl-pshell-import.ipf.

    +

    Definition at line 86 of file pearl-pshell-import.ipf.

    @@ -2085,7 +2091,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    Dimension label for the energy dispersive dimension of multi-dimensional datasets.

    -

    Definition at line 57 of file pearl-pshell-import.ipf.

    +

    Definition at line 64 of file pearl-pshell-import.ipf.

    @@ -2101,7 +2107,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    List of preferred datasets to load for preview.

    -

    Definition at line 70 of file pearl-pshell-import.ipf.

    +

    Definition at line 77 of file pearl-pshell-import.ipf.

    @@ -2117,7 +2123,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    Dimension label for the scan dimension of multi-dimensional datasets.

    -

    Definition at line 63 of file pearl-pshell-import.ipf.

    +

    Definition at line 70 of file pearl-pshell-import.ipf.

    @@ -2133,7 +2139,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    List of datasets that must be loaded to determine the axis scaling of a Scienta image.

    -

    Definition at line 73 of file pearl-pshell-import.ipf.

    +

    Definition at line 80 of file pearl-pshell-import.ipf.

    @@ -2149,7 +2155,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    List of datasets that should be transposed upon loading.

    -

    Definition at line 76 of file pearl-pshell-import.ipf.

    +

    Definition at line 83 of file pearl-pshell-import.ipf.

    @@ -2159,7 +2165,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    -Go to the documentation of this file.
    1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
    2 #pragma IgorVersion = 6.36
    3 #pragma ModuleName = PearlPShellImport
    4 #pragma version = 1.03
    5 #include <HDF5 Browser>
    6 #include "pearl-gui-tools"
    7 #include "pearl-area-import"
    8 
    9 // copyright (c) 2013-16 Paul Scherrer Institut
    10 //
    11 // Licensed under the Apache License, Version 2.0 (the "License");
    12 // you may not use this file except in compliance with the License.
    13 // You may obtain a copy of the License at
    14 // http:///www.apache.org/licenses/LICENSE-2.0
    15 
    50 
    55 
    57 const string kEnergyDimLabel = "energy";
    58 
    60 const string kAngleDimLabel = "angle";
    61 
    63 const string kScanDimLabel = "scan";
    64 
    67 const string kDataDimLabel = "data";
    68 
    70 const string kPreviewDatasets = "ScientaImage;ScientaSpectrum;ImageAngleDistribution;ImageEnergyDistribution;Counts;SampleCurrent;";
    71 
    73 const string kScientaScalingDatasets = "LensMode;ScientaChannelBegin;ScientaChannelEnd;ScientaSliceBegin;ScientaSliceEnd;";
    74 
    76 const string kTransposedDatasets = "ScientaImage;";
    77 
    79 const variable kDetectorSensitivity = 4;
    80 
    102 variable psh5_open_file(string ANickName, string APathName, string AFileName){
    103  string ANickName
    104  string APathName
    105  string AFileName
    106 
    107  setdatafolder root:
    108  newdatafolder /s /o $("root:" + ANickName)
    109  dfref fileDF = GetDataFolderDFR()
    110 
    111  variable fileID
    112  HDF5OpenFile /P=$APathName /R fileID as AFileName
    113  if (v_flag == 0)
    114  string /g s_filepath
    115  string /g s_scanpaths
    116  s_filepath = s_path + s_filename
    117  s_scanpaths = psh5_list_scans(fileID)
    118  else
    119  fileID = 0
    120  endif
    121 
    122  return fileID
    123 };
    124 
    132 variable psh5_close_file(variable fileID){
    133  variable fileID
    134 
    135  HDF5CloseFile fileID
    136 };
    137 
    162 string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
    163  string ANickName
    164  string APathName
    165  string AFileName
    166  variable load_data
    167  variable load_attr
    168 
    169  if (ParamIsDefault(load_data))
    170  load_data = 1
    171  endif
    172  if (ParamIsDefault(load_attr))
    173  load_attr = 1
    174  endif
    175 
    176  dfref saveDF = GetDataFolderDFR()
    177 
    178  // performance monitoring
    179  variable timerRefNum
    180  variable /g psh5_perf_secs
    181  timerRefNum = startMSTimer
    182 
    183  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
    184  if (fileID)
    185  dfref fileDF = GetDataFolderDFR()
    186  svar s_filepath
    187  svar s_scanpaths
    188  AFileName = s_filepath
    189  print "loading " + s_filepath + "\r"
    190 
    191  variable ig
    192  variable ng = ItemsInList(s_scanpaths, ";")
    193  string sg
    194  string folder
    195 
    196  for (ig = 0; ig < ng; ig += 1)
    197  sg = StringFromList(ig, s_scanpaths, ";")
    198  folder = ReplaceString("/", sg, "")
    199  folder = ReplaceString(" ", folder, "")
    200  folder = CleanupName(folder, 0)
    201  setdatafolder fileDF
    202  newdatafolder /s /o $folder
    203  psh5_load_scan_complete(fileID, sg, load_data=load_data, load_attr=load_attr)
    204  endfor
    205 
    206  psh5_close_file(fileID)
    207  else
    208  AFileName = ""
    209  endif
    210 
    211  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
    212 
    213  setdatafolder saveDF
    214  return AFileName
    215 };
    216 
    243 string psh5_load_preview(string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue, string pref_scans = defaultValue, string pref_datasets = defaultValue){
    244  string APathName
    245  string AFileName
    246  variable load_data
    247  variable load_attr
    248  string pref_scans
    249  string pref_datasets
    250 
    251  if (ParamIsDefault(load_data))
    252  load_data = 1
    253  endif
    254  if (ParamIsDefault(load_attr))
    255  load_attr = 1
    256  endif
    257  if (ParamIsDefault(pref_scans))
    258  pref_scans = "*scan1*;"
    259  endif
    260  if (ParamIsDefault(pref_datasets))
    261  pref_datasets = ""
    262  endif
    263 
    264  dfref saveDF = GetDataFolderDFR()
    265 
    266  variable fileID
    267  string scanpaths = ""
    268  string dataname = ""
    269 
    270  // performance monitoring
    271  variable timerRefNum
    272  variable /g adh5_perf_secs
    273  timerRefNum = startMSTimer
    274 
    275  HDF5OpenFile /P=$APathName /R /Z fileID as AFileName
    276  if (v_flag == 0)
    277  AFileName = s_path + s_filename
    278  dfref fileDF = GetDataFolderDFR()
    279 
    280  scanpaths = psh5_list_scans(fileID)
    281  variable ng = ItemsInList(scanpaths)
    282  variable ig
    283  string sg
    284  variable np = ItemsInList(pref_scans)
    285  variable ip
    286  string sp
    287  variable found = 0
    288  if (ng > 0)
    289  for (ip = 0; ip < np; ip += 1)
    290  for (ig = 0; ig < ng; ig += 1)
    291  sg = StringFromList(ig, scanpaths)
    292  sp = StringFromList(ip, pref_scans)
    293  if (StringMatch(sg, sp))
    294  found = 1
    295  break
    296  endif
    297  endfor
    298  if (found)
    299  break
    300  endif
    301  endfor
    302  if (!found)
    303  ig = 0
    304  endif
    305  sg = StringFromList(ig, scanpaths)
    306 
    307  if (load_attr)
    308  setdatafolder fileDF
    309  newdatafolder /o/s attr
    310  killwaves /a/z
    311  psh5_load_scan_attrs(fileID, sg)
    312  endif
    313 
    314  setdatafolder fileDF
    315  dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr, pref_datasets=pref_datasets)
    316  else
    317  print "no scans found in file " + AFileName
    318  endif
    319 
    320  HDF5CloseFile fileID
    321  endif
    322 
    323  if (timerRefNum >= 0)
    324  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
    325  endif
    326 
    327  setdatafolder saveDF
    328  return dataname
    329 };
    330 
    353 string psh5_load_scan_complete(variable fileID, string scanpath, variable load_data = defaultValue, variable load_attr = defaultValue){
    354  variable fileID
    355  string scanpath
    356  variable load_data
    357  variable load_attr
    358 
    359  if (ParamIsDefault(load_data))
    360  load_data = 1
    361  endif
    362  if (ParamIsDefault(load_attr))
    363  load_attr = 1
    364  endif
    365 
    366  dfref saveDF = GetDataFolderDFR()
    367 
    368  dfref dataDF = GetDataFolderDFR()
    369  string wavenames
    370  string attrnames
    371  psh5_load_scan_meta(fileID, scanpath)
    372  if (load_attr)
    373  newdatafolder /s /o attr
    374  attrnames = psh5_load_scan_attrs(fileID, scanpath)
    375  endif
    376  if (load_data)
    377  setdatafolder dataDF
    378  wavenames = psh5_load_scan_data(fileID, scanpath)
    379  endif
    380  if (load_data && load_attr)
    381  setdatafolder dataDF
    383  endif
    384 
    385  setdatafolder saveDF
    386  return wavenames
    387 };
    388 
    397 string psh5_list_scans(variable fileID){
    398  variable fileID
    399 
    400  HDF5ListGroup /F /TYPE=1 fileID, "/"
    401 
    402  variable ig
    403  variable ng = ItemsInList(S_HDF5ListGroup, ";")
    404  string sg
    405  string scans = ""
    406 
    407  for (ig = 0; ig < ng; ig += 1)
    408  sg = StringFromList(ig, S_HDF5ListGroup, ";")
    409  if (cmpstr(sg[1,4], "scan") == 0)
    410  scans = AddListItem(sg, scans, ";", inf)
    411  endif
    412  endfor
    413 
    414  return scans
    415 };
    416 
    432 string psh5_list_scan_datasets(variable fileID, string scanpath, variable include_regions = defaultValue){
    433  variable fileID
    434  string scanpath
    435  variable include_regions
    436 
    437  if (ParamIsDefault(include_regions))
    438  include_regions = 0
    439  endif
    440  string result
    441 
    442  HDF5ListGroup /TYPE=2 /Z fileID, scanpath
    443  result = S_HDF5ListGroup
    444 
    445  if (include_regions)
    446  HDF5ListGroup /R /TYPE=2 /Z fileID, scanpath
    447  variable n = ItemsInList(S_HDF5ListGroup)
    448  variable i
    449  string ds
    450  string region_datasets
    451  for (i = 0; i < n; i += 1)
    452  ds = StringFromList(i, S_HDF5ListGroup)
    453  if (StringMatch(ds, "region*/*"))
    454  //region_datasets = psh5_list_scan_datasets(fileID, ReplaceString("//", scanpath + "/" + region, "/"), include_regions=0)
    455  result = AddListItem(ds, result, ";", inf)
    456  endif
    457  endfor
    458  endif
    459 
    460  return result
    461 };
    462 
    473 string psh5_list_scan_regions(variable fileID, string scanpath){
    474  variable fileID
    475  string scanpath
    476 
    477  HDF5ListGroup /TYPE=1 /Z fileID, scanpath
    478  variable n = ItemsInList(S_HDF5ListGroup)
    479  variable i
    480  string result = ""
    481  string s
    482  for (i = 0; i < n; i += 1)
    483  s = StringFromList(i, S_HDF5ListGroup)
    484  if (StringMatch(s, "region*"))
    485  result = AddListItem(s, result, ";", inf)
    486  endif
    487  endfor
    488 
    489  return result
    490 };
    491 
    506 string psh5_load_scan_data(variable fileID, string scanpath){
    507  variable fileID
    508  string scanpath
    509 
    510  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
    511  variable nds = ItemsInList(datasets)
    512  variable ids
    513  string sds
    514  string sw
    515  string wavenames = ""
    516  for (ids = 0; ids < nds; ids += 1)
    517  sds = StringFromList(ids, datasets)
    518  sw = psh5_load_dataset(fileID, scanpath, sds, set_scale=0)
    519  wavenames = AddListItem(sw, wavenames, ";", inf)
    520  endfor
    521 
    522  return wavenames
    523 };
    524 
    546 string psh5_load_scan_attrs(variable fileID, string scanpath, variable attr_sets = defaultValue){
    547  variable fileID
    548  string scanpath
    549  variable attr_sets
    550 
    551  if (ParamIsDefault(attr_sets))
    552  attr_sets = 1
    553  endif
    554 
    555  string attr_path = ReplaceString("//", scanpath + "/attrs", "/")
    556  string attr_list = ""
    557  if (attr_sets & 1)
    558  HDF5ListGroup /TYPE=2 /Z fileID, attr_path
    559  if (!v_flag)
    560  attr_list = S_HDF5ListGroup
    561  endif
    562  endif
    563 
    564  variable ids
    565  variable nds
    566  string sds
    567 
    568  if (attr_sets & 2)
    569  nds = ItemsInList(kScientaScalingDatasets, ";")
    570  for (ids = 0; ids < nds; ids += 1)
    571  sds = StringFromList(ids, kScientaScalingDatasets)
    572  if (WhichListItem(sds, attr_list) < 0)
    573  attr_list = AddListItem(sds, attr_list, ";", inf)
    574  endif
    575  endfor
    576  endif
    577 
    578  nds = ItemsInList(attr_list, ";")
    579  string wavenames = ""
    580  for (ids = 0; ids < nds; ids += 1)
    581  sds = StringFromList(ids, attr_list, ";")
    582  HDF5LoadData /O /Q /Z fileID, attr_path + "/" + sds
    583  if (!v_flag)
    584  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    585  endif
    586  endfor
    587  wavenames = ReplaceString(";;", wavenames, ";")
    588 
    589  return wavenames
    590 };
    591 
    614 string psh5_load_scan_meta(variable fileID, string scanpath){
    615  variable fileID
    616  string scanpath
    617  string wavenames = ""
    618 
    619  HDF5LoadData /O /Q /Z /A="Dimensions" /N=ScanDimensions /TYPE=1 fileID, scanpath
    620  if (!v_flag)
    621  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    622  else
    623  make /n=1 /o ScanDimensions
    624  ScanDimensions = 0
    625  wavenames = AddListItem("ScanDimensions", wavenames, ";", inf)
    626  endif
    627  HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 fileID, scanpath
    628  if (!v_flag)
    629  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    630  else
    631  make /n=1 /o /t ScanReadables
    632  ScanReadables[0] = "ScientaSpectrum"
    633  wavenames = AddListItem("ScanReadables", wavenames, ";", inf)
    634  endif
    635  HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 fileID, scanpath
    636  if (!v_flag)
    637  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    638  endif
    639  HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 fileID, scanpath
    640  if (!v_flag)
    641  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    642  endif
    643  wavenames = ReplaceString(";;", wavenames, ";")
    644 
    645  return wavenames
    646 };
    647 
    681 string psh5_load_dataset(variable fileID, string scanpath, string datasetname, variable set_scale = defaultValue){
    682  variable fileID
    683  string scanpath
    684  string datasetname
    685  variable set_scale
    686 
    687  if (ParamIsDefault(set_scale))
    688  set_scale = 1
    689  endif
    690 
    691  dfref base_df = GetDataFolderDFR()
    692 
    693  string datasetpath
    694  datasetpath = scanpath + "/" + datasetname
    695  datasetpath = ReplaceString("//", datasetpath, "/")
    696 
    697  string regionname
    698  string regionpath
    699  if (ItemsInList(datasetname, "/") >= 2)
    700  regionname = StringFromList(0, datasetname, "/")
    701  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
    702  datasetname = RemoveListItem(0, datasetname, "/")
    703  NewDataFolder /o/s $regionname
    704  else
    705  regionname = ""
    706  regionpath = scanpath
    707  endif
    708 
    709  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    710  InitHDF5DataInfo(di)
    711  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    712  if (err != 0)
    713  print "error accessing detector/data"
    714  return ""
    715  endif
    716 
    717  string dataname
    718  if (di.ndims < 2)
    719  HDF5LoadData /O /Q /Z fileID, datasetpath
    720  dataname = StringFromList(0, S_waveNames)
    721  else
    722  dataname = psh5_load_dataset_slabs(fileID, regionpath, datasetname)
    723  endif
    724 
    725  wave /z data = $dataname
    726  if (waveexists(data))
    727  psh5_load_dataset_meta(fileID, regionpath, datasetname, data)
    728  ps_set_dimlabels(data)
    729  if (set_scale)
    730  ps_scale_dataset(data)
    731  endif
    732  else
    733  dataname = ""
    734  endif
    735 
    736  setdatafolder base_df
    737  return dataname
    738 };
    739 
    753 static string select_dataset(string file_datasets, string pref_datasets){
    754  string file_datasets
    755  string pref_datasets
    756 
    757  variable index
    758  variable nds = ItemsInList(file_datasets)
    759  variable ids
    760  string sds = ""
    761  string mds = ""
    762  variable np = ItemsInList(pref_datasets)
    763  variable ip
    764  string sp
    765  variable found = 0
    766  if (nds > 0)
    767  for (ip = 0; ip < np; ip += 1)
    768  for (ids = 0; ids < nds; ids += 1)
    769  sds = StringFromList(ids, file_datasets)
    770  index = ItemsInList(sds, "/") - 1
    771  mds = StringFromList(index, sds, "/")
    772  sp = StringFromList(ip, pref_datasets)
    773  if (StringMatch(mds, sp))
    774  found = 1
    775  break
    776  endif
    777  endfor
    778  if (found)
    779  break
    780  endif
    781  endfor
    782  if (!found)
    783  ids = 0
    784  sds = StringFromList(ids, file_datasets)
    785  endif
    786  endif
    787 
    788  return sds
    789 };
    790 
    815 string psh5_load_scan_preview(variable fileID, string scanpath, variable set_scale = defaultValue, string pref_datasets = defaultValue){
    816  variable fileID
    817  string scanpath
    818  variable set_scale
    819  string pref_datasets
    820 
    821  if (ParamIsDefault(set_scale))
    822  set_scale = 1
    823  endif
    824  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
    825  pref_datasets = kPreviewDatasets
    826  endif
    827 
    828  dfref saveDF = GetDataFolderDFR()
    829  dfref dataDF = saveDF
    830 
    831  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
    832  string datasetname = select_dataset(datasets, pref_datasets)
    833  string datasetpath
    834  datasetpath = scanpath + "/" + datasetname
    835  datasetpath = ReplaceString("//", datasetpath, "/")
    836 
    837  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    838  InitHDF5DataInfo(di)
    839  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    840  if (err != 0)
    841  print "error accessing detector/data"
    842  return ""
    843  endif
    844 
    845  string dataname
    846  if (di.ndims < 2)
    847  HDF5LoadData /O /Q /Z fileID, datasetpath
    848  dataname = StringFromList(0, S_waveNames)
    849  wave /z data = $dataname
    850  if (waveexists(data))
    851  ps_set_dimlabels(data)
    852  endif
    853  else
    854  variable dim2start = 0
    855  variable dim2count = 1
    856  variable dim3start = 0
    857  variable dim3count = 1
    858  if (di.ndims >= 3)
    859  dim2start = floor(di.dims[2] / 2)
    860  dim2count = 1
    861  endif
    862  if (di.ndims >= 4)
    863  dim3start = floor(di.dims[3] / 2)
    864  dim3count = 1
    865  endif
    866 
    867  dataname = psh5_load_dataset_slab(fileID, scanpath, datasetname, dim2start, dim2count, dim3start, dim3count)
    868  endif
    869 
    870  wave /z data = $dataname
    871  if (waveexists(data))
    872  if (set_scale)
    873  setdatafolder dataDF
    874  string positioners
    875  string positioner
    876  string positionerpath
    877  positioners = psh5_load_scan_meta(fileID, scanpath)
    878  wave /t /z ScanWritables
    879  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    880  positioner = ScanWritables[0]
    881  if (strlen(positioner) > 0)
    882  positionerpath = scanpath + "/" + positioner
    883  positionerpath = ReplaceString("//", positionerpath, "/")
    884  HDF5LoadData /O /Q /Z fileID, positionerpath
    885  endif
    886  endif
    887 
    888  setdatafolder dataDF
    889  newdatafolder /o/s attr
    890  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
    891  setdatafolder dataDF
    892  ps_scale_dataset(data)
    893  endif
    894  else
    895  dataname = ""
    896  endif
    897 
    898  return dataname
    899 };
    900 
    928 string psh5_load_scan_section(variable fileID, string scanpath, variable dim, variable set_scale = defaultValue, string pref_datasets = defaultValue){
    929  variable fileID
    930  string scanpath
    931  variable dim
    932  variable set_scale
    933  string pref_datasets
    934 
    935  // select first dimension (future argument)
    936  // 0 = first dimension is x axis (energy of scienta image)
    937  dim = 0
    938 
    939  if (ParamIsDefault(set_scale))
    940  set_scale = 1
    941  endif
    942  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
    943  pref_datasets = kPreviewDatasets
    944  endif
    945 
    946  dfref saveDF = GetDataFolderDFR()
    947  dfref dataDF = saveDF
    948 
    949  string datasets = psh5_list_scan_datasets(fileID, scanpath)
    950  string datasetname = select_dataset(datasets, pref_datasets)
    951  string datasetpath
    952  datasetpath = scanpath + "/" + datasetname
    953  datasetpath = ReplaceString("//", datasetpath, "/")
    954  string dataname = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    955  string destname = dataname[0,29] + num2str(dim)
    956 
    957  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    958  InitHDF5DataInfo(di)
    959  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    960  if (err != 0)
    961  print "error accessing detector/data"
    962  return ""
    963  else if (di.ndims != 3)
    964  print "error: rank of dataset != 3"
    965  return ""
    966  endif
    967 
    968  variable idx, idy, idz, idt
    969  variable transpose = WhichListItem(dataname, kTransposedDatasets) >= 0
    970  if (transpose)
    971  idx = 1
    972  idy = 0
    973  else
    974  idx = 0
    975  idy = 1
    976  endif
    977  idz = 2
    978  idt = 3
    979 
    980  variable nx, ny, nz
    981  nx = di.dims[idx]
    982  ny = di.dims[idy]
    983  nz = di.dims[idz]
    984 
    985  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    986  wave slab
    987  slab[][%Start] = 0
    988  slab[][%Stride] = 1
    989  slab[][%Count] = 1
    990  slab[][%Block] = 1
    991 
    992  if (dim == 0)
    993  slab[idy][%Start] = floor(ny / 2)
    994  slab[idx][%Block] = nx
    995  make /n=(nx,nz) /o $destname
    996  else
    997  slab[idx][%Start] = floor(nx / 2)
    998  slab[idy][%Block] = ny
    999  make /n=(ny,nz) /o $destname
    1000  endif
    1001  slab[idz][%Block] = nz
    1002  wave data = $destname
    1003  data = 0
    1004 
    1005  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    1006  if (!v_flag)
    1007  wave slabdata
    1008  if (transpose)
    1009  data += slabdata[0][p][q][0]
    1010  else
    1011  data += slabdata[p][0][q][0]
    1012  endif
    1013  endif
    1014  killwaves /z slab, slabdata
    1015 
    1016  if (set_scale)
    1017  make /n=(1,1,1) /free dummy
    1018  ps_set_dimlabels2(dummy, dataname)
    1019  setdimlabel 0, -1, $GetDimLabel(dummy, dim, -1), data
    1020  setdimlabel 1, -1, $kScanDimLabel, data
    1021 
    1022  setdatafolder dataDF
    1023  string positioners
    1024  string positioner
    1025  string positionerpath
    1026  positioners = psh5_load_scan_meta(fileID, scanpath)
    1027  wave /t /z ScanWritables
    1028  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    1029  positioner = ScanWritables[0]
    1030  if (strlen(positioner) > 0)
    1031  positionerpath = scanpath + "/" + positioner
    1032  positionerpath = ReplaceString("//", positionerpath, "/")
    1033  HDF5LoadData /O /Q /Z fileID, positionerpath
    1034  endif
    1035  endif
    1036 
    1037  setdatafolder dataDF
    1038  newdatafolder /o/s attr
    1039  killwaves /a/z
    1040  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
    1041  setdatafolder dataDF
    1042  ps_scale_dataset(data)
    1043  endif
    1044 
    1045  return destname
    1046 };
    1047 
    1066 variable psh5_load_dataset_meta(variable fileID, string datapath, string datasetname, wave datawave){
    1067  variable fileID
    1068  string datapath
    1069  string datasetname
    1070  wave datawave
    1071 
    1072  dfref saveDF = GetDataFolderDFR()
    1073  SetDataFolder NewFreeDataFolder()
    1074 
    1075  string datasetpath = datapath + "/" + datasetname
    1076  datasetpath = ReplaceString("//", datasetpath, "/")
    1077  string wnote
    1078 
    1079  HDF5LoadData /O /Q /Z /A="Writable Dimension" /N=WriteDim fileID, datasetpath
    1080  if (!v_flag)
    1081  wave WriteDim
    1082  // scan dimension starts at 1
    1083  sprintf wnote, "ScanDimension=%u", WriteDim[0]
    1084  Note datawave, wnote
    1085  endif
    1086 
    1087  HDF5LoadData /O /Q /Z /A="Writable Index" /N=WriteIndex fileID, datasetpath
    1088  if (!v_flag)
    1089  wave WriteIndex
    1090  sprintf wnote, "WriteableIndex=%u", WriteIndex[0]
    1091  Note datawave, wnote
    1092  endif
    1093 
    1094  HDF5LoadData /O /Q /Z /A="Readable Index" /N=ReadIndex fileID, datasetpath
    1095  if (!v_flag)
    1096  wave ReadIndex
    1097  sprintf wnote, "ReadableIndex=%u", ReadIndex[0]
    1098  Note datawave, wnote
    1099  endif
    1100 
    1101  setdatafolder saveDF
    1102  return 0
    1103 };
    1104 
    1123 string psh5_load_dataset_slabs(variable fileID, string datapath, string datasetname, variable progress = defaultValue){
    1124  variable fileID
    1125  string datapath
    1126  string datasetname
    1127  variable progress
    1128 
    1129  if (ParamIsDefault(progress))
    1130  progress = 1
    1131  endif
    1132 
    1133  variable result = 0
    1134  string datasetpath
    1135  string datawavename
    1136  datasetpath = datapath + "/" + datasetname
    1137  datasetpath = ReplaceString("//", datasetpath, "/")
    1138  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    1139 
    1140  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    1141  InitHDF5DataInfo(di)
    1142  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    1143  if (err != 0)
    1144  print "error accessing detector/data"
    1145  return ""
    1146  endif
    1147  if (di.ndims < 2)
    1148  print "error: rank of dataset < 2"
    1149  return ""
    1150  else if (di.ndims < 3)
    1151  progress = 0
    1152  endif
    1153 
    1154  variable idx, idy, idz, idt, izt
    1155  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
    1156  if (transpose)
    1157  idx = 1
    1158  idy = 0
    1159  else
    1160  idx = 0
    1161  idy = 1
    1162  endif
    1163  idz = 2
    1164  idt = 3
    1165 
    1166  variable nx, ny, nz, nt, nzt
    1167  nx = di.dims[idx]
    1168  ny = di.dims[idy]
    1169  nz = di.dims[idz]
    1170  nt = di.dims[idt]
    1171  make /n=(nx,ny,nz,nt) /o $datawavename
    1172  wave data = $datawavename
    1173 
    1174  nz = max(nz, 1)
    1175  nt = max(nt, 1)
    1176  nzt = nz * nt
    1177  izt = 0
    1178  if (progress)
    1179  display_progress_panel("HDF5 Import", "Loading data...", nzt)
    1180  endif
    1181 
    1182  // load data image by image
    1183  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    1184  wave slab
    1185  slab[][%Start] = 0
    1186  slab[][%Stride] = 1
    1187  slab[][%Count] = 1
    1188  slab[][%Block] = 1
    1189  slab[idx][%Block] = nx
    1190  slab[idy][%Block] = ny
    1191 
    1192  variable iz, it
    1193  for (iz = 0; iz < nz; iz += 1)
    1194  for (it = 0; it < nt; it += 1)
    1195  slab[idz][%Start] = iz
    1196  slab[idt][%Start] = it
    1197  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    1198  wave slabdata// 2D, 3D, or 4D with singletons
    1199  if (transpose)
    1200  data[][][iz][it] = slabdata[q][p][0][0]
    1201  else
    1202  data[][][iz][it] = slabdata[p][q][0][0]
    1203  endif
    1204 
    1205  // progress window
    1206  izt += 1
    1207  if (progress)
    1208  if (update_progress_panel(izt))
    1209  result = -4// user abort
    1210  break
    1211  endif
    1212  endif
    1213  endfor
    1214  if (result < 0)
    1215  break
    1216  endif
    1217  endfor
    1218 
    1219  if (progress)
    1221  endif
    1222 
    1223  killwaves /z slab, slabdata
    1224  if (!result)
    1225  ps_set_dimlabels(data)
    1226  return datawavename
    1227  else
    1228  killwaves /z data
    1229  return ""
    1230  endif
    1231 };
    1232 
    1259 string psh5_load_dataset_slab(variable fileID, string datapath, string datasetname, variable dim2start, variable dim2count, variable dim3start, variable dim3count){
    1260  variable fileID
    1261  string datapath
    1262  string datasetname
    1263  variable dim2start
    1264  variable dim2count
    1265  variable dim3start
    1266  variable dim3count
    1267 
    1268  string datasetpath
    1269  string datawavename
    1270  datasetpath = datapath + "/" + datasetname
    1271  datasetpath = ReplaceString("//", datasetpath, "/")
    1272  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    1273 
    1274  STRUCT HDF5DataInfo di
    1275  InitHDF5DataInfo(di)
    1276  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    1277  if (err != 0)
    1278  print "error accessing detector/data"
    1279  return ""
    1280  endif
    1281  if (di.ndims < 2)
    1282  print "error: rank of dataset < 2"
    1283  return ""
    1284  endif
    1285 
    1286  variable idx, idy, idz, idt
    1287  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
    1288  if (transpose)
    1289  idx = 1
    1290  idy = 0
    1291  else
    1292  idx = 0
    1293  idy = 1
    1294  endif
    1295  idz = 2
    1296  idt = 3
    1297 
    1298  variable nx, ny
    1299  nx = di.dims[idx]
    1300  ny = di.dims[idy]
    1301  make /n=(nx,ny) /o $datawavename
    1302  wave data = $datawavename
    1303  data = 0
    1304 
    1305  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    1306  wave slab
    1307  slab[][%Start] = 0
    1308  slab[][%Stride] = 1
    1309  slab[][%Count] = 1
    1310  slab[][%Block] = 1
    1311  slab[idx][%Block] = nx
    1312  slab[idy][%Block] = ny
    1313 
    1314  variable iz, it
    1315  variable navg = 0
    1316  variable dim2end = dim2start + dim2count - 1
    1317  variable dim3end = dim3start + dim3count - 1
    1318  for (iz = dim2start; iz <= dim2end; iz += 1)
    1319  for (it = dim3start; it <= dim3end; it += 1)
    1320  slab[idz][%Start] = iz
    1321  slab[idt][%Start] = it
    1322  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    1323  if (!v_flag)
    1324  wave slabdata
    1325  if (transpose)
    1326  data += slabdata[q][p][0][0]
    1327  else
    1328  data += slabdata[p][q][0][0]
    1329  endif
    1330  navg += 1
    1331  endif
    1332  endfor
    1333  endfor
    1334  if (navg)
    1335  data /= navg
    1336  endif
    1337 
    1338  killwaves /z slab, slabdata
    1339  ps_set_dimlabels(data)
    1340  return datawavename
    1341 };
    1342 
    1358 variable ps_set_dimlabels(wave data){
    1359  wave data
    1360 
    1361  ps_set_dimlabels2(data, NameOfWave(data))
    1362 };
    1363 
    1377 variable ps_set_dimlabels2(wave data, string name){
    1378  wave data
    1379  string name
    1380 
    1381  variable dummy
    1382  try
    1383  // intrinsic dimensions
    1384  strswitch(name)
    1385  case "ScientaImage":
    1386  setdimlabel 0, -1, $kEnergyDimLabel, data
    1387  setdimlabel 1, -1, $kAngleDimLabel, data
    1388  if (WaveDims(data) >= 3)
    1389  setdimlabel 2, -1, $kScanDimLabel, data
    1390  endif
    1391  AbortOnRTE
    1392  break
    1393  case "ImageAngleDistribution":
    1394  case "ScientaAngleDistribution":
    1395  if (WaveDims(data) >= 2)
    1396  setdimlabel 0, -1, $kScanDimLabel, data
    1397  setdimlabel 1, -1, $kAngleDimLabel, data
    1398  else
    1399  setdimlabel 0, -1, $kAngleDimLabel, data
    1400  endif
    1401  AbortOnRTE
    1402  break
    1403  case "ScientaSpectrum":
    1404  case "ImageEnergyDistribution":
    1405  case "ScientaEnergyDistribution":
    1406  if (WaveDims(data) >= 2)
    1407  setdimlabel 0, -1, $kScanDimLabel, data
    1408  setdimlabel 1, -1, $kEnergyDimLabel, data
    1409  else
    1410  setdimlabel 0, -1, $kEnergyDimLabel, data
    1411  endif
    1412  AbortOnRTE
    1413  break
    1414  default:
    1415  if (WaveDims(data) == 1)
    1416  setdimlabel 0, -1, $kScanDimLabel, data
    1417  AbortOnRTE
    1418  else
    1419  return 1
    1420  endif
    1421  endswitch
    1422  catch
    1423  dummy = GetRTError(1)
    1424  return 2
    1425  endtry
    1426  return 0
    1427 };
    1428 
    1434 static dfr find_scan_folder(dfref dataDF){
    1435  dfref dataDF
    1436 
    1437  dfref attrDF = dataDF:attr
    1438  if (!DataFolderRefStatus(attrDF))
    1439  string df = GetDataFolder(1, dataDF) + ":"
    1440  dfref scanDF = $df
    1441  else
    1442  dfref scanDF = dataDF
    1443  endif
    1444  return scanDF
    1445 };
    1446 
    1451 static dfr find_attr_folder(dfref dataDF){
    1452  dfref dataDF
    1453 
    1454  dfref attrDF = dataDF:attr
    1455  if (!DataFolderRefStatus(attrDF))
    1456  string df = GetDataFolder(1, dataDF) + ":"
    1457  dfref scanDF = $df
    1458  dfref attrDF = scanDF:attr
    1459  endif
    1460  return attrDF
    1461 };
    1462 
    1480  dfref scanDF = GetDataFolderDFR()
    1481  dfref attrDF = find_attr_folder(scanDF)
    1482 
    1483  make /n=3 /free lo, hi
    1484  make /n=3 /t /free ax, un
    1485  wave /t /z /SDFR=scanDF ScanReadables
    1486  if (WaveExists(ScanReadables))
    1487  variable isr
    1488  variable nsr = numpnts(ScanReadables)
    1489  string ssr
    1490  string sdf
    1491  for (isr = 0; isr < nsr; isr += 1)
    1492  setdatafolder scanDF
    1493  ssr = ScanReadables[isr]
    1494  if (ItemsInList(ssr, "/") >= 2)
    1495  sdf = StringFromList(0, ssr, "/")
    1496  ssr = RemoveListItem(0, ssr, "/")
    1497  setdatafolder $sdf
    1498  endif
    1499  wave /z wsr=$ssr
    1500  if (WaveExists(wsr))
    1501  ps_detect_scale(ax, lo, hi, un)
    1502  ps_scale_dataset_2(wsr, ax, lo, hi, un)
    1503  endif
    1504  endfor
    1505  endif
    1506  setdatafolder scanDF
    1507 };
    1508 
    1525 variable ps_scale_dataset(wave data){
    1526  wave data
    1527 
    1528  dfref saveDF = GetDataFolderDFR()
    1529  dfref dataDF = GetWavesDataFolderDFR(data)
    1530 
    1531  setdatafolder dataDF
    1532  make /n=3 /free lo, hi
    1533  make /n=3 /t /free ax, un
    1534  ps_detect_scale(ax, lo, hi, un)
    1535  ps_scale_dataset_2(data, ax, lo, hi, un)
    1536  setdatafolder saveDF
    1537 };
    1538 
    1539 static wave find_scale_wave(string name, dfref dataDF, dfref scanDF, dfref attrDF){
    1540  string name
    1541  dfref dataDF
    1542  dfref scanDF
    1543  dfref attrDF
    1544 
    1545  wave /SDFR=dataDF /Z w = $name
    1546  if (!WaveExists(w))
    1547  wave /SDFR=scanDF /Z w = $name
    1548  if (!WaveExists(w))
    1549  wave /SDFR=attrDF /Z w = $name
    1550  endif
    1551  endif
    1552  return w
    1553 };
    1554 
    1596 variable ps_detect_scale(wave ax, wave lo, wave hi, wave un){
    1597  wave /t ax
    1598  wave lo
    1599  wave hi
    1600  wave /t un
    1601 
    1602  dfref dataDF = GetDataFolderDFR()
    1603  dfref scanDF = find_scan_folder(dataDF)
    1604  dfref attrDF = find_attr_folder(dataDF)
    1605 
    1606  redimension /n=4 lo, hi, un, ax
    1607  setdimlabel 0, 0, $kEnergyDimLabel, lo, hi, un, ax
    1608  setdimlabel 0, 1, $kAngleDimLabel, lo, hi, un, ax
    1609  setdimlabel 0, 2, $kScanDimLabel, lo, hi, un, ax
    1610  setdimlabel 0, 3, $kDataDimLabel, lo, hi, un, ax
    1611 
    1612  // default values
    1613  lo[%$kEnergyDimLabel] = 0
    1614  hi[%$kEnergyDimLabel] = 1
    1615  un[%$kEnergyDimLabel] = "eV"
    1616  ax[%$kEnergyDimLabel] = "Ekin"
    1617 
    1618  lo[%$kAngleDimLabel] = -1
    1619  hi[%$kAngleDimLabel] = 1
    1620  un[%$kAngleDimLabel] = "arb."
    1621  un[%$kAngleDimLabel] = "slice"
    1622 
    1623  lo[%$kScanDimLabel] = 0
    1624  hi[%$kScanDimLabel] = 1
    1625  un[%$kScanDimLabel] = "arb."
    1626  ax[%$kScanDimLabel] = "scan"
    1627 
    1628  lo[%$kDataDimLabel] = 0
    1629  hi[%$kDataDimLabel] = 0
    1630  un[%$kDataDimLabel] = "arb."
    1631  ax[%$kDataDimLabel] = "value"
    1632 
    1633  wave /SDFR=attrDF /T /Z LensMode
    1634  wave /Z ChannelBegin = find_scale_wave("ScientaChannelBegin", dataDF, scanDF, attrDF)
    1635  wave /Z ChannelEnd = find_scale_wave("ScientaChannelEnd", dataDF, scanDF, attrDF)
    1636  wave /Z SliceBegin = find_scale_wave("ScientaSliceBegin", dataDF, scanDF, attrDF)
    1637  wave /Z SliceEnd = find_scale_wave("ScientaSliceEnd", dataDF, scanDF, attrDF)
    1638 
    1639  // lens mode can give more detail
    1640  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
    1641  strswitch(LensMode[0])
    1642  case "Angular45":
    1643  lo[%$kAngleDimLabel] = -45/2
    1644  hi[%$kAngleDimLabel] = +45/2
    1645  un[%$kAngleDimLabel] = ""
    1646  ax[%$kAngleDimLabel] = "angle"
    1647  break
    1648  case "Angular60":
    1649  lo[%$kAngleDimLabel] = -60/2
    1650  hi[%$kAngleDimLabel] = +60/2
    1651  un[%$kAngleDimLabel] = ""
    1652  ax[%$kAngleDimLabel] = "angle"
    1653  break
    1654  case "Transmission":
    1655  un[%$kAngleDimLabel] = "arb."
    1656  ax[%$kAngleDimLabel] = "offset"
    1657  break
    1658  endswitch
    1659  endif
    1660 
    1661  // best option if scales are explicit in separate waves
    1662  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
    1663  lo[%$kEnergyDimLabel] = ChannelBegin[0]
    1664  hi[%$kEnergyDimLabel] = ChannelEnd[0]
    1665  endif
    1666  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
    1667  lo[%$kAngleDimLabel] = SliceBegin[0]
    1668  hi[%$kAngleDimLabel] = SliceEnd[0]
    1669  endif
    1670 
    1671  wave /z /t /SDFR=scanDF ScanWritables
    1672  if (WaveExists(ScanWritables))
    1673  wave /z /SDFR=scanDF scanner = $ScanWritables[0]
    1674  if (!WaveExists(scanner))
    1675  wave /z /SDFR=attrDF scanner = $ScanWritables[0]
    1676  endif
    1677  if (WaveExists(scanner) && (numpnts(scanner) >= 1))
    1678  lo[%$kScanDimLabel] = scanner[0]
    1679  hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1]
    1680  ax[%$kScanDimLabel] = NameOfWave(scanner)
    1681  strswitch(NameOfWave(scanner))
    1682  case "Eph":
    1683  ax[%$kScanDimLabel] = "photon energy"
    1684  un[%$kScanDimLabel] = "eV"
    1685  break
    1686  case "ManipulatorX":
    1687  case "ManipulatorY":
    1688  case "ManipulatorZ":
    1689  case "FocusYTrans":
    1690  case "FocusZTrans":
    1691  case "RefocusYTrans":
    1692  case "RefocusZTrans":
    1693  case "ExitSlitY":
    1694  un[%$kScanDimLabel] = "mm"
    1695  break
    1696  case "ExitSlit":
    1697  un[%$kScanDimLabel] = "m"
    1698  break
    1699  case "ManipulatorTheta":
    1700  case "ManipulatorTilt":
    1701  case "ManipulatorPhi":
    1702  un[%$kScanDimLabel] = ""
    1703  break
    1704  case "FocusXRot":
    1705  case "FocusYRot":
    1706  case "FocusZRot":
    1707  case "RefocusXRot":
    1708  case "RefocusYRot":
    1709  case "RefocusZRot":
    1710  un[%$kScanDimLabel] = "mrad"
    1711  break
    1712  endswitch
    1713  endif
    1714  endif
    1715 };
    1716 
    1750 variable ps_scale_dataset_2(wave data, wave ax, wave lo, wave hi, wave un){
    1751  wave data
    1752  wave /t ax
    1753  wave lo
    1754  wave hi
    1755  wave /t un
    1756 
    1757  string sdim
    1758  sdim = GetDimLabel(data, 0, -1)
    1759  if (strlen(sdim))
    1760  setscale /i x lo[%$sdim], hi[%$sdim], un[%$sdim], data
    1761  Note data, "AxisLabelX=" + ax[%$sdim]
    1762  endif
    1763 
    1764  sdim = GetDimLabel(data, 1, -1)
    1765  if (strlen(sdim))
    1766  setscale /i y lo[%$sdim], hi[%$sdim], un[%$sdim], data
    1767  Note data, "AxisLabelY=" + ax[%$sdim]
    1768  endif
    1769 
    1770  sdim = GetDimLabel(data, 2, -1)
    1771  if (strlen(sdim))
    1772  setscale /i z lo[%$sdim], hi[%$sdim], un[%$sdim], data
    1773  Note data, "AxisLabelZ=" + ax[%$sdim]
    1774  endif
    1775 
    1776  string data_unit = un[%$kDataDimLabel]
    1777  string data_label = ax[%$kDataDimLabel]
    1778  if (cmpstr(data_unit, "arb.") == 0)
    1779  strswitch(NameOfWave(data))
    1780  case "ScientaImage":
    1781  case "ImageAngleDistribution":
    1782  case "ScientaAngleDistribution":
    1783  case "ScientaSpectrum":
    1784  case "ImageEnergyDistribution":
    1785  case "ScientaEnergyDistribution":
    1786  data *= kDetectorSensitivity
    1787  data_unit = "counts"
    1788  data_label = "intensity"
    1789  break
    1790  case "SampleCurrent":
    1791  case "RefCurrent":
    1792  case "AuxCurrent":
    1793  data_unit = "A"
    1794  data_label = "current"
    1795  break
    1796  case "MachineCurrent":
    1797  data_unit = "mA"
    1798  data_label = "current"
    1799  break
    1800  endswitch
    1801  endif
    1802  setscale d 0, 0, data_unit, data
    1803  Note data, "AxisLabelD=" + data_label
    1804  Note data, "Dataset=" + NameOfWave(data)
    1805 };
    1806 
    1846 string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress = defaultValue){
    1847  string ANickName
    1848  string APathName
    1849  string AFileName
    1850  funcref adh5_default_reduction reduction_func
    1851  string reduction_param
    1852  variable progress
    1853 
    1854  if (ParamIsDefault(progress))
    1855  progress = 1
    1856  endif
    1857 
    1858  dfref saveDF = GetDataFolderDFR()
    1859 
    1860  // performance monitoring
    1861  variable timerRefNum
    1862  variable /g psh5_perf_secs
    1863  timerRefNum = startMSTimer
    1864 
    1865  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
    1866  string wavenames = ""
    1867  if (fileID)
    1868  dfref fileDF = GetDataFolderDFR()
    1869  svar s_filepath
    1870  svar s_scanpaths
    1871  AFileName = s_filepath
    1872  print "loading " + s_filepath + "\r"
    1873 
    1874  variable ig = 0
    1875  variable ng = ItemsInList(s_scanpaths)
    1876  string scanpath
    1877  string folder
    1878  string positioners
    1879  string positioner
    1880  string positionerpath
    1881 
    1882  scanpath = StringFromList(ig, s_scanpaths)
    1883  folder = ReplaceString("/", scanpath, "")
    1884  folder = ReplaceString(" ", folder, "")
    1885  folder = CleanupName(folder, 0)
    1886  setdatafolder fileDF
    1887  newdatafolder /s /o $folder
    1888  dfref dataDF = GetDataFolderDFR()
    1889  positioners = psh5_load_scan_meta(fileID, scanpath)
    1890  newdatafolder /s /o attr
    1891  killwaves /a/z
    1892  psh5_load_scan_attrs(fileID, scanpath)
    1893  setdatafolder dataDF
    1894  wave /t /z ScanWritables
    1895  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    1896  positioner = ScanWritables[0]
    1897  if (strlen(positioner) > 0)
    1898  positionerpath = scanpath + "/" + positioner
    1899  positionerpath = ReplaceString("//", positionerpath, "/")
    1900  HDF5LoadData /O /Q /Z fileID, positionerpath
    1901  endif
    1902  endif
    1903 
    1904  setdatafolder dataDF
    1905  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
    1906  string dataset = select_dataset(datasets, "ScientaImage")
    1907  wavenames = psh5_load_dataset_reduced(fileID, scanpath, dataset, reduction_func, reduction_param, progress=progress)
    1908 
    1909  psh5_close_file(fileID)
    1910  endif
    1911 
    1912  if (timerRefNum >= 0)
    1913  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
    1914  endif
    1915 
    1916  setdatafolder saveDF
    1917  return wavenames
    1918 };
    1919 
    1920 
    1970 string psh5_load_dataset_reduced(variable fileID, string scanpath, string datasetname, funcref reduction_func, string reduction_param, variable progress = defaultValue, variable nthreads = defaultValue){
    1971  variable fileID
    1972  string scanpath
    1973  string datasetname
    1974  funcref adh5_default_reduction reduction_func
    1975  string reduction_param
    1976  variable progress
    1977  variable nthreads
    1978 
    1979  if (ParamIsDefault(progress))
    1980  progress = 1
    1981  endif
    1982  if (ParamIsDefault(nthreads))
    1983  nthreads = -1
    1984  endif
    1985 
    1986  dfref base_df = GetDataFolderDFR()
    1987  variable result = 0
    1988  string datasetpath
    1989  string datawavename
    1990  string wavenames = ""
    1991 
    1992  datasetpath = scanpath + "/" + datasetname
    1993  datasetpath = ReplaceString("//", datasetpath, "/")
    1994  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    1995 
    1996  string regionname
    1997  string regionpath
    1998  if (ItemsInList(datasetname, "/") >= 2)
    1999  regionname = StringFromList(0, datasetname, "/")
    2000  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
    2001  datasetname = RemoveListItem(0, datasetname, "/")
    2002  NewDataFolder /o/s $regionname
    2003  else
    2004  regionname = ""
    2005  regionpath = scanpath
    2006  endif
    2007 
    2008  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    2009  InitHDF5DataInfo(di)
    2010  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    2011  if (err != 0)
    2012  print "error accessing detector/data"
    2013  result = -1
    2014  return wavenames
    2015  endif
    2016  if (di.ndims < 2)
    2017  print "error: rank of dataset < 2"
    2018  result = -2
    2019  return wavenames
    2020  else if (di.ndims < 3)
    2021  progress = 0
    2022  endif
    2023 
    2024  variable idx, idy, idz, idt
    2025  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
    2026  if (transpose)
    2027  idx = 1
    2028  idy = 0
    2029  else
    2030  idx = 0
    2031  idy = 1
    2032  endif
    2033  idz = 2
    2034  idt = 3
    2035 
    2036  variable nx, ny, nz, nt, nzt
    2037  nx = di.dims[idx]
    2038  ny = di.dims[idy]
    2039  nz = di.dims[idz]
    2040  nt = di.dims[idt]
    2041  // adjust singleton dimensions
    2042  nz = max(nz, 1)
    2043  nt = max(nt, 1)
    2044  nzt = nz * nt
    2045 
    2046  // load data image by image
    2047  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    2048  wave slab
    2049  slab[][%Start] = 0
    2050  slab[][%Stride] = 1
    2051  slab[][%Count] = 1
    2052  slab[][%Block] = 1
    2053  slab[idx][%Block] = nx
    2054  slab[idy][%Block] = ny
    2055 
    2056  // set up multi threading
    2057  if (nthreads < 0)
    2058  nthreads = ThreadProcessorCount
    2059  endif
    2060  if (nthreads > 0)
    2061  variable threadGroupID = ThreadGroupCreate(nthreads)
    2062  variable ithread
    2063  for (ithread = 0; ithread < nthreads; ithread += 1)
    2064  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
    2065  endfor
    2066  else
    2067  make /n=(nzt) /df /free processing_folders
    2068  endif
    2069 
    2070  if (progress)
    2071  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
    2072  endif
    2073 
    2074  // create a template wave with the correct scales and labels
    2075  make /n=(nx,ny) /d /o $datawavename
    2076  wave template = $datawavename
    2077  ps_set_dimlabels2(template, datawavename)
    2078  ps_scale_dataset(template)
    2079 
    2080  variable iz, it, izt
    2081  string dfname
    2082  izt = 0
    2083  for (iz = 0; iz < nz; iz += 1)
    2084  for (it = 0; it < nt; it += 1)
    2085  // load hyperslab
    2086  slab[idz][%Start] = iz
    2087  slab[idt][%Start] = it
    2088  dfname = "processing_" + num2str(izt)
    2089  newdatafolder /s $dfname
    2090  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    2091 
    2092  // send to processing queue
    2093  duplicate template, image
    2094  variable /g r_index = iz
    2095  variable /g s_index = it
    2096  string /g func_param = reduction_param
    2097 
    2098  if (nthreads > 0)
    2099  WaveClear image
    2100  ThreadGroupPutDF threadGroupID, :
    2101  else
    2102  processing_folders[izt] = GetDataFolderDFR()
    2103  make /n=1/d profile1, profile2
    2104  wave slabdata
    2105  variable /g func_result
    2106  func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
    2107  WaveClear slabdata, image, profile1, profile2
    2108  setdatafolder ::
    2109  endif
    2110 
    2111  izt += 1
    2112  // progress window
    2113  if (progress)
    2114  if (update_progress_panel(izt))
    2115  print "user abort"
    2116  result = -4
    2117  break
    2118  endif
    2119  endif
    2120  endfor
    2121  endfor
    2122 
    2123  killwaves /z slab, slabdata, template
    2124  if (progress)
    2125  update_progress_panel(0, message="Processing data (step 2 of 2)...")
    2126  endif
    2127 
    2128  dfref dfr
    2129  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
    2130  if (nthreads > 0)
    2131  do
    2132  if (progress)
    2133  if (update_progress_panel(izt))
    2134  print "user abort"
    2135  result = -4
    2136  break
    2137  endif
    2138  endif
    2139  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
    2140  if (DatafolderRefStatus(dfr) != 0)
    2141  break
    2142  endif
    2143  while (1)
    2144  else
    2145  if (progress)
    2146  if (update_progress_panel(izt))
    2147  print "user abort"
    2148  result = -4
    2149  break
    2150  endif
    2151  endif
    2152  dfr = processing_folders[izt]
    2153  endif
    2154 
    2155  if (result != 0)
    2156  break
    2157  endif
    2158 
    2159  nvar rr = dfr:r_index
    2160  nvar ss = dfr:s_index
    2161  nvar func_result = dfr:func_result
    2162  wave profile1 = dfr:profile1
    2163  wave profile2 = dfr:profile2
    2164 
    2165  if (func_result == 0)
    2166  if (izt == 0)
    2167  make /n=(dimsize(profile1, 0), nz, nt) /d /o ReducedData1
    2168  make /n=(dimsize(profile2, 0), nz, nt) /d /o ReducedData2
    2169  setdimlabel 0, -1, $getdimlabel(profile1, 0, -1), ReducedData1
    2170  setdimlabel 0, -1, $getdimlabel(profile2, 0, -1), ReducedData2
    2171  setdimlabel 1, -1, $kScanDimLabel, ReducedData1
    2172  setdimlabel 1, -1, $kScanDimLabel, ReducedData2
    2173  ps_scale_dataset(ReducedData1)
    2174  ps_scale_dataset(ReducedData2)
    2175  setscale /p x dimoffset(profile1, 0), dimdelta(profile1, 0), waveunits(profile1, 0), ReducedData1
    2176  setscale /p x dimoffset(profile2, 0), dimdelta(profile2, 0), waveunits(profile2, 0), ReducedData2
    2177  setscale d 0, 0, waveunits(profile1, -1), ReducedData1
    2178  setscale d 0, 0, waveunits(profile2, -1), ReducedData2
    2179  endif
    2180  ReducedData1[][rr][ss] = profile1[p]
    2181  ReducedData2[][rr][ss] = profile2[p]
    2182  else
    2183  print "error during data reduction."
    2184  result = -3
    2185  break
    2186  endif
    2187  endfor
    2188 
    2189  if (nthreads > 0)
    2190  variable tstatus = ThreadGroupRelease(threadGroupID)
    2191  if (tstatus == -2)
    2192  print "error: thread did not terminate properly."
    2193  result = -5
    2194  endif
    2195  else
    2196  for (izt = 0; izt < nzt; izt += 1)
    2197  KillDataFolder /Z processing_folders[izt]
    2198  endfor
    2199  endif
    2200 
    2201  if (result == 0)
    2202  if (nz == 1)
    2203  redimension /n=(-1, 0, 0) ReducedData1
    2204  redimension /n=(-1, 0, 0) ReducedData2
    2205  else if (nt == 1)
    2206  redimension /n=(-1, nz, 0) ReducedData1
    2207  redimension /n=(-1, nz, 0) ReducedData2
    2208  endif
    2209  wavenames = "ReducedData1;ReducedData2;"
    2210  endif
    2211  if (progress)
    2213  endif
    2214 
    2215  setdatafolder base_df
    2216  return wavenames
    2217 };
    2218 
    2219 threadsafe static variable reduce_slab_worker(funcref reduction_func){
    2220  funcref adh5_default_reduction reduction_func
    2221  do
    2222  // wait for job from main thread
    2223  do
    2224  dfref dfr = ThreadGroupGetDFR(0, 1000)
    2225  if (DataFolderRefStatus(dfr) == 0)
    2226  if (GetRTError(2))
    2227  return 0// no more jobs
    2228  endif
    2229  else
    2230  break
    2231  endif
    2232  while (1)
    2233 
    2234  // get input data
    2235  wave slabdata = dfr:slabdata
    2236  wave image = dfr:image
    2237  svar func_param = dfr:func_param
    2238  nvar rr = dfr:r_index
    2239  nvar ss = dfr:s_index
    2240 
    2241  // do the work
    2242  newdatafolder /s outDF
    2243  make /n=1/d profile1, profile2
    2244  variable /g r_index = rr
    2245  variable /g s_index = ss
    2246  variable /g func_result
    2247  func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
    2248 
    2249  // send output to queue and clean up
    2250  WaveClear slabdata, image, profile1, profile2
    2251  ThreadGroupPutDF 0, :
    2252  KillDataFolder dfr
    2253  while (1)
    2254 
    2255  return 0
    2256 };
    2257 
    2258 threadsafe static variable reduce_slab_image(wave slabdata, wave image, wave profile1, wave profile2, funcref reduction_func, string reduction_param){
    2259  wave slabdata
    2260  wave image
    2261  wave profile1
    2262  wave profile2
    2263  funcref adh5_default_reduction reduction_func
    2264  string reduction_param
    2265 
    2266  // the multiplication by detector sensitivity assumes that we are loading a ScientaImage.
    2267  image = slabdata[q][p][0][0] * kDetectorSensitivity
    2268 
    2269  return reduction_func(image, profile1, profile2, reduction_param)
    2270 };
    2271 
    2286 string psh5_load_info(string APathName, string AFileName){
    2287  string APathName
    2288  string AFileName
    2289 
    2290  dfref saveDF = GetDataFolderDFR()
    2291  dfref fileDF = NewFreeDataFolder()
    2292  setdatafolder fileDF
    2293 
    2294  variable fileID
    2295  string filepath
    2296  string scanpaths
    2297  variable nscans
    2298  variable iscan
    2299  string scanpath
    2300  string info = ""
    2301 
    2302  HDF5OpenFile /P=$APathName /R fileID as AFileName
    2303  if (v_flag == 0)
    2304  filepath = s_path + s_filename
    2305  scanpaths = psh5_list_scans(fileID)
    2306  nscans = ItemsInList(scanpaths)
    2307  for (iscan = 0; iscan < nscans; iscan += 1)
    2308  scanpath = StringFromList(iscan, scanpaths)
    2309  info = info + scanpath + "\r"
    2310  info = info + psh5_load_scan_info(fileID, scanpath)
    2311  endfor
    2312  HDF5CloseFile fileID
    2313  endif
    2314 
    2315  setdatafolder saveDF
    2316  return info
    2317 };
    2318 
    2333 string psh5_load_scan_info(variable fileID, string scanpath){
    2334  variable fileID
    2335  string scanpath
    2336 
    2337  string info = ""
    2338  string positions = ""
    2339  string positioners = ""
    2340  string readables = ""
    2341  string detectors = ""
    2342  string regions = ""
    2343 
    2344  psh5_load_scan_meta(fileID, scanpath)
    2345 
    2346  wave /z ScanDimensions
    2347  wave /t /z ScanWritables
    2348  wave /t /z ScanReadables
    2349  wave /z ScanSteps
    2350 
    2351  if (WaveExists(ScanSteps) && (numpnts(ScanSteps) >= 1))
    2352  ScanSteps += 1
    2353  positions = "positions = (" + wave2list(ScanSteps, "%u", ",") + ")"
    2354  info = AddListItem(positions, info, "\r", inf)
    2355  endif
    2356  if (WaveExists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    2357  positioners = "positioners = " + twave2list(ScanWritables, ",")
    2358  info = AddListItem(positioners, info, "\r", inf)
    2359  endif
    2360 
    2361  variable i, m, n
    2362  string s
    2363  if (WaveExists(ScanReadables) && (numpnts(ScanReadables) >= 1))
    2364  readables = twave2list(ScanReadables, ",")
    2365  n = ItemsInList(readables, ",")
    2366  for (i = 0; i < n; i += 1)
    2367  s = StringFromList(i, readables, ",")
    2368  m = ItemsInList(s, "/")
    2369  if (m > 1)
    2370  s = StringFromList(m - 1, s, "/")
    2371  endif
    2372  if (WhichListItem(s, detectors, ",") < 0)
    2373  detectors = AddListItem(s, detectors, ",", inf)
    2374  endif
    2375  endfor
    2376  detectors = "detectors = " + detectors
    2377  info = AddListItem(detectors, info, "\r", inf)
    2378  endif
    2379 
    2380  regions = psh5_list_scan_regions(fileID, scanpath)
    2381  if (strlen(regions) > 0)
    2382  regions = "regions = " + regions
    2383  info = AddListItem(regions, info, "\r", inf)
    2384  endif
    2385 
    2386  return info
    2387 };
    2388 
    2392 static string twave2list(wave wt, string sep){
    2393  wave /t wt
    2394  string sep
    2395 
    2396  string list = ""
    2397  variable n = numpnts(wt)
    2398  variable i
    2399  for (i = 0; i < n; i += 1)
    2400  list = AddListItem(wt[i], list, sep, inf)
    2401  endfor
    2402 
    2403  return list
    2404 };
    2405 
    2409 static string wave2list(wave w, string format, string sep){
    2410  wave w
    2411  string format
    2412  string sep
    2413 
    2414  string list = ""
    2415  variable n = numpnts(w)
    2416  variable i
    2417  string s
    2418  for (i = 0; i < n; i += 1)
    2419  sprintf s, format, w[i]
    2420  list = AddListItem(s, list, sep, inf)
    2421  endfor
    2422 
    2423  return list
    2424 };
    2425 
    string psh5_list_scan_regions(variable fileID, string scanpath)
    list regions of a PShell scan group.
    -
    const string kEnergyDimLabel
    Dimension label for the energy dispersive dimension of multi-dimensional datasets.
    -
    string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress=defaultValue)
    load and reduce the ScientaImage dataset of the first scan of a PShell data file. ...
    -
    string psh5_load_dataset_reduced(variable fileID, string scanpath, string datasetname, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
    load a reduced dataset from the open PShell HDF5 file.
    +Go to the documentation of this file.
    1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
    2 #pragma IgorVersion = 6.36
    3 #pragma ModuleName = PearlPShellImport
    4 #include <HDF5 Browser>
    5 #include "pearl-gui-tools"
    6 #include "pearl-area-import"
    7 
    8 // copyright (c) 2013-18 Paul Scherrer Institut
    9 //
    10 // Licensed under the Apache License, Version 2.0 (the "License");
    11 // you may not use this file except in compliance with the License.
    12 // You may obtain a copy of the License at
    13 // http:///www.apache.org/licenses/LICENSE-2.0
    14 
    57 
    62 
    64 const string kEnergyDimLabel = "energy";
    65 
    67 const string kAngleDimLabel = "angle";
    68 
    70 const string kScanDimLabel = "scan";
    71 
    74 const string kDataDimLabel = "data";
    75 
    77 const string kPreviewDatasets = "ScientaImage;ScientaSpectrum;ImageAngleDistribution;ImageEnergyDistribution;Counts;SampleCurrent;";
    78 
    80 const string kScientaScalingDatasets = "LensMode;ScientaChannelBegin;ScientaChannelEnd;ScientaSliceBegin;ScientaSliceEnd;";
    81 
    83 const string kTransposedDatasets = "ScientaImage;";
    84 
    86 const variable kDetectorSensitivity = 4;
    87 
    109 variable psh5_open_file(string ANickName, string APathName, string AFileName){
    110  string ANickName
    111  string APathName
    112  string AFileName
    113 
    114  setdatafolder root:
    115  newdatafolder /s /o $("root:" + ANickName)
    116  dfref fileDF = GetDataFolderDFR()
    117 
    118  variable fileID
    119  HDF5OpenFile /P=$APathName /R fileID as AFileName
    120  if (v_flag == 0)
    121  string /g s_filepath
    122  string /g s_scanpaths
    123  s_filepath = s_path + s_filename
    124  s_scanpaths = psh5_list_scans(fileID)
    125  else
    126  fileID = 0
    127  endif
    128 
    129  return fileID
    130 };
    131 
    139 variable psh5_close_file(variable fileID){
    140  variable fileID
    141 
    142  HDF5CloseFile fileID
    143 };
    144 
    169 string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
    170  string ANickName
    171  string APathName
    172  string AFileName
    173  variable load_data
    174  variable load_attr
    175 
    176  if (ParamIsDefault(load_data))
    177  load_data = 1
    178  endif
    179  if (ParamIsDefault(load_attr))
    180  load_attr = 1
    181  endif
    182 
    183  dfref saveDF = GetDataFolderDFR()
    184 
    185  // performance monitoring
    186  variable timerRefNum
    187  variable /g psh5_perf_secs
    188  timerRefNum = startMSTimer
    189 
    190  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
    191  if (fileID)
    192  dfref fileDF = GetDataFolderDFR()
    193  svar s_filepath
    194  svar s_scanpaths
    195  AFileName = s_filepath
    196  print "loading " + s_filepath + "\r"
    197 
    198  variable ig
    199  variable ng = ItemsInList(s_scanpaths, ";")
    200  string sg
    201  string folder
    202 
    203  for (ig = 0; ig < ng; ig += 1)
    204  sg = StringFromList(ig, s_scanpaths, ";")
    205  folder = ReplaceString("/", sg, "")
    206  folder = ReplaceString(" ", folder, "")
    207  folder = CleanupName(folder, 0)
    208  setdatafolder fileDF
    209  newdatafolder /s /o $folder
    210  psh5_load_scan_complete(fileID, sg, load_data=load_data, load_attr=load_attr)
    211  endfor
    212 
    213  psh5_close_file(fileID)
    214  else
    215  AFileName = ""
    216  endif
    217 
    218  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
    219 
    220  setdatafolder saveDF
    221  return AFileName
    222 };
    223 
    250 string psh5_load_preview(string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue, string pref_scans = defaultValue, string pref_datasets = defaultValue){
    251  string APathName
    252  string AFileName
    253  variable load_data
    254  variable load_attr
    255  string pref_scans
    256  string pref_datasets
    257 
    258  if (ParamIsDefault(load_data))
    259  load_data = 1
    260  endif
    261  if (ParamIsDefault(load_attr))
    262  load_attr = 1
    263  endif
    264  if (ParamIsDefault(pref_scans))
    265  pref_scans = "*scan1*;"
    266  endif
    267  if (ParamIsDefault(pref_datasets))
    268  pref_datasets = ""
    269  endif
    270 
    271  dfref saveDF = GetDataFolderDFR()
    272 
    273  variable fileID
    274  string scanpaths = ""
    275  string dataname = ""
    276 
    277  // performance monitoring
    278  variable timerRefNum
    279  variable /g adh5_perf_secs
    280  timerRefNum = startMSTimer
    281 
    282  HDF5OpenFile /P=$APathName /R /Z fileID as AFileName
    283  if (v_flag == 0)
    284  AFileName = s_path + s_filename
    285  dfref fileDF = GetDataFolderDFR()
    286 
    287  scanpaths = psh5_list_scans(fileID)
    288  variable ng = ItemsInList(scanpaths)
    289  variable ig
    290  string sg
    291  variable np = ItemsInList(pref_scans)
    292  variable ip
    293  string sp
    294  variable found = 0
    295  if (ng > 0)
    296  for (ip = 0; ip < np; ip += 1)
    297  for (ig = 0; ig < ng; ig += 1)
    298  sg = StringFromList(ig, scanpaths)
    299  sp = StringFromList(ip, pref_scans)
    300  if (StringMatch(sg, sp))
    301  found = 1
    302  break
    303  endif
    304  endfor
    305  if (found)
    306  break
    307  endif
    308  endfor
    309  if (!found)
    310  ig = 0
    311  endif
    312  sg = StringFromList(ig, scanpaths)
    313 
    314  if (load_attr)
    315  setdatafolder fileDF
    316  newdatafolder /o/s attr
    317  killwaves /a/z
    318  psh5_load_scan_attrs(fileID, sg)
    319  endif
    320 
    321  setdatafolder fileDF
    322  dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr, pref_datasets=pref_datasets)
    323  else
    324  print "no scans found in file " + AFileName
    325  endif
    326 
    327  HDF5CloseFile fileID
    328  endif
    329 
    330  if (timerRefNum >= 0)
    331  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
    332  endif
    333 
    334  setdatafolder saveDF
    335  return dataname
    336 };
    337 
    360 string psh5_load_scan_complete(variable fileID, string scanpath, variable load_data = defaultValue, variable load_attr = defaultValue){
    361  variable fileID
    362  string scanpath
    363  variable load_data
    364  variable load_attr
    365 
    366  if (ParamIsDefault(load_data))
    367  load_data = 1
    368  endif
    369  if (ParamIsDefault(load_attr))
    370  load_attr = 1
    371  endif
    372 
    373  dfref saveDF = GetDataFolderDFR()
    374 
    375  dfref dataDF = GetDataFolderDFR()
    376  string wavenames
    377  string attrnames
    378  psh5_load_scan_meta(fileID, scanpath)
    379  if (load_attr)
    380  newdatafolder /s /o attr
    381  attrnames = psh5_load_scan_attrs(fileID, scanpath)
    382  endif
    383  if (load_data)
    384  setdatafolder dataDF
    385  wavenames = psh5_load_scan_data(fileID, scanpath)
    386  endif
    387  if (load_data && load_attr)
    388  setdatafolder dataDF
    390  endif
    391 
    392  setdatafolder saveDF
    393  return wavenames
    394 };
    395 
    404 string psh5_list_scans(variable fileID){
    405  variable fileID
    406 
    407  HDF5ListGroup /F /TYPE=1 fileID, "/"
    408 
    409  variable ig
    410  variable ng = ItemsInList(S_HDF5ListGroup, ";")
    411  string sg
    412  string scans = ""
    413 
    414  for (ig = 0; ig < ng; ig += 1)
    415  sg = StringFromList(ig, S_HDF5ListGroup, ";")
    416  if (cmpstr(sg[1,4], "scan") == 0)
    417  scans = AddListItem(sg, scans, ";", inf)
    418  endif
    419  endfor
    420 
    421  return scans
    422 };
    423 
    439 string psh5_list_scan_datasets(variable fileID, string scanpath, variable include_regions = defaultValue){
    440  variable fileID
    441  string scanpath
    442  variable include_regions
    443 
    444  if (ParamIsDefault(include_regions))
    445  include_regions = 0
    446  endif
    447  string result
    448 
    449  HDF5ListGroup /TYPE=2 /Z fileID, scanpath
    450  result = S_HDF5ListGroup
    451 
    452  if (include_regions)
    453  HDF5ListGroup /R /TYPE=2 /Z fileID, scanpath
    454  variable n = ItemsInList(S_HDF5ListGroup)
    455  variable i
    456  string ds
    457  string region_datasets
    458  for (i = 0; i < n; i += 1)
    459  ds = StringFromList(i, S_HDF5ListGroup)
    460  if (StringMatch(ds, "region*/*"))
    461  //region_datasets = psh5_list_scan_datasets(fileID, ReplaceString("//", scanpath + "/" + region, "/"), include_regions=0)
    462  result = AddListItem(ds, result, ";", inf)
    463  endif
    464  endfor
    465  endif
    466 
    467  return result
    468 };
    469 
    480 string psh5_list_scan_regions(variable fileID, string scanpath){
    481  variable fileID
    482  string scanpath
    483 
    484  HDF5ListGroup /TYPE=1 /Z fileID, scanpath
    485  variable n = ItemsInList(S_HDF5ListGroup)
    486  variable i
    487  string result = ""
    488  string s
    489  for (i = 0; i < n; i += 1)
    490  s = StringFromList(i, S_HDF5ListGroup)
    491  if (StringMatch(s, "region*"))
    492  result = AddListItem(s, result, ";", inf)
    493  endif
    494  endfor
    495 
    496  return result
    497 };
    498 
    513 string psh5_load_scan_data(variable fileID, string scanpath){
    514  variable fileID
    515  string scanpath
    516 
    517  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
    518  variable nds = ItemsInList(datasets)
    519  variable ids
    520  string sds
    521  string sw
    522  string wavenames = ""
    523  for (ids = 0; ids < nds; ids += 1)
    524  sds = StringFromList(ids, datasets)
    525  sw = psh5_load_dataset(fileID, scanpath, sds, set_scale=0)
    526  wavenames = AddListItem(sw, wavenames, ";", inf)
    527  endfor
    528 
    529  return wavenames
    530 };
    531 
    553 string psh5_load_scan_attrs(variable fileID, string scanpath, variable attr_sets = defaultValue){
    554  variable fileID
    555  string scanpath
    556  variable attr_sets
    557 
    558  if (ParamIsDefault(attr_sets))
    559  attr_sets = 1
    560  endif
    561 
    562  string attr_path = ReplaceString("//", scanpath + "/attrs", "/")
    563  string attr_list = ""
    564  if (attr_sets & 1)
    565  HDF5ListGroup /TYPE=2 /Z fileID, attr_path
    566  if (!v_flag)
    567  attr_list = S_HDF5ListGroup
    568  endif
    569  endif
    570 
    571  variable ids
    572  variable nds
    573  string sds
    574 
    575  if (attr_sets & 2)
    576  nds = ItemsInList(kScientaScalingDatasets, ";")
    577  for (ids = 0; ids < nds; ids += 1)
    578  sds = StringFromList(ids, kScientaScalingDatasets)
    579  if (WhichListItem(sds, attr_list) < 0)
    580  attr_list = AddListItem(sds, attr_list, ";", inf)
    581  endif
    582  endfor
    583  endif
    584 
    585  nds = ItemsInList(attr_list, ";")
    586  string wavenames = ""
    587  for (ids = 0; ids < nds; ids += 1)
    588  sds = StringFromList(ids, attr_list, ";")
    589  HDF5LoadData /O /Q /Z fileID, attr_path + "/" + sds
    590  if (!v_flag)
    591  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    592  endif
    593  endfor
    594  wavenames = ReplaceString(";;", wavenames, ";")
    595 
    596  return wavenames
    597 };
    598 
    621 string psh5_load_scan_meta(variable fileID, string scanpath){
    622  variable fileID
    623  string scanpath
    624  string wavenames = ""
    625 
    626  HDF5LoadData /O /Q /Z /A="Dimensions" /N=ScanDimensions /TYPE=1 fileID, scanpath
    627  if (!v_flag)
    628  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    629  else
    630  make /n=1 /o ScanDimensions
    631  ScanDimensions = 0
    632  wavenames = AddListItem("ScanDimensions", wavenames, ";", inf)
    633  endif
    634  HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 fileID, scanpath
    635  if (!v_flag)
    636  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    637  else
    638  make /n=1 /o /t ScanReadables
    639  ScanReadables[0] = "ScientaSpectrum"
    640  wavenames = AddListItem("ScanReadables", wavenames, ";", inf)
    641  endif
    642  HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 fileID, scanpath
    643  if (!v_flag)
    644  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    645  endif
    646  HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 fileID, scanpath
    647  if (!v_flag)
    648  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
    649  endif
    650  wavenames = ReplaceString(";;", wavenames, ";")
    651 
    652  return wavenames
    653 };
    654 
    688 string psh5_load_dataset(variable fileID, string scanpath, string datasetname, variable set_scale = defaultValue){
    689  variable fileID
    690  string scanpath
    691  string datasetname
    692  variable set_scale
    693 
    694  if (ParamIsDefault(set_scale))
    695  set_scale = 1
    696  endif
    697 
    698  dfref base_df = GetDataFolderDFR()
    699 
    700  string datasetpath
    701  datasetpath = scanpath + "/" + datasetname
    702  datasetpath = ReplaceString("//", datasetpath, "/")
    703 
    704  string regionname
    705  string regionpath
    706  if (ItemsInList(datasetname, "/") >= 2)
    707  regionname = StringFromList(0, datasetname, "/")
    708  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
    709  datasetname = RemoveListItem(0, datasetname, "/")
    710  NewDataFolder /o/s $regionname
    711  else
    712  regionname = ""
    713  regionpath = scanpath
    714  endif
    715 
    716  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    717  InitHDF5DataInfo(di)
    718  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    719  if (err != 0)
    720  print "error accessing detector/data"
    721  return ""
    722  endif
    723 
    724  string dataname
    725  if (di.ndims < 2)
    726  HDF5LoadData /O /Q /Z fileID, datasetpath
    727  dataname = StringFromList(0, S_waveNames)
    728  else
    729  dataname = psh5_load_dataset_slabs(fileID, regionpath, datasetname)
    730  endif
    731 
    732  wave /z data = $dataname
    733  if (waveexists(data))
    734  psh5_load_dataset_meta(fileID, regionpath, datasetname, data)
    735  ps_set_dimlabels(data)
    736  if (set_scale)
    737  ps_scale_dataset(data)
    738  endif
    739  else
    740  dataname = ""
    741  endif
    742 
    743  setdatafolder base_df
    744  return dataname
    745 };
    746 
    760 static string select_dataset(string file_datasets, string pref_datasets){
    761  string file_datasets
    762  string pref_datasets
    763 
    764  variable index
    765  variable nds = ItemsInList(file_datasets)
    766  variable ids
    767  string sds = ""
    768  string mds = ""
    769  variable np = ItemsInList(pref_datasets)
    770  variable ip
    771  string sp
    772  variable found = 0
    773  if (nds > 0)
    774  for (ip = 0; ip < np; ip += 1)
    775  for (ids = 0; ids < nds; ids += 1)
    776  sds = StringFromList(ids, file_datasets)
    777  index = ItemsInList(sds, "/") - 1
    778  mds = StringFromList(index, sds, "/")
    779  sp = StringFromList(ip, pref_datasets)
    780  if (StringMatch(mds, sp))
    781  found = 1
    782  break
    783  endif
    784  endfor
    785  if (found)
    786  break
    787  endif
    788  endfor
    789  if (!found)
    790  ids = 0
    791  sds = StringFromList(ids, file_datasets)
    792  endif
    793  endif
    794 
    795  return sds
    796 };
    797 
    822 string psh5_load_scan_preview(variable fileID, string scanpath, variable set_scale = defaultValue, string pref_datasets = defaultValue){
    823  variable fileID
    824  string scanpath
    825  variable set_scale
    826  string pref_datasets
    827 
    828  if (ParamIsDefault(set_scale))
    829  set_scale = 1
    830  endif
    831  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
    832  pref_datasets = kPreviewDatasets
    833  endif
    834 
    835  dfref saveDF = GetDataFolderDFR()
    836  dfref dataDF = saveDF
    837 
    838  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
    839  string datasetname = select_dataset(datasets, pref_datasets)
    840  string datasetpath
    841  datasetpath = scanpath + "/" + datasetname
    842  datasetpath = ReplaceString("//", datasetpath, "/")
    843 
    844  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    845  InitHDF5DataInfo(di)
    846  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    847  if (err != 0)
    848  print "error accessing detector/data"
    849  return ""
    850  endif
    851 
    852  string dataname
    853  if (di.ndims < 2)
    854  HDF5LoadData /O /Q /Z fileID, datasetpath
    855  dataname = StringFromList(0, S_waveNames)
    856  wave /z data = $dataname
    857  if (waveexists(data))
    858  ps_set_dimlabels(data)
    859  endif
    860  else
    861  variable dim2start = 0
    862  variable dim2count = 1
    863  variable dim3start = 0
    864  variable dim3count = 1
    865  if (di.ndims >= 3)
    866  dim2start = floor(di.dims[2] / 2)
    867  dim2count = 1
    868  endif
    869  if (di.ndims >= 4)
    870  dim3start = floor(di.dims[3] / 2)
    871  dim3count = 1
    872  endif
    873 
    874  dataname = psh5_load_dataset_slab(fileID, scanpath, datasetname, dim2start, dim2count, dim3start, dim3count)
    875  endif
    876 
    877  wave /z data = $dataname
    878  if (waveexists(data))
    879  if (set_scale)
    880  setdatafolder dataDF
    881  string positioners
    882  string positioner
    883  string positionerpath
    884  positioners = psh5_load_scan_meta(fileID, scanpath)
    885  wave /t /z ScanWritables
    886  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    887  positioner = ScanWritables[0]
    888  if (strlen(positioner) > 0)
    889  positionerpath = scanpath + "/" + positioner
    890  positionerpath = ReplaceString("//", positionerpath, "/")
    891  HDF5LoadData /O /Q /Z fileID, positionerpath
    892  endif
    893  endif
    894 
    895  setdatafolder dataDF
    896  newdatafolder /o/s attr
    897  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
    898  setdatafolder dataDF
    899  ps_scale_dataset(data)
    900  endif
    901  else
    902  dataname = ""
    903  endif
    904 
    905  return dataname
    906 };
    907 
    935 string psh5_load_scan_section(variable fileID, string scanpath, variable dim, variable set_scale = defaultValue, string pref_datasets = defaultValue){
    936  variable fileID
    937  string scanpath
    938  variable dim
    939  variable set_scale
    940  string pref_datasets
    941 
    942  // select first dimension (future argument)
    943  // 0 = first dimension is x axis (energy of scienta image)
    944  dim = 0
    945 
    946  if (ParamIsDefault(set_scale))
    947  set_scale = 1
    948  endif
    949  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
    950  pref_datasets = kPreviewDatasets
    951  endif
    952 
    953  dfref saveDF = GetDataFolderDFR()
    954  dfref dataDF = saveDF
    955 
    956  string datasets = psh5_list_scan_datasets(fileID, scanpath)
    957  string datasetname = select_dataset(datasets, pref_datasets)
    958  string datasetpath
    959  datasetpath = scanpath + "/" + datasetname
    960  datasetpath = ReplaceString("//", datasetpath, "/")
    961  string dataname = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    962  string destname = dataname[0,29] + num2str(dim)
    963 
    964  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    965  InitHDF5DataInfo(di)
    966  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    967  if (err != 0)
    968  print "error accessing detector/data"
    969  return ""
    970  else if (di.ndims != 3)
    971  print "error: rank of dataset != 3"
    972  return ""
    973  endif
    974 
    975  variable idx, idy, idz, idt
    976  variable transpose = WhichListItem(dataname, kTransposedDatasets) >= 0
    977  if (transpose)
    978  idx = 1
    979  idy = 0
    980  else
    981  idx = 0
    982  idy = 1
    983  endif
    984  idz = 2
    985  idt = 3
    986 
    987  variable nx, ny, nz
    988  nx = di.dims[idx]
    989  ny = di.dims[idy]
    990  nz = di.dims[idz]
    991 
    992  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    993  wave slab
    994  slab[][%Start] = 0
    995  slab[][%Stride] = 1
    996  slab[][%Count] = 1
    997  slab[][%Block] = 1
    998 
    999  if (dim == 0)
    1000  slab[idy][%Start] = floor(ny / 2)
    1001  slab[idx][%Block] = nx
    1002  make /n=(nx,nz) /o $destname
    1003  else
    1004  slab[idx][%Start] = floor(nx / 2)
    1005  slab[idy][%Block] = ny
    1006  make /n=(ny,nz) /o $destname
    1007  endif
    1008  slab[idz][%Block] = nz
    1009  wave data = $destname
    1010  data = 0
    1011 
    1012  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    1013  if (!v_flag)
    1014  wave slabdata
    1015  if (transpose)
    1016  data += slabdata[0][p][q][0]
    1017  else
    1018  data += slabdata[p][0][q][0]
    1019  endif
    1020  endif
    1021  killwaves /z slab, slabdata
    1022 
    1023  if (set_scale)
    1024  make /n=(1,1,1) /free dummy
    1025  ps_set_dimlabels2(dummy, dataname)
    1026  setdimlabel 0, -1, $GetDimLabel(dummy, dim, -1), data
    1027  setdimlabel 1, -1, $kScanDimLabel, data
    1028 
    1029  setdatafolder dataDF
    1030  string positioners
    1031  string positioner
    1032  string positionerpath
    1033  positioners = psh5_load_scan_meta(fileID, scanpath)
    1034  wave /t /z ScanWritables
    1035  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    1036  positioner = ScanWritables[0]
    1037  if (strlen(positioner) > 0)
    1038  positionerpath = scanpath + "/" + positioner
    1039  positionerpath = ReplaceString("//", positionerpath, "/")
    1040  HDF5LoadData /O /Q /Z fileID, positionerpath
    1041  endif
    1042  endif
    1043 
    1044  setdatafolder dataDF
    1045  newdatafolder /o/s attr
    1046  killwaves /a/z
    1047  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
    1048  setdatafolder dataDF
    1049  ps_scale_dataset(data)
    1050  endif
    1051 
    1052  return destname
    1053 };
    1054 
    1073 variable psh5_load_dataset_meta(variable fileID, string datapath, string datasetname, wave datawave){
    1074  variable fileID
    1075  string datapath
    1076  string datasetname
    1077  wave datawave
    1078 
    1079  dfref saveDF = GetDataFolderDFR()
    1080  SetDataFolder NewFreeDataFolder()
    1081 
    1082  string datasetpath = datapath + "/" + datasetname
    1083  datasetpath = ReplaceString("//", datasetpath, "/")
    1084  string wnote
    1085 
    1086  HDF5LoadData /O /Q /Z /A="Writable Dimension" /N=WriteDim fileID, datasetpath
    1087  if (!v_flag)
    1088  wave WriteDim
    1089  // scan dimension starts at 1
    1090  sprintf wnote, "ScanDimension=%u", WriteDim[0]
    1091  Note datawave, wnote
    1092  endif
    1093 
    1094  HDF5LoadData /O /Q /Z /A="Writable Index" /N=WriteIndex fileID, datasetpath
    1095  if (!v_flag)
    1096  wave WriteIndex
    1097  sprintf wnote, "WriteableIndex=%u", WriteIndex[0]
    1098  Note datawave, wnote
    1099  endif
    1100 
    1101  HDF5LoadData /O /Q /Z /A="Readable Index" /N=ReadIndex fileID, datasetpath
    1102  if (!v_flag)
    1103  wave ReadIndex
    1104  sprintf wnote, "ReadableIndex=%u", ReadIndex[0]
    1105  Note datawave, wnote
    1106  endif
    1107 
    1108  setdatafolder saveDF
    1109  return 0
    1110 };
    1111 
    1130 string psh5_load_dataset_slabs(variable fileID, string datapath, string datasetname, variable progress = defaultValue){
    1131  variable fileID
    1132  string datapath
    1133  string datasetname
    1134  variable progress
    1135 
    1136  if (ParamIsDefault(progress))
    1137  progress = 1
    1138  endif
    1139 
    1140  variable result = 0
    1141  string datasetpath
    1142  string datawavename
    1143  datasetpath = datapath + "/" + datasetname
    1144  datasetpath = ReplaceString("//", datasetpath, "/")
    1145  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    1146 
    1147  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    1148  InitHDF5DataInfo(di)
    1149  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    1150  if (err != 0)
    1151  print "error accessing detector/data"
    1152  return ""
    1153  endif
    1154  if (di.ndims < 2)
    1155  print "error: rank of dataset < 2"
    1156  return ""
    1157  else if (di.ndims < 3)
    1158  progress = 0
    1159  endif
    1160 
    1161  variable idx, idy, idz, idt, izt
    1162  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
    1163  if (transpose)
    1164  idx = 1
    1165  idy = 0
    1166  else
    1167  idx = 0
    1168  idy = 1
    1169  endif
    1170  idz = 2
    1171  idt = 3
    1172 
    1173  variable nx, ny, nz, nt, nzt
    1174  nx = di.dims[idx]
    1175  ny = di.dims[idy]
    1176  nz = di.dims[idz]
    1177  nt = di.dims[idt]
    1178  make /n=(nx,ny,nz,nt) /o $datawavename
    1179  wave data = $datawavename
    1180 
    1181  nz = max(nz, 1)
    1182  nt = max(nt, 1)
    1183  nzt = nz * nt
    1184  izt = 0
    1185  if (progress)
    1186  display_progress_panel("HDF5 Import", "Loading data...", nzt)
    1187  endif
    1188 
    1189  // load data image by image
    1190  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    1191  wave slab
    1192  slab[][%Start] = 0
    1193  slab[][%Stride] = 1
    1194  slab[][%Count] = 1
    1195  slab[][%Block] = 1
    1196  slab[idx][%Block] = nx
    1197  slab[idy][%Block] = ny
    1198 
    1199  variable iz, it
    1200  for (iz = 0; iz < nz; iz += 1)
    1201  for (it = 0; it < nt; it += 1)
    1202  slab[idz][%Start] = iz
    1203  slab[idt][%Start] = it
    1204  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    1205  wave slabdata// 2D, 3D, or 4D with singletons
    1206  if (transpose)
    1207  data[][][iz][it] = slabdata[q][p][0][0]
    1208  else
    1209  data[][][iz][it] = slabdata[p][q][0][0]
    1210  endif
    1211 
    1212  // progress window
    1213  izt += 1
    1214  if (progress)
    1215  if (update_progress_panel(izt))
    1216  result = -4// user abort
    1217  break
    1218  endif
    1219  endif
    1220  endfor
    1221  if (result < 0)
    1222  break
    1223  endif
    1224  endfor
    1225 
    1226  if (progress)
    1228  endif
    1229 
    1230  killwaves /z slab, slabdata
    1231  if (!result)
    1232  ps_set_dimlabels(data)
    1233  return datawavename
    1234  else
    1235  killwaves /z data
    1236  return ""
    1237  endif
    1238 };
    1239 
    1266 string psh5_load_dataset_slab(variable fileID, string datapath, string datasetname, variable dim2start, variable dim2count, variable dim3start, variable dim3count){
    1267  variable fileID
    1268  string datapath
    1269  string datasetname
    1270  variable dim2start
    1271  variable dim2count
    1272  variable dim3start
    1273  variable dim3count
    1274 
    1275  string datasetpath
    1276  string datawavename
    1277  datasetpath = datapath + "/" + datasetname
    1278  datasetpath = ReplaceString("//", datasetpath, "/")
    1279  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    1280 
    1281  STRUCT HDF5DataInfo di
    1282  InitHDF5DataInfo(di)
    1283  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    1284  if (err != 0)
    1285  print "error accessing detector/data"
    1286  return ""
    1287  endif
    1288  if (di.ndims < 2)
    1289  print "error: rank of dataset < 2"
    1290  return ""
    1291  endif
    1292 
    1293  variable idx, idy, idz, idt
    1294  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
    1295  if (transpose)
    1296  idx = 1
    1297  idy = 0
    1298  else
    1299  idx = 0
    1300  idy = 1
    1301  endif
    1302  idz = 2
    1303  idt = 3
    1304 
    1305  variable nx, ny
    1306  nx = di.dims[idx]
    1307  ny = di.dims[idy]
    1308  make /n=(nx,ny) /o $datawavename
    1309  wave data = $datawavename
    1310  data = 0
    1311 
    1312  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    1313  wave slab
    1314  slab[][%Start] = 0
    1315  slab[][%Stride] = 1
    1316  slab[][%Count] = 1
    1317  slab[][%Block] = 1
    1318  slab[idx][%Block] = nx
    1319  slab[idy][%Block] = ny
    1320 
    1321  variable iz, it
    1322  variable navg = 0
    1323  variable dim2end = dim2start + dim2count - 1
    1324  variable dim3end = dim3start + dim3count - 1
    1325  for (iz = dim2start; iz <= dim2end; iz += 1)
    1326  for (it = dim3start; it <= dim3end; it += 1)
    1327  slab[idz][%Start] = iz
    1328  slab[idt][%Start] = it
    1329  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    1330  if (!v_flag)
    1331  wave slabdata
    1332  if (transpose)
    1333  data += slabdata[q][p][0][0]
    1334  else
    1335  data += slabdata[p][q][0][0]
    1336  endif
    1337  navg += 1
    1338  endif
    1339  endfor
    1340  endfor
    1341  if (navg)
    1342  data /= navg
    1343  endif
    1344 
    1345  killwaves /z slab, slabdata
    1346  ps_set_dimlabels(data)
    1347  return datawavename
    1348 };
    1349 
    1365 variable ps_set_dimlabels(wave data){
    1366  wave data
    1367 
    1368  ps_set_dimlabels2(data, NameOfWave(data))
    1369 };
    1370 
    1384 variable ps_set_dimlabels2(wave data, string name){
    1385  wave data
    1386  string name
    1387 
    1388  variable dummy
    1389  try
    1390  // intrinsic dimensions
    1391  strswitch(name)
    1392  case "ScientaImage":
    1393  setdimlabel 0, -1, $kEnergyDimLabel, data
    1394  setdimlabel 1, -1, $kAngleDimLabel, data
    1395  if (WaveDims(data) >= 3)
    1396  setdimlabel 2, -1, $kScanDimLabel, data
    1397  endif
    1398  AbortOnRTE
    1399  break
    1400  case "ImageAngleDistribution":
    1401  case "ScientaAngleDistribution":
    1402  if (WaveDims(data) >= 2)
    1403  setdimlabel 0, -1, $kScanDimLabel, data
    1404  setdimlabel 1, -1, $kAngleDimLabel, data
    1405  else
    1406  setdimlabel 0, -1, $kAngleDimLabel, data
    1407  endif
    1408  AbortOnRTE
    1409  break
    1410  case "ScientaSpectrum":
    1411  case "ImageEnergyDistribution":
    1412  case "ScientaEnergyDistribution":
    1413  if (WaveDims(data) >= 2)
    1414  setdimlabel 0, -1, $kScanDimLabel, data
    1415  setdimlabel 1, -1, $kEnergyDimLabel, data
    1416  else
    1417  setdimlabel 0, -1, $kEnergyDimLabel, data
    1418  endif
    1419  AbortOnRTE
    1420  break
    1421  default:
    1422  if (WaveDims(data) == 1)
    1423  setdimlabel 0, -1, $kScanDimLabel, data
    1424  AbortOnRTE
    1425  else
    1426  return 1
    1427  endif
    1428  endswitch
    1429  catch
    1430  dummy = GetRTError(1)
    1431  return 2
    1432  endtry
    1433  return 0
    1434 };
    1435 
    1441 static dfr find_scan_folder(dfref dataDF){
    1442  dfref dataDF
    1443 
    1444  dfref attrDF = dataDF:attr
    1445  if (!DataFolderRefStatus(attrDF))
    1446  string df = GetDataFolder(1, dataDF) + ":"
    1447  dfref scanDF = $df
    1448  else
    1449  dfref scanDF = dataDF
    1450  endif
    1451  return scanDF
    1452 };
    1453 
    1458 static dfr find_attr_folder(dfref dataDF){
    1459  dfref dataDF
    1460 
    1461  dfref attrDF = dataDF:attr
    1462  if (!DataFolderRefStatus(attrDF))
    1463  string df = GetDataFolder(1, dataDF) + ":"
    1464  dfref scanDF = $df
    1465  dfref attrDF = scanDF:attr
    1466  endif
    1467  return attrDF
    1468 };
    1469 
    1487  dfref scanDF = GetDataFolderDFR()
    1488  dfref attrDF = find_attr_folder(scanDF)
    1489 
    1490  make /n=3 /free lo, hi
    1491  make /n=3 /t /free ax, un
    1492  wave /t /z /SDFR=scanDF ScanReadables
    1493  if (WaveExists(ScanReadables))
    1494  variable isr
    1495  variable nsr = numpnts(ScanReadables)
    1496  string ssr
    1497  string sdf
    1498  for (isr = 0; isr < nsr; isr += 1)
    1499  setdatafolder scanDF
    1500  ssr = ScanReadables[isr]
    1501  if (ItemsInList(ssr, "/") >= 2)
    1502  sdf = StringFromList(0, ssr, "/")
    1503  ssr = RemoveListItem(0, ssr, "/")
    1504  setdatafolder $sdf
    1505  endif
    1506  wave /z wsr=$ssr
    1507  if (WaveExists(wsr))
    1508  ps_detect_scale(ax, lo, hi, un)
    1509  ps_scale_dataset_2(wsr, ax, lo, hi, un)
    1510  endif
    1511  endfor
    1512  endif
    1513  setdatafolder scanDF
    1514 };
    1515 
    1532 variable ps_scale_dataset(wave data){
    1533  wave data
    1534 
    1535  dfref saveDF = GetDataFolderDFR()
    1536  dfref dataDF = GetWavesDataFolderDFR(data)
    1537 
    1538  setdatafolder dataDF
    1539  make /n=3 /free lo, hi
    1540  make /n=3 /t /free ax, un
    1541  ps_detect_scale(ax, lo, hi, un)
    1542  ps_scale_dataset_2(data, ax, lo, hi, un)
    1543  setdatafolder saveDF
    1544 };
    1545 
    1546 static wave find_scale_wave(string name, dfref dataDF, dfref scanDF, dfref attrDF){
    1547  string name
    1548  dfref dataDF
    1549  dfref scanDF
    1550  dfref attrDF
    1551 
    1552  wave /SDFR=dataDF /Z w = $name
    1553  if (!WaveExists(w))
    1554  wave /SDFR=scanDF /Z w = $name
    1555  if (!WaveExists(w))
    1556  wave /SDFR=attrDF /Z w = $name
    1557  endif
    1558  endif
    1559  return w
    1560 };
    1561 
    1603 variable ps_detect_scale(wave ax, wave lo, wave hi, wave un){
    1604  wave /t ax
    1605  wave lo
    1606  wave hi
    1607  wave /t un
    1608 
    1609  dfref dataDF = GetDataFolderDFR()
    1610  dfref scanDF = find_scan_folder(dataDF)
    1611  dfref attrDF = find_attr_folder(dataDF)
    1612 
    1613  redimension /n=4 lo, hi, un, ax
    1614  setdimlabel 0, 0, $kEnergyDimLabel, lo, hi, un, ax
    1615  setdimlabel 0, 1, $kAngleDimLabel, lo, hi, un, ax
    1616  setdimlabel 0, 2, $kScanDimLabel, lo, hi, un, ax
    1617  setdimlabel 0, 3, $kDataDimLabel, lo, hi, un, ax
    1618 
    1619  // default values
    1620  lo[%$kEnergyDimLabel] = 0
    1621  hi[%$kEnergyDimLabel] = 1
    1622  un[%$kEnergyDimLabel] = "eV"
    1623  ax[%$kEnergyDimLabel] = "Ekin"
    1624 
    1625  lo[%$kAngleDimLabel] = -1
    1626  hi[%$kAngleDimLabel] = 1
    1627  un[%$kAngleDimLabel] = "arb."
    1628  un[%$kAngleDimLabel] = "slice"
    1629 
    1630  lo[%$kScanDimLabel] = 0
    1631  hi[%$kScanDimLabel] = 1
    1632  un[%$kScanDimLabel] = "arb."
    1633  ax[%$kScanDimLabel] = "scan"
    1634 
    1635  lo[%$kDataDimLabel] = 0
    1636  hi[%$kDataDimLabel] = 0
    1637  un[%$kDataDimLabel] = "arb."
    1638  ax[%$kDataDimLabel] = "value"
    1639 
    1640  wave /SDFR=attrDF /T /Z LensMode
    1641  wave /Z ChannelBegin = find_scale_wave("ScientaChannelBegin", dataDF, scanDF, attrDF)
    1642  wave /Z ChannelEnd = find_scale_wave("ScientaChannelEnd", dataDF, scanDF, attrDF)
    1643  wave /Z SliceBegin = find_scale_wave("ScientaSliceBegin", dataDF, scanDF, attrDF)
    1644  wave /Z SliceEnd = find_scale_wave("ScientaSliceEnd", dataDF, scanDF, attrDF)
    1645 
    1646  // lens mode can give more detail
    1647  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
    1648  strswitch(LensMode[0])
    1649  case "Angular45":
    1650  lo[%$kAngleDimLabel] = -45/2
    1651  hi[%$kAngleDimLabel] = +45/2
    1652  un[%$kAngleDimLabel] = ""
    1653  ax[%$kAngleDimLabel] = "angle"
    1654  break
    1655  case "Angular60":
    1656  lo[%$kAngleDimLabel] = -60/2
    1657  hi[%$kAngleDimLabel] = +60/2
    1658  un[%$kAngleDimLabel] = ""
    1659  ax[%$kAngleDimLabel] = "angle"
    1660  break
    1661  case "Transmission":
    1662  un[%$kAngleDimLabel] = "arb."
    1663  ax[%$kAngleDimLabel] = "offset"
    1664  break
    1665  endswitch
    1666  endif
    1667 
    1668  // best option if scales are explicit in separate waves
    1669  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
    1670  lo[%$kEnergyDimLabel] = ChannelBegin[0]
    1671  hi[%$kEnergyDimLabel] = ChannelEnd[0]
    1672  endif
    1673  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
    1674  lo[%$kAngleDimLabel] = SliceBegin[0]
    1675  hi[%$kAngleDimLabel] = SliceEnd[0]
    1676  endif
    1677 
    1678  wave /z /t /SDFR=scanDF ScanWritables
    1679  if (WaveExists(ScanWritables))
    1680  wave /z /SDFR=scanDF scanner = $ScanWritables[0]
    1681  if (!WaveExists(scanner))
    1682  wave /z /SDFR=attrDF scanner = $ScanWritables[0]
    1683  endif
    1684  if (WaveExists(scanner) && (numpnts(scanner) >= 1))
    1685  lo[%$kScanDimLabel] = scanner[0]
    1686  hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1]
    1687  ax[%$kScanDimLabel] = NameOfWave(scanner)
    1688  strswitch(NameOfWave(scanner))
    1689  case "Eph":
    1690  ax[%$kScanDimLabel] = "photon energy"
    1691  un[%$kScanDimLabel] = "eV"
    1692  break
    1693  case "ManipulatorX":
    1694  case "ManipulatorY":
    1695  case "ManipulatorZ":
    1696  case "FocusYTrans":
    1697  case "FocusZTrans":
    1698  case "RefocusYTrans":
    1699  case "RefocusZTrans":
    1700  case "ExitSlitY":
    1701  un[%$kScanDimLabel] = "mm"
    1702  break
    1703  case "ExitSlit":
    1704  un[%$kScanDimLabel] = "m"
    1705  break
    1706  case "ManipulatorTheta":
    1707  case "ManipulatorTilt":
    1708  case "ManipulatorPhi":
    1709  un[%$kScanDimLabel] = ""
    1710  break
    1711  case "FocusXRot":
    1712  case "FocusYRot":
    1713  case "FocusZRot":
    1714  case "RefocusXRot":
    1715  case "RefocusYRot":
    1716  case "RefocusZRot":
    1717  un[%$kScanDimLabel] = "mrad"
    1718  break
    1719  endswitch
    1720  endif
    1721  endif
    1722 };
    1723 
    1763 variable ps_scale_dataset_2(wave data, wave ax, wave lo, wave hi, wave un){
    1764  wave data
    1765  wave /t ax
    1766  wave lo
    1767  wave hi
    1768  wave /t un
    1769 
    1770  string snote = note(data)
    1771  string sdim
    1772  sdim = GetDimLabel(data, 0, -1)
    1773  if (strlen(sdim))
    1774  setscale /i x lo[%$sdim], hi[%$sdim], un[%$sdim], data
    1775  snote = ReplaceStringByKey("AxisLabelX", snote, ax[%$sdim], "=", "\r")
    1776  endif
    1777 
    1778  sdim = GetDimLabel(data, 1, -1)
    1779  if (strlen(sdim))
    1780  setscale /i y lo[%$sdim], hi[%$sdim], un[%$sdim], data
    1781  snote = ReplaceStringByKey("AxisLabelY", snote, ax[%$sdim], "=", "\r")
    1782  endif
    1783 
    1784  sdim = GetDimLabel(data, 2, -1)
    1785  if (strlen(sdim))
    1786  setscale /i z lo[%$sdim], hi[%$sdim], un[%$sdim], data
    1787  snote = ReplaceStringByKey("AxisLabelZ", snote, ax[%$sdim], "=", "\r")
    1788  endif
    1789 
    1790  string data_unit = un[%$kDataDimLabel]
    1791  string data_label = ax[%$kDataDimLabel]
    1792  string s
    1793  variable def = (cmpstr(data_unit, "arb.") == 0) && (cmpstr(data_label, "value") == 0)
    1794 
    1795  if (def)
    1796  s = StringByKey("AxisLabelD", snote, "=", "\r")
    1797  if (strlen(s) > 0)
    1798  data_label = s
    1799  def = 0
    1800  endif
    1801  s = StringByKey("AxisUnitD", snote, "=", "\r")
    1802  if (strlen(s) > 0)
    1803  data_unit = s
    1804  def = 0
    1805  endif
    1806  endif
    1807 
    1808  if (def)
    1809  strswitch(NameOfWave(data))
    1810  case "ScientaImage":
    1811  case "ImageAngleDistribution":
    1812  case "ScientaAngleDistribution":
    1813  case "ScientaSpectrum":
    1814  case "ImageEnergyDistribution":
    1815  case "ScientaEnergyDistribution":
    1816  data *= kDetectorSensitivity
    1817  data_unit = "counts"
    1818  data_label = "intensity"
    1819  def = 0
    1820  break
    1821  case "SampleCurrent":
    1822  case "RefCurrent":
    1823  case "AuxCurrent":
    1824  data_unit = "A"
    1825  data_label = "current"
    1826  def = 0
    1827  break
    1828  case "MachineCurrent":
    1829  data_unit = "mA"
    1830  data_label = "current"
    1831  def = 0
    1832  break
    1833  endswitch
    1834  endif
    1835 
    1836  setscale d 0, 0, data_unit, data
    1837  snote = ReplaceStringByKey("AxisLabelD", snote, data_label, "=", "\r")
    1838  snote = ReplaceStringByKey("AxisUnitD", snote, data_unit, "=", "\r")
    1839  snote = ReplaceStringByKey("Dataset", snote, NameOfWave(data), "=", "\r")
    1840  note /k data, snote
    1841 };
    1842 
    1893 string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress = defaultValue, variable nthreads = defaultValue){
    1894  string ANickName
    1895  string APathName
    1896  string AFileName
    1897  funcref adh5_default_reduction reduction_func
    1898  string reduction_param
    1899  variable progress
    1900  variable nthreads
    1901 
    1902  if (ParamIsDefault(progress))
    1903  progress = 1
    1904  endif
    1905  if (ParamIsDefault(nthreads))
    1906  nthreads = -1
    1907  endif
    1908 
    1909  dfref saveDF = GetDataFolderDFR()
    1910 
    1911  // performance monitoring
    1912  variable timerRefNum
    1913  variable /g psh5_perf_secs
    1914  timerRefNum = startMSTimer
    1915 
    1916  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
    1917  string wavenames = ""
    1918  if (fileID)
    1919  dfref fileDF = GetDataFolderDFR()
    1920  svar s_filepath
    1921  svar s_scanpaths
    1922  AFileName = s_filepath
    1923  print "loading " + s_filepath + "\r"
    1924 
    1925  variable ig = 0
    1926  variable ng = ItemsInList(s_scanpaths)
    1927  string scanpath
    1928  string folder
    1929  string positioners
    1930  string positioner
    1931  string positionerpath
    1932 
    1933  scanpath = StringFromList(ig, s_scanpaths)
    1934  folder = ReplaceString("/", scanpath, "")
    1935  folder = ReplaceString(" ", folder, "")
    1936  folder = CleanupName(folder, 0)
    1937  setdatafolder fileDF
    1938  newdatafolder /s /o $folder
    1939  dfref dataDF = GetDataFolderDFR()
    1940  positioners = psh5_load_scan_meta(fileID, scanpath)
    1941  newdatafolder /s /o attr
    1942  killwaves /a/z
    1943  psh5_load_scan_attrs(fileID, scanpath)
    1944  setdatafolder dataDF
    1945  wave /t /z ScanWritables
    1946  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    1947  positioner = ScanWritables[0]
    1948  if (strlen(positioner) > 0)
    1949  positionerpath = scanpath + "/" + positioner
    1950  positionerpath = ReplaceString("//", positionerpath, "/")
    1951  HDF5LoadData /O /Q /Z fileID, positionerpath
    1952  endif
    1953  endif
    1954 
    1955  setdatafolder dataDF
    1956  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
    1957  string dataset = select_dataset(datasets, "ScientaImage")
    1958  wavenames = psh5_load_dataset_reduced(fileID, scanpath, dataset, reduction_func, reduction_param, progress=progress, nthreads=nthreads)
    1959 
    1960  psh5_close_file(fileID)
    1961  endif
    1962 
    1963  if (timerRefNum >= 0)
    1964  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
    1965  endif
    1966 
    1967  setdatafolder saveDF
    1968  return wavenames
    1969 };
    1970 
    1971 
    2022 string psh5_load_dataset_reduced(variable fileID, string scanpath, string datasetname, funcref reduction_func, string reduction_param, variable progress = defaultValue, variable nthreads = defaultValue){
    2023  variable fileID
    2024  string scanpath
    2025  string datasetname
    2026  funcref adh5_default_reduction reduction_func
    2027  string reduction_param
    2028  variable progress
    2029  variable nthreads
    2030 
    2031  if (ParamIsDefault(progress))
    2032  progress = 1
    2033  endif
    2034  if (ParamIsDefault(nthreads))
    2035  nthreads = -1
    2036  endif
    2037 
    2038  dfref base_df = GetDataFolderDFR()
    2039  variable result = 0
    2040  string datasetpath
    2041  string datawavename
    2042  string wavenames = ""
    2043 
    2044  datasetpath = scanpath + "/" + datasetname
    2045  datasetpath = ReplaceString("//", datasetpath, "/")
    2046  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
    2047 
    2048  string regionname
    2049  string regionpath
    2050  if (ItemsInList(datasetname, "/") >= 2)
    2051  regionname = StringFromList(0, datasetname, "/")
    2052  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
    2053  datasetname = RemoveListItem(0, datasetname, "/")
    2054  NewDataFolder /o/s $regionname
    2055  else
    2056  regionname = ""
    2057  regionpath = scanpath
    2058  endif
    2059 
    2060  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
    2061  InitHDF5DataInfo(di)
    2062  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
    2063  if (err != 0)
    2064  print "error accessing detector/data"
    2065  result = -1
    2066  return wavenames
    2067  endif
    2068  if (di.ndims < 2)
    2069  print "error: rank of dataset < 2"
    2070  result = -2
    2071  return wavenames
    2072  else if (di.ndims < 3)
    2073  progress = 0
    2074  endif
    2075 
    2076  variable idx, idy, idz, idt
    2077  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
    2078  if (transpose)
    2079  idx = 1
    2080  idy = 0
    2081  else
    2082  idx = 0
    2083  idy = 1
    2084  endif
    2085  idz = 2
    2086  idt = 3
    2087 
    2088  variable nx, ny, nz, nt, nzt
    2089  nx = di.dims[idx]
    2090  ny = di.dims[idy]
    2091  nz = di.dims[idz]
    2092  nt = di.dims[idt]
    2093  // adjust singleton dimensions
    2094  nz = max(nz, 1)
    2095  nt = max(nt, 1)
    2096  nzt = nz * nt
    2097 
    2098  // load data image by image
    2099  HDF5MakeHyperslabWave("slab", max(di.ndims, 4))
    2100  wave slab
    2101  slab[][%Start] = 0
    2102  slab[][%Stride] = 1
    2103  slab[][%Count] = 1
    2104  slab[][%Block] = 1
    2105  slab[idx][%Block] = nx
    2106  slab[idy][%Block] = ny
    2107 
    2108  // set up multi threading
    2109  if (nthreads < 0)
    2110  nthreads = ThreadProcessorCount
    2111  endif
    2112  if (nthreads > 0)
    2113  variable threadGroupID = ThreadGroupCreate(nthreads)
    2114  variable ithread
    2115  for (ithread = 0; ithread < nthreads; ithread += 1)
    2116  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
    2117  endfor
    2118  else
    2119  make /n=(nzt) /df /free processing_folders
    2120  endif
    2121 
    2122  if (progress)
    2123  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
    2124  endif
    2125 
    2126  // create a template wave with the correct scales and labels
    2127  make /n=(nx,ny) /d /o $datawavename
    2128  wave template = $datawavename
    2129  ps_set_dimlabels2(template, datawavename)
    2130  ps_scale_dataset(template)
    2131 
    2132  variable iz, it, izt
    2133  string dfname
    2134  variable iw, nw
    2135  string sw
    2136  make /n=0 /free /wave result_waves
    2137 
    2138  izt = 0
    2139  for (iz = 0; iz < nz; iz += 1)
    2140  for (it = 0; it < nt; it += 1)
    2141  // load hyperslab
    2142  slab[idz][%Start] = iz
    2143  slab[idt][%Start] = it
    2144  dfname = "processing_" + num2str(izt)
    2145  newdatafolder /s $dfname
    2146  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
    2147 
    2148  // send to processing queue
    2149  duplicate template, image
    2150  variable /g r_index = iz
    2151  variable /g s_index = it
    2152  string /g func_param = reduction_param
    2153 
    2154  if (nthreads > 0)
    2155  WaveClear image
    2156  ThreadGroupPutDF threadGroupID, :
    2157  else
    2158  processing_folders[izt] = GetDataFolderDFR()
    2159  make /n=1/d profile1, profile2
    2160  wave slabdata
    2161  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
    2162  variable /g func_result = numpnts(reduced_waves)
    2163  adh5_get_result_waves(reduced_waves, "redw_", 0)
    2164  WaveClear slabdata, image, reduced_waves
    2165  setdatafolder ::
    2166  endif
    2167 
    2168  izt += 1
    2169  // progress window
    2170  if (progress)
    2171  if (update_progress_panel(izt))
    2172  print "user abort"
    2173  result = -4
    2174  break
    2175  endif
    2176  endif
    2177  endfor
    2178  endfor
    2179 
    2180  killwaves /z slab, slabdata, template
    2181  if (progress)
    2182  update_progress_panel(0, message="Processing data (step 2 of 2)...")
    2183  endif
    2184 
    2185  dfref dfr
    2186  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
    2187  if (nthreads > 0)
    2188  do
    2189  if (progress)
    2190  if (update_progress_panel(izt))
    2191  print "user abort"
    2192  result = -4
    2193  break
    2194  endif
    2195  endif
    2196  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
    2197  if (DatafolderRefStatus(dfr) != 0)
    2198  break
    2199  endif
    2200  while (1)
    2201  else
    2202  if (progress)
    2203  if (update_progress_panel(izt))
    2204  print "user abort"
    2205  result = -4
    2206  break
    2207  endif
    2208  endif
    2209  dfr = processing_folders[izt]
    2210  endif
    2211 
    2212  if (result != 0)
    2213  break
    2214  endif
    2215 
    2216  nvar rr = dfr:r_index
    2217  nvar ss = dfr:s_index
    2218  nvar func_result = dfr:func_result
    2219 
    2220  if (func_result < 1)
    2221  print "error during data reduction."
    2222  result = -3
    2223  break
    2224  endif
    2225 
    2226  if (numpnts(result_waves) == 0)
    2227  redimension /n=(func_result) result_waves
    2228  for (iw = 0; iw < func_result; iw += 1)
    2229  sw = "redw_" + num2str(iw)
    2230  wave profile = dfr:$sw
    2231  sw = "ReducedData" + num2str(iw+1)
    2232  make /n=(dimsize(profile, 0), nz, nt) /d /o $sw
    2233  wave data = $sw
    2234  setdimlabel 0, -1, $getdimlabel(profile, 0, -1), data
    2235  setdimlabel 1, -1, $kScanDimLabel, data
    2236  note data, note(profile)
    2237  ps_scale_dataset(data)
    2238  setscale /p x dimoffset(profile, 0), dimdelta(profile, 0), waveunits(profile, 0), data
    2239  setscale d 0, 0, waveunits(profile, -1), data
    2240  result_waves[iw] = data
    2241  endfor
    2242  endif
    2243  for (iw = 0; iw < func_result; iw += 1)
    2244  sw = "redw_" + num2str(iw)
    2245  wave profile = dfr:$sw
    2246  wave data = result_waves[iw]
    2247  data[][rr][ss] = profile[p]
    2248  endfor
    2249  endfor
    2250 
    2251  if (nthreads > 0)
    2252  variable tstatus = ThreadGroupRelease(threadGroupID)
    2253  if (tstatus == -2)
    2254  print "error: thread did not terminate properly."
    2255  result = -5
    2256  endif
    2257  else
    2258  for (izt = 0; izt < nzt; izt += 1)
    2259  KillDataFolder /Z processing_folders[izt]
    2260  endfor
    2261  endif
    2262 
    2263  if (result == 0)
    2264  nw = numpnts(result_waves)
    2265  wavenames = ""
    2266  for (iw = 0; iw < nw; iw += 1)
    2267  wave data = result_waves[iw]
    2268  if (nz == 1)
    2269  redimension /n=(-1, 0, 0) data
    2270  else if (nt == 1)
    2271  redimension /n=(-1, nz, 0) data
    2272  endif
    2273  wavenames += nameofwave(data) + ";"
    2274  endfor
    2275  endif
    2276  if (progress)
    2278  endif
    2279 
    2280  setdatafolder base_df
    2281  return wavenames
    2282 };
    2283 
    2284 threadsafe static variable reduce_slab_worker(funcref reduction_func){
    2285  funcref adh5_default_reduction reduction_func
    2286  do
    2287  // wait for job from main thread
    2288  do
    2289  dfref dfr = ThreadGroupGetDFR(0, 1000)
    2290  if (DataFolderRefStatus(dfr) == 0)
    2291  if (GetRTError(2))
    2292  return 0// no more jobs
    2293  endif
    2294  else
    2295  break
    2296  endif
    2297  while (1)
    2298 
    2299  // get input data
    2300  wave slabdata = dfr:slabdata
    2301  wave image = dfr:image
    2302  svar func_param = dfr:func_param
    2303  nvar rr = dfr:r_index
    2304  nvar ss = dfr:s_index
    2305 
    2306  // do the work
    2307  newdatafolder /s outDF
    2308  variable /g r_index = rr
    2309  variable /g s_index = ss
    2310  wave /wave reduced_waves = reduce_slab_image(slabdata, image, reduction_func, func_param)
    2311  variable /g func_result = numpnts(reduced_waves)
    2312 
    2313  // send output to queue and clean up
    2314  adh5_get_result_waves(reduced_waves, "redw_", 0)
    2315  WaveClear slabdata, image, reduced_waves
    2316  ThreadGroupPutDF 0, :
    2317  KillDataFolder dfr
    2318  while (1)
    2319 
    2320  return 0
    2321 };
    2322 
    2323 threadsafe static wave reduce_slab_image(wave slabdata, wave image, funcref reduction_func, string reduction_param){
    2324  wave slabdata
    2325  wave image
    2326  funcref adh5_default_reduction reduction_func
    2327  string reduction_param
    2328 
    2329  // the multiplication by detector sensitivity assumes that we are loading a ScientaImage.
    2330  image = slabdata[q][p][0][0] * kDetectorSensitivity
    2331 
    2332  return reduction_func(image, reduction_param)
    2333 };
    2334 
    2349 string psh5_load_info(string APathName, string AFileName){
    2350  string APathName
    2351  string AFileName
    2352 
    2353  dfref saveDF = GetDataFolderDFR()
    2354  dfref fileDF = NewFreeDataFolder()
    2355  setdatafolder fileDF
    2356 
    2357  variable fileID
    2358  string filepath
    2359  string scanpaths
    2360  variable nscans
    2361  variable iscan
    2362  string scanpath
    2363  string info = ""
    2364 
    2365  HDF5OpenFile /P=$APathName /R fileID as AFileName
    2366  if (v_flag == 0)
    2367  filepath = s_path + s_filename
    2368  scanpaths = psh5_list_scans(fileID)
    2369  nscans = ItemsInList(scanpaths)
    2370  for (iscan = 0; iscan < nscans; iscan += 1)
    2371  scanpath = StringFromList(iscan, scanpaths)
    2372  info = info + scanpath + "\r"
    2373  info = info + psh5_load_scan_info(fileID, scanpath)
    2374  endfor
    2375  HDF5CloseFile fileID
    2376  endif
    2377 
    2378  setdatafolder saveDF
    2379  return info
    2380 };
    2381 
    2396 string psh5_load_scan_info(variable fileID, string scanpath){
    2397  variable fileID
    2398  string scanpath
    2399 
    2400  string info = ""
    2401  string positions = ""
    2402  string positioners = ""
    2403  string readables = ""
    2404  string detectors = ""
    2405  string regions = ""
    2406 
    2407  psh5_load_scan_meta(fileID, scanpath)
    2408 
    2409  wave /z ScanDimensions
    2410  wave /t /z ScanWritables
    2411  wave /t /z ScanReadables
    2412  wave /z ScanSteps
    2413 
    2414  if (WaveExists(ScanSteps) && (numpnts(ScanSteps) >= 1))
    2415  ScanSteps += 1
    2416  positions = "positions = (" + wave2list(ScanSteps, "%u", ",") + ")"
    2417  info = AddListItem(positions, info, "\r", inf)
    2418  endif
    2419  if (WaveExists(ScanWritables) && (numpnts(ScanWritables) >= 1))
    2420  positioners = "positioners = " + twave2list(ScanWritables, ",")
    2421  info = AddListItem(positioners, info, "\r", inf)
    2422  endif
    2423 
    2424  variable i, m, n
    2425  string s
    2426  if (WaveExists(ScanReadables) && (numpnts(ScanReadables) >= 1))
    2427  readables = twave2list(ScanReadables, ",")
    2428  n = ItemsInList(readables, ",")
    2429  for (i = 0; i < n; i += 1)
    2430  s = StringFromList(i, readables, ",")
    2431  m = ItemsInList(s, "/")
    2432  if (m > 1)
    2433  s = StringFromList(m - 1, s, "/")
    2434  endif
    2435  if (WhichListItem(s, detectors, ",") < 0)
    2436  detectors = AddListItem(s, detectors, ",", inf)
    2437  endif
    2438  endfor
    2439  detectors = "detectors = " + detectors
    2440  info = AddListItem(detectors, info, "\r", inf)
    2441  endif
    2442 
    2443  regions = psh5_list_scan_regions(fileID, scanpath)
    2444  if (strlen(regions) > 0)
    2445  regions = "regions = " + regions
    2446  info = AddListItem(regions, info, "\r", inf)
    2447  endif
    2448 
    2449  return info
    2450 };
    2451 
    2455 static string twave2list(wave wt, string sep){
    2456  wave /t wt
    2457  string sep
    2458 
    2459  string list = ""
    2460  variable n = numpnts(wt)
    2461  variable i
    2462  for (i = 0; i < n; i += 1)
    2463  list = AddListItem(wt[i], list, sep, inf)
    2464  endfor
    2465 
    2466  return list
    2467 };
    2468 
    2472 static string wave2list(wave w, string format, string sep){
    2473  wave w
    2474  string format
    2475  string sep
    2476 
    2477  string list = ""
    2478  variable n = numpnts(w)
    2479  variable i
    2480  string s
    2481  for (i = 0; i < n; i += 1)
    2482  sprintf s, format, w[i]
    2483  list = AddListItem(s, list, sep, inf)
    2484  endfor
    2485 
    2486  return list
    2487 };
    2488 
    string psh5_list_scan_regions(variable fileID, string scanpath)
    list regions of a PShell scan group.
    +
    const string kEnergyDimLabel
    Dimension label for the energy dispersive dimension of multi-dimensional datasets.
    +
    string psh5_load_dataset_reduced(variable fileID, string scanpath, string datasetname, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
    load a reduced dataset from the open PShell HDF5 file.
    variable kill_progress_panel()
    +
    string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress=defaultValue, variable nthreads=defaultValue)
    load and reduce the ScientaImage dataset of the first scan of a PShell data file. ...
    variable display_progress_panel(string title, string message, variable progress_max)
    -
    string psh5_load_scan_preview(variable fileID, string scanpath, variable set_scale=defaultValue, string pref_datasets=defaultValue)
    load a preview dataset from an open PShell HDF5 file.
    -
    string psh5_load_scan_attrs(variable fileID, string scanpath, variable attr_sets=defaultValue)
    load attributes of a PShell scan group.
    -
    const string kTransposedDatasets
    List of datasets that should be transposed upon loading.
    -
    string psh5_load_scan_complete(variable fileID, string scanpath, variable load_data=defaultValue, variable load_attr=defaultValue)
    load all data of a selected scan from a PShell data file.
    -
    static threadsafe variable reduce_slab_worker(funcref reduction_func)
    -
    variable ps_set_dimlabels2(wave data, string name)
    set dimension labels according to the axis type
    -
    const string kScanDimLabel
    Dimension label for the scan dimension of multi-dimensional datasets.
    -
    string psh5_load_dataset(variable fileID, string scanpath, string datasetname, variable set_scale=defaultValue)
    load a dataset from an open PShell HDF5 file.
    -
    variable ps_set_dimlabels(wave data)
    set dimension labels according to the axis type
    -
    static dfr find_scan_folder(dfref dataDF)
    find the scan folder
    -
    const string kAngleDimLabel
    Dimension label for the angle dispersive dimension of multi-dimensional datasets. ...
    -
    static string twave2list(wave wt, string sep)
    convert text wave to list.
    -
    variable ps_scale_dataset_2(wave data, wave ax, wave lo, wave hi, wave un)
    set the dimension scales of a dataset.
    -
    static string wave2list(wave w, string format, string sep)
    convert numeric wave to list.
    -
    static threadsafe variable reduce_slab_image(wave slabdata, wave image, wave profile1, wave profile2, funcref reduction_func, string reduction_param)
    -
    static string select_dataset(string file_datasets, string pref_datasets)
    select the preferred dataset from a list of available datasets.
    -
    const string kDataDimLabel
    Dimension label for the data dimension.
    -
    string psh5_load_preview(string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue, string pref_scans=defaultValue, string pref_datasets=defaultValue)
    load a preview image from a PShell data file.
    -
    variable psh5_open_file(string ANickName, string APathName, string AFileName)
    open a HDF5 file created by the PShell data acquisition program and prepare the data folder...
    -
    string psh5_load_dataset_slabs(variable fileID, string datapath, string datasetname, variable progress=defaultValue)
    load a dataset slab-wise from the open PShell HDF5 file.
    -
    variable ps_scale_datasets()
    set the dimension scales of loaded PShell Scienta datasets according to attributes.
    -
    string psh5_load_scan_meta(variable fileID, string scanpath)
    load metadata of a PShell scan group.
    -
    threadsafe variable adh5_default_reduction(wave source, wave dest1, wave dest2, string *param)
    function prototype for adh5_load_reduced_detector
    -
    const string kScientaScalingDatasets
    List of datasets that must be loaded to determine the axis scaling of a Scienta image.
    -
    string psh5_load_scan_section(variable fileID, string scanpath, variable dim, variable set_scale=defaultValue, string pref_datasets=defaultValue)
    load a longitudinal section of a scan from an open PShell HDF5 file.
    -
    string psh5_list_scan_datasets(variable fileID, string scanpath, variable include_regions=defaultValue)
    list datasets of a PShell scan group.
    -
    string psh5_load_info(string APathName, string AFileName)
    load descriptive info from a PShell data file.
    -
    string psh5_load_dataset_slab(variable fileID, string datapath, string datasetname, variable dim2start, variable dim2count, variable dim3start, variable dim3count)
    load a single image from the open PShell data file.
    -
    string psh5_load_scan_data(variable fileID, string scanpath)
    load all datasets of a PShell scan group.
    -
    const variable kDetectorSensitivity
    multiply scienta detector intensity by this value to get actual counts.
    -
    string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
    load everything from a PShell data file.
    -
    static dfr find_attr_folder(dfref dataDF)
    find the attributes data folder
    -
    static wave find_scale_wave(string name, dfref dataDF, dfref scanDF, dfref attrDF)
    +
    string psh5_load_scan_preview(variable fileID, string scanpath, variable set_scale=defaultValue, string pref_datasets=defaultValue)
    load a preview dataset from an open PShell HDF5 file.
    +
    string psh5_load_scan_attrs(variable fileID, string scanpath, variable attr_sets=defaultValue)
    load attributes of a PShell scan group.
    +
    const string kTransposedDatasets
    List of datasets that should be transposed upon loading.
    +
    string psh5_load_scan_complete(variable fileID, string scanpath, variable load_data=defaultValue, variable load_attr=defaultValue)
    load all data of a selected scan from a PShell data file.
    +
    static threadsafe variable reduce_slab_worker(funcref reduction_func)
    +
    variable ps_set_dimlabels2(wave data, string name)
    set dimension labels according to the axis type
    +
    const string kScanDimLabel
    Dimension label for the scan dimension of multi-dimensional datasets.
    +
    string psh5_load_dataset(variable fileID, string scanpath, string datasetname, variable set_scale=defaultValue)
    load a dataset from an open PShell HDF5 file.
    +
    variable ps_set_dimlabels(wave data)
    set dimension labels according to the axis type
    +
    threadsafe variable adh5_get_result_waves(wave results, string result_prefix, variable start_index)
    copy waves from wave reference wave into current data folder
    +
    static dfr find_scan_folder(dfref dataDF)
    find the scan folder
    +
    const string kAngleDimLabel
    Dimension label for the angle dispersive dimension of multi-dimensional datasets. ...
    +
    static string twave2list(wave wt, string sep)
    convert text wave to list.
    +
    variable ps_scale_dataset_2(wave data, wave ax, wave lo, wave hi, wave un)
    set the dimension scales of a dataset.
    +
    static threadsafe wave reduce_slab_image(wave slabdata, wave image, funcref reduction_func, string reduction_param)
    +
    static string wave2list(wave w, string format, string sep)
    convert numeric wave to list.
    +
    static string select_dataset(string file_datasets, string pref_datasets)
    select the preferred dataset from a list of available datasets.
    +
    const string kDataDimLabel
    Dimension label for the data dimension.
    +
    string psh5_load_preview(string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue, string pref_scans=defaultValue, string pref_datasets=defaultValue)
    load a preview image from a PShell data file.
    +
    variable psh5_open_file(string ANickName, string APathName, string AFileName)
    open a HDF5 file created by the PShell data acquisition program and prepare the data folder...
    +
    string psh5_load_dataset_slabs(variable fileID, string datapath, string datasetname, variable progress=defaultValue)
    load a dataset slab-wise from the open PShell HDF5 file.
    +
    variable ps_scale_datasets()
    set the dimension scales of loaded PShell Scienta datasets according to attributes.
    +
    string psh5_load_scan_meta(variable fileID, string scanpath)
    load metadata of a PShell scan group.
    +
    const string kScientaScalingDatasets
    List of datasets that must be loaded to determine the axis scaling of a Scienta image.
    +
    string psh5_load_scan_section(variable fileID, string scanpath, variable dim, variable set_scale=defaultValue, string pref_datasets=defaultValue)
    load a longitudinal section of a scan from an open PShell HDF5 file.
    +
    string psh5_list_scan_datasets(variable fileID, string scanpath, variable include_regions=defaultValue)
    list datasets of a PShell scan group.
    +
    string psh5_load_info(string APathName, string AFileName)
    load descriptive info from a PShell data file.
    +
    string psh5_load_dataset_slab(variable fileID, string datapath, string datasetname, variable dim2start, variable dim2count, variable dim3start, variable dim3count)
    load a single image from the open PShell data file.
    +
    threadsafe wave adh5_default_reduction(wave source, string *param)
    function prototype for adh5_load_reduced_detector
    +
    string psh5_load_scan_data(variable fileID, string scanpath)
    load all datasets of a PShell scan group.
    +
    const variable kDetectorSensitivity
    multiply scienta detector intensity by this value to get actual counts.
    +
    string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data=defaultValue, variable load_attr=defaultValue)
    load everything from a PShell data file.
    +
    static dfr find_attr_folder(dfref dataDF)
    find the attributes data folder
    +
    static wave find_scale_wave(string name, dfref dataDF, dfref scanDF, dfref attrDF)
    variable update_progress_panel(variable progress, string message=defaultValue, variable progress_max=defaultValue)
    -
    string psh5_list_scans(variable fileID)
    list scan groups of a PShell data file.
    -
    variable psh5_close_file(variable fileID)
    close a HDF5 file opened by psh5_open_file.
    -
    variable ps_detect_scale(wave ax, wave lo, wave hi, wave un)
    detect the dimension scales from attributes.
    -
    variable psh5_load_dataset_meta(variable fileID, string datapath, string datasetname, wave datawave)
    load metadata of a PShell dataset.
    -
    const string kPreviewDatasets
    List of preferred datasets to load for preview.
    -
    variable ps_scale_dataset(wave data)
    set the dimension scales of a loaded PShell Scienta dataset according to attributes.
    -
    string psh5_load_scan_info(variable fileID, string scanpath)
    load descriptive info from a PShell scan.
    +
    string psh5_list_scans(variable fileID)
    list scan groups of a PShell data file.
    +
    variable psh5_close_file(variable fileID)
    close a HDF5 file opened by psh5_open_file.
    +
    variable ps_detect_scale(wave ax, wave lo, wave hi, wave un)
    detect the dimension scales from attributes.
    +
    variable psh5_load_dataset_meta(variable fileID, string datapath, string datasetname, wave datawave)
    load metadata of a PShell dataset.
    +
    const string kPreviewDatasets
    List of preferred datasets to load for preview.
    +
    variable ps_scale_dataset(wave data)
    set the dimension scales of a loaded PShell Scienta dataset according to attributes.
    +
    string psh5_load_scan_info(variable fileID, string scanpath)
    load descriptive info from a PShell scan.
    -

    Definition at line 76 of file pearl-scienta-preprocess.ipf.

    +

    set reduction parameters from cursors in a graph.

    +

    PRELIMINARY - function arguments may change

    +

    sets reduction parameters from cursors in a graph. an even number of cursors (2 or more) must be set on the image. cursor names and order do not matter, except that the alphabetically first cursor which is attached to an image selects the image. the cursors mark the following positions, from innermost to outermost pair: 1) low and high limits of peak region. 2) peak-side boundary of lower and upper background region. 3) lower and upper cropping region.

    + +

    Definition at line 89 of file pearl-scienta-preprocess.ipf.

    - +
    - - - - - - - - - - - - - - - - -
    wave fit_scienta_ang_transm (wave data,
    wave params 
    )
    -
    - -

    Definition at line 551 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - -
    wave fit_scienta_poly_bg (wave data,
    wave params,
    variable bgterms 
    )
    -
    - -

    Definition at line 610 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - + - - - - - - - - - - - - @@ -320,14 +237,12 @@ Licensed under the Apache License, Version 2.0 (the "License");
    threadsafe variable gauss2_reduction threadsafe wave gauss4_reduction ( wave  source,
    wave dest1,
    wave dest2,
    -

    fit horizontal cuts of an image with two gaussian peaks on a linear background

    -

    the function fits each horizontal profile (EDC) with two gaussian peaks on a linear background. the position and width of the peaks is kept fixed according to input parameters. the peak amplitude is constrained to positive value.

    -

    the width parameter is defined as in Igor's gauss curve fit function (standard deviation divided by the square root of two). the return value in dest1 is the integrated peak either of peak 1 or peak 2. dest2 returns the corresponding error estimate.

    +

    fit horizontal cuts of an image with up to four gaussian peaks on a linear background

    +

    the function fits each horizontal profile (EDC) with four gaussian peaks on a linear background. the position and width of the peaks is kept fixed according to input parameters. the peak amplitude is constrained to positive value.

    +

    the width parameter is defined as in Igor's gauss curve fit function (standard deviation divided by the square root of two). the return value in dest1 is the integrated peak of one of the peaks. dest2 returns the corresponding error estimate.

    Parameters
    - - - +
    sourcesource wave. two-dimensional distribution of counts. for correct weighting and error estimation it is important that the source wave contains actual counts (Poisson statistics).
    dest1(out) peak area
    dest2(out) error estimate of peak area
    sourcesource wave. two-dimensional distribution of counts. for correct weighting and error estimation it is important that the source wave contains actual counts (Poisson statistics).
    param(in, out) semicolon-separated key=value list of processing parameters. this is a pass-by-reference argument. the following parameters are required. position, width and limit parameters are on the x (energy) scale.
    • rngl low limit of fit interval
    • rngh high limit of fit interval
    • @@ -335,41 +250,33 @@ Licensed under the Apache License, Version 2.0 (the "License");
    • wid1 width of peak 1
    • pos2 position of peak 2
    • wid2 width of peak 2
    • -
    • return select result to return, either "int1" or "int2".
    • +
    • pos3 position of peak 3
    • +
    • wid3 width of peak 3
    • +
    • pos4 position of peak 4
    • +
    • wid4 width of peak 4
    • +
    • npeaks number of peaks to fit: 1...4 the others are held at amplitude 0.
    • ybox box size of averaging in y direction, must be 1 or 3. other values lead to corrupt data.
    -
    Returns
    zero if successful, non-zero if an error occurs.
    +
    Returns
    free wave containing references of the result waves. the number of waves is two times the number of peaks that are fit. the first npeaks waves contain the peak integrals, the second npeaks waves the corresponding error estimates.
    -

    Definition at line 903 of file pearl-scienta-preprocess.ipf.

    +

    Definition at line 672 of file pearl-scienta-preprocess.ipf.

    - +
    - + - - - - - - - - - - - - @@ -384,32 +291,41 @@ Licensed under the Apache License, Version 2.0 (the "License");
    threadsafe variable int_linbg_reduction threadsafe wave int_linbg_reduction ( wave  source,
    wave dest1,
    wave dest2,
    -

    Definition at line 197 of file pearl-scienta-preprocess.ipf.

    +

    linear-background subtracted integration reduction function.

    +

    data reduction function for adh5_load_reduced_detector. cf. adh5_default_reduction for an explanation of reduction functions.

    +

    this function calculates the average pixel value of each angular slice in one center and two background intervals. a background value is calculated at the center position by linear interpolation from the two background values. returns the center minus linear background in dest1. returns the Poisson one-sigma error in dest2.

    +

    typical values (peak centered on detector, FWHM ~ 20 % of image) Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2

    +
    Parameters
    + + + +
    sourcescienta detector image, energy axis along X, angle axis along Y. two-dimensional intensity distribution (image). the scales are carried over to the result waves.
    paramparameters in a key1=value1;key2=value2;... list. all region parameters are relative to the image size (0...1).
      +
    • Lcrop = size of the lower cropping region
    • +
    • Hcrop = size of the upper cropping region
    • +
    • Lsize = size of the lower background integration region
    • +
    • Hsize = size of the upper background integration region
    • +
    • Cpos = center position of the of the peak integration region
    • +
    • Csize = size of the peak integration region
    • +
    +
    +
    +
    +
    Returns
    free wave containing references of the two result waves. the first wave is the integral minus linear background. the second wave is the Poisson one-sigma error.
    + +

    Definition at line 214 of file pearl-scienta-preprocess.ipf.

    - +
    - + - - - - - - - - - - - - @@ -424,16 +340,37 @@ Licensed under the Apache License, Version 2.0 (the "License");
    threadsafe variable int_quadbg_reduction threadsafe wave int_quadbg_reduction ( wave  source,
    wave dest1,
    wave dest2,
    -

    Definition at line 457 of file pearl-scienta-preprocess.ipf.

    +

    integrate peak area minus a quadratic background

    +

    data reduction function for adh5_load_reduced_detector. cf. adh5_default_reduction for an explanation of reduction functions.

    +

    this function calculates the average pixel value of each angular slice in one center and two background intervals. a background value is calculated at the center position by linear interpolation from the two background values. returns the center minus linear background in dest1. returns the Poisson one-sigma error in dest2.

    +

    typical values (peak centered on detector, FWHM ~ 20 % of image) Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2

    +
    Parameters
    + + + +
    sourcescienta detector image, energy axis along X, angle axis along Y. two-dimensional intensity distribution (image). the scales are carried over to the result waves.
    paramparameters in a key1=value1;key2=value2;... list. all region parameters are relative to the image size (0...1).
      +
    • Lcrop = size of the lower cropping region
    • +
    • Hcrop = size of the upper cropping region
    • +
    • Lsize = size of the lower background integration region
    • +
    • Hsize = size of the upper background integration region
    • +
    • Cpos = center position of the of the peak integration region
    • +
    • Csize = size of the peak integration region
    • +
    +
    +
    +
    +
    Returns
    free wave containing references of the two result waves. the first wave is the integral minus linear background. the second wave is the Poisson one-sigma error.
    + +

    Definition at line 367 of file pearl-scienta-preprocess.ipf.

    - +
    - + @@ -442,10 +379,9 @@ Licensed under the Apache License, Version 2.0 (the "License");
    variable prompt_gauss2_reduction variable prompt_gauss4_reduction ( string *  param)
    -

    prompt for the gauss2_reduction parameters

    -

    useful for testing or manual processing. to debug, (temporarily) remove the threadsafe attribute from the gauss2_reduction function.

    +

    prompt for the gauss4_reduction parameters

    -

    Definition at line 834 of file pearl-scienta-preprocess.ipf.

    +

    Definition at line 580 of file pearl-scienta-preprocess.ipf.

    @@ -463,7 +399,9 @@ Licensed under the Apache License, Version 2.0 (the "License");
    -

    Definition at line 36 of file pearl-scienta-preprocess.ipf.

    +

    prompt the user for integrate on linear background reduction parameters.

    + +

    Definition at line 35 of file pearl-scienta-preprocess.ipf.

    @@ -481,7 +419,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
    -

    Definition at line 410 of file pearl-scienta-preprocess.ipf.

    +

    Definition at line 305 of file pearl-scienta-preprocess.ipf.

    @@ -499,59 +437,29 @@ Licensed under the Apache License, Version 2.0 (the "License");
    -

    parameter dialog for the redim_linbg_reduction() function

    +

    parameter dialog for the redim_linbg_reduction() function

    Parameters
    - +
    paramparameter string in a key1=value1;key2=value2;... list. the parameter string is passed by reference. see redim_linbg_reduction() for a description of parameters.
    paramparameter string in a key1=value1;key2=value2;... list. the parameter string is passed by reference. see redim_linbg_reduction() for a description of parameters.
    Returns
    zero if the user clicked OK, non-zero if the user clicked Cancel.
    -

    Definition at line 716 of file pearl-scienta-preprocess.ipf.

    +

    Definition at line 463 of file pearl-scienta-preprocess.ipf.

    - +
    - - - - - - -
    variable prompt_Shockley_anglefit (string * param)
    -
    - -

    Definition at line 322 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - + - - - - - - - - - - - - @@ -569,12 +477,10 @@ Licensed under the Apache License, Version 2.0 (the "License");

    linear background reduction function for incorrectly dimensioned scienta image

    if the energy step size does not divide the energy range to an integer number, the scienta image is exported with the wrong array size. this can be fixed by redimensioning the array.

    the current implementation works in the case where dimension 0 needs to be incremented. the function may be generalized to dimension 1 and/or decrementing by additional parameters. it is not known yet whether a generalization is needed or whether it can cover all cases.

    -

    background subtraction and peak integration is the same as by the int_linbg_reduction() function.

    +

    background subtraction and peak integration is the same as by the int_linbg_reduction() function.

    Parameters
    threadsafe variable redim_linbg_reduction threadsafe wave redim_linbg_reduction ( wave  source,
    wave dest1,
    wave dest2,
    - -
    sourcesource wave Scienta detector image, energy axis along X, angle axis along Y
    dest1destination wave 1
    dest2destination wave 2 each wave is a one-dimensional intensity distribution the function may redimension these waves to one of the image dimensions (it must be clear to the user which dimension this is). the meaning of dest1 and dest2 is up to the particular function, e.g. dest1 could hold the mean value and dest2 the one-sigma error, or dest1 could hold the X-profile, and dest2 the Y-profile.
    paramparameter string in a key1=value1;key2=value2;... list. the parameter string is passed by reference.
    @@ -588,148 +494,18 @@ Licensed under the Apache License, Version 2.0 (the "License");
  • Csize size of the peak integration region
  • typical values (peak centered on detector, FWHM ~ 20 % of image) Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2

    -
    Returns
    zero if successful, non-zero if an error occurs.
    +
    Returns
    free wave containing references of the two result waves. the first wave is the integral minus linear background. the second wave is the Poisson one-sigma error.
    -

    Definition at line 787 of file pearl-scienta-preprocess.ipf.

    +

    Definition at line 526 of file pearl-scienta-preprocess.ipf.

    - +
    - - - - - - - - - - - - - - - - -
    threadsafe variable scienta_ang_transm (wave w,
    variable x 
    )
    -
    - -

    Definition at line 578 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - -
    variable scienta_norm (wave w,
    variable x 
    )
    -
    - -

    Definition at line 544 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - -
    variable scienta_poly_bg (wave w,
    variable e,
    variable a 
    )
    -
    - -

    Definition at line 654 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    threadsafe variable Shockley_anglefit (wave source,
    wave dest1,
    wave dest2,
    string * param 
    )
    -
    - -

    Definition at line 337 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - + @@ -738,74 +514,10 @@ Licensed under the Apache License, Version 2.0 (the "License");
    variable test_gauss2_reduction variable test_gauss4_reduction ( wave  image)
    -

    apply the gauss2_reduction function to a single image

    +

    apply the gauss4_reduction function to a single image

    useful for testing or manual processing. to debug, (temporarily) remove the threadsafe attribute from the gauss2_reduction function.

    -

    Definition at line 810 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - -
    variable test_int_linbg (wave image)
    -
    - -

    Definition at line 180 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - -
    variable test_int_quadbg (wave image)
    -
    - -

    Definition at line 440 of file pearl-scienta-preprocess.ipf.

    - -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - -
    variable test_shockley_anglefit (wave image,
    variable branch 
    )
    -
    - -

    Definition at line 297 of file pearl-scienta-preprocess.ipf.

    +

    Definition at line 546 of file pearl-scienta-preprocess.ipf.

    @@ -815,7 +527,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
    -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 #pragma version = 1.03
    5 #include "mm-fitfuncs"
    6 
    7 // $Id$
    8 // author: matthias.muntwiler@psi.ch
    9 // Copyright (c) 2013-17 Paul Scherrer Institut
    10 
    11 // Licensed under the Apache License, Version 2.0 (the "License");
    12 // you may not use this file except in compliance with the License.
    13 // You may obtain a copy of the License at
    14 // http://www.apache.org/licenses/LICENSE-2.0
    15 
    30 
    35 
    36 variable prompt_int_linbg_reduction(string* param){
    37  string &param
    38 
    39  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
    40  variable Lsize = NumberByKey("Lsize", param, "=", ";")
    41  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
    42  variable Hsize = NumberByKey("Hsize", param, "=", ";")
    43  variable Cpos = NumberByKey("Cpos", param, "=", ";")
    44  variable Csize = NumberByKey("Csize", param, "=", ";")
    45 
    46  prompt Lcrop, "Lower cropping region"
    47  prompt Hcrop, "Upper cropping region"
    48  prompt Lsize, "Lower background region"
    49  prompt Hsize, "Upper background region"
    50  prompt Cpos, "Center position"
    51  prompt Csize, "Center integration region"
    52 
    53  doprompt "int_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
    54  if (v_flag == 0)
    55  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
    56  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
    57  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
    58  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
    59  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
    60  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
    61  endif
    62 
    63  return v_flag
    64 };
    65 
    67  // this function is for testing only, until we implement a proper interface
    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 };
    75 
    76 string csr_int_linbg_reduction(string win){
    77  // PRELIMINARY - function arguments may change
    78 
    79  // sets reduction parameters from cursors in a graph.
    80  // an even number of cursors (2 or more) must be set on the image.
    81  // cursor names and order do not matter,
    82  // except that the alphabetically first cursor which is attached to an image selects the image.
    83  // the cursors mark the following positions, from innermost to outermost pair:
    84  // 1) low and high limits of peak region.
    85  // 2) peak-side boundary of lower and upper background region.
    86  // 3) lower and upper cropping region.
    87 
    88  string win
    89 
    90  // read all cursor positions
    91  variable ic
    92  string sc
    93  variable nc = 10
    94  make /n=(nc) /free positions
    95  variable np = 0
    96  wave /z image = $""
    97  string imagename = ""
    98  string tracename = ""
    99  string info
    100 
    101  for (ic = 0; ic < nc; ic += 1)
    102  sc = num2char(char2num("A") + ic)
    103  wave /z wc = CsrWaveRef($sc, win)
    104  info = CsrInfo($sc, win)
    105  tracename = StringByKey("TNAME", info, ":", ";")
    106  if (waveexists(wc) && (wavedims(wc) == 2))
    107  if (!waveexists(image))
    108  wave image = wc
    109  imagename = tracename
    110  endif
    111  if (cmpstr(tracename, imagename) == 0)
    112  positions[np] = pcsr($sc, win)
    113  np += 1
    114  endif
    115  endif
    116  endfor
    117 
    118  np = floor(np / 2) * 2// ignore odd cursor
    119  redimension /n=(np) positions
    120  sort positions, positions
    121  // shift upper positions by one so that the rightmost pixel becomes 1.0
    122  positions = p >= np / 2 ? positions + 1 : positions
    123  positions = positions / dimsize(image, 0)
    124 
    125  // map innermost cursor pair to peak center and size
    126  variable ip2 = np / 2
    127  variable ip1 = ip2 - 1
    128  variable Cpos = (positions[ip1] + positions[ip2]) / 2
    129  variable Csize = positions[ip2] - positions[ip1]
    130  if (ip1 >= 0)
    131  Cpos = (positions[ip1] + positions[ip2]) / 2
    132  Csize = positions[ip2] - positions[ip1]
    133  else
    134  // default: a small region in the center
    135  Cpos = 0.5
    136  Csize = 0.2
    137  endif
    138 
    139  // background region
    140  ip1 -= 1
    141  ip2 += 1
    142  variable Lsize
    143  variable Hsize
    144  if (ip1 >= 0)
    145  Lsize = positions[ip1]
    146  Hsize = 1 - positions[ip2]
    147  else
    148  // default: everything outside the peak region
    149  Lsize = Cpos - Csize / 2
    150  Hsize = 1 - (Cpos + Csize / 2)
    151  endif
    152 
    153  // crop region
    154  ip1 -= 1
    155  ip2 += 1
    156  variable Lcrop
    157  variable Hcrop
    158  if (ip1 >= 0)
    159  Lcrop = positions[ip1]
    160  Hcrop = 1 - positions[ip2]
    161  else
    162  // default: dead corners of the EW4000 at PEARL
    163  Lcrop = 0.11
    164  Hcrop = 0.11
    165  endif
    166  Lsize = max(Lsize - Lcrop, 0)
    167  Hsize = max(Hsize - Hcrop, 0)
    168 
    169  string param = ""
    170  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
    171  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
    172  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
    173  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
    174  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
    175  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
    176 
    177  return param
    178 };
    179 
    180 variable test_int_linbg(wave image){
    181  // useful for testing or manual processing
    182  // since the int_linbg_reduction function cannot be called from the command line directly.
    183  wave image
    184 
    185  string param = ""
    187 
    188  string data1_name = "test_data1"
    189  string data2_name = "test_data2"
    190  duplicate /o image, $data1_name, $data2_name
    191  wave w_data1 = $data1_name
    192  wave w_data2 = $data2_name
    193 
    194  int_linbg_reduction(image, w_data1, w_data2, param)
    195 };
    196 
    197 threadsafe variable int_linbg_reduction(wave source, wave dest1, wave dest2, string* param){
    198  // data reduction function for adh5_load_reduced_detector
    199  // calculates the average pixel value of each angular slice
    200  // in one center and two background intervals.
    201  // a background value is calculated at the center position
    202  // by linear interpolation from the two background values.
    203  // returns the center minus linear background in dest1.
    204  // returns the Poisson one-sigma error in dest2.
    205  wave source// source wave
    206  // Scienta detector image, energy axis along X, angle axis along Y
    207  wave dest1, dest2// destination waves
    208  // each wave is a one-dimensional intensity distribution
    209  // the function may redimension these waves to one of the image dimensions
    210  // (it must be clear to the user which dimension this is).
    211  // the meaning of dest1 and dest2 is up to the particular function,
    212  // e.g. dest1 could hold the mean value and dest2 the one-sigma error,
    213  // or dest1 could hold the X-profile, and dest2 the Y-profile.
    214  string &param// parameters in a key1=value1;key2=value2;... list
    215  // all region parameters are relative to the image size (0...1)
    216  // Lcrop = size of the lower cropping region
    217  // Hcrop = size of the upper cropping region
    218  // Lsize = size of the lower background integration region
    219  // Hsize = size of the upper background integration region
    220  // Cpos = center position of the of the peak integration region
    221  // Csize = size of the peak integration region
    222 
    223  // typical values (peak centered on detector, FWHM ~ 20 % of image)
    224  // Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2
    225 
    226  variable nx = dimsize(source, 0)
    227  variable ny = dimsize(source, 1)
    228 
    229  // read parameters
    230  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
    231  variable lsize = NumberByKey("Lsize", param, "=", ";")
    232  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
    233  variable hsize = NumberByKey("Hsize", param, "=", ";")
    234  variable cpos = NumberByKey("Cpos", param, "=", ";")
    235  variable csize = NumberByKey("Csize", param, "=", ";")
    236 
    237  // validate parameters
    238  // background parameters are optional, center parameter is required.
    239  if (numtype(lcrop) != 0)
    240  lcrop = 0
    241  endif
    242  if (numtype(lsize) != 0)
    243  lsize = 0
    244  endif
    245  if (numtype(hcrop) != 0)
    246  hcrop = 0
    247  endif
    248  if (numtype(hsize) != 0)
    249  hsize = 0
    250  endif
    251  if (numtype(Cpos) != 0)
    252  return 1// Cpos parameter missing
    253  endif
    254  if (numtype(Csize) != 0)
    255  return 2// Csize parameter missing
    256  endif
    257 
    258  variable lpos = lcrop + lsize / 2
    259  variable hpos = 1 - (hcrop + hsize / 2)
    260 
    261  variable p0
    262  variable p1
    263 
    264  adh5_setup_profile(source, dest1, 1)
    265  adh5_setup_profile(source, dest2, 1)
    266 
    267  duplicate /free dest1, lbg, hbg
    268  if (lsize > 0)
    269  p0 = round(lcrop * nx)
    270  p1 = round((lcrop + lsize) * nx)
    271  ad_profile_y_w(source, p0, p1, lbg)
    272  else
    273  lbg = 0
    274  endif
    275  if (hsize > 0)
    276  p0 = round((1 - hcrop - hsize) * nx)
    277  p1 = round((1 - hcrop) * nx)
    278  ad_profile_y_w(source, p0, p1, hbg)
    279  else
    280  hbg = 0
    281  endif
    282  if (csize > 0)
    283  p0 = round((cpos - csize/2) * nx)
    284  p1 = round((cpos + csize/2) * nx)
    285  ad_profile_y_w(source, p0, p1, dest1)
    286  else
    287  dest1 = 0
    288  endif
    289 
    290  variable scale = (cpos - lpos) / (hpos - lpos)
    291  dest2 = dest1
    292  dest1 -= scale * (hbg - lbg) + lbg
    293  dest2 = sqrt(dest2 + scale^2 * (hbg + lbg))
    294  return 0// return zero if successful, non-zero if an error occurs
    295 };
    296 
    297 variable test_shockley_anglefit(wave image, variable branch){
    298  // apply the Shockley_anglefit function to a single image
    299  // useful for testing or manual processing
    300  // since the Shockley_anglefit function cannot be called from the command line directly.
    301  wave image
    302  variable branch// +1 or -1
    303 
    304  string param = ""
    305  param = ReplaceStringByKey("branch", param, num2str(branch), "=", ";")
    306 
    307  string s_branch
    308  if (branch >= 0)
    309  s_branch = "p"
    310  else
    311  s_branch = "n"
    312  endif
    313  string pkpos_name = "saf_pkpos_" + s_branch
    314  string pkwid_name = "saf_pkwid_" + s_branch
    315  duplicate /o image, $pkpos_name, $pkwid_name
    316  wave w_pkpos = $pkpos_name
    317  wave w_pkwid = $pkwid_name
    318 
    319  shockley_anglefit(image, w_pkpos, w_pkwid, param)
    320 };
    321 
    322 variable prompt_Shockley_anglefit(string* param){
    323  string &param
    324 
    325  variable branch = NumberByKey("branch", param, "=", ";")
    326 
    327  prompt branch, "Branch (-1 or +1)"
    328 
    329  doprompt "Shockley_anglefit_reduction Parameters", branch
    330  if (v_flag == 0)
    331  param = ReplaceNumberByKey("branch", param, branch, "=", ";")
    332  endif
    333 
    334  return v_flag
    335 };
    336 
    337 threadsafe variable Shockley_anglefit(wave source, wave dest1, wave dest2, string* param){
    338  // data reduction function for adh5_load_reduced_detector
    339  // specialized for analysing the Cu(111) Shockley surface state
    340  // do curve fitting of one branch of the surface state
    341  // the result is peak position versus energy
    342  // TODO: this function contains hard-coded parameters. please generalize as necessary.
    343  wave source// source wave
    344  // Scienta detector image, energy axis along X, angle axis along Y
    345  // the apex of the surface state must be at angle 0
    346  wave dest1, dest2// destination waves
    347  // dest1: peak position
    348  // dest2: peak width (sigma)
    349  string &param// parameters in a key1=value1;key2=value2;... list
    350  // branch=-1 or +1: select negative (positive) angles for the fit interval, respectively
    351 
    352  variable nx = dimsize(source, 0)
    353  variable ny = dimsize(source, 1)
    354 
    355  // read parameters
    356  variable branch = NumberByKey("branch", param, "=", ";")
    357 
    358  // validate parameters
    359  if (numtype(branch) != 0)
    360  branch = +1
    361  endif
    362 
    363  // prepare output
    364  adh5_setup_profile(source, dest1, 0)
    365  adh5_setup_profile(source, dest2, 0)
    366  dest1 = nan
    367  dest2 = nan
    368 
    369  // select angle range
    370  // hard-coded for a particular measurement series
    371  variable y0
    372  variable y1
    373  if (branch < 0)
    374  y0 = -5
    375  y1 = 0
    376  else
    377  y0 = 0
    378  y1 = 5
    379  endif
    380 
    381  // select energy range
    382  // start at the point of highest intensity and go up 0.45 eV
    383  variable p0
    384  variable p1
    385  variable q0
    386  variable q1
    387  duplicate /free dest1, center
    388  q0 = round((y0 - dimoffset(source, 1)) / dimdelta(source, 1))
    389  q1 = round((y1 - dimoffset(source, 1)) / dimdelta(source, 1))
    390  ad_profile_x_w(source, q0, q1, center)
    391  wavestats /q/m=1 center
    392  p0 = round((v_maxloc - dimoffset(source, 0)) / dimdelta(source, 0))
    393  p1 = round((v_maxloc + 0.4 - dimoffset(source, 0)) / dimdelta(source, 0))
    394 
    395  // prepare intermediate data buffer
    396  make /n=(ny)/d/free profile
    397  setscale /p x dimoffset(source,1), dimdelta(source,1), waveunits(source,1), profile
    398 
    399  variable pp
    400  for (pp = p0; pp <= p1; pp += 1)
    401  profile = source[pp][p]
    402  curvefit /Q /NTHR=1 /W=2 gauss profile(y0,y1)
    403  wave w_coef
    404  dest1[pp] = w_coef[2]
    405  dest2[pp] = w_coef[3]
    406  endfor
    407  return 0// return zero if successful, non-zero if an error occurs
    408 };
    409 
    410 variable prompt_int_quadbg_reduction(string* param){
    411  string &param
    412 
    413  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
    414  variable Lsize = NumberByKey("Lsize", param, "=", ";")
    415  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
    416  variable Hsize = NumberByKey("Hsize", param, "=", ";")
    417  variable Cpos = NumberByKey("Cpos", param, "=", ";")
    418  variable Csize = NumberByKey("Csize", param, "=", ";")
    419 
    420  prompt Lcrop, "Lower cropping region"
    421  prompt Hcrop, "Upper cropping region"
    422  prompt Lsize, "Lower background region"
    423  prompt Hsize, "Upper background region"
    424  prompt Cpos, "Center position"
    425  prompt Csize, "Center integration region"
    426 
    427  doprompt "int_quadbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
    428  if (v_flag == 0)
    429  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
    430  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
    431  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
    432  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
    433  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
    434  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
    435  endif
    436 
    437  return v_flag
    438 };
    439 
    440 variable test_int_quadbg(wave image){
    441  // useful for testing or manual processing
    442  // since the int_quadbg_reduction function cannot be called from the command line directly.
    443  wave image
    444 
    445  string param = ""
    447 
    448  string data1_name = "test_data1"
    449  string data2_name = "test_data2"
    450  duplicate /o image, $data1_name, $data2_name
    451  wave w_data1 = $data1_name
    452  wave w_data2 = $data2_name
    453 
    454  int_quadbg_reduction(image, w_data1, w_data2, param)
    455 };
    456 
    457 threadsafe variable int_quadbg_reduction(wave source, wave dest1, wave dest2, string* param){
    458  // data reduction function for adh5_load_reduced_detector
    459  // integrates peak area minus a quadratic backgrouind
    460  wave source// source wave
    461  // Scienta detector image, energy axis along X, angle axis along Y
    462  wave dest1, dest2// destination waves
    463  string &param// parameters in a key1=value1;key2=value2;... list
    464  // all region parameters are relative to the image size (0...1)
    465  // Lcrop = size of the lower cropping region
    466  // Hcrop = size of the upper cropping region
    467  // Lsize = size of the lower background integration region
    468  // Hsize = size of the upper background integration region
    469  // Cpos = center position of the of the peak integration region
    470  // Csize = size of the peak integration region
    471 
    472  // typical values (peak centered on detector, FWHM ~ 20 % of image)
    473  // Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2
    474 
    475  variable nx = dimsize(source, 0)
    476  variable ny = dimsize(source, 1)
    477 
    478  // read parameters
    479  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
    480  variable lsize = NumberByKey("Lsize", param, "=", ";")
    481  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
    482  variable hsize = NumberByKey("Hsize", param, "=", ";")
    483  variable cpos = NumberByKey("Cpos", param, "=", ";")
    484  variable csize = NumberByKey("Csize", param, "=", ";")
    485 
    486  // validate parameters
    487  // background parameters are optional, center parameter is required.
    488  if (numtype(lcrop) != 0)
    489  lcrop = 0
    490  endif
    491  if (numtype(lsize) != 0)
    492  lsize = 0
    493  endif
    494  if (numtype(hcrop) != 0)
    495  hcrop = 0
    496  endif
    497  if (numtype(hsize) != 0)
    498  hsize = 0
    499  endif
    500  if (numtype(Cpos) != 0)
    501  return 1// Cpos parameter missing
    502  endif
    503  if (numtype(Csize) != 0)
    504  return 2// Csize parameter missing
    505  endif
    506 
    507  // crop boundaries
    508  variable pcl = round(lcrop * nx)
    509  variable pch = round((1 - hcrop) * nx)
    510  // fit boundaries
    511  variable pfl = round((lcrop + lsize) * nx)
    512  variable pfh = round((1 - hcrop - hsize) * nx)
    513  // integration boundaries
    514  variable pil = round((cpos - csize/2) * nx)
    515  variable pih = round((cpos + csize/2) * nx)
    516 
    517  adh5_setup_profile(source, dest1, 0)
    518  adh5_setup_profile(source, dest2, 0)
    519 
    520  // prepare intermediate data buffer
    521  make /n=(nx) /d /free profile, mask, fit
    522  setscale /p x dimoffset(source,0), dimdelta(source,0), waveunits(source,0), profile, mask, fit
    523  mask = ((p >= pcl) && (p < pfl)) || ((p >= pfh) && (p < pch))
    524 
    525  variable qq
    526  variable sp, sf
    527  variable xil = x2pnt(profile, pil)
    528  variable xih = x2pnt(profile, pih)
    529 
    530  make /n=3 /free /d w_coef
    531  for (qq = 0; qq < ny; qq += 1)
    532  profile = source[p][qq]
    533  curvefit /Q /NTHR=1 /W=2 poly 3, kwCWave=w_coef, profile /M=mask
    534  fit = poly(w_coef, x)
    535  sp = sum(profile, xil, xih)
    536  sf = sum(fit, xil, xih)
    537  dest1[qq] = sp - sf
    538  dest2[qq] = sqrt(sp)
    539  endfor
    540 
    541  return 0// return zero if successful, non-zero if an error occurs
    542 };
    543 
    544 variable scienta_norm(wave w, variable x){
    545  wave w
    546  variable x
    547 
    548  return w[0] * (x^2 - w[1]^2)
    549 };
    550 
    551 wave fit_scienta_ang_transm(wave data, wave params){
    552  wave data// measured angular distribution (1D)
    553  wave /z params
    554 
    555  if (!waveexists(params))
    556  make /n=12 /o params
    557  endif
    558  redimension /n=12/d params
    559 
    560  variable h = wavemax(data) - wavemin(data)
    561  params[0] = h / 2
    562  params[1] = 0
    563  params[2] = 7
    564  params[3] = h / 4
    565  params[4] = -23
    566  params[5] = 4
    567  params[6] = h / 4
    568  params[7] = +23
    569  params[8] = 4
    570  params[9] = h / 2
    571  params[10] = 0
    572  params[11] = -0.001
    573  FuncFit /NTHR=0 /q scienta_ang_transm params data
    574 
    575  return params
    576 };
    577 
    578 threadsafe variable scienta_ang_transm(wave w, variable x){
    579  // parameterized angular transmission function of the analyser
    580  wave w// coefficients
    581  // w[0] = amplitude gauss 1
    582  // w[1] = position gauss 1
    583  // w[2] = width gauss 1
    584  // w[3] = amplitude gauss 2
    585  // w[4] = position gauss 2
    586  // w[5] = width gauss 2
    587  // w[6] = amplitude gauss 3
    588  // w[7] = position gauss 3
    589  // w[8] = width gauss 3
    590  // w[9] = constant background
    591  // w[10] = linear background
    592  // w[11] = quadratic background
    593  variable x
    594 
    595  make /free /n=4 /d w_int
    596  w_int[0] = 0
    597  w_int[1,] = w[p - 1]
    598  variable pk1 = gauss1d(w_int, x)
    599  w_int[1,] = w[p + 2]
    600  variable pk2 = gauss1d(w_int, x)
    601  w_int[1,] = w[p + 5]
    602  variable pk3 = gauss1d(w_int, x)
    603  w_int[0,2] = w[9 + p]
    604  w_int[3] = 0
    605  variable bg = poly(w_int, x)
    606 
    607  return bg + pk1 + pk2 + pk3
    608 };
    609 
    610 wave fit_scienta_poly_bg(wave data, wave params, variable bgterms){
    611  wave data// measured distribution (2D)
    612  wave /z params// wave, will be redimensioned for the correct size
    613  variable bgterms// number of terms in the polynomial background: 2, 3, or 4
    614 
    615  if (!waveexists(params))
    616  make /n=15 /o params
    617  endif
    618  redimension /n=15 /d params
    619 
    620  variable wmax = wavemax(data)
    621  variable wmin = wavemin(data)
    622  params[0] = 0
    623  params[1] = 7
    624  params[2] = 1 / 2
    625  params[3] = -23
    626  params[4] = 4
    627  params[5] = 1 / 2
    628  params[6] = +23
    629  params[7] = 4
    630  params[8] = 1
    631  params[9] = 0
    632  params[10] = -0.001
    633  params[11] = wmin
    634  params[12] = (wmax - wmin) / dimdelta(data,1) / dimsize(data,1)
    635  params[13] = 0
    636  params[14] = 0
    637 
    638  string h = "0000000000000"
    639  if (bgterms < 3)
    640  h = h + "1"
    641  else
    642  h = h + "0"
    643  endif
    644  if (bgterms < 4)
    645  h = h + "1"
    646  else
    647  h = h + "0"
    648  endif
    649  FuncFitMD /NTHR=1 /q /h=h scienta_poly_bg params data
    650 
    651  return params
    652 };
    653 
    654 variable scienta_poly_bg(wave w, variable e, variable a){
    655  // polynomial background with
    656  // parameterized angular transmission function of the analyser
    657  wave w// coefficients
    658  // angular transmission, varies with a
    659  // amplitude of gauss 1 = 1 constant
    660  // other peak amplitudes and linear terms are relative to gauss 1
    661  // w[0] = position gauss 1
    662  // w[1] = width gauss 1
    663  // w[2] = amplitude gauss 2, relative to gauss 1
    664  // w[3] = position gauss 2
    665  // w[4] = width gauss 2
    666  // w[5] = amplitude gauss 3, relative to gauss 1
    667  // w[6] = position gauss 3
    668  // w[7] = width gauss 3
    669  // w[8] = constant term
    670  // w[9] = linear term
    671  // w[10] = quadratic term
    672  // spectral background, varies with e
    673  // w[11] = constant term
    674  // w[12] = linear term
    675  // w[13] = quadratic term
    676  // w[14] = cubic term
    677  variable a// detection angle
    678  variable e// electron energy
    679 
    680  make /free /n=4 /d w_int
    681  variable p0 = 0
    682 
    683  w_int[0] = 0
    684  w_int[1] = 1
    685  w_int[2,] = w[p0 + p - 2]
    686  variable pk1 = gauss1d(w_int, a)
    687  p0 += 2
    688 
    689  w_int[1,] = w[p0 + p - 1]
    690  variable pk2 = gauss1d(w_int, a)
    691  p0 += 3
    692 
    693  w_int[1,] = w[p0 + p - 1]
    694  variable pk3 = gauss1d(w_int, a)
    695  p0 += 3
    696 
    697  w_int[0,2] = w[p0 + p]
    698  w_int[3] = 0
    699  variable base = poly(w_int, a)
    700  p0 += 3
    701 
    702  w_int[0,3] = w[p0 + p]
    703  variable bg = poly(w_int, e)
    704 
    705  return bg * (base + pk1 + pk2 + pk3)
    706 };
    707 
    716 variable prompt_redim_linbg_reduction(string* param){
    717  string &param
    718 
    719  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
    720  variable Lsize = NumberByKey("Lsize", param, "=", ";")
    721  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
    722  variable Hsize = NumberByKey("Hsize", param, "=", ";")
    723  variable Cpos = NumberByKey("Cpos", param, "=", ";")
    724  variable Csize = NumberByKey("Csize", param, "=", ";")
    725 
    726  prompt Lcrop, "Lower cropping region"
    727  prompt Hcrop, "Upper cropping region"
    728  prompt Lsize, "Lower background region"
    729  prompt Hsize, "Upper background region"
    730  prompt Cpos, "Center position"
    731  prompt Csize, "Center integration region"
    732 
    733  doprompt "redim_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
    734  if (v_flag == 0)
    735  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
    736  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
    737  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
    738  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
    739  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
    740  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
    741  endif
    742 
    743  return v_flag
    744 };
    745 
    787 threadsafe variable redim_linbg_reduction(wave source, wave dest1, wave dest2, string* param){
    788  wave source
    789  wave dest1, dest2
    790  string &param
    791 
    792  variable nx = dimsize(source, 0)
    793  variable ny = dimsize(source, 1)
    794 
    795  duplicate /free source, source_redim
    796  redimension /n=(nx * ny) source_redim
    797  nx += 1
    798  redimension /n=(nx, ny) source_redim
    799 
    800  return int_linbg_reduction(source_redim, dest1, dest2, param)
    801 };
    802 
    803 // DblGaussLinBG function fit reduction
    804 
    810 variable test_gauss2_reduction(wave image){
    811  wave image
    812 
    813  string param = ""
    814  param = ReplaceNumberByKey("rngl", param, -inf, "=", ";")
    815  param = ReplaceNumberByKey("rngh", param, inf, "=", ";")
    816  param = ReplaceNumberByKey("pos1", param, 113.70, "=", ";")
    817  param = ReplaceNumberByKey("wid1", param, 1.46, "=", ";")
    818  param = ReplaceNumberByKey("pos2", param, 126.53, "=", ";")
    819  param = ReplaceNumberByKey("wid2", param, 1.63, "=", ";")
    820  param = ReplaceNumberByKey("ybox", param, 1, "=", ";")
    821  param = ReplaceStringByKey("return", param, "amp1", "=", ";")
    822 
    823  make /o test1
    824  make /o test2
    825 
    826  gauss2_reduction(image, test1, test2, param)
    827 };
    828 
    834 variable prompt_gauss2_reduction(string* param){
    835  string &param
    836 
    837  variable rngl = NumberByKey("rngl", param, "=", ";")
    838  variable rngh = NumberByKey("rngh", param, "=", ";")
    839  variable pos1 = NumberByKey("pos1", param, "=", ";")
    840  variable wid1 = NumberByKey("wid1", param, "=", ";")
    841  variable pos2 = NumberByKey("pos2", param, "=", ";")
    842  variable wid2 = NumberByKey("wid2", param, "=", ";")
    843  variable ybox = NumberByKey("ybox", param, "=", ";")
    844  string retpar = StringByKey("return", param, "=", ";")
    845 
    846  prompt rngl, "range low"
    847  prompt rngh, "range high"
    848  prompt pos1, "position 1"
    849  prompt wid1, "width 1"
    850  prompt pos2, "position 2"
    851  prompt wid2, "width 2"
    852  prompt ybox, "ybox (1 or 3)"
    853  prompt retpar, "return", popup "amp1;amp2;"
    854 
    855  doprompt "gauss2_reduction reduction parameters", rngl, rngh, pos1, wid1, pos2, wid2, ybox, retpar
    856  if (v_flag == 0)
    857  param = ReplaceNumberByKey("rngl", param, rngl, "=", ";")
    858  param = ReplaceNumberByKey("rngh", param, rngh, "=", ";")
    859  param = ReplaceNumberByKey("pos1", param, pos1, "=", ";")
    860  param = ReplaceNumberByKey("wid1", param, wid1, "=", ";")
    861  param = ReplaceNumberByKey("pos2", param, pos2, "=", ";")
    862  param = ReplaceNumberByKey("wid2", param, wid2, "=", ";")
    863  param = ReplaceStringByKey("return", param, retpar, "=", ";")
    864  param = ReplaceNumberByKey("ybox", param, ybox, "=", ";")
    865  endif
    866 
    867  return v_flag
    868 };
    869 
    903 threadsafe variable gauss2_reduction(wave source, wave dest1, wave dest2, string* param){
    904  wave source
    905  wave dest1, dest2
    906  string &param
    907 
    908  variable nx = dimsize(source, 0)
    909  variable ny = dimsize(source, 1)
    910 
    911  // prepare output
    912  adh5_setup_profile(source, dest1, 1)
    913  adh5_setup_profile(source, dest2, 1)
    914  dest1 = 0
    915  dest2 = 0
    916 
    917  // read parameters
    918  variable rngl = NumberByKey("rngl", param, "=", ";")
    919  variable rngh = NumberByKey("rngh", param, "=", ";")
    920  variable pos1 = NumberByKey("pos1", param, "=", ";")
    921  variable wid1 = NumberByKey("wid1", param, "=", ";")
    922  variable pos2 = NumberByKey("pos2", param, "=", ";")
    923  variable wid2 = NumberByKey("wid2", param, "=", ";")
    924  variable ybox = NumberByKey("ybox", param, "=", ";")
    925  string retpar = StringByKey("return", param, "=", ";")
    926 
    927  variable idestcoef
    928  if (cmpstr(retpar, "amp2") == 0)
    929  idestcoef = 3
    930  else
    931  idestcoef = 0
    932  endif
    933 
    934  // prepare curve fit
    935  make /free xprof
    936  adh5_setup_profile(source, xprof, 0)
    937  duplicate /free xprof, xprof_sig
    938  make /free /d /n=8 w_coef, W_sigma
    939  w_coef[0] = {1, pos1, wid1, 1, pos2, wid2, 0, 0}
    940 
    941  variable pl = max(x2pnt(xprof, rngl), 0)
    942  variable ph = min(x2pnt(xprof, rngh), numpnts(xprof) - 1)
    943 
    944  // text constraints cannot be used in threadsafe functions.
    945  // the following matrix-vector forumlation is equivalent to:
    946  // make /free /T /N=4 constraints
    947  // constraints[0] = {"K0 >= 0", "K3 >= 0", "K6 <= 0", "K7 => 0"}
    948  make /free /n=(4,8) cmat
    949  make /free /n=4 cvec
    950  cmat = 0
    951  cmat[0][0] = -1
    952  cmat[1][3] = -1
    953  cmat[2][6] = 1
    954  cmat[3][7] = -1
    955  cvec = 0
    956 
    957  // loop over angle scale
    958  variable p0 = 0
    959  variable p1 = numpnts(dest1) - 1
    960  variable pp
    961  variable wmin
    962  variable wmax
    963  if (ybox > 1)
    964  p0 += ceil((ybox - 1) / 2)
    965  p1 -= ceil((ybox - 1) / 2)
    966  endif
    967  variable V_FitNumIters
    968 
    969  for (pp = p0; pp <= p1; pp += 1)
    970  xprof = source[p][pp]
    971  if (ybox > 1)
    972  xprof += source[p][pp-1] + source[p][pp+1]
    973  endif
    974  xprof_sig = max(sqrt(xprof), 1)
    975  xprof /= ybox
    976  xprof_sig /= ybox
    977 
    978  wmin = wavemin(xprof)
    979  wmax = wavemax(xprof)
    980  w_coef[0] = wmax - wmin
    981  w_coef[3] = w_coef[0]
    982  w_coef[6] = 0
    983  w_coef[7] = wmin
    984  FuncFit /H="01101100" /Q /NTHR=1 /N /W=2 DblGaussLinBG w_coef xprof[pl,ph] /C={cmat, cvec} /I=1 /W=xprof_sig[pl,ph]
    985  wave w_sigma
    986 
    987  if (V_FitNumIters < 40)
    988  dest1[pp] = max(w_coef[idestcoef], 0)
    989  dest2[pp] = max(w_sigma[idestcoef], 0)
    990  endif
    991  endfor
    992 
    993  dest1 *= w_coef[idestcoef+2] * sqrt(pi)
    994  dest2 *= w_coef[idestcoef+2] * sqrt(pi)
    995 
    996  return 0
    997 };
    998 
    wave fit_scienta_ang_transm(wave data, wave params)
    -
    variable test_int_linbg(wave image)
    -
    threadsafe variable Shockley_anglefit(wave source, wave dest1, wave dest2, string *param)
    -
    variable prompt_gauss2_reduction(string *param)
    prompt for the gauss2_reduction parameters
    -
    threadsafe variable redim_linbg_reduction(wave source, wave dest1, wave dest2, string *param)
    linear background reduction function for incorrectly dimensioned scienta image
    -
    variable scienta_poly_bg(wave w, variable e, variable a)
    +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 
    35 variable prompt_int_linbg_reduction(string* param){
    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 };
    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 };
    75 
    89 string csr_int_linbg_reduction(string 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 };
    181 
    214 threadsafe wave int_linbg_reduction(wave source, string* 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 };
    304 
    305 variable prompt_int_quadbg_reduction(string* param){
    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 };
    334 
    367 threadsafe wave int_quadbg_reduction(wave source, string* 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 };
    454 
    463 variable prompt_redim_linbg_reduction(string* param){
    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 };
    492 
    526 threadsafe wave redim_linbg_reduction(wave source, string* 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 };
    540 
    546 variable test_gauss4_reduction(wave 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 };
    576 
    580 variable prompt_gauss4_reduction(string* 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 };
    631 
    672 threadsafe wave gauss4_reduction(wave source, string* 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 };
    805 
    806 
    838 string find_gauss4_reduction_params(wave spectrum, wave 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 };
    904 
    912 variable test_shockley_anglefit(wave image, variable 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 };
    932 
    933 variable prompt_Shockley_anglefit(string* 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 };
    947 
    970 threadsafe wave Shockley_anglefit(wave source, string* 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 };
    1036 
    1037 variable scienta_norm(wave w, variable x){
    1038  wave w
    1039  variable x
    1040 
    1041  return w[0] * (x^2 - w[1]^2)
    1042 };
    1043 
    1044 wave fit_scienta_ang_transm(wave data, wave 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 };
    1070 
    1071 threadsafe variable scienta_ang_transm(wave w, variable x){
    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 };
    1102 
    1103 wave fit_scienta_poly_bg(wave data, wave params, variable 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 };
    1146 
    1147 variable scienta_poly_bg(wave w, variable e, variable a){
    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 };
    1200 
    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.
    -
    wave fit_scienta_poly_bg(wave data, wave params, variable bgterms)
    -
    variable prompt_Shockley_anglefit(string *param)
    -
    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 variable scienta_ang_transm(wave w, variable x)
    -
    threadsafe variable int_quadbg_reduction(wave source, wave dest1, wave dest2, string *param)
    -
    threadsafe variable gauss2_reduction(wave source, wave dest1, wave dest2, string *param)
    fit horizontal cuts of an image with two gaussian peaks on a linear background
    -
    variable test_shockley_anglefit(wave image, variable branch)
    -
    threadsafe variable int_linbg_reduction(wave source, wave dest1, wave dest2, string *param)
    -
    variable scienta_norm(wave w, variable x)
    -
    variable prompt_redim_linbg_reduction(string *param)
    parameter dialog for the redim_linbg_reduction() function
    +
    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.
    -
    variable prompt_int_linbg_reduction(string *param)
    -
    variable test_int_quadbg(wave image)
    -
    string csr_int_linbg_reduction(string win)
    -
    string capture_int_linbg_cursors()
    -
    variable test_gauss2_reduction(wave image)
    apply the gauss2_reduction function to a single image
    +
    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
    @@ -191,7 +191,7 @@ Data Fields
    -

    Definition at line 201 of file pearl-fitfuncs.ipf.

    +

    Definition at line 346 of file pearl-fitfuncs.ipf.

    @@ -205,7 +205,7 @@ Data Fields
    -

    Definition at line 200 of file pearl-fitfuncs.ipf.

    +

    Definition at line 345 of file pearl-fitfuncs.ipf.

    @@ -219,7 +219,7 @@ Data Fields
    -

    Definition at line 191 of file pearl-fitfuncs.ipf.

    +

    Definition at line 336 of file pearl-fitfuncs.ipf.

    @@ -233,7 +233,7 @@ Data Fields
    -

    Definition at line 205 of file pearl-fitfuncs.ipf.

    +

    Definition at line 350 of file pearl-fitfuncs.ipf.

    @@ -247,7 +247,7 @@ Data Fields
    -

    Definition at line 197 of file pearl-fitfuncs.ipf.

    +

    Definition at line 342 of file pearl-fitfuncs.ipf.

    @@ -261,7 +261,7 @@ Data Fields
    -

    Definition at line 196 of file pearl-fitfuncs.ipf.

    +

    Definition at line 341 of file pearl-fitfuncs.ipf.

    @@ -274,7 +274,7 @@ Data Fields